I have two Logitech trackballs, a Wireless TrackMan FX and a Marble Mouse. Both report the same set of buttons in evtest: BTN_LEFT, BTN_RIGHT, BTN_MIDDLE, BTN_SIDE and BTN_EXTRA even though they only have four physical buttons each. The TrackMan FX sends the exact events I want: left, right, middle and side. However, the Marble Mouse sends BTN_EXTRA instead of BTN_MIDDLE, so I'd like to remap that.
This answer seems to cover exactly what I want and hwdb looks like the right place to do it. Alas, it only works halfway and I have no idea why; I suspect it has to do with the two different input events generated by a single click. evtest reports a working middle click from the FX like this (leaving out irrelevant time stamps for clarity):
type 4 (EV_MSC), code 4 (MSC_SCAN), value 90003
type 1 (EV_KEY), code 274 (BTN_MIDDLE), value 1
The unmodified click from the MarbleMouse:
type 4 (EV_MSC), code 4 (MSC_SCAN), value 90005
type 1 (EV_KEY), code 276 (BTN_EXTRA), value 1
So my 99-marblebutton.hwdb file does this:
evdev:input:b0003v046DpC408*
ID_INPUT_KEY=1
KEYBOARD_KEY_90005=btn_middle
And the resulting input event is modified thus:
type 4 (EV_MSC), code 4 (MSC_SCAN), value 90005
type 1 (EV_KEY), code 274 (BTN_MIDDLE), value 1
So I do get a BTN_MIDDLE event but the associated MSC_SCAN still has the wrong value, and that seems to make a difference as the middle click isn't recognized anywhere. In fact it doesn't even seem to be considered a valid input event at all: using libinput debug-events I can see the unmodified event:
event7 POINTER_BUTTON +97.374s BTN_EXTRA (276) pressed, seat count: 1
With the hwdb config in place, nothing is reported when I press the same button, and consequently wev doesn't see the events either.
Other things I've tried include remapping in swaywm which sort of works, but only in some applications:
set $MOUSE "1133:50184:Logitech_USB_Trackball"
bindsym --input-device=$MOUSE --whole-window BTN_EXTRA seat - cursor press BTN_MIDDLE
bindsym --input-device=$MOUSE --whole-window --release BTN_EXTRA seat - cursor release BTN_MIDDLE
interception-tools allow me to write a filter that can "fix" both the EV_KEY and the EV_MSC event, but the effect is similar to hwdb: the events show up fine in evtest but libinput doesn't even see them.
Solaar doesn't seem to support either of my devices, and I'm too thick to get input-remapper to do anything useful.