http://techtrickery.com/pedals.html
Typical Technological Trickery
Linux programming tricks
Using foot pedals for modifier keys in Linux
20 Oct 2014
Update 2016-07-23: Updated the format of the udev rules for recent
Linux distributions (in Ubuntu since at least 16.04, possibly
earlier), thanks to an anonymous reader for the tip!
The constant use of modifier keys in emacs can be painful, hence the
term "emacs pinky". A good way to reduce the strain on your hands due
to modifier keys is to use your feet instead! With this in mind I
bought a cheap set of usb pedals, and bound them to the control, alt
and super keys. Since the process of binding the pedals to the
appropriate keys turned out to be fairly complex, and not documented
anywhere else, I've written this post as instructions both to myself
in the future and to anyone else wishing to explore the use of pedals
to reduce rsi.
We perform the binding in two steps: First we set up a low level
binding of the pedals to somes key that does not clash with any key
on the real keyboard. I've chosen to bind the pedals to F13-F15, in X
they correspond to those extra keys, sometimes found above the normal
function keys, which launch an email client, web browser, etc. The
instructions for setting up this binding are detailed in the next
section. The second step is then to use xmodmap to bind this key to
the desired final key.
Note: we could just set the pedals to send keycodes for modifiers
directly and skip the second step. However binding them to some
intermediate scancode gives much more flexibility and makes it much
easier to change the configuration. In particular modifying the
keybinds only requires running a shell command instead modifying a
config file (which requires root) and rebooting.
Before beginning the instructions I should explain a little about how
keys are bound to actions. At the lowest level the hardware sends a
scancode. Then udev converts this scancode to a keycode. Finally
X-windows recieves the keycode and applies any additional rules (such
as those set using xmodmap) before sending the keypress to the
application.
(The following instructions may be somewhat specific to Ubuntu-based
systems, I haven't tried this out on anything else.)
Setting the pedal scancodes to appropriate keycodes (in udev)
So first of all we need to make sure that the keycodes sent by the
pedals don't clash with pre-existing keys. Unfortunately mine send a,
b and c by default, which is completely useless.
To achive this we need to write a new configuration file for hwdb (in
older vesions of Ubuntu I was able to use another approach). The
details of the syntax for this configuration file is explained in the
file 60-keyboard.hwdb, on my system (Ubuntu 16.04) it is stored in /
lib/udev/hwdb.d/60-keyboard.hwdb. The configuration file entry
consists of two parts: first an identifier for the keyboard, then a
list of scancodes sent by the hardware and the keycodes that they
should be interpreted as.
From the documentation, the format for the generic input device
matchers is:
# evdev:input:bZZZZvYYYYpXXXXeWWWW-VVVV
# This matches on the kernel modalias of the input-device, mainly:
# ZZZZ is the bus-id (see /usr/include/linux/input.h BUS_*), YYYY, XXXX and
# WWW are the 4-digit hex uppercase vendor, product and version ID and VVVV
# is an arbitrary length input-modalias describing the device capabilities.
To find the "4-digit hex uppercase vendor" (YYYY) and the "4-digit
hex uppercase product" (XXXX) we can use the lsusb command. This
displays a list of usb devices, each something like:
Bus 002 Device 016: ID 0c45:7403 Microdia Foot Switch
On the line corresponding to the foot switch, the pair of hex numbers
in the 6th column are the required YYYY and XXXX. Note that we also
need to convert any hex letters to upper case. So in this case YYYY =
0C45, XXXX = 7403. I left the bus-id, version ID and "input-modalias
describing the device capabilities" (whatever that means) as * which
seems to work as a glob. So the final identifier is
evdev:input:b*v0C45p7403e*-*
For the next step we need to obtain the scancodes of the pedals. We
use the command
sudo evtest
(a huge thankyou to VVayfarer on superuser for explaining how to do
this). This gives a list of devices to choose from, choose the device
corresponding to the pedals. Next press each pedal in turn to get
some information about the key and scan codes. The output we are
interested in is the line that looks something like:
Event: time 1413813459.045323, type 4 (EV_MSC), code 4 (MSC_SCAN), value 70005
which tells us that the scancode for this pedal is 70005. The
documentation in 60-keyboard.hwdb, specifies the format for scancode
to keycode bindings as:
# Scan codes are specified as:
# KEYBOARD_KEY_=
# The scan code should be expressed in hex lowercase and in
# full bytes, a multiple of 2 digits. The key codes are retrieved
# and normalized from the kernel input API header.
So if we have the scancode 70005 and we want to bind it to F14 we
would write
KEYBOARD_KEY_70005=f14
The final result should look something like this
keyboard:usb:v0C45p7403*
KEYBOARD_KEY_70004=f13
KEYBOARD_KEY_70005=f14
KEYBOARD_KEY_70006=f15
and should be added to the file /etc/udev/hwdb.d/
90-custom-keyboard.hwdb. Finally, to update the database, you need to
run the command
sudo udevadm hwdb --update
and reboot your computer. (The arch linux wiki states that you can
run the command sudo udevadm trigger instead of rebooting, but that
doesn't work for me. Possibly because it requires a newer version of
something.)
Binding the keycodes to modifiers (in X)
So now we have pedals that are bound to some unique keycodes. Next we
need to bind the keycodes to the desired modifiers. This is made
slightly more complex by X and hwdb having different names for keys,
for the keys I used:
hwdb | X
-----------------
f13 | XF86Tools
f14 | XF86Launch5
f15 | XF86Launch6
An easy way to determine the names of keys is to open up emacs and
press the keys, if they are unbound then emacs will display something
like is undefined. Alternatively the always handy xev
command can be used.
I wanted to bind the pedals to control, alt and super respectively.
The following commands take care of this using xmodmap
xmodmap -e "keycode any = XF86Tools" -e "keysym XF86Tools = Control_L"
xmodmap -e "keycode any = XF86Launch5" -e "keysym XF86Launch5 = Alt_L"
xmodmap -e "keycode any = XF86Launch6" -e "keysym XF86Launch6 = Super_L"
The keycode any = XF86Tools command ensures that xmodmap has some
binding for XF86Tools. The keysym XF86Tools = Control_L command is
just the standard keybinding command, it sets XF86Tools to be
Control_L.
If you have any questions, comments or if something doesn't work
please feel free to email me.
Work
I work on building affordable financial infrastructure for
sub-Saharan Africa at Wave mobile money.
Emacs Projects
* electric-operator
Insert spacing around operators as you type
* terminal-here
Open a terminal emulator in a file's directory
* frames-only-mode
Play nicely with tiling window managers
* aggressive-fill-paragraph-mode
Autofill paragraphs as you type
* fill-function-arguments
Line wrap/unwrap function arguments
* emacs-read-stdin
An alias that can read from stdin
Other Projects
* ankicli
Command line interface for Anki
* polish-nonsense
Generate grammatically correct Polish
Etc
[GitHub-Mar] [rss]
* About me