How I hacked my multimedia keyboard buttons to work in X (and why you probably shouldn't attempt it):
I'm posting this guide because I believe very strongly that this should be easier than it was. Unfortunately I received very little help, and the documentation around on google is at best spotty and at worst completely useless, which left me to assemble the necessary facts on my own and write up a dirty hack (and believe me, it's an ugly one) to make my multimedia keyboard buttons do something useful.
First, a few notes:
* I am running kernel 2.6.25.11-97 on FC9. If you're using something earlier than this, I don't know if you'll have the correct drivers.
* keytouch did not work for me. keytouch-acpid hung on startup, and even when I ran things manually it never seemed to notice when I was pressing my keys. keytouch-editor appeared to work, but truncated some important scancode information from the keyboard config file that I created. Even after I corrected it, keytouch did not work.
* My key events didn't show up in xev.
* I tried using the evdev driver -- and there may yet be a way to do this and have it work -- but no help was available on figuring out all of the weird bitfield options, so I had to go with another way.
* In case anyone has this exact keyboard, it's an IBM SK-8815.
Getting started:
Your USB keyboard is actually two devices. One of these is the main keyboard, and the other one is the multimedia keys. The first thing you need to do is find which /dev/input/event* device you need to refer to. Start by typing:
Code:
cat /proc/bus/input/devices
You'll see a bunch of thesee:
Code:
I: Bus=0003 Vendor=04b3 Product=301b Version=0110
N: Name="Lite-On Technology USB Productivity Option Keyboard( has the hub in # 1 )"
P: Phys=usb-0000:00:1a.7-4.2.1/input0
S: Sysfs=/devices/pci0000:00/0000:00:1a.7/usb1/1-4/1-4.2/1-4.2.1/1-4.2.1:1.0/input/input4
U: Uniq=
H: Handlers=kbd event4
B: EV=120013
B: KEY=10000 7 ff9f207a c14057ff febeffdf ffefffff ffffffff fffffffe
B: MSC=10
B: LED=1f
I: Bus=0003 Vendor=04b3 Product=301b Version=0110
N: Name="Lite-On Technology USB Productivity Option Keyboard( has the hub in # 1 )"
P: Phys=usb-0000:00:1a.7-4.2.1/input1
S: Sysfs=/devices/pci0000:00/0000:00:1a.7/usb1/1-4/1-4.2/1-4.2.1/1-4.2.1:1.1/input/input5
U: Uniq=
H: Handlers=kbd event5
B: EV=13
B: KEY=ff 0 2000000 3878 d8000001 e0000 0 0 0
B: MSC=10
Your keyboard will probably differ from mine, but if you have a multimedia USB keyboard, the media keys will probably correspond top the second entry. Check the Handlers= line for the device name (it will look like eventN, in this case, event5).
Now that you what device you'll be reading from, you need to make this readable by you. The safest way to do this is to create a new group, add yourself to it, then set up a kernel rule to make that device file readable by that group. When I did it, it looked like this:
BE SURE TO REPLACE 'YOU' WITH YOUR USERNAME, AND 'event5' WITH THE CORRECT DEVICE FILE NAME.
Code:
groupadd mmkeys
usermod -G mmkeys YOU
echo 'KERNEL=="event5", NAME="input/%k", GROUP="mmkeys", MODE="0640"' | cat >> /etc/udev/rules.d/10-local.rules
You will probably need to reboot your computer for this to take effect. Please note that this is not very secure, and anyone in this group will be able to monitor your multimedia button presses. Never do this on a multi-user machine, and make sure only trusted users are members of that group.
Once you've rebooted, the next thing you need to do is get a look at what this device outputs when one of those keys is pressed. The best way to do that is with a little perl script:
AGAIN, BE SURE TO REPLACE 'event5' WITH THE CORRECT DEVICE FILE.
Code:
#!/usr/bin/perl
use strict;
$| = 1;
open(IN, "<", "/dev/input/event5");
my($x);
while(1) {
read(IN, $x, 1);
my($hex);
$hex = sprintf("%02x", ord($x));
print($hex);
}
Run that script (call it anything you want) and watch the output as you press the multimedia buttons on your keyboard.
It will look something like this (without the space n the middle, which phpbb added):
Code:
b4d8904848df00000400040006000900b4d8904852df00000100050101000000b4d8904855df00000000000000000000
NOTE: For all I know, the output may be a lot shorter per keypress on your keyboard. This is just what it looks like on mine.
In my case, it was outputting 96 hex characters per event (keypress/release), or 48 bits. Bear in mind that I have no knowledge of USB devices, so this may change from keyboard to keyboard. Count up the number of characters and divide that by 2, and that's how many bits your keyboard is outputting. The next step is to see if we can find a pattern. Create a new perl script, or modify the old one, so that it looks like this:
Change the '48' to the number of bytes that you just calculated.
Code:
#!/usr/bin/perl
use strict;
$| = 1;
open(IN, "<", "/dev/input/event5");
my($x);
while(1) {
read(IN, $x, 48);
my($hex);
for(my($i) = 0; $i < length($x); $i++) {
$hex .= sprintf("%02x", ord(substr($x, $i, 1)));
}
print($hex, "\n");
}
Your output should look like this now (but without the space in the middle):
Code:
b4d8904848df00000400040006000900b4d8904852df00000100050101000000b4d8904855df00000000000000000000
b5d89048033d01000400040006000900b5d890480d3d01000100050100000000b5d89048113d01000000000000000000
b5d890481de90e000400040006000900b5d890482be90e000100050101000000b5d8904833e90e000000000000000000
b6d89048db5e0b000400040006000900b6d89048ea5e0b000100050100000000b6d89048f25e0b000000000000000000
...
Now the fun part. As you press and release your multimedia keys, try to figure out what numbers are always the same, what numbers are always different, and what numbers depend on what key you're pressing. On my keyboard, everything apart from bytes 25 thru 28 was junk, as far as I could tell. Byte 28 was 1 if the key was pressed, and 0 if it was released. Bytes 25-27 were a number that corresponded to the key pressed. I then created this script:
Code:
#!/usr/bin/perl
use strict;
$| = 1;
# /dev/input/event5 sends strings of 48 bytes when a key is pressed or released.
# Looks like the important bytes are 25-28. Bytes 25-27 appear to identify they key,
# and byte 29 is 1 if the key was pressed, and 0 if it was released.
#0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7
#d3c59048805f0b0004000400e9000c00d3c590488a5f0b000100730000000000d3c590488f5f0b000000000000000000
# Key mappings
my(%keys) = (
"000001", "konsole", # Access IBM
"000101", "dbus-send --session --dest=org.freedesktop.ScreenSaver --type=method_call --print-reply /ScreenSaver org.freedesktop.ScreenSaver.Lock", # Lock Desktop
"000201", "dolphin $ENV{HOME}/Documents", # My Documents
"000301", "kate", # Word Processor
"000401", "", # Spreadsheet
"000501", "", # Calculator
"000601", "evolution", # E-mail
"000701", "firefox", # Internet
);
open(IN, "<", "/dev/input/event5");
my($x);
while(1) {
read(IN, $x, 48);
# We don't care about releases in this case. Only pay attention if byte 28 is 1.
next if(ord(substr($x, 28, 1)) == 0);
# Get bytes 25-27.
$x = substr($x, 25, 3);
my($hex);
for(my($i) = 0; $i < length($x); $i++) {
$hex .= sprintf("%02x", ord(substr($x, $i, 1)));
}
#print($hex, "\n");
#print($keys{$hex}, "\n");
system("$keys{$hex} &");
}
I created a hash that mapped bytes 25-27 to various console commands (note that these are meant for KDE. GNOME's will differ somewhat). When one of the keys is pressed (I skip release events), I run the shell command that is in the hash for that keypress. If you run the script from the command line, it should work. Uncomment out the print statements for some debugging code. Finally, once that was done, I added this to my KDE startup scripts and restarted X. Now my multimedia keys actually do what I want them to.
So, why all this work? Well, mostly it's a cry for help. I'm told somewhere that if you set specific options in the x.org evdev device driver in xorg.conf, then you can actually use your multimedia keyboard as a legitimate X input device without having to go through these steps. Furthermore, you can apparently figure out how to set these options by looking at the B: lines in /proc/bus/input/devices. If anyone knows how to do this, I'd love to see it done. But for now, my multimedia keys work.
Edit: If I had more time, I'd write this in C or C++, and perhaps put a gui on it so it would run in the systray. This here is the result of an hour or two of work.