Skip to content

Hide cursor overlay while user is typing#49

Open
Catafal wants to merge 1 commit intofarzaa:mainfrom
Catafal:fix/hide-cursor-while-typing
Open

Hide cursor overlay while user is typing#49
Catafal wants to merge 1 commit intofarzaa:mainfrom
Catafal:fix/hide-cursor-while-typing

Conversation

@Catafal
Copy link
Copy Markdown

@Catafal Catafal commented Apr 10, 2026

Feature

Hide Clicky cursor when user types, matching macOS native behavior (resolves #37)

Problem

When macOS hides the system cursor on keypress (NSCursor.setHiddenUntilMouseMoves(true)), the Clicky blue cursor companion kept rendering at full opacity — floating mid-screen while the system cursor was invisible. Every user who types sees this visual mismatch.

Root Cause

No typing-detection existed anywhere in the codebase. The CGEvent tap in GlobalPushToTalkShortcutMonitor already received every .keyDown event system-wide (it was already in the event mask), but silently dropped all non-PTT keystrokes.

Solution

Extend the existing event tap — no new taps, no new permissions needed.

GlobalPushToTalkShortcutMonitor.swift

  • New @Published var isUserTyping: Bool
  • In handleGlobalEventTap: set isUserTyping = true when eventType == .keyDown && shortcutTransition == .none (PTT combo uses .flagsChanged, never hits this path)

CompanionManager.swift

  • Forwards isUserTyping via Combine subscription
  • Exposes resetUserTyping() for BlueCursorView to call on mouse move

OverlayWindow.swift

  • New shouldHideForTyping computed property: isUserTyping && voiceState == .idle
  • Triangle opacity gate: && !shouldHideForTyping added
  • 16ms cursor-tracking timer: detects mouse movement >1pt and calls resetUserTyping() — mirrors the "until mouse moves" part of setHiddenUntilMouseMoves

Behavior

Scenario Before After
User types while cursor is visible (idle) Cursor stays visible Cursor hides
User moves mouse after typing Cursor stays hidden Cursor reappears
User presses PTT (ctrl+option) Voice activates Voice activates, cursor not hidden
Voice active (.listening/.processing/.responding) Waveform/spinner show Waveform/spinner stay visible

Testing

  • GIVEN Clicky cursor visible + voiceState idle, WHEN any key pressed, THEN cursor hides ✓
  • GIVEN cursor hidden by typing, WHEN mouse moves, THEN cursor reappears ✓
  • GIVEN user presses ctrl+option (PTT), THEN voice activates normally, no hide ✓
  • GIVEN voice active, WHEN user types, THEN waveform/spinner remain visible ✓

Closes #37

Mirrors macOS NSCursor.setHiddenUntilMouseMoves(true) behavior:
the Clicky cursor now hides on any keypress and reappears on mouse move.

- GlobalPushToTalkShortcutMonitor: publishes isUserTyping = true on any
  non-PTT keyDown event (CGEvent tap already received these; now acts on them)
- CompanionManager: forwards isUserTyping via Combine; exposes resetUserTyping()
- OverlayWindow: shouldHideForTyping gates triangle opacity during idle state;
  16ms cursor timer calls resetUserTyping() when mouse moves >1pt

PTT shortcut (ctrl+option) uses .flagsChanged not .keyDown — unaffected.
Voice interaction states (.listening/.processing/.responding) are never hidden.

Fixes farzaa#37

Co-Authored-By: Claude Sonnet 4.6 <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.

Make the cursor vanish

1 participant