Repository navigation
fix: menu-bar icon draws blank in the error states, and a missing grant reports as a missing pad - #9
Open
mmorrison wants to merge 2 commits into
Conversation
keyboard.badge.exclamationmark is not an SF Symbol. It is absent from CoreGlyphs' name_availability.plist entirely, so NSImage(systemSymbolName:) returns nil for it on every macOS, and the compose path falls back to an empty NSImage - leaving the menu bar showing the status dot on its own with no keyboard behind it. It only affects .permissionDenied and .deviceMissing, which are the two states where the icon most needs to be findable, so the app appears to vanish from the menu bar at exactly the moment something is wrong. The healthy states use keyboard (10.15) and keyboard.fill (12.0), which is why this stays hidden in normal use. Move the symbol names to WLKit so a test can assert they all resolve on the running system, use keyboard.badge.ellipsis for the problem states (macOS 11.0, under the package's 13.0 floor), and fall back to the plain keyboard rather than to a blank image so an unresolvable name can never blank the icon again.
mmorrison
force-pushed
the
fix/menu-bar-icon-and-permission-diagnosis
branch
from
September 1, 2026 14:33
7f2489e to
28c11b4
Compare
IOHIDDeviceOpen answers kIOReturnNotPermitted (0xE00002E2) both when the Input Monitoring grant is missing and when the pad is already held or has wedged, so the error code cannot be what decides between them. The check here only recognised the older 0xE00002C1, so on current systems a permissions failure fell through to the generic branch and the menu said "Looking for the pad" - which sends you hunting for a cable when the answer is a checkbox. The 0xE00002C1 reading is also a leftover from before d2e7c86 ("open the HID device shared instead of seized"), where that code meant a refused seize rather than a refused grant. Consult IOHIDCheckAccess, which is the only caller that actually knows the state of the grant, and keep believing an error that names a permission outright in case the check is stale. Each case now names what to do next rather than printing a bare error code.
mmorrison
force-pushed
the
fix/menu-bar-icon-and-permission-diagnosis
branch
from
September 1, 2026 14:44
28c11b4 to
ed47081
Compare
This branch has not been deployed
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 bugs, both found while setting the app up on a Creator Micro 2. Each is one commit, and neither changes any behaviour that currently works.
1. The menu-bar icon draws blank in the error states
keyboard.badge.exclamationmarkis not an SF Symbol. Not "not on older systems" - it is absent fromname_availability.plistentirely, soNSImage(systemSymbolName:)returns nil for it everywhere, and the compose path inMenuBarIcon.image(for:)falls back to an emptyNSImage. The menu bar ends up showing the status dot on its own with no keyboard behind it.It only affects
.permissionDeniedand.deviceMissing. Every healthy state useskeyboard(macOS 10.15) orkeyboard.fill(12.0), which both resolve, so it stays invisible in normal use and appears precisely when something has gone wrong and you are hunting for the icon to find out what.What this does:
WLKitasIconSymbols, so a test can assert every name the icon draws actually resolveskeyboard.badge.ellipsisfor the problem states: available since macOS 11.0, comfortably under the package's macOS 13 floor, and it keeps the keyboard shape so the icon stays findable in a crowded menu bar2. A missing Input Monitoring grant reports as a missing pad
IOHIDDeviceOpenanswerskIOReturnNotPermitted(0xE00002E2) both when the grant is missing and when the pad is already held or has wedged, so the error code alone cannot tell them apart.openDevice()only recognises the older0xE00002C1, so on current systems a permissions failure falls through to the generic branch and the menu says "Looking for the pad".That is an expensive wrong answer: it sends you checking cables and reseating hardware when the fix is a checkbox in System Settings. I lost a while to it before reading the source.
The
0xE00002C1reading also looks like a leftover from before d2e7c86 ("open the HID device shared instead of seized"), where that code meant a refused seize rather than a refused grant.What this does:
IOHIDCheckAccess, the only API that actually knows the state of the grant, instead of pattern-matching the error codeTesting
swift testpasses locally: 89 tests, 4 skipped (the live-device ones, no pad attached to the test binary). The two new suites are 7 of those.Both fixes were verified against the failing case first. The icon test fails on
keyboard.badge.exclamationmarkbefore the change, and the classifier test covers the case that misled me, which is the same error code with the grant already in place resolving to a device problem rather than a permission one.On CI specifically: the icon test asserts symbol availability on whatever it runs on, so I checked the versions rather than assuming. Every symbol it now names is available on macOS 11.0 or earlier, so it holds on the macos-14 runner and on the package's macOS 13 minimum.
Happy to split these into two PRs if you would rather take them separately.