├── .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 |
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 |
--------------------------------------------------------------------------------