# 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
This commit is contained in:
SliverKeigo
2025-05-12 15:51:07 +08:00
committed by GitHub
parent fc7a98351c
commit 2328cbd46f
2 changed files with 8 additions and 2 deletions
@@ -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"
/>
</div>
</div>
@@ -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"
/>
</div>
</div>