![]() | ![]() |
|
Linux Backspace/Delete mini-HOWTOSebastiano Vignavigna@acm.org
1. IntroductionEvery 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.
2. How Keys Are Turned Into ActionsWhen 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.
3. Why It Doesn't (Always) WorkI 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. XThe 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
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 ApplicationsWhen 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:
6. What You Should Do On Your SystemNote 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 Done6.1.1. Detecting DevianceThe first step towards a clean solution is to know exactly which terminals are deviant and which not. Usually they all behave like the console, and in this case the modifications to get everything working are minimal. If, however, you have some deviant terminal (e.g., a deviant version of gnome-terminal), you will have to treat it in a special way. The following C one-liner
6.1.2. Distinguishing Between EmulatorsIf you have some deviant terminal emulator, you must distinguish it from the standard ones. Theoretically, this should not be a problem because there are different entries in the terminal database for terminals with different sequences (the entry used depends on the value of the TERM variable). Here we take the approach that the gnome entry should be used for all deviant VT100 emulators, and the xterm entry for the standard ones. This is in line with several distributions (except a few cases like RedHat ≤5.0, where the xterm entry is deviant). However, gnome-terminal uses by default the same entry as xterm, so if one is deviant and the other one is not you will need to find a way to tell them apart. The option termname of gnome-terminal allows the user to set the TERM variable to a more sensible name. However, in older versions of gnome-terminal the option does not work. Moreover, sometimes it is not easy to modify the way gnome-terminal is started. A good idea here is to exploit the fact that gnome-terminal sets the COLORTERM variable to gnome-terminal. Thus, by adding a simple test to the shell configuration files we can fix the TERM variable. 6.1.3. Fixing the Terminal DatabaseOur problem now is that the terminal database could lack a gnome entry for deviant terminals (this happens on a number of termcap and terminfo versions). Recent terminfo databases have an entry gnome, but, in any case, since gnome-terminal behaves essentially like xterm modulo our famous two keys, it is possible to automagically generate a brand new correct entry. 6.1.4. Fixing the Shell BehaviourThe readline library used by the bash and by many other programs to read the input line can be customized so to recognize specific sequences of characters. The customization can also depend on the TERM variable, so once we can distinguish terminals we can do fine tuning of the keyboard. Moreover, if you want less and other application that do raw line input to work correctly, you must convince the shell that under a deviant terminal emulator the erase character is BS, and not DEL (in the other case the Backspace key is already emitting DEL, so we do not have to do anything). This can be done using the command stty. 6.2. How to Do It
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
Now, add the following snippet to ~/.inputrc[4]:
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
We will now generate on-the-fly a suitable termcap entry for deviant terminal emulators; this can be done as follows, always in ~/.bashrc:
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:
6.3. Fixing for tcshIn the case of the tcsh, the fixes go all in ~/.tcshrc, and follow the same rationale as the ones for the bash:
7. What If Nothing WorksThe 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.
8. More HackingSo, 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,
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. ConclusionsThe 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
|