feat: add tauri-plugin-shortcut with centralized shortcut registry#4056
Open
devin-ai-integration[bot] wants to merge 8 commits intomainfrom
Open
feat: add tauri-plugin-shortcut with centralized shortcut registry#4056devin-ai-integration[bot] wants to merge 8 commits intomainfrom
devin-ai-integration[bot] wants to merge 8 commits intomainfrom
Conversation
- 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>
Contributor
Author
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
✅ Deploy Preview for hyprnote canceled.
|
✅ Deploy Preview for hyprnote-storybook canceled.
|
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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
feat: add tauri-plugin-shortcut with centralized shortcut registry
Summary
Creates a new
tauri-plugin-shortcutRust 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/):ShortcutIdenum with#[serde(rename_all = "snake_case")]— all 35 shortcut identifiers as type-safe enum variants, exported via specta as a TS string literal unionShortcutDefstruct with typedid: ShortcutId, keys, category, description, scope (Global vs Scoped)registry.rsget_all_shortcutscommand exposed via spectaTS side:
ShortcutIdtype generated by specta — compile-time enforcement that all shortcut references are validuseShortcutRegistryhook — shared React Query fetch withkeysMapfor O(1) lookup byShortcutIduseShortcutKeys(id: ShortcutId)— convenience hook to read a single key binding from the registryuseScopedShortcut(id, handler, options?, deps?)— wrapper hook that combinesuseShortcutKeys+useHotkeysinto a single call, automatically guarding withenabled: !!keysuseGlobalShortcutshook reads all key bindings from the registry viak(id: ShortcutId)helper (no hardcoded key strings)toggle_sidebar,focus_search,open_note_dialog,switch_to_enhanced/raw/transcript,prev/next_panel_tab,transcript_search,play_pause_audio,undo_delete) useuseScopedShortcut— no more manualuseShortcutKeys+useHotkeystwo-step patternuseTabsShortcutsfunction (~225 lines inbody/index.tsx) is removed; its logic now lives inuseGlobalShortcutsCI:
tauri-plugin-shortcutto the Windows CI exclude list indesktop_ci.yamlReview & Testing Checklist for Human
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.mod+n,mod+t,mod+w,mod+1-9,mod+alt+left/right,mod+shift+t/c/o/comma/l/f/n,mod+j,mod+,mod+\(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)mod+wclose-while-listening behavior — complex branching (listening → confirmation, pinned → unpin, chat_support → CLOSE event, else → close). Logic was moved fromuseTabsShortcutsinbody/index.tsxtouseGlobalShortcutsin a different component context.mod+,splitKey special case — this shortcut usessplitKey: "|"option inuseGlobalShortcuts. Confirm it still works through the registry.useScopedShortcutwrapper works correctly — especially for shortcuts with custom options likeenableOnFormTags: false(play_pause_audio) or complex handlersRecommended 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
ShortcutIdenum 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.useScopedShortcutwrapper: Simplifies scoped shortcut registration by combininguseShortcutKeys+useHotkeysinto one call. Automatically setsenabled: !!keysto prevent invalid handlers.enabled: false) until the registry query completes. This preventsuseHotkeys("")from registering invalid handlers, but means there's a brief window (~1s) on app launch where no shortcuts work.useTabsShortcutsfunction was removed frombody/index.tsx; its logic now lives inuseGlobalShortcutsin_layout.tsx.Link to Devin run: https://app.devin.ai/sessions/b4eb1d2ab0224f56b5f02c120d5531f4
Requested by: @yujonglee