Blog

Keyboard problems upon switching from xterm to urxvt

I recently changed my terminal emulator; after several years with the “good old” xterm, I switched to the Unicode-enabled variant of rxvt, urxvt (or rxvt-unicode). Although I am now pleased with urxvt, I ran into a few minor problems when I started to use that emulator, and I would like to expose them here, along with the workarounds I found.

The Home and End problem

The <Home> and <End> keys, which are supposed to move the cursor to the beginning and the end of line, respectively, didn’t work. The reason was that the escape sequences emitted by urxvt when those keys are pressed were not the escape sequences expected by readline. By default, urxvt emits <Esc>[7~ for <Home> and <Esc>[8~ for <End> (this can by verified by typing <Control>-V followed by the desired key, at the terminal prompt). And here are the relevant lines of the default readline configuration file on my Slackware system, /etc/inputrc:

# for linux console
"\e[1~": beginning-of-line
"\e[4~": end-of-line

# for xterm
"\eOH": beginning-of-line
"\eOF": end-of-line

# for freebsd console
"\e[H": beginning-of-line
"\e[F": end-of-line

So, readline maps several escape sequences from several terminal emulators to the beginning-of-line and end-of-line functions, but the sequences from urxvt are not included.

There are (at least) two solutions. The first is to modify the configuration of readline (either in the system-wide /etc/inputrc file, or in my own ~/.inputrc file) to add the missing mapping:

# for urxvt
"\e[7~": beginning-of-line
"\e[8~": end-of-line

The second solution is quite the opposite: modify the configuration of urxvt so that it sends control sequences already recognized by readline. That’s what I did, by adding the following lines to my ~/.Xdefaults file:

urxvt.keysym.Home: \033[1~
urxvt.keysym.End: \033[4~

The Control-L problem

The <Control>-L combination is supposed to clear the terminal screen. There again, in urxvt it didn’t work: pressing <Control>-L only resulted in a new line, as if <Return> has been pressed instead.

I have still not understood the reason for that behavior. Here are the tests I conducted and the conclusions I can draw.

First, the <Control>-L combination is correctly associated to readline’s clear-screen function:

$ bind -P | grep clear
clear-screen can be found on "\C-l".

I can bind another combination to the clear-screen function:

$ bind ‘"\C-g": clear-screen’
$ bind -P | grep clear
clear-screen can be found on "\C-g", "\C-l".

but the new combination <Control>-G produces exactly the same (incorrect) behavior as the default <Control>-L. So I assume the clear-screen is called, but somehow fails to clear the screen as it should.

To clear the screen, readline must send to the terminal an appropriate escape sequence. According to urxvt’s man page, that sequence is <Esc>[H<Esc>[2J. A lookup into the terminfo(5) database confirms:

$ infocmp rxvt-unicode | grep clear
        clear=\E[H\E[2J, cnorm=\E[?25h, cr=^M

Manually emitting that sequence clears the screen as expected:

$ echo -ne "\033[H\033[2J"
(The screen is cleared.)

So the terminfo entry for rxvt-unicode is correct.

Why then readline cannot clear the screen? I don’t know. I guess I’m missing something here, but that’s as far as my understanding of the problem goes.

The workaround I found is quite ugly, I admit: I instructed urxvt (through the ~/.Xdefaults file) to intercept the <Control>-L sequence and to call the clear command:

urxvt.keysym.Control-l: clear\n

Then, I added clear to the HISTIGNORE environment variable, so that my shell history does not get polluted by dozens of clear calls (I use the <Control>-L quite a lot):

HISTIGNORE="clear:$HISTIGNORE"
export HISTIGNORE

UPDATE: I finally found out what the problem was. As I suspected, I was missing something, and the fault is entirely mine.

I had assumed from the beginning that readline retrieves the appropriate escape sequence through terminfo(5), while it really uses termcap(5)! And when I compiled and installed rxvt-unicode (which is not provided by Slackware), I did make sure to update the terminfo database, but I completely neglected the /etc/termcap file. That’s why readline was unable to obtain the escape sequence it needed to clear the screen—while the clear(1) command, which uses terminfo, had no problem. Adding to /etc/termcap the contents of the rxvt-unicode.termcap file (provided in rxvt-unicode’s archive) solved the problem.