A little while back I bought an ASRock 330HT as a media PC. Aside from the fan being a little noisier than I hoped, the remote control had no Linux driver so I bought a Hama MCE remote control after reading that it works well under Linux. Unfortunately, while it works fine under Linux, it's got hardcoded key values and not every key is unique. As an example the "i" info button is actually a prolonged right click, a couple of the keys send *exactly* the same keycodes as others (Play and Pause), and there are a bunch of buttons which generate Control-Shift-foo and Alt-bar and so on. I guess under Windows Media Center these all serve a specific purpose. Under Linux and its media center programs (such as XBMC) they don't (and XBMC's input layer is a bit restrictive).
I had my toys, but things weren't working exactly as I wanted. What's a guy to do? I got hacking, of course.
The Linux Input Subsystem is pretty clean nowadays and detecting the correct device and reading a few bytes from /dev/input/eventXX isn't all that hard. Within a couple of hours I was reading the bytes from the remote and pretty printing them as I received them. Unfortunately, this lead to the realisation (as shown above) that the remote's a little screwy and that a few hacks would be necessary to make things work as I wanted. But I was having fun and I was learning something.
The next step was deciding how to use these key events. XBMC has an interface to LIRC and another chap had written a python script making the HAMA MCE remote produce LIRC events. I tried it, fixed some bugs, and it worked.. but it was unsatisfying.. the MCE remote also has a mouse cursor (there are two input devices generated - a mouse and a keyboard - but the mouse device also sends a few key events that I care about as well as the all-important info button).. I started to explore the uinput device which lets you create a fake input device and write to it. Figuring out how to initialise it was a little tricky but I found some similar code and worked it out.. after that it's just writing input events to the device.
My initial idea of just reading all input, munging a few things, and passing the remaining events directly through proved somewhat problematic. If you leave a stranded Control or Alt key pressed down then you have a serious problem and in my tests I had to kill my X session a few times. A better way is to read all the input and have a virtual keyboard that handles the MOD keys, does the processing of normal keystrokes, does the translations, and then converts the translated events back into input events for uinput, ensuring there're no dangling modkeys.
The final step was to create a versatile translated step. I decided that I wanted a configuration file, instead of coding the translations all in python.
Here's some snippets from my config file:
# simple 1-1 translation KEY_HOMEPAGE-down = send KEY_ESC-down KEY_HOMEPAGE-up = send KEY_ESC-up # the info button/right click magic BTN_RIGHT-down = set rightclick time.time() BTN_RIGHT-up = if (time.time()-rightclick) > 0.3; send KEY_I; else; send BTN_RIGHT # compound key sequence example Alt-KEY_F4-down = wait Alt-KEY_F4-down KEY_F4-up = send KEY_ESC; clear
The wait action means to add the current key event to the match criteria for the next keystroke. clear then clear's the list.
Code will be online soon at http://github.com/rmt/pyinputevent/