For my wrist health
If I use a mouse for too long, my wrist and forearm start to feel uncomfortable.
Switching to a drawing tablet solved it.
But recently the tablet’s battery seems to be swelling (a bit scary…), and I’ve been eyeing the Magic Trackpad 2 for a long time.
For my wrist health, I spent a lot bought Apple’s Magic Trackpad 2.
Quick unboxing: it’s smaller than I expected, a pretty delicate little slab.
Over Bluetooth, it works out of the box on both Windows and Linux, but only as basic left/right click. Multi-finger gestures (like Windows’ three-finger task switch) don’t work by default.
So I had to do some extra configuration.
Windows Setup
Setup on Windows is very easy: someone has already made a driver. Just install it.
Project page: Github - imbushuo/mac-precision-touchpad
After installation, the trackpad supports multi-finger gestures and behaves like a laptop’s built-in touchpad.
Linux Setup
On Linux it’s slightly more annoying. I hit a few many pitfalls, so I’m writing this down.
First Attempt (Failed)
Manjaro’s Settings app has some touchpad options, but only basic stuff; there’s no way to configure multi-finger gestures.
And for some reason, the built-in settings often “forget” themselves: after waking the PC from sleep, the trackpad resets to defaults (pointer speed, scroll direction, etc.).
Changing them again in Settings sometimes doesn’t take effect either. Weird.
So I gave up on the GUI settings and configured it manually.
I found this tutorial: Configure Apple Magic Trackpad 2 Gestures on Manjaro KDE
It seemed to match what I wanted, so I skimmed it and followed the steps.
-
sudo pacman -S libinput-gestures
Installlibinput-gestures, which lets us map multi-finger gestures to actions. -
sudo gpasswd -a $USER input
Add your user to theinputgroup. -
Then you can start the
libinput-gesturesservicelibinput-gestures-setup startstartlibinput-gestures-setup stopstop- also commonly used:
restart|autostart|status
-
The service seemed to start fine. Next, configure gestures.
The config file can live in two places:
/etc/libinput-gestures.confis the system-level config (with some defaults).
~/.config/libinput-gestures.confis per-user and you write it yourself.
Typically you put your custom mappings in~/.config/libinput-gestures.conf. -
After editing the config, restart the service:
libinput-gestures-setup restart
But after doing all that, none of the gestures worked.
I ran libinput-gestures -d for debugging; no matter what I did on the trackpad, libinput-gestures printed nothing. It looked like it wasn’t receiving any events.
I tried for a while with no result and gave up for the moment. (I briefly thought I just couldn’t make this thing work.)
Second Attempt (Found the Cause)
Two weeks later, I happened to look at the libinput package again. I realized libinput-gestures probably reads trackpad events from libinput, then triggers actions according to the config.
So if libinput-gestures wasn’t seeing any events, what about libinput itself?
-
First, check how to use
libinputTerminal window $ libinput -hUsage: libinput [--help|--version] <command> [<args>]Global options:--help ...... show this help and exit--version ... show version information and exitCommands:list-devicesList all devices with their default configuration optionsdebug-eventsPrint events to stdoutdebug-guiDisplay a simple GUI to visualize libinput's events.measure <feature>Measure various device properties. See the man page for more infoanalyze <feature>Analyze device events. See the man page for more inforecordRecord event stream from a device node. See the man page for more inforeplayReplay a previously recorded event stream. See the man page for more info -
Next, see whether
libinputcan even recognize the trackpad:
libinput list-devices
It prints a bunch of devices. Find the trackpad and you’ll see something like:Terminal window Device: Apple Inc. Magic Trackpad 2Kernel: /dev/input/event11Group: 4Seat: seat0, defaultSize: 162x115mmCapabilities: pointer gestureTap-to-click: disabledTap-and-drag: enabledTap drag lock: disabledLeft-handed: disabledNat.scrolling: disabledMiddle emulation: disabledCalibration: n/aScroll methods: *two-finger edgeClick methods: button-areas *clickfingerDisable-w-typing: n/aDisable-w-trackpointing: n/aAccel profiles: flat *adaptive customRotation: n/aDevice: Apple Inc. Magic Trackpad 2Kernel: /dev/input/event13Group: 4Seat: seat0, defaultSize: 162x115mmCapabilities: pointer gestureTap-to-click: disabledTap-and-drag: enabledTap drag lock: disabledLeft-handed: disabledNat.scrolling: disabledMiddle emulation: disabledCalibration: n/aScroll methods: *two-finger edgeClick methods: button-areas *clickfingerDisable-w-typing: n/aDisable-w-trackpointing: n/aAccel profiles: flat *adaptive customRotation: n/aBut weirdly, it showed two Magic Trackpad 2 devices, even though I only connected one.
In hindsight, this was the culprit.
-
Then check whether
libinputcan receive trackpad events:
libinput debug-events /dev/input/event11, then interact with the trackpad a bit.Terminal window event11 DEVICE_ADDED Apple Inc. Magic Trackpad 2 seat0 default group1 cap:pg size 162x115mm tap(dl off)event11 POINTER_MOTION +0.012s 0.00/ 1.04 ( +0.00/ +5.34)event11 POINTER_MOTION +0.022s 0.00/ 0.72 ( +0.00/ +3.20)event11 POINTER_MOTION +0.034s 0.00/ 1.20 ( +0.00/ +5.34)event11 GESTURE_HOLD_BEGIN +0.040s 1event11 POINTER_MOTION +0.045s -0.22/ 1.44 ( -1.00/ +6.41)event11 POINTER_MOTION +0.056s -0.90/ 1.67 ( -4.00/ +7.48)event11 GESTURE_HOLD_END +0.056s 1 cancelledevent11 POINTER_MOTION +0.067s -1.79/ 2.39 ( -8.00/+10.68)event11 POINTER_MOTION +0.079s -2.69/ 2.39 (-12.00/+10.68)event11 POINTER_MOTION +0.090s -3.36/ 2.87 (-15.00/+12.82)event11 POINTER_MOTION +0.101s -6.49/ 5.74 (-29.00/+25.64)event11 POINTER_MOTION +0.112s -7.16/ 4.78 (-32.00/+21.36)event11 POINTER_MOTION +0.124s -8.51/ 5.26 (-38.00/+23.50)event11 POINTER_MOTION +0.135s -9.18/ 5.02 (-41.00/+22.43)event11 POINTER_MOTION +0.146s -6.72/ 2.87 (-30.00/+12.82)event11 POINTER_MOTION +0.157s -9.63/ 4.31 (-43.00/+19.23)event11 POINTER_MOTION +0.169s -9.40/ 3.35 (-42.00/+14.95)event11 POINTER_MOTION +0.180s -8.51/ 2.87 (-38.00/+12.82)event11 POINTER_MOTION +0.191s -4.70/ 0.72 (-21.00/ +3.20)...Great:
libinputprinted a bunch of trackpad events. -
So the problem became:
libinputcan read trackpad events, butlibinput-gesturescan’t.
Next, I checkedlibinput-gestures --helpto understand how it works.Terminal window $ libinput-gestures --helpusage: libinput-gestures [-h] [-c CONFFILE] [-v] [-d] [-r] [-l] [--device DEVICE]Read gestures from libinput touchpad and action shell commands.options:-h, --help show this help message and exit-c CONFFILE, --conffile CONFFILEalternative configuration file-v, --verbose output diagnostic messages-d, --debug output diagnostic messages only, do not action gestures-r, --raw output raw libinput debug-event messages only, do not action gestures-l, --list just list out environment and configuration--device DEVICE explicit device name to use (or path if starts with /)Roughly:
-dshows whether your configured gestures are being triggered
-rprints the raw events received fromlibinput
If you want to see whetherlibinput-gesturesis receiving events at all,-ris the right choice.
(I only understood this clearly after everything worked. While debugging I just tried every flag I could find.)libinput-gestures-setup stopto stop the currentlibinput-gesturesservice
libinput-gestures -r --device /dev/input/event11to check whetherlibinput-gesturescan read events fromevent11Terminal window $ libinput-gestures -r --device /dev/input/event11libinput-gestures: session KDE+x11 on Linux-6.1.**Hash: **device /dev/input/event11libinput-gestures: device /dev/input/event11: Apple Inc. Magic Trackpad 2-event11 DEVICE_ADDED Apple Inc. Magic Trackpad 2 seat0 default group1 cap:pg size 162x115mm tap(dl off)event11 POINTER_MOTION +0.867s 2.59/ 0.00 (+13.00/ +0.00)event11 POINTER_MOTION +0.878s 3.58/ 0.24 (+16.00/ +1.07)event11 POINTER_MOTION +0.889s 3.81/ 0.24 (+17.00/ +1.07)event11 POINTER_MOTION +0.900s 3.81/ 0.72 (+17.00/ +3.20)event11 POINTER_MOTION +0.912s 3.58/ 0.48 (+16.00/ +2.14)event11 POINTER_MOTION +0.923s 3.13/ 0.48 (+14.00/ +2.14)event11 POINTER_MOTION +0.934s 2.69/ 0.00 (+12.00/ +0.00)event11 POINTER_MOTION +0.945s 2.24/ 0.24 (+10.00/ +1.07)event11 POINTER_MOTION +0.957s 1.79/ 0.00 ( +8.00/ +0.00)event11 POINTER_MOTION +0.968s 2.46/ 0.24 (+11.00/ +1.07)Just like
libinput,libinput-gesturesprinted a bunch of events here. Soevent11was fine.Next, I tried
libinput-gestures -r --device /dev/input/event13to see what the other “trackpad” device was.Terminal window $ libinput-gestures -r --device /dev/input/event13libinput-gestures: session KDE+x11 on Linux-6.1.**Hash: **device /dev/input/event13libinput-gestures: device /dev/input/event13: Apple Inc. Magic Trackpad 2-event13 DEVICE_ADDED Apple Inc. Magic Trackpad 2 seat0 default group1 cap:pg size 162x115mm tap(dl off)No matter what I did on the physical trackpad, this device produced zero events.
-
So the situation was: for some reason my computer had two trackpad devices,
/dev/input/event11and/dev/input/event13.
The former worked; the latter was dead.I also checked
libinput-gestures -d:Terminal window $ libinput-gestures -dlibinput-gestures: session KDE+x11 on Linux-6.1.**Hash: **Gestures configured in ~/.config/libinput-gestures.conf:swipe up 4 xdotool key ctrl+super+Downswipe down 4 xdotool key ctrl+super+Upswipe left 4 xdotool key ctrl+super+Rightswipe right 4 xdotool key ctrl+super+Leftlibinput-gestures: device /dev/input/event13: Apple Inc. Magic Trackpad 2
Case closed: libinput-gestures was defaulting to /dev/input/event13, the device that receives no events.
As for why the system saw two trackpads and the second one had no events:
My guess is that I tested it via cable first (Lightning), then later switched to Bluetooth.
For some reason, the old “wired” device node didn’t disappear and was left behind.
Andlibinput-gestureshappened to pick that zombie device… sigh.
Make libinput-gestures Use the Right Device
So the fix is to tell libinput-gestures to use the device that actually receives events: /dev/input/event11.
I vaguely remembered seeing this in the system-level config file /etc/libinput-gestures.conf, so I opened it and read carefully.
############################################################################### This application normally determines your touchpad device automatically. Some users may have multiple touchpads but by default we use only the first one found. However, you can choose to specify the explicit device name to use. Run "libinput list-devices" to work out the name of your device (from the "Device:" field). Then add a device line specifying that name, e.g:# device DLL0665:01 06CB:76AD Touchpad# If the device name starts with a '/' then it is instead considered as the explicit device path although since device paths can change through reboots this is best to be a symlink. E.g. instead of specifying /dev/input/event12, you should use the corresponding full path link under /dev/input/by-path/ or /dev/input/by-id/.# You can choose to use ALL touchpad devices by setting the device name to "all". E.g. Do this if you have multiple touchpads which you want to use in parallel. This reduces performance slightly so only set this if you have to.# device allTurns out the author already explained it clearly: by default, libinput-gestures uses the first touchpad device it finds.
If you have multiple devices, you can explicitly specify which one to use.
device /dev/input/event11device /dev/input/by-path/pci-0000:00:****-event-mousedevice /dev/input/by-id/usb-Apple_Inc._Magic_Trackpad_2_****-event-mouseI tested it: all three approaches above can pin to a specific device.
But as the author notes, event11 is not stable across reboots, so it’s better to use a stable symlink under by-path or by-id.
There’s also a simple brute-force option:
device allUse all touchpad devices (at the cost of a bit of performance).
After thinking about it, I decided to use device all.
Sometimes I need to plug the trackpad in to charge, or switch to wired mode when Bluetooth is flaky.
The system treats wired and Bluetooth as two devices. If I pin to the Bluetooth device via by-path/by-id, then the config breaks when I switch to wired.
So I went with the “no-brain” device all.
Change Trackpad Settings via xinput
Now that libinput-gestures was fixed, multi-finger gestures started working.
Next I wanted to set trackpad options like pointer speed and natural scrolling.
In theory these can be changed in the GUI settings.
But as mentioned earlier, after waking from sleep these settings sometimes reset to defaults and can’t be changed again via the GUI.
So I looked for a CLI way to configure the trackpad.
After some searching, xinput seemed the simplest.
Usage reference: ArchWiki - xinput
xinput listto find the devicexinput list-props deviceto see available propertiesxinput set-prop device property valuesto set properties
And here I hit the same issue again: xinput also showed two trackpads.
$ xinput list⎡ Virtual core pointer id=2 [master pointer (3)]⎜ ↳ Virtual core XTEST pointer id=4 [slave pointer (2)]⎜ ↳ Logi K855 Keyboard id=11 [slave pointer (2)]⎜ ↳ Apple Inc. Magic Trackpad 2 id=9 [slave pointer (2)]⎜ ↳ Apple Inc. Magic Trackpad 2 id=13 [slave pointer (2)]⎣ Virtual core keyboard id=3 [master keyboard (2)] ↳ Virtual core XTEST keyboard id=5 [slave keyboard (3)] ↳ Power Button id=6 [slave keyboard (3)] ↳ Power Button id=7 [slave keyboard (3)] ↳ Sleep Button id=8 [slave keyboard (3)] ↳ CSCTEK USB Audio and HID id=10 [slave keyboard (3)] ↳ Logi K855 Keyboard id=12 [slave keyboard (3)]I decided to do the same thing as libinput-gestures: since I didn’t know which one was the “real” device, just configure both.
I borrowed ideas from:
Stack Overflow - ‘xinput list’ shows same device twice & device IDs change: how to use ‘set-prop’ in a script?
Stack Overflow - How to make a program that finds id’s of xinput devices and sets xinput some settings
And stitched together a script that works:
# Setup Apple Magic Trackpad 2
# Get all trackpad device idsids=$(xinput --list | grep "Trackpad" | cut -d '=' -f 2 | cut -f 1)
for id in $idsdo xinput set-prop $id "libinput Accel Speed" 0.5 xinput set-prop $id "libinput Natural Scrolling Enabled" 1done
libinput-gestures-setup restartsystemctl --user restart libinput-gestures.serviceI put this into .bashrc. Whenever the trackpad feels “off”, I can hit Ctrl+Alt+T to open a terminal and re-run it, and the trackpad becomes smooth again.
The last two lines are there because the
libinput-gesturesservice sometimes dies and needs a restart.
You can restart withlibinput-gestures-setup restart.
Or registerlibinput-gesturesas asystemduser service and restart it viasystemctlas in the script.
Forsystemdsetup, see: Github - bulletmark/libinput-gestures - SYSTEMD USER SERVICE
Summary
So the root cause was: libinput saw two trackpad devices, and libinput-gestures defaulted to the dead one, so none of my configuration worked.
After a lot of searching, I found the fix was clearly written in the documentation. I just didn’t read it carefully at the beginning… and wasted a lot of time.
Lesson learned: read the docs properly.
Trackpad 2 Experience
Overall it’s pretty good. Over Bluetooth it drops around ~20% battery per week, maybe less (I didn’t measure precisely). Battery life is decent.
Bluetooth latency feels a bit higher and it’s less stable than wired: occasionally it stops responding and reconnects after a few seconds.
Other than that, I’m happy with it. Money well spent.
Tray Icons Disappearing
After using the trackpad for a while, I noticed that sometimes some tray icons randomly disappear, and the keyboard layout resets to the default US layout and can’t be changed back. I’m not sure if it’s related to the trackpad disconnecting/reconnecting.
I searched for a command to restart the tray and added an alias to .bashrc:
alias tray_restart='kded5 --replace > /dev/null 2>&1 &'When the tray icons are gone, running tray_restart fixes it.