Enable macOS-style swipe gestures on Apple Magic Mouse 2 for Linux/Wayland.
- 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
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) |
- Linux with kernel 5.15+ (built-in Magic Mouse 2 support)
- Wayland session (not X11)
- Python 3.8+
wtype(for sending keystrokes on Wayland)
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: waylandNote: X11 sessions are not supported (would require xdotool instead of wtype).
Choose one of the two methods below:
git clone https://github.com/brenoperucchi/magic-mouse-gestures.git
cd magic-mouse-gestures
./install.shThe 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.
Arch Linux:
sudo pacman -S python wtype bluez-utilsDebian/Ubuntu:
sudo apt install python3 wtype bluezFedora:
sudo dnf install python3 wtype bluezgit 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-rulesDisconnect and reconnect via Bluetooth to apply permissions:
bluetoothctl disconnect <MAC_ADDRESS>
bluetoothctl connect <MAC_ADDRESS>mkdir -p ~/.config/systemd/user
cp systemd/magic-mouse-gestures.service ~/.config/systemd/user/
systemctl --user daemon-reload
systemctl --user enable --now magic-mouse-gesturesVerify it's running:
systemctl --user status magic-mouse-gesturescd magic-mouse-gestures
./uninstall.shThis stops the service, removes all installed files, and restores default permissions.
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) |
SWIPE_THRESHOLD=150 SWIPE_VELOCITY_MIN=150 python3 /opt/magic-mouse-gestures/magic_mouse_gestures.pyEdit the service file to add environment variables:
systemctl --user edit magic-mouse-gesturesAdd:
[Service]
Environment="SWIPE_THRESHOLD=150"
Environment="SWIPE_VELOCITY_MIN=150"Then restart:
systemctl --user restart magic-mouse-gesturessystemctl --user stop magic-mouse-gesturesDEBUG=1 python3 /opt/magic-mouse-gestures/magic_mouse_gestures.pyOr from the project directory:
DEBUG=1 python3 ~/Projects/magic-mouse-gestures/magic_mouse_gestures.pyDEBUG=1 python3 /opt/magic-mouse-gestures/magic_mouse_gestures.py 2>&1 | tee ~/magic-mouse.logsystemctl --user start magic-mouse-gesturesjournalctl --user -u magic-mouse-gestures -fMake sure your Magic Mouse 2 is connected via Bluetooth:
bluetoothctl devicesEither run with sudo or install the udev rules (see installation).
-
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
After reconnecting the Magic Mouse, check permissions:
ls -la /dev/hidraw*The Magic Mouse device should show crw-rw-rw- permissions.
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)
Coordinates are 12-bit values (0-4095) parsed as:
x = tdata[0] | ((tdata[1] & 0x0F) << 8)
y = (tdata[2] << 4) | (tdata[1] >> 4)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.
The hid_magicmouse kernel module handles scroll functionality. Our driver handles swipe gestures. Both work together.
Check if module is loaded:
lsmod | grep hid_magicmouseForce load the module:
sudo modprobe hid_magicmouseView module parameters:
modinfo hid_magicmouseCurrent settings:
systool -m hid_magicmouse -avThe 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_magicmouseThen reconnect the Magic Mouse via Bluetooth.
Contributions are welcome! Feel free to open issues or submit pull requests.
MIT License - see LICENSE for details.
- Apple Magic Mouse 2 HID documentation from the Linux kernel source
- The Hyprland and Wayland communities