The Kensington Expert Mouse and Slimblade trackballs have four buttons and a scrollwheel, and I have my personal preference for their layout. There is a utility program available for Windows and macOS to customise the button mapping, but no equivalent program exists for Linux. Fortunately it doesn’t need to, because under Linux there are multiple ways to alter the button-click events sent by input devices; I tried the not-so-new-any-more hotness that is udev before settling on a simple X Windows xorg configuration file.

Xorg approach

X Windows includes the Xorg configuration file system, usually located at /etc/xorg.conf.d. Following the somewhat standard Linux approach, filenames in this directory should be prefixed with a number between 0 and 100, which denotes the order in which they are processed. Cutting to the chase, I created a file named 50-trackball.conf, with the following content:

Section “InputClass”
Identifier “libinput Kensington trackball”
MatchDevicePath “/dev/input/event*”
MatchVendor “047d”
MatchProduct “Kensington Slimblade Trackball”
Driver “libinput”
Option “ButtonMapping” “3 2 1”
Option “DragLockButtons” “2 3”
EndSection

It is necessary to restart X Windows to have it re-read the contents of /etc/xorg.conf.d. The simplest way to achieve this is to log out and back in. Here’s what each line does:

  • Identifier “libinput Kensington trackball”
    This is simply a label for the entry; can be anything.
  • MatchDevicePath “/dev/input/event*”
    Which /dev input event streams to monitor. I’ve configured this to ‘all of them’ to save me the grief of working out which one the trackball appears at. It might even change each time the trackball is reconnected, I don’t know.
  • MatchVendor “047d”
  • MatchProduct “Kensington Slimblade Trackball”
    These are used to decide whether the event data should be filtered. The vendor id can be determined using lsusb – it’s the first of the two hex IDs on the row for the Kensington trackball in that command’s output.
  • Driver “libinput”
    Which device driver I would like to have process events for this stream.
  • Option “ButtonMapping” “3 2 1”
    Okay, finally we’re getting to the meat of this. The syntax here is “which physical button should send left button events, which sends middle button events, and which sends right button events”. “3 2 1” flips the front-left (1) and front-right (3) buttons of the trackball to get left-handed behaviour, whilst assigning the back-left button (2) as middle button.
  • Option “DragLockButtons” “2 3”
    When using a trackball it is not comfortable to hold a button down whilst dragging, so this syntax means that a single click of the back-left button starts a drag at the current cursor position. Front-right terminates the drag at the new current cursor position.

The above configuration is fully set-and-forget; I use a KVM switch and yet the configuration is applied faithfully whenever the trackball is assigned to the Linux laptop.

Udev approach

This is what I tried before settling upon the Xorg configuration above (or rather, before this post set me straight). Udev sends events when new devices are plugged in, and has a built-in system to write rules to trigger actions based on those events. As mentioned above, I use a KVM switch and therefore thought it’d be necessary to reconfigure the trackball setup every time I switch it to the Linux laptop. I therefore wrote a udev rule that detected the connection and ran a script that would perform the configuration. Here is the rule (written to a file at /etc/udev/rules.d/80-trackball.rules):

ATTRS{idVendor}==”047d”, ATTRS{idProduct}==”2041″, OWNER=”<your username>“, ACTION==”bind”, RUN+=”<full path to configuration script>”

Once again, idVendor and idProduct can be determined using lsusb, owner is the user as which to perform actions. The script I ran is here; the gist is that it runs xinput and parses the output to find the dynamically-assigned usbId, then again uses xinput to apply the button configuration desired. In testing, the udev rule would fire reliably when the trackball was connected, but xinput would for some reason not list the trackball device. The exact same script worked fine when run interactively. It’s not a timing issue – it worked no better if I put 5 seconds delay in the script to allow everything to notionally ‘settle’. I include this failed approach more as a reminder to myself what not to try¬† when I move from X Windows to Wayland and no longer have Xorg input device configuration as an option :->