Skip to content

fix: media-key tap no longer captures other devices' volume/mute keys - #6

Open
greghughespdx wants to merge 1 commit into
machinarii:mainfrom
greghughespdx:fix/media-key-passthrough
Open

fix: media-key tap no longer captures other devices' volume/mute keys#6
greghughespdx wants to merge 1 commit into
machinarii:mainfrom
greghughespdx:fix/media-key-passthrough

Conversation

@greghughespdx

Copy link
Copy Markdown

Summary

Stops the media-key interceptor from capturing volume/mute/media keys that belong to other input devices. While HyperVibe is running today, every keyboard's volume keys, mute key, and volume HUD stop working normally — this fixes that.

Problem

MediaKeyInterceptor installs a system-wide HID event tap for media keys. At that level there is no device identity: the tap sees the same events for a Magic Keyboard's volume keys as for anything remote-related. The current handler then:

  1. Routes any media key from any device into the app's remote button mappings — so a keyboard's volume-up key executes whatever the remote's volume-up button is mapped to
  2. Consumes every media-key event unconditionally, even when no mapping exists — so the keyboard's mute key does nothing at all, and the system volume HUD never appears

The result is that simply having HyperVibe running breaks normal keyboard volume/mute behavior system-wide. This also silently eats media-key events synthesized by other software.

Solution

Invert the consume condition. The interceptor now consumes an event only when it correlates with a button press just observed on the remote's own seized HID interface (the existing 0.2s debounce check) — those are remote-origin duplicates whose action the HID path already executed, and macOS's default handling shouldn't also fire for them. Every other media-key event passes through untouched, restoring native volume, mute, and HUD behavior for all other devices.

The mapping-execution path is removed from the interceptor entirely: remote buttons are already handled by the seized HID interface, so the tap's only remaining job is suppressing remote-origin duplicates.

One deliberate behavior change: if the app ever fails to seize the remote, its presses now fall through to macOS default media handling instead of executing the mapped action. That's the correct failure mode — events the app doesn't own are no longer trapped.

Testing

  • Reproduced on a Mac Studio: with the current code running, keyboard volume keys execute remote mappings, mute is dead, no HUD
  • After the fix: keyboard volume/mute/HUD fully native while the app runs
  • Verified pass-through directly: a synthesized volume-key event reaches macOS and steps the volume normally with the app running
  • Remote buttons unaffected (still handled via the seized HID interface)

The system-wide media-key tap has no device identity, so it was routing
every keyboard's volume keys into the remote's button mappings and
consuming mute/volume events unconditionally - breaking native keyboard
volume, mute, and the volume HUD whenever the app was running.

Consume only events correlated with a press just seen on the remote's
seized HID interface (remote-origin duplicates the HID path already
handled); pass everything else through untouched.
JamesZwq added a commit to JamesZwq/hypervibe that referenced this pull request Jul 20, 2026
- ConfigStore.save now REFUSES to overwrite an on-disk config that doesn't parse (a hand-edit typo
  the app is running the fallback for), and backs up config.jsonc→.bak before any overwrite — so a
  UI gesture can no longer erase all bindings by writing fallback-derived content (fable machinarii#1).
- Layer 'used' marking moved above the Spaces/repeatKey early-returns and wired into the select /
  swipe / two-finger paths, so hold-layer + repeat-key/click/gesture is momentary, not a false
  sticky toggle (fable machinarii#2).
- Track the sticky-activator button so re-tapping toggles OFF even when the .layer binding isn't
  visible from inside the layer's own inherits chain (fable machinarii#3).
- Hot-reload clears a sticky layer whose mode was deleted/renamed (else all keys resolve nil with
  no way to pop) (fable machinarii#4). Disconnect now KEEPS the sticky layer (BLE idle-disconnect shouldn't
  drop it) and only unwinds the momentary hold (fable machinarii#8). Pending double-tap singles are cancelled
  on disconnect (fable machinarii#6, partial).

Co-Authored-By: Claude Opus 4.8 (1M context) <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.

1 participant