Xmouse for Windows is brilliant. And it makes a mockery of any linux desktop user’s claim to having the more customizable user environment. Well at least as far as pointers go. What Xmouse does is allow you to intercept any mouse action and translate it into any sort of user interaction, be that simply another mouse action, a keyboard action, interacting with the desktop, starting a new program, a mix of the above or (possibly) something else entirely. It has a huge list of possibilities and options, including automatically switching profiles to match the currently running program.
On linux we have a mess of a wiki page with an assortment of hacks. Googling specfic issues result in a similar cocktail of ancient xorg tools, including xkbset, xinput, xmodmap, btnx, xkbe and many more. Now, I’m not one to disparage using old, true and tested tools (see: devilspie, wmctrl) but in this case I believe, it is just poorly documented hacks as X seems to have added ‘pointers’ as somewhat of an afterthought. Poorly worded howtos, barely understood copy-and-paste suggestions and google results stretching back into the mists of time and linux make this a horrible jungle for even experienced linux users. The google problem is compounded by intersecting interests: Some want their mouse to do keyboard inputs, some want them to do commands, some want keyboard keys to serve as mouse buttons, etc.
imwheel has been brought to my attention before but a) the tool seems to have fallen from grace sometime in the previous decade (for one it was dropped from the official Arch Linux repositories and now only resides in the AUR) and b) the man page isn’t really written from the perspective of a user with a specific goal in mind and c) I do believe the semi-gui configuration helper (somewhat similar to xev) isn’t working in today’s desktop environments. So I know that I’ve tried it before and given up – if I even succeeded in building it – concluding that it was probably dead in the water.
Well, Lazarus just got up and walked. The difficulty (for me) lay in the fact that the command line options don’t really hint at how you would want to use it. You have to create a config file but then you can simply run it with ‘imwheel’ and forget about it. As simple as that. This will allow you to intercept mouse actions and get a mixture of mouse and keyboard output that can be made dependent on the currently active program. A somewhat simplistic Xmouse, then. Without the GUI.
Enough prologue let’s get to see what it does and how. The example below will attempt to make pressing one mouse button output an ‘O’ and pressing another button will output an ‘L’. Why? It’s a fairly simple test and I use it to assign the mouse buttons to actions in game configurations that do not recognise my mouse buttons.
The imwheel configuration file (~/.imwheelrc) consists of section in which the first line designates the program to which the configuration applies (so that I might assign the same key one use in Firefox and another in Borderlands). In this example we shall simply say “Match any program” so that the configuration applies universally:
Those familiar with regular expressions will recognise it as “Match any character, repeated zero or more time”. Those unfamiliar with regexes can either simply copy-paste the line (the quotes are part of the code) or do a quick tutorial on regular expressions. I recommend the latter option. It’s quick and useful knowledge that is sure to come in handy later on.
The second and following lines then detail what to intercept and what it shall be translated into. Each line is one mouse action to intercept and it’s translation.
None, Thumb1, l None, Thumb2, o
The options are separated by commas. The three options here are the only mandatory ones. The first proscribes what keys (as in keyboard keys) must be held down in order for the mouse action to be intercepted and the second option is what the mouse action to be intercepted is. You can find a list of standard mouse buttons and their imwheel input name on the imwheel man page under ‘Keysyms‘.
In the first case we simply ask to intercept presses on the mouse button referred to as Thumb1 (aka the ‘back’ button when used in a browser setting) when no keys are held down. We could have specified that this particular instruction should only be used when the button was pushed in conjunction with the left shift key. The final option in the first line simply tells imwheel to output a lowercase L when this button is pushed.
To test it, run “imwheel -dD” on a terminal (little -d switch prevents daemoning, capital -D switch turns on debugging info) and open up a text editor somewhere and see how many LOLs you can input without using the keyboard.
Right, enough play, let’s try to do something useful instead. Supposing I want the thumb buttons to work as tab switchers across the board – in Firefox, Nautilus, Gedit, The GIMP, even in GNU screen? If imwheel can accomplish that I might just consider withdrawing the ‘simplistic’ from my characterization.
Let’s take the most common solution first. Tab flipping tends to be assigned to Ctrl+PageDown (next tab / tab to the right) and Ctrl+PageUp (previous tab / tab to the left). At least that’s the case in three of the programs I mentioned above – Firefox, Nautilus and The GIMP.
imwheel can output multiple key codes at once. Instead of writing a single output code you write as many as you like, dividing them by pipes (“|”). It also allows you to output all kinds of ‘keysyms’ rather than just letters. If we look at the man page for imwheel or – for a more complete listing – this table of keysyms we should be able to find the codes for ctrl and the pageup/-down keys. Well, ctrl is easy: We even have a choice between Control_L and Control_R. But there is no PageDown, Page_Down or PageDn? Straightforward solution: Open up a terminal and enter ‘xev’ and DON’T touch the mouse (or you’ll likely flood the terminal with output). Xev tells you what codes belong to various kinds of input. So we carefully, gingerly tap a single time on the PageDown key. Here’s the part of the output that corresponds to my pressing the key:
KeyPress event, serial 36, synthetic NO, window 0x2800001, root 0x28d, subw 0x0, time 6430408, (652,823), root:(653,889), state 0x10, keycode 117 (keysym 0xff56, Next), same_screen YES, XLookupString gives 0 bytes: XmbLookupString gives 0 bytes: XFilterEvent returns: False KeyRelease event, serial 36, synthetic NO, window 0x2800001, root 0x28d, subw 0x0, time 6430478, (652,823), root:(653,889), state 0x10, keycode 117 (keysym 0xff56, Next), same_screen YES, XLookupString gives 0 bytes: XFilterEvent returns: False
You get two blocks because pressing the key and letting it go is each considered one event. You can find the keysym in the third line of either block: “Next”. Doing the same for PageUp reveals, it’s called “Prior”. So to send the output Ctrl+PageDown/PageUp we use the keysyms we’ve found and combine them with a pipe, like this:
".*" None, Thumb1, Control_L|Prior None, Thumb2, Control_L|Next
Once again you run “imwheel -dD” and hopefully you get the desired result in all of our test programs. Well, all except for Gedit and Screen. The former has the annoyingly idiosyncratic keybindings Ctrl + Alt + PageDown / PageUp. However this is no problem for imwheel as it can just as easily output three codes as two at once:
"[gG]edit" None, Thumb1, Alt_L|Control_L|Prior None, Thumb2, Alt_L|Control_L|Next
The window matching here is again regex based and translates as matching either ‘gedit’ or ‘Gedit’ (but not ‘gGedit’: two characters enter but only one character leaves). To find out possible class names for the window you wish to target I recommend using xprop:
xprop | grep -i class
and then click the crosshairs on the window in question.
GNU Screen poses the greater problem as it does not have a window – it’s an ncurses application. Supposing however, that you have one terminal (Xfce4-terminal in my case) that you’re willing to dedicate to Screen this too can be made to work:
"[Xx]fce4-terminal" None, Thumb1, Control_L|a|p None, Thumb2, Control_L|a|n
Note that imwheel sends all three key presses at the same time which isn’t usually the way people enter Screen shortcuts. I at least usually hit Ctrl+a, let go of both, then hit n/p but Screen also accepts the input fed to it by imwheel.
So yes, imwheel passed our challenge and I will henceforth refer to it as the Xmouse of Linux. Pretty damn impressive for a piece of software that does not appear to have been updated in over ten years!
One final note: imwheel looks through your blocks one by one to see if it applies to any given window that you use the keys in. Once it finds a window match, it stops. Therefore you should save the catch-all window match for last. Otherwise window-specific rules such as the ones used above will never be used by the program.
Photo by PixCat