lørdag den 29. maj 2010

Getting your multimedia keys/remote control to work under X11 - by hacking your kernel

Right, so I have a media center (who doesn`t these days), and ofcourse a remote control for it.
My problem is, that I`ve got a Logitech ultraX media remote.
It is a nice remote, but only some of of the keys on the remote works out of the box
Heres the story of how I got all of my keys working.


The underlying problem
The underlying problem to all of this is that X11 does not support more then 255 different keys.
This is fine for most purposes, but not many media keys are included in these 255 keys.
Meny (if not all) common keys are mapped with a low keycode (range 0 to 200 (like letters and numbers), but many specialized meida keys are mapped much higher.

Testing to see if your keys really are dead in X
The first thing I did when trying to get the keys working, was running xev, which tells me if X recieves the input (key press in my case), and what that input is mapped to.
The problem was, that xev didn`t recieve any input from the buttons that did not work.
If your key press is detected in xev, this guide is NOT for you!
This guide is for getting your keys to register in X (xev)!

Solutions/Remedies for the problem?
After googling a bit I quickly found a MultimediaKeys guide on the gentoo-wiki.com site, which suggested running "showkey" from a real console (to open a real console hit alt-ctrl-f1).
When doing so, it registered my input, and showed a corrosponding keycode, but no scancode.
Output from showkey, when pressing some of the non-working keys in X (subtitle, language, dvd, music and repeat keys on the remote were pressed here):
showkey
kb mode was UNICODE
[ if you are trying this under X, it might not work
since the X server is also reading /dev/console ]

press any key (program terminates 10s after last keypress)...
keycode 28 release
keycode 370 press
keycode 370 release
keycode 368 press
keycode 368 release
keycode 389 press
keycode 389 release
keycode 391 press
keycode 391 release
keycode 129 press
keycode 129 release
The first line above (keycode 28 release) is the enter key being released (after executing the command).

I didn`t note it at the time, but the buttons that worked had keycodes lower then 255, and those that did not had keycodes higher then 255.
TAKE NOTE OF THIS, IT IS IMPORTANT!

So, first I thought it was because the input did not generate any scancodes (showkey -s shows generated scancodes, and showkey -k shows generated keycodes) - (but none of the keys do, and some of them work), so that wasn`t it.
So I hacked around a bit to generate some fake scancodes, but this was/is a dead end, and is not needed.

Using keytouch
The gentoo wiki guide suggested using a application called "keytouch" to get the keys working.
The keytouch application is used as a system service, and translates keycodes higher then 255 to lower keycodes, or it can map key presses directly to program commands.
I`ve tried keytouch; When starting the service (you can only do this after you`ve selected a keyboard/remote or created your own), I get this output (which means it does not work):
* Service keytouch starting
keytouch-init: Failed to set keycode:
keycode 148 to scancode -57260 (0xffff2054)
keytouch-init: Failed to set keycode:
keycode 149 to scancode -57260 (0xffff2054)
keytouch-init: Failed to set keycode:
keycode 202 to scancode -57260 (0xffff2054)
keytouch-init: Failed to set keycode:
keycode 203 to scancode -57260 (0xffff2054)
keytouch-init: Failed to set keycode:
keycode 227 to scancode -57260 (0xffff2054)
keytouch-init: Failed to set keycode:
keycode 141 to scancode -57260 (0xffff2054)
keytouch-init: Failed to set keycode:
keycode 225 to scancode 786 (0x312)
keytouch-init: Failed to set keycode:
keycode 224 to scancode 786 (0x312)
keytouch-init: Failed to set keycode:
keycode 231 to scancode -57260 (0xffff2054)
keytouch-init: Failed to set keycode:
keycode 124 to scancode -57260 (0xffff2054)
keytouch-init: Failed to set keycode:
keycode 235 to scancode -57260 (0xffff2054)
keytouch-init: Failed to set keycode:
keycode 219 to scancode 786 (0x312)
keytouch-init: Failed to set keycode:
keycode 147 to scancode -57260 (0xffff2054)
keytouch-init: Failed to set keycode:
keycode 129 to scancode -57260 (0xffff2054)
* Service keytouch started
So, no luck there :-(

Alternate solution - hacking the kernel
I figured the easiest way would then be to just change the mapping of the non-working keys to a lower keycode, this way I also don`t need yet another system service running, and I really want as few of those as possible (both to reduce system boot time, and to conserve system ressources).
The next step requires compiling your own kernel.
If you don`t know how, read the documentation for your distro (it's not covered here).
I`m running gentoo linux on all of my systems, so I`m quite comfortable compiling my own kernel, so heres what you need to do, once you know how (and has otherwise configured your kernel correctly for your own system).

Determine what keycodes needs to be remapped
Run showkey from a real console (as described above), and write down all the keycodes for the keys that does not work.
Note: showkey shows the keycodes in decimal form, and later you`ll need them in hex, so you may want to convert the numbers as you write them down.
For instance, take the Subtitle key from the showkey output above, it has a keycode of 370 in decimal, and thus becomes 0x172 in hex.

Remap the keys
Now edit /usr/src/linux/include/linux/input.h
In this file you will find all the defines for the keycodes that the linux kernel can generate.
Now, search for the keycodes you`ve noted down (remember to search for the converted hex numbers).
Once you have found a #define match, change the value to something lower then 248 (Range 248 - 255 is reserved for special needs of AT keyboard driver acording to a comment in input.h) - (you don`t have to write the value down in hex, you can write it in decimal if you want).
You`ll be remapping your keys to a keycode that most likely is already used, and the system won`t know the difference between these, so think about how you remap!

For the subtitle example, here the relevant part of input.h (lines 472 to 477):
#define KEY_LANGUAGE 0x170
#define KEY_TITLE 0x171
#define KEY_SUBTITLE 0x172
#define KEY_ANGLE 0x173
#define KEY_ZOOM 0x174
#define KEY_MODE 0x175
I`v changed the value of KEY_SUBTITLE to 183.
This means that the susbtitle button will ack like the F13 key (because it has a keycode value of 183) - (which I don`t have on my keyboard, and don`t use - since I have never heard of it).
You can also remap them directly to something else, like the arrow keys, if you know how you are going to use them.
For instance if you are going to use them in mythtv, or some other application where you`ll need s, m or any other key, this might be simpler, however it does not give you as much control over your keys as they will always ack like and s or a m.

I`ve remapped every key on the remote having a higher keycode then 255, to something else f14,f15...f24 and others.

Save, recompile and reboot
Once done, save input.h, and recompile your kernel (do a make clean first, to ensure the new values are used).
Now install your new kernel and reboot.

Testing if it works
Once rebooted, start X, fire up xev, and viola, all your keys now work (as whatever you remapped them to).


Why the 255 limit?
Q: So why does X only allow for 255 keys?
A: I don`t know!
The X11 protocol was released in 1985, and they properly didn`t think it was an issue.
The problem shound be fixed in X12, but no-one really knows when this is comming out.

Are there any drawbacks?
Yep, sure:
  • One drawback to this is that you can`t use one key to create keycombo`s.
  • Every time you update to a new kernel, you`ll have to patch it with your own remapped values.

Any suggestions?
I suggest remapping to the f13...f24 keys, and then let mythtv, xbmc or xmodmap remap the keys from there, as it gives you more control, and the abillity to make key combinations (keycombo`s).

References

Ingen kommentarer:

Send en kommentar