# Phase 9: Scan Cancellation & Keyboard Shortcuts - Research **Researched:** 2026-03-06 **Domain:** Go context cancellation, frontend keyboard event management, Lit web component architecture **Confidence:** HIGH ## Summary This phase adds two independent feature sets to YellowJacket: scan control (cancel/pause/resume) on the Go backend with frontend buttons, and a full keyboard shortcut system on the Lit frontend with configurable bindings persisted via the existing TOML config. **Scan cancellation** requires threading a cancellable `context.Context` through the existing scan pipeline. The current `Scan()` method already checks `l.ctx.Done()` in several `select` blocks within the directory walker and worker pool. The implementation adds a dedicated `scanCancel context.CancelFunc` field on `Library`, Pause/Resume via a sync-based mechanism (channel or mutex), and new Wails-bound methods (`CancelScan`, `PauseScan`, `ResumeScan`). The cancel confirmation dialog ("Keep X tracks found so far, or discard?") is a frontend concern — the backend simply stops and reports partial results vs rolls back. **Keyboard shortcuts** are a pure frontend feature. No external libraries are needed — the browser's `KeyboardEvent` API is sufficient for a Wails desktop app. A central `KeyboardShortcutService` singleton listens on `document.keydown`, resolves the active scope (Global, Panel-specific, Text Input), looks up the action, and dispatches it. Bindings are stored in the Go config (new `Shortcuts` TOML section) and exposed via Wails bindings. The settings UI adds a "Keyboard Shortcuts" tab to the existing `config-page` component with record-style key capture. **Primary recommendation:** Implement scan cancellation via `context.WithCancel` + a pause channel on the backend, and keyboard shortcuts as a frontend-only `KeyboardShortcutService` with Go config persistence. Both are zero-dependency — no new libraries needed on either side. ## User Constraints (from CONTEXT.md) ### Locked Decisions - Hybrid style: Space/arrows for player controls (no modifier), Ctrl+key for app actions - Up/Down arrows adjust volume, Left/Right seek within track - Both `/` and `Ctrl+F` focus the search box - `Q` toggles the queue panel - `S` for shuffle, `R` for repeat (single-key player controls) - `Ctrl+A` for select-all in any multi-select context (track lists, etc.) - All bindings are configurable — the above are defaults - Claude fills in remaining defaults (mute, etc.) using common media player conventions - Record-style key capture: click a shortcut row, press the new key combo, it captures live - Conflicts show a warning with the conflicting action — user chooses to overwrite (old becomes unbound) or cancel - Shortcuts grouped by category (Player, Navigation, App) in the settings view - "Reset to defaults" button resets all shortcuts; individual per-shortcut reset also available - Lives as a "Keyboard Shortcuts" tab within the existing settings dialog - Three scopes: Global (always active), Panel-specific (when a panel has focus), Text Input (shortcuts suppressed) - Global scope: player controls (Space, arrows, S, R, Q, etc.) fire regardless of which panel is focused - Panel-specific scope: track list gets Enter-to-play and Delete-to-remove when focused - Text Input scope: only Escape works (blurs the text input) — all other shortcuts suppressed - No visual scope indicator — relies on natural browser focus behavior; users learn through use - Pause and Cancel buttons placed next to the existing status label, above the existing progress bar in the scanner UI - On cancel: prompt the user — "Keep X tracks found so far, or discard?" — gives user control over partial results - On resume after pause: skip already-processed files and continue with remaining — no duplicate work - Scan control is buttons-only — no keyboard shortcuts for cancel/pause (scans are infrequent) ### Claude's Discretion - Remaining default key assignments not explicitly discussed (mute, volume step size, etc.) - Scan progress detail level and error handling during scan - Loading/disabled states for scan control buttons - Visual design of the shortcut settings UI (spacing, grouping headers, etc.) - How the cancel confirmation dialog looks and behaves ### Deferred Ideas (OUT OF SCOPE) None — discussion stayed within phase scope ## Phase Requirements | ID | Description | Research Support | |----|-------------|-----------------| | SCAN-01 | User can cancel an in-progress library scan via a cancel button | Go context cancellation pattern; new `CancelScan()` Wails binding; frontend cancel button in config-page scan section | | SCAN-02 | Cancelled scan stops gracefully without corrupting the database | Batch-transactional writes already atomic; cancel skips orphan cleanup (STATE.md warning); partial results either kept or discarded per user choice | | SCAN-03 | User can pause a library scan and resume it without re-scanning processed files | Pause channel blocks worker pool goroutines; resume unblocks; existingPaths sync.Map already tracks processed files | | KEY-01 | Default keybindings work out of box | Frontend `KeyboardShortcutService` with hardcoded default map; Go config stores overrides | | KEY-02 | User can customize all keyboard shortcuts via a visual settings UI | "Keyboard Shortcuts" tab in config-page; record-style key capture component; Wails config bindings for persistence | | KEY-03 | Shortcut conflicts are detected and warned about when rebinding | Frontend conflict detection during key capture — compare against all bindings in same scope | | KEY-04 | Shortcuts are scoped — different bindings apply based on focused component | Three-scope system (Global, Panel, TextInput); scope resolved by checking `document.activeElement` shadow DOM chain | | KEY-05 | Shortcuts are disabled when text input has focus (except Escape to blur) | TextInput scope check: if active element is ``, `