Skip to content

fix: prevent Enter from sending during IME composition - #965

Merged
ocavue merged 9 commits into
masterfrom
ocavue/ime-chat
Jul 27, 2026
Merged

ocavue merged 9 commits into
masterfrom
ocavue/ime-chat

Conversation

@ocavue

@ocavue ocavue commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Ignore the keydown that commits an IME composition (WebKit fires it after compositionend with isComposing false) so committing Japanese text can't send the chat message, select a cmdk item, or trigger app shortcuts.

Summary by CodeRabbit

  • Bug Fixes
    • Improved text input with IMEs by preventing Enter, Escape, keyboard shortcuts, and related actions (such as submissions, selections, and navigation) from triggering while text is still being composed.
    • Applied consistent IME-safe key handling across chat, command palette, search/find, tasks, settings dialogs, graph creation, onboarding, and mobile inputs.
    • Kept the original keyboard behavior once composition is complete.
  • Tests
    • Added automated coverage for the IME/composition key-handling behavior.

@coderabbitai

coderabbitai Bot commented Jul 27, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

IME composition detection is centralized in a shared helper and applied across desktop/mobile inputs, task controls, find handling, resizing, and application shortcuts to prevent keyboard actions from firing during composition.

Changes

IME keyboard handling

Layer / File(s) Summary
Composition detection helper
apps/desktop/src/lib/keyboard.ts, apps/desktop/src/lib/keyboard.test.tsx
Adds and tests isKeyboardEventComposing, including WebKit composition-tail timing behavior.
Desktop input and control guards
apps/desktop/src/components/{chat,command-palette,context-sidebar}/*, apps/desktop/src/components/{graph-chooser,note-find-bar}.tsx, apps/desktop/src/components/settings/*, apps/desktop/src/components/tasks/task-row.tsx, apps/desktop/src/hooks/use-sidebar-resize.ts
Guards existing Enter, Escape, selection, submission, and resize handlers during IME composition.
Mobile input and task guards
apps/desktop/src/mobile/*
Prevents composition events from triggering repository, graph, onboarding, search, and task actions.
Find and application shortcut guards
apps/desktop/src/providers/note-find-provider.tsx, apps/desktop/src/lib/tasks/use-task-keyboard.ts, apps/desktop/src/routing/app-shortcuts.ts
Skips find-session, task shortcut, history, and application shortcut processing while composition is active.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

Suggested labels: codex

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 65.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: blocking Enter-based sending during IME composition.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ocavue/ime-chat

Comment @coderabbitai help to get the list of available commands.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR addresses an IME/WebKit composition edge case where Enter (and other key handlers) can fire while the user is still composing text, by centralizing composition detection in a shared helper and using it to early-return in keydown handlers across desktop and mobile UI.

Changes:

  • Add isKeyboardEventComposing helper to consistently detect IME composition (including a WebKit workaround).
  • Guard global shortcuts and multiple component keydown handlers to avoid acting on keys during composition.
  • Replace direct event.isComposing checks with the shared helper in affected flows (find, chat, command palette, inputs, etc.).

Reviewed changes

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

Show a summary per file
File Description
apps/desktop/src/routing/app-shortcuts.ts Skip app-level shortcut handling while IME composition is active.
apps/desktop/src/providers/note-find-provider.tsx Prevent find-related key handlers (Escape/mod+F) from firing during composition.
apps/desktop/src/mobile/task-row.tsx Prevent Enter/Space “edit” activation while composing text.
apps/desktop/src/mobile/search-input.tsx Prevent Enter-to-blur behavior during composition.
apps/desktop/src/mobile/onboarding-icloud-section.tsx Prevent Enter-to-create actions while composing in the input.
apps/desktop/src/mobile/new-graph-drawer.tsx Prevent Enter-to-create actions while composing in the input.
apps/desktop/src/mobile/connect-github-drawer.tsx Prevent Enter-to-continue actions while composing in wizard inputs.
apps/desktop/src/lib/keyboard.ts Introduce shared IME composition detection helper with WebKit workaround.
apps/desktop/src/hooks/use-sidebar-resize.ts Prevent keyboard-resize handling while IME composition is active.
apps/desktop/src/components/tasks/task-row.tsx Prevent Enter/Space task selection behavior from firing during composition.
apps/desktop/src/components/settings/model-combobox.tsx Prevent Enter-to-commit behavior while composing.
apps/desktop/src/components/settings/destructive-section.tsx Prevent Enter-to-confirm destructive action while composing.
apps/desktop/src/components/note-find-bar.tsx Prevent Escape/mod key handling during composition in the find UI.
apps/desktop/src/components/graph-chooser.tsx Prevent Enter-to-create behavior while composing in graph name inputs.
apps/desktop/src/components/context-sidebar/attendee-combobox.tsx Prevent Enter behavior during composition in attendee combobox.
apps/desktop/src/components/command-palette/command-palette.tsx Prevent Enter/pointer-intent handling during composition in cmdk.
apps/desktop/src/components/chat/chat-input.tsx Prevent Enter-to-send while composing (core motivation of the PR).

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

Comment thread apps/desktop/src/lib/keyboard.ts Outdated
Comment on lines +1 to +21
let isComposing = false
let timer : ReturnType<typeof setTimeout> | undefined

// Workaround for a bug in WebKit where the isComposing property is reset to false event when the IME is still composing.
// https://bugs.webkit.org/show_bug.cgi?id=311717
export function isKeyboardEventComposing(event: KeyboardEvent): boolean {
if (event.isComposing) {
if (timer) {
clearTimeout(timer)
timer = undefined
}
isComposing = true
} else if (isComposing && !timer) {
timer = setTimeout(() => {
isComposing = false
timer = undefined
}, 40)
}

return isComposing
}

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/desktop/src/components/context-sidebar/attendee-combobox.tsx`:
- Around line 154-156: Add stopPropagation() to the isKeyboardEventComposing
guard in the attendee combobox keydown handler before returning, while
preserving the existing default behavior by not preventing the event.

In `@apps/desktop/src/routing/app-shortcuts.ts`:
- Around line 318-320: Update onHistoryKeyDownCapture to call
isKeyboardEventComposing(event) at the start and return immediately when
composition is active, before any triggerCommand() logic. Keep the existing
bubbling onKeyDown guard unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 3a2c8648-559f-4941-bf14-b8eb996831f0

📥 Commits

Reviewing files that changed from the base of the PR and between a92725f and 7dad0df.

📒 Files selected for processing (17)
  • apps/desktop/src/components/chat/chat-input.tsx
  • apps/desktop/src/components/command-palette/command-palette.tsx
  • apps/desktop/src/components/context-sidebar/attendee-combobox.tsx
  • apps/desktop/src/components/graph-chooser.tsx
  • apps/desktop/src/components/note-find-bar.tsx
  • apps/desktop/src/components/settings/destructive-section.tsx
  • apps/desktop/src/components/settings/model-combobox.tsx
  • apps/desktop/src/components/tasks/task-row.tsx
  • apps/desktop/src/hooks/use-sidebar-resize.ts
  • apps/desktop/src/lib/keyboard.ts
  • apps/desktop/src/mobile/connect-github-drawer.tsx
  • apps/desktop/src/mobile/new-graph-drawer.tsx
  • apps/desktop/src/mobile/onboarding-icloud-section.tsx
  • apps/desktop/src/mobile/search-input.tsx
  • apps/desktop/src/mobile/task-row.tsx
  • apps/desktop/src/providers/note-find-provider.tsx
  • apps/desktop/src/routing/app-shortcuts.ts

Comment on lines +154 to +156
if (isKeyboardEventComposing(keyEvent.nativeEvent)) {
return
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the target file around the reported lines.
FILE="apps/desktop/src/components/context-sidebar/attendee-combobox.tsx"
wc -l "$FILE"
sed -n '120,190p' "$FILE"

# Find composition and cmdk-related handling in the same file.
rg -n "isKeyboardEventComposing|stopPropagation|cmdk|Enter|composition" "$FILE"

# Locate any local references to cmdk or the combobox component.
rg -n "attendee-combobox|Command|cmdk" apps/desktop/src -g '!**/dist/**' -g '!**/build/**'

Repository: team-reflect/reflect-open

Length of output: 37550


🏁 Script executed:

#!/bin/bash
set -euo pipefail

FILE="apps/desktop/src/components/context-sidebar/attendee-combobox.tsx"
TEST="apps/desktop/src/components/context-sidebar/attendee-combobox.test.tsx"

# Show the component's root structure and event wiring.
sed -n '180,260p' "$FILE"

# Show the test coverage around keyboard/composition behavior.
wc -l "$TEST"
sed -n '1,220p' "$TEST"

# Look for any explicit IME/composition tests across the desktop app.
rg -n "composition|isKeyboardEventComposing|Composing|IME" apps/desktop/src -g '!**/dist/**' -g '!**/build/**'

Repository: team-reflect/reflect-open

Length of output: 17268


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Show the composition helper and nearby explanation.
sed -n '1,120p' apps/desktop/src/lib/keyboard.ts

# Inspect sibling handlers that use the same composition guard.
sed -n '140,190p' apps/desktop/src/components/command-palette/command-palette.tsx
sed -n '30,70p' apps/desktop/src/components/note-find-bar.tsx
sed -n '90,130p' apps/desktop/src/components/tasks/task-row.tsx
sed -n '75,110p' apps/desktop/src/components/chat/chat-input.tsx

Repository: team-reflect/reflect-open

Length of output: 6686


Stop propagation during composition.
This early return lets the IME keydown bubble to cmdk’s root Enter handler during the WebKit composition window, so an IME commit can still select an attendee. Call stopPropagation() before returning and leave default behavior alone.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/desktop/src/components/context-sidebar/attendee-combobox.tsx` around
lines 154 - 156, Add stopPropagation() to the isKeyboardEventComposing guard in
the attendee combobox keydown handler before returning, while preserving the
existing default behavior by not preventing the event.

Comment thread apps/desktop/src/routing/app-shortcuts.ts
@ocavue
ocavue merged commit 0e4658b into master Jul 27, 2026
14 of 15 checks passed
@ocavue
ocavue deleted the ocavue/ime-chat branch July 27, 2026 06:12
This was referenced Jul 26, 2026
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