Re-enable the event tap when the system disables it; verify installer checksum - #17
Open
vipergsm wants to merge 2 commits into
Open
Re-enable the event tap when the system disables it; verify installer checksum#17vipergsm wants to merge 2 commits into
vipergsm wants to merge 2 commits into
Conversation
macOS disables an event tap on .tapDisabledByTimeout or .tapDisabledByUserInput. The callback treated both as no-ops, so parrot kept running with a dead tap: the menu bar icon stayed put, the menu still read "idle - hold fn to dictate", and fn silently did nothing until the user noticed and restarted. For a daemon meant to sit in the menu bar for days that is a hard failure mode to diagnose. Re-enable the tap from the main run loop (the one that owns it) and log a line to stderr so the event is visible. Also narrow the mask. Only .flagsChanged is ever acted on -- handle() discards everything else on its first line -- but the tap subscribed to keyDown and keyUp as well, so every keystroke system-wide caused an event.copy() and a main-queue dispatch for nothing. Beyond the wasted work, that raises the odds of the very timeout above, and needlessly routes typed content (including password fields) through an Accessibility-privileged process. keyDown/keyUp are still subscribed under --debug-hotkey, where they are actually used.
The release workflow already builds and uploads parrot-macos-arm64.tar.gz.sha256, but install.sh never fetched it. The script is invoked as `curl | sh`, downloads an unsigned binary, strips its quarantine attribute and moves it into /usr/local/bin -- with the checksum sitting unused two lines away. Fetch and verify it.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two independent fixes found while reading the source before installing parrot on a Mac mini. Happy to split them into separate PRs if you'd prefer.
Built and running locally with both applied (
swift build -c release, Swift 6.3, macOS 26.5, M-series).1. The event tap is never re-enabled
macOS disables an event tap on
.tapDisabledByTimeoutor.tapDisabledByUserInput. The callback treats both as no-ops:The comment is honest about it, but the failure is silent and hard to attribute: parrot keeps running, the menu bar icon stays put, the menu still reads "idle · hold fn to dictate" — and
fndoes nothing. For something designed to sit in the menu bar for days, the first symptom is usually "dictation stopped working at some point and I don't know when".This calls
CGEvent.tapEnable(tap:enable:true)from the main run loop (the one that owns the tap) and writes a line to stderr so the event is at least visible.2. The tap subscribes to every keystroke and uses none of them
The mask registers
flagsChanged | keyDown | keyUp, buthandle()discards everything else on its first line:So every keystroke system-wide causes an
event.copy()and a main-queue dispatch that does nothing. Three costs: needless main-thread work, a higher chance of triggering exactly the timeout above, and typed content — including password fields — passing through a process that holds Accessibility permission. It's.listenOnlyand entirely local, so nothing leaves the machine; it's just avoidable surface area for a background daemon.keyDown/keyUpare still subscribed under--debug-hotkey, where they're genuinely used.3.
install.shpublishes a SHA256 it never checksrelease.ymlbuilds and uploadsparrot-macos-arm64.tar.gz.sha256.install.shnever fetches it. The script runs ascurl | sh, downloads an unsigned binary, strips its quarantine attribute and moves it into/usr/local/bin— with the checksum sitting unused two lines away. Four lines to close.Separately, and not something for this PR: it might be worth a README note that under
parrot install --launch-at-loginthe daemon needs its own Accessibility and Microphone grants, distinct from the ones granted to the terminal — and that because the binary is unsigned, TCC keys those grants to the binary hash, so every update invalidates them. It presents as "I updated and it stopped working, butdoctorsays everything is fine", sincedoctorrun from a terminal is checking the terminal's grants, not the daemon's.