Goals:
- Write a script to remap mouse buttons
- Run the script when the wireless mouse is connected
This is my mouse:
The default right-click is the bottom right button, but I would like to use the top right button instead.
Remap mouse buttons
First, xinput
gives the id and name assigned to my mouse. Then, xinput list 18(device id)
gives information about all buttons on my mouse.
$ xinput
...
⎜ ↳ Expert Wireless TB Mouse id=18 [slave pointer (2)]
$ xinput list 18
Expert Wireless TB Mouse id=18 [slave pointer (2)]
Reporting 7 classes:
Class originated from: 18. Type: XIButtonClass
Buttons supported: 9
Button labels: "Button Left" "Button Middle" "Button Right" "Button Wheel Up" "Button Wheel Down" "Button Horiz Wheel Left" "Button Horiz Wheel Right" "Button Side" "Button Extra"
$ xinput
...
⎜ ↳ Expert Wireless TB Mouse id=18 [slave pointer (2)]
$ xinput list 18
Expert Wireless TB Mouse id=18 [slave pointer (2)]
Reporting 7 classes:
Class originated from: 18. Type: XIButtonClass
Buttons supported: 9
Button labels: "Button Left" "Button Middle" "Button Right" "Button Wheel Up" "Button Wheel Down" "Button Horiz Wheel Left" "Button Horiz Wheel Right" "Button Side" "Button Extra"
However, the labels are quite confusing. To find out which button is pressed, run xinput test 18(device id)
and press buttons you want to switch.
$ xinput test 18
button press 8
button release 8
button press 3
button release 3
$ xinput test 18
button press 8
button release 8
button press 3
button release 3
This is much clearer than the “Button Side”. To remap buttons, simply use xinput set-button-map $mouse_id 1 2 8 4 5 6 7 3 9
which switches 3
and 8
.
Problem: When I restart the laptop, everything goes back to the default settings. With the help of StackOverflow, I created a script called remap_mouse_buttons.sh
:
mouse_id=$(xinput list | grep "Expert Wireless TB Mouse" | sed 's/^.*id=\([0-9]*\)[ \t].*/\1/')
xinput set-button-map $mouse_id 1 2 8 4 5 6 7 3 9
mouse_id=$(xinput list | grep "Expert Wireless TB Mouse" | sed 's/^.*id=\([0-9]*\)[ \t].*/\1/')
xinput set-button-map $mouse_id 1 2 8 4 5 6 7 3 9
I added this to the Start Up Applications. Unfortunately, this didn’t work because if I didn’t connect the mouse when the computer started, the system wouldn’t find the device let alone remap buttons.
NOTE: I highly recommend you keep track of the error message by changing the second line to:
xinput set-button-map $mouse_id 1 2 8 4 5 6 7 3 9 2>&1 | sudo tee /home/yourusername/error.txt
xinput set-button-map $mouse_id 1 2 8 4 5 6 7 3 9 2>&1 | sudo tee /home/yourusername/error.txt
Additional resources:
Run the script when the mouse is connected
What I should do is executing the script when the mouse is connected via Bluetooth. udev rules are perfect for this job.
This tutorial on how to write basic udev rules helped me a lot.
# Where custom made rules are
$ cd /etc/udev/rules.d/
# The naming convention is xx-description.rules. "xx" is a number, and the larger it is, the later it will be executed
$ sudo touch 88-remapmouse.rules
# Where custom made rules are
$ cd /etc/udev/rules.d/
# The naming convention is xx-description.rules. "xx" is a number, and the larger it is, the later it will be executed
$ sudo touch 88-remapmouse.rules
Before writing rules, we need to gather information about the device. Run udevadm monitor
and reconnect the device to get its path. Then, run udevadm info
to get detailed information.
$udevadm monitor
monitor will print the received events for:
UDEV - the event which udev sends out after rule processing
KERNEL - the kernel uevent
KERNEL[8572.460135] remove /devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:3585 (bluetooth)
KERNEL[8572.465756] add /devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:3585 (bluetooth)
UDEV [8572.525910] remove /devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:3585 (bluetooth)
UDEV [8572.582738] add /devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:3585 (bluetooth)
# The output has been truncated
$ udevadm info -ap /devices/pci0000:00/00:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:3585
...
looking at device '/devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:3585':
KERNEL=="hci0:3585"
SUBSYSTEM=="bluetooth"
DRIVER==""
...
looking at parent device '/devices/pci0000:00/0000:00:14.0/usb1/1-7':
KERNELS=="1-7"
SUBSYSTEMS=="usb"
DRIVERS=="usb"
...
ATTRS{idProduct}=="0a2b"
ATTRS{idVendor}=="8087"
...
$udevadm monitor
monitor will print the received events for:
UDEV - the event which udev sends out after rule processing
KERNEL - the kernel uevent
KERNEL[8572.460135] remove /devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:3585 (bluetooth)
KERNEL[8572.465756] add /devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:3585 (bluetooth)
UDEV [8572.525910] remove /devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:3585 (bluetooth)
UDEV [8572.582738] add /devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:3585 (bluetooth)
# The output has been truncated
$ udevadm info -ap /devices/pci0000:00/00:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:3585
...
looking at device '/devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:3585':
KERNEL=="hci0:3585"
SUBSYSTEM=="bluetooth"
DRIVER==""
...
looking at parent device '/devices/pci0000:00/0000:00:14.0/usb1/1-7':
KERNELS=="1-7"
SUBSYSTEMS=="usb"
DRIVERS=="usb"
...
ATTRS{idProduct}=="0a2b"
ATTRS{idVendor}=="8087"
...
Now we have enough info to write the 88-remapmouse.rules
:
ACTION=="add",\
SUBSYSTEMS=="usb",\
ATTRS{idProduct}=="0a2b",\
ATTRS{idVendor}=="8087",\
ENV{DISPLAY}=":0.0",\
ENV{XAUTHORITY}="/run/user/1000/gdm/Xauthority",\
RUN+="/home/lisixian/remap_mouse.sh"
ACTION=="add",\
SUBSYSTEMS=="usb",\
ATTRS{idProduct}=="0a2b",\
ATTRS{idVendor}=="8087",\
ENV{DISPLAY}=":0.0",\
ENV{XAUTHORITY}="/run/user/1000/gdm/Xauthority",\
RUN+="/home/lisixian/remap_mouse.sh"
==
match the value
=
assign a value (overwrite)
+=
add another value
The script seems daunting, but what it says is simply “When the device with matching values is detected(connected), run /home/lisixian/remap_mouse.sh
(the script in the first section)“.
NOTE: ENV{DISPLAY}=":0.0"
and ENV{XAUTHORITY}="/run/user/1000/gdm/Xauthority
are important. From the tutorial:
Those variables are essential when interacting with the X server programmatically, to setup some needed information: with the
DISPLAY
variable, we specify on what machine the server is running, what display and what screen we are referencing, and withXAUTHORITY
we provide the path to the file which contains Xorg authentication and authorization information.
I got Cannot connect to X server
error without these two lines.
Finally!
udevadm control --reload # reload all rules
udevadm control --reload # reload all rules
Now, disconnect your device and connect again to see the results.