fix(cli): map NumLock/CapsLock modifier-bit variants under kitty protocol
With the kitty keyboard protocol push active (CSI >1u disambiguate), kitty
encodes lock-key state into the CSI modifier field of function keys: a
plain Down with NumLock on arrives as ESC[1;129B (NumLock), ESC[1;65B
(CapsLock), or ESC[1;193B (both) instead of the legacy ESC[B. Stock
prompt_toolkit maps none of these, so the parser fires Escape and
inserts the remainder as literal text in the input line.
03bf85d83 restored the kitty push and completed the extended-key alias
table but left these lock-bit variants unmapped, so kitty + NumLock
still leaks [1;129A/B for arrow/nav keys.
Map modifier 129/65/193 (plain) and 130/66/194 (+shift) for arrows,
Home/End, Insert/Delete/PageUp/PageDown, and CSI-u Enter/Tab/Backspace/
Space to their plain keys.
This commit is contained in:
@@ -366,6 +366,56 @@ def install_modify_other_keys_aliases() -> int:
|
||||
# matching Ink TUI + Desktop (#78285)
|
||||
})
|
||||
|
||||
# -- Lock-key modifier bits (NumLock=128, CapsLock=64) under the kitty
|
||||
# disambiguate push: kitty encodes lock state into the CSI sequence, so
|
||||
# a plain Down with NumLock on arrives as ESC[1;129B (NumLock), ESC[1;65B
|
||||
# (CapsLock) or ESC[1;193B (both) instead of the legacy ESC[B that stock
|
||||
# prompt_toolkit maps. Those fall through the parser and leak as literal
|
||||
# text ("[1;129B") in the input line. Map them to the plain key; the
|
||||
# +shift variants (130/66/194) to the Shift* keys.
|
||||
lock_plain = (129, 65, 193)
|
||||
lock_shift = (130, 66, 194)
|
||||
for mod in lock_plain:
|
||||
for trailer, key in (
|
||||
("A", Keys.Up), ("B", Keys.Down), ("C", Keys.Right), ("D", Keys.Left),
|
||||
("H", Keys.Home), ("F", Keys.End),
|
||||
):
|
||||
seq = f"\x1b[1;{mod}{trailer}"
|
||||
if seq not in ANSI_SEQUENCES:
|
||||
ANSI_SEQUENCES[seq] = key
|
||||
changed += 1
|
||||
for num, key in (
|
||||
(2, Keys.Insert), (3, Keys.Delete), (5, Keys.PageUp), (6, Keys.PageDown),
|
||||
):
|
||||
seq = f"\x1b[{num};{mod}~"
|
||||
if seq not in ANSI_SEQUENCES:
|
||||
ANSI_SEQUENCES[seq] = key
|
||||
changed += 1
|
||||
for cp, key in (
|
||||
(13, Keys.ControlM), # Enter
|
||||
(9, Keys.Tab), # Tab
|
||||
(127, Keys.Backspace), # Backspace
|
||||
(32, " "), # Space
|
||||
):
|
||||
seq = f"\x1b[{cp};{mod}u"
|
||||
if seq not in ANSI_SEQUENCES:
|
||||
ANSI_SEQUENCES[seq] = key
|
||||
changed += 1
|
||||
for mod in lock_shift:
|
||||
for trailer, key in (
|
||||
("A", Keys.ShiftUp), ("B", Keys.ShiftDown), ("C", Keys.ShiftRight),
|
||||
("D", Keys.ShiftLeft), ("H", Keys.ShiftHome), ("F", Keys.ShiftEnd),
|
||||
):
|
||||
seq = f"\x1b[1;{mod}{trailer}"
|
||||
if seq not in ANSI_SEQUENCES:
|
||||
ANSI_SEQUENCES[seq] = key
|
||||
changed += 1
|
||||
for num, key in ((2, Keys.ShiftInsert), (3, Keys.ShiftDelete)):
|
||||
seq = f"\x1b[{num};{mod}~"
|
||||
if seq not in ANSI_SEQUENCES:
|
||||
ANSI_SEQUENCES[seq] = key
|
||||
changed += 1
|
||||
|
||||
# -- Kitty functional keys (Private Use Area codepoints) ----
|
||||
# kitty emits these CSI-u encodings even in LEGACY mode for keys that
|
||||
# have no legacy encoding, so unmapped they leak as literal text in any
|
||||
|
||||
Reference in New Issue
Block a user