Menu ▾ ▴

#42 Add Caprine-style keyboard shortcuts (conversation nav, search, composer)

closed
nobody
None
2026-07-03
2026-07-03
Anonymous
No

Originally created by: kristofferR

Implements the shortcut set from [#18] and [#30] (Ref [#18], Ref [#30]).

New shortcuts

Action Key
Previous / next conversation Cmd/Ctrl+[ / ], and Ctrl+Tab / Ctrl+Shift+Tab
New conversation Cmd/Ctrl+Shift+N (File menu; Cmd/Ctrl+N stays New Window)
Search conversations Cmd/Ctrl+K
Search in conversation Cmd/Ctrl+F
Focus message input Cmd/Ctrl+L
Emoji / GIF / attach files Cmd/Ctrl+E / G / T

The browser-style Cmd/Ctrl+[/] history bindings are removed per [#18] and the keys reused for conversation navigation.

Decisions where the two issues conflicted

  • Cmd+N: stays New Window (maintainer call, matching [#18]'s recommendation). New Conversation is a File-menu item on Cmd/Ctrl+Shift+N, and Hide Names & Avatars (the previous Shift+N holder) moved to Cmd/Ctrl+Shift+H. A page-side ⌘N binding alone was never an option — the native File menu claims the key before the page sees it.
  • Focus input key: [#18] suggested ⌘I, [#30] says ⌘L — used ⌘L (⌘⇧I is already Toggle Conversation Information).
  • Next/prev conversation is in (from [#18]) even though [#30] listed it as out of scope; mute/archive/delete and sticker stay out per [#30].

Implementation

  • All actions are page-side in inject/messenger.js, per [#30]'s mechanism table: plain DOM ops where possible (composer focus, chat-list search focus, the /messages/new/ compose link), clicking Messenger's own buttons otherwise — no React-fiber reaching.
  • Cmd/Ctrl+F is the two-step case: the Search control only exists inside the conversation-info sidebar (aria-label is just "Search", no complementary landmark). If it's not present the handler opens the sidebar via the existing __carrierToggleInfo and clicks Search once React renders it (50 ms poll, 2 s cap).
  • Handlers bail quietly when a control is missing (login page, FB markup churn).
  • The dev-only mcp-bridge.js gains a sanitized __carrier_mcp_shortcut_probe__ (roles/labels/rects of shortcut targets; chat rows and articles excluded, digits masked) and a CSP-safe __carrier_mcp_call__:<name> invoker restricted to the __carrierShortcuts registry. Release builds compile none of this.

Verification

Every selector was verified against the live Messenger DOM in an mcp debug build, and each helper was invoked end-to-end: next/prev switch threads (URL confirmed), ⌘F opens the sidebar → Search input focused (screenshot-verified), ⌘K/⌘L focus their inputs, emoji/GIF pickers open and toggle closed, New Conversation SPA-navigates to the compose view with the To: field active. attachFiles was validated by label match only (clicking it opens a native file dialog).

Gates: cargo fmt / clippy -D warnings / cargo test --lib (44 passed) / node --check on both injected files.

https://claude.ai/code/session_01BuZke2qu27Gw363mGTm7gn

Summary by CodeRabbit

  • New Features
  • Added keyboard shortcuts to move between conversations, open a new conversation, and quickly access chat tools like search, composer focus, emoji/GIF pickers, and file attachment.

  • Bug Fixes

  • Updated shortcut behavior so conversation switching works consistently with tab and bracket keys.
  • Corrected the shortcut for hiding names and avatars to avoid conflicts.

  • Documentation

  • Refreshed the keyboard shortcuts list to match the latest app behavior.

Related

Tickets: #18
Tickets: #30
Tickets: #357
Tickets: #53

Discussion

  • Anonymous

    Anonymous - 2026-07-03

    Originally posted by: kristofferR

    @coderabbitai review

     
  • Anonymous

    Anonymous - 2026-07-03

    Originally posted by: coderabbitai[bot]

    ✅ Action performed Review finished. > Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.
     
  • Anonymous

    Anonymous - 2026-07-03

    Originally posted by: coderabbitai[bot]

    Review Change Stack

    📝 Walkthrough ## Walkthrough This PR adds conversation navigation shortcuts (Ctrl+Tab/Ctrl+Shift+Tab, Cmd/Ctrl+[/]) and Messenger action shortcuts (search, composer focus, emoji/GIF pickers, attach, new conversation) via a new window.__carrierShortcuts registry, wires a native "New Conversation" menu item, changes the Hide Names & Avatars accelerator to Shift+H, adds an MCP bridge probe/invocation path, and updates docs. ### Changes **Messenger shortcuts and menu integration** |Layer / File(s)|Summary| |---|---| |**Conversation navigation and shortcut helpers**
    `src-tauri/inject/messenger.js`|Adds stepConversation navigation and focus/search/composer/picker/attach/new-conversation helpers, exposed via window.__carrierShortcuts.| |**Shortcut keymap wiring and hotkey comment fix**
    `src-tauri/inject/messenger.js`|Replaces history-based [/] navigation with stepConversation, adds Ctrl+Tab/Ctrl+Shift+Tab cycling and new action bindings, and fixes the Hide Names & Avatars comment.| |**Native menu: New Conversation item and accelerator change**
    `src-tauri/src/lib.rs`|Adds a "New Conversation" menu item (CmdOrCtrl+Shift+N), changes Hide Names & Avatars accelerator to CmdOrCtrl+Shift+H, and handles the new_conversation event to invoke the JS shortcut hook.| |**MCP bridge probe and helper invocation**
    `src-tauri/inject/mcp-bridge.js`|Adds shortcutProbe() and execute-js handling for shortcut probe and whitelisted __carrierShortcuts calls, bypassing arbitrary Function evaluation for those cases.| |**Documentation and settings UI updates**
    `README.md`, `dist/settings.html`|Updates keyboard shortcuts list and settings hint text to reflect new navigation shortcuts and the Shift+H accelerator.| **Estimated code review effort:** 3 (Moderate) | ~30 minutes ### Sequence Diagram(s) :::mermaid sequenceDiagram participant User participant NativeMenu as Native Menu (lib.rs) participant Webview participant Messenger as messenger.js participant DOM as Messenger DOM User->>NativeMenu: Trigger "New Conversation" (Shift+N) NativeMenu->>Webview: eval JS Webview->>Messenger: window.__carrierShortcuts.newConversation() Messenger->>DOM: Navigate via SPA route or fallback DOM-->>Messenger: New conversation opened User->>Messenger: Ctrl+Tab / Cmd+] Messenger->>Messenger: stepConversation(direction) Messenger->>DOM: Locate current thread + visible chat rows DOM-->>Messenger: Next/prev thread element Messenger->>DOM: Click/navigate to target conversation :::mermaid sequenceDiagram participant MCPClient participant Bridge as mcp-bridge.js participant Window as window.__carrierShortcuts participant DOM as Messenger DOM MCPClient->>Bridge: execute-js "__carrier_mcp_call__:focusComposer" Bridge->>Window: lookup helper by name Window->>DOM: focusComposer() DOM-->>Window: composer focused Window-->>Bridge: {called, returned} Bridge-->>MCPClient: result MCPClient->>Bridge: execute-js "__carrier_mcp_shortcut_probe__" Bridge->>DOM: scan controls, masks data DOM-->>Bridge: sanitized control descriptors Bridge-->>MCPClient: shortcutProbe() result **Possibly related issues** - [kristofferR/Carrier#18](https://github.com/kristofferR/Carrier/issues/18): Implements the described removal of history-based navigation in favor of next/prev conversation and related Messenger shortcuts. - [kristofferR/Carrier#30](https://github.com/kristofferR/Carrier/issues/30): Implements the described Messenger keyboard-shortcut additions including new conversation, search, emoji/GIF, and attach actions. **Possibly related PRs** - [[kristofferR/Carrier#2](https://github.com/kristofferR/Carrier/issues/2)](https://github.com/kristofferR/Carrier/pull/2): Both PRs modify conversation navigation/shortcut handling in `src-tauri/inject/messenger.js`. - [[kristofferR/Carrier#11](https://github.com/kristofferR/Carrier/issues/11)](https://github.com/kristofferR/Carrier/pull/11): Both PRs extend the `execute-js` responder in `src-tauri/inject/mcp-bridge.js` with new probe/call handling.
    🚥 Pre-merge checks | ✅ 5
    ✅ Passed checks (5 passed) | Check name | Status | Explanation | | :------------------------: | :------- | :----------------------------------------------------------------------------------------------------------------------------------------------------- | | Description Check | ✅ Passed | Check skipped - CodeRabbit’s high-level summary is enabled. | | Title check | ✅ Passed | The title is clear and matches the main change set: adding Caprine-style keyboard shortcuts for conversation navigation, search, and composer actions. | | Docstring Coverage | ✅ Passed | No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. | | 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. |
    ✨ 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 `feature/caprine-shortcuts`

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

     
  • Anonymous

    Anonymous - 2026-07-03

    Originally posted by: kristofferR

    @coderabbitai review

     
  • Anonymous

    Anonymous - 2026-07-03

    Originally posted by: coderabbitai[bot]

    ✅ Action performed Review finished. > Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.
     
  • Anonymous

    Anonymous - 2026-07-03

    Originally posted by: kristofferR

    @coderabbitai review

     
  • Anonymous

    Anonymous - 2026-07-03

    Originally posted by: coderabbitai[bot]

    ✅ Action performed Review finished. > Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.
     
  • Anonymous

    Anonymous - 2026-07-03

    Ticket changed by: kristofferR

    • status: open --> closed
     

Log in to post a comment.