Skip to content

FEAT(client): Use Input Monitoring instead of Accessibility for macOS…#7065

Open
nicholas-lonsinger wants to merge 1 commit intomumble-voip:masterfrom
nicholas-lonsinger:input-monitoring
Open

FEAT(client): Use Input Monitoring instead of Accessibility for macOS…#7065
nicholas-lonsinger wants to merge 1 commit intomumble-voip:masterfrom
nicholas-lonsinger:input-monitoring

Conversation

@nicholas-lonsinger
Copy link
Contributor

… global shortcuts

Replace the Accessibility permission requirement with the lesser Input Monitoring permission for macOS global shortcuts (Push-to-Talk). The event tap is now created in listen-only mode (kCGEventTapOptionListenOnly) which only requires Input Monitoring permission on macOS 10.15+.

Key changes:

  • Request CGRequestListenEventAccess() instead of Accessibility
  • Create listen-only event tap instead of active/suppressing tap
  • canSuppress() returns false, hiding the Suppress column (matches Windows/Linux behavior)
  • Update Settings UI to reference Input Monitoring permission
  • Open Input Monitoring privacy pane instead of Accessibility
  • Remove NSAccessibilityUsageDescription from plist

All existing suppression code is left intact but dormant, as it may be re-added or removed at a later point.

Checks

@coderabbitai
Copy link

coderabbitai bot commented Feb 3, 2026

Walkthrough

Updates macOS global-shortcut handling and docs to distinguish Input Monitoring (macOS 10.15+) from Accessibility (macOS 10.9–10.14). Adds runtime helpers to detect and request the appropriate permission, opens the correct privacy/settings pane, and updates UI text and buttons. Objective-C++ changes call the new permission flow at startup, switch the CGEventTap to listen-only, and disable event suppression. Info.plist usage text for accessibility was adjusted.

Possibly related issues

Possibly related PRs

Suggested labels

client, macOS

Suggested reviewers

  • Krzmbrzl
🚥 Pre-merge checks | ✅ 2
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately reflects the main change: switching macOS global shortcuts from Accessibility to Input Monitoring permission.
Description check ✅ Passed The PR description is comprehensive, clearly explaining the rationale, key changes, and implementation details while addressing the template's commit guidelines check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Tip

Issue Planner is now in beta. Read the docs and try it out! Share your feedback on Discord.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In `@src/mumble/GlobalShortcut_macx.mm`:
- Around line 138-140: Wrap the call to CGRequestListenEventAccess() in a
compile-time SDK guard so the symbol is only referenced when building against
macOS 10.15+ SDKs: add an `#if` check around the CGRequestListenEventAccess()
invocation that tests MAC_OS_X_VERSION_MAX_ALLOWED (or
MAC_OS_X_VERSION_MIN_REQUIRED) for MAC_OS_X_VERSION_10_15 (or uses an equivalent
macro check pattern used elsewhere in the codebase), keeping the existing
runtime __builtin_available(macOS 10.15, *) check intact; leave the
kCGEventTapOptionListenOnly usage as-is since it is available on older SDKs.

In `@src/mumble/GlobalShortcut.cpp`:
- Around line 642-653: The Input Monitoring UI text and prefs link are gated for
10.9+ (OSXMavericks) but must be limited to macOS 10.15+ to match
CMAKE_OSX_DEPLOYMENT_TARGET and showWarning() behavior; update the checks in
reload() and commit() to use a 10.15 version guard (e.g. current >=
QOperatingSystemVersion(10,15)) instead of OSXMavericks, and likewise guard
on_qpbOpenAccessibilityPrefs_clicked() so the Privacy_ListenEvent link is only
used when macOS 10.15+ is available (or wrap it with __builtin_available(macOS
10.15, *)). Repeat these changes for the other similar blocks (the sections
noted around the other ranges) and ensure label/qpbOpenAccessibilityPrefs text
and visibility are only set for 10.15+.
- Around line 672-684: The call to CGPreflightListenEventAccess() inside the
macOS runtime check must be wrapped with a compile-time SDK guard to avoid build
errors on older SDKs; modify the block containing __builtin_available(macOS
10.15, *) in GlobalShortcut.cpp so that the line calling
CGPreflightListenEventAccess() is only compiled when
MAC_OS_X_VERSION_MAX_ALLOWED >= 101500 (keep the existing __builtin_available
runtime check intact), and preserve the existing `#if`
MAC_OS_X_VERSION_MAX_ALLOWED >= 1090 else fallback
(AXIsProcessTrustedWithOptions / QFile check) so older SDKs and runtimes still
use the fallback paths.

