Linux Backspace/Delete mini-HOWTO

Sebastiano Vigna

vigna@acm.org

Revision History
Revision v1.619 Jan 2002
Included many comments from Alex Boldt and Chung-Rui Kao.
Revision v1.53 May 2000
Updated for new distros and the tput trick.
Revision v1.47 December 2000
Updated for Red Hat 7.0 and Helix Gnome conflicts.
Revision v1.318 October 2000
Name change.
Revision v1.215 October 2000
Updated. Added "What If Nothing Works" section.
Revision v1.113 September 2000
Added tcsh fixes
Revision v1.05 September 2000
First release

Table of Contents
1. Introduction
2. How Keys Are Turned Into Actions
3. Why It Doesn't (Always) Work
4. X
5. What You Should Do When Writing Applications
6. What You Should Do On Your System
6.1. What Needs to Be Done
6.2. How to Do It
6.3. Fixing for tcsh
7. What If Nothing Works
8. More Hacking
9. Conclusions

1. Introduction

Every Linux user has been sooner or later trapped in a situation in which having working Backspace and Delete keys on the console and on X seemed impossible. This paper explains why this happens and suggests solutions. The notions given here are essentially distribution-independent: due to the widely different content of system configuration files in each distribution, I will try to give the reader enough knowledge to think up his/her own fixes, if necessary.

I assume that the Backspace key should go back one character and then erase the character under the cursor. On the other hand, the Delete key should delete the character under the cursor, without moving it. If you think that the function of the two keys should be exchanged, in spite of the fact that most keyboards feature an arrow pointing to the left () on the Backspace key, then this paper will not give you immediate solutions, but certainly you may find the explanations given here useful.

Another assumption is that the fixes should alter only local (user) files. No standard part of the distribution should be altered. Finally, this document discusses how to set up your system so that applications get the right events. If an application decides to interpret such events in an idiosyncratic way, the only possible fix is to reconfigure the application.

Note

Since the first release of this Mini-HOWTO things have become even more entangled. Different distributions of the same terminal emulator (e.g., gnome-terminal as provided by Red Hat 7.0, Helix Code/Ximian or even Red Hat≥7.1) generate different ASCII sequences. Due to this mismatch, now the terminal databases correspond even less to the terminal emulators they are supposed to describe. To set a firm ground for the following discussion, we assume basically as correct settings the ones proposed in the Debian keyboard policy.


2. How Keys Are Turned Into Actions

