Skip to content

feat(shortcut): single/double press detection for Ctrl+G#31

Open
0xMMA wants to merge 29 commits intomainfrom
feature/shortcut-double-press
Open

feat(shortcut): single/double press detection for Ctrl+G#31
0xMMA wants to merge 29 commits intomainfrom
feature/shortcut-double-press

Conversation

@0xMMA
Copy link
Copy Markdown
Owner

@0xMMA 0xMMA commented Apr 6, 2026

Closes #30

Summary

  • Add Go-side double-press detector with 200ms state machine (internal/features/shortcut/detect.go) — classifies raw hotkey presses as Single or Double via channels/timers
  • Wire detector into main.go shortcut goroutine: clipboard captured on first press, shortcut:single or shortcut:double emitted as distinct Wails events, window focused on double press
  • Frontend: WailsService exposes shortcutSingle$ / shortcutDouble$ replacing the old undifferentiated shortcutTriggered$; FixComponent subscribes to single, TextEnhancementComponent subscribes to double, ShellComponent navigates to /enhance on double press

Test Plan

  • Go: 5 new detector unit tests (single, double, slow double, triple, stop) — go test ./internal/features/shortcut/ -run TestDetector
  • Frontend: 132 Vitest tests passing, including updated shortcut subscription tests for fix, text-enhancement, and shell components
  • Manual: single Ctrl+G triggers silent fix regardless of active route; double Ctrl+G opens Pyramidize UI and focuses window
  • Manual: verify 200ms threshold feels right — single press has imperceptible delay

🤖 Generated with Claude Code

0xMMA and others added 29 commits April 6, 2026 00:49
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…#30)

CopyFromForeground() sleeps ~150ms (Ctrl+C + wait). Capturing on every
press ate into the 200ms detection window, leaving only ~50ms margin.
Use atomic.Bool to capture only on the first press of each cycle.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
#30)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ble shortcuts (#30)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…gurable shortcuts (#30)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…hook (#30)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ents (#30)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ok (#30)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…cutPyramidize$, add settings fields (#30)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…corder (#30)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Three bugs fixed:
- Auto-repeat: track trigger keyup in double-tap state machine. Only
  accept second tap after the trigger key has been physically released
  and pressed again (tapWaitRelease → tapWaitSecond phases).
- Recording conflict: add SetPaused() to service interface. Recorder
  component pauses the hook during capture mode so keypresses pass
  through to the webview instead of being intercepted.
- Diagnostic logging: add Debug-level trace logs in hook callback for
  modifier tracking, tap phases, and combo matching.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
FixComponent is only mounted on the /fix route. When the app is hidden
or on another route, the shortcutFix$ subscription didn't exist, so
the silent fix never ran. Move it to ShellComponent which is always
mounted — read clipboard, enhance, write back, paste to foreground.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
#30)

Outlook uses delayed clipboard rendering — the fixed 150ms sleep wasn't
enough for the clipboard to be populated. Now polls
GetClipboardSequenceNumber in 25ms intervals up to 1s timeout.
Fast apps still finish in ~25-50ms; slow apps like Outlook get the
full second.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When the shortcut combo includes Shift or Alt (e.g. Ctrl+Shift+G for
pyramidize), those modifiers are still physically held when
CopyFromForeground sends Ctrl+C. The target app sees Ctrl+Shift+C
instead of Ctrl+C, which Outlook and other apps silently ignore.

Fix: inject Shift-up and Alt-up events before Ctrl+C (and Ctrl+V)
so the receiving app always gets a clean Ctrl+C/Ctrl+V regardless of
which modifiers the shortcut combo used.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…wn (#30)

Gives the user time to release modifier keys before CopyFromForeground
runs, reducing the chance of Ctrl+Shift+C instead of Ctrl+C.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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.

Shortcut flow broken on Windows — no single/double distinction, focus, and routing issues

1 participant