Skip to content

fix: show platform-correct hotkey labels in recording overlays - #19

Merged
nikolaykolibarov merged 3 commits into
mainfrom
fix/platform-hotkey-labels
Oct 25, 2026
Merged

nikolaykolibarov merged 3 commits into
mainfrom
fix/platform-hotkey-labels

Conversation

@nikolaykolibarov

@nikolaykolibarov nikolaykolibarov commented Oct 25, 2026 •

Copy link
Copy Markdown
Member

Problem

The recording UI hard-coded macOS key symbols and ignored the configured hotkeys:

Where Before
In-app overlay (RecordingOverlay.tsx) Stop ⌥ / Cancel esc on every platform
Home "Start recording" badge (App.tsx) ⌥/⌘ symbols on Windows/Linux too
Native macOS overlay (overlay_darwin.go) Stop ⌥ / Cancel esc
Native Windows overlay (appearance.go) Stop (no key) / Cancel esc

A Windows user with Right Alt saw ⌥. A Mac user with Right Command also saw ⌥.

Fix

  • One formatter per language, with one shared test table.
    • frontend/src/hotkeyLabels.ts: formatHotkeyShortLabel gives the compact badge label. formatHotkeyLabel gives the Settings/sidebar label. App.tsx now uses these instead of its two switch tables.
    • internal/hotkey/labels.go: ShortLabel / ShortLabelFor(name, goos) are the Go equivalent for the native overlays.
    • Both are tested against internal/hotkey/testdata/short_labels.json, so they can't drift apart.
    • macOS: ⌥ ⌘ ⌃ ⇧ ⇪ fn Esc ⇥ ↩ ⌫
    • Windows: Alt Win Ctrl Shift Caps Fn Esc Tab Enter Bksp Del
    • Linux: same as Windows, but Super for the meta key.
    • F-keys, letters, digits, Space and arrows are the same on all platforms.
  • No startup flash: the Home badge and sidebar hint stay hidden until the platform and both hotkeys have loaded. Before this, Windows briefly showed the macOS default ⌥.
  • In-app overlay: RecordingOverlay takes stopKeyLabel / cancelKeyLabel props. App passes them from the loaded currentHotkey, cancelHotkey and platform.
  • Native overlays: new overlay.SetHotkeyLabels(stop, cancel) for darwin, windows, and a no-op for other builds. app.go refreshes it from config at startup, in ReregisterHotkey, and after SetRecordingHotkey / SetCancelHotkey save. The refresh runs under a lock so concurrent changes can't leave a stale label. Labels update live, even while the panel is open.
    • macOS: buttons read Stop <key> / Cancel <key> and grow to fit, right-aligned.
    • Windows: appearance.go draws the same captions and sizes the buttons to fit. Hit testing uses the rectangles from the last drawn frame. Captions without a key keep the original 70/75 px layout. overlay_windows_test.go now also sets wide labels and checks that clicks follow the drawn buttons.

Files

  • frontend/src/hotkeyLabels.ts (new)
  • frontend/src/App.tsx
  • frontend/src/RecordingOverlay.tsx
  • internal/hotkey/labels.go (new)
  • internal/overlay/{appearance.go, overlay_darwin.go, overlay_windows.go, overlay_other.go}
  • app.go
  • Tests:
    • frontend/src/{hotkeyLabels.test.ts, RecordingOverlay.test.tsx}
    • internal/hotkey/{labels_test.go, testdata/short_labels.json}
    • internal/overlay/appearance_test.go
  • .github/workflows/ci.yml: runs npm test in the macOS job. Before this, the frontend tests never ran in CI.

Small, intentional text changes

The long labels (Settings and sidebar) now follow one rule:

  • macOS Ctrl/Shift show as Right ⌃ / Right ⇧. They used to be Right Ctrl / Right Shift, which didn't match Right ⌥ / Right ⌘.
  • Windows/Linux show Enter instead of Return.
  • Linux shows Super instead of Win.

Compact badge changes:

  • Windows/Linux: ⊞ and the Mac glyphs become Win/Super, Alt, Ctrl, Shift, Caps, Tab, Enter, Bksp, Del.
  • macOS: Space replaces ␣, ↩ replaces ↵, and fn matches the key cap.
  • macOS delete shows ⌫, because that's the key hotkey_darwin.go actually binds.

Onboarding still uses Go's GetRecordingHotkeyDisplayName ("Right Option (⌥)" / "Right Alt"). That text is already platform-correct, so this PR leaves it alone.

