Korean/CJK IME input drops characters in the terminal#30
Merged
Conversation
Owner
|
tested locally,. all good ✔️ merged and tagged v0.11.5 Thanks for your contribution! |
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
Typing Korean (and other IME-composed CJK) into any terminal pane dropped characters: each syllable collapsed to its leading jamo, so
안녕하세요came out asㅇㄴㅎ세. ASCII input was unaffected. This bridges the gap WebKit leaves in xterm.js's IME handling so composed input reaches the PTY intact.fix issue #29
AS-IS
TO-BE
Root cause
WebKit (WKWebView) does not drive CJK composition through the standard
compositionstart/update/endevents. Those never fire; on every keystrokeisComposingstaysfalseandkeyCodeis always229. Instead WebKit composes directly in xterm's helper textarea viainputevents:inputType: "insertText": a fresh jamo is appended (syllable start)inputType: "insertReplacementText": the in-progress syllable is refinedxterm's
_inputEventforwards onlyinsertTextand ignores everything else, so every refinement is dropped and only the leading jamo of each syllable reaches the PTY.Event trace from the live app (
localStorage.imeDebug=1), typing안녕:input insertText data="ㅇ" taValue="ㅇ" → forwarded ✓
input insertReplacementText data="아" taValue="아" → DROPPED ✗
input insertReplacementText data="안" taValue="안" → DROPPED ✗
input insertText data="ㄴ" taValue="안ㄴ" → forwarded ✓
input insertReplacementText data="녀" taValue="안녀" → DROPPED ✗
input insertReplacementText data="녕" taValue="안녕" → DROPPED ✗
PTY receives
ㅇ+ㄴ=ㅇㄴ, matching the symptom.Fix
New
src/lib/ime.ts(setupImeReplacementBridge): for everyinputevent xterm drops (replacement + composition-delete types), diff the textarea value (code-point aware) against its previous value and send backspaces (DEL,0x7f) for the removed suffix plus the new tail, so the PTY line mirrors the textarea exactly.insertTextstays handled by xterm; the bridge only resyncs its diff baseline. Diffing the whole composing value also handles Korean final-consonant migration (안+ㅏ→아나). AkeyCode === 229keydown guard keeps xterm's keydown path inert during IME, and an opt-inimeDebuglogger is left in for future WebKit regressions.Wired into
TerminalPane(agent/right-split tabs) andAuxTerminal(bottom-split shells). English/control keys route through keypress/keydown and never hit the bridge.Testing
src/lib/ime.test.ts(14 cases, happy-dom): delta math (append, replace, final-consonant migration, shrink, surrogate-pair backspaces), input-type gating, the full안녕WebKit sequence reconstructing on a model PTY, plus Enter baseline reset, cleanup, and the no-PTY case.tsc -bclean.안녕하세요, final-consonant migration, mid-composition backspace, mixed English, and Enter to submit.Affected surfaces