#+TITLE: Zutty key mapping sequences
#+OPTIONS: author:nil timestamp:nil toc:nil num:nil val:nil html-style:nil H:3 ^:{}
#+HTML_HEAD: <link rel="stylesheet" type="text/css" href="org.css"/>

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 [[https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-VT220-Style-Function-Keys][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 ~  |
