Skip to content

fix: keep prompt input inert during Safari IME composition#38728

Open
powoct wants to merge 5 commits into
anomalyco:devfrom
powoct:safari-ime-composition
Open

fix: keep prompt input inert during Safari IME composition#38728
powoct wants to merge 5 commits into
anomalyco:devfrom
powoct:safari-ime-composition

Conversation

@powoct

@powoct powoct commented Jul 24, 2026

Copy link
Copy Markdown

Issue for this PR

Closes #38674

Type of change

  • Bug fix
  • New feature
  • Refactor / code improvement
  • Documentation

What does this PR do?

In Safari, typing CJK text in the web app prompt input misbehaves in two ways: the IME composition gets aborted mid-input, and the Enter that confirms a candidate submits the message with the raw pinyin still in it.

Two causes, fixed in order:

  1. Safari fires compositionend before the confirming Enter keydown, so that keydown reports isComposing=false. The first commits add a guard that treats any key event within 100ms of compositionend (tracked with performance.now()) as part of the IME confirmation, in both the v1 (packages/app) and v2 (packages/session-ui) editors.

  2. That guard alone was not enough on a production deployment: the v2 editor still ran dispatch/setState on every keydown and read/wrote the selection on keyup/pointerup while composing. Safari reacts by aborting the composition after every letter, so nihao becomes five one-letter compositions and the final Enter arrives as a plain keyCode=13 long after any compositionend — nothing left for the guard to recognize. The last commit makes the v2 editor completely inert while a composition is active (and during the 100ms window after it): no keydown dispatch, no cursor sync, no input handling, no editor DOM rewrites. State is reconciled once from the DOM on compositionend. With the editor inert, Safari keeps the composition as a single segment, the confirming Enter reports keyCode=229, and the existing guard catches it.

Note: Enter committing the raw romaji (instead of 你好) is macOS Pinyin design — Space selects the candidate. The bug was that the app submitted the message on that Enter.

How did you verify your code works?

  • Real-device Safari 26 on macOS with macOS Pinyin and Japanese IMEs, against an instrumented build logging every composition/key event: nihao + Enter no longer submits and the text stays in the box, nihao + Space commits 你好, Japanese live conversion with multi-segment auto-commit is not interrupted, and plain-English Enter / Shift+Enter behavior is unchanged. Chrome regression-tested with the same IMEs.
  • bun test machine.test.ts in packages/session-ui (13 pass, including 2 new IME assertions) and bun typecheck across the affected packages.

Screenshots / recordings

No visual change; the fix only touches input event handling.

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

Made with Cursor

powoct and others added 5 commits July 24, 2026 20:18
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Production Safari testing showed the earlier Enter guard was not enough:
every composition keystroke still went through onKeyDown dispatch and the
onKeyUp/onPointerUp cursor sync, which makes Safari abort the composition
and split it into per-letter micro compositions. The confirming Enter then
arrives as a plain keyCode 13 long after compositionend and no guard can
recognize it, so the raw pinyin gets submitted.

Make the editor do nothing while a composition is active (and during the
100ms window after compositionend): skip keydown dispatch, cursor sync,
input handling, and editor DOM rewrites, then reconcile state once from
the DOM on compositionend. This keeps the composition as a single segment
so the confirming Enter reports keyCode 229 and is caught by the guard.

Co-authored-by: Cursor <cursoragent@cursor.com>
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.

Safari: CJK IME composition is aborted mid-input in web app prompt input

1 participant