Home » Linux Magazine » Consistent Keyboard Configuration

Consistent Keyboard Configuration

John F. Bunch

Issue #38, June 1997

Eliminate inconsistent behavior from your keyboard by following the instructions in this article.

One of the convenient features of Linux is that the keyboard can be completely reconfigured to suit personal tastes. This feature can be a blessing or a curse when keys do not perform the same actions in all applications, but with a little work you can program any key to perform almost any task. Inconsistent keyboard behavior can be eliminated, and applications customized as desired.

In this article, you learn how to achieve consistent behavior for the BACKSPACE, DELETE and ALT keys. The Caps Lock key is switched with the left CTRL key to make the typing of control characters easier. The keys of the editing keypad are configured to perform as labeled. Function keys, and some keys of the numeric keypad, are programmed to perform arbitrary tasks. A shutdown key is also configured.

The keyboard configuration techniques will be demonstrated by a wide range of examples, one program at a time. Where practical, these techniques will be demonstrated for bash, less, Netscape, minicom and Emacs. Furthermore, the keyboard will be made to work as desired, regardless of whether the application is running in an xterm window, in a virtual console, or in an X11 window manager. However, it is assumed that the user has an IBM PC-compatible keyboard.


An IBM PC-compatible keyboard is divided into five blocks of keys. The alphabetic keys and those surrounding them form the main keypad. To the immediate right of the main keypad are two small sets of keys. The upper six keys are the editing keys; the lower four keys are the arrow keys, which are also called cursor control keys. At the far right is the numeric keypad. Finally, the function keys stretch in a single line across the top of the keyboard.

When a function key or an arrow key is pressed, an escape sequence is normally transmitted by the key. An escape sequence is a string of a few characters, the first of which is an ESCAPE control code. The rest of the string is used to distinguish one key from another.

The VT100 family is a set line of text-only display terminals once manufactured by Digital Equipment Corporation. The VT100 has become the de facto standard for ASCII terminals. Its successor, the VT200, is compatible with the VT100 family. However, VT200s also have a row of twenty function keys and six editing keys that the VT100s did not have. The VT200 keyboard is somewhat similar to the IBM PC-style keyboard that is now in general use.

Keypress Events

A keypress event occurs when the user presses any key on the keyboard. The event passes through various software programs, eventually resulting in some sort of action (see Figure 1). Ideally, the same keypress will result in a similar action in all programs, thus reducing the user’s confusion.

For example, suppose a user is running Emacs inside an xterm under the X Window System and presses the up arrow key. Referring again to Figure 1, the up arrow is pressed, resulting in an event keycode of 98 being generated, which uniquely identifies that key. The X Window System translates this keycode into the “Up” keysym, which is received by the xterm. The xterm then translates the “Up” keysym into the three-character escape sequence “\\eOA” (“\\e” represents the ASCII ESCAPE control code). Emacs receives “\\eOA” as a series of three input events, which are then translated by the function-key-map into the vector [up]. The vector [up] passes unchanged through the key-translation-map. Finally, the global-map maps [up] to the previous-line command, which moves the cursor up one line in the buffer.

Figure 1. Keypress Event Flowchart

                       | Keypress |
                            | keycode
                |                        |
                V                        V
        +--------------+        +-----------------+
        | Linux kernel |        | X Window System |
        +-------+------+        +--------+--------+
                |                        |
                |                        | keysym
                |                        |
                |            +-----------+---------+
                |            |           |         |
                |            V           |         |
                |        +-------+       |         |
                |        | xterm |       |         |
                |        +---+---+       |         |
                |            |           |         |
                +------------+           |         |
                |                        |         |
                | character              |         V
                |                        |   +----------+
  +------+------+---------------+ +------+   | netscape |
  |      |      |               | |          +-----+----+
  V      |      V               V V                |
+------+ | +------+  +=======+---+-------------+   |
| less | | | bash |  | emacs |   :             |   |
+-+----+ | +----+-+  +=======+   : input event |   |
  |      V      |    |           V             |   |
  | +---------+ |    |  +------------------+   |   |
  | | minicom | |    |  | function-key-map |   |   |
  | +----+----+ |    |  +--------+---------+   |   |
  |      |      |    |           |             |   |
  |      |      |    |           | input event |   |
  |      |      |    |           V             |   |
  |      |      |    | +---------------------+ |   |
  |      |      |    | | key-translation-map | |   |
  |      |      |    | +---------+-----------+ |   |
  |      |      |    |           :             |   |
  |      |      |    |           : input event |   |
  |      |      |    |           V             |   |
  |      |      |    |     +------------+      |   |
  |      |      |    |     | global-map |      |   |
  |      |      |    +-----+-----+------+------+   |
  |      |      |                |                 |
                            | command
                       | Action |


One way to approach configuring the BACKSPACE and DELETE keys is to let them act as they do in DOS and MS Windows. That is, BACKSPACE erases the character to the left of the cursor, and DELETE erases the character under the cursor. This is a very convenient arrangement.

