Blog Image

Custom mouse button mapping for the indecisive ambidexter

Kavin Chandrasekaran Oct 30, 2018 0 Comments

​Are you ambidextrous? Do you switch the mouse between right and left hands often? Cannot use the Logitech's software for button maps because you're on a Linux distro? Well, I was in that same situation and I realized I needed to dig up my long forgotten shell scripting.

After being able to afford a Windows license, I had forgotten my once beloved shell scripts from the good 'ol Ubuntu days, when Canonical would ship an Ubuntu CD internationally, for FREE, if you just ask for it. Now that Microsoft has worked so hard to drive me crazy with their uninstallable bloatware and incessant updates I am back on Ubuntu.

I often switch my mouse between right and left depending on my mood or because of a mess I made on one side of the table and I am not ready to clean up just yet. My friends think I have an evil alter-ego who is left-handed and he just takes over on my bad days; I am not entirely dismissing that theory yet. Ever since the serious real-estate upgrade of my displays, I wanted to get something with a trackball (SERIOUSLY! who wants to keep dragging the wrist around to get from one end to another), I went old school and got this wonderful Logitech Trackman. I got it partially because of the ambidexterity support; okay, because it was the only one I could find. To sum it up, it is awesome!, a bliss too adapt and extremely comfortable to use.

But just plugging it in and using in Ubuntu 18.04, it had it's drawbacks. My major issue was with the lack of the scroll wheel functionality. Google came to the rescue and pointed me to what I could do about it.

All I had to do was to write a tiny script to turn on wheel emulation and assign a button to use in combination with the trackball to make it a wheel. Jordi Castells it in a detailed way (Did you notice the pun. Huh-huh). Check his post for button maps and how to decide on the numbers to use in the commands.

Below is the script to enable wheel for right hand button map.

#!/bin/bash

xinput set-int-prop "Logitech USB Trackball" "Evdev Wheel Emulation Button" 8 8

xinput set-int-prop "Logitech USB Trackball" "Evdev Wheel Emulation" 8 1

xinput set-int-prop "Logitech USB Trackball" "Evdev Middle Button Emulation" 8 1

xinput set-button-map "Logitech USB Trackball" 1 9 3 4 5 6 7 8 2

xinput set-prop "Logitech USB Trackball" "Device Accel Constant Deceleration" 0.7

notify-send -t 3000 "Changed mouse to right-hand profile"

Run it when you feel like switching to right, or call it from your ~/.xprofile and it runs at the beginning of every session. Easy peasy right. Nope.

Notice the parameter to set the Wheel Emulation is using the the Evdev set of drivers. But Ubuntu 18.04 came with libinput input drivers. The fix turned out to be really easy, or at least it worked and hasn't broken anything else. Just switch the drivers to Evdev.

sudo apt remove xserver-xorg-input-libinput

sudo apt install xserver-xorg-input-evdev

Now the script runs and the mouse wheel functionality works. TADA!!. But wait, I wasn't done yet. I need a script for my left-handed days and I need a desktop shortcut where I can switch between right-handed and left-handed profiles.

Script for changing to left-hand button map:

#!/bin/bash

xinput set-int-prop "Logitech USB Trackball" "Evdev Wheel Emulation Button" 8 9

xinput set-int-prop "Logitech USB Trackball" "Evdev Wheel Emulation" 8 1

xinput set-int-prop "Logitech USB Trackball" "Evdev Middle Button Emulation" 8 1

xinput set-button-map "Logitech USB Trackball" 3 8 1 4 5 6 7 2 9

xinput set-prop "Logitech USB Trackball" "Device Accel Constant Deceleration" 0.7

The desktop file contains:

[Desktop Entry]

Encoding=UTF-8

Version=1.1

Type=Application

Terminal=false

Exec=/home/user/scripts/mouse/trackball_left.sh

Name= Trackman - Left

Icon=/home/user/scripts/mouse/mouse_left.png

Everything worked peachy, albeit the overhead of having to run the appropriate desktop app to change the profile.

Then came the need for remembering the last-activated profile. If I had the right-hand map profile in .xprofile file, and it was a left-handed week, I had to awkwardly double-click with my left pinky to activate the left-hand profile. I can't have THAT!

So I added a line to the end of both the scripts to write the profile being activated to a scratch file.

In the left-hand profile script:

echo "left" > "/home/user/scripts/mouse/last_mouse_position"

In the right-hand profile script:

echo "right" > "/home/user/scripts/mouse/last_mouse_position"

Then I used another script to look at the scratch file and decide with script corresponding to the last profile needs to be called. I call it the mouse_switcher.sh:

#!/bin/bash

line=$(head -n 1 "/home/user/scripts/mouse/last_mouse_position")

if [[ $line == 'left' ]]; then

source "/home/user/scripts/mouse/trackball_left.sh"

elif [[ $line == 'right' ]]; then

source "/home/user/scripts/mouse/trackball_right.sh"

fi

Now I just needed to add the mouse_switcher.sh to the .xprofile file or the your preferred way of startup scripts.

I was pretty happy with this setup for a while and then came the use-case of sharing the mouse between my workstation and my laptop. I had the same version of Ubuntu so I just replicated the scripts. I had to use an USB switch to share the keyboard and mouse between machines when they were both running; which in-turn means the scripts set to run during the system startup or session initialization wouldn't be triggered. So, the mouse would essentially be with the default button mapping whenever you switch between machines. I needed something to capture the event of the mouse being plugged-in and then trigger the mouse_switcher.sh script. Light bulb

I created a new file /etc/udev/rules.d/mouse_profiler.rules containing the below line:

ACTION=="add", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="c408", RUN+="/home/user/scripts/mouse/mouse_switcher.sh"

I plug in the mouse and the script gets triggered aaand the mouse still has the default button map. Pretty frustrating. After a lot of scouring online forums, I found out that xinput is refreshed after the udev rules are executed. Just great. I tried delayed script run using sleep, but that didn't work either. I wasn't ready to give up and I came across this beautiful idea of using inotify watchers. Inotify is a monitoring system looking over the filesystem. You can setup inotify watchers to do a certain action if a file is being modified or deleted or accessed, etc.

The final solution is to have a inotify watcher looking for modifications to a scratch file, that gets modified whenever the mouse is plugged in. We already know how to do that. In the udev rules file /etc/udev/rules.d/mouse_profiler.rules, instead of calling mouse_switcher.sh:

ACTION=="add", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="c408", RUN+="/home/user/scripts/mouse/trigger_mouse_connect.sh"

trigger_mouse_connect.sh contains:

#!/bin/bash

lock="/home/kavin/scripts/mouse/mouse_profile.lock"

exec 9>"$lock"

if ! flock -n 9; then

exit 1

fi

echo "Profile Change triggered - $(date)" > $lock &

Then the only remaining step is to setup the inotify watcher. You can set it up in the ~/.xprofile file so it runs at the beginning of every session.

file-inotify ~/scripts/mouse/mouse_profile.lock ~/scripts/mouse/mouse_switcher.sh &

That's it, after 4 hours I was able to keep switching between computers to my heart's content, without having to do anything to keep my stupid scroll wheel.

2 Comments

Leave a Comment