Zutty key mapping sequences

This is a summary of the character sequences Zutty emits in response to various special keys, and how this mapping depends on the state of the terminal.

Mode settings affecting the emitted sequences

Mode Description Setting
DECANM VT52 Mode CSI ? 2 l
DECANM VT100 mode CSI ? 2 h
DECCKM/N Cursor Key Mode: Normal/Cursor CSI ? 1 l
DECAKM/A Cursor Key Mode: Application CSI ? 1 h
DECKPNM Normal/Numeric Keypad Mode ESC >
DECKPAM Alternate/Application Keypad Mode ESC =

Effect of modifier keys

In case of modifiers being held while a key is pressed, a derived sequence is sent that includes a Modifier Code as an additional (last) parameter of the original sequence. If the original sequence did not start with CSI, the start is changed to CSI (with the exception of keypad keys). If there were no original parameters in the sequence, a first default parameter of 1 is added before appending the Modifier Code.

Modifier codes:

Modifier(s) Code
Shift 2
Alt 3
Alt + Shift 4
Control 5
Control + Shift 6
Control + Alt 7
Control + Alt + Shift 8

To make it clearer, in each section we will include some examples of what sequences will result when some modifiers are applied.

Modifiers are generally not applicable to VT52 mode, but are uniform across ANSI and keypad modes.

Sequences that are the same regardless of state

Key Sequence
Insert, KP_Insert CSI 2 ~
Delete, KP_Delete CSI 3 ~
Prior (PageUp), KP_Prior CSI 5 ~
Next (PageDown), KP_Next CSI 6 ~

Modifier examples:

  • Shift + Insert: CSI 2 ; 2 ~
  • Control + PageUp: CSI 5 ; 5 ~

Modifiers work even in VT52 mode.

Function keys

These are independent of cursor key and numeric keypad modes.

Key VT100 VT52
F1, KP_F1 SS3 P ESC P
F2, KP_F2 SS3 Q ESC Q
F3, KP_F3 SS3 R ESC R
F4, KP_F4 SS3 S ESC S
F5 CSI 1 5 ~ CSI 1 5 ~
F6 CSI 1 7 ~ CSI 1 7 ~
F7 CSI 1 8 ~
F8 CSI 1 9 ~  
F9 CSI 2 0 ~  
F10 CSI 2 1 ~  
F11 CSI 2 3 ~  
F12 CSI 2 4 ~  
F13 CSI 2 5 ~  
F14 CSI 2 6 ~  
F15 CSI 2 8 ~  
F16 CSI 2 9 ~  
F17 CSI 3 1 ~  
F18 CSI 3 2 ~  
F19 CSI 3 3 ~  
F20 CSI 3 4 ~  

Modifier examples:

  • Shift + F1: CSI 1 ; 2 P
  • Alt + F4: CSI 1 ; 3 S
  • Shift + F5: CSI 1 5 ; 2 ~
  • Control + Shift + F10: CSI 2 1 ; 6 ~

Modifiers are not applied in VT52 mode.

Sequences dependent on cursor key mode setting

Key VT100 Normal VT100 App VT52
Up CSI A SS3 A ESC A
Down CSI B SS3 B ESC B
Right CSI C SS3 C ESC C
Left CSI D SS3 D ESC D
Home CSI H SS3 H ESC H
End CSI F SS3 F ESC F

Examples (apply both in Normal and App mode):

  • Alt + Left: CSI 1 ; 3 D
  • Control + Home: CSI 1 ; 5 H

Modifiers are not applied in VT52 mode.

Note that arrow keys on the numeric keypad (KP_Up, etc.) are handled as completely different keys; their encoding method is described in the next section.

Sequences dependent on keypad mode setting

This only affects the keypad. The corresponding non-keypad keys always send the literals in the Normal column. Normal (aka. numeric) mode is shared between VT100 and VT52.

Some keys are received from X with different keysyms based on the NumLock state; for these keys, the second column shows the keysym with NumLock off. In VT100 App mode with NumLock on, all keys generate their literals (as in normal mode), but see further below regarding the Shift key. With NumLock off, mappings are generated as per the below table, depending on the terminal mode setting.

