Skip to content

Commit 63a2e36

Browse files
committed
patch 9.0.0930: cannot debug the Kitty keyboard protocol with TermDebug
Problem: Cannot debug the Kitty keyboard protocol with TermDebug. Solution: Add Kitty keyboard protocol support to the libvterm fork. Recognize the escape sequences that the protocol generates. Add the 'keyprotocol' option to allow the user to specify for which terminal what protocol is to be used, instead of hard-coding this. Add recognizing the kitty keyboard protocol status.
1 parent 0b6d6a1 commit 63a2e36

22 files changed

Lines changed: 381 additions & 43 deletions

runtime/doc/map.txt

Lines changed: 41 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,19 @@ This subject is introduced in sections |05.4|, |24.7| and |40.1| of the user
1010
manual.
1111

1212
1. Key mapping |key-mapping|
13-
1.1 MAP COMMANDS |:map-commands|
14-
1.2 Special arguments |:map-arguments|
15-
1.3 Mapping and modes |:map-modes|
16-
1.4 Listing mappings |map-listing|
17-
1.5 Mapping special keys |:map-special-keys|
18-
1.6 Special characters |:map-special-chars|
19-
1.7 What keys to map |map-which-keys|
20-
1.8 Examples |map-examples|
21-
1.9 Using mappings |map-typing|
22-
1.10 Mapping alt-keys |:map-alt-keys|
23-
1.11 Mapping in modifyOtherKeys mode |modifyOtherKeys|
24-
1.12 Mapping an operator |:map-operator|
13+
1.1 MAP COMMANDS |:map-commands|
14+
1.2 Special arguments |:map-arguments|
15+
1.3 Mapping and modes |:map-modes|
16+
1.4 Listing mappings |map-listing|
17+
1.5 Mapping special keys |:map-special-keys|
18+
1.6 Special characters |:map-special-chars|
19+
1.7 What keys to map |map-which-keys|
20+
1.8 Examples |map-examples|
21+
1.9 Using mappings |map-typing|
22+
1.10 Mapping alt-keys |:map-alt-keys|
23+
1.11 Mapping in modifyOtherKeys mode |modifyOtherKeys|
24+
1.12 Mapping with Kitty keyboard protocol |kitty-keyboard-protocol|
25+
1.13 Mapping an operator |:map-operator|
2526
2. Abbreviations |abbreviations|
2627
3. Local mappings and functions |script-local|
2728
4. User-defined commands |user-commands|
@@ -1009,7 +1010,34 @@ When the 'esckeys' option is off, then modifyOtherKeys will be disabled in
10091010
Insert mode to avoid every key with a modifier causing Insert mode to end.
10101011

10111012

1012-
1.12 MAPPING AN OPERATOR *:map-operator*
1013+
1.12 MAPPING WITH KITTY KEYBOARD PROTOCOL *kitty-keyboard-protocol*
1014+
1015+
If the value of 'term' contains "kitty" then Vim will send out an escape
1016+
sequence to enable the Kitty keyboard protocol. This can be changed with the
1017+
'keyprotocol' option.
1018+
1019+
Like modifyOtherKeys, this will make it possible to distinguish between more
1020+
keys with modifiers. Also, this protocol sends an escape sequence for the Esc
1021+
key, so that Vim does not need to use a timeout to know whether receiving an
1022+
Esc character means the Esc key was pressed or it's the start of an escape
1023+
sequence.
1024+
1025+
Vim automatically detects if the Kitty keyboard protocol was enabled when it
1026+
spots the response to the status request (this should be part of the |t_TI|
1027+
termcap entry). To see if Vim detected such an escape sequence use: >
1028+
:verbose map
1029+
The first line will then show "Kitty keyboard protocol: {value}" (possibly
1030+
translated). The meaning of {value}:
1031+
Unknown no status received yet
1032+
Off protocol is not used
1033+
On protocol is used
1034+
Disabled protocol was used but expected to have been disabled
1035+
by 't_TE'
1036+
Cleared protocol expected to have beeen disabled by 't_TE',
1037+
previous state is unknown
1038+
1039+
1040+
1.13 MAPPING AN OPERATOR *:map-operator*
10131041

