mirror of
https://github.com/feschber/lan-mouse.git
synced 2026-05-08 15:18:05 +03:00
macos: drop the CapturePane / EmulationPane enums
Now that we always route Reenable clicks to the Accessibility pane on macOS 13+ (AX transitively covers Input Monitoring listen-only and Post Event, and the bundle isn't listed in the separate panes anyway), the CapturePane / EmulationPane enums and their non-Accessibility variants are dead weight. Remove them along with: - `missing_capture_pane` / `missing_emulation_pane` - `open_input_monitoring_settings` / `open_post_event_settings` - `input_monitoring_granted` / `post_event_granted` preflight wrappers - the `CGPreflightListenEventAccess` / `CGPreflightPostEventAccess` FFI declarations in lan-mouse-gtk (the daemon crates keep their own) `handle_capture` / `handle_emulation` collapse to a single helper that opens the Accessibility pane if AX is missing, otherwise just retries. `ensure_listed_in_input_monitoring` is kept because it still has a side effect on macOS 13/14, where Input Monitoring is a separately- granted category. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
committed by
Ferdinand Schober
parent
b3cade9bac
commit
8a444f98dd
@@ -2,10 +2,12 @@
|
||||
|
||||
//! Tiny macOS Privacy-pane helpers used by the GUI.
|
||||
//!
|
||||
//! Clicking "Reenable" on the capture/emulation warning row should take the
|
||||
//! user to whichever Privacy pane is actually missing a grant — opening the
|
||||
//! Accessibility pane when the user has already granted Accessibility (and
|
||||
//! only needs Input Monitoring) is confusing and hides the real request.
|
||||
//! On macOS 13+, the Accessibility grant transitively confers the
|
||||
//! listen-only event-tap privilege that Input Monitoring gates and the
|
||||
//! synthesize-event privilege that Post Event gates, and the bundle
|
||||
//! typically isn't even listed in those separate panes. So the single
|
||||
//! user-facing action for any missing-capture or missing-emulation
|
||||
//! scenario is "re-toggle Accessibility" — we don't route elsewhere.
|
||||
|
||||
use std::ffi::{c_uchar, c_void};
|
||||
use std::process::Command;
|
||||
@@ -48,9 +50,7 @@ extern "C" {
|
||||
|
||||
#[link(name = "CoreGraphics", kind = "framework")]
|
||||
extern "C" {
|
||||
fn CGPreflightListenEventAccess() -> c_uchar;
|
||||
fn CGRequestListenEventAccess() -> c_uchar;
|
||||
fn CGPreflightPostEventAccess() -> c_uchar;
|
||||
fn CGRequestPostEventAccess() -> c_uchar;
|
||||
|
||||
// CFMachPortRef CGEventTapCreate(
|
||||
@@ -73,67 +73,6 @@ pub fn accessibility_granted() -> bool {
|
||||
raw != 0
|
||||
}
|
||||
|
||||
pub fn input_monitoring_granted() -> bool {
|
||||
let raw = unsafe { CGPreflightListenEventAccess() };
|
||||
log::debug!("CGPreflightListenEventAccess() = {raw}");
|
||||
raw != 0
|
||||
}
|
||||
|
||||
pub fn post_event_granted() -> bool {
|
||||
let raw = unsafe { CGPreflightPostEventAccess() };
|
||||
log::debug!("CGPreflightPostEventAccess() = {raw}");
|
||||
raw != 0
|
||||
}
|
||||
|
||||
// Variants `InputMonitoring` and `PostEvent` are currently never returned
|
||||
// by `missing_capture_pane` / `missing_emulation_pane` — on macOS 13+ those
|
||||
// categories auto-grant via Accessibility and the bundle typically isn't
|
||||
// listed in those separate panes, so routing users there is a dead end.
|
||||
// Kept in the enum so older-macOS behavior can be restored without a
|
||||
// structural change.
|
||||
#[allow(dead_code)]
|
||||
pub enum CapturePane {
|
||||
Accessibility,
|
||||
InputMonitoring,
|
||||
/// Everything is already granted; the caller should just retry.
|
||||
None,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub enum EmulationPane {
|
||||
Accessibility,
|
||||
PostEvent,
|
||||
None,
|
||||
}
|
||||
|
||||
pub fn missing_capture_pane() -> CapturePane {
|
||||
if !accessibility_granted() {
|
||||
CapturePane::Accessibility
|
||||
} else if !input_monitoring_granted() {
|
||||
// On macOS 13+, Accessibility trust confers the listen-only
|
||||
// event-tap privilege that Input Monitoring gates, and on Sequoia
|
||||
// the bundle typically isn't listed in the Input Monitoring pane
|
||||
// at all. The actionable fix when IM preflight is still 0 is to
|
||||
// re-toggle Accessibility, so send the user there rather than to
|
||||
// an empty IM list.
|
||||
CapturePane::Accessibility
|
||||
} else {
|
||||
CapturePane::None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn missing_emulation_pane() -> EmulationPane {
|
||||
if !accessibility_granted() {
|
||||
EmulationPane::Accessibility
|
||||
} else if !post_event_granted() {
|
||||
// Post Event is nested under Accessibility on modern macOS and
|
||||
// auto-grants alongside it. Point the user back to Accessibility
|
||||
// for the same reason as the capture case above.
|
||||
EmulationPane::Accessibility
|
||||
} else {
|
||||
EmulationPane::None
|
||||
}
|
||||
}
|
||||
|
||||
/// Poll for an Accessibility grant transition. Starts a 1-second GLib
|
||||
/// timer that fires `on_granted` once, the first time
|
||||
@@ -165,20 +104,6 @@ pub fn open_accessibility_settings() {
|
||||
open_url("x-apple.systempreferences:com.apple.preference.security?Privacy_Accessibility");
|
||||
}
|
||||
|
||||
pub fn open_input_monitoring_settings() {
|
||||
unsafe {
|
||||
ensure_listed_in_input_monitoring();
|
||||
}
|
||||
open_url("x-apple.systempreferences:com.apple.preference.security?Privacy_ListenEvent");
|
||||
}
|
||||
|
||||
pub fn open_post_event_settings() {
|
||||
unsafe {
|
||||
CGRequestPostEventAccess();
|
||||
}
|
||||
open_url("x-apple.systempreferences:com.apple.preference.security?Privacy_PostEvent");
|
||||
}
|
||||
|
||||
/// Make sure the app appears in System Settings → Privacy → Input Monitoring.
|
||||
///
|
||||
/// `CGRequestListenEventAccess()` is *supposed* to register the app in the
|
||||
|
||||
@@ -10,6 +10,16 @@ use lan_mouse_ipc::{DEFAULT_PORT, FrontendRequestWriter};
|
||||
|
||||
use crate::authorization_window::AuthorizationWindow;
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
fn open_accessibility_if_missing(ctx: &str) {
|
||||
if crate::macos_privacy::accessibility_granted() {
|
||||
log::info!("{ctx}: Accessibility already granted, retry only");
|
||||
} else {
|
||||
log::info!("{ctx}: opening Accessibility pane");
|
||||
crate::macos_privacy::open_accessibility_settings();
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(CompositeTemplate, Default)]
|
||||
#[template(resource = "/de/feschber/LanMouse/window.ui")]
|
||||
pub struct Window {
|
||||
@@ -143,44 +153,14 @@ impl Window {
|
||||
#[template_callback]
|
||||
fn handle_emulation(&self) {
|
||||
#[cfg(target_os = "macos")]
|
||||
{
|
||||
use crate::macos_privacy::{self, EmulationPane};
|
||||
match macos_privacy::missing_emulation_pane() {
|
||||
EmulationPane::Accessibility => {
|
||||
log::info!("Reenable emulation: opening Accessibility pane");
|
||||
macos_privacy::open_accessibility_settings();
|
||||
}
|
||||
EmulationPane::PostEvent => {
|
||||
log::info!("Reenable emulation: opening Post Event pane");
|
||||
macos_privacy::open_post_event_settings();
|
||||
}
|
||||
EmulationPane::None => {
|
||||
log::info!("Reenable emulation: both grants present, retry only");
|
||||
}
|
||||
}
|
||||
}
|
||||
open_accessibility_if_missing("Reenable emulation");
|
||||
self.obj().request_emulation();
|
||||
}
|
||||
|
||||
#[template_callback]
|
||||
fn handle_capture(&self) {
|
||||
#[cfg(target_os = "macos")]
|
||||
{
|
||||
use crate::macos_privacy::{self, CapturePane};
|
||||
match macos_privacy::missing_capture_pane() {
|
||||
CapturePane::Accessibility => {
|
||||
log::info!("Reenable capture: opening Accessibility pane");
|
||||
macos_privacy::open_accessibility_settings();
|
||||
}
|
||||
CapturePane::InputMonitoring => {
|
||||
log::info!("Reenable capture: opening Input Monitoring pane");
|
||||
macos_privacy::open_input_monitoring_settings();
|
||||
}
|
||||
CapturePane::None => {
|
||||
log::info!("Reenable capture: both grants present, retry only");
|
||||
}
|
||||
}
|
||||
}
|
||||
open_accessibility_if_missing("Reenable capture");
|
||||
self.obj().request_capture();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user