Skip to content

fix(hotkey): a microphone that closed itself does not cost the next double-tap - #61

Merged
hannesreinsch merged 1 commit into
mainfrom
fix/the-gesture-resets-when-the-mic-closes-itself
Sep 9, 2026
Merged

fix(hotkey): a microphone that closed itself does not cost the next double-tap#61
hannesreinsch merged 1 commit into
mainfrom
fix/the-gesture-resets-when-the-mic-closes-itself

Conversation

@hannesreinsch

@hannesreinsch hannesreinsch commented Sep 9, 2026

Copy link
Copy Markdown
Collaborator

"When the microphone closes automatically, the double press control doesn't reset."

Why

recording was a local flag inside listen_double_tap and the only record of whether anything was running. That was true while nothing else could end a clip.

The microphone can now close itself — after fifteen seconds of silence, or the two-minute cap. So the clip was gone while the loop still believed it was running: the next tap was spent being a STOP for something already stopped, and the double-tap only worked on the try after that.

The fix

The loop asks instead of assuming. is_recording is an optional callback polled once per poll — lambda: bool(mine) in the daemon, a list lookup and never work. A clip that ended without a tap resets the gesture on the spot, and says so in the log (saw("ended")).

Given no callback, the loop behaves exactly as it always did — a second test pins that half, so the change cannot quietly become the new behaviour everywhere.

It also fixes a case that was always wrong: an on_start that could not open the microphone left recording true, so the next tap was spent stopping a clip that never existed.

The driver

_tap_the_key runs the real listen_double_tap over a scripted key sequence with its clock and its key reader replaced, so a double-tap takes microseconds and no real key is touched. The test starts a clip, has the watchdog end it between the pairs, and asserts the second double-tap starts rather than stops.

Gate

208 passed, ruff clean, mypy clean.

🤖 Generated with Claude Code

https://claude.ai/code/session_01P7oJz8M9QzsdJimoM318cj

Summary by CodeRabbit

  • Bug Fixes

    • Improved double-tap recording behavior when a recording ends automatically due to inactivity or the maximum duration.
    • The next double-tap now correctly starts a new recording instead of being interpreted as a stop command for an already-ended recording.
  • Tests

    • Added coverage for automatic recording shutdown and preserved existing double-tap behavior when the new option is not used.

…ouble-tap

"When the microphone closes automatically, the double press control doesn't
reset."

`recording` was a local flag in `listen_double_tap` and the only record of
whether anything was running — true when nothing else could end a clip. The
microphone can now close itself, after fifteen seconds of silence or the
two-minute cap, so the clip was gone while the loop still believed it was
running: the next tap was spent being a STOP for something already stopped,
and the double-tap only worked on the try after that.

The loop asks instead. `is_recording` is an optional callback polled once per
poll — `lambda: bool(mine)` in the daemon, a list lookup and never work — and a
clip that ended without a tap resets the gesture on the spot (`saw("ended")`,
so the log says which). Given none, the loop behaves exactly as it always did,
and a test pins that half too.

It also fixes a case that was always wrong: an `on_start` that could not open
the microphone left `recording` true, so the next tap was spent stopping a clip
that never existed.

`_tap_the_key` drives the real loop over a scripted key sequence with its clock
and its key reader replaced, so a double-tap takes microseconds and no real key
is touched.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P7oJz8M9QzsdJimoM318cj
@coderabbitai

coderabbitai Bot commented Sep 9, 2026

Copy link
Copy Markdown

Review Change StackReview Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Advanced

Run ID: 7ac97ffe-5833-4dd8-9b0c-ba78d3a4f9f3

📥 Commits

Reviewing files that changed from the base of the PR and between 3974f41 and 0c67b80.

📒 Files selected for processing (3)
  • murmurflow/dictate.py
  • murmurflow/hotkey.py
  • tests/test_murmurflow.py

📝 Walkthrough

Walkthrough

The double-tap listener now accepts recording-state callbacks. The listening loop supplies microphone state, and the listener resets stale state when a recording closes independently. Tests cover both the new behavior and legacy behavior without the callback.

Changes

Recording state synchronization

Layer / File(s) Summary
Callback wiring
murmurflow/dictate.py, murmurflow/hotkey.py
bind_trigger accepts and forwards is_recording. listen_loop supplies the microphone-state callback. listen_double_tap declares the callback.
Ended-recording reconciliation
murmurflow/hotkey.py, tests/test_murmurflow.py
The listener detects independently ended recordings, resets its tap state, and emits "ended". Tests cover the new flow and behavior without the callback.

Estimated code review effort: 2 (Simple) | ~10 minutes

Sequence Diagram(s)

sequenceDiagram
  participant listen_loop
  participant bind_trigger
  participant listen_double_tap
  participant microphone_state
  participant on_tap
  listen_loop->>bind_trigger: pass is_recording callback
  bind_trigger->>listen_double_tap: forward callback
  listen_double_tap->>microphone_state: poll recording state
  microphone_state-->>listen_double_tap: report recording ended
  listen_double_tap->>on_tap: emit "ended"
Loading
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/the-gesture-resets-when-the-mic-closes-itself

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@hannesreinsch
hannesreinsch merged commit 4798bfd into main Sep 9, 2026
1 of 2 checks passed
@hannesreinsch
hannesreinsch deleted the fix/the-gesture-resets-when-the-mic-closes-itself branch September 9, 2026 14:40
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