Skip to content

Keybinds 2/4: migrate the editing keys (Delete, Backspace, G, F, K) to registerShortcut #38

Closed

Description

@cchacs

Part of #10. Depends on Keybinds 1/4.

Scope

  • Register Delete, Backspace, G, F and K through window.registerShortcut() with the scope and condition decided in 1/4 (expected: plugin-editor), so they appear in the global ? help panel.
  • Keep the existing typing-target guard (_editorIsTypingTarget) so the keys do not fire while a text field is focused.
  • Remove the corresponding branches from onKeyDown.
  • Clean up with window.unregisterShortcut(key, scope) using the same scope on teardown.

Acceptance criteria

  • The five keys behave as before in the editor and no longer work outside its screen.
  • They are listed in the ? help panel.
  • Tests cover registration and the typing-target guard.

Out of scope

Space and Escape (3/4).

Activity

  1. pullfrog commented on Oct 2, 2026

    @pullfrog

    Plan — Keybinds 2/4: migrate Delete, Backspace, G, F, K to registerShortcut (#38)

    Context

    • Host API (confirmed): window.registerShortcut({ key, handler, description, scope, condition? }); scopes are global | player | library | settings | plugin-<id>. It returns an unregister handle, and the guide says to "keep the returned handle … and unregister when your screen tears down" (feedBack plugin spec, best-practices rule 43). The issue's window.unregisterShortcut(key, scope) is the alternate form to verify against the installed host.
    • 1/4 (Keybinds 1/4: audit the hardcoded keys in onKeyDown and decide each key's scope #37) already landed as an audit comment (decision table). It flagged three gaps that block a faithful migration: claim-without-acting, exclusive catch-all modality, and ordered ownership.
    • What actually hardcodes these keys today (src/input.js):
      • G/F/K — the drum-edit articulation toggles (ghost / flam / choke), one guard block at input.js:2023-2043.
      • Delete/Backspace — a first-match ladder at input.js:2138-2222 (tempo barline → anchor → handshape → tone → drum hits → notes) plus the Tracks-overview region delete at input.js:2011-2016.
      • Registered as one document keydown listener at main.js:2387; the editor's own ? panel (EDITOR_SHORTCUT_COMMANDS) is a separate, in-plugin surface — the host ? panel is the new target.
    • No registerShortcut call exists in the repo yet (grep returns only a comment), so this issue is the first consumer and must feature-detect the host API.

    Decisions to confirm before coding

    1. Scope for Delete/Backspace: plugin-editor, not player. The Keybinds 1/4: audit the hardcoded keys in onKeyDown and decide each key's scope #37 audit recommended player, but it assumed a three-scope vocabulary; the real contract makes player a distinct screen, and Keybinds 2/4: migrate the editing keys (Delete, Backspace, G, F, K) to registerShortcut #38's acceptance criterion is "behave as before in the editor and no longer work outside its screen." All seven ladder rungs are editor-chrome/editor-data operations, so plugin-editor is the narrowest correct scope. G/F/K are unambiguously plugin-editor.
    2. Host dispatch order vs. onKeyDown. The read-only Tab-preview/User-Guide lenses swallow every key today by returning early in onKeyDown (input.js:1802-1831); a host-dispatched shortcut may run before/independently of that listener. The migrated handlers must re-check the lens/recording/mode guards themselves, or lens keyboard ownership must move to a capture-phase swallow.
    3. condition semantics and the exact unregister signature — verify against the installed host; fall back to guarding inside the handler and calling the returned handle on teardown.

    Milestones

    M1 — Registration plumbing (no behavior change).
    Add a small module (e.g. src/shortcut-registry.js, or a section of src/shortcuts.js) exporting registerEditorShortcuts() / unregisterEditorShortcuts():

    • Feature-detect window.registerShortcut (typeof === 'function'), no-op under node/host-absent, matching the repo's degrade-under-node rule.
    • Store returned handles in a module-level slot; unregister all in teardown.
    • Call register from init() (main.js:2364) and unregister from _teardownScreenSoft() (main.js:919, the complexity-budgeted helper, not the published closure).

    M2 — Extract the handlers so onKeyDown and the registry share one body.

    • _editorDeleteSelection(e) — the ordered input.js:2138-2222 ladder, returning a handled boolean; include the parts-view region rung (host.partsViewRegionDelete()).
    • _editorDrumArticulation(dk) — the G/F/K block, returning handled.
    • Each registered handler: run the context guard (typing target + lens/mode/recording), then e.preventDefault() when it consumed the key — preserving today's fall-through.

    M3 — Register the five keys, remove the onKeyDown branches.

    M4 — Tests (tests/keybind_registration.test.mjs, plus adjustments):

    • Stub window.registerShortcut to capture calls; assert 5 registrations with correct key/scope/description.
    • Typing-target guard: invoking a handler with a focused text field must not act; a canvas target must.
    • Delete ladder parity: one representative per rung (notes, tempo, parts-view region) through the registered handler.
    • Teardown calls the unregister handle(s); no registration when the host API is absent.
    • Re-run tests/user_guide_gate.test.mjs (fires Delete through onKeyDown) and the drum suites; update any that depended on the removed branches.

    M5 — Docs. Add a CHANGELOG.md [Unreleased] ▸ Added entry (the five keys now surface in the host ? panel); note the #37 decision-table scope correction if a comment edit is warranted.

    Acceptance-criteria mapping

    • Five keys behave as before in-editor, off-screen no longer → plugin-editor scope + preserved guards (M2/M3).
    • Listed in the ? help panel → registerShortcut with description (M3/M5).
    • Tests for registration + typing-target guard → M4.

    Out of scope

    Space and Escape (#39); removing the document listener / final ? verification (#40).

    Task list (3/3 completed)

    Pullfrog  | Implement plan ➔ | View workflow run | via Pullfrog | Using big-pickle (free) | 𝕏

  2. deleted a comment from pullfrog on Oct 9, 2026
  3. pullfrog commented on Oct 9, 2026

    @pullfrog

    Implemented #38 and opened PR #65.

    The editing keys (Delete/Backspace, drum G/F/K) now register with window.registerShortcut under the plugin-editor scope, with the shared delete ladder and drum toggles extracted so the host handler and the onKeyDown fallback use one body. Teardown unregisters; hosts without the API degrade to the old path.

    Pre-commit review caught a real Shift+Delete (EOF Cut) regression from the modifier-blind early return — fixed with modifier guards on the early-return and both handlers, plus atomic registration rollback and the restored tempo-map hint. node --test → 384 pass / 0 fail (15 new); lint clean.

    Pullfrog  | View workflow run | via Pullfrog | Using big-pickle (free) | 𝕏

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions