Skip to content

feat: hold-or-double-tap mode for the push-to-talk shortcut - #1878

Open
ljden wants to merge 1 commit into
cjpais:mainfrom
ljden:feat/double-tap-toggle
Open

feat: hold-or-double-tap mode for the push-to-talk shortcut#1878
ljden wants to merge 1 commit into
cjpais:mainfrom
ljden:feat/double-tap-toggle

Conversation

@ljden

@ljden ljden commented Aug 8, 2026

Copy link
Copy Markdown

Human Written Description

Optional extension for Push To Talk where a double tap of the Transcribe Shortcut functions as a toggle. Useful for sometimes recording a short transcript and sometimes for recording a longer session. This is based on input from other users such as on #147.
This is an alternative approach to the one I took in #1877 - happy to go with either (or neither if it's not the time). I think I like this one better, but the other one is ok.

Related Issues/Discussions

Related to #147. This implements the behavior described there — a brief press
toggles, press-and-hold is push-to-talk — as an opt-in setting, refined to
require a double-tap to start a session so that an accidental key press
is a no-op instead of an open microphone.

With the "Double-Tap To Toggle" switch enabled (shown only while Push To Talk
is on, off by default):

  • Hold the transcribe shortcut → push-to-talk, exactly as today
  • Double-tap → hands-free session, ended by the next press
  • Lone tap → the recording is discarded via the existing cancel path —
    nothing is transcribed or pasted, even if the tap caught real speech

Recording starts on key-down in all cases; classification happens at release
from the press duration, so no gesture adds latency. Every release still goes
through the existing RELEASE_GRACE deferral, so X11 auto-repeat can't
misclassify a held key as a tap (#1539's scenario). The coordinator's input
events now carry an InputMode enum (toggle / push-to-talk /
hold-or-double-tap) instead of a push_to_talk bool; signal/CLI triggers are
unchanged (always toggle).

Design notes:

  • The setting persists when Push To Talk is turned off — it's inert without
    PTT (the handler derives the mode from push_to_talk first) and applies
    again when PTT returns.
  • Timing constants live next to the existing DEBOUNCE/RELEASE_GRACE:
    HOLD_THRESHOLD 300 ms (hold vs tap) and SECOND_TAP_WINDOW 150 ms (lone
    vs double tap, measured from the tap's release). Deliberately constants,
    not settings — happy to expose them if there's demand. One consequence:
    a push-to-talk recording shorter than 300 ms is treated as a tap and
    discarded, which is the accidental-press protection working as intended.
  • A sibling branch implements the two-shortcut variant from the Auto push to talk and command line options #147 comments
    (separate always-toggle binding). The two are independent and composable —
    happy to go with either or both, whichever fits the project's direction.
    see feat: add opt-in always-toggle shortcut alongside push-to-talk #1877

Community Feedback

In #147, @cjpais described this behavior as "a good default behavior" and
noted the code at the time wouldn't support it well — the coordinator added
since then (serialized input events with deadline-based deferral) turned out
to support it cleanly. @retspen, @codepunkt and @samleibowitz expressed
interest in a toggle mode coexisting with push-to-talk.

Testing

  • cargo test: 183 passed — includes 6 new deterministic tests for the
    hold-or-double-tap state machine (hold, lone-tap discard, double-tap lock,
    locked-session behavior, X11 auto-repeat absorption, hold duration measured
    from the initial press), driven by a synthetic-clock simulator mirroring the
    coordinator loop, in the same style as the existing PTT regression tests
  • cargo check, cargo clippy, cargo fmt --check clean (no new warnings)
  • bun run lint, tsc, prettier --check, vite build all pass
  • Frozen v0.9 settings-store test still passes; the new setting is
    #[serde(default)], no migration needed
  • Manual on macOS (bun run tauri dev): hold/double-tap/lone-tap all behave
    as described; PTT off→on cycle keeps the switch state consistent

Screenshots/Videos (if applicable)

image image image

AI Assistance

  • No AI was used in this PR
  • AI was used (please describe below)

If AI was used:

  • Tools used: Claude Code
  • How extensively: implementation, tests, and commit message AI-written under
    human direction; design decisions (double-tap vs single-tap, opt-in scoping,
    timing values) made by the human, who reviewed the diff, ran all checks, and
    manually tested the feature

Adds an opt-in double_tap_toggle setting: with push-to-talk on, holding the
transcribe shortcut still works as push-to-talk, while a double-tap starts an
ongoing session ended by the next press. A lone tap discards its recording
instead of transcribing a fraction of a second of audio, so grazing the key
is a no-op.

Recording starts on key-down either way; the hold-vs-tap decision happens at
release, from the press duration. Every release is still deferred by the
existing RELEASE_GRACE so X11 auto-repeat cannot misclassify a held key as a
tap, and a lone tap's recording is discarded through the existing cancel path
when the second-tap window elapses. The coordinator's input events now carry
an InputMode (toggle / push-to-talk / hold-or-double-tap) instead of a
push_to_talk bool.

Double-tap-toggle only modifies how the push-to-talk shortcut behaves, so
its switch is shown only while push-to-talk is on.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@adamkdean

Copy link
Copy Markdown

My preference would be a short delay, to see if it's a key down/up or a key down to decide if it's toggle or PTT

@ljden

ljden commented Aug 9, 2026

Copy link
Copy Markdown
Author

My preference would be a short delay, to see if it's a key down/up or a key down to decide if it's toggle or PTT

@adamkdean I'm curious to hear why you prefer a short tap over a double tap?

My motivation was that I wanted to prevent accidentally triggering the toggle state. Particularly when you map a single modifier key like the right command/super/alt/option key, accidental triggers are likely.

@adamkdean

adamkdean commented Aug 9, 2026 via email

Copy link
Copy Markdown

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