Skip to content

Unwind shifted punctuation key codes to base characters under Kitty keyboard protocol - #171

Merged
tomlm merged 2 commits into
mainfrom
copilot/fix-shift-key-code-issue
Oct 13, 2026
Merged

tomlm merged 2 commits into
mainfrom
copilot/fix-shift-key-code-issue

Conversation

Copilot AI commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

Under the Kitty keyboard protocol, key events report the unshifted base character as the primary key code, carrying any shifted character in the alternate-key sub-parameter. KittyKeyboard.GetKeyCode previously unwound KeyEvent.Code only for Digit* and Key* prefixes, causing main-keyboard punctuation positions under Shift to fall through to ev.Key[0] and emit the shifted symbol as the primary key code.

Changes

  • Punctuation key code unwinding (src/XTerm.NET/Input/KittyKeyboard.cs):

    • When ev.ShiftKey is set, map the 11 main-keyboard punctuation Code values (Backquote, Minus, Equal, BracketLeft, BracketRight, Backslash, Semicolon, Quote, Comma, Period, Slash) to their US-positional base characters (\``, -, =, [, ], `, ;, ', ,, ., /).
    • Sequenced after Digit* and Key* handlers to preserve hot-path performance for letter and digit inputs.
  • Regression and end-to-end tests (src/XTerm.NET.Tests/Input/):

    • Added Shifted_punctuation_appears_as_a_sub_parameter covering all 11 punctuation keys with ReportAlternateKeys (AllKeys | Alternates).
    • Added coverage for ReportAllKeysAsEscapeCodes and Ctrl+Shift disambiguated chords.
    • Added Terminal.GenerateKittyKeyInput test asserting mode-aware unwinding through the terminal entry point.
// Shift+= (key: "+", code: "Equal")
// Before: CSI 43;2u    ('+' reported as key code)
// After:  CSI 61;2u    ('=' base key code)

// Ctrl+Shift+= under ReportAlternateKeys
// Before: CSI 43:43;6u (duplicated shifted symbol)
// After:  CSI 61:43;6u (base key 61 with shifted alternate 43)

Co-authored-by: tomlm <17789481+tomlm@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix shift key code handling for punctuation in KittyKeyboard Unwind shifted punctuation key codes to base characters under Kitty keyboard protocol Oct 13, 2026
Copilot AI requested a review from tomlm October 13, 2026 00:42
@tomlm
tomlm marked this pull request as ready for review October 13, 2026 01:28
@github-actions

Copy link
Copy Markdown
Contributor

Perf comparison — this change, against its base

3 run(s) of each side, alternating on one machine. Allocation is a count and is gated exactly. Time is a measurement, so its gate is derived from the spread this job just observed in itself rather than fixed in advance.

corpus bytes/char gen0/Mchar ns/char Δ time noise gate
scroll-ascii 0.00 → 0.00 0.00 → 0.00 3.36 → 3.36 +0.1% ±1% 4%
sgr-churn 0.00 → 0.00 0.00 → 0.00 9.02 → 8.99 -0.3% ±39% 117%
truecolor 0.00 → 0.00 0.00 → 0.00 10.00 → 9.96 -0.4% ±0% 4%
alt-redraw 0.00 → 0.00 0.00 → 0.00 14.40 → 14.36 -0.3% ±1% 4%
unicode 7.66 → 7.66 0.45 → 0.45 35.31 → 36.14 +2.3% ±6% 18%
flood 0.00 → 0.00 0.00 → 0.00 94.58 → 94.44 -0.1% ±1% 4%

Each corpus is gated at max(4%, 3 × its own noise). A wide noise column means this runner was busy and the timing half of the table should be read as advisory; the allocation half is exact either way.

assemblies measured
  • base: XTerm.NET 2.0.5.0 mvid:4e8fedf9-7edf-4be2-a232-82a728abd815
  • head: XTerm.NET 2.0.5.0 mvid:55751f9c-4ba5-449d-8e92-4047946a145e

Perf comparison — cumulative, everything since 2.0.3

3 run(s) of each side, alternating on one machine. Allocation is a count and is gated exactly. Time is a measurement, so its gate is derived from the spread this job just observed in itself rather than fixed in advance.

corpus bytes/char gen0/Mchar ns/char Δ time noise gate
scroll-ascii 0.00 → 0.00 0.00 → 0.00 3.38 → 3.36 -0.4% ±1% 5%
sgr-churn 0.00 → 0.00 0.00 → 0.00 9.07 → 8.99 -0.9% ±39% 117%
truecolor 0.00 → 0.00 0.00 → 0.00 10.11 → 9.96 -1.5% ±1% 5%
alt-redraw 0.00 → 0.00 0.00 → 0.00 14.28 → 14.36 +0.6% ±3% 10%
unicode 7.66 → 7.66 0.45 → 0.45 35.33 → 36.14 +2.3% ±5% 15%
flood 0.00 → 0.00 0.00 → 0.00 94.63 → 94.44 -0.2% ±1% 5%

Each corpus is gated at max(5%, 3 × its own noise). A wide noise column means this runner was busy and the timing half of the table should be read as advisory; the allocation half is exact either way.

assemblies measured
  • base: XTerm.NET 2.0.3.0 mvid:9ba0ce98-0d1e-4424-8aa1-9ab012cdc07a
  • head: XTerm.NET 2.0.5.0 mvid:55751f9c-4ba5-449d-8e92-4047946a145e

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Kitty keyboard: Shift is unwound only for Digit* and Key* codes, so shifted punctuation reports the shifted character as the key code

2 participants