There are a lot of players between your keyboard and the process that finally handles the keyboard event. Among the major pieces of the landscape are the fact that the X system has its own keyboard-handling layer, and X associates different "keycodes" with keys than your Linux base system does. The showkey
command is showing you the keycodes in Linux-base-system lingo. For xmodmap
you need the X keycodes, which are what xev
is displaying. So long as you're planning to work in X and do your key rebinding with xmodmap
, then, ignore showkeys
and just listen to what xev
says.
What you want to look for in your xev
output are blocks like this:
KeyPress event, serial 27, synthetic NO, window 0x1200001,
root 0x101, subw 0x0, time 6417361, (340,373), root:(342,393),
state 0x0, keycode 64 (keysym 0xffe9, Alt_L), same_screen YES,
XLookupString gives 0 bytes:
XmbLookupString gives 0 bytes:
XFilterEvent returns: False
KeyRelease event, serial 27, synthetic NO, window 0x1200001,
root 0x101, subw 0x0, time 6417474, (340,373), root:(342,393),
state 0x8, keycode 64 (keysym 0xffe9, Alt_L), same_screen YES,
XLookupString gives 0 bytes:
XFilterEvent returns: False
xev
tends to generate a lot of output, especially when you move your mouse. You may have to scroll back a while to find the output you're looking for. In the previous output, we see that the keysym Alt_L
is associated with the X keycode 64
.
First find the scancode of the key that needs to be remapped, e.g. with the evtest
utility. A line like the following one (with MSC_SCAN
in it) should be output:
Event: time 1417131619.686259, type 4 (EV_MSC), code 4 (MSC_SCAN), value 70068
followed by a second one giving the current key code. If no MSC_SCAN
line is output, this is due to a kernel driver bug, but the scancode can still be found with the input-kbd
utility; evtest
should have given the key code, so that it should be easy to find the corresponding line in the input-kbd
output (e.g. by using grep
).
Once the scancodes of the keys to be remapped have been determined, create a file such as /etc/udev/hwdb.d/98-custom-keyboard.hwdb
containing the remappings. The beginning of the file /lib/udev/hwdb.d/60-keyboard.hwdb
gives some information. In my case (which works), I have:
evdev:input:b0003v05ACp0221*
KEYBOARD_KEY_70035=102nd # Left to z: backslash bar
KEYBOARD_KEY_70064=grave # Left to 1: grave notsign
KEYBOARD_KEY_70068=insert # F13: Insert
(Before udev 220, I had to use keyboard:usb:v05ACp0221*
for the first line.)
The evdev:
string must be at the beginning of the line.
Note that the letters in the vendor and product id should be capital letters.
Each KEYBOARD_KEY_
settings should have exactly one space before (note: a line with no spaces will give an error message, and a line with two spaces were silently ignored with old udev versions). KEYBOARD_KEY_
is followed by the scancode in hexadecimal (like what both evtest
and input-kbd
give). Valid values could be obtained from either the evtest
output or the input-kbd
output, or even from the /usr/include/linux/input.h
file: for instance, KEY_102ND
would give 102nd
(by removing KEY_
and converting to lower case), which I used above.
After the file is saved, type:
udevadm hwdb --update
to (re)build the database /etc/udev/hwdb.bin
(you can check its timestamp). Then,
udevadm trigger --sysname-match="event*"
will take the new settings into account. You can check with evtest
.
In 2014, the released udev had incomplete/buggy information in /lib/udev/hwdb.d/60-keyboard.hwdb
, but you can look at the latest development version of the file and/or my bug report and discussion concerning the documentation and spacing issues.
If this doesn't work, the problem might be found after temporarily increasing the log level of udevd
with udevadm control
(see the udevadm(8) man page for details).
For old udev
versions such as 204, this method should still work.
Best Answer
If you're using Linux, the best way to distinguish between input devices is to use the Linux Event Interface. After a device's hardware-specific input is decoded, it's converted to an intermediate Linux-specific event structure and made available by reading one or more of the character devices under
/dev/input/
. This is completely independent of the programming language you use, by the way.Each hardware device gets its own
/dev/input/eventX
device, and there are also aggregates (e.g./dev/input/mice
which represents the motion of all mice in the system). Your system may also have/dev/input/by-path
and/dev/input/by-id
.There's an
ioctl
calledEVIOCGNAME
which returns the name of the device as a humanly-readable string, or you can use something like/dev/input/by-id/usb-Logitech_USB_Gaming_Mouse-mouse
.You open the device, and every time an event arrives from the input hardware, you'll get a packet of data. If you can read C, you can study the file
/usr/include/linux/input.h
which shows exactly how this stuff works. If you don't, you could read this question which provides all the information you need.The good thing about the event interface is that you just find out what device you need, and you can read input from that input device only, ignoring all others. You'll also get notifications about keys, buttons and controls you normally wouldn't by just reading the ‘cooked’ character stream from a terminal: even dead keys like Shift, etc.
The bad thing is that the event interface doesn't return ‘cooked’ characters, it just uses numeric codes for keys (the codes corresponding to each key are found in the aforementioned header file — but also in the Python source of event.py. If your input device has unusual keys/buttons, you may need to experiment a bit till you get the right numbers.