I'm trying to create a Rust program that will ask for accessibility permission on macOS.
If the permission is granted (through Settings -> Privacy & Security -> Accessibility), then it works and returns true from AXIsProcessTrustedWithOptions
.
But if the permission is not allowed, instead of prompting to ask for the permission, the program crashes with a segfault.
It seems the settings dictionary is created incorrectly, but I'm not sure why.
I created it by following AXIsProcessTrustedWithOptions Apple's docs and tested it on macOS 14.4.1 (Apple silicon).
use accessibility_sys::AXIsProcessTrustedWithOptions;
use core_foundation_sys::base::{CFRelease, TCFTypeRef};
use core_foundation_sys::dictionary::{CFDictionaryAddValue, CFDictionaryCreateMutable};
use core_foundation_sys::number::kCFBooleanTrue;
use std::ffi::CString;
use std::ptr;
fn main() {
let mut is_allowed = false;
unsafe {
let options =
CFDictionaryCreateMutable(ptr::null_mut(), 1, std::ptr::null(), std::ptr::null());
let key = CString::new("AXTrustedCheckOptionPrompt").unwrap();
let value = kCFBooleanTrue;
CFDictionaryAddValue(options, key.as_ptr().as_void_ptr(), value.as_void_ptr());
is_allowed = AXIsProcessTrustedWithOptions(options);
CFRelease(options as *const _);
}
println!("Accessibility permission enabled: {}", is_allowed);
}
Thanks for the help in the comments, I used accessibility_sys::kAXTrustedCheckOptionPrompt
instead of my own CString and now it doesn't crash! also added error handling
use std::{error::Error, ptr};
use accessibility_sys::{kAXTrustedCheckOptionPrompt, AXIsProcessTrustedWithOptions};
use core_foundation_sys::dictionary::{CFDictionaryAddValue, CFDictionaryCreateMutable};
use core_foundation_sys::base::{CFRelease, TCFTypeRef};
use core_foundation_sys::number::{kCFBooleanFalse, kCFBooleanTrue};
fn check_accessibility(ask_if_not_allowed: bool) -> Result<bool, Box<dyn Error>> {
let is_allowed;
unsafe {
let options =
CFDictionaryCreateMutable(ptr::null_mut(), 0, std::ptr::null(), std::ptr::null());
let key = kAXTrustedCheckOptionPrompt;
let value = if ask_if_not_allowed {kCFBooleanTrue} else {kCFBooleanFalse};
if !options.is_null() {
CFDictionaryAddValue(
options,
key.as_void_ptr(),
value.as_void_ptr(),
);
is_allowed = AXIsProcessTrustedWithOptions(options);
CFRelease(options as *const _);
} else {
return Err("options is null".into());
}
}
Ok(is_allowed)
}
fn main() {
let is_allowed = check_accessibility(true).unwrap();
println!("Accessibility permission enabled: {}", is_allowed);
}