Skip to content

feat(shortcut): replace push-to-talk toggle with two coexisting hotkeys (classic + PTT)#1302

Open
kud wants to merge 4 commits intocjpais:mainfrom
kud:feat/ptt-and-classic-hotkeys
Open

feat(shortcut): replace push-to-talk toggle with two coexisting hotkeys (classic + PTT)#1302
kud wants to merge 4 commits intocjpais:mainfrom
kud:feat/ptt-and-classic-hotkeys

Conversation

@kud
Copy link
Copy Markdown

@kud kud commented Apr 15, 2026

Before Submitting This PR

Please confirm you have done the following:

If this is a feature or change that was previously closed/rejected:

  • I have explained in the description below why this should be reconsidered
  • I have gathered community feedback (link to discussion below)

Human Written Description

I've been using Handy daily and kept running into the same friction: I'd be mid-conversation and want a quick dictation, but I was in toggle mode and had to go flip the push-to-talk setting first. SuperWhisper solves this elegantly — you have two separate hotkeys, and the behaviour is implicit in which one you press. No settings to toggle, no mental overhead.

This PR replaces the push-to-talk boolean toggle with two coexisting, independently configurable hotkeys: the existing classic toggle shortcut (press once to start, press again to stop and transcribe) and a new dedicated push-to-talk shortcut (hold to record, release to transcribe). Both are always active simultaneously. You just reach for whichever one fits the moment — hold PTT for a quick aside, use the classic toggle for a longer note.

I also cleaned up a few UX rough edges in the shortcut input components while I was there: a trash icon to explicitly clear a binding to empty, a "No hotkey" placeholder when a binding is unset, and modifier keys rendered as Unicode symbols (⌃ ⌥ ⇧ ⌘) so long combos stay readable.

Related Issues/Discussions

Fixes #
Discussion:

Community Feedback

No formal discussion thread yet — happy to start one if that would help. The feature pattern itself is well-established (SuperWhisper, which many Handy users are familiar with, works exactly this way).

Testing

  • 80 Rust unit tests pass including new regression tests covering the PTT binding path
  • Tested manually on macOS: both hotkeys active simultaneously, PTT correctly triggers on key-down and stops on key-up, classic toggle behaviour unchanged
  • Settings migration tested: existing installs with the old push_to_talk boolean pick up the new transcribe_with_push_to_talk binding correctly on first launch, and the new binding persists to disk via store.save()
  • Empty-binding guard confirmed: leaving PTT unset does not trigger a shortcut registration error

Screenshots/Videos (if applicable)

image

AI Assistance

  • AI was used (please describe below)

If AI was used:

  • Tools used: Claude Code (claude-sonnet-4-6) via the CLI
  • How extensively: Claude Code implemented the majority of the Rust backend changes and the frontend shortcut input components under my direction. I designed the overall approach (two coexisting bindings, PTT driven by binding ID rather than a global flag), specified the UX details, and reviewed every diff. The "Human Written Description" above is my own words.

kud added 2 commits April 16, 2026 00:36
…configurable bindings

- Replace 'push to talk' boolean setting with dedicated 'Push-to-Talk Shortcut' hotkey
- PTT now always acts as hold-to-record regardless of global transcription mode
- Implement three configurable hotkeys: Classic (toggle), Push-to-Talk (hold), Cancel
- Add clear_binding Rust command to explicitly remove any hotkey
- Display modifier keys as Unicode symbols (⌃⌥⇧⌘) with L/R prefix for sided variants
- Show 'No hotkey' placeholder when binding is unset
- Hide reset button for bindings without defaults; display trash icon instead
- Add store.save() to settings migration for persistence on first launch
- Remove PushToTalk.tsx component (functionality integrated into keybindings)
- Add clearBinding Tauri command for removing shortcuts completely
- Show 'No hotkey' placeholder when binding is not set
- Display trash icon button to clear active bindings
- Hide reset button when no default binding exists
- Replace verbose modifier names with Unicode symbols (⌃⌥⇧⌘)
- Add L/R prefix for sided variants (L⌃, R⇧, etc.)
- Change key combination separator from '+' to space for cleaner display
- New TrashIcon SVG component
- Remove push_to_talk from AppSettings type
@kud kud marked this pull request as ready for review April 15, 2026 23:41
@cjpais
Copy link
Copy Markdown
Owner

cjpais commented Apr 30, 2026

Right now no new features are being merged. I'm open to this, but it will be taken up at a later time as we revisit shortcuts generally. Right now there are an absolute ton of shortcut requests and I can't just merge one without people getting on me about not merging the one they want.

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.

2 participants