Skip to content

fix(desktop): prevent keyboard shortcuts from leaking characters into chat input#3520

Merged
Kitenite merged 2 commits into
superset-sh:mainfrom
joshuavial:kind-tomato
Apr 18, 2026
Merged

fix(desktop): prevent keyboard shortcuts from leaking characters into chat input#3520
Kitenite merged 2 commits into
superset-sh:mainfrom
joshuavial:kind-tomato

Conversation

@joshuavial
Copy link
Copy Markdown
Contributor

@joshuavial joshuavial commented Apr 17, 2026

Summary

  • Keyboard shortcuts (e.g. Option+J/K for workspace navigation) were inserting the resulting special character into the chat input of the newly focused workspace
  • Root cause: useHotkey called the handler but never called e.preventDefault(), so the browser still processed the key event and typed the character
  • Fix: call e.preventDefault() in the central useHotkey wrapper before invoking the callback, covering all registered shortcuts

Test plan

  • Use Option+J / Option+K (or Cmd+Alt+Up/Down) to switch between workspaces — no stray characters should appear in the chat input
  • Verify other hotkeys (new workspace, toggle sidebar, close workspace, jump-to shortcuts) still work correctly
  • Verify chat input typing is unaffected

Summary by cubic

Prevents hotkey combos from inserting characters into inputs when switching workspaces. Hotkeys now block default key actions so the browser doesn’t type stray characters.

  • Bug Fixes
    • In the central useHotkey hook, call e.preventDefault() before the callback; this is default-on and can be disabled via options.preventDefault = false.

Written for commit 1b95c65. Summary will update on new commits.

Summary by CodeRabbit

  • Bug Fixes
    • Hotkeys in the desktop app now suppress default browser actions by default, preventing unintended behaviors when shortcuts are triggered.
    • Hotkey callbacks continue to receive the original keyboard event, and there is an option to allow default browser behavior when needed.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 17, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 0829ed27-b093-4063-a23f-9c364aa02245

📥 Commits

Reviewing files that changed from the base of the PR and between c257689 and 1b95c65.

📒 Files selected for processing (1)
  • apps/desktop/src/renderer/hotkeys/hooks/useHotkey/useHotkey.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/desktop/src/renderer/hotkeys/hooks/useHotkey/useHotkey.ts

📝 Walkthrough

Walkthrough

The useHotkey hook's internal handler now calls event.preventDefault() before invoking the callback when a hotkey triggers, unless options?.preventDefault is explicitly set to false. The hook signature is unchanged.

Changes

Cohort / File(s) Summary
Hotkey Event Handling
apps/desktop/src/renderer/hotkeys/hooks/useHotkey/useHotkey.ts
Handler updated to call event.preventDefault() (unless overridden via options) prior to executing the latest callback; callback still receives the original KeyboardEvent.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐰 I hopped a key and heard a click,
The browser paused—I'd stopped its trick,
A gentle nudge, a quiet art,
preventDefault keeps actions apart,
Now my shortcut sings from the heart.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main bug being fixed: preventing keyboard shortcuts from inserting characters into the chat input.
Description check ✅ Passed The description includes a clear summary of the issue, root cause, and fix, with a comprehensive test plan. It follows the template structure with relevant sections completed.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented Apr 17, 2026

Greptile Summary

This PR fixes a character-leakage bug in the desktop app where keyboard shortcut combos that produce special characters (e.g. Option+J → on macOS) were inserting those characters into the chat input of the newly focused workspace. The fix adds a single unconditional e.preventDefault() call in the central useHotkey wrapper before invoking the user-supplied callback, covering all registered shortcuts in one place.

Key changes:

  • useHotkey.ts: e.preventDefault() is now called on every hotkey event before the callback fires, preventing the browser from processing the key character into any focused input element.
  • This interacts correctly with the existing enableOnFormTags: true, enableOnContentEditable: true defaults — the handler now fires in form/contentEditable contexts AND blocks the character insertion.
  • Callers like useTerminalHotkeys.ts that already passed { preventDefault: true } in options will now have that option be redundant (double-call is harmless).
  • No callers pass { preventDefault: false }, so no existing behaviour is broken.

Confidence Score: 5/5

Safe to merge — minimal, targeted one-line fix with no regressions.

The change is a single e.preventDefault() insertion at the correct central location. All registered hotkeys are application-level actions that should prevent browser defaults; no callers pass { preventDefault: false } that could be undermined. The existing enableOnFormTags: true, enableOnContentEditable: true defaults already ensured handlers fired in input contexts — the missing e.preventDefault() was the only gap. The fix is logically complete and doesn't affect normal typing (non-matching keys never trigger the handler).

