From 2328cbd46f35d80cd3b17bc2837a96c9d8eca02e Mon Sep 17 00:00:00 2001 From: SliverKeigo Date: Mon, 12 May 2025 15:51:07 +0800 Subject: [PATCH] # Fix IME input submission issue with Enter key (#158) ## Problem When using Input Method Editor (IME) for languages like Chinese or Japanese, pressing Enter key triggers two actions simultaneously: 1. Confirms the current IME input 2. Submits the message This makes it impossible to properly input text using IME. ## Solution Add IME composition state detection to prevent message submission during IME input: 1. Add `isComposing` state to track IME input status 2. Listen to `compositionstart` and `compositionend` events to update IME state 3. Add IME state check in `handleSend` function ## Files Changed - `apps/stage-web/src/components/Layouts/InteractiveArea.vue` - `apps/stage-web/src/components/Layouts/MobileInteractiveArea.vue` ## Testing Steps 1. Use Chinese/Japanese IME to input text 2. Press Enter key while IME candidate window is showing 3. Verify that text is correctly entered into the input field instead of triggering message submission 4. After IME input is complete, verify that pressing Enter key submits the message normally ## Additional Notes - While mobile devices typically use virtual keyboards, we've added the same handling logic to maintain code consistency and prepare for potential desktop mode in the future - This change does not affect normal message submission functionality --- apps/stage-web/src/components/Layouts/InteractiveArea.vue | 5 ++++- .../src/components/Layouts/MobileInteractiveArea.vue | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/apps/stage-web/src/components/Layouts/InteractiveArea.vue b/apps/stage-web/src/components/Layouts/InteractiveArea.vue index 6365e1ab3..343548d6a 100644 --- a/apps/stage-web/src/components/Layouts/InteractiveArea.vue +++ b/apps/stage-web/src/components/Layouts/InteractiveArea.vue @@ -17,6 +17,7 @@ const messageInput = ref('') const listening = ref(false) const tab = ref<'chat' | 'custom' | 'clothes'>('chat') const showMicrophoneSelect = ref(false) +const isComposing = ref(false) const providersStore = useProvidersStore() const { activeProvider, activeModel } = storeToRefs(useConsciousnessStore()) @@ -46,7 +47,7 @@ const { transcribe: generate, terminate } = useWhisper(WhisperWorker, { }) async function handleSend() { - if (!messageInput.value.trim()) { + if (!messageInput.value.trim() || isComposing.value) { return } @@ -224,6 +225,8 @@ onAfterSend(async () => { 'transition-colors-none placeholder:transition-colors-none': themeColorsHueDynamic, }" @submit="handleSend" + @compositionstart="isComposing = true" + @compositionend="isComposing = false" /> diff --git a/apps/stage-web/src/components/Layouts/MobileInteractiveArea.vue b/apps/stage-web/src/components/Layouts/MobileInteractiveArea.vue index 3bc54734e..c9f87c40b 100644 --- a/apps/stage-web/src/components/Layouts/MobileInteractiveArea.vue +++ b/apps/stage-web/src/components/Layouts/MobileInteractiveArea.vue @@ -12,6 +12,7 @@ import MobileChatHistory from '../Widgets/MobileChatHistory.vue' const messageInput = ref('') const listening = ref(false) +const isComposing = ref(false) const providersStore = useProvidersStore() const { activeProvider, activeModel } = storeToRefs(useConsciousnessStore()) @@ -23,7 +24,7 @@ const { send, onAfterSend } = useChatStore() const { t } = useI18n() async function handleSend() { - if (!messageInput.value.trim()) { + if (!messageInput.value.trim() || isComposing.value) { return } @@ -98,6 +99,8 @@ onMounted(() => { transition="all duration-250 ease-in-out placeholder:all placeholder:duration-250 placeholder:ease-in-out" :class="{ 'transition-colors-none placeholder:transition-colors-none': themeColorsHueDynamic }" @submit="handleSend" + @compositionstart="isComposing = true" + @compositionend="isComposing = false" />