NumLock on NumLock off Normal VT100 App VT52 App
KP_Space   SP SS3 SP ESC ? SP
KP_Tab   TAB SS3 I ESC ? I
KP_Enter   CR SS3 M ESC ? M
KP_Multiply   * SS3 j ESC ? j
KP_Add   + SS3 k ESC ? k
KP_Separator   , SS3 l ESC ? l
KP_Subtract   - SS3 m ESC ? m
KP_Decimal KP_Delete . SS3 n ESC ? n
KP_Divide   / SS3 o ESC ? o
KP_0 KP_Insert 0 SS3 p ESC ? p
KP_1 KP_End 1 SS3 q ESC ? q
KP_2 KP_Down 2 SS3 r ESC ? r
KP_3 KP_Page_Down 3 SS3 s ESC ? s
KP_4 KP_Left 4 SS3 t ESC ? t
KP_5 KP_Begin 5 SS3 u ESC ? u
KP_6 KP_Right 6 SS3 v ESC ? v
KP_7 KP_Home 7 SS3 w ESC ? w
KP_8 KP_Up 8 SS3 x ESC ? x
KP_9 KP_Page_Up 9 SS3 y ESC ? y
KP_Equal   = SS3 X ESC ? X

Modifier keys do not cause the SS3 to change to CSI. This is how xterm behaves, and Zutty emulates that behaviour.

Examples:

  • Alt + KP_Minus: SS3 3 m
  • Control + KP_Enter: SS3 5 M
  • Control + KP_Plus: SS3 5 k
  • Control + Shift + KP_Left: SS3 6 t

Modifiers are not applied in VT52 mode.

There is some additional subtlety related to use of the Shift key. Pressing Shift has a momentary effect of inverting the NumLock state. This is not specific to Zutty; it works on the X level and is easily seen via e.g., xev. For example, with NumLock off, hitting "4" on the numeric keypad will generate KP_Left, while hitting the same key with Shift held down will generate KP_4. With NumLock on, results will be reversed: an unmodified keypress will generate KP_4, while a Shift-press will generate KP_Left.

Why is this interesting? Let's go through the encodings of these keys. In normal (numeric) mode, Zutty generates the literals shown in the Normal column regardless of the NumLock state, and without any modifier encoding. That is, hitting "4" on the keypad will yield a "4" with or without NumLock, and all modifiers will be discarded.

In application (aka. ANSI, aka. alternate) keypad mode, however, all the details come into play. Hitting keypad "4" will generate "4" only if NumLock is on; with NumLock off, it will be encoded as the escape sequence SS3 t. Further, holding Shift while hitting the same key will have slightly asymmetrical results depending on NumLock state:

  • With NumLock off, Zutty will consider the keypress as a modifier combination of Shift plus KP_Left, and encode it as SS3 2 t. In the same manner, Control plus KP_Left will be encoded as SS3 5 t, and so on for other (possibly compounded) modifiers and keys.
  • With NumLock on, the baseline is to generate literals only, just as in numeric mode. Modifiers will be ignored, so Control + KP_4 (the keysym Zutty sees due to NumLock being on) will still generate a "4" only. However, if Shift is among the active modifiers, it will turn KP_4 back into KP_Left, and the result will be, again, encoded as SS3 2 t (or the corresponding modifier code).

The intention is that Zutty behaves just like xterm with VT220-style function keys. In case of manual side-by-side comparisons, please remember to put xterm into "VT220 Keyboard" mode (by choosing it in the Control + left-click menu, setting the XTerm.keyboardType X resource to vt220, or passing -kt vt220 on the command line).

Special key combinations

The resource settings altSendsEscape and modifyOtherKeys (modeled after xterm) control how other key combinations (not specified in the above tables) are encoded.

The encoding rules are, by and large, meant to be the same as that of xterm; please refer to its extensive documentation for details. As a complement, below we present several example key encodings for different values of modifyOtherKeys (columns 0, 1 and 2), with an altSendsEscape setting of true (the default).

