# Basti’s Buggy Blog

Poking at software.

# urxvt and Emacs - The Ultimate Guide

One of the major advantages of Emacs is that in addition to working on graphical interfaces, it can be used from a terminal as well. However, some features (such as many keybindings) are not available when using Emacs in terminals, due to ancient protocol limitations. This post shows how to make the most of Emacs on a terminal (urxvt).

“I don’t care about the why, just show me how!"
I got you

## The Goal

The objective is to get all Emacs keybindings to work when running emacs inside the urxvt terminal. The following video demonstrates that emacs running in urxvt can distinguish between C-p and C-S-p:

The following table1 shows all the mappings that can work with emacs in the terminal:

Modifiers Description
S Space key with shift
C [2-8] (note: xterm.el supports other key binds)
C-S [A-Z]
C-M “g” and space keys
M-S [A-Z]
C-M-S [A-Z]
s or s-S from space to “~” (almost 8 bits characters without control sequences)
H or H-S same as s-S, but use Hyper modifier

## Emacs and Terminal Keybindings

If you are an Emacs user, you might have noticed that some keybindings do not work when starting Emacs without a window system (-nw or --no-window-system). The explaination is relatively simple: Whereas the Emacs instance running under X11 has access to all keyboard events (keyup, keydown) etc., the instance running in a terminal emulator is much more limited. Among other shortcomings, Emacs running inside a terminal cannot distinguish between C-<key> (ctrl + key) and C-S-<key> (ctrl + shift + key)!

Try it for yourself: open a new terminal and execute the cat command. All terminal input will now be provided to the cat command as stdin and echoed back stdout and therefore your terminal. Now press C-o and C-S-o and observe the difference (spoiler: there is none).

What’s up with the ^ characters? Those characters are used in combination with [A-Z] characters in order to display ASCII control characters in caret notation. You might have seen this in utilities like less, which show the caret notation for non printable characters like the windows carriage return ^M. But what exactly are they there for?

Let’s do a little test and insert all literal C-<key> sequences in alphabetical order into an Emacs buffer. We can prefix our ctrl + key commands with C-q to do a quoted insert and prevent Emacs from executing keybindings associated with the input. You will see two things:

1. The entered characters have a special font face as they represent non printable bytes
2. The characters ^I and ^J seem to be missing (more on that in a bit)

If you did the steps above, your buffer should look like this:

Let’s inspect it further by using the emacs-integrated hex editor: hexl-mode! This allows us to see the underlying byte representation of those characters we just typed.

We can see that the characters we typed are represented by the bytes 0x01-0x1a. We can have a look into the ASCII table to reveal their meaning. (The table also includes 0x1b-0x1f)

Hex Term Description
0x01 ^A start of heading
0x02 ^B start of text
0x03 ^C end of text
0x04 ^D end of transmission
0x05 ^E enquiry
0x06 ^F acknowledge
0x07 ^G bell
0x08 ^H backspace
0x09 horizontal tab
0x0a new line
0x0b ^K vertical tab
0x0c ^L new page
0x0d ^M carriage return
0x0e ^N shift out
0x0f ^O shift in
0x10 ^P data link escape
0x11 ^Q device control 1
0x12 ^R device control 2
0x13 ^S device control 3
0x14 ^T device control 4
0x15 ^U negative acknowledge
0x16 ^V synchronous idle
0x17 ^W end of block
0x18 ^X cancel
0x19 ^Y end of medium
0x1a ^Z substitute
0x1b ^[ escape
0x1c ^\ file separator
0x1d ^] group separator
0x1e ^^ record separator
0x1f ^_ unit separator
0x7f ^? delete

If you look at the hex-codes 0x09 and 0x0a (where ^I and ^J should have been), you can see that those characters represent a horizontal tab and a new line. This explains why we cannot see them in our emacs buffer. Instead of displaying the control characters in caret notation, emacs simply renders them as a tab and a newline!

As you can see, there are no ASCII control characters represented by a caret and a lowercase character. Therefore the terminal simply can not distinguish between a C-<key> and a C-S-<key> keypress.

## Aside: How the Terminal handles control characters

Before looking for a way to work around this limitation, let us learn about the handling of those control characters a bit more.

While the process behind handling a ^C (end of text in ASCII) input is more complicated, it leads to a SIGINT signal being sent. It shows that the meaning behind the ASCII characters has changed over the course of the last decades and should not be take literally. You can check how your terminal interprets those control characters by executing the command stty -a:

As you can see ^C is translate into “intr”, which causes a SIGINT to be sent.

## How urxvt Solves This Problem

Both, xterm and urxvt, can work around this limitation by being able to capture the keyboard input from the X window system, just like Emacs does in X11 mode. This however is the case for most terminal emulators. The difference that makes xterm and urxvt stand out is their configurability and key-remapping capabilities. Instead of handling the key sequence C-p and C-S-p both as ^P, two distinct actions can be executed.

The idea is to configure both – Emacs and urxvt – in a way that:

1. The pressed key sequence can be uniquely represented by control characters in the terminal
2. Emacs is able to translate the control characters back to the original key sequence

Of course I’m not the first one to discover this possibility since the package xterm-keybinder aims to solve this exact problem. The rest of the article will focus on how xterm-keybinder works under the hood and how to configure it.

### Configuring urxvt

The emacs package xterm-keybinder aims to provide the translation logic for both previously described translation steps.

For the first translation step (keypress to control characters), the package provides a start script which starts urxvt with the right configuration. You can either use this script, or move the configuration into the .Xdefaults file if you want this configuration by default. I recommend using the .Xdefaults file.

As you can see below, the urxvt configuration remaps several key-combinations, which previously could not be represented in the terminal. The mapping follows a specific scheme:

In the example above, urxvt is configured to map the non-terminal-representable key-combinations ending in -F to sequences lead by a control character. You might wonder about the red ^[ (=“escape”/ESC) control character. In Emacs, emitting this control character is equal to pressing Meta (e.g. M-f is equal to ESC f).

In our example whenever C-S-F is pressed, urxvt emits the sequence M-[ [ = F. You can confirm this by using cat in your terminal:

If you would open your emacs -nw now and tried to press C-S-f, you’d disappointedly notice that Emacs does not recognize this input yet. In fact, if you try to type that key combination manually inside Emacs, you should notice that the key combination is not used (unless you configured it otherwise).

### Configuring Emacs

To make Emacs translate the control characters back to the original key-combination, some more work is necessary. You could manually register the sequences that are defined in the ~/.Xdefaults configuration, but that would be very elaborate.

As a proof-of-concept, let’s define two sequences (for multicursor) by hand in urxvt and in Emacs:

This is enough to get the two keybindings working! To automatically setup all other keybindings, refer to the xterm-keybinder documentation1 and the complete configuration files below.

## Complete Configs

If you don’t care about the details, you should be able to get up and running if you integrate the following configuration into your ~/.emacs and your ~/.Xdefaults file.

When making changes to the ~/.Xdefaults file, reload the configuration and restart urxvt:

xrdb -remove ~/.Xdefaults && xrdb -load ~/.Xdefaults


### Emacs

Note: the emacs configuration does not require use-package, I’m just using it out of convenience.

### urxvt

Note: this configuration contains more than the minimal configurations required to make urxvt work.