It is also a good idea to decide what control codes should be transmitted when these keys are pressed. Based on the key labels, let the BACKSPACE key transmit a BACKSPACE (ASCII code 8, 010 in octal, 0x08 in hexadecimal, CTRL-H), and let the DELETE key transmit a DELETE (ASCII code 127, 177 in octal, 7F in hexadecimal). Simple solutions are usually the best.

The ALT key, which acts somewhat like a shift key, can be configured in one of two ways. Either it can set the eighth bit of the key being pressed with it, or it can cause an ESCAPE to be transmitted just before the key being pressed with it. Both methods will be used at different times. Sometimes it is simpler to configure the ALT key to transmit an ESCAPE. For example, holding down ALT while pressing A would cause the string “\\eA” to be transmitted. However, at other times it will be configured to set the eighth bit of the character being pressed, thus adding 128 to the ASCII code of that character. Meta is a synonym for ALT.

Linux Kernel

First, the kernel’s keyboard translation tables will be redefined. Since these tables are not used directly by the X Window System, use one of the virtual consoles, not a window manager. Log in as root or use su. Different distributions of Linux may load the translation tables in different ways. To determine which keyboard translation table is in use, type:

# find /etc -type f | xargs grep loadkeys

You should see output something like:

/etc/init.d/boot:  loadkeys \

which would indicate that the U.S. translation table is in use. 

Assuming the U.S. translation table is in use, enter the following commands to make a copy of it:

# cd /usr/lib/kbd/keytables
# cp us.map custom.map

The format of keyboard table files is given in keytables(5).

Now edit custom.map using any text editor. Find the following lines:

keycode 14 = Delete           Delete
        alt     keycode  14 = Meta_Delete

These lines specify that when keynumber 14 is pressed (the BACKSPACE key), send a DELETE to the system, and when ALT-BACKSPACE is pressed, send a Meta_DELETE. To find out the keynumber of any key, use the showkey command.

To make the BACKSPACE key conform to the design decisions, change these lines to read:

keycode  14 = BackSpace        BackSpace
         alt     keycode  14 = Meta_BackSpace

However, a delete key is also needed, so replace the following line:

keycode 111 = Remove

with these two lines:

keycode 111 = Delete           Delete
        alt             keycode 111 = Meta_Delete

Keynumber 111 is the DELETE key on the editing keypad, just below the INSERT key. 

Now, to swap Caps_Lock with the left CTRL key, redefine keycodes 29 and 58 as follows:

keycode  29 = Caps_Lock    # Left Control key.
keycode  58 = Control      # Caps Lock key.

Configuring the numeric keypad presents a special challenge. In us.map, several of the keys transmit the same escape sequences as an editing key. This makes it impossible, for example, for a program to distinguish between the PAGE UP key on the editing keypad and the 9/Pg Up key on the numeric keypad. Furthermore, the NUM LOCK, /, *, – and + keys do not even transmit escape sequences.

To alleviate these problems, the virtual console’s numeric keypad will be configured somewhat like a VT100 numeric keypad. Since xterm already emulates a VT102, this will save work by making the virtual consoles more compatible with xterm. Note that this technique could cause incompatibilities with software programs that expect the keys to behave as defined by us.map. If this becomes a problem, the keys can always be switched back.

To be able to configure the keys of the numeric keypad independently, they will have to be changed into function keys. Since the kernel supports up to 246 function keys, F1 through F246, this is not a problem. Redefine the following keycodes as shown:

keycode  55 = F112    # Numeric keypad *.
keycode  69 = F110    # NumLock.
keycode  71 = F107    # Numeric keypad 7.
keycode  72 = F108    # Numeric keypad 8.
keycode  73 = F109    # Numeric keypad 9.
keycode  74 = F113    # Numeric keypad -.
keycode  75 = F104    # Numeric keypad 4.
keycode  76 = F105    # Numeric keypad 5.
keycode  77 = F106    # Numeric keypad 6.
keycode  78 = F114    # Numeric keypad +.
keycode  79 = F101    # Numeric keypad 1.
keycode  80 = F102    # Numeric keypad 2.
keycode  81 = F103    # Numeric keypad 3.
keycode  82 = F100    # Numeric keypad 0.
keycode  83 = F116    # Numeric keypad ..
keycode  96 = F115    # Numeric keypad Enter.
keycode  98 = F111    # Numeric keypad /.

Furthermore, it is necessary to define the escape sequences that these keys transmit, so add these lines to the end of the file:

string F100 = "\\033Op"
string F101 = "\\033Oq"
string F102 = "\\033Or"
string F103 = "\\033Os"
string F104 = "\\033Ot"
string F105 = "\\033Ou"
string F106 = "\\033Ov"
string F107 = "\\033Ow"
string F108 = "\\033Ox"
string F109 = "\\033Oy"
string F110 = "\\033OP"
string F111 = "\\033Oo"
string F112 = "\\033Oj"
string F113 = "\\033Om"
string F114 = "\\033Ok"
string F115 = "\\033OM"
string F116 = "\\033On"

