The kbd package provides the dumpkeys and loadkeys programs for manipulating the keyboard translation tables.

Short Version

dumpkeys | sed 's/Caps_Lock/Control/g' | loadkeys

Long Version

Run dumpkeys to see the current translation tables:

dumpkeys

The first line should be something like:

keymaps 0-255

That means that the each keycode line in the file will contain up to 256 values corresponding to what is to happen when that key is pressed and certian modifiers are in effect. The 0-based index of the column serves as a bitmask in accordance with the table below:

<table border=1>

Modifier Value shift1 altgr2 control4 alt8 shiftl16 shiftr32 ctrll64 ctrlr128 capsshift256

</table>

For example, the value in column 129 is what happens when the keycode is pressed while shift (1) and ctrlr (128) are in effect.

You’ll also see a bunch of keycode lines:

keycode 5 = four dollar dollar
  control keycode 5 = Control_backslash
  alt keycode 5 = Meta_four
  shift alt keycode 5 = Meta_dollar
  control alt keycode 5 = Meta_Control_backslash

Ignore the indentation; the whitespace preceeding the last four lines is insignificant. However, the first line uses a different syntax from the last four.

The first line uses the standard syntax. When keycode 5 is pressed, which happens to be the “4” keyy:

  • if no modifiers are in effect, “4” is output.
  • if only shift is in effect, “$” is output.
  • if only altgr is in effect, “4” is output.

The omitted 253 columns are implicitly set to VoidSymbol which ensures that the key has no effect with those modifier combinations.

The last four lines use an alternate syntax which abandons the columns approach in favor of explicitly listing the modifiers.

Finding Keycodes

To see which keycodes corresponding to the physical keys on your keyboard, run showkeys and start pressing buttons. I’ll run it and press caps lock:

# 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  58 press
keycode  58 release

First output is “keycode 28 release.” Keycode 28 is the enter key on my keyboard, so that is simply me releasing the enter key after starting the program.

The next lines corresponding to me pressing and releasing the caps lock key which turns out to be keycode 58.

Finding Actions

dumpkeys -l will give you a ton of information, including the table of modifiers above as well as different actions that you can map to keycodes. You can output strings, cycle through virtual consoles, etc.

Mapping Caps Lock

Let’s see where Caps Lock is defined:

# dumpkeys | grep Caps_Lock
keycode 58 = Caps_Lock Caps_Lock Caps_Lock 
  control keycode 58 = Caps_Lock 
  shift control keycode 58 = Caps_Lock 
  altgr control keycode 58 = Caps_Lock 
  alt keycode 58 = Caps_Lock 
  shift alt keycode 58 = Caps_Lock 
  control alt keycode 58 = Caps_Lock 

The syntax should be familiar. The first line gives keycode 58 the action of Caps_Lock when it is pressed by itself or in combination with either shift or altgr, and the subsequent lines give keycode 58 the action of Caps_Lock for an assortment of additional modifiers.

Simply changing Caps_Lock to Control in the above does the intended mapping.

In Arch Linux, to make it permanent, you can save the altered mapping to a new file in /usr/share/kbd/keymaps/:

dumpkeys | sed 's/Caps_Lock/Control' > /usr/share/kbd/keymaps/personal.map

And then ensure the following appears in your /etc/vconsole.conf:

KEYMAP=personal