@nicholas-lonsinger nicholas-lonsinger force-pushed the input-monitoring branch 2 times, most recently from cc056d5 to 9d7eb90 Compare February 4, 2026 05:08
@nicholas-lonsinger
Copy link
Contributor Author

The changes requested by code rabbit were to add more checks for architectures prior to the macOS build target of macOS 10.15.

I would recommend not doing these changes (In fact I removed the checks in a subsequent squash/force push) for the following reasons:

  • This code is dead and will not execute on the target build
  • Leaving in for backwards compatibility doesn't make sense as the feature is not backwards compatible either.
  • If true backwards compatibility was needed, then this should be re-coded to use Input Monitoring for macOS >= 10.15 and Accessibility for macOS < 10.15. I thought this solution would be overly complex and again unnecessary, but could be done if it was a requirement.

@nicholas-lonsinger nicholas-lonsinger force-pushed the input-monitoring branch 3 times, most recently from 901a034 to 291af77 Compare February 10, 2026 18:46
@nicholas-lonsinger
Copy link
Contributor Author

@coderabbitai review

@coderabbitai
Copy link

coderabbitai bot commented Feb 10, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/mumble/GlobalShortcut.cpp (1)

652-663: ⚠️ Potential issue | 🟡 Minor

eventFilter path may show the warning container with the button still hidden.

The eventFilter on WindowActivate (line 656) sets the warning container visible via showWarning(), but does not unhide qpbOpenInputMonitoringSettings. If the button was hidden in the constructor (line 643) and reload() never unhid it (e.g., permission was previously granted), a subsequent WindowActivate where showWarning() now returns true would display the warning text without the "Open Privacy Settings" button.

This is an unlikely edge case (would require revoking Input Monitoring while the settings dialog is open), but it would leave users with a warning and no actionable button.

Suggested fix: also manage button visibility in eventFilter
 	if (e->type() == QEvent::WindowActivate) {
 		if (!Global::get().s.bSuppressMacEventTapWarning) {
-			qwWarningContainer->setVisible(showWarning());
+			bool warn = showWarning();
+			qwWarningContainer->setVisible(warn);
+			if (warn) {
+				qpbOpenInputMonitoringSettings->setHidden(false);
+			}
 		}
 	}

Also applies to: 865-874

🧹 Nitpick comments (1)
src/mumble/GlobalShortcut_macx.mm (1)

65-170: Dead suppression logic in the callback — consider a clarifying comment.

With kCGEventTapOptionListenOnly, the return value of the callback is ignored by the system. The suppress variable computation (lines 69, 85, 120, 133) and the return suppress ? nullptr : event on line 170 are now effectively dead code. The PR description states this is intentionally preserved for future re-use.

A brief comment near line 69 or line 170 noting that suppression is dormant under listen-only mode would help future readers understand this is deliberate rather than an oversight.

Suggested clarifying comment
+	// Note: With kCGEventTapOptionListenOnly, the return value of this callback
+	// is ignored by the system. Suppression logic is retained for potential future
+	// reactivation with kCGEventTapOptionDefault.
 	return suppress ? nullptr : event;

…hortcuts

Use Input Monitoring permission instead of Accessibility for macOS global
shortcuts, with runtime fallback to Accessibility API for older systems.

This change:
- Uses @available runtime checks to select the appropriate permission API
  based on the running macOS version
- macOS 10.15+ (Catalina): Uses Input Monitoring API
  (CGPreflightListenEventAccess/CGRequestListenEventAccess)
- macOS 10.9 - 10.14: Falls back to Accessibility API
- Updates UI to reference the correct permission type
- Opens the correct System Settings pane for the detected API
- Helper functions in GlobalShortcut_macx.mm encapsulate version checks
  and are callable from C++ code via extern "C" linkage
- Adds proactive permission prompt for older macOS using
  AXIsProcessTrustedWithOptions with kAXTrustedCheckOptionPrompt,
  ensuring users see a system dialog on all supported versions
- Updates GlobalShortcuts.md documentation with version-specific
  instructions for both Input Monitoring and Accessibility permissions
- Adds Input Monitoring screenshot for documentation

This allows a single binary to support older deployment targets while
using the correct permission system at runtime.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@nicholas-lonsinger
Copy link
Contributor Author

nicholas-lonsinger commented Feb 10, 2026

I have two versions of this update, the current version includes support for the 1.5 branch and will use Input Monitoring by default but will switch to Accessibility on older < 10.15 version of Mac OS (probably very few people). This can help improve the security of the app on the older OS while preserving support.

If this is good then I would submit a second version of this just for the master branch that would be for the newer macOS version (currently oldest support is macOS 14), so it wouldn't need any reference to Accessibility.

If you just want to apply it to just the master though I can change it so it's only Input Monitoring based so it wouldn't need the dead code in there anymore.

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

Comments