macOS-style swipe gestures for Apple Magic Mouse 2 on Linux/Wayland
Project description
Magic Mouse Gestures for Linux
Enable macOS-style swipe gestures on Apple Magic Mouse 2 for Linux/Wayland.
Features
- Horizontal swipe gestures for browser back/forward navigation
- Works with Wayland compositors (Hyprland, Sway, GNOME, etc.)
- Lightweight Python daemon with minimal dependencies
- Automatic device detection and reconnection
- Configurable via environment variables
How It Works
The Magic Mouse 2 has a touch-sensitive surface, but Linux only exposes basic mouse functionality by default. This driver reads raw HID data directly from the device to detect touch positions and translate horizontal swipes into keyboard shortcuts.
| Gesture | Action |
|---|---|
| Swipe → (right) | Browser back (Alt+Left) |
| Swipe ← (left) | Browser forward (Alt+Right) |
Requirements
- Linux with kernel 5.15+ (built-in Magic Mouse 2 support)
- Wayland session (not X11)
- Python 3.8+
wtype(for sending keystrokes on Wayland)
Supported Desktops
This driver uses wtype which requires Wayland. It works with:
| Desktop | Wayland Support |
|---|---|
| GNOME | Default since 3.22 (2017+) |
| KDE Plasma | Default since Plasma 6 (2024+) |
| Hyprland | Wayland-native |
| Sway | Wayland-native |
To check if you're running Wayland:
echo $XDG_SESSION_TYPE
# Should output: wayland
Note: X11 sessions are not supported (would require xdotool instead of wtype).
Installation
Choose one of the two methods below:
Option A: Automatic Installation (Recommended)
git clone https://github.com/brenoperucchi/magic-mouse-gestures.git
cd magic-mouse-gestures
./install.sh
The installer will:
- Check dependencies (
python3,wtype,bluetoothctl) - Install the driver to
/opt/magic-mouse-gestures/ - Install udev rules for non-root access
- Reconnect Magic Mouse to apply permissions
- Install and enable the systemd user service
- Verify everything is working
Note: Do NOT run with sudo. The script requests sudo only when needed.
Option B: Manual Installation
1. Install dependencies
Arch Linux:
sudo pacman -S python wtype bluez-utils
Debian/Ubuntu:
sudo apt install python3 wtype bluez
Fedora:
sudo dnf install python3 wtype bluez
2. Install driver and udev rules
git clone https://github.com/brenoperucchi/magic-mouse-gestures.git
cd magic-mouse-gestures
# Install driver
sudo mkdir -p /opt/magic-mouse-gestures
sudo cp magic_mouse_gestures.py /opt/magic-mouse-gestures/
sudo chmod +x /opt/magic-mouse-gestures/magic_mouse_gestures.py
# Install udev rules
sudo cp udev/99-magic-mouse.rules /etc/udev/rules.d/
sudo udevadm control --reload-rules
3. Reconnect Magic Mouse
Disconnect and reconnect via Bluetooth to apply permissions:
bluetoothctl disconnect <MAC_ADDRESS>
bluetoothctl connect <MAC_ADDRESS>
4. Install and enable the service
mkdir -p ~/.config/systemd/user
cp systemd/magic-mouse-gestures.service ~/.config/systemd/user/
systemctl --user daemon-reload
systemctl --user enable --now magic-mouse-gestures
Verify it's running:
systemctl --user status magic-mouse-gestures
Uninstall
cd magic-mouse-gestures
./uninstall.sh
This stops the service, removes all installed files, and restores default permissions.
Configuration
All thresholds can be configured via environment variables (no need to edit code):
| Variable | Default | Description |
|---|---|---|
SWIPE_THRESHOLD |
200 | Minimum horizontal movement (pixels) |
SWIPE_VERTICAL_MAX |
150 | Maximum vertical movement (pixels) |
SWIPE_TIME_MAX |
0.5 | Maximum swipe duration (seconds) |
SWIPE_VELOCITY_MIN |
200 | Minimum swipe velocity (pixels/second) |
SCROLL_COOLDOWN |
0.25 | Cooldown after scroll before allowing swipe (seconds) |
MIN_FINGERS |
1 | Minimum fingers for swipe gesture |
MAX_FINGERS |
2 | Maximum fingers (ignore if more) |
DEBUG |
false | Enable debug output (1, true, yes) |
Example: Custom configuration
SWIPE_THRESHOLD=150 SWIPE_VELOCITY_MIN=150 python3 /opt/magic-mouse-gestures/magic_mouse_gestures.py
Persistent configuration (systemd)
Edit the service file to add environment variables:
systemctl --user edit magic-mouse-gestures
Add:
[Service]
Environment="SWIPE_THRESHOLD=150"
Environment="SWIPE_VELOCITY_MIN=150"
Then restart:
systemctl --user restart magic-mouse-gestures
Debugging
Step 1: Stop the systemd service
systemctl --user stop magic-mouse-gestures
Step 2: Run manually with debug enabled
DEBUG=1 python3 /opt/magic-mouse-gestures/magic_mouse_gestures.py
Or from the project directory:
DEBUG=1 python3 ~/Projects/magic-mouse-gestures/magic_mouse_gestures.py
Step 3: Save debug output to a file
DEBUG=1 python3 /opt/magic-mouse-gestures/magic_mouse_gestures.py 2>&1 | tee ~/magic-mouse.log
Step 4: Restart the service when done
systemctl --user start magic-mouse-gestures
View service logs
journalctl --user -u magic-mouse-gestures -f
Troubleshooting
Device not found
Make sure your Magic Mouse 2 is connected via Bluetooth:
bluetoothctl devices
Permission denied
Either run with sudo or install the udev rules (see installation).
Gestures not working
-
Check if the service is running:
systemctl --user status magic-mouse-gestures
-
View logs:
journalctl --user -u magic-mouse-gestures -f
-
Run with debug to see touch data:
systemctl --user stop magic-mouse-gestures DEBUG=1 python3 /opt/magic-mouse-gestures/magic_mouse_gestures.py
Verify udev rules
After reconnecting the Magic Mouse, check permissions:
ls -la /dev/hidraw*
The Magic Mouse device should show crw-rw-rw- permissions.
Technical Details
HID Data Structure
The Magic Mouse 2 sends touch data in the following format:
- Header (14 bytes): Mouse movement and button states
- Touch data (8 bytes per finger):
- Bytes 0-1: X position (12-bit)
- Bytes 1-2: Y position (12-bit)
- Bytes 3-4: Touch ellipse dimensions
- Bytes 5-6: Touch ID and orientation
- Byte 7: Touch state (1-4 = contact, 5-7 = lift)
Coordinate Parsing
Coordinates are 12-bit values (0-4095) parsed as:
x = tdata[0] | ((tdata[1] & 0x0F) << 8)
y = (tdata[2] << 4) | (tdata[1] >> 4)
Why not libinput?
The Linux kernel's hid-magicmouse driver converts touch data into scroll events only. It doesn't expose raw multitouch data to libinput, which is why libinput-gestures doesn't work with Magic Mouse.
This driver bypasses that limitation by reading directly from the HID raw interface.
Kernel Module: hid_magicmouse
The hid_magicmouse kernel module handles scroll functionality. Our driver handles swipe gestures. Both work together.
Check if module is loaded:
lsmod | grep hid_magicmouse
Force load the module:
sudo modprobe hid_magicmouse
View module parameters:
modinfo hid_magicmouse
Current settings:
systool -m hid_magicmouse -av
Scroll Configuration
The installer copies modprobe/hid-magicmouse.conf to /etc/modprobe.d/ with optimized scroll settings:
options hid_magicmouse scroll_acceleration=1 scroll_speed=32 emulate_3button=0
| Option | Default | Description |
|---|---|---|
scroll_acceleration |
1 | Enable scroll acceleration |
scroll_speed |
32 | Scroll speed multiplier |
emulate_3button |
0 | Emulate middle button with 3-finger click |
emulate_scroll_wheel |
1 | Enable scroll wheel emulation |
Apply changes manually:
sudo modprobe -r hid_magicmouse && sudo modprobe hid_magicmouse
Then reconnect the Magic Mouse via Bluetooth.
Contributing
Contributions are welcome! Feel free to open issues or submit pull requests.
License
MIT License - see LICENSE for details.
Acknowledgments
- Apple Magic Mouse 2 HID documentation from the Linux kernel source
- The Hyprland and Wayland communities
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file magic_mouse_gestures-0.1.0.tar.gz.
File metadata
- Download URL: magic_mouse_gestures-0.1.0.tar.gz
- Upload date:
- Size: 10.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
52271751711937371f0c9587e1369fcdfb98687e6e6033aead717aa87b222c2b
|
|
| MD5 |
39396cd43e4b229f15ff2a05954e1441
|
|
| BLAKE2b-256 |
b0799048610233b6eeafd8883306fa1b3268b8938946d88aa88cba21ffab66cf
|
File details
Details for the file magic_mouse_gestures-0.1.0-py3-none-any.whl.
File metadata
- Download URL: magic_mouse_gestures-0.1.0-py3-none-any.whl
- Upload date:
- Size: 10.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f8ff4e80aaa6df057fbf30f98c30c04cb907cca2f5c6352fc0caf3c762699629
|
|
| MD5 |
9faff7785b1e206751d5819830e5b6ff
|
|
| BLAKE2b-256 |
4b0ca27d49c93881ac9885dbef6e69b477a76852dd5a3152f1bc0333eb72c4c3
|