“\\033” is the octal representation of ESCAPE. These are the same escape sequences that will be transmitted by these keys when running xterm, after following the remaining steps. 

Although function keys F6 through F12 are compatible with xterm, F1 through F5 are not. To fix this, add these lines:

string F1 = "\\033[11~"
string F2 = "\\033[12~"
string F3 = "\\033[13~"
string F4 = "\\033[14~"
string F5 = "\\033[15~"

It is recommended that the following keycodes be defined so the keysyms (the names following the equals signs) will match the keycaps. However, this will not change the escape sequences transmitted, since these keysyms are only synonyms for the original keysyms:

keycode 102 = Home      # Was Find.
keycode 104 = PageUp    # Was Prior.
keycode 107 = Enc       # Was Select.
keycode 109 = PageDown  # Was Next.

One very nice feature is to be able to hold down the ALT key while using the arrow keys to pan within Emacs. Since ALT-Left and ALT-Right were previously used to switch virtual consoles, those functions will be remapped to CTRL-Left and CTRL-Right. 

Change these two lines as shown:

# Ctrl-Left (was Alt)
control keycode 105 = Decr_Console
# Ctrl-Right (was Alt)
control keycode 106 = Incr_Console

And add the following lines:

alt     keycode 103 = F117   # Left Alt-Up Arrow
altgr   keycode 103 = F117   # Right Alt-Up Arrow
alt     keycode 105 = F120   # Left Alt-Left Arrow
altgr   keycode 105 = F120   # Right Alt-Left Arrow
alt     keycode 106 = F119   # Left Alt-Right Arrow
altgr   keycode 106 = F119   # Right Alt-Right Arrow
alt     keycode 108 = F118   # Left Alt-Down Arrow
altgr   keycode 108 = F118   # Right Alt-Down Arrow
string F117 = "\\033\\033[A"   # Alt-Up Arrow
string F118 = "\\033\\033[B"   # Alt-Down Arrow
string F119 = "\\033\\033[C"   # Alt-Right Arrow
string F120 = "\\033\\033[D"   # Alt-Left Arrow

Note ALT-arrow transmits an ESCAPE followed by the normal escape sequence for the arrow key. 

Of course, CTRL-ALT-DELETE will reboot Linux, but what if the user is finished for the day and wants a quick shutdown? To make CTRL-ALT-H-END shut down Linux, add the following lines:

# Numeric keypad End
control alt     keycode  79 = KeyboardSignal
control altgr   keycode  79 = KeyboardSignal
# Editing keypad End
control alt     keycode  107 = KeyboardSignal
control altgr   keycode  107 = KeyboardSignal

Then save the file, and edit /etc/inittab. Add or edit the following lines as shown:

# Action on special keypress (CTRL-ALT-END).
kb::kbrequest:/sbin/shutdown -h now

Save the file, and everything is ready to be tested. Type:

# loadkeys custom.map

and try the new keys. DELETE should act as BACKSPACE did before. Caps Lock has been switched with the left CTRL key. Exit all programs, then try CTRL-ALT-END. After shutdown, use the hardware reset button to reboot. 

If the keyboard passed these basic tests, us.map can be replaced with custom.map. Regular users may encounter errors when running loadkeys, because it requires read access to /dev/console. Furthermore, different users using different maps could cause confusion. Therefore, it is suggested the new keymap be permanently installed on the system by root.

Warning: If these installation instructions are not followed correctly, it is possible to place the keyboard in an unusable state, forcing the user to reboot from the installation floppies. Please take any necessary precautions before proceeding.

To install custom.map permanently, edit /etc/init.d/boot, or whichever boot script contains the loadkeys command, and add the following line to the top of the file:


Then replace the loadkeys command with:

if [ -f $custom_keys ]  # If custom keys exist,
then                            # then load them.
  loadkeys $custom_keys
else                            # Else use the regular keys.
  loadkeys /usr/lib/kbd/keytables/us.map

This way, if custom.map somehow gets deleted, the keyboard will still work. Run this script to make sure it is correct. If it works, the new keymap will be automatically activated at the next system boot. 

X Window System

Now start X as root. Change the directory to /etc/X11 and look at the file Xmodmap. Most likely, this file is empty, except for some comments. If not, rename it to Xmodmap.old, exit the window manager and restart X.

Starting with an empty Xmodmap is important, because when X comes up, it creates its keyboard modifier map and keymap table based on the kernel’s current keyboard translation tables, which were just reconfigured. X then reads the Xmodmap file, which overrides the kernel. This could destroy some of the benefits of the work just completed on the kernel.

