fix(extension): drop manual IME compositionend send that doubled CJK input

xterm.js already handles IME composition correctly: partial jamo are
suppressed while _isComposing, and _finalizeComposition emits the final
composed string through onData exactly once, asynchronously via
setTimeout(0).

The local workaround for #1272 sent e.data manually on compositionend —
one macrotask BEFORE xterm's own emission of the same string — so every
composed Korean syllable was sent to the PTY twice (안녕 → 안녕안녕).
ASCII input was unaffected because it never goes through composition.

Remove the custom compositionstart/compositionend listeners and let
xterm deliver the final string through the normal onData path.

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Minseo Lee 2026-08-11 16:49:58 +09:00
parent d303e15e63
commit c68e5d831c
1 changed files with 7 additions and 17 deletions

View File

@ -433,25 +433,15 @@
});
ro.observe(els.mount);
// IME composition handling for Korean/CJK input (issue #1272).
// Suppress partial jamo during composition; only send the final
// composed string on compositionend. Without this, Korean IME
// sends fragmented input or doubles characters.
let composing = false;
const ta = term.textarea;
if (ta) {
ta.addEventListener('compositionstart', () => { composing = true; });
ta.addEventListener('compositionend', (e) => {
composing = false;
if (e.data && ws && ws.readyState === WebSocket.OPEN) {
ws.send(new TextEncoder().encode(e.data));
}
});
}
// IME composition (Korean/CJK, issue #1272) is handled by xterm.js
// itself: partial jamo are suppressed while _isComposing, and the final
// composed string is emitted through onData once, asynchronously
// (setTimeout in _finalizeComposition). A previous local workaround
// sent e.data manually on compositionend — but xterm emits the same
// string one macrotask later, so every composed syllable went out
// TWICE. Do not re-add a manual compositionend send.
term.onData((data) => {
if (composing) return; // suppress partial input events during IME composition
if (ws && ws.readyState === WebSocket.OPEN) {
ws.send(new TextEncoder().encode(data));
}