No files require special attention.

Important Files Changed

Filename Overview
apps/desktop/src/renderer/hotkeys/hooks/useHotkey/useHotkey.ts Added e.preventDefault() before the user callback in the central hotkey wrapper — correct, minimal fix that prevents character leakage for all registered shortcuts.

Sequence Diagram

sequenceDiagram
    participant User
    participant Browser as Browser/Electron
    participant useHotkeys as react-hotkeys-hook
    participant useHotkey as useHotkey wrapper
    participant Callback as Hotkey Callback
    participant ChatInput as Chat Input (form/contentEditable)

    User->>Browser: Press Option+J (macOS)
    Browser->>useHotkeys: keydown event (enableOnFormTags: true)
    useHotkeys->>useHotkey: matched hotkey handler(e)
    useHotkey->>Browser: e.preventDefault()
    Note over Browser,ChatInput: Character insertion blocked
    useHotkey->>Callback: callbackRef.current(e)
    Callback->>Browser: Switch workspace / perform action
    Note over ChatInput: No stray character inserted
Loading

Reviews (1): Last reviewed commit: "fix(desktop): prevent default on hotkeys..." | Re-trigger Greptile

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
apps/desktop/src/renderer/hotkeys/hooks/useHotkey/useHotkey.ts (1)

19-22: Unconditional preventDefault() — confirm this is the intended global policy.

Calling e.preventDefault() on every hotkey match fixes the character-leak bug, but changes behavior across all useHotkey call sites. Callers in TasksTopBar.tsx, useChatMessageSearch.ts, TerminalPane.tsx, and ChatShortcuts.tsx that explicitly pass { preventDefault: true } now have redundant options—the field is effectively ignored since you call it unconditionally.

Consider either:

  • Removing the redundant preventDefault: true flags at call sites, or
  • Making preventDefault opt-out-able with options?.preventDefault !== false to preserve flexibility for future hotkeys that may need to allow default behavior (e.g., bare keys like Enter, Tab, or /).

Since all registered hotkeys currently use modifier combinations, there's no immediate regression, but this unconditional approach locks in the policy globally.

♻️ Optional: make preventDefault opt-out-able
-		(e, _h) => {
-			e.preventDefault();
-			callbackRef.current(e);
-		},
-		{ enableOnFormTags: true, enableOnContentEditable: true, ...options },
+		(e, _h) => {
+			if (options?.preventDefault !== false) {
+				e.preventDefault();
+			}
+			callbackRef.current(e);
+		},
+		{
+			enableOnFormTags: true,
+			enableOnContentEditable: true,
+			...options,
+		},
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/desktop/src/renderer/hotkeys/hooks/useHotkey/useHotkey.ts` around lines
19 - 22, The handler in useHotkey currently calls e.preventDefault()
unconditionally which ignores callers' options; update the inline handler (the
(e, _h) => { ... } in useHotkey.ts) to only call e.preventDefault() when
options?.preventDefault !== false (i.e., default to preventing but allow
opt-out), so callers that passed preventDefault: true remain compatible and
callers can opt out by passing preventDefault: false; ensure
callbackRef.current(e) is still invoked and adjust any relevant TypeScript types
for the options parameter if needed.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@apps/desktop/src/renderer/hotkeys/hooks/useHotkey/useHotkey.ts`:
- Around line 19-22: The handler in useHotkey currently calls e.preventDefault()
unconditionally which ignores callers' options; update the inline handler (the
(e, _h) => { ... } in useHotkey.ts) to only call e.preventDefault() when
options?.preventDefault !== false (i.e., default to preventing but allow
opt-out), so callers that passed preventDefault: true remain compatible and
callers can opt out by passing preventDefault: false; ensure
callbackRef.current(e) is still invoked and adjust any relevant TypeScript types
for the options parameter if needed.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 5e1b8385-4603-4c62-812c-d5b33c8dc0e8

📥 Commits

Reviewing files that changed from the base of the PR and between 4a1f41a and c257689.

📒 Files selected for processing (1)
  • apps/desktop/src/renderer/hotkeys/hooks/useHotkey/useHotkey.ts

Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

No issues found across 1 file

@Kitenite Kitenite merged commit 1bf690b into superset-sh:main Apr 18, 2026
7 checks passed
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