Since the kernel has already been reconfigured, the work of configuring X will be reduced by the work already done in creating custom.map. Specifically, DELETE and BACKSPACE will still transmit DELETE and BACKSPACE, because X got that information from the kernel.

Now enter the following command to replace Xmodmap with the current keymap table:

# xmodmap -pke > /etc/X11/Xmodmap

Edit Xmodmap. It appears similar to the file custom.map, but do not be misled. The keycodes are different. To find the keycode number for a given key, run xev from an xterm, put the mouse cursor inside the xev window, and press the key. Look for the key’s “keycode” in the output. For more information, see xev(1) and xmodmap(1).

Finally, to switch the Caps Lock and the left CTRL key, add these lines to the end of the file:

! Recreate the Lock and Control modifier maps.
clear Lock
clear Control
add Lock = Caps_Lock
add Control = Control_L Control_R

To be able to configure keys on the numeric keypad, they must be given an appropriate keysym following the equals sign. Therefore, change the following lines as shown:

keycode  63 = KP_Multiply
keycode  77 = KP_F1
keycode  79 = KP_7
keycode  80 = KP_8
keycode  81 = KP_9
keycode  82 = KP_Subtract
keycode  83 = KP_4
keycode  84 = KP_5
keycode  85 = KP_6
keycode  86 = KP_Add
keycode  87 = KP_1
keycode  88 = KP_2
keycode  89 = KP_3
keycode  90 = KP_0
keycode  91 = KP_Decimal
keycode 108 = KP_Enter
keycode 112 = KP_Divide

Keycodes 99 and 105 are assigned to the keysyms Prior and Next, respectively. Just as was done in custom.map, change them to the following keysyms, which are functionally equivalent, but match the keycaps:

keycode  99 = Page_Up
keycode 105 = Page_Down

Now save the file, then type:

# xmodmap /etc/X11/Xmodmap

to activate the new definitions. If your keyboard will not work at all, use CTRL-ALT-BACKSPACE to exit X. Then use a virtual console to fix the problem. 


The xterm program receives keysyms from X and converts them into characters and into escape sequences. Since xterm emulates a VT102 terminal, it requires little configuration work.

Edit the /etc/X11/Xresources file, and add the following line:

XTerm*ttyModes: erase ^H

This automatically makes BACKSPACE (CTRL-H) delete characters to the left of the cursor. It is the same as if the user typed:

$ stty erase ^H

every time an xterm was started. Also add this line:

XTerm*appkeypadDefault: true

This will cause the keys of the numeric keypad to transmit their escape sequences instead of numbers, operators, etc. It is the same as if the user pressed CTRL–MiddleButton and selected “Enable Application Keypad” in every xterm window. 

Unfortunately, Emacs normally resets the numeric keypad when it exits, so the keys no longer transmit escape sequences. To correct this behavior, the “rmkx” capability must be removed from the terminfo(5) database:

# cd /etc/terminfo/x
# infocmp xterm > xterm.txt
# emacs xterm.txt

Remove the “rmkx” entry, save the file, and exit. Then:

# tic xterm.txt
# rm xterm.txt

It is also necessary to tell xterm what the ALT-Arrow keys transmit, and what the HOME and END editing keys transmit. (The default escape sequences that xterm uses for HOME and END are unconventional.) Type the first seven lines below. Then cut and paste the remaining lines from the xterm(1) man page, underneath the heading, “The default bindings in the VT102 window are.”

Alt <KeyPress> Up:string(0x1b) string(0x1b) string("OA")
Alt <KeyPress> Down:string(0x1b) string(0x1b) string("OB") \\n\\
Alt <KeyPress> Right:string(0x1b) string(0x1b) string("OC") \\n\\
Alt <KeyPress> Left:string(0x1b) string(0x1b) string("OD") \\n\\
<KeyPress> Home:string(0x1b) string("[1~") \\n\\
<KeyPress> End:string(0x1b) string("[4~") \\n\\
Shift <KeyPress> \
        Prior:scroll-back(1,halfpage) \\n\\
Shift <KeyPress> \
        Next:scroll-forw(1,halfpage) \\n\\
Shift <KeyPress> \
        Select:select-cursor-start() \\n\\
Shift <KeyPress> select-cursor-end(PRIMARY, \
        CUT_BUFFER0) \\n\\
Shift <KeyPress> Insert:insert-selection(PRIMARY,\
        CUT_BUFFER0) \\n\\
~Meta<KeyPress>:insert-seven-bit() \\n\\
Meta<KeyPress>:insert-eight-bit() \\n\\
!Ctrl <Btn1Down>:popup-menu(mainMenu) \\n\\
!Lock Ctrl <Btn1Down>:popup-menu(mainMenu) \\n\\
!Mod2 Ctrl <Btn1Down>:popup-menu(mainMenu) \\n\\
!Mod2 Lock Ctrl \
        <Btn1Down>:popup-menu(mainMenu) \\n\\
