$_ BSDHowTo.ch
How To... Why not..? Scripts RSS logo

How to make extra keys on pointing devices work

Last update: 2018-08-14

Introduction

In this post I show you how I made the backward and forward keys work on my mouse and trackball. You can use this as a template to make any key on a pointing device execute any action you want. It is all about remapping keys on pointing devices the right way.

I have successfully tested the steps in this post using a Logitech Performance MX mouse and a Logitech MX Ergo trackball. These two devices report the same button number for the forward and backward buttons as for the scroll wheel.

Find out how keys are reported

First, you have to find out how many keys your mouse reports to OpenBSD. Use dmesg(8) and grep(1) for the job:

$ dmesg | grep ums
ums0 at uhidev1 reportid 2: 16 buttons, Z and W dir
wsmouse0 at ums0 mux 0

The device supports 16 buttons as well as Z and W direction reporting. The Z direction is for scrolling up and down, while the W direction is for scrolling left and right.

Next, you have to find out which physical button is reported with which logical number. For this you can use xev(1). This will generate a lot of output in the terminal window, so I redirect it to a text file:

$ xev -event mouse > mouse.txt

I use this order for the keys on my pointing devices:

  1. Left button
  2. Middle button (Wheel)
  3. Right button
  4. Wheel up
  5. Wheel down
  6. Wheel left
  7. Wheel right
  8. Backward button
  9. Forward button

Analyze the reporting

Open mouse.txt in your $EDITOR and remove all the events that are not ButtonPress events. In the end your list will look similar to mine:

ButtonPress event, serial 25, synthetic NO, window 0x3600001,
    root 0x299, subw 0xa01c4b, time 18519290, (89,89), root:(347,234),
    state 0x10, button 1, same_screen YES

ButtonPress event, serial 25, synthetic NO, window 0x3600001,
    root 0x299, subw 0x0, time 18522174, (89,89), root:(347,234),
    state 0x10, button 2, same_screen YES

ButtonPress event, serial 25, synthetic NO, window 0x3600001,
    root 0x299, subw 0xa01c4c, time 18525786, (89,89), root:(347,234),
    state 0x10, button 3, same_screen YES

ButtonPress event, serial 25, synthetic NO, window 0x3600001,
    root 0x299, subw 0x0, time 18527848, (89,89), root:(347,234),
    state 0x10, button 4, same_screen YES

ButtonPress event, serial 25, synthetic NO, window 0x3600001,
    root 0x299, subw 0xa01c4d, time 18529090, (89,89), root:(347,234),
    state 0x10, button 5, same_screen YES

ButtonPress event, serial 25, synthetic NO, window 0x3600001,
    root 0x299, subw 0xa01c4e, time 18531062, (89,89), root:(347,234),
    state 0x10, button 6, same_screen YES

ButtonPress event, serial 25, synthetic NO, window 0x3600001,
    root 0x299, subw 0xa01c4f, time 18532322, (89,89), root:(347,234),
    state 0x10, button 7, same_screen YES

ButtonPress event, serial 25, synthetic NO, window 0x3600001,
    root 0x299, subw 0xa01c50, time 18534152, (89,89), root:(347,234),
    state 0x10, button 4, same_screen YES

ButtonPress event, serial 25, synthetic NO, window 0x3600001,
    root 0x299, subw 0x0, time 18535288, (89,89), root:(347,234),
    state 0x10, button 5, same_screen YES

This drawing visualizes what actually is reported by the different parts involved, from the pointing device to the application getting an event from X11.

Button mapping

Adapt the config of Xorg

The ws(4) driver for Xorg provides config options to remap the Z and W axis. This allows you to shift the movements of the scroll wheel to other logical button numbers. Add the following section to /etc/X11/xorg.conf:

Section "InputClass"
    Identifier "Your Mouse"
    MatchDriver "ws"
    Driver "ws"
    Option "Buttons" "16"
    Option "Device" "/dev/wsmouse"
    Option "Floating" "false"
    Option "WAxisMapping" "10 11"
    Option "ZAxisMapping" "8 9"
EndSection

This trick will only work if your mouse reports enough keys to the driver. With this you remap the wheel movements to else unused button numbers.

Remap the mouse keys

The remapping in xorg.conf(5) is only one half of the process. The input from the driver is processed again by the upper layer of Xorg. You need to change the button mapping there too in order to get the desired result. Use xmodmap(1) in your ~/.xsession for this:

xmodmap -e "pointer = 1 2 3 8 9 10 11 4 5 6 7 12 13 14 15 16"

Now you should be able to use the backward and forward buttons of your mouse as expected, at least in your browser of trust.

The final mapping of buttons looks like this in the visualization:

Final mapping

The technical details

Back in the days when the X Window System was designed all mice had a maximum of three buttons and two axes (X and Y). Nobody imagined back then that mice would get more axes, but it seemed reasonable to assume that more buttons could be a thing in the future.

Modern pointing devices have one or more wheels. And by design the movements of the wheels are reported as additional axes. Wheels on mice are a success story, so people using X11 wanted to use the wheels too. The developers decided to map additional axes simply to buttons, because adding buttons in X11 is easy. The next free button numbers are 4 and 5, so the positive and negative movement along the Z axis is mapped to these two buttons. That worked very well, so the same schema was applied for the W axis, this time to the buttons 6 and 7. Your trouble begins when you connect a pointing device that has more than the usual three physical buttons on it and you want to use these. The pointing device reports the wheel movements as axes. The additional buttons are simply counted up, beginning with button 4.