You can change the output of the Linux console keyboard with loadkeys. It's an extremely powerful command, and the man page can be confusing, but for simple use (which is often all we need it for), it's very easy.
For example, let's reprogram the F10 key:
echo 'string F10 = "foo" ' | loadkeys
See? That wasn't difficult. Oops, now what was the original value so we can put it back? Ahh, perhaps a little preparation would have been wise before changing that. The "dumpkeys" command does that:
dumpkeys > myfullkeymap dumpkeys --funcs-only > funcsonlymap
The "funcs-only" map is short:
string F1 = "\033[[A" string F2 = "\033[[B" string F3 = "\033[[C" string F4 = "\033[[D" string F5 = "\033[[E" string F6 = "\033[17~" string F7 = "\033[18~" string F8 = "\033[19~" string F9 = "\033[20~" string F10 = "\033[21~" string F11 = "\033[23~" string F12 = "033[24~" string F13 = "\033[25~" string F14 = "\033[26~" string F15 = "\033[28~" string F16 = "\033[29~" string F17 = "\033[31~" string F18 = "\033[32~" string F19 = "\033[33~" string F20 = "\033[34~" string Find = "\033[1~" string Insert = "\033[2~" string Remove = "\033[3~" string Select = "\033[4~" string Prior = "\033[5~" string Next = "\033[6~" string Macro = "\033[M" string Pause = "\033[P"
Yours will be different if you reprogrammed F10 above. Do this to put it back:
echo 'string F10 = "\033[21~" ' | loadkeys
If you had previously saved "funcsonlymap", you could put it all back with "loadkeys funcsonlymap" at any time, or simply use "loadkeys -d"
The full key map is much longer and can be confusing. The first thing you have to understand is how keyboards really work: they actually send a keycode (also called "scancodes"). The "A" key on your keyboard actually sends 30, and F10 sends 68. You can use "showkey" to see what keycodes are really being sent (just stop typing briefly and showkey will exit). In the full keymap dump, you'll find:
keycode 68 = F10 F22 Console_22 F34 alt keycode 68 = Console_10 control alt keycode 68 = Console_10
And later in the same file you'll find:
string F10 = "\033[21~"
The last one is easy to understand, but what does the first part mean? Well, it defines key symbols, "keysms" in the "man keymaps" explanation. It's position dependent: F10 is the unshifted key, F22 is the shifted F10, but then we start getting confusing. The man page does a lousy job explaining it:
Which of the actions bound to a given key is taken when it is pressed depends on what modifiers are in effect at that moment. The keyboard driver supports 8 modifiers. These modifiers are labeled (completely arbitrarily) Shift, AltGr, Control, Alt, ShiftL, ShiftR, CtrlL and CtrlR. Each of these modifiers has an associated weight of power of two according to the following table: modifier weight Shift 1 AltGr 2 Control 4 Alt 8 ShiftL 16 ShiftR 32 CtrlL 64 CtrlR 128 The effective action of a key is found out by adding up the weights of all the modifiers in effect. By default, no modifiers are in effect, so action number zero, i.e. the one in the first column in a key defini- tion line, is taken when the key is pressed or released. When e.g. Shift and Alt modifiers are in effect, action number nine (from the 10th column) is the effective one. Changing the state of what modifiers are in effect can be achieved by binding appropriate key actions to desired keys. For example, binding the symbol Shift to a key sets the Shift modifier in effect when that key is pressed and cancels the effect of that modifier when the key is released. Binding AltGr_Lock to a key sets AltGr in effect when the key is pressed and cancels the effect when the key is pressed again. (By default Shift, AltGr, Control and Alt are bound to the keys that bear a similar label; AltGr may denote the right Alt key.)
AltGr is the right hand Alt-Key, by the way. Later on, the man page helpfully tells us:
To find out what keysyms there are available for use in keymaps, use the command dumpkeys --long-info Unfortunately, there is currently no description of what each symbol does. It has to be guessed from the name or figured out from the kernel sources.
So, going back to that key 68 definition, it's easy to see that F22 is the shifted F10, and indeed we can redefine it with:
echo 'string F22 = "Foo" ' | loadkeys
But if you try that with Console_22, you'll get an error message from loadkeys. That's because it is one of the "actions" the man page is so vague about. It's defining the action for the right hand alt key and the function key. I could change it by replacing the keymap definition:
keycode 68 = F10 F22 F100 F34 alt keycode 68 = Console_10 control alt keycode 68 = Console_10
And then set F100 to be what I want:
echo 'string F100 = "Foo" ' | loadkeys
And then Right Alt-F10 will send "Foo". That's fine. Or, I could leave it as it is and use it for what it is really intended for, but we'll save that for later. The next position (F34) should be (as I understand the man page ) Shift , Right Alt, and F10. It isn't. If I program F34, it's Control F10 that sends what I set F34 to. That makes no sense at all.
Let's take it slowly: Okey-dokey. It's binary, calculated back from position, right? Seems to make sense. After F22, position One. which obviously matches Shift, we have Console_22 in position Two. That should mean that it matches the AltGr or Right Alt key and indeed it does: if I enable tty22 in /etc/inittab, the AltGr-F10 will switch me to tty22 on the console.
The next position is Three and it's F34. I define F34 on the fly
echo 'string F34 = "Key34" ' | loadkeys
because it's undefined in my default keymap. I would expect, since it is position Three, that the modifiers would be Shift and Altgr - 2 + 1 equals 3, right?
Nope. Actually, Control F10 sends "Key34" after this. How does THAT make any sense?
It doesn't. And it gets more strange. If I modify that keymapping like this:
keycode 68 = F10 F22 Console_22 F34 F100 F101
and define F34, F100, and F101, it then works exactly as I would expect it to! Right Alt F10 sends the F34 string, Control F10 sends the F100, and Shift Control F10 sends the F101 string..
So why does it work differently by adding two keysyms???
And then I look farther down the table and see more confusion. How the heck can ShiftL (which I assume means Left Shift) be a modifier weight if Shift already is? Do I assume that to use those positions you'd have to NOT define the ordinary shift combination? That might make sense, but the man page doesn't explain that.
It is easy to get confused (obviously), so they also provide a shortcut:
The "alt keycode 68 = Console_10" is a shorthand way of defining alt plus F10 without stringing out the first keycode line to nine columns. Without that, you'd need nine entries (you can use VoidSymbol as a place holder for key combinations you don't care about) and you'd need thirteen to define CTRL-ALT-F10. So at the command line you can also do:
echo 'control alt keycode 68 = F100' | loadkeys
That lets us redefine the key combinations but still doesn't tell us what the mysterious "Console_" entries mean. The "control alt keycode 68 = Console_10" obviously defines the key that will switch to the "F10" virtual console. Let's try changing it:
echo 'control alt keycode 68 = Console_3' | loadkeys
With that in place, CTRL-ALT-F10 will switch to tty3. What about Console_22? Yes, that's a virtual console too - as long as you enable tty22 in inittab. If you have enabled tty22, then with the default keymap shown above, the right alt key and F10 will switch you to a virtual console on tty22.
There's more to keymaps, but this at least gets you started.
Got something to add? Send me email.
More Articles by Tony Lawrence © 2009-11-07 Tony Lawrence
FORTRAN's tragic fate has been its wide acceptance, mentally chaining thousands and thousands of programmers to our past mistakes. (Edsger W. Dijkstra)