Merge branch 'fork/beetle0915/fix/ime-enter-composition' into dev

This commit is contained in:
HouYunFei
2026-07-08 16:30:38 +08:00
4 changed files with 61 additions and 2 deletions
@@ -2,6 +2,7 @@ import { useEffect, useRef, useState, type ReactNode } from "react";
import { Button, Tooltip } from "antd";
import { ArrowUp, CheckCircle2, CircleAlert, ImagePlus, LoaderCircle, UserRound, Wrench, X, XCircle } from "lucide-react";
import { isPlainEnterKey } from "@/lib/keyboard-event";
import { canvasThemes } from "@/lib/canvas-theme";
import type { LocalUser } from "@/stores/use-user-store";
@@ -197,7 +198,7 @@ export function AgentChatComposer({
void onAddFiles(images);
}}
onKeyDown={(event) => {
if (event.key !== "Enter" || event.shiftKey || event.ctrlKey || event.metaKey) return;
if (!isPlainEnterKey(event)) return;
event.preventDefault();
void onSubmit();
}}
@@ -4,6 +4,7 @@ import { createPortal } from "react-dom";
import { FileText, Image as ImageIcon, Music2, Video } from "lucide-react";
import { canvasThemes } from "@/lib/canvas-theme";
import { isImeComposing, isPlainEnterKey } from "@/lib/keyboard-event";
import { useThemeStore } from "@/stores/use-theme-store";
import type { CanvasResourceReference } from "@/lib/canvas/canvas-resource-references";
@@ -131,6 +132,10 @@ export const CanvasResourceMentionTextarea = forwardRef<HTMLTextAreaElement, Pro
props.onPointerUp?.(event);
}}
onKeyDown={(event) => {
if (isImeComposing(event)) {
onKeyDown?.(event);
return;
}
if (mention && candidates.length) {
if (event.key === "ArrowDown") {
event.preventDefault();
@@ -153,7 +158,7 @@ export const CanvasResourceMentionTextarea = forwardRef<HTMLTextAreaElement, Pro
return;
}
}
if (event.key === "Enter" && onSubmit && !event.ctrlKey && !event.metaKey && !event.shiftKey) {
if (isPlainEnterKey(event) && onSubmit) {
event.preventDefault();
onSubmit();
return;
+22
View File
@@ -0,0 +1,22 @@
type NativeKeyboardEventLike = {
isComposing?: boolean;
keyCode?: number;
which?: number;
};
type KeyboardEventLike = NativeKeyboardEventLike & {
key?: string;
shiftKey?: boolean;
ctrlKey?: boolean;
metaKey?: boolean;
nativeEvent?: NativeKeyboardEventLike;
};
export function isImeComposing(event: KeyboardEventLike) {
const nativeEvent = event.nativeEvent;
return Boolean(event.isComposing || nativeEvent?.isComposing || event.keyCode === 229 || event.which === 229 || nativeEvent?.keyCode === 229 || nativeEvent?.which === 229);
}
export function isPlainEnterKey(event: KeyboardEventLike) {
return event.key === "Enter" && !event.shiftKey && !event.ctrlKey && !event.metaKey && !isImeComposing(event);
}
+31
View File
@@ -0,0 +1,31 @@
import assert from "node:assert/strict";
import { isImeComposing, isPlainEnterKey } from "../src/lib/keyboard-event";
type KeyboardEventLike = Parameters<typeof isPlainEnterKey>[0];
function enterEvent(overrides: Partial<KeyboardEventLike> = {}): KeyboardEventLike {
return {
key: "Enter",
shiftKey: false,
ctrlKey: false,
metaKey: false,
...overrides,
};
}
assert.equal(isPlainEnterKey(enterEvent()), true, "plain Enter submits");
assert.equal(isPlainEnterKey(enterEvent({ shiftKey: true })), false, "Shift+Enter does not submit");
assert.equal(isPlainEnterKey(enterEvent({ ctrlKey: true })), false, "Ctrl+Enter does not submit");
assert.equal(isPlainEnterKey(enterEvent({ metaKey: true })), false, "Meta+Enter does not submit");
assert.equal(isPlainEnterKey(enterEvent({ nativeEvent: { isComposing: true } })), false, "IME composition Enter does not submit");
assert.equal(isPlainEnterKey(enterEvent({ nativeEvent: { keyCode: 229 } })), false, "legacy IME Enter does not submit");
assert.equal(isPlainEnterKey(enterEvent({ key: "a" })), false, "non-Enter keys do not submit");
assert.equal(isImeComposing(enterEvent({ isComposing: true })), true, "direct composition flag is detected");
assert.equal(isImeComposing(enterEvent({ nativeEvent: { isComposing: true } })), true, "native composition flag is detected");
assert.equal(isImeComposing(enterEvent({ keyCode: 229 })), true, "direct legacy keyCode composition is detected");
assert.equal(isImeComposing(enterEvent({ nativeEvent: { keyCode: 229 } })), true, "native legacy keyCode composition is detected");
assert.equal(isImeComposing(enterEvent()), false, "plain Enter is not composition");
console.log("ime keyboard tests passed");