vigna@acm.org
Revision History | ||
---|---|---|
Revision v1.6 | 19 Jan 2002 | |
Included many comments from Alex Boldt and Chung-Rui Kao. | ||
Revision v1.5 | 3 May 2000 | |
Updated for new distros and the tput trick. | ||
Revision v1.4 | 7 December 2000 | |
Updated for Red Hat 7.0 and Helix Gnome conflicts. | ||
Revision v1.3 | 18 October 2000 | |
Name change. | ||
Revision v1.2 | 15 October 2000 | |
Updated. Added "What If Nothing Works" section. | ||
Revision v1.1 | 13 September 2000 | |
Added tcsh fixes | ||
Revision v1.0 | 5 September 2000 | |
First release |
![]() | 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. |
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]
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).
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]
![]() | 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.
bash$ export TERM=gnome |
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.
void main(void) {int c; while(c = getchar()) printf("%d 0x%02X\n", c, c);} |
![]() | 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. |
bash$ tic <(infocmp xterm |\ sed 's/xterm|/gnome|/' |\ sed 's/kbs=\\177,/kbs=^H,/' |\ sed 's/kdch1=\\E\[3~,/kdch1=\\177,/') |
Now, add the following snippet to ~/.inputrc[4]:
"\e[3~": delete-char |
$if term=gnome DEL: delete-char Meta-DEL: kill-word "\M-\C-?": kill-word $endif |
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 |
![]() | 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 |
![]() | 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. |
bindkey "^[[3~" delete-char if ($?COLORTERM) then if ($COLORTERM == "gnome-terminal") then setenv TERM gnome endif endif if ($?TERM) then if ($TERM == "gnome") then setenv TERMCAP \ "`infocmp -C gnome | grep -v '^#' | tr '\n\t' ' ' | sed 's/\\ //g' | sed s/::/:/g`" bindkey "^?" delete-char bindkey "^[^?" delete-word bindkey "\377" delete-word endif endif set KBS=`tput kbs` if (${%KBS} == 1) then stty erase $KBS endif |
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.
![]() | 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. |
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" |
XTerm.VT100.Translations: \ <Key>BackSpace: string(0x7F)\n\ <Key>Delete: string("\033[3~") |
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).
[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
| |
[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. |