Skip to content

Recover Ctrl+<letter> and Escape under a CJK IME (keyCode 229) - #6066

Open
openwong2kim wants to merge 1 commit into
xtermjs:masterfrom
openwong2kim:fix/ime-keycode-229-control-keys
Open

Recover Ctrl+<letter> and Escape under a CJK IME (keyCode 229)#6066
openwong2kim wants to merge 1 commit into
xtermjs:masterfrom
openwong2kim:fix/ime-keycode-229-control-keys

Conversation

@openwong2kim

Copy link
Copy Markdown

Fixes #6065

What

While a CJK IME is active, Windows/Chromium delivers control inputs with keyCode === 229 ("Process") even though they never begin a composition. Ctrl+<letter>, Ctrl+Space, and a bare Escape are then silently dropped — nothing reaches onData. Inside an in-pane TUI this shows up as Ctrl+J not inserting a newline, Ctrl+C not interrupting, and Escape not cancelling; the same keys work with the IME off.

Root cause and measurements are in #6065. In short, two keyCode-based paths combine:

  1. CompositionHelper.keydown returns false for every keyCode === 229 keydown, so _keyDown bails before the encoder runs. That assumes a later input/composition event will carry the key — true for printable characters, but control chords produce neither.
  2. evaluateKeyboardEvent switches on keyCode, so 229 matches neither Escape (case 27) nor the Ctrl+<letter> derivation (keyCode 65..90).

The physical ev.code is correct throughout, so it's used to recover the intended key.

Changes

  • common/input/Keyboard.ts — add recoverImeControlKeyCode(ev): when keyCode === 229, map ev.code back to a real keyCode for the masked control inputs (Escape → 27; with Ctrl held, KeyA..KeyZ → 65..90 and Space → 32). evaluateKeyboardEvent uses the recovered value for its switch and for the Ctrl+<letter>/Ctrl+Space cases in the default branch. Printable/composable keys keep keyCode === 229 and are left to the composition path.
  • browser/input/CompositionHelper.ts — in the non-composing keyCode === 229 branch, let control inputs (ev.code === 'Escape', or ev.ctrlKey && !ev.altKey && !ev.metaKey) continue to the normal key handler (return true) instead of being swallowed. A small isImeControlPassthrough predicate mirrors the recovery scope.

Both are gated on the control-key conditions, so genuine IME composition — which never involves Ctrl, and for a bare key produces an input/composition event — is unaffected.

Testing

  • Keyboard.test.ts: new cases asserting Ctrl+J\n, Ctrl+C\x03, Ctrl+Space\x00, Escape\x1b at keyCode 229; that a plain composable key at 229 still yields no key; and that real keyCodes are unaffected.
  • CompositionHelper.test.ts: new cases asserting keydown returns true (passthrough) for a Ctrl chord and for Escape at keyCode 229.
  • Full Keyboard + CompositionHelper suites pass (77 tests). tsgo build clean; oxlint --type-aware and the naming ESLint config clean on both changed files.
  • End-to-end dynamic repro against the built lib/xterm.mjs in Chromium (dispatches keydowns with keyCode forced to 229): stock emits nothing for all four control inputs; with the fix they emit the correct bytes and a plain composing key still emits nothing.
keydown (keyCode 229) stock onData fixed onData
Ctrl+J (nothing) 0a
Ctrl+C (nothing) 03
Ctrl+Space (nothing) 00
Escape (nothing) 1b
plain j (composing) (nothing) (nothing)

Notes

Scoped to Ctrl+<letter>, Ctrl+Space, and Escape — the inputs with confirmed field reports. Alt/Meta chords are derived from keyCode in the same branch and are plausibly affected; left out here to keep the change conservative, easy to add if wanted.

When a CJK IME is active, Windows/Chromium reports keyCode 229 for keys it
has claimed, including control inputs that never begin a composition. Those
were dropped: CompositionHelper.keydown swallowed every 229 keydown, and
evaluateKeyboardEvent switches on keyCode so Escape and Ctrl+<letter> never
matched. Recover the real keyCode from the physical code for these inputs
(Escape, Ctrl+letter, Ctrl+Space) and let them through the composition gate,
leaving printable/composable keys untouched.
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.

Ctrl+<letter> and Escape are silently dropped under a CJK IME (keyCode 229)

2 participants