~Meta <Btn1Down>:select-start() \\n\\
~Meta <Btn1Motion>:select-extend() \\n\\
!Ctrl <Btn2Down>:popup-menu(vtMenu) \\n\\
!Lock Ctrl <Btn2Down>:popup-menu(vtMenu) \\n\\
!Mod2 Ctrl <Btn2Down>:popup-menu(vtMenu) \\n\\
!Mod2 Lock Ctrl \
        <Btn2Down>:popup-menu(vtMenu) \\n\\
~Ctrl ~Meta <Btn2Down>:ignore() \\n\\
~Ctrl ~Meta <Btn2Up>:insert-selection(PRIMARY, CUT_BUFFER0) \\n\\
!Ctrl <Btn3Down>:popup-menu(fontMenu) \\n\\
!Lock Ctrl <Btn3Down>:popup-menu(fontMenu) \\n\\
!Mod2 Ctrl <Btn3Down>:popup-menu(fontMenu) \\n\\
!Mod2 Lock Ctrl \
        <Btn3Down>:popup-menu(fontMenu) \\n\\
~Ctrl ~Meta <Btn3Down>:start-extend() \\n\\
~Meta <Btn3Motion>:select-extend() \\n\\
<BtnUp>>>>>>>>:select-end(PRIMARY, CUT_BUFFER0) \\n\\

Make sure each line ends exactly as shown, and there is not even a blank space after the last backslash on each line. Then change “Prior” to “Page_Up,” change “Next” to “Page_Down,” and change “Select” to “End” to match the keycaps. 

ALT-Arrow transmits an ESCAPE (0x1b in hexadecimal) followed by the escape sequence for the arrow key, but ALT-<Keypress> sets the eighth bit of that key (examine the line that begins with “Meta<KeyPress>”). Also, the escape sequences for the ALT-arrow keys are not the same as were used in custom.map. For a full explanation of this file’s format, see the RESOURCES heading under X(1). Save the file. Type:

# xrdb /etc/X11/Xresources

to activate the definitions. The BACKSPACE key should now work properly the next time an xterm is started.


Create a new file, /etc/inputrc for system-wide use or ~/.inputrc for personal use. This will be a readline startup file (see bash(1)).

First, make the DELETE key delete characters under the cursor, and make HOME and END work by adding:

DEL: delete-char
# Home.
"\\e[1~": beginning-of-line
# End.
"\\e[4~": end-of-line"

DEL is a special symbol bash understands to be DELETE. For the HOME and END keys, their escape sequences are given in quotation marks, followed by a colon, and then the command.

