diff --git a/frontend/app/view/term/term-model.ts b/frontend/app/view/term/term-model.ts index a256929e7d..fe6e90f811 100644 --- a/frontend/app/view/term/term-model.ts +++ b/frontend/app/view/term/term-model.ts @@ -697,6 +697,9 @@ export class TermViewModel implements ViewModel { } handleTerminalKeydown(event: KeyboardEvent): boolean { + if (event.isComposing || event.keyCode === 229) { + return false; + } const waveEvent = keyutil.adaptFromReactOrNativeKeyEvent(event); if (waveEvent.type != "keydown") { return true; diff --git a/frontend/app/view/term/termwrap.ts b/frontend/app/view/term/termwrap.ts index d10b600459..57b41efe2a 100644 --- a/frontend/app/view/term/termwrap.ts +++ b/frontend/app/view/term/termwrap.ts @@ -111,6 +111,8 @@ export class TermWrap { lastPasteData: string = ""; lastPasteTime: number = 0; + pendingImeDedup: string[] = []; + // dev only (for debugging) recentWrites: { idx: number; data: string; ts: number }[] = []; recentWritesCounter: number = 0; @@ -383,6 +385,27 @@ export class TermWrap { const copyOnSelectAtom = getSettingsKeyAtom("term:copyonselect"); const trimTrailingWhitespaceAtom = getSettingsKeyAtom("term:trimtrailingwhitespace"); this.toDispose.push(this.terminal.onData(this.handleTermData.bind(this))); + const ta = this.terminal.textarea; + if (ta) { + const onCompEnd = (e: CompositionEvent) => { + const compHelper = (this.terminal as any)._core?._inputHandler?._compositionHelper; + if (compHelper && "_isSendingComposition" in compHelper) { + compHelper._isSendingComposition = false; + } + if (!e.data) { + return; + } + this.pendingImeDedup.push(e.data); + this.sendDataHandler?.(e.data); + this.multiInputCallback?.(e.data); + }; + ta.addEventListener("compositionend", onCompEnd); + this.toDispose.push({ + dispose: () => { + ta.removeEventListener("compositionend", onCompEnd); + }, + }); + } this.toDispose.push( this.terminal.onSelectionChange( debounce(50, () => { @@ -467,7 +490,11 @@ export class TermWrap { if (!this.loaded) { return; } - + const dedupIdx = this.pendingImeDedup.indexOf(data); + if (dedupIdx !== -1) { + this.pendingImeDedup.splice(dedupIdx, 1); + return; + } this.sendDataHandler?.(data); this.multiInputCallback?.(data); }