Tests

  • cd frontend && npm test:
    • Formatter checked against the shared table for darwin/windows/linux, with a mocked platform.
    • Checks that Windows output never contains Mac glyphs.
    • Long-label cases.
    • App keeps the badges hidden while GetPlatform is pending, then shows Alt / Right Alt on Windows with no ⌥ at any point. It also passes the configured keys to the overlay (⌘ / F10).
    • RecordingOverlay renders the configured labels: Windows Alt/Esc, macOS ⌘, F9/F10. It omits an empty badge and keeps the button wiring.
  • go test -race ./... passes on macOS, including:
    • TestShortLabelFor, which uses the shared table;
    • TestButtonText;
    • TestOverlayButtonsFitHotkeyLabels, which covers the original layout for bare captions, wider buttons that fit their captions at 1x/1.5x/2x, no overlap with the status text, and the key label actually being drawn.
  • Windows cross-checks:
    • GOOS=windows go vet is clean for internal/overlay.
    • GOOS=windows CGO_ENABLED=0 go test -c builds for ./internal/overlay and ./internal/hotkey.
    • GOOS=windows go vet ./... for the whole module still stops at portaudio (needs cgo), the same as on main.
    • There is also an existing vet warning in hotkey_windows.go:136, in a file this PR doesn't touch.
  • npm run build, go vet ./... pass.
  • Two independent read-only reviews were done.
    • The first found no high-severity issues. Both medium findings are fixed: the label refresh race, and the Windows click test that only used the default layout.
    • The second found no high or medium issues. Two low findings are fixed: the startup badge flash, and the shared table now covers every key alias. Not changed: a hand-edited, unknown key name can widen the native Windows Stop button without limit. The Settings UI can't produce such a name.

Manual verification (macOS, wails dev with an isolated HOME, driven via bindings)

Config Home badge In-app overlay Native macOS overlay
rightoption / escape ⌥ Stop ⌥ · Cancel Esc Stop ⌥ · Cancel Esc
f9 / escape, set in Settings F9 Stop F9 · Cancel Esc Stop F9 · Cancel Esc
rightcommand / f10, set in Settings ⌘ Stop ⌘ · Cancel F10 Stop ⌘ · Cancel F10
rightshift / f10, after rebase and review fixes ⇧, sidebar Right ⇧ Stop ⇧ · Cancel F10 Stop ⇧ · Cancel F10
rightalt, with GetPlatform mocked to windows Alt, sidebar Right Alt Stop Alt · Cancel Esc n/a. The Windows renderer output (go test artifact) shows Stop Alt · Cancel Esc

Screenshots were taken locally. They aren't attached because they come from a dev build.

Merging with PR #18

This branch first added its own minimal Vitest setup, byte-identical to PR #18's (package.json, vite.config.ts, src/test/setup.ts, the md5 file). #18 was merged while this was in progress. After rebasing onto it, those files and the lockfile are unchanged from main. The only test-infrastructure change left is the CI npm test step. Locally, all 77 frontend tests pass, including #18's.

Please check on Windows

  • The native overlay should read Stop Alt / Cancel Esc with default keys, and the buttons should still be clickable.
  • After changing the key in Settings, the next recording's overlay should show the new key.

The in-app and native recording overlays hard-coded "Stop ⌥" and
"Cancel esc", so Windows users saw macOS symbols and nobody saw their
configured keys.

- frontend/src/hotkeyLabels.ts formats key names per platform; App uses
  it for settings, the Home badge and the RecordingOverlay labels.
- hotkey.ShortLabel is the Go equivalent. Both are tested against the
  shared table in internal/hotkey/testdata/short_labels.json.
- overlay.SetHotkeyLabels updates the native overlays on macOS and
  Windows (no-op elsewhere). app.go refreshes it from config at startup,
  on re-registration and after each hotkey change, under a lock so
  concurrent changes cannot leave a stale label.
- Native buttons grow to fit their captions; Windows hit testing uses
  the same rectangles that are drawn, and the Windows overlay test now
  clicks the labelled layout.
The Home badge and sidebar hint rendered with the macOS defaults until
GetPlatform and the hotkey bindings resolved, so Windows briefly showed
⌥. They now appear once the platform and both keys have loaded.

Also extend the shared label table with every alias the formatters
accept, so the Go and TypeScript implementations cannot drift.
@nikolaykolibarov
nikolaykolibarov merged commit 9a736ac into main Oct 25, 2026
4 checks passed
@nikolaykolibarov
nikolaykolibarov deleted the fix/platform-hotkey-labels branch October 25, 2026 19:30
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