Guarantee menu bar reachability, fix reconnect state, and add quality-of-life features - #30
Open
distractedhero wants to merge 11 commits into
Open
distractedhero wants to merge 11 commits into
distractedhero wants to merge 11 commits into
Conversation
The status item can silently fail to show up in the menu bar even when there is free space (no overflow chevron, not crowded) -- confirmed by screenshot while diagnosing this against upstream DParent10#9 and DParent10#11, which also both report the icon simply never appearing. - Give the status item a stable autosaveName so AppKit can persist and restore its slot across launches instead of treating it as a fresh, position-less item every time. This is the maintainer's own leading theory in both linked issues. - Replace the one-shot, UserDefaults-gated first-launch alert with a check that runs on every launch. If the item is genuinely visible, show the popover once per install as before. If it isn't, guarantee a way in: temporarily switch to .regular activation policy and open a real window hosting the same content, instead of an alert that a process with no Dock icon and no visible menu bar item may never be able to reliably present. The activation policy reverts to .accessory when that window is closed.
Once the one-time first-launch popover had fired, double-clicking NagaController again (or `open`-ing it, or clicking a Dock icon) did nothing visible — the process was already running and had no other way to surface UI, which reads as "the app doesn't open." Implement applicationShouldHandleReopen to bring the popover (or the fallback window, if the status item never rendered) forward every time the app is reopened, not just on the very first launch. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Ad-hoc signing (`codesign --sign -`) derives the code identity from the binary's own hash, so it's different on every single build. macOS ties Accessibility and Input Monitoring grants to that identity, so every rebuild silently revoked both and forced a re-grant in System Settings before the app could read the mouse's HID input again. Prefer any local codesigning identity already in the keychain (a real certificate, tied to a Team ID rather than the binary's content) and only fall back to ad-hoc when none exists. Override via NAGA_CODESIGN_IDENTITY. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…ailure The status item can silently fail to render with no icon and no overflow chevron, reproduced live on a stock, notarized v0.2.2 release. AppKit's own visibility flags (statusItem.isVisible, button.window?.isVisible) don't reliably reflect that failure — they reported the item as visible in the same session where it plainly wasn't on screen. A fix built on detecting the failure is therefore not trustworthy. Stop trying to detect it. Switch LSUIElement to false so the app always has a Dock icon, and always show the main window on launch and on reopen (double-click, `open`, clicking the Dock icon), independent of whatever the menu bar is doing. The status item is still created as a convenience for the (apparently more common) case where it does work, but it's no longer the only way in. This is a bigger behavioral change than a bug fix — a persistent Dock icon changes the app's default feel from "background menu-bar utility" to "regular app" — so it's not proposed upstream yet pending discussion with the maintainer. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Every comparable menu-bar utility has this; NagaController didn't. Uses SMAppService (macOS 13+, already the app's stated minimum), so no helper app or legacy SMLoginItem bookkeeping is needed. A checkbox next to the existing remapping toggle mirrors SMAppService.mainApp.status on open and registers/unregisters on change. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The user guide already admits the toggle-mode Hypershift state is easy to lose track of — that's the documented reason the long-hold force-deactivate safety valve exists. A HUD is the other half of that fix: something visible at the moment it toggles, not just a menu bar title text change that requires already knowing to look for it (and which the current status-item rendering issues make an unreliable place to put state anyway). HUDNotifier is a small, dependency-free borderless window, reused singleton-style so a second call just replaces what's showing rather than stacking. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Verifying a shell command, app launch, or macro mapping meant saving it and then physically pressing the mouse button — awkward mid-edit, and impossible for triggers not yet learned. Test runs buildActionFromUI()'s result once through ButtonMapper immediately, unsaved, the same builder Save already uses. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
IOHIDManagerRegisterDeviceMatchingCallback was registered without its counterpart, IOHIDManagerRegisterDeviceRemovalCallback, so nothing cleared lastDPI/lastDPIDirection, the synthetic button-down states, or the pointer router across a Bluetooth drop, sleep/wake, or dongle reseat. The user guide already claims a fresh DPI baseline gets recorded "after launching the app or reconnecting the mouse" — that was only ever true for launch. A button physically held down at the moment of disconnect also never got its release, leaving it stuck. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Profiles are importable from any JSON file, and a systemCommand action runs on the mouse button press with no per-press confirmation. A shared profiles.json (someone's public "Naga setup", found online) could carry one silently. Split the decode step out of importProfiles so the caller can inspect a file before committing to it, and warn with a count when it contains shell-command actions. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Every version bump otherwise requires noticing a new GitHub release by hand. Hits the releases API at most once a day, compares semver tags, and posts a notification MainViewController's banner listens for — no auto-download, no auto-install, just visibility. Deliberately not Sparkle: a full auto-update framework is a lot of dependency and maintenance surface for what a one-line version check mostly solves. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
A "Changes on this branch" section, separate from the general Features list, so anyone looking at this fork can see at a glance what's here beyond upstream v0.2.2 and why — without digging through commit messages. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
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.
Summary
Two open issues (#9, #11) report the app running with no visible menu bar icon and no other way in. I reproduced this live, including on a fresh copy of the official notarized v0.2.2 release — not a build issue on my end — with no third-party menu-bar manager involved and a normal, single-display notched MacBook. AppKit's own visibility flags (
statusItem.isVisible,button.window?.isVisible) reported the item as present in the same session where it plainly wasn't rendering, so a fix that depends on detecting the failure isn't trustworthy. This PR stops trying to detect it and guarantees reachability unconditionally instead, then adds a handful of small, contained quality-of-life features on top.Reliability fixes
LSUIElement→false): the app always has a Dock icon now, and always shows its main window on launch and on reopen (double-click,open, clicking the Dock icon) — independent of whether the menu bar item renders. The status item is still created as a convenience for the (apparently more common) case where it works.Scripts/build_app.shnow prefers any local codesigning identity already in the keychain over ad-hoc (codesign --sign -). Ad-hoc signing derives a fresh, content-based identity on every build, so a rebuild silently revoked previously-granted Accessibility/Input Monitoring — this fix keeps grants stable across rebuilds. (Doesn't affect your release signing, which is already Developer ID.)HIDListenerregistered a device-matching callback but never a removal one, solastDPI/lastDPIDirectionand in-flight button-press state survived a Bluetooth drop, sleep/wake, or dongle reseat. The user guide already claims a fresh baseline gets recorded "after launching the app or reconnecting the mouse" — that was only ever true for launch. Now actually true for reconnects too, and a button physically held at disconnect no longer gets stuck "down."Quality-of-life additions
SMAppService(macOS 13+, already the stated minimum), no helper app needed.systemCommandaction runs with no per-press confirmation. A sharedprofiles.jsonfound online could otherwise silently bind a button to arbitrary shell code. Now warns with a count before committing an import that contains one.Testing
SMAppServicestatus query and the update-check network call both fire correctly in the unified log, no crashes or faults.Happy to split this into smaller PRs if that's easier to review — the reliability fixes and the QoL additions are reasonably separable, they just happened to land in one investigation session.