From ef6a7e6c58eebac860bf343d367070204c3099e0 Mon Sep 17 00:00:00 2001 From: zheli Date: Thu, 27 Aug 2026 13:42:29 +0800 Subject: [PATCH] fix(composer): ignore Enter during IME composition --- .../src/components/Composer.skills.test.tsx | 25 +++++++++++++++++++ surfaces/gui/src/components/Composer.tsx | 5 ++++ 2 files changed, 30 insertions(+) diff --git a/surfaces/gui/src/components/Composer.skills.test.tsx b/surfaces/gui/src/components/Composer.skills.test.tsx index 9d1250be23..fd68a9eeac 100644 --- a/surfaces/gui/src/components/Composer.skills.test.tsx +++ b/surfaces/gui/src/components/Composer.skills.test.tsx @@ -47,6 +47,31 @@ afterEach(() => { }); describe("Composer / skills popup", () => { + it("does not send when Enter confirms IME composition", async () => { + stubFetch(); + const p = props(); + render(); + fireEvent.change(box(), { target: { value: "你好" } }); + + fireEvent.keyDown(box(), { key: "Enter", isComposing: true }); + expect(p.onSend).not.toHaveBeenCalled(); + expect((box() as HTMLTextAreaElement).value).toBe("你好"); + + fireEvent.keyDown(box(), { key: "Enter" }); + await waitFor(() => expect(p.onSend).toHaveBeenCalledWith("你好", [], undefined)); + }); + + it("does not send for WebKit's legacy IME key code", () => { + stubFetch(); + const p = props(); + render(); + fireEvent.change(box(), { target: { value: "你好" } }); + + fireEvent.keyDown(box(), { key: "Enter", keyCode: 229 }); + expect(p.onSend).not.toHaveBeenCalled(); + expect((box() as HTMLTextAreaElement).value).toBe("你好"); + }); + it("opens on a leading '/' and lists only enabled skills from the effective menu", async () => { stubFetch(); render(); diff --git a/surfaces/gui/src/components/Composer.tsx b/surfaces/gui/src/components/Composer.tsx index c57d46f989..dbb2b5b81e 100644 --- a/surfaces/gui/src/components/Composer.tsx +++ b/surfaces/gui/src/components/Composer.tsx @@ -402,6 +402,11 @@ export function Composer(props: Props) { }; const onKey = (e: React.KeyboardEvent) => { + // Enter confirms the active IME candidate before it means "send". WebKit may + // report the composition keydown with the legacy 229 key code, so keep that + // fallback alongside the standards-based isComposing flag. + if (e.nativeEvent.isComposing || e.nativeEvent.keyCode === 229) return; + if (slashQuery !== null) { if (e.key === "ArrowDown") { e.preventDefault();