You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Thanks for the excellent bug report — your root-cause analysis was spot on. Fixed in v0.6.3 (commit 5292107).
Root cause
Your point #1 was the actual bug. In CompositionHelper._finalizeComposition() (xterm.js 5.5, src/browser/input/CompositionHelper.ts), the compositionend path defers reading the textarea via setTimeout(0):
With fast Hangul typing, a new compositionstart can fire before the deferred reader runs, which shifts _isComposing / _compositionPosition so the substring that finally reaches triggerDataEvent is wrong — manifesting as the dropped / duplicated / incorrectly composed characters you saw. xterm's own inline comment on that block literally names Korean as the counter-example:
The last compositionupdate event's data property does not always accurately describe the character, a counter example being Korean where an ending consonant can move to the following character if the following input is a vowel.
Your points #2 and #3 were the right things to check but weren't the primary cause — Chromium 130 (Electron 33) populates the textarea synchronously before compositionend fires, and node-pty write() is a clean UTF-8 passthrough to conpty.
Fix
src/renderer/hooks/useTerminal.ts — after terminal.open(), patch the _compositionHelper instance to replace _finalizeComposition with a synchronous implementation:
No setTimeout → no race with a subsequent compositionstart.
Reads the textarea at event time (reliable in Chromium 130+).
Replaces the method on both call paths — compositionendand the sync finalize from CompositionHelper.keydown when a non-composition key (Enter, arrow keys) is pressed mid-composition.
Clears only the consumed portion of the textarea so the trailing input event (inputType: 'insertCompositionText') can't double-consume it.
Still routes through _coreService.triggerDataEvent(), so it integrates with xterm's normal onData → pty.write() pipeline.
Bonus fix (belt and suspenders)
Even with the composition race fixed, if conpty is running in a non-UTF-8 code page, Korean bytes can still get mangled between the renderer and the shell. So I also set UTF-8 I/O encoding in the shell integration scripts:
Important — right-click the zip → Properties → Unblock (or powershell "Get-ChildItem -Recurse | Unblock-File" after extracting) to strip the Mark of the Web, otherwise SmartScreen will be unhappy
Extract and run wmux.exe
Please reopen this issue if you still see any composition weirdness after the update — especially with 종성 → 초성 migration (e.g. typing 간 + ㅏ which should re-compose to 가나). That edge case is the exact scenario the xterm code comment was worried about, and it's the one I'd most like independent confirmation on. 🙏
Thank you so much for the incredibly thorough and prompt fix! 🙏
Your detailed root-cause analysis and the synchronous _finalizeComposition patch are truly impressive. The fact that you not only addressed the core setTimeout(0) race condition but also added the UTF-8 encoding fix as a belt-and-suspenders measure shows real attention to detail.
I've updated to v0.6.3 and Korean input is now working flawlessly — including the 종성 → 초성 migration case (e.g., 간 + ㅏ → 가나) that you mentioned. No more dropped or duplicated characters.
As a Korean user, having reliable Hangul input is absolutely essential, and this fix makes wmux a joy to use. Thank you for caring about international input support and for the incredibly fast turnaround.
Activity
amirlehmam commentedon Apr 10, 2026
Thanks for the excellent bug report — your root-cause analysis was spot on. Fixed in v0.6.3 (commit 5292107).
Root cause
Your point #1 was the actual bug. In
CompositionHelper._finalizeComposition()(xterm.js 5.5,src/browser/input/CompositionHelper.ts), thecompositionendpath defers reading the textarea viasetTimeout(0):With fast Hangul typing, a new
compositionstartcan fire before the deferred reader runs, which shifts_isComposing/_compositionPositionso the substring that finally reachestriggerDataEventis wrong — manifesting as the dropped / duplicated / incorrectly composed characters you saw. xterm's own inline comment on that block literally names Korean as the counter-example:Your points #2 and #3 were the right things to check but weren't the primary cause — Chromium 130 (Electron 33) populates the textarea synchronously before
compositionendfires, and node-ptywrite()is a clean UTF-8 passthrough to conpty.Fix
src/renderer/hooks/useTerminal.ts— afterterminal.open(), patch the_compositionHelperinstance to replace_finalizeCompositionwith a synchronous implementation:Key properties:
setTimeout→ no race with a subsequentcompositionstart.compositionendand the sync finalize fromCompositionHelper.keydownwhen a non-composition key (Enter, arrow keys) is pressed mid-composition.inputevent (inputType: 'insertCompositionText') can't double-consume it._coreService.triggerDataEvent(), so it integrates with xterm's normalonData→pty.write()pipeline.Bonus fix (belt and suspenders)
Even with the composition race fixed, if conpty is running in a non-UTF-8 code page, Korean bytes can still get mangled between the renderer and the shell. So I also set UTF-8 I/O encoding in the shell integration scripts:
src/shell-integration/wmux-powershell-integration.ps1:src/shell-integration/wmux-cmd-integration.cmd:How to get the fix
wmux-0.6.3-win-x64.zippowershell "Get-ChildItem -Recurse | Unblock-File"after extracting) to strip the Mark of the Web, otherwise SmartScreen will be unhappywmux.exePlease reopen this issue if you still see any composition weirdness after the update — especially with 종성 → 초성 migration (e.g. typing
간+ㅏwhich should re-compose to가나). That edge case is the exact scenario the xterm code comment was worried about, and it's the one I'd most like independent confirmation on. 🙏감사합니다!
babyfings commentedon Apr 10, 2026
Thank you so much for the incredibly thorough and prompt fix! 🙏
Your detailed root-cause analysis and the synchronous
_finalizeCompositionpatch are truly impressive. The fact that you not only addressed the coresetTimeout(0)race condition but also added the UTF-8 encoding fix as a belt-and-suspenders measure shows real attention to detail.I've updated to v0.6.3 and Korean input is now working flawlessly — including the 종성 → 초성 migration case (e.g., 간 + ㅏ → 가나) that you mentioned. No more dropped or duplicated characters.
As a Korean user, having reliable Hangul input is absolutely essential, and this fix makes wmux a joy to use. Thank you for caring about international input support and for the incredibly fast turnaround.
정말 감사합니다! 🎉
fix(terminal): korean hangul IME composition race on Windows 11 (amir…
feat: address issue #32 (notification sounds, single-instance CLI, qu…
security: harden pipe auth, CDP proxy, markdown XSS, and webview
fix(workspace-title): keep unquoted shell paths with spaces whole; sk…
docs(spec): record what was actually verified; note why default cwd/s…
Merge pull request #1 from mkh63d/feat/new-workspace-layout-picker
docs: add technical specifications for terminal bell separation and r…