To determine the escape sequence transmitted by a key, look it up in custom.map. Alternately, bring up Emacs, then type CTRL-Q followed by the key. That will usually insert the escape sequence into the buffer. The ESCAPE character will appear as ^[, i.e., control-left bracket.

The readline commands shown thus far are taken from the bash man page. If you would like to program a key to enter a regular command when pressed, put the command in quotation marks. For example, to make the 1 key on the numeric keypad list the current directory, add these lines:

# KP_1
"\\eOq": "ls\\C-m"

The \\C-m is a CTRL-M, or a carriage return, which, as we know, is necessary to execute the command.

Other keys may be programmed as desired. Save the file.

If a system-wide /etc/inputrc file was created, add the following line to /etc/profile:

export INPUTRC=/etc/inputrc

Then type:

# . /etc/profile

This will override the default initialization file, ~/.inputrc. 

Regardless of where the file was created, it may now be activated by typing CTRL-XCTRL-R, which is normally bound to the readline command “re-read-init-file.”


Create a new file, /etc/lesskey, for system-wide use. This will be a lesskey(1) input file. Type these lines exactly as shown and then save the file:

\\177    delete
^H      backspace
\\e[1~   home
\\e[4~   end

The control line, #line-edit, introduces bindings for line-editing commands. \\177 is the octal representation of DELETE, and ^H represents CTRL-H, which is a BACKSPACE. The escape sequences are those transmitted by the HOME and END keys.

Compile the file as follows:

# lesskey -o /etc/less /etc/lesskey

Add the following line to /etc/profile:

export LESS="-k/etc/less$"

Then type:

# . /etc/profile

The next time less is executed, it will read the key definitions from /etc/less. When entering a command line at the bottom of the screen (for example, the pattern for a search command), these key definitions will be active. 

If a user wants to add personal key definitions to less, they may be placed in a file, say ~/lesskey, then compiled as follows:

# lesskey -o ~/.less ~/lesskey

These personal key definitions will be activated in addition to those defined system-wide.

Netscape and Minicom

Since Netscape is from the DOS/Windows world, it requires no special configuration. The designers made BACKSPACE, DELETE, HOME, END, PAGE UP and PAGE DOWN work just as expected. It simply shows that somebody did a good job, and it lends credibility to this design.

If minicom is used, then as root, enter the command:

# minicom -s

This will activate the configuration menu for minicom. Select “Screen and keyboard” from the menu. Type “A,” then press the space bar. Use “B” to determine what BACKSPACE should transmit. Since most remote systems will use DELETE to delete to the left, “DEL” is probably the best choice here. If this creates a problem, change it to BS. Press ESC when done.

Back at the configuration menu, select “Save setup as dfl,” then “Exit from Minicom.”


Emacs can be executed in at least three different environments: in a virtual console, in an xterm, or in an X11 window manager. To run Emacs within an xterm, the -nw option must be used. Regardless of the environment, the keys will be made to perform identical functions.

Emacs contains a series of many keymaps that translate input events into other input events and eventually into commands. Three of these keymaps are diagrammed in Figure 1. The ellipses indicate the omission of keymaps beyond the scope of this article.

As root, change directory to /usr/lib/emacs/XX.XX/lisp/term, where XX.XX is the version of Emacs installed. This directory contains initialization files for several types of terminals. Read the README file for more information.

Make a backup of xterm.el, then edit this file to look like Listing 1 This file maps the escape sequences sent by the keys onto Emacs vectors of length 1. A vector is a general-purpose Emacs array, and vector values are enclosed in brackets, e.g.,.

Listing 1. xterm.el/con80x25.el

; xterm.el/con80x25.el
; Copyright 1996 John F. Bunch
; Defines function keys for an xterm
; or for a Linux virtual console
; with an IBM PC-compatible 101-key keyboard.

; Clear the function-key-map.
(setq function-key-map (make-sparse-keymap))

; Main function keys:
(define-key function-key-map "\e[11~" [f1])
(define-key function-key-map "\e[12~" [f2])
(define-key function-key-map "\e[13~" [f3])
(define-key function-key-map "\e[14~" [f4])
(define-key function-key-map "\e[15~" [f5])
(define-key function-key-map "\e[17~" [f6])
(define-key function-key-map "\e[18~" [f7])
(define-key function-key-map "\e[19~" [f8])
(define-key function-key-map "\e[20~" [f9])
(define-key function-key-map "\e[21~" [f10])
(define-key function-key-map "\e[23~" [f11])
(define-key function-key-map "\e[24~" [f12])

; Editing keypad:
(define-key function-key-map "\e[2~" [insert])
(define-key function-key-map "\e[1~" [home])
(define-key function-key-map "\e[4~" [end])
(define-key function-key-map "\e[5~" [prior]) ;page-up
(define-key function-key-map "\e[6~" [next])  ;page-down

; Arrow keys (Reset or Normal mode):
(define-key function-key-map "\e[A" [up])
(define-key function-key-map "\e[B" [down])
(define-key function-key-map "\e[C" [right])
(define-key function-key-map "\e[D" [left])
(define-key function-key-map "\e\e[A" [M-up])
(define-key function-key-map "\e\e[B" [M-down])
(define-key function-key-map "\e\e[C" [M-right])
(define-key function-key-map "\e\e[D" [M-left])

; Arrow keys (Set or Application mode):
(define-key function-key-map "\eOA" [up])
(define-key function-key-map "\eOB" [down])
(define-key function-key-map "\eOC" [right])
(define-key function-key-map "\eOD" [left])
(define-key function-key-map "\e\eOA" [M-up])
(define-key function-key-map "\e\eOB" [M-down])
(define-key function-key-map "\e\eOC" [M-right])
(define-key function-key-map "\e\eOD" [M-left])

; Numeric keypad:
(define-key function-key-map "\eOP" [kp-f1])
(define-key function-key-map "\eOo" [kp-divide])
(define-key function-key-map "\eOj" [kp-multiply])
(define-key function-key-map "\eOm" [kp-subtract])
(define-key function-key-map "\eOk" [kp-add])
(define-key function-key-map "\eOM" [kp-enter])
(define-key function-key-map "\eOn" [kp-decimal])
(define-key function-key-map "\eOp" [kp-0])
(define-key function-key-map "\eOq" [kp-1])
(define-key function-key-map "\eOr" [kp-2])
(define-key function-key-map "\eOs" [kp-3])
(define-key function-key-map "\eOt" [kp-4])
(define-key function-key-map "\eOu" [kp-5])
(define-key function-key-map "\eOv" [kp-6])
(define-key function-key-map "\eOw" [kp-7])
(define-key function-key-map "\eOx" [kp-8])
(define-key function-key-map "\eOy" [kp-9])

When Emacs is executed in an xterm or a virtual console, it reads this file. The function-key-map is then configured such that when any of these keys are pressed, Emacs automatically translates the escape sequences into vectors. This makes it easier to configure Emacs, not only because all of the keys can be referred to by their names, but also because the programmer never needs to remember the escape sequences after this file has been created. Furthermore, these vectors have the same names as the X Window keysyms, thereby providing consistency among all three execution environments.

The PAGE UP/DOWN keys are now referred to as prior and next. These definitions provide support for some of the Emacs commands, such as calendar, which expect these keys to be available. Also, even though /etc/X11/Xmodmap defines these keys to transmit the Page_Up and Page_Down keysyms, Emacs sees them as prior and next when running under X.

Two sets of definitions are listed for the arrow keys, Reset or Normal and Set or Application. This is because the VT100 series of terminals has two modes of operation in which keys transmit different escape sequences. Notice that in /usr/lib/kbd/keytables/custom.map, ALT-UP ARROW 17) transmits \\e\\e[A, but in /etc/X11/Xresources, ALT-UP ARROW transmits \\e\\eOA. In both cases, these are an ESCAPE followed by the escape sequence transmitted by the UP ARROW key. One method of dealing with this problem is simply to define both sets of escape sequences, as is shown here.

The configuration file, xterm.el, needs be compiled for increased performance, as well as to overwrite the previously compiled version. After saving the file, enter the following command:

# emacs -batch -f batch-byte-compile xterm.el

Since this file is also designed for the virtual consoles, make links as follows:

# ln -s xterm.el con80x25.el
# ln -s xterm.elc con80x25.elc

The .elc files, which are compiled, are the ones used by Emacs. 

For running Emacs directly under X, some changes need to be made to x-win.el. Please make a backup copy, then find and change the following lines as shown:

(define-key function-key-map [backspace] [?\\b])
(define-key function-key-map [M-backspace] [?\\M-\\b])
(put 'backspace 'ascii-character 8)

Save the file. Compile it with:

# emacs -batch -f batch-byte-compile x-win.el

Emacs does not need to know about escape sequences when running directly under an X11 window manager, because it receives the keysyms directly and converts them into vectors automatically. However, since the design states that the BACKSPACE key transmits a BACKSPACE, not a DELETE, three lines had to be changed to make x-win.el comply. Note that M-backspace is short for Meta-backspace, which is a synonym for ALT-backspace. 

Now it is finally time for the last step, assigning functions to the Emacs keys. Change the directory to /usr/lib/emacs/site-lisp, which is where local Emacs Lisp programs are stored.

Create a file named “ibmkey.el” to define the key bindings for an IBM PC-compatible keyboard. Enter as much of Listing 2, ibmkey.el, as desired.

Listing 2. ibmkey.el

; ibmkey.el
; Copyright 1996 John F. Bunch

; Clear the key-translation-map (normally defined by loaddefs.el).
(setq key-translation-map (make-sparse-keymap))
; Switch Backspace and Delete.
(define-key key-translation-map "\177" "\^H")
(define-key key-translation-map "\^H" "\177")
; Definitions of Backspace and Delete keys as strings.
(defvar Backspace "\177")
(defvar Delete "\^H")

; Help & Undo.
(global-set-key [f1] 'help-command)
(global-set-key [f1 f1] 'help-for-help)
(global-set-key [f4] 'advertised-undo)

; Backspace.
(global-set-key Backspace 'backward-delete-char-untabify)

; Editing keypad.
(global-set-key [insert] 'overwrite-mode)
(global-set-key Delete 'delete-char)
(global-set-key [home] 'beginning-of-line)
(global-set-key [end] 'end-of-line)

; Pan (use Alt-arrows).
; Scrolls the display without moving the cursor.
(defun pan-up () (interactive)
    (scroll-up 1)
(defun pan-down () (interactive)
    (scroll-down 1)
(defun pan-right () (interactive)
    (scroll-right 1)
(defun pan-left () (interactive)
    (scroll-left 1)
(global-set-key [M-up] 'pan-up)
(global-set-key [M-down] 'pan-down)
(global-set-key [M-left] 'pan-left)
(global-set-key [M-right] 'pan-right)

; Numeric keypad.
; Define kp-f1 (Num Lock) as a prefix key.
(global-set-key [kp-f1] (make-keymap))
; Universal argument.
(global-set-key [kp-f1 kp-f1] 'universal-argument)
; Search
(global-set-key [kp-divide] 'search-backward)
(global-set-key [kp-multiply] 'search-forward)
; Cut & Paste
(global-set-key [kp-decimal] 'set-mark-command)
(global-set-key [kp-subtract] 'kill-region)    ;Cut
(global-set-key [kp-f1 kp-subtract] 'yank)     ;Paste
(global-set-key [kp-add] 'kill-ring-save)      ;Copy
(global-set-key [kp-5] 'kill-line)  ;Cut to end of line.
(global-set-key [kp-f1 kp-5] 'yank) ;Paste.
; Movement
(global-set-key [kp-7] 'beginning-of-line)
(global-set-key [kp-8] 'backward-paragraph)
(global-set-key [kp-9] 'scroll-down)
(global-set-key [kp-f1 kp-9] 'beginning-of-buffer)
(global-set-key [kp-4] 'backward-word)
(global-set-key [kp-f1 kp-4] 'backward-sentence)
(global-set-key [kp-6] 'forward-word)
(global-set-key [kp-f1 kp-6] 'forward-sentence)
(global-set-key [kp-1] 'end-of-line)
(global-set-key [kp-2] 'forward-paragraph)
(global-set-key [kp-3] 'scroll-up)
(global-set-key [kp-f1 kp-3] 'end-of-buffer)
(global-set-key [kp-enter] 'other-window)
; Toggle insert mode.
(global-set-key [kp-0] 'overwrite-mode)

The default Emacs key-translation-map is defined in /usr/lib/emacs/XX.XX/lisp/loaddefs.el. This file is included in the emacs-el (GNU Emacs LISP files) package of the Debian distribution. It normally maps the F1 key and the HELP key (if present) to BACKSPACE, because BACKSPACE (CTRL-H) is normally mapped to the Emacs help-command in the global-map. Refer to Figure 1.

However, to accommodate the design presented here, the key-translation-map will be redefined. Since Emacs is based on the assumption that DELETE is to be used to delete characters to the left of the cursor, and since the design presented here assumes that the BACKSPACE key will perform that function, the key-translation-map will be used to switch the BACKSPACE and the DELETE keys. After this is done, pressing the BACKSPACE key will cause a DELETE to come out of the key-translation-map, and pressing DELETE will cause a BACKSPACE to come out.

To reduce confusion, the variable “BACKSPACE” is defined to hold a DELETE, and the variable “DELETE” is defined to hold a BACKSPACE. This way, when BACKSPACE is pressed, the value of the variable “BACKSPACE” will come out of the key-translation-map, and when DELETE is pressed, the value of the variable “DELETE” will come out, thus eliminating the confusion caused by the switch.

Many function keys are defined as examples, using the global-map. Since BACKSPACE is no longer available for help, F1 is now mapped directly to that function, without the use of the key-translation-map. F4 is mapped to Undo. The BACKSPACE key and the editing keys are defined to perform their labeled functions, except for prior and next, which are already defined by Emacs (see loaddefs.el). While holding down ALT, the arrow keys will pan the text in all four directions. Finally, the keys of the numeric keypad are defined to perform various functions.

There are several sources of information for programming Emacs. Press F1 twice to access the extensive online help facility. Also, the GNU Emacs Lisp Reference Manual (800+ pages) is available at ftp://prep.ai.mit.edu/pub/gnu/elisp-manual-19-2.4.tar.gz for the truly serious Emacs Lisp programmer. This manual can also be ordered from the Free Software Foundation. The order forms are located in /usr/lib/emacs/XX.XX/etc/ORDERS*.

Now save, and then compile ibmkey.el:

# emacs -batch -f batch-byte-compile ibmkey.el

Finally, edit /usr/lib/emacs/site-lisp/site-start.el, and add this line:

(load "ibmkey")

This file will automatically load ibmkey.el (or ibmkey.elc, if ibmkey.el was compiled) when Emacs is started by anyone on the system. If personal key mappings are desired, place them in ~/.emacs. 


The techniques for configuring and programming the keyboard for the Linux kernel, the X Window System, xterm, bash, less, Netscape, minicom and Emacs have been presented. Table 1. Configuration Files and Commands summarizes the configuration files and commands.

Table 1

Program Configuration File(s) to Edit Initialization/Compilation Command(s)
Linux kernel /usr/lib/kbd/keytables/custom.map loadkeys /usr/lib/kbd/keytables/custom.map /etc/rc.boot/console
X Window System /etc/X11/Xmodmap xmodmap /etc/X11/Xmodmap
xterm /etc/X11/Xresources xrdb /etc/X11/Xresources
bash /etc/profile export INPUTRC=/etc/inputrc /etc/inputrc
Control-X Control-R less /etc/lesskey export LESS=/etc/less lesskey -o /etc/less /etc/lesskey
minicom /var/lib/minicom/minirc.dfl None.
emacs /usr/lib/emacs/XX.XX/lisp/term/ emacs -batch -f
batch-byte-compile <file>.el xterm.el

After following these instructions, the keyboard should be configured to act more like the keyboard the typical user is accustomed to. The editing keys will perform as labeled. The Caps Lock and left CTRL keys will be switched. Various other keys will perform useful functions. Furthermore, the basic techniques discussed here can be applied to other computer programs which permit configuration of the keyboard.

John Bunch, bunch@ro.com, is a member of University Baptist Church in Huntsville, Alabama, where he sings in the choir. To pay his bills and those of his church, he works as a Software Consultant for Intergraph Corporation. He holds a B.S. in computer science from the University of Tennessee, Knoxville, and a M.S. in computer science from East Tennessee State University, Johnson City.


Check Also

linux security

Focus: Kernel Internals

Don Marti Issue #82, February 2001 It’s Special Kernel Issue time. Expecting a thick magazine ...