Skip to content

feat: add tauri-plugin-shortcut with centralized shortcut registry#4056

Open
devin-ai-integration[bot] wants to merge 8 commits intomainfrom
devin/1771395727-shortcut-registry-plugin
Open

feat: add tauri-plugin-shortcut with centralized shortcut registry#4056
devin-ai-integration[bot] wants to merge 8 commits intomainfrom
devin/1771395727-shortcut-registry-plugin

Conversation

@devin-ai-integration
Copy link
Contributor

@devin-ai-integration devin-ai-integration bot commented Feb 18, 2026

feat: add tauri-plugin-shortcut with centralized shortcut registry

Summary

Creates a new tauri-plugin-shortcut Rust plugin that serves as the single source of truth for all keyboard shortcuts in the app. The Rust side declares all shortcuts; the TS side reads from the registry and registers handlers as needed.

Rust side (plugins/shortcut/):

  • ShortcutId enum with #[serde(rename_all = "snake_case")] — all 35 shortcut identifiers as type-safe enum variants, exported via specta as a TS string literal union
  • ShortcutDef struct with typed id: ShortcutId, keys, category, description, scope (Global vs Scoped)
  • Static registry of all shortcuts in registry.rs
  • Single get_all_shortcuts command exposed via specta

TS side:

  • ShortcutId type generated by specta — compile-time enforcement that all shortcut references are valid
  • useShortcutRegistry hook — shared React Query fetch with keysMap for O(1) lookup by ShortcutId
  • useShortcutKeys(id: ShortcutId) — convenience hook to read a single key binding from the registry
  • useScopedShortcut(id, handler, options?, deps?) — wrapper hook that combines useShortcutKeys + useHotkeys into a single call, automatically guarding with enabled: !!keys
  • useGlobalShortcuts hook reads all key bindings from the registry via k(id: ShortcutId) helper (no hardcoded key strings)
  • All scoped shortcuts (toggle_sidebar, focus_search, open_note_dialog, switch_to_enhanced/raw/transcript, prev/next_panel_tab, transcript_search, play_pause_audio, undo_delete) use useScopedShortcut — no more manual useShortcutKeys + useHotkeys two-step pattern
  • Scoped shortcuts remain in their original components — they are NOT moved to global scope
  • The old useTabsShortcuts function (~225 lines in body/index.tsx) is removed; its logic now lives in useGlobalShortcuts

CI:

  • Added tauri-plugin-shortcut to the Windows CI exclude list in desktop_ci.yaml

Review & Testing Checklist for Human

  • Verify shortcuts work after app launch — all shortcuts now depend on async getAllShortcuts() resolving via React Query. Until the query completes, shortcuts are disabled. Open the app and confirm shortcuts activate within ~1s. This is a behavioral change from the old synchronous registration.
  • Test ALL global shortcutsmod+n, mod+t, mod+w, mod+1-9, mod+alt+left/right, mod+shift+t/c/o/comma/l/f/n, mod+j, mod+,
  • Test scoped shortcuts in their correct contextmod+\ (sidebar), mod+k (search), mod+o (empty tab), mod+f (transcript), alt+s/m/t (editor tabs), ctrl+alt+left/right (panel nav in note-input), space (audio playback), mod+z (undo delete)
  • Verify mod+w close-while-listening behavior — complex branching (listening → confirmation, pinned → unpin, chat_support → CLOSE event, else → close). Logic was moved from useTabsShortcuts in body/index.tsx to useGlobalShortcuts in a different component context.
  • Verify mod+, splitKey special case — this shortcut uses splitKey: "|" option in useGlobalShortcuts. Confirm it still works through the registry.
  • Verify useScopedShortcut wrapper works correctly — especially for shortcuts with custom options like enableOnFormTags: false (play_pause_audio) or complex handlers

Recommended test plan: Open the app, create tabs of different types (empty, note, calendar, session with active listening), and systematically test each shortcut. Pay special attention to shortcuts with complex logic (mod+w) and scoped shortcuts that should only work in specific contexts.

Notes

  • The Rust registry is now the authoritative source for all key bindings. TS reads from it dynamically rather than hardcoding strings.
  • Type safety: The ShortcutId enum provides compile-time validation that all shortcut references are valid. Typos in shortcut IDs are now caught at build time rather than silently failing at runtime.
  • useScopedShortcut wrapper: Simplifies scoped shortcut registration by combining useShortcutKeys + useHotkeys into one call. Automatically sets enabled: !!keys to prevent invalid handlers.
  • Startup race condition: Shortcuts are disabled (enabled: false) until the registry query completes. This prevents useHotkeys("") from registering invalid handlers, but means there's a brief window (~1s) on app launch where no shortcuts work.
  • Scoped shortcuts remain in their original components for proper context scoping, but now read their key bindings from the Rust registry.
  • The old useTabsShortcuts function was removed from body/index.tsx; its logic now lives in useGlobalShortcuts in _layout.tsx.

Link to Devin run: https://app.devin.ai/sessions/b4eb1d2ab0224f56b5f02c120d5531f4
Requested by: @yujonglee

- Create plugins/shortcut/ with types, registry, and get_all_shortcuts command
- Wire plugin into app (Cargo.toml, lib.rs, capabilities, package.json)
- Create useGlobalShortcuts hook centralizing ~13 global shortcuts
- Migrate shortcuts from body/index.tsx, chat.ts, settings.ts to hook
- Mount useGlobalShortcuts in main layout

Co-Authored-By: yujonglee <yujonglee.dev@gmail.com>
@devin-ai-integration
Copy link
Contributor Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR that start with 'DevinAI' or '@devin'.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

@netlify
Copy link

netlify bot commented Feb 18, 2026

Deploy Preview for hyprnote canceled.

Name Link
🔨 Latest commit 7ab7d13
🔍 Latest deploy log https://app.netlify.com/projects/hyprnote/deploys/6995d8d461da000008f5f425

@netlify
Copy link

netlify bot commented Feb 18, 2026

Deploy Preview for hyprnote-storybook canceled.

Name Link
🔨 Latest commit 7ab7d13
🔍 Latest deploy log https://app.netlify.com/projects/hyprnote-storybook/deploys/6995d8d4cdcce60007eb140a

devin-ai-integration bot and others added 7 commits February 18, 2026 06:42
Co-Authored-By: yujonglee <yujonglee.dev@gmail.com>
Co-Authored-By: yujonglee <yujonglee.dev@gmail.com>
… in TS

- Create useShortcutRegistry hook with shared query and keysMap lookup
- Refactor useGlobalShortcuts to use registry keys via k(id) helper
- Update all scoped shortcuts (leftsidebar, search, empty, note-input,
  settings, ai, transcript search, audio playback, undo-delete) to
  read keys from the Rust registry
- Add enabled guards so shortcuts only activate after registry loads

Co-Authored-By: yujonglee <yujonglee.dev@gmail.com>
Co-Authored-By: yujonglee <yujonglee.dev@gmail.com>
Co-Authored-By: yujonglee <yujonglee.dev@gmail.com>
Co-Authored-By: yujonglee <yujonglee.dev@gmail.com>
Co-Authored-By: yujonglee <yujonglee.dev@gmail.com>
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.

1 participant

Comments