10141042
An operator is used before a {motion} command. To define your own operator
10151043
you must create a mapping that first sets the 'operatorfunc' option and then

runtime/doc/options.txt

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4888,6 +4888,50 @@ A jump table for the options with a short description can be found at |Q_op|.
48884888
<PageUp> and <PageDown>.
48894889
The 'keymodel' option is set by the |:behave| command.
48904890

4891+
*'keyprotocol'* *'kpc'*
4892+
'keyprotocol' 'kpc' string (default: see below)
4893+
global
4894+
Specifies what keyboard protocol to use depending on the value of
4895+
'term'. The supported keyboard protocols names are:
4896+
none whatever the terminal uses
4897+
mok2 modifyOtherKeys level 2, as supported by xterm
4898+
kitty Kitty keyboard protocol, as supported by Kitty
4899+
4900+
The option value is a list of command separated items. Each item has
4901+
a pattern that is matched against the 'term' option, a colon and the
4902+
protocol name to be used. To illustrate this, the default value would
4903+
be set with: >
4904+
set keyprotocol=kitty:kitty,foot:kitty,wezterm:kitty,xterm:mok2
4905+
4906+
< This means that when 'term' contains "kitty, "foot" or "wezterm"
4907+
somewhere then the "kitty" protocol is used. When 'term' contains
4908+
"xterm" somewhere, then the "mok2" protocol is used.
4909+
4910+
The first match is used, thus if you want to have "kitty" use the
4911+
kitty protocol, but "badkitty" not, then you should match "badkitty"
4912+
first and use the "none" value: >
4913+
set keyprotocol=badkitty:none,kitty:kitty
4914+
<
4915+
The option is used after 'term' has been changed. First the termcap
4916+
entries are set, possibly using the builtin list, see |builtin-terms|.
4917+
Then this option is inspected and if there is a match and a protocol
4918+
is specified the following happens:
4919+
none Nothing, the regular t_TE and t_TI values remain
4920+
4921+
mok2 The t_TE value is changed to:
4922+
CSI >4;m disables modifyOtherKeys
4923+
The t_TI value is changed to:
4924+
CSI >4;2m enables modifyOtherKeys
4925+
4926+
kitty The t_TE value is changed to:
4927+
CSI >4;m disables modifyOtherKeys
4928+
CSI <u disables the kitty keyboard protocol
4929+
The t_TI value is changed to:
4930+
CSI >1u enables the kitty keyboard protocol
4931+
CSI ?u request kitty keyboard protocol state
4932+
CSI >c request the termresponse
4933+
4934+
48914935
*'keywordprg'* *'kp'*
48924936
'keywordprg' 'kp' string (default "man" or "man -s", DOS: ":help",
48934937
VMS: "help")

runtime/doc/quickref.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -775,6 +775,7 @@ Short explanation of each option: *option-list*
775775
'key' encryption key
776776
'keymap' 'kmp' name of a keyboard mapping
777777
'keymodel' 'km' enable starting/stopping selection with keys
778+
'keyprotocol' 'kpc' what keyboard protocol to use for what terminal
778779
'keywordprg' 'kp' program to use for the "K" command
779780
'langmap' 'lmap' alphabetic characters for other language mode
780781
'langmenu' 'lm' language to be used for the menus

src/edit.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -330,7 +330,7 @@ edit(
330330

331331
// Disable modifyOtherKeys, keys with modifiers would cause exiting
332332
// Insert mode.
333-
out_str(T_CTE);
333+
out_str_t_TE();
334334
}
335335

