http://invisible-island.net/xterm/modified-keys/
Copyright © 2019 by Thomas E. Dickey


XTerm – “Other” Modified Keys

Background

Like the modified function- and cursor-keys introduced in patch #94 (1999) and refined in patch #167 (2002), xterm can send other keys as special escape sequences. Again, that was due to another developer's suggestion.

In the beginning

It was simple enough, at first:

Subject: support for key bindings for C-. C-, etc etc in xterm?
From: Dan Nicolaescu <dann@ics.uci.edu>
Date: Tue, 04 Apr 2006 15:53:39 -0700

Hi!

Do you plan to add support for the few C-KEY combinations that are not
currently supported (i.e. the ones that don't correspond to any ASCII
sequence).

The reason I am asking is that these keys could be used in emacs, some
modes use them in X11, but they cannot be used in an xterm.
If you add such support to xterm, I'll add the corresponding support
to the emacs CVS right away, the only think needed is the
corresponding escape sequences.

I understand that key bindings are a twisted and hard to understand
business, and I am not sure if this idea has been considered and
rejected before, I apologize if that is indeed the case.

Thanks
        --dan

Emacs users like key bindings, so the request was not really surprising. I had not thought of extending xterm in this manner:

Subject: Re: support for key bindings for C-. C-, etc etc in xterm?
From: Dan Nicolaescu <dann@ics.uci.edu>
Date: Tue, 04 Apr 2006 16:56:04 -0700

Thomas Dickey <dickey@his.com> writes:

  > On Tue, 4 Apr 2006, Dan Nicolaescu wrote:
  >
  > >
  > > Hi!
  > >
  > > Do you plan to add support for the few C-KEY combinations that are not
  > > currently supported (i.e. the ones that don't correspond to any ASCII
  > > sequence).
  >
  > I hadn't thought of that - which ones, for example?
  >
  > xterm supports control-modifiers for function- and keypad-keys.

I know, and I added support for all of them in emacs :-)

  >  Perhaps you're talking about things like control/{, which doesn't
  > correspond to an ASCII control character?

Right.

Right now I am thinking: Control-. Control-, Control-TAB,
At least these have uses in emacs. I would have to think more what
else would be useful, in case you are willing to add support for them.

Thanks
                --dan

I was willing to do this:

Subject: Re: support for key bindings for C-. C-, etc etc in xterm?
From: Dan Nicolaescu <dann@ics.uci.edu>
Date: Wed, 05 Apr 2006 10:10:02 -0700

