[Howto] Remapping buttons with xbindkeys and xte

TuxSometimes you buy devices like a mouse or a keyboard which provide additional buttons for special functions. Or which have buttons which do not behave as expected. In such cases the button actions can be mapped to other functions, or even to other buttons.

I recently bought a Logitech M705 mouse which works almost perfectly. However, there is one nagging bug: the middle mouse button does not trigger the usual event “mouseclick two” which is interpreted as pressing the middle button, the scroll wheel which is crucial for example browsing the web. Nothing happens.

In such cases the first step is to see if the operating system receives any input at all. Fire up a shell and start the program xev. It opens a small, white window where you can move your cursor to. As soon as the cursor enters the window, you will see a lot of log data on the shell: xev shows you all X events, thus all data you enter via keyboard or mouse.

In my case I pressed the middle button, and saw:

ButtonPress event, serial 40, synthetic NO, window 0x5800001,
    root 0xc7, subw 0x5800002, time 19610234, (46,38), root:(1784,61),
    state 0x10, button 6, same_screen YES
[...]
ButtonRelease event, serial 40, synthetic NO, window 0x5800001,
    root 0xc7, subw 0x5800002, time 19610234, (46,38), root:(1784,61),
    state 0x210, button 6, same_screen YES

The interesting part is that the button was not interpreted as “button 2” as I would have expected, but as “button 6”. That’s not what I expected, and thus the button must be remapped to the event “button 2”.

Mapping of keys and buttons can be done via xbindkeys: in case of KDE I created a symlink to start the program at each startup:

ls -la ~/.kde/env/xbindkeys 
lrwxrwxrwx 1 liquidat users 18 Aug  1 10:56 .kde/env/xbindkeys -> /usr/bin/xbindkeys

xbindkeys reads its configuration from ~/.xbindkeysrc, so that’s the place where we need to configure the actual mapping. The syntax is:

#    "command to start"
#       associated key

The most interesting part of the mapping is: how to trigger the action “button 2”? That is done by the program xte which generates fake input. Thus the final configuration is:

"xte 'mouseclick 2'"                                                                                                                                                                                           
  b:6  

And you are done. Pressing the mouse button 6 on the Logitech M705 now launches the mouseclick 2.

However, as stated correctly by the comments below, this is just an intermediate solution! A long time solution is to fix the mapping in evdev, the Linux input handling.