336336
/*

src/globals.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1377,6 +1377,24 @@ EXTERN int pending_end_reg_executing INIT(= 0);
13771377
// no longer be used.
13781378
EXTERN int seenModifyOtherKeys INIT(= FALSE);
13791379

1380+
// The state for the Kitty keyboard protocol.
1381+
typedef enum {
1382+
// Initially we have no clue if the protocol is on or off.
1383+
KKPS_INITIAL,
1384+
// Used when receiving the state and the flags are zero.
1385+
KKPS_OFF,
1386+
// Used when receiving the state and the flags are non-zero.
1387+
KKPS_ENABLED,
1388+
// Used after outputting t_KE when the state was KKPS_ENABLED. We do not
1389+
// really know if t_KE actually disabled the protocol, the following t_KI
1390+
// is expected to request the state, but the response may come only later.
1391+
KKPS_DISABLED,
1392+
// Used after outputting t_KE when the state was not KKPS_ENABLED.
1393+
KKPS_AFTER_T_KE,
1394+
} kkpstate_T;
1395+
1396+
EXTERN kkpstate_T kitty_protocol_state INIT(= KKPS_INITIAL);
1397+
13801398
EXTERN int no_mapping INIT(= FALSE); // currently no mapping allowed
13811399
EXTERN int no_zero_mapping INIT(= 0); // mapping zero not allowed
13821400
EXTERN int allow_keys INIT(= FALSE); // allow key codes when no_mapping

src/libvterm/include/vterm.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,7 @@ size_t vterm_output_get_buffer_remaining(const VTerm *vt);
368368
size_t vterm_output_read(VTerm *vt, char *buffer, size_t len);
369369

370370
int vterm_is_modify_other_keys(VTerm *vt);
371+
int vterm_is_kitty_keyboard(VTerm *vt);
371372
void vterm_keyboard_unichar(VTerm *vt, uint32_t c, VTermModifier mod);
372373
void vterm_keyboard_key(VTerm *vt, VTermKey key, VTermModifier mod);
373374

src/libvterm/src/keyboard.c

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,12 @@ int vterm_is_modify_other_keys(VTerm *vt)
1010
return vt->state->mode.modify_other_keys;
1111
}
1212

13+
// VIM: added
14+
int vterm_is_kitty_keyboard(VTerm *vt)
15+
{
16+
return vt->state->mode.kitty_keyboard;
17+
}
18+
1319

1420
void vterm_keyboard_unichar(VTerm *vt, uint32_t c, VTermModifier mod)
1521
{
@@ -19,6 +25,12 @@ void vterm_keyboard_unichar(VTerm *vt, uint32_t c, VTermModifier mod)
1925
return;
2026
}
2127

28+
// VIM: added kitty keyboard protocol support
29+
if (vterm_is_kitty_keyboard(vt) && mod != 0) {
30+
vterm_push_output_sprintf_ctrl(vt, C1_CSI, "%d;%du", c, mod+1);
31+
return;
32+
}
33+
2234
/* The shift modifier is never important for Unicode characters
2335
* apart from Space
2436
*/
@@ -166,8 +178,10 @@ void vterm_keyboard_key(VTerm *vt, VTermKey key, VTermModifier mod)
166178
break;
167179

168180
case KEYCODE_TAB:
181+
if (vterm_is_kitty_keyboard(vt) && mod != 0)
182+
vterm_push_output_sprintf_ctrl(vt, C1_CSI, "9;%du", mod+1);
169183
/* Shift-Tab is CSI Z but plain Tab is 0x09 */
170-
if(mod == VTERM_MOD_SHIFT)
184+
else if(mod == VTERM_MOD_SHIFT)
171185
vterm_push_output_sprintf_ctrl(vt, C1_CSI, "Z");
172186
else if(mod & VTERM_MOD_SHIFT)
173187
vterm_push_output_sprintf_ctrl(vt, C1_CSI, "1;%dZ", mod+1);
@@ -186,7 +200,10 @@ void vterm_keyboard_key(VTerm *vt, VTermKey key, VTermModifier mod)
186200
case KEYCODE_LITERAL: case_LITERAL:
187201
if (vterm_is_modify_other_keys(vt) && mod != 0)
188202
vterm_push_output_sprintf_ctrl(vt, C1_CSI, "27;%d;%d~", mod+1, k.literal);
189-
else if(mod & (VTERM_MOD_SHIFT|VTERM_MOD_CTRL))
203+
else if (vterm_is_kitty_keyboard(vt) && mod == 0 && k.literal == '\x1b')
204+
vterm_push_output_sprintf_ctrl(vt, C1_CSI, "%du", k.literal);
205+
else if ((vterm_is_kitty_keyboard(vt) && mod != 0)
206+
|| (mod & (VTERM_MOD_SHIFT|VTERM_MOD_CTRL)))
190207
vterm_push_output_sprintf_ctrl(vt, C1_CSI, "%d;%du", k.literal, mod+1);
191208
else
192209
vterm_push_output_sprintf(vt, mod & VTERM_MOD_ALT ? ESC_S "%c" : "%c", k.literal);

