Main page...           Popular tags: Electronics (12), Linux (11), DIY (8), Hack (8), Retrocomputing (7), Other (6), Debian (5), Curiosities (4)


Using dead multimedia keys in Linux.

2016-08-20 20:46:22,  In: Linux, Keyboard, Hack

For years I was using a KeyMaestro keyboard connected to PS/2 port. This keyboard is a normal AT keyboard with a set of multimedia/Internet keys. When I switched to Linux, I decided to still stick with it as most multimedia keys were working OK.
But not all the keys. Let's try to make them all running.
First, you should know how the keyboard is used in Linux. The user presses a key, then the keyboard emits the code. Driver in Linux kernel emits the SCANCODE, and Linux program responsible for keyboard mapping maps it to KEYCODE. The keycode may be then used by the system (to be translated to letter as keysym, but we don't go up this level). This way many different keyboards for different platforms may be used by only altering the scancode-to-keycode translation method.
To make key do things we want, we must get its keycode. The most simple method is to use xev and, after seeing the window, pressing the keys. In the console, you will see:
KeyPress event, serial 39, synthetic NO, window 0x4a00001,
root 0x9d, subw 0x0, time 18579975, (822,760), root:(826,780),
state 0x10, keycode 164 (keysym 0x1008ff30, XF86Favorites), same_screen YES,
XLookupString gives 0 bytes:
XmbLookupString gives 0 bytes:
XFilterEvent returns: False

KeyRelease event, serial 39, synthetic NO, window 0x4a00001,
root 0x9d, subw 0x0, time 18580025, (822,760), root:(826,780),
state 0x10, keycode 164 (keysym 0x1008ff30, XF86Favorites), same_screen YES,
XLookupString gives 0 bytes:
XFilterEvent returns: False

We can see that the "Favorites" key has been pressed with keycode 164. We can then use it in the program like Favorites key (at least Firefox can do it) or bind it to program using your desktop environment's settings or using XBindkeys.

   If it doesn't work...

The problem starts when you press the key in xev, press it, press it... and nothing pops to the console. This means that the resolution of keycode from scancode gave no results (or there is no scancode at all, then it's really not supported in generic AT keyboard driver). In Debian 8 I found that showkey --scancodes method gives no results here too! Dead as a doornail?
But let's check do we catch the scancode at all, because it looks like showkey will not return data is conversion is not made. With evdev, we can do it using evtest:
mcbx@mcbx:~$ sudo evtest

We have to select our keyboard number from the list and press Return. Then we have a key-pressing playground. Let's see the sample results:
Testing ... (interrupt to exit)
Event: time 1470607226.777906, type 4 (EV_MSC), code 4 (MSC_SCAN), value 1c
Event: time 1470607226.777906, type 1 (EV_KEY), code 28 (KEY_ENTER), value 0
Event: time 1470607226.777906, -------------- EV_SYN ------------
Event: time 1470607229.644498, type 4 (EV_MSC), code 4 (MSC_SCAN), value 1e
Event: time 1470607229.644498, type 1 (EV_KEY), code 30 (KEY_A), value 1
Event: time 1470607229.644498, -------------- EV_SYN ------------
Event: time 1470607229.722753, type 4 (EV_MSC), code 4 (MSC_SCAN), value 1e
Event: time 1470607229.722753, type 1 (EV_KEY), code 30 (KEY_A), value 0
Event: time 1470607229.722753, -------------- EV_SYN ------------
Event: time 1470607234.524089, type 4 (EV_MSC), code 4 (MSC_SCAN), value e6
Event: time 1470607234.524089, type 1 (EV_KEY), code 156 (KEY_BOOKMARKS), value 1
Event: time 1470607234.524089, -------------- EV_SYN ------------
Event: time 1470607234.583731, type 4 (EV_MSC), code 4 (MSC_SCAN), value e6
Event: time 1470607234.583731, type 1 (EV_KEY), code 156 (KEY_BOOKMARKS), value 0
Event: time 1470607234.583731, -------------- EV_SYN ------------
Event: time 1470607236.193270, type 4 (EV_MSC), code 4 (MSC_SCAN), value a5
Event: time 1470607236.193270, -------------- EV_SYN ------------
Event: time 1470607236.287066, type 4 (EV_MSC), code 4 (MSC_SCAN), value a5
Event: time 1470607236.193270, -------------- EV_SYN ------------


First we can see release of Return key, we confirmed the keyboard's number with it. Next I pressed key A, so I can see that it emitted a scancode value 1e (MSC_SCAN, value 1e), translated to keycode 30 (EV_KEY, code 30). Next, I pressed this "Favorites" key which works, and it did the same thing. But notice two last keys which gave no result in xev - they emitted the scancodes (a5 and a6), but it was not translated to keycode. According to documentation you can write evdev hwdb rules, but I found that sometimes they just take wrong scancodes. In this example in Debian 8, scancodes a5 and a6 have been back-mapped to my "Multimedia stop" and "Previous song" keys and I have no idea how. On the other computer with Debian unstable, it just doesn't work at all.
So to make the keys accessible it is needed to map the keycodes a different way. We will use setkeycodes program. First, let's look for a free keycodes. Remember the output you got from evtest? There is something like:
Input device name: "AT Translated Set 2 keyboard"
Supported events:
Event type 0 (EV_SYN)
Event type 1 (EV_KEY)
Event code 1 (KEY_ESC)
Event code 2 (KEY_1)
Event code 3 (KEY_2)
Event code 4 (KEY_3)
Event code 5 (KEY_4)
. . . and more


This is a list of available keycodes. Let's find two unused of them, e.g. KEY_CALC (in my test Event code 140) and KEY_CAMERA (in my test code 212) and assign to the scancodes the following way (as root):
setkeycodes a5 140
setkeycodes a6 212

Then try xev again. It should give the results.
This way stubborn keys in some laptops can be programmed too. Remember that you have to run setkeycodes lines every boot and as root, so put it in some autorun file. I don't care about multiuser here, so I just put my commands in /etc/rc.local just before exit 0.


Older post...       Main page       Newer post...