From 0bcb8ce6c3914627a19cc792ad78abd59d5a36eb Mon Sep 17 00:00:00 2001 From: Syngnat Date: Wed, 13 May 2026 20:19:44 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B=20fix(ai-chat):=20=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=E8=BE=93=E5=85=A5=E6=B3=95=E5=80=99=E9=80=89=E9=98=B6?= =?UTF-8?q?=E6=AE=B5=E5=9B=9E=E8=BD=A6=E8=AF=AF=E5=8F=91=E9=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 识别 IME keyCode/which 229 的候选输入事件 - 避免候选词确认触发 AI 对话发送 - 补充发送快捷键回归测试 Refs #461 --- frontend/src/utils/aiChatSendShortcut.test.ts | 3 +++ frontend/src/utils/aiChatSendShortcut.ts | 11 ++++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/frontend/src/utils/aiChatSendShortcut.test.ts b/frontend/src/utils/aiChatSendShortcut.test.ts index 0ae56ec..d6d1aab 100644 --- a/frontend/src/utils/aiChatSendShortcut.test.ts +++ b/frontend/src/utils/aiChatSendShortcut.test.ts @@ -52,6 +52,9 @@ describe('aiChatSendShortcut', () => { expect(shouldSendAIChatOnKeyDown(binding('Enter'), { key: 'Enter', shiftKey: true })).toBe(false); expect(shouldSendAIChatOnKeyDown(binding('Enter'), { key: 'Enter', isComposing: true })).toBe(false); expect(shouldSendAIChatOnKeyDown(binding('Enter'), { key: 'Enter', nativeEvent: { isComposing: true } })).toBe(false); + expect(shouldSendAIChatOnKeyDown(binding('Enter'), { key: 'Enter', keyCode: 229 })).toBe(false); + expect(shouldSendAIChatOnKeyDown(binding('Enter'), { key: 'Enter', which: 229 })).toBe(false); + expect(shouldSendAIChatOnKeyDown(binding('Enter'), { key: 'Enter', nativeEvent: { keyCode: 229 } })).toBe(false); expect(shouldSendAIChatOnKeyDown(binding('Enter'), { key: 'a' })).toBe(false); expect(shouldSendAIChatOnKeyDown(binding('Enter', false), { key: 'Enter' })).toBe(false); }); diff --git a/frontend/src/utils/aiChatSendShortcut.ts b/frontend/src/utils/aiChatSendShortcut.ts index d2ebcab..6e90d17 100644 --- a/frontend/src/utils/aiChatSendShortcut.ts +++ b/frontend/src/utils/aiChatSendShortcut.ts @@ -2,6 +2,8 @@ import { DEFAULT_SHORTCUT_OPTIONS, getShortcutDisplay, isShortcutMatch, type Sho export interface AIChatSendShortcutKeyEventLike { key?: string; + keyCode?: number; + which?: number; shiftKey?: boolean; metaKey?: boolean; ctrlKey?: boolean; @@ -9,6 +11,8 @@ export interface AIChatSendShortcutKeyEventLike { isComposing?: boolean; nativeEvent?: { isComposing?: boolean; + keyCode?: number; + which?: number; }; preventDefault?: () => void; stopPropagation?: () => void; @@ -29,7 +33,12 @@ export const shouldSendAIChatOnKeyDown = ( if (!binding?.enabled) { return false; } - if (event.shiftKey || event.isComposing || event.nativeEvent?.isComposing) { + // Some IMEs report Enter during an active candidate/composition as keyCode 229. + const isImeCandidateEvent = event.keyCode === 229 + || event.which === 229 + || event.nativeEvent?.keyCode === 229 + || event.nativeEvent?.which === 229; + if (event.shiftKey || event.isComposing || event.nativeEvent?.isComposing || isImeCandidateEvent) { return false; } return isShortcutMatch(event as KeyboardEvent, binding.combo);