You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Hardcoded keybinds in onKeyDown bypass window.registerShortcut #10
screen.js's onKeyDown handler (around line 2122) hardcodes keyboard shortcuts (Space, Delete, Backspace, Escape, G, F, K) directly as a document-level key listener, rather than registering them through the core-provided window.registerShortcut() API.
Core's shortcut system (documented in slopsmith's CLAUDE.md under "Keyboard Shortcuts") exists specifically so that:
All shortcuts appear in the global ? help panel
Shortcuts can be scoped (plugin-{id}) and conditionally active
Users have one place to discover every available keybind across the whole app
Because the editor's shortcuts bypass this system entirely, they're invisible to users unless they read the source — despite the Arrangement Editor being arguably the most shortcut-dense screen in the entire plugin ecosystem.
Ask
Migrate the hardcoded key handling in onKeyDown to window.registerShortcut() calls, scoped to plugin-editor (or player/global as appropriate per key), so these shortcuts surface in the ? help panel like every other plugin's shortcuts are expected to.
Looked at doing this migration. Flagging a scoping concern before anyone sinks time into it: onKeyDown in src/input.js (~1600-2900) isn't a flat list of independent key bindings — it's a stateful dispatcher with sequenced, mutually-exclusive gates (tab-preview modal, user-guide modal, context-menu Escape ownership, tool-palette open state, tempo-map/drum-edit/parts-view mode checks, an EOF-profile-aware key map, a Select-All policy that has to run before the recording/parts-view read-only guards, etc.), where order between gates is load-bearing, not just per-key logic.
window.registerShortcut() is built for the "each shortcut is its own independent handler + optional condition() guard" shape (see core's Keyboard Shortcuts docs) — it has no primitive for "this whole block of keys is owned by whichever modal/mode is currently active, checked in a specific priority order." Force-fitting that here would mean either (a) one registerShortcut() call per key with a condition() re-deriving the same modal/mode state onKeyDown already computes once up front — real duplication risk — or (b) keeping the dispatcher and registering a single catch-all shortcut that just calls into it, which satisfies the letter of "use registerShortcut" but not the actual goal (each shortcut discoverable individually in the ? help panel).
Given the size (a ~3000-line file, arguably the most shortcut-dense screen in the plugin ecosystem, as the issue notes) and how much of the correctness here rides on gate ordering, I don't think this is a safe "Effort: Low" change to make speculatively without a design decision on which of those two shapes (or a third: extend registerShortcut with priority-group/modal-ownership semantics core-side) is wanted. Left it alone rather than risk a regression in the editor's most complex screen. Happy to take a swing at it if someone confirms the intended shape.
Activity
cchacs commentedon Sep 10, 2026
Looked at doing this migration. Flagging a scoping concern before anyone sinks time into it:
onKeyDowninsrc/input.js(~1600-2900) isn't a flat list of independent key bindings — it's a stateful dispatcher with sequenced, mutually-exclusive gates (tab-preview modal, user-guide modal, context-menu Escape ownership, tool-palette open state, tempo-map/drum-edit/parts-view mode checks, an EOF-profile-aware key map, a Select-All policy that has to run before the recording/parts-view read-only guards, etc.), where order between gates is load-bearing, not just per-key logic.window.registerShortcut()is built for the "each shortcut is its own independent handler + optionalcondition()guard" shape (see core's Keyboard Shortcuts docs) — it has no primitive for "this whole block of keys is owned by whichever modal/mode is currently active, checked in a specific priority order." Force-fitting that here would mean either (a) oneregisterShortcut()call per key with acondition()re-deriving the same modal/mode state onKeyDown already computes once up front — real duplication risk — or (b) keeping the dispatcher and registering a single catch-all shortcut that just calls into it, which satisfies the letter of "use registerShortcut" but not the actual goal (each shortcut discoverable individually in the?help panel).Given the size (a ~3000-line file, arguably the most shortcut-dense screen in the plugin ecosystem, as the issue notes) and how much of the correctness here rides on gate ordering, I don't think this is a safe "Effort: Low" change to make speculatively without a design decision on which of those two shapes (or a third: extend
registerShortcutwith priority-group/modal-ownership semantics core-side) is wanted. Left it alone rather than risk a regression in the editor's most complex screen. Happy to take a swing at it if someone confirms the intended shape._Generated by Claude Code
Generated by Claude Code
cchacs commentedon Oct 2, 2026
Split into sub-issues (proposed; adjust freely). The "Keybinds N/4" titles map to issue numbers as shown:
?help panelGenerated by Claude Code
feat(editor): per-track offset nudge, numeric prompt + coalescing undo (