Skip to content

Commit d750c0a

Browse files
authored
Merge pull request #262 from RustCastLabs/hotkey-launching-fix
Hotkey launching fix
2 parents 3ef7eb8 + 82ffa41 commit d750c0a

6 files changed

Lines changed: 112 additions & 1 deletion

File tree

assets/entitlements.plist

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
3+
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
4+
<plist version="1.0">
5+
<dict>
6+
<key>com.apple.security.app-sandbox</key>
7+
<false/>
8+
<key>com.apple.security.device.input-monitoring</key>
9+
<true/>
10+
<key>com.apple.security.temporary-exception.accessibility</key>
11+
<true/>
12+
</dict>
13+
</plist>

scripts/sign-macos.sh

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
#!/usr/bin/env -S bash -e
22

3+
ENTITLEMENTS_PATH="assets/entitlements.plist"
4+
35
APP_BUNDLE_PATH="${APP_BUNDLE_PATH:?APP_BUNDLE_PATH not set}"
46

57
# 1. Create a temporary keychain and import certificate
@@ -29,6 +31,7 @@ security set-key-partition-list -S apple-tool:,apple:,codesign: \
2931

3032
# 2. Sign app bundle
3133
codesign --deep --force --options runtime --timestamp \
34+
--entitlements $ENTITLEMENTS_PATH \
3235
--sign "$MACOS_CERTIFICATE_NAME" \
3336
"$APP_BUNDLE_PATH"
3437

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
/// Taken from: <https://github.com/acsandmann/rift/blob/main/src/sys/accessibility.rs>
2+
use std::ffi::c_void;
3+
use std::thread;
4+
use std::time::{Duration, Instant};
5+
6+
use log::info;
7+
use objc2::rc::autoreleasepool;
8+
use objc2::runtime::AnyObject;
9+
use objc2::{class, msg_send};
10+
11+
#[link(name = "ApplicationServices", kind = "framework")]
12+
unsafe extern "C" {
13+
fn AXIsProcessTrustedWithOptions(options: *const c_void) -> bool;
14+
15+
static kAXTrustedCheckOptionPrompt: *const c_void;
16+
}
17+
18+
#[link(name = "CoreFoundation", kind = "framework")]
19+
unsafe extern "C" {
20+
static kCFBooleanTrue: *const c_void;
21+
static kCFBooleanFalse: *const c_void;
22+
}
23+
24+
const AX_POLL_INTERVAL: Duration = Duration::from_millis(250);
25+
const AX_POLL_TIMEOUT: Duration = Duration::from_secs(30);
26+
27+
#[inline]
28+
fn ax_is_trusted() -> bool {
29+
unsafe {
30+
autoreleasepool(|_| {
31+
let keys: [*mut AnyObject; 1] = [kAXTrustedCheckOptionPrompt as *mut AnyObject];
32+
let vals: [*mut AnyObject; 1] = [kCFBooleanFalse as *mut AnyObject];
33+
let dict: *mut AnyObject = msg_send![
34+
class!(NSDictionary),
35+
dictionaryWithObjects: vals.as_ptr(),
36+
forKeys: keys.as_ptr(),
37+
count: 1usize
38+
];
39+
40+
AXIsProcessTrustedWithOptions(dict.cast())
41+
})
42+
}
43+
}
44+
45+
#[allow(unsafe_op_in_unsafe_fn)]
46+
unsafe fn prompt_ax_trust_dialog() {
47+
autoreleasepool(|_| {
48+
let keys: [*mut AnyObject; 1] = [kAXTrustedCheckOptionPrompt as *mut AnyObject];
49+
let vals: [*mut AnyObject; 1] = [kCFBooleanTrue as *mut AnyObject];
50+
51+
let dict: *mut AnyObject = msg_send![
52+
class!(NSDictionary),
53+
dictionaryWithObjects: vals.as_ptr(),
54+
forKeys: keys.as_ptr(),
55+
count: 1usize
56+
];
57+
58+
let _ = AXIsProcessTrustedWithOptions(dict.cast());
59+
});
60+
}
61+
62+
pub fn ensure_accessibility_permission() {
63+
if ax_is_trusted() {
64+
return;
65+
}
66+
67+
info!("Accessibility permission is not granted; prompting user for permission now.");
68+
69+
unsafe { prompt_ax_trust_dialog() };
70+
71+
let start = Instant::now();
72+
loop {
73+
if ax_is_trusted() {
74+
info!("Accessibility permission granted");
75+
return;
76+
}
77+
78+
if start.elapsed() >= AX_POLL_TIMEOUT {
79+
break;
80+
}
81+
82+
thread::sleep(AX_POLL_INTERVAL);
83+
}
84+
85+
println!(
86+
"Rustcast still does not have accessibility permission. Enable it in System Settings > Privacy & Security > Accessibility, then restart Rustcast."
87+
);
88+
89+
std::process::exit(1);
90+
}

src/platform/macos/launching.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,13 @@ use std::sync::{Arc, Mutex};
33
use block2::RcBlock;
44
use objc2_app_kit::{NSEvent, NSEventMask, NSEventModifierFlags, NSEventType};
55

6-
use crate::app::{Message, tile::ExtSender};
6+
use crate::{
7+
app::{Message, tile::ExtSender},
8+
platform::macos::accessibility::ensure_accessibility_permission,
9+
};
710

811
pub fn global_handler(sender: ExtSender) {
12+
ensure_accessibility_permission();
913
local_handler(sender.clone());
1014
let mask = NSEventMask::KeyDown | NSEventMask::FlagsChanged;
1115
let sender = Arc::new(Mutex::new(sender.0.clone()));

src/platform/macos/login.rs

Whitespace-only changes.

src/platform/macos/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
//! Macos specific logic, such as window settings, etc.
2+
pub mod accessibility;
23
pub mod discovery;
34
pub mod haptics;
45
pub mod launching;

0 commit comments

Comments
 (0)