fix(mobile): CJK input loss — IME state machine, focus routing, and Android InputConnection recovery#143
Open
TeigenZhang wants to merge 1 commit into
Open
fix(mobile): CJK input loss — IME state machine, focus routing, and Android InputConnection recovery#143TeigenZhang wants to merge 1 commit into
TeigenZhang wants to merge 1 commit into
Conversation
…ndroid InputConnection recovery Three independent root causes of intermittent Chinese character loss (English was unaffected because it bypasses the composition path): 1. input-cjk.js state machine: stuck _composing when compositionend never fires (WeChat/Sogou IMEs) silently swallowed all input; the deferred compositionend flush could reset the textarea mid-next-composition (cancels the live IME composition on iOS); the 100ms keydown-echo window discarded ANY input regardless of content. 2. Focus stealing: session-select / SSE-reconnect paths call terminal.focus() (15+ call sites), landing focus on xterm's hidden textarea; with the CJK onData gate active, everything typed there was swallowed. Fix: focus router in initTerminal routes ALL terminal.focus() calls to the CJK field while it is visible, plus a self-healing onData gate that reclaims focus when it swallows input. 3. Android InputConnection wedge (9-key IMEs + Chromium): the keyboard composes in its own UI but delivers zero DOM events. Fix: skip redundant textarea value/selection writes (they race IME session setup), and re-tapping the focused empty field forces a blur→focus cycle that restarts the input session. Diagnostics: input-cjk.js now traces every IME event/flush decision into the crash-diag breadcrumbs; /api/crash-diag stores beacons per page-load id (iOS PWA reloads no longer wipe the trail, concurrent clients no longer clobber each other) and flushes on visibilitychange. Tests: test/input-cjk.test.ts (vm-sandbox, 9 cases incl. regression guards for all three root causes).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes Chinese/Japanese/Korean (CJK) input silently disappearing on mobile — characters composed in the IME never reach the PTY, or land in the wrong place after switching apps. Three distinct root causes, one per layer:
compositionstart/compositionupdate/compositionendwere not tracked as a proper state machine, so a composition that was interrupted (app switch, focus steal) leftcjkActivestuck or cleared at the wrong time, dropping the committed text.terminal.focus(), which stole focus back to xterm's hidden textarea while the CJK field was visible. The IME then composed into a black hole (xterm'sonDatais gated bycjkActive). Now everyterminal.focus()routes through one chokepoint that keeps the CJK field focused when it's visible.InputConnectionmid-composition; the textarea silently stopped emitting input events. Detect the dead connection and re-establish it.Changes
input-cjk.js— composition state machine + Android InputConnection recoveryterminal-ui.js— focus router chokepoint so restore paths don't steal focus from the CJK fieldapp.js/server.ts— crash-diag tracing hooks used to pin down the Android casetest/input-cjk.test.ts— 9 new cases (241 lines) covering the state machine and focus routingTest plan
npm test -- test/input-cjk.test.ts— 9/9 passnpm run check:frontend-syntax