├── .gitignore ├── Cargo.toml ├── README.md ├── build.rs ├── doc └── prompt.png └── src └── lib.rs /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | Cargo.lock 3 | .idea 4 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "macos-accessibility-client" 3 | description = "Wrapper around macOS' accessibility client APIs" 4 | repository = "https://github.com/next-slide-please/macos-accessibility-client" 5 | version = "0.0.1" 6 | authors = ["Lucas Jenß"] 7 | categories = ["os::macos-apis", "accessibility"] 8 | edition = "2018" 9 | license = "Apache-2.0" 10 | build = "build.rs" 11 | 12 | [dependencies] 13 | core-foundation = "0.9" 14 | core-foundation-sys = "0.8" 15 | 16 | [package.metadata.docs.rs] 17 | default-target = "x86_64-apple-darwin" -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # macOS accessibility client 2 | 3 | This crate, in its current state, only provides the functionality to query whether the running application is a trusted accessibility client, and if not, display the following rather well known prompt: 4 | 5 | Screenshot of macOS accessibility prompt 6 | 7 | More functionality may be added in the future. Feel free to open an issue if you think there's something missing. 8 | 9 | How to use: 10 | 11 | ```rust 12 | #[cfg(target_os = "macos")] 13 | fn query_accessibility_permissions() -> bool { 14 | let trusted = macos_accessibility_client::accessibility::application_is_trusted_with_prompt(); 15 | if trusted { 16 | print!("Application is totally trusted!"); 17 | } else { 18 | print!("Application isn't trusted :("); 19 | } 20 | return trusted 21 | } 22 | 23 | #[cfg(not(target_os = "macos"))] 24 | fn query_accessibility_permissions() -> bool { 25 | print!("Who knows... 🤷‍♀️"); 26 | return true 27 | } 28 | ``` 29 | 30 | 31 | ## License 32 | 33 | Copyright 2021 Lucas Jenß 34 | 35 | Licensed under the Apache License, Version 2.0 (the "License"); 36 | you may not use this file except in compliance with the License. 37 | You may obtain a copy of the License at 38 | 39 | http://www.apache.org/licenses/LICENSE-2.0 40 | 41 | Unless required by applicable law or agreed to in writing, software 42 | distributed under the License is distributed on an "AS IS" BASIS, 43 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 44 | See the License for the specific language governing permissions and 45 | limitations under the License. -------------------------------------------------------------------------------- /build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | if std::env::var("TARGET").unwrap().contains("-apple") { 3 | println!("cargo:rustc-link-lib=framework=ApplicationServices"); 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /doc/prompt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/next-slide-please/macos-accessibility-client/03025a91c471d4a115ad116739a8576216e527e2/doc/prompt.png -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_snake_case)] 2 | 3 | /// Raw C-bindings for some of Apple's accessibility API. See [Apple's documentation](https://developer.apple.com/documentation/applicationservices/axuielement_h?language=objc#overview) 4 | pub mod raw { 5 | use core_foundation::string::CFStringRef; 6 | use core_foundation_sys::base::Boolean; 7 | use core_foundation_sys::dictionary::CFDictionaryRef; 8 | 9 | extern "C" { 10 | pub static kAXTrustedCheckOptionPrompt: CFStringRef; 11 | 12 | pub fn AXIsProcessTrusted() -> Boolean; 13 | pub fn AXIsProcessTrustedWithOptions(theDict: CFDictionaryRef) -> Boolean; 14 | 15 | } 16 | } 17 | 18 | /// Wrapped bindings to some of Apple's accessibility client API. 19 | pub mod accessibility { 20 | use core_foundation::base::TCFType; 21 | use core_foundation::boolean::CFBoolean; 22 | use core_foundation::dictionary::CFDictionary; 23 | use core_foundation::string::CFString; 24 | 25 | use crate::raw::{ 26 | kAXTrustedCheckOptionPrompt, AXIsProcessTrusted, AXIsProcessTrustedWithOptions, 27 | }; 28 | 29 | /// Checks whether or not this application is a trusted accessibility client. 30 | pub fn application_is_trusted() -> bool { 31 | unsafe { 32 | return AXIsProcessTrusted() != 0; 33 | } 34 | } 35 | 36 | /// Same as [application_is_trusted], but also shows the user a prompt asking 37 | /// them to allow accessibility API access if it hasn't already been given. 38 | pub fn application_is_trusted_with_prompt() -> bool { 39 | unsafe { 40 | let option_prompt = CFString::wrap_under_get_rule(kAXTrustedCheckOptionPrompt); 41 | let dict: CFDictionary = 42 | CFDictionary::from_CFType_pairs(&[(option_prompt, CFBoolean::true_value())]); 43 | return AXIsProcessTrustedWithOptions(dict.as_concrete_TypeRef()) != 0; 44 | } 45 | } 46 | } 47 | 48 | #[cfg(test)] 49 | mod tests { 50 | use crate::accessibility::{application_is_trusted, application_is_trusted_with_prompt}; 51 | 52 | #[test] 53 | fn test_application_is_trusted() { 54 | assert_eq!(false, application_is_trusted()); 55 | } 56 | 57 | #[test] 58 | fn test_application_is_trusted_with_prompt() { 59 | assert_eq!(false, application_is_trusted_with_prompt()); 60 | } 61 | } 62 | --------------------------------------------------------------------------------