Key 0 1 2
Shift-a A A CSI 27 ; 2 ; 65 ~
Shift-Space Space Space CSI 27 ; 2 ; 32 ~
Shift-TAB CSI Z CSI Z CSI 27 ; 2 ; 9 ~
Shift-Return Return CSI 27 ; 2 ; 13 ~ CSI 27 ; 2 ; 13 ~
Control-Space ^@ ^@ CSI 27 ; 5 ; 32 ~
Control-Alt-Space ESC ^@ ESC ^@ CSI 27 ; 7 ; 32 ~
Control-Shift-Space ^@ ^@ CSI 27 ; 6 ; 32 ~
Control-Alt-Shift-Space ESC ^@ ESC ^@ CSI 27 ; 8 ; 32 ~
Control-TAB TAB CSI 27 ; 5 ; 9 ~ CSI 27 ; 5 ; 9 ~
Control-Return Return CSI 27 ; 5 ; 13 ~ CSI 27 ; 5 ; 13 ~
Control-Alt-Return ESC Return CSI 27 ; 7 ; 13 ~ CSI 27 ; 7 ; 13 ~
Control-Alt-Shift-Return ESC Return CSI 27 ; 8 ; 13 ~ CSI 27 ; 8 ; 13 ~
Control-/ ^_ ^_ CSI 27 ; 5 ; 47 ~
Control-0 0 CSI 27 ; 5 ; 48 ~ CSI 27 ; 5 ; 48 ~
Control-1 1 CSI 27 ; 5 ; 49 ~ CSI 27 ; 5 ; 49 ~
Control-2 ^@ ^@ CSI 27 ; 5 ; 50 ~
Control-3 ESC ESC CSI 27 ; 5 ; 51 ~
Control-4 ^\ ^\ CSI 27 ; 5 ; 52 ~
Control-5 ^] ^] CSI 27 ; 5 ; 53 ~
Control-6 ^^ ^^ CSI 27 ; 5 ; 54 ~
Control-7 ^_ ^_ CSI 27 ; 5 ; 55 ~
Control-8 DEL DEL CSI 27 ; 5 ; 56 ~
Control-9 9 CSI 27 ; 5 ; 57 ~ CSI 27 ; 5 ; 57 ~
Control-! (Control-Shift-1) ! CSI 27 ; 6 ; 33 ~ CSI 27 ; 6 ; 33 ~
Control-@ (Control-Shift-2) ^@ ^@ CSI 27 ; 6 ; 64 ~
Control-# (Control-Shift-3) # CSI 27 ; 6 ; 35 ~ CSI 27 ; 6 ; 35 ~
Control-$ (Control-Shift-4) $ CSI 27 ; 6 ; 36 ~ CSI 27 ; 6 ; 36 ~
Control-% (Control-Shift-5) % CSI 27 ; 6 ; 37 ~ CSI 27 ; 6 ; 37 ~
Control-^ (Control-Shift-6) ^^ ^^ CSI 27 ; 6 ; 94 ~
Control-& (Control-Shift-7) & CSI 27 ; 6 ; 38 ~ CSI 27 ; 6 ; 38 ~
Control-* (Control-Shift-8) * CSI 27 ; 6 ; 42 ~ CSI 27 ; 6 ; 42 ~
Control-( (Control-Shift-9) ( CSI 27 ; 6 ; 40 ~ CSI 27 ; 6 ; 40 ~
Control-) (Control-Shift-0) ) CSI 27 ; 6 ; 41 ~ CSI 27 ; 6 ; 41 ~
Control-[ ^[ ^[ CSI 27 ; 5 ; 91 ~
Control-] ^] ^] CSI 27 ; 5 ; 93 ~
Control-{ (Control-Shift-[) ^[ ^[ CSI 27 ; 6 ; 123 ~
Control-} (Control-Shift-]) ^] ^] CSI 27 ; 6 ; 125 ~
Control-c ^C ^C CSI 27 ; 5 ; 99 ~
Control-d ^D ^D CSI 27 ; 5 ; 100 ~
Control-i TAB TAB CSI 27 ; 5 ; 105 ~
Control-Shift-I TAB TAB CSI 27 ; 6 ; 73 ~
Control-x ^X ^X CSI 27 ; 5 ; 120 ~
Control-Alt-x ESC ^X ESC ^X CSI 27 ; 7 ; 120 ~
Control-Shift-D ^D ^D CSI 27 ; 6 ; 68 ~
Control-Alt-Shift-D ESC ESC ESC ESC CSI 27 ; 8 ; 68 ~
Control-; ; CSI 27 ; 5 ; 59 ~ CSI 27 ; 5 ; 59 ~
Control-: (Control-Shift-;) : CSI 27 ; 6 ; 58 ~ CSI 27 ; 6 ; 58 ~
Control-\ ^\ ^\ CSI 27 ; 5 ; 92 ~
Control-¦ (Control-Shift-\) ^\ ^\ CSI 27 ; 6 ; 124 ~
Control-` ^@ ^@ CSI 27 ; 5 ; 96 ~
Control-~ (Control-Shift-`) ^^ ^^ CSI 27 ; 6 ; 126 ~
Alt-Space ESC Space ESC Space CSI 27 ; 3 ; 32 ~
Alt-Shift-Space ESC Space ESC Space CSI 27 ; 4 ; 32 ~
Alt-TAB ESC TAB ESC TAB CSI 27 ; 3 ; 9 ~
Alt-Return ESC Return CSI 27 ; 3 ; 13 ~ CSI 27 ; 3 ; 13 ~
Alt-Shift-Return ESC Return CSI 27 ; 4 ; 13 ~ CSI 27 ; 4 ; 13 ~
Alt-d ESC d ESC d CSI 27 ; 3 ; 100 ~
Alt-Shift-d ESC D ESC D CSI 27 ; 4 ; 68 ~
Alt-x ESC x ESC x CSI 27 ; 3 ; 120 ~
Alt-Shift-X ESC X ESC X CSI 27 ; 4 ; 88 ~