Skip to content

fix: prevent Enter from sending message during IME composition#63

Open
zzzhizhia wants to merge 2 commits intoSamuelZ12:mainfrom
zzzhizhia:fix/ime-composition
Open

fix: prevent Enter from sending message during IME composition#63
zzzhizhia wants to merge 2 commits intoSamuelZ12:mainfrom
zzzhizhia:fix/ime-composition

Conversation

@zzzhizhia
Copy link

Summary

  • Fix chat input sending message when pressing Enter to confirm IME (Chinese input method) composition
  • Add e.nativeEvent.isComposing as secondary guard alongside the existing isComposingRef
  • Delay isComposingRef reset in onCompositionEnd via setTimeout(0) to handle browsers where compositionend fires before keydown
  • Apply the same fix to note editor and transcript search input for consistency

Root cause

In Chrome with Chinese IME, when typing English letters and pressing Enter to confirm, the event order can be compositionendkeydown. The existing onCompositionEnd handler immediately set isComposingRef.current = false, so by the time keydown fired, the ref was already reset and the message was sent.

Changes

  • components/ai-chat.tsx: Add isComposing check + delay ref reset
  • components/note-editor.tsx: Add isComposing guard
  • components/transcript-viewer.tsx: Add isComposing guard

Test plan

  • Use Chinese IME (e.g. Pinyin) to type English letters in the chat input
  • Press Enter to confirm IME composition — message should NOT be sent
  • Press Enter again (after IME is dismissed) — message should be sent
  • Shift+Enter should still create a new line
  • Normal English keyboard input + Enter should send as usual

When using a Chinese IME to type English, pressing Enter to confirm the
composition was incorrectly sending the chat message. This happened
because some browsers fire compositionend before keydown, resetting the
isComposing ref before the keydown handler could check it.

- Add e.nativeEvent.isComposing check as a secondary guard
- Delay resetting isComposingRef in onCompositionEnd via setTimeout(0)
  so the keydown handler for the same keystroke still sees it as true
- Apply the same IME guard to note-editor and transcript-viewer
Copilot AI review requested due to automatic review settings March 3, 2026 09:50
@vercel
Copy link

vercel bot commented Mar 3, 2026

@zzzhizhia is attempting to deploy a commit to the samuelz12's projects Team on Vercel.

A member of the Team first needs to authorize it.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Prevents Enter from triggering “send” / “next” behaviors while the user is confirming IME (e.g., Chinese Pinyin) composition, addressing Chrome’s compositionend → keydown ordering edge case.

Changes:

  • Add e.nativeEvent.isComposing guards to Enter key handlers across chat, note editor, and transcript search.
  • In chat input, delay resetting isComposingRef on compositionend to ensure the subsequent Enter keydown is still treated as composing.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
components/ai-chat.tsx Adds nativeEvent.isComposing guard and delays isComposingRef reset after composition ends.
components/note-editor.tsx Prevents Cmd/Ctrl+Enter save from firing during IME composition.
components/transcript-viewer.tsx Prevents Enter-based search navigation from firing during IME composition.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 1274 to +1282
onCompositionEnd={() => {
isComposingRef.current = false;
// Delay resetting the flag so the keydown handler for the
// same Enter keystroke still sees isComposing as true.
// In some browsers (e.g. Chrome with Chinese IME),
// compositionend fires before keydown for the Enter key
// that confirms the composition.
setTimeout(() => {
isComposingRef.current = false;
}, 0);
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

onCompositionEnd schedules a setTimeout(0) that unconditionally sets isComposingRef.current = false. If a new composition starts before the timeout fires (e.g., user immediately continues composing), the pending timeout can incorrectly flip the flag to false while composition is active. Consider storing the timeout id (or a monotonically increasing composition sequence) in a ref and cancelling/invalidating it in onCompositionStart (and on unmount) before scheduling a new reset.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants