Skip to content

Add single-tap toggle recording mode + fix hotkey character leak#167

Open
pchalasani wants to merge 1 commit intokitlangton:mainfrom
pchalasani:feat/single-tap-shortcut
Open

Add single-tap toggle recording mode + fix hotkey character leak#167
pchalasani wants to merge 1 commit intokitlangton:mainfrom
pchalasani:feat/single-tap-shortcut

Conversation

@pchalasani
Copy link

@pchalasani pchalasani commented Feb 12, 2026

Summary

  • Adds a RecordingMode enum (.singleTap / .doubleTap) replacing the useDoubleTapOnly boolean
  • Single-tap mode (new default): tap hotkey once to start recording, tap again to stop — no press-and-hold or double-tap needed
  • Double-tap mode: preserves existing hold-to-record + double-tap-lock behaviour
  • Fixes hotkey character leak: when stopping recording with a printable-key hotkey (e.g. ^;), the character (semicolon) no longer leaks into the active app
  • Settings UI: replaces "Use double-tap only" toggle with a "Single Tap / Double Tap" segmented picker, shown for all hotkey types
  • Backwards-compatible: old JSON with useDoubleTapOnly=true decodes as .doubleTap

Files changed

File Change
HexCore/.../HexSettings.swift Add RecordingMode enum, replace useDoubleTapOnly property, backwards-compat decode
HexCore/.../HotKeyProcessor.swift Replace useDoubleTapOnly with recordingMode, update state machine for toggle mode
Hex/.../TranscriptionFeature.swift Sync recordingMode, intercept key on .stopRecording to prevent character leak
Hex/.../HotKeySectionView.swift Replace toggle with segmented picker for all hotkey types
HexCore/.../HotKeyProcessorTests.swift 7 new single-tap toggle tests, update existing tests for recordingMode param
HexCore/.../HexSettingsMigrationTests.swift Update assertion for backwards compat

Test plan

  • cd HexCore && swift test — all 67 tests pass (7 new + 60 existing)
  • Manual: set hotkey to ^;, verify single-tap starts/stops recording
  • Manual: verify no semicolon leaks into pasted text on stop
  • Manual: ESC cancels toggle recording
  • Manual: switch to "Double Tap" mode → old hold-to-record behaviour works
  • Manual: modifier-only hotkey works in both modes

Summary by CodeRabbit

  • New Features

    • Added single-tap toggle option for recording mode; users can now select between Single Tap and Double Tap recording activation methods.
  • Bug Fixes

    • Fixed hotkey character leak when stopping recording.

Introduces a RecordingMode enum (.singleTap / .doubleTap) replacing
the old useDoubleTapOnly boolean. Single-tap mode (new default) lets
users tap the hotkey once to start recording, tap again to stop —
no need for press-and-hold or double-tap. Double-tap mode preserves
the existing hold-to-record + double-tap-lock behaviour.

Also fixes a bug where the hotkey's printable character (e.g. semicolon
in Control+Semicolon) leaked into the active app when stopping a
recording in toggle/doubleTapLock mode, by intercepting the key event
on .stopRecording when the key matches the hotkey.

Settings UI updated: the "Use double-tap only" toggle (key+modifier
only) is replaced with a "Single Tap / Double Tap" segmented picker
shown for all hotkey types. Backwards-compatible: old JSON with
useDoubleTapOnly=true decodes as .doubleTap.

Includes 7 new HotKeyProcessor tests covering single-tap toggle for
standard and modifier-only hotkeys, release persistence, and ESC
cancellation.
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 12, 2026

📝 Walkthrough

Walkthrough

This PR replaces a boolean useDoubleTapOnly flag with an enum-based RecordingMode system (singleTap/doubleTap) across settings, hotkey processing logic, and UI components. The change introduces single-tap toggle functionality for recording mode alongside bug fixes for hotkey character leaks during stop operations.

Changes

Cohort / File(s) Summary
Core Settings & Logic
HexCore/Sources/HexCore/Settings/HexSettings.swift, HexCore/Sources/HexCore/Logic/HotKeyProcessor.swift
Introduced new public RecordingMode enum with .singleTap and .doubleTap cases. Replaced useDoubleTapOnly: Bool property with recordingMode: RecordingMode in HexSettings and HotKeyProcessor initialization. Updated hotkey state transition logic to handle singleTap mode (immediate start/stop via double-tap lock) and retain doubleTap hold-to-record behavior. Added legacy migration path for decoding old boolean values.
UI Layer
Hex/Features/Settings/HotKeySectionView.swift
Replaced boolean toggle ("Use double-tap only") with segmented picker bound to recordingMode. Updated UI binding from useDoubleTapOnly to store.hexSettings.recordingMode with picker options for Single Tap and Double Tap modes.
Feature Integration
Hex/Features/Transcription/TranscriptionFeature.swift
Updated HotKeyProcessor configuration to use recordingMode instead of useDoubleTapOnly. Adjusted hotkey interception logic: start/continue now depends on key presence; stop now only intercepts when key exists and matches configured hotkey.
Test Updates
HexCore/Tests/HexCoreTests/HotKeyProcessorTests.swift, HexCore/Tests/HexCoreTests/HexSettingsMigrationTests.swift
Extended test harness with recordingMode parameter (defaulting to .doubleTap) in runScenario. Added comprehensive single-tap toggle mode test coverage. Updated migration test assertion from useDoubleTapOnly == true to recordingMode == .doubleTap.
Release Notes
.changeset/50f5fa9e.md
Added minor version changeset documenting single-tap toggle feature and hotkey character leak bug fix.

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant UI as HotKeySectionView
    participant Settings as HexSettings
    participant Feature as TranscriptionFeature
    participant Processor as HotKeyProcessor

    User->>UI: Select Recording Mode (Single/Double Tap)
    UI->>Settings: Update recordingMode property
    Settings->>Feature: Notify settings change
    Feature->>Processor: Initialize with recordingMode
    Processor->>Processor: Configure state machine<br/>(singleTap → doubleTapLock path<br/>doubleTap → hold-to-record)
    Processor->>Feature: Ready for hotkey detection
    User->>Processor: Press hotkey
    alt Single Tap Mode
        Processor->>Processor: Transition to doubleTapLock
        Processor->>Feature: Emit startRecording
        User->>Processor: Release hotkey (matching key)
        Processor->>Feature: Emit stopRecording
    else Double Tap Mode
        Processor->>Processor: Start timing
        Processor->>Feature: Emit startRecording (on hold)
        User->>Processor: Release hotkey
        Processor->>Feature: Emit stopRecording
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • Sync recording delay with minimumKeyTime setting #100: Modifies hotkey press/handling logic in TranscriptionFeature.swift with changes to how hotkey presses are processed and timing parameters are passed.
  • Fix #122 -  #150: Updates hotkey-related logic in TranscriptionFeature.swift, including fixes to hotkey interception and the cancellation/sleep loop used by hotkey monitoring effects.

Poem

🐰 A toggle becomes a choice so clear,
Two modes of tapping now appear!
From bool to enum, we've set it free,
Single or double—pick with glee!
Hotkeys now flow with grace divine,

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 31.58% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the two main changes: adding single-tap toggle recording mode and fixing the hotkey character leak, matching the primary objectives of the pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

No actionable comments were generated in the recent review. 🎉

🧹 Recent nitpick comments
.changeset/50f5fa9e.md (1)

5-5: Include the PR number in the changeset description.

Per repository guidelines, changeset entries should include the GitHub issue/PR number. Consider appending (#167).

Proposed fix
-Add single-tap toggle recording mode and fix hotkey character leak on stop
+Add single-tap toggle recording mode and fix hotkey character leak on stop (`#167`)

As per coding guidelines, "Include user-facing impact and GitHub issue/PR number in the format 'Improve Fn hotkey stability (#89)'."

Tip

Issue Planner is now in beta. Read the docs and try it out! Share your feedback on Discord.


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 and usage tips.

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f540401fe4

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

if recordingMode == .singleTap {
// Toggle mode: go straight to doubleTapLock
// (release will be ignored; next press stops)
state = .doubleTapLock

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Preserve transcription cancel path before single-tap start

In single-tap mode, the first matching hotkey press now transitions directly to .doubleTapLock and returns .startRecording, which causes TranscriptionFeature.startHotKeyMonitoringEffect to dispatch .startRecording directly instead of .hotKeyPressed; that bypasses handleHotKeyPressed’s isTranscribing cancellation branch, so pressing the hotkey while a previous transcription is still running can leave the old transcription in flight while a new recording starts, leading to overlapping workflows and stale transcript output.

Useful? React with 👍 / 👎.

Comment on lines +300 to +301
state = .doubleTapLock
return .startRecording

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Retain accidental click discard for modifier-only single-tap

Setting single-tap starts recording by immediately entering .doubleTapLock, but processMouseClick() only performs the modifier-only accidental-trigger discard while in .pressAndHold and always ignores clicks in .doubleTapLock; this means common Option+click interactions now keep recording running instead of being discarded within the safety window, regressing the existing protection against accidental modifier-only activations.

Useful? React with 👍 / 👎.

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