feat(audio,macos): live IOHIDCheckAccess for Input Monitoring permission
Replaces the macOS PTT backend's query_permission() stub (which had
returned Undetermined unconditionally) with a real IOKit call:
extern "C" { fn IOHIDCheckAccess(request_type: u32) -> u32; }
IOHIDCheckAccess(kIOHIDRequestTypeListenEvent = 1)
Returns Granted (0), Denied (1), or Unknown (2). The existing 1.5 s
re-query worker now drives real descriptor transitions when the user
grants or revokes Input Monitoring in System Settings: the watch
sender republishes the descriptor, ChanoraSession forwards
BridgeEvent::PttCapability, and the Flutter capability badge updates
within ~1.5 s without an app restart.
Verified live on the M1 Mac:
rustc /tmp/check_perm.rs && ./check_perm
IOHIDCheckAccess(ListenEvent) = 2 (Unknown)
This is the expected initial state on a fresh box where Chanora has
not yet attempted CGEventTapCreate; once the next commit lands the
event-tap worker, the macOS Input Monitoring prompt will fire on
first audio start and the value transitions to Granted/Denied.
Tests: chanora_audio 28 / 0 / 0 on macOS (Linux had 32; the 4-test
delta is the Linux-only portal probe tests). The existing 7 macOS
backend unit tests still cover the descriptor builder + state
machine purely; they don't exercise the live IOKit call (which
would need a TCC-aware test harness).
SDD-085 reference: macOS Event Tap backend / L2 / L3 capability;
SRS-198 honest capability advertising.
This commit is contained in:
@@ -58,15 +58,31 @@ impl PermissionState {
|
||||
}
|
||||
|
||||
fn query_permission() -> PermissionState {
|
||||
// Live `IOHIDCheckAccess` query lands in the macOS platform
|
||||
// verification commit (it needs the IOKit framework link).
|
||||
// Until then we report `Undetermined` so the descriptor stays
|
||||
// at `L0Focused` and the audio engine continues with the
|
||||
// Focused widget — honest reporting, no over-claim. The
|
||||
// periodic re-query loop below still exercises the watch
|
||||
// sender path so a future replacement of this function
|
||||
// automatically engages the runtime upgrade.
|
||||
PermissionState::Undetermined
|
||||
// Live IOHIDCheckAccess query against the IOKit HID subsystem.
|
||||
// The Input Monitoring permission ("Listen Event" access type)
|
||||
// is what gates CGEventTap from receiving global key/mouse
|
||||
// events. Returns the live permission state every call; the
|
||||
// periodic re-query loop in `MacOSEventTapBackend::start`
|
||||
// republishes the descriptor whenever this value transitions.
|
||||
//
|
||||
// SAFETY: IOHIDCheckAccess is a thread-safe synchronous IOKit
|
||||
// entry point with no side effects beyond reading a system
|
||||
// preference. The `#[link]` attribute on the extern block
|
||||
// resolves at build time against the IOKit framework. The u32
|
||||
// return value maps directly onto the documented
|
||||
// IOHIDAccessType enumerator { Granted=0, Denied=1, Unknown=2 }.
|
||||
#[link(name = "IOKit", kind = "framework")]
|
||||
extern "C" {
|
||||
fn IOHIDCheckAccess(request_type: u32) -> u32;
|
||||
}
|
||||
// kIOHIDRequestTypeListenEvent == 1 per IOHIDLib.h.
|
||||
const REQUEST_TYPE_LISTEN_EVENT: u32 = 1;
|
||||
let raw = unsafe { IOHIDCheckAccess(REQUEST_TYPE_LISTEN_EVENT) };
|
||||
match raw {
|
||||
0 => PermissionState::Granted,
|
||||
1 => PermissionState::Denied,
|
||||
_ => PermissionState::Undetermined,
|
||||
}
|
||||
}
|
||||
|
||||
/// Try to construct the macOS event-tap backend. Returns `None`
|
||||
|
||||
Reference in New Issue
Block a user