Customising keyboard maps in Linux is somewhat … confused with lots of different tools and layers to perform the same task. There are a number of tools for performing some form of keyboard mapping, but the most common ones have some disadvantages :-
- xkb (which is the modern X way), and xmodmap (which is deprecated but conveniently has a very simple syntax for dealing with a single key) both work fine for ordinary keys but cannot do anything with “unusual” keys not passed into X. Just look online for just how many people have trouble with multimedia keys not being recognised.
- The PS/2-specific tools of dumpkeys, loadkeys, and setkeycodes which work fine, but are somewhat reluctant to help out with USB keyboards.
- Plus the desktop environment you are using may well have its own idea of how the keyboard will be used (GNOME has a nasty tendency to grab the menu key away from me).
There is fortunately another way which is rather difficult to find information about. Which is the reason behind this posting of course.
This “other method” is to use the generic input system to perform the keyboard mapping which has certain advantages over other methods. Most of the information to do this came from a README file contained within the source code.
The Example Keyboard
To demonstrate keyboard mapping, it is helpful to have an example keyboard with custom mappings to play with. Many of the keyboards I use this for are rather complex with many mappings, but I also have a mini keyboard with relatively few mappings :-
Original Key | new function |
---|---|
Esc | Lock screen |
`/~ | Esc |
Caps Lock | Control |
Insert | Delete |
Delete | `/~ |
No great mystery as to why I want my keyboard mapped this way – I’m just fussy about keyboards.
The Basic “Tool”
In fact there is just one tool – /lib/udev/keymap – which performs all of the relevant tasks. Before it can do anything, it needs to be provided with the path of the relevant input device. This is easiest done from the console (rather than in X) as root. The easiest way of identifying the device is to unplug the keyboard, reboot the machine, and :-
# ls /dev/input/e* > /var/tmp/old.list [Plug in keyboard] # ls /dev/input/e* > /var/tmp/new.list # diff /var/tmp/old.list /var/tmp/old.list > /dev/input/event13 > /dev/input/event14
If you are lucky, there will be just one new input device. If not, you will have to try each one in turn. The first job is to record the keycode of each key to be customised in turn. To do this, it is necessary to run keymap with the input device and the “-i” option, and each keystroke will result in some output :-
# /lib/udev/keymap /dev/input/event13 -i Press ESC to finish, or Control-C if this device is not your primary keyboard scan code: 0x70029 key code: esc # /lib/udev/keymap /dev/input/event13 -i Press ESC to finish, or Control-C if this device is not your primary keyboard scan code: 0x70035 key code: grave scan code: 0x70039 key code: capslock scan code: 0x70049 key code: insert scan code: 0x7004C key code: delete
A key can be mapped temporarily using keymap. But before that a list of possible key names is useful to have; there is one to be found in /usr/include/ :-
# grep KEY_ /usr/include/linux/input.h | less
The relevant name would be the part that follows the “KEY_” converted to lower-case.
# /lib/udev/keymap /dev/input/event13 0x70035 esc
But that is rather a temporary solution; it is better by far to create a file containing the necessary mappings to be automatically applied :-
# cat /tmp/custom-filco.map 0x70029 screenlock # Original: key code: esc 0x70035 esc # Original: key code: grave 0x70039 leftctrl # Original: key code: capslock 0x70049 delete # Original: key code: insert 0x7004C insert # Original: key code: delete
Making The Mappings Permanent
The first step is to obtain some details to uniquely (or as much as possible) identify the keyboard. Run :-
# udevadm info --export-db > /tmp/udev-db.txt
And look through the output for the input device you previously used. Look for a ID_VENDOR_ID and ID_MODEL_ID that you can use.
Next add a rule to /lib/udev/rules.d/95-keymap.rules along the lines of :-
ENV{ID_VENDOR_ID}=="04d9", ENV{ID_MODEL_ID}=="2011", RUN+="keymap $name custom-filco.map"
Once this is working you may want to add it to your version of custom-filco.map as a comment to preserve it for use after upgrades; alternatively you may wish to create a new file that will not get overwritten.
Before activating the new rule, remember to copy /tmp/custom-filco.map into /lib/keymaps/custom-filco.map. And again keep another copy in a safe place to preserve.
As to how to activate, a reboot is probably the simplest way.