From 2adf4d4312285b527d2477ee02f919079e072c31 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 11 Apr 2026 09:47:10 +0000 Subject: [PATCH 1/2] Initial plan From 4d0c2bfaa0004cf9b4999901b9d71353350a2951 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 11 Apr 2026 09:51:38 +0000 Subject: [PATCH 2/2] fix: prevent Enter submit during IME composition in chat input Agent-Logs-Url: https://github.com/OpenSource03/harnss/sessions/1710c611-f27a-4dfc-9fdc-0b92bd8dd572 Co-authored-by: OpenSource03 <29690431+OpenSource03@users.noreply.github.com> --- src/components/InputBar.test.ts | 31 +++++++++++++++++++++ src/components/input-bar/InputBar.tsx | 3 +- src/components/input-bar/index.ts | 1 + src/components/input-bar/input-bar-utils.ts | 21 ++++++++++++++ 4 files changed, 55 insertions(+), 1 deletion(-) diff --git a/src/components/InputBar.test.ts b/src/components/InputBar.test.ts index 5172973..59598e0 100644 --- a/src/components/InputBar.test.ts +++ b/src/components/InputBar.test.ts @@ -5,6 +5,7 @@ import { getAvailableSlashCommands, getSlashCommandReplacement, isClearCommandText, + shouldSubmitOnEnter, } from "./input-bar"; describe("InputBar slash command helpers", () => { @@ -46,4 +47,34 @@ describe("InputBar slash command helpers", () => { getSlashCommandReplacement({ name: "fix", description: "", source: "codex-skill", defaultPrompt: "bug" }), ).toBe("$fix bug"); }); + + it("does not submit enter while IME composition is active", () => { + expect( + shouldSubmitOnEnter({ + key: "Enter", + shiftKey: false, + isComposing: true, + }), + ).toBe(false); + expect( + shouldSubmitOnEnter({ + key: "Enter", + shiftKey: false, + nativeEvent: { isComposing: true }, + }), + ).toBe(false); + expect( + shouldSubmitOnEnter({ + key: "Enter", + shiftKey: false, + nativeEvent: { keyCode: 229 }, + }), + ).toBe(false); + }); + + it("submits enter only for non-composition send shortcut", () => { + expect(shouldSubmitOnEnter({ key: "Enter", shiftKey: false })).toBe(true); + expect(shouldSubmitOnEnter({ key: "Enter", shiftKey: true })).toBe(false); + expect(shouldSubmitOnEnter({ key: "a", shiftKey: false })).toBe(false); + }); }); diff --git a/src/components/input-bar/InputBar.tsx b/src/components/input-bar/InputBar.tsx index 9378449..9dc135d 100644 --- a/src/components/input-bar/InputBar.tsx +++ b/src/components/input-bar/InputBar.tsx @@ -46,6 +46,7 @@ import { extractEditableContent, getAvailableSlashCommands, isClearCommandText, + shouldSubmitOnEnter, } from "./input-bar-utils"; import { ContextGauge } from "./ContextGauge"; import { AttachmentPreview } from "./AttachmentPreview"; @@ -543,7 +544,7 @@ export const InputBar = memo(function InputBar({ return; } - if (e.key === "Enter" && !e.shiftKey) { + if (shouldSubmitOnEnter(e)) { e.preventDefault(); if (!isSending && !isAwaitingAcpOptions) { handleSend(); diff --git a/src/components/input-bar/index.ts b/src/components/input-bar/index.ts index 1c4dc31..c8c6bb7 100644 --- a/src/components/input-bar/index.ts +++ b/src/components/input-bar/index.ts @@ -7,4 +7,5 @@ export { getAvailableSlashCommands, getSlashCommandReplacement, isClearCommandText, + shouldSubmitOnEnter, } from "./input-bar-utils"; diff --git a/src/components/input-bar/input-bar-utils.ts b/src/components/input-bar/input-bar-utils.ts index ccec8d2..d676395 100644 --- a/src/components/input-bar/input-bar-utils.ts +++ b/src/components/input-bar/input-bar-utils.ts @@ -146,6 +146,27 @@ export function fuzzyMatch( return { match: false, score: 0 }; } +type EnterKeyEventLike = { + key: string; + shiftKey: boolean; + isComposing?: boolean; + nativeEvent?: { + isComposing?: boolean; + keyCode?: number; + }; +}; + +/** Enter should submit only when not composing text via an IME. */ +export function shouldSubmitOnEnter(event: EnterKeyEventLike): boolean { + if (event.key !== "Enter" || event.shiftKey) return false; + const nativeEvent = event.nativeEvent; + return !( + event.isComposing || + nativeEvent?.isComposing || + nativeEvent?.keyCode === 229 + ); +} + // ── Slash command helpers (exported for tests + external consumers) ── export const LOCAL_CLEAR_COMMAND: SlashCommand = {