src/libvterm/src/state.c

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1423,9 +1423,37 @@ static int on_csi(const char *leader, const long args[], int argcount, const cha
14231423
}
14241424
break;
14251425

1426-
case LEADER('>', 0x6d): // xterm resource modifyOtherKeys
1426+
case LEADER('>', 0x6d): // CSI > 4 ; Pv m xterm resource modifyOtherKeys
14271427
if (argcount == 2 && args[0] == 4)
1428+
{
1429+
// can't have both modify_other_keys and kitty_keyboard
1430+
state->mode.kitty_keyboard = 0;
1431+
14281432
state->mode.modify_other_keys = args[1] == 2;
1433+
}
1434+
break;
1435+
1436+
case LEADER('>', 0x75): // CSI > 1 u enable kitty keyboard protocol
1437+
if (argcount == 1 && args[0] == 1)
1438+
{
1439+
// can't have both modify_other_keys and kitty_keyboard
1440+
state->mode.modify_other_keys = 0;
1441+
1442+
state->mode.kitty_keyboard = 1;
1443+
}
1444+
break;
1445+
1446+
case LEADER('<', 0x75): // CSI < u disable kitty keyboard protocol
1447+
if (argcount <= 1)
1448+
state->mode.kitty_keyboard = 0;
1449+
break;
1450+
1451+
case LEADER('?', 0x75): // CSI ? u request kitty keyboard protocol state
1452+
if (argcount <= 1)
1453+
// TODO: this only uses the values zero and one. The protocol specifies
1454+
// more values, the progressive enhancement flags.
1455+
vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, "?%du",
1456+
state->mode.kitty_keyboard);
14291457
break;
14301458

14311459
case 0x6e: // DSR - ECMA-48 8.3.35

src/libvterm/src/vterm_internal.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ struct VTermState
130130
unsigned int bracketpaste:1;
131131
unsigned int report_focus:1;
132132
unsigned int modify_other_keys:1;
133+
unsigned int kitty_keyboard:1;
133134
} mode;
134135

135136
VTermEncodingInstance encoding[4], encoding_utf8;

src/map.c

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -312,8 +312,27 @@ list_mappings(
312312
// Prevent mappings to be cleared while at the more prompt.
313313
++map_locked;
314314

315-
if (p_verbose > 0 && keyround == 1 && seenModifyOtherKeys)
316-
msg_puts(_("Seen modifyOtherKeys: true"));
315+
if (p_verbose > 0 && keyround == 1)
316+
{
317+
if (seenModifyOtherKeys)
318+
msg_puts(_("Seen modifyOtherKeys: true"));
319+
if (kitty_protocol_state != KKPS_INITIAL)
320+
{
321+
char *name = _("Unknown");
322+
switch (kitty_protocol_state)
323+
{
324+
case KKPS_INITIAL: break;
325+
case KKPS_OFF: name = _("Off"); break;
326+
case KKPS_ENABLED: name = _("On"); break;
327+
case KKPS_DISABLED: name = _("Disabled"); break;
328+
case KKPS_AFTER_T_KE: name = _("Cleared"); break;
329+
}
330+
331+
char buf[200];
332+
vim_snprintf(buf, sizeof(buf), _("Kitty keyboard protocol: %s"), name);
333+
msg_puts(buf);
334+
}
335+
}
317336

318337
// need to loop over all global hash lists
319338
for (int hash = 0; hash < 256 && !got_int; ++hash)

0 commit comments

Comments
 (0)