Here are some notes on assigning functions to those special keys that come on so many keyboards. My Gateway SK-9920 has 12 of these hotkeys: volume up, down, and mute; play, stop, next, and last track; internet, help, mail, shopping cart (?), and back (presumably). I don't even know what the creators of this keyboard envisioned for the "shopping cart" key. Often these keys aren't recognized out-of-the-box in Windows, much less in Linux.
Like usual, there are almost certainly specific GNOME or KDE tools to accomplish this goal. Since I'm not running those, however, I'll stick to tools available in almost any X.Org environment (I happen to be using Ratpoison).
First, some terminology. A scancode is the lowest level of identification for a key. If your key doesn't have a scancode, you're out of luck - the kernel doesn't recognize the key at all. A keycode is the next level of identification. If your key's scancode is identified with a keycode, then there's just one more step to make it do what you want. The last level of identification is a symbol. A scancode is mapped to a keycode, which is mapped to a symbol (for example, the letter "e" or "Caps Lock").
Starting out, none of my hotkeys were mapped to symbols, some were mapped to keycodes, and some only had scancodes (thankfully there were no completely "dead" keys). You can check if a key has a keycode by using
xbindkeys. In a terminal (in X - not a console) type
followed by the key you want to check. Here's an example of the output from my "Back" hotkey (before I bound it using xbindkeys, but after I assigned a keycode to the scancode, as described at the end of this post):
james@tv:~$ xbindkeys -k Press combination of keys or/and click under the window. You can use one of the two lines after "NoCommand" in $HOME/.xbindkeysrc to bind a key. "(Scheme function)" m:0x10 + c:211 Mod2 + NoSymbol
Binding keycodes to actions
Using the output from
xbindkeys -k, it's easy to bind a key to an action. This will be configured in the
~/.xbindkeysrc file (you may need to create it). It will take effect when you run
xbindkeys. You'll probably want to call it in your
~/.xinitrc file. Here's an example of the format from my
# internet key "firefox" m:0x10 + c:178 # play/pause key "mpc toggle" m:0x10 + c:162 # stop key "mpc stop" m:0x10 + c:164 # previous track key "mpc prev" m:0x10 + c:144 # next track key "mpc next" m:0x10 + c:153 # volume up key "amixer set 'Headphone' 1%+ ; amixer set 'PCM' 1%+" m:0x10 + c:176 # volume down key "amixer set 'Headphone' 1%- ; amixer set 'PCM' 1%-" m:0x10 + c:174 # mute key "amixer set 'Headphone' toggle ; amixer set 'PCM' toggle" m:0x10 + c:160
It's a pretty simple format. Obviously the "#" precedes a comment (and is optional, but recommended). The next line is the command you want the hotkey to run (surrounded by quotes). You'll recognize the final line from the output of
xbindkeys -k. I'm not sure if you can use either output line (or both) but mine works fine with just the first line following the
"(Scheme function)" line.
That's all there is to it... unless your key does not have a keycode.
Mapping scancodes to keycodes
xbindkeys -k does not recognize your key, it's probably not associated with a keycode. You can check if the key has a scancode (in other words, if the kernel recognizes the key) by pressing the key and then checking
dmesg to see if the key was mentioned. Here's an example of what it will look like (from pushing my "Back" hotkey, before I assigned it to a keycode):
james@tv:~$ dmesg | tail -4 [ 48.274918] atkbd.c: Unknown key pressed (translated set 2, code 0x83 on isa0060/serio0). [ 48.274918] atkbd.c: Use 'setkeycodes e003 <keycode>' to make it known. [ 48.789832] atkbd.c: Unknown key released (translated set 2, code 0x83 on isa0060/serio0). [ 48.789832] atkbd.c: Use 'setkeycodes e003 <keycode>' to make it known.
If you get similar output, you're key has a scancode (and is not mapped to a keycode). You can use
setkeycodes to assign a keycode to the key. Before doing this, however, you're going to want to make sure that you don't assign it to a keycode that's already in use. You can find this out by looking at your keymap.
james@tv:~$ cp /etc/console/boottime.kmap.gz . james@tv:~$ gunzip boottime.kmap.gz james@tv:~$ less boottime.kmap
-- SNIP -- keycode 81 = KP_3 altgr keycode 81 = Hex_3 alt keycode 81 = Ascii_3 keycode 82 = KP_0 altgr keycode 82 = Hex_0 alt keycode 82 = Ascii_0 keycode 83 = KP_Period altgr control keycode 83 = Boot control alt keycode 83 = Boot keycode 84 = Last_Console keycode 85 = keycode 86 = less greater bar alt keycode 86 = Meta_less shift alt keycode 86 = Meta_greater keycode 87 = F11 F23 Console_23 F35 alt keycode 87 = Console_11 control alt keycode 87 = Console_11 keycode 88 = F12 F24 Console_24 F36 alt keycode 88 = Console_12 control alt keycode 88 = Console_12 keycode 89 = keycode 90 = keycode 91 = keycode 92 = keycode 93 = keycode 94 = keycode 95 = keycode 96 = KP_Enter altgr keycode 96 = Hex_F keycode 97 = Control keycode 98 = KP_Divide altgr keycode 98 = Hex_B keycode 99 = Control_backslash alt keycode 99 = Meta_Control_backslash shift alt keycode 99 = Meta_Control_backslash control alt keycode 99 = Meta_Control_backslash keycode 100 = AltGr keycode 101 = Break keycode 102 = Find -- SNIP --
You can see that some keycodes are not being used (89-95, for example), so those are safe to use. (By the way, I've heard that you're supposed to pick a keycode between 1-127, but I don't know why, or what happens if you don't - I've never used one outside of that range).
You can then assign a scancode to one of these unused keycodes using
setkeycodes (as root).
setkeycodes 0x83 89
The above code assigns the scancode from my "Back" hotkey to the unused keycode "89". Once that's been done, you can use
xbindkeys -k (as described above) to get the correct identifier to bind the key using
Assuming you want to use this binding after you reboot, you'll want to add the
setkeycodes command to
/etc/rc.local. Here's an example of mine:
james@tv:~$ cat /etc/rc.local #!/bin/sh -e # # rc.local # # This script is executed at the end of each multiuser runlevel. # Make sure that the script will "exit 0" on success or any other # value on error. # # In order to enable or disable this script just change the execution # bits. # # By default this script does nothing. ## James added to map the "back", "shopping cart", and "?" keys on Gateway keyboard setkeycodes 0x83 89 & setkeycodes 0x81 90 & setkeycodes 0x82 91 & exit 0
Please feel free to mention better or alternate ways, or anything that I've got wrong.