When a key is pressed on the keyboard, a number of hardware and software components cooperate so as to guarantee that the intended meaning of the key (e.g., emitting a certain character) matches the actual behaviour of the key. I will concentrate on the software side (as our control on the hardware part is nonexistent), and in particular, for the time being, on the events related to console output.

  1. Hitting a key causes raw keyboard scancodes to be generated; these scancodes are then transformed in a keycode. On an i386 system, usually the key Backspace emits 14 and the key Delete emits 111.

  2. The keycodes are translated by the keyboard library into a keyboard symbol (keysym) using the keyboard definition loaded by the user. If you look into your keyboard database (e.g., in /lib/kbd/), you'll discover several definitions for different computers, different layouts and possibly different interpretations of the same keys (e.g., one could desire that the two Alt keys really behave as distinct modifiers). The Linux console keyboard layout assigns keysym Delete to keycode 14 and keysym Remove to keycode 111. This may seem strange, but the Linux console emulates a VT100 terminal, and this is the way things work in that realm.[1]

  3. Our journey has still to come to an end. Console applications read ASCII sequences, not keysyms. So the console must read keysyms and translate them into ASCII sequences that suitably encode the keys. Of course, this operation must be performed in a way that is understandable by applications. For instance, on the Linux console the Delete keysym is mapped to the ASCII code 127 (DEL), the Remove keysym on a suitable escape sequence, and the BackSpace keysym to ASCII code 8 (BS).

  4. Finally, we must in a sense roll back to what we had before and translate the ASCII sequences generated by each key into a key capability. This goal is reached by a terminal database, which contains, for each kind of terminal, a reverse mapping from sequences of characters to key capabilities (which are essentially a subset of the keysyms).[2]

    Note

    Unfortunately, there are two "standard" terminal databases, termcap and terminfo. Depending on your distribution, you could be using either one of them, or the database could even depend on the application. Our discussion will concentrate on the more modern terminfo database, but the suggested fixes take both into consideration.

    For instance, on the Linux console F1 generates an escape followed by [[A, which can be translated to the capability key_f1 by looking into the terminal-database entry of the console (try infocmp linux if you want to have a look at the entry). A very good and thorough discussion of terminal databases can be found in GNU's termcap manual. Usually Linux applications use the newer terminfo database, contained in the ncurses package.

    Maybe at this point not surprisingly, the Linux console terminfo entry maps DEL to the kbs (backspace key) capability, and escape followed by [3~ to the kdch1 ("delete-one-char" key) capability. Even if you could find strange that the Backspace key emits a DEL, the terminal database puts everything back into its right place, and correctly behaving applications will interpret DEL as the capability kbs, thus deleting the character to the left of the cursor.


3. Why It Doesn't (Always) Work

I hope the basic problem is clear at this point: there is a bottleneck between the keyboard and console applications, that is, the fact that they can only communicate by ASCII sequences. So special keys must be first translated from keysyms to sequences, and then from sequences to key capabilities. Since different consoles have different ideas about what this translation can look like, we need a terminal database. The system would work flawlessly, except for a small problem: it is not always set up correctly, and not everyone uses it.

Applications must have a way to know which database entry to use: this is accomplished by suitably setting the TERM environment variable. In some cases, there is a mismatch between the terminal emulator and the content of the database entry suggested by TERM.

Moreover, many applications do not use the terminal database (or at least not all of it), and consider BS and DEL ASCII codes with an intended meaning: thus, without looking at the database, they assign them semantics (usually, of course, the semantics is removing the character before or under the cursor). So now our beautiful scheme is completely broken (as every Linux user is bitterly aware). For instance, the bash assumes that DEL should do a backward-delete-char, that is, backspace. Hence, on a fresh install the Backspace key works on the console as expected, but just because of two twists in a row! Of course, the Delete key does not work. This happens because the bash does not look into the terminal database for the kdch1 capability.

Just to illustrate how things have become entangled, consider the fix_bs_and_del script provided with the Red Hat distribution (and maybe others). It assigns on-the-fly the BackSpace keysym to the Backspace key, and the Delete keysym to the Delete key. Now the shell works! Unfortunately, all programs relying on the correct coupling of keysym generation and terminal database mappings are now not working at all, as the Delete keysym is mapped to DEL, and the latter to the kbs key capability by the terminfo database, so in such programs both keys produce backspacing.


4. X

The situation under X is not really different. There is just a different layer, that is, the X window system translates the scancodes into its own keysyms, which are much more varied and precise than the console ones, and feeds them into applications (by the way, this is the reason why XEmacs is not plagued by the problem: X translates keycode 22 to keysym BackSpace and keycode 107 to keysym Delete, and then the user can easily assign to those keysyms the desired behaviour). Of course, a terminal emulator program (usually a VT100 emulator in the X world) must translate the X keysyms into ASCII sequences, so we are again in our sore business.

More in detail, usually xterm behaves exactly like the console (i.e., it emits the same ASCII sequences), but, for instance, gnome-terminal in Red Hat <7.0 or ≥7.1 emits BS for Backspace and DEL for Delete. The real fun starts when you realise that by default they use the same terminal-database entry, so the fact that the kbs capability is associated to an ASCII DEL makes all correctly behaving applications produce the same behaviour for the Backspace and Delete keys in gnome-terminal. The simple statement

bash$ export TERM=gnome
can solve the problem in this case for correctly behaving applications. Well, not always, because your system could lack an entry in the terminal database named gnome, in particular if it is not very up-to-date.

In any case, this is not always a solution: if, for instance, you have a Red Hat 7.0 distribution, your gnome-terminal behaves like a console. But beware: if you upgraded your desktop using the Helix distribution, then your gnome-terminal behaves like a pre-7.0 Red Hat.

Just to make easier the following discussion, let us define standard a VT100 emulator behaving like the console, and deviant one that emits BS for Backspace and DEL for Delete.[3] Thus, for instance, xterm has always been standard in the Debian distribution, while it switched a couple of times from standard to deviant and viceversa in Red Hat; the behaviour of gnome-terminal is even more erratic. See Section 8 for some information on how to turn a deviant terminal into a standard one.


5. What You Should Do When Writing Applications

When you write a console application, be kind to the user and try to understand what comes from the standard input using the following fallback chain:

  1. open the right terminfo entry, and try to process the sequence so as to discover whether it has a particular meaning on the current terminal; if so, use the terminfo semantics;

  2. use the ASCII intended meaning on line feeds, newlines, tab characters and, of course, BS and DEL. Crossing your finger could also be useful.


6. What You Should Do On Your System

Note again that the main issue that confuses people trying to fix their system is that usually they are fixing thing in the wrong place. Since the parts that work often just work by chance, trying to fix the system assuming something is broken will often lead to change correct settings into incorrect settings.


6.1. What Needs to Be Done


6.2. How to Do It

Caution

These fixes have some drawbacks. First, they work only for the specified terminals. Second, in theory (but this is unlikely to happen) they could confuse the readline library on other terminals. Both limitations are however mostly harmless.

First of all, check with infocmp gnome whether you already have a gnome entry in your terminfo database (we will fix termcap later). If the entry does not exist, the following command

bash$ tic <(infocmp xterm |\
        sed 's/xterm|/gnome|/' |\
        sed 's/kbs=\\177,/kbs=^H,/' |\
        sed 's/kdch1=\\E\[3~,/kdch1=\\177,/')
will create a correct one in ~/.terminfo. If the same command is launched by the root, it will generate the entry in the global database (you can override this behaviour by setting TERMINFO to ~/.terminfo). Note that if your xterm entry is already deviant (e.g., you have a Red Hat ≤5.0) the script will copy it unchanged, which is exactly what we want.

Now, add the following snippet to ~/.inputrc[4]:

"\e[3~": delete-char
This line teaches the readline library how to manage your standard Delete key for standard emulators, and with a bit of luck it should not interfere with other terminals. However, now we must also explain to the library the meaning of the DEL character on deviant terminals, for instance by adding

$if term=gnome
DEL: delete-char
Meta-DEL: kill-word
"\M-\C-?": kill-word
$endif
to ~/.inputrc. If xterm is deviant, too, you must add other three lines for it. On the other hand, if no terminal emulator is deviant this part is not needed. All these changes can be made global by altering the /etc/inputrc file.

Note that the conditional assignments make deviant terminal emulators work given that the TERM variable is set correctly. To guarantee this, there are a number of techniques. First of all, since the default value of the TERM variable for gnome-terminal is xterm, if all terminals are not deviant then we do nothing. If, however, a terminal that by default uses the xterm entry is deviant you must find a way to set the TERM variable correctly; assume for instance this is true of gnome-terminal.

The simplest way to obtain this effect is to start gnome-terminal with the argument --termname=gnome, for instance by suitably setting the command line in the launcher on the GNOME panel. If however you have an old version, and this method does not work, you can add the lines

if [ "$COLORTERM" = "gnome-terminal" ]
then
    export TERM=gnome
fi
to your ~/.bashrc configuration file[5]. The assignment is executed only under gnome-terminal, and sets correctly the TERM variable.

Note

Setting the terminal to gnome could prevent ls from using colours, as many versions of ls do not know that gnome-terminal is colour capable. To avoid this problem, create a configuration file ~/.dircolors with dircolors --print-database >~/.dircolors, and add a line TERM=gnome to the configuration file.

We will now generate on-the-fly a suitable termcap entry for deviant terminal emulators; this can be done as follows, always in ~/.bashrc:

if [ "$TERM" = "gnome" ]
then
    export TERMCAP=$(infocmp -C gnome | grep -v '^#' | \
                    tr '\n\t' '  ' | sed 's/\\  //g' | sed s/::/:/g)
fi

Finally, we must explain to the terminal device which character is generated by the erase key. Since usually the erase key is expected to backspace, there is a nice trick taken from the Red Hat /etc/bashrc that works: add this to ~/.bashrc:

KBS=$(tput kbs)
if [ ${#KBS} -eq 1 ]; then stty erase $KBS; fi
It's a simple idea: we read from the terminal database the capability kbs, and set the erase character to its value if it is a single character (which happens in both standard and deviant terminals).

Note

Certain distributions could have fixes already in place in the system-wide /etc/inputrc configuration file. In this case you can eliminate redundant lines from your ~/.inputrc.


7. What If Nothing Works

The first thing to do is understanding which ASCII codes are produced by a certain key using the C one-liner.

Once you know which sequences are produced, you must check the current terminfo entry with infocmp (don't be scared by the amount of information printed!) and be sure that the kbs and kdch1 capabilities correspond to the right sequences (that is, the one produced by the respective keys). Moreover, you must check with stty -a that the erase character is the one emitted by the Backspace key (note that ^H represent BS whereas ^? represents DEL).

If there is a mismatch, there can be several different reason: wrong content of the TERM variable, wrong entry of the terminal database, wrong terminal emulation under X. I hope at this point you have enough information to dig the solution autonomously.

Note

If different applications behave in different ways, it is likely that some of them are using the terminal database correctly, and some are not. Remember that the fact that the keys produce the right behaviour in a certain application does not mean that the application is using correctly the terminal database—they could work just by chance. If you want to have an independent check, you can try whether the ne editor works. ne uses all terminal capabilities, including kbs and kdch1, and uses intended meaning only as a last resource.


8. More Hacking

So, you're not happy with the information you got. In this case, there is even more hacking you can do on the Backspace/Delete issue, using suitable commands that get or set the way X and the console handle keys.

It could happen that, for some reason, what I said talking about X is not true, that is, X does not translate keycode 22 to keysym BackSpace and keycode 107 to keysym Delete (or even that, on your particular keyboard, the keycodes associated to Backspace/Delete are not 22 and 107). To be sure of that, you need to use xev, a simple X application that will display the keycode and keysym associated to the key you press. If anything goes wrong, there are several ways you can fix the problem: the easy, temporary way is to use xmodmap, a command that lets you change many settings related to X keyboard handling. For instance,
xmodmap -e "keycode 22 = BackSpace"
xmodmap -e "keycode 107 = Delete"
will set correctly the keysyms (assuming that 22 and 107 are the correct keycodes for you). In case you want to do some changes permanently, you can play with the resources vt100.backArrowKey, vt100.translations and ttyModes of xterm (and similar terminal applications) in the configuration file ~/.Xdefaults. One possibility, for instance, is
XTerm.VT100.Translations: \
        <Key>BackSpace: string(0x7F)\n\
        <Key>Delete:    string("\033[3~")
You should take a look at the xterm man page for more information.

The program that does for the console what xev does for X is showkeys: it will dump the console keycodes of the keys you press. Combining showkeys with dumpkeys, which will print on standard output the console keymap, you can easily fix mismatches between keycodes and keysyms. Analogously to xmodmap, loadkeys can then fix single associations, or load entirely new console keymaps. With it, you can even change the string associated to a given keysym. If you want to record these changes, you will have to define a new keymap for the console (you should have a look at the system keymaps, usually located in /lib/kbd).


9. Conclusions

The fixes suggested here should solve to a large extent the problem of deleting text you wrote (however, they do not help in creating other text :)).

There is a small bug in the whole setting: if you're using the COLORTERM trick and you start xterm from gnome-terminal, the former will get TERM set to gnome. This inconvenience is, of course, mostly harmless, and does not occur if you simply started gnome-terminal with TERM suitably set.

Another nontrivial problem that essentially has no solution is the one concerning remote connections: if you connect to a host whose terminal database is incoherent with yours, you will have to set up things manually.

Finally, it should be noted that the fixes will not work for broken applications (for instance, applications ignoring the kbs key capability). There is little to do in this case, as fixing for one broken application will likely break all well-behaving ones.

Notes

[1]

This claim has been asserted/disputed several times commenting this document. If you have any definitive information on this subject, please write me.

[2]

Some programs rely on the terminal driver for input line editing, such as deleting characters or words. With stty, you can tell the terminal driver what character it should use to delete the character to the left of the cursor (the erase character). You can check your current settings with stty -a and set them with stty erase character.

[3]

Also these definitions have been asserted/disputed several times commenting this document. If you have any definitive information on this subject, please write me.

[4]

On older version of the bash, you must remember to set INPUTRC suitably, for instance adding

export INPUTRC=~/.inputrc
to your ~/.profile (or whichever file is read just by login shells).

[5]

More precisely, to the shell configuration file that is read in every shell, not only in login shells. The right file depend on startup sequence of your bash.