Thomas Dickey <dickey@his.com> writes:

  > On Tue, 4 Apr 2006, Dan Nicolaescu wrote:
  >
  > > Thomas Dickey <dickey@his.com> writes:
  > >
  > >  > On Tue, 4 Apr 2006, Dan Nicolaescu wrote:
  > >  >
  > >  > >
  > >  > > Hi!
  > >  > >
  > >  > > Do you plan to add support for the few C-KEY combinations that are not
  > >  > > currently supported (i.e. the ones that don't correspond to any ASCII
  > >  > > sequence).
  > >  >
  > >  > I hadn't thought of that - which ones, for example?
  > >  >
  > >  > xterm supports control-modifiers for function- and keypad-keys.
  > >
  > > I know, and I added support for all of them in emacs :-)
  > >
  > >  >  Perhaps you're talking about things like control/{, which doesn't
  > >  > correspond to an ASCII control character?
  > >
  > > Right.
  > >
  > > Right now I am thinking: Control-. Control-, Control-TAB,
  > > At least these have uses in emacs. I would have to think more what
  > > else would be useful, in case you are willing to add support for them.
  >
  > well, offhand (I'll have to think about this, of course), it would be
  > straightforward to add an option that would pass the extra characters
  > as if they were function-keys in the form
  >
  >     \E[27;modifier;code~
  >
  > just like the existing function keys - using the decimal value of the
  > character as the code.

That would work perfectly well from the point of view of emacs.
If you decide this is feasible, please let me know if you need any help
with this.

Thanks
                --dan

I chose this format because it was consistent with the earlier work, and (noticing that 27 was unused) chose that as the primary code. After all, decimal 27 is the “same” as the ASCII escape character.

Subject: Re: support for key bindings for C-. C-, etc etc in xterm?
From: Dan Nicolaescu <dann@ics.uci.edu>
Date: Fri, 12 May 2006 09:20:51 -0700

Thomas Dickey <dickey@his.com> writes:

  > On Sat, 6 May 2006, Dan Nicolaescu wrote:
  >
  > > Have you reached a decision about adding these key bindings to xterm?
  >
  > It's on my list - just lots of realtime nuisances recently.  I thought
  > I might have time in #213, but that became a short bug-fix, rather
  > than new development.  In my to-do list, I have this marked for #214
  > (and will probably do it unless someone points out a nasty
  > fix-it-right-now-bug).

Thanks!
Based on that I have added these key bindings to emacs with a note
that they will be available in xterm-214 or later:
\e[27;5;9~  control-TAB
\e[27;5;44~ control-,
\e[27;5;46~ control-.
\e[27;5;47~ control-/
\e[27;5;92~ control-\

(I'll add more such key bindings as soon as I find them potentially useful).

      --dan

As promised, I added the feature in patch #214. Nicolaescu added support in Emacs in xterm.el in stages beginning in May 2006.

Seeing that there would be different user preferences for this area, I added resource-settings (and when appropriate) new control sequences for enabling the corresponding function-key feature. In summary:

An alternative

In March 2008, I received mail from Paul Evans, regarding the modifyOtherKeys feature. He asked about the reason for choosing the 27 encoding. Also, he asked for more information:

> I'm also interested to know the selection criteria on how XTerm decides
> to use this representation or not - when modifyOtherKeys=2, it seems to
> pick it for just about everything - Shift-Q, for example, leaving plain
> "q" to represent unshifted, yet "1" and "!" each encode natively - this
> mode seems a little overkill. Alternatively, in modifyOtherKeys=1, it
> doesn't seem to go far enough - Ctrl-R and Ctrl-Shift-R both using the
> same bytesequence to represent them, seeming to defeat the point of using
> such a mode.

It was a tradeoff (with some feedback from two different people at extremes).
Some of the modified-key combinations are generally predefined (and hard to
work around).  For the predefined combinations, xterm doesn't actually
see the key+modifier - it only gets whatever the keyboard configuration
has first mapped it to.  That seems to be the issue with "1" vs "!".

Also, Because xterm's using the *LookupString() functions to resolve events,
it doesn't see quite as much as xev does.

In response to my explanation of the 27, Evans responded

I've been thinking over [the above], and come to the conclusion it isn't
very neat.

What would you think instead to using one of the other Private Use CSIs
here, say, "u"

Ctrl-A, for example, could become

  CSI 65 ; 5 u

The "u" is 0x75, so Private Use. It's almost self-documenting - the "u"
hints at being "Unicode". And it fits in with the use of ~ much nicer...
CSI 65 ; 5 ~ is the 65th function key with the 5 modifier bits. This
would also strengthen one of my standard arguments I make at everyone on
why they should implement a Proper CSI Parser.

Evans was unfamiliar with the nuances of the X11 library (and how its keycodes and keysyms are related), and did not pick up on the mention of *LookupString() or xev.

He also ignored the fact that it was used in Emacs, stating

I think it's fairly safe to say that nobody really uses the CSI 27
feature of XTerm thus far - it's taken enough beating with sticks for
people to even get as far as noticing the modifiers. If we catch this
arbitrary unicode sequence now, and do it right, we should be able to
fix it easily.

However, to give him something to experiment with, I added the formatOtherKeys resource in patch #235 (2008/04/20).

Two years passed, and Evans came back:

Date: Mon, 16 Aug 2010 19:06:06 +0100
From: Paul LeoNerd Evans <leonerd@leonerd.org.uk>
To: dickey@invisible-island.net
Subject: Xterm and modified keys

On the subject of xterm and modified keypresses, you may recall we were
discussing this quite a while ago.

Well, since then I've now got a nice client-side library for programs to
use to parse VT-style keypresses, plus XTerm's extensions for modified
cursor/function keys, and the CSI u style we came up with. See

  http://www.leonerd.org.uk/code/libtermkey/

I've also had a stab at actually documenting the terminal interface
here:

  http://www.leonerd.org.uk/hacks/fixterms/

How is xterm support looking in this direction? I was hoping at some
point it might be possible to enable a mode where it would properly send
keypresses in this neat scheme all the time; e.g. that Ctrl-D would
continue to work as it does now, but then Ctrl-Shift-D sends its proper
sequence; namely,  CSI 68;5 u

Actually, the “fixterms” documentation is far shorter than this page, and does not go into much detail. It mentions a few specific control characters (tab, return, escape), but states that other control characters use the CSI-u encoding. The page also conflates the modified cursor- and function-keys with the “other” keys (in the section “Really special keypresses”).

If Evans had constructed a table to illustrate the difference between xterm and his objective (as well as participating in development), he might have gotten somewhere.

Later he continued:

Date: Wed, 23 Feb 2011 16:29:10 +0000
From: Paul LeoNerd Evans <leonerd@leonerd.org.uk>
To: Thomas Dickey <dickey@his.com>
Subject: XTerm, modifyOtherKeys, modified unicode, and libtermkey

How is the current state-of-play regarding xterm and modified unicode
keypresses? I was hoping by now there'd be a mode I could set my xterm
into, such that the following happened:

  Ctrl-D                 \x04
  Ctrl-Shift-D           CSI 68;5 u

  Tab                    \x09
  Ctrl-I                 CSI 105;5 u
  Ctrl-Shift-I           CSI 73;5 u

This would help strengthen my proposal to get libtermkey more supported
by applications, such as my ever-present case-in-point being vim;
currently under debate in this thread:

  https://groups.google.com/group/vim_dev/browse_thread/thread/d9ba7d51d7d9eb73?pli=1

Specifically see Benjamin R Haskell's message of Feb 23rd, and my
response to it.

Still more time passed:

Date: Wed, 19 Nov 2014 18:46:59 +0000
From: "Paul \"LeoNerd\" Evans" <leonerd@leonerd.org.uk>
To: dickey@his.com
Subject: Re: A mode switch number for enabling CSI u keypress encodings

On Sun, 12 Oct 2014 19:29:27 -0400
Thomas Dickey <dickey@his.com> wrote:

> I haven't revisited this (in xterm, fonts and the ReGIS stuff have
> been most of the recent work).
> ...in a quick check, it seems quite a while since we discussed this.
> I have some to-do item from 2008 updated in 2009.

Yeah ;) Well.. that all still needs fixing. Last time I checked the
behaviour was still far from ideal.

Do you need a more comprehensive check list / comparison chart, or
somesuch? Or are you aware what needs to happen and just have to get
around to actually doing it..?

Between those last two messages, Evans had done some development. While he had begun libvterm late in 2007, it was not until late 2011 that he began making changes to support the CSI-u format:

Thus, Evans provided the third implementation of CSI-u late in 2011 (after xterm in mid-2008, mintty in mid-2009). According to Evans' comment in freebsd-arch (March 2014), he completed pangoterm around that time (see source-tree for October 4, 2011).

There is no documentation for pangoterm aside from its source-code. Likewise, documentation for libvterm is scanty, consisting of a list of output control sequences which it supports, noting those which were from VT100, VT220 or VT320 (some inaccuracies noted). The list does not mention which were from xterm or ECMA-48 (about 10% is from xterm versus the other categories). But it does not mention input sequences. For that, one must read the source-code or test it, e.g., with tack. As one might guess from the commit-comments, there are some quirks.

For example (testing 0~bzr607-1) typing control-alt-a and control-1 both produced escape-1. Other sequences using alt produced a CSI-u escape sequence (usually).

How It Works

Very briefly:

All of the relevant processing is done in xterm's input.c, and the resources which control this are documented in the manual page. But the interaction between these resources and which special cases apply to a given key can be hard for users to follow, without testing.

Developers can have a hard time with this as well. One could use xev, to see what events the X server may send xterm. Most of xev's output is not useful. But xterm has a debugging trace which shows the useful information. For this example:

the debugging trace contains this information:

Input(0,0) keysym 0xFFE3, 0:'' 7bit
Input(0,0) keysym 0xFFBE, 0:'' Control 7bit FKey
Input(0,7) keysym 0xFFE2, 0:'' 7bit
Input(0,7) keysym 0x0048, 1:'H' Shift 7bit
Input(0,8) keysym 0x0065, 1:'e' 7bit
Input(0,9) keysym 0x006C, 1:'l' 7bit
Input(0,10) keysym 0x0070, 1:'p' 7bit
Input(0,11) keysym 0xFFE2, 0:'' 7bit
Input(0,11) keysym 0x0021, 1:'!' Shift 7bit
Input(0,12) keysym 0xFF0D, 1:'\r' 7bit
Input(2,0) keysym 0xFFE3, 0:'' 7bit
Input(2,0) keysym 0x0065, 1:'e' 7bit
Input(2,1) keysym 0x0078, 1:'x' 7bit
Input(2,2) keysym 0x0069, 1:'i' 7bit
Input(2,3) keysym 0x0074, 1:'t' 7bit
Input(2,4) keysym 0xFF0D, 1:'\r' 7bit
Input(4,0) keysym 0xFFE3, 0:'' 7bit
Input(4,0) keysym 0x0064, 1:'\004' Control 7bit

Some of the lines have nothing in the quotes, e.g., the lines with keysyms 0xFFE3, and 0xFFE2. Those events are for modifiers. The X library takes those into account when it delivers the function key F1 (0xFFBE) and the 'H' (shifted 'h').

The case-conversion (“h” to “H”) is handled by the keyboard configuration. This aspect of the X library is documented in The X Keyboard Extension: Library Specification. The fact that uppercase and lowercase letters happen to be on the same key is incidental to the overall scheme of groups and modifiers.

Examples

In October 2019, Bram Moolenaar asked for more information about how xterm prefixes keys. That led into a discussion of modifyOtherKeys, noting that the manual page description is rather short. I suggested that the best way to document this would be to construct a table, to make it simpler to see the pattern (and special cases). The resulting script (modify-keys.pl) does this:

I verified the script (for my keyboard, at least) using a curses application xterm_keys which I wrote in 2006 to help with my other-key and function-key development. That sets xterm into the various keyboard modes, and prints the result from typed keys in readable form.

XTerm – demo with modified-keys

This example shows xterm_keys, using xdotool to send all 16 combinations of shift, alt, control, and meta for a given keycode to an xterm whose Allow SendEvents has been enabled.

That is an animated Gif, showing the various menus. The data window briefly shows the difference between sending 0x000d and 0xff0d (XK_return). The latter can have a shift modifier associated with the event.

Not all keyboard configurations contain all modifiers. My MacPorts configuration does:

xmodmap:  up to 2 keys per modifier, (keycodes in parentheses):

shift       Shift_L (0x40),  Shift_R (0x44)
lock        Caps_Lock (0x41)
control     Control_L (0x43),  Control_R (0x46)
mod1        Alt_L (0x42),  Alt_R (0x45)
mod2        Meta_L (0x3f),  Meta_R (0x47)
mod3      
mod4      
mod5      

but others do not, e.g., Debian/testing:

xmodmap:  up to 4 keys per modifier, (keycodes in parentheses):

shift       Shift_L (0x32),  Shift_R (0x3e)
lock        Caps_Lock (0x42)
control     Control_L (0x25),  Control_R (0x69)
mod1        Alt_L (0x40),  Alt_R (0x6c),  Meta_L (0xcd)
mod2        Num_Lock (0x4d)
mod3      
mod4        Super_L (0x85),  Super_R (0x86),  Super_L (0xce),  Hyper_L (0xcf)
mod5        ISO_Level3_Shift (0x5c),  Mode_switch (0xcb)

The modify-keys.pl script does not take that into account; it is always possible to send keypress events directly to xterm without limiting those to the keys listed in the XKB configuration. On the other hand, although xdotool can send keypress events to pangoterm (a GDK application), GDK does not process those correctly. Typing directly into pangoterm, I find also that it does not recognize either the alt or meta key. Omitting those from the test does not help with the xdotool script; testing has to be done manually. Here is a screenshot showing the part of the test which it can do:

pangoterm – demo with modified-keys

Here are some examples of the output from modify-keys.pl. Because my machine (and Bram's) used keyboard layout “us” and model is “pc105” that has been best-tested, e.g., using the xterm_keys program.

Other programs

Because Evans heavily promotes his alternative, this elicits some response. To date (late 2019) there are a few implementations, and some related discussion of applications which could be modified to work with the feature:

In the neovim issue, there is a comment by Evans:

leonerd commented on Mar 8, 2014

You mention wanting a standard. There is one. I wrote it
http://www.leonerd.org.uk/hacks/fixterms/
This is what libtermkey parses, and also what
libvterm/pangoterm will output.  xterm will /mostly/ output
that, but gets it a bit wrong in places depending on the value
of the formatOtherKeys setting.  It's either too eager or not
eager enough to use CSI u encoding.  But that's a relatively
small bug that should be easy enough for xterm to fix.

Others reading Evans' comments come away with the understanding that Evans is saying that xterm imitates pangoterm, and does a poor job at that. For instance, in Add Escapes for Ctrl-Tab Shift-Ctrl-Tab (vte #94), Martin Hostettler wrote

\e[27;<mod>;<char>~ is "modify other" aka xterm's interpretation of leonerd's fixterm.
and later (after some discussion) altered his comment to say
\e[27;<mod>;<char>~ is "modify other" aka xterm's interpretation of leonerd's fixterm.

edit: Actually it seems \e[27;<mod>;<char>~ predates fixterm (which proposes CSI u not 27) and is an xterm extension.

With more insight, Hostettler might have pointed out that xterm's CSI-u implementation predates fixterm by a few years.