Skip to content

fix: Various problems with Chinese IMEs#320525

Open
arnavnagzirkar wants to merge 2 commits into
microsoft:mainfrom
arnavnagzirkar:fix-275646
Open

fix: Various problems with Chinese IMEs#320525
arnavnagzirkar wants to merge 2 commits into
microsoft:mainfrom
arnavnagzirkar:fix-275646

Conversation

@arnavnagzirkar

Copy link
Copy Markdown

Summary

When third-party Chinese IMEs (like Sogou on macOS) substitute punctuation (e.g. . ), they fire compositionstart/compositionupdate/compositionend events.

Root cause

When third-party Chinese IMEs (like Sogou on macOS) substitute punctuation (e.g. . ), they fire compositionstart/compositionupdate/compositionend events. During this composition, the browser also fires keydown events with event.isComposing = true and a non-229 keyCode (e.g. keyCode 190 for .).

xterm.js's _compositionHelper.keydown() method handles keydown events:

  • When _isComposing = true and keyCode = 229 (the standard IME Process code): correctly returns false (no-op, let composition events handle it)
  • When _isComposing = true and keyCode ≠ 229 (e.g. 190 for "."): bug - calls _finalizeComposition(false) (which sends an empty/partial composition) and then returns true, causing xterm.js to also process and send the raw key (.) to the shell

VS Code's attachCustomKeyEventHandler did not check event.isComposing, so it always passed every keydown event to xterm.js's handler, triggering the buggy code path.

Reference: xtermjs/xterm.js#4486 (unfixed upstream as of this writing)

What changed

src/vs/workbench/contrib/terminal/browser/terminalInstance.ts

Added an early-return guard in attachCustomKeyEventHandler (the VS Code custom key handler registered with xterm.js):

// Do not process keys that are part of an IME composition; compositionstart/end events
// handle sending the composed text to the terminal. Without this, xterm.js will incorrectly
// process the raw key (eg. "." instead of "。") and potentially send it to the shell.
// See: https://github.com/microsoft/vscode/issues/275646
if (event.isComposing) {
 return false;
}

Returning false from this handler tells xterm.js to skip its own _compositionHelper.keydown() call for that event, preventing the raw key from being sent to the shell. The composition events (compositionstart/compositionupdate/compositionend) are handled by separate direct listeners on the textarea in xterm.js - they are not affected by this change, so the composed Chinese characters are still correctly sent when the composition ends.

Why this is safe:

  • Keys with isComposing=true and keyCode=229 were already no-ops in xterm.js; returning false for those has the same effect
  • Keys with isComposing=true and non-229 keyCode are the bug case; returning false skips the buggy _finalizeComposition(false) + key processing path
  • On macOS/Chrome, the confirming key press (e.g. Enter/Space) fires AFTER compositionend, so its isComposing is false - it is not affected by this check
  • VS Code keybindings during composition are unusual; users don't typically trigger VS Code commands while an IME is actively composing

Issue

Fixes #275646

Issue: #275646

Diffstat

.../contrib/terminal/browser/terminalInstance.ts | 8 ++++++++
 .../terminal/test/browser/terminalInstance.test.ts | 22 ++++++++++++++++++++++
 2 files changed, 30 insertions(+)

Testing

  • Ran the relevant tests and linter for the changed files while developing.

  • Kept the change minimal and focused on this one issue.

AI assistance

I used GitHub Copilot to help write parts of this change. I've reviewed and tested it myself, I understand what it does, and I'll follow up on any review feedback.

Copilot AI review requested due to automatic review settings June 9, 2026 00:41
@vs-code-engineering

vs-code-engineering Bot commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

📬 CODENOTIFY

The following users are being notified based on files changed in this PR:

@anthonykim1

Matched files:

  • src/vs/workbench/contrib/terminal/browser/terminalInstance.ts
  • src/vs/workbench/contrib/terminal/test/browser/terminalInstance.test.ts

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Fixes Chinese IME composition-related keydown handling so raw punctuation keys aren’t incorrectly sent to the shell during an active composition session.

Changes:

  • Ignore keydown events with event.isComposing === true in the terminal’s custom key handler to avoid triggering xterm.js’s buggy composition path.
  • Add a browser test to verify composed keydown events are blocked (handler returns false) and not preventDefault’ed.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
src/vs/workbench/contrib/terminal/browser/terminalInstance.ts Adds an early return for event.isComposing in the xterm custom key event handler.
src/vs/workbench/contrib/terminal/test/browser/terminalInstance.test.ts Adds a unit test asserting composed keydown events are ignored by the custom handler.

Comment on lines +1141 to +1144
// Do not process keys that are part of an IME composition; compositionstart/end events
// handle sending the composed text to the terminal. Without this, xterm.js will incorrectly
// process the raw key (eg. "." instead of "。") and potentially send it to the shell.
// See: https://github.com/microsoft/vscode/issues/275646
test('custom key event handler should return false for keys that are part of an IME composition to prevent raw key from being sent to shell', async () => {
const instance = await createTerminalInstance();
let capturedHandler: ((e: KeyboardEvent) => boolean) | undefined;
instance.xterm!.raw.attachCustomKeyEventHandler = handler => { capturedHandler = handler; };
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.

Various problems with Chinese IMEs

4 participants