Skip to content

Commit 1e36c96

Browse files
committed
add permission detecter to fix ANR problem on macOS
1 parent 8aa907c commit 1e36c96

File tree

1 file changed

+136
-2
lines changed

1 file changed

+136
-2
lines changed

src/libuiohook.patch

+136-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,99 @@
1+
diff --git a/src/darwin/input_helper.c b/src/darwin/input_helper.c
2+
index ada5829..20a68db 100644
3+
--- a/src/darwin/input_helper.c
4+
+++ b/src/darwin/input_helper.c
5+
@@ -40,7 +40,7 @@ static KeyboardLayoutRef prev_keyboard_layout = NULL;
6+
static TISInputSourceRef prev_keyboard_layout = NULL;
7+
#endif
8+
9+
-bool is_accessibility_enabled() {
10+
+bool is_accessibility_enabled(bool prompt) {
11+
bool is_enabled = false;
12+
13+
// Dynamically load the application services framework for examination.
14+
@@ -59,7 +59,7 @@ bool is_accessibility_enabled() {
15+
} else if (kAXTrustedCheckOptionPrompt_t != NULL) {
16+
// New accessibility API 10.9 and later.
17+
const void * keys[] = { *kAXTrustedCheckOptionPrompt_t };
18+
- const void * values[] = { kCFBooleanTrue };
19+
+ const void * values[] = { prompt ? kCFBooleanTrue : kCFBooleanFalse };
20+
21+
CFDictionaryRef options = CFDictionaryCreate(
22+
kCFAllocatorDefault,
23+
diff --git a/src/darwin/input_helper.h b/src/darwin/input_helper.h
24+
index ebd4666..799b823 100644
25+
--- a/src/darwin/input_helper.h
26+
+++ b/src/darwin/input_helper.h
27+
@@ -170,7 +170,7 @@
28+
29+
/* Check for access to Apples accessibility API.
30+
*/
31+
-extern bool is_accessibility_enabled();
32+
+extern bool is_accessibility_enabled(bool prompt);
33+
34+
/* Converts an OSX key code and event mask to the appropriate Unicode character
35+
* representation.
136
diff --git a/src/darwin/input_hook.c b/src/darwin/input_hook.c
2-
index e6cd6ce..04d040b 100644
37+
index e6cd6ce..3546c7e 100644
338
--- a/src/darwin/input_hook.c
439
+++ b/src/darwin/input_hook.c
5-
@@ -958,7 +958,7 @@ CGEventRef hook_event_proc(CGEventTapProxy tap_proxy, CGEventType type, CGEventR
40+
@@ -103,6 +103,37 @@ static dispatcher_t dispatcher = NULL;
41+
// re-enable the tap when it gets disabled by a timeout
42+
static event_runloop_info *hook = NULL;
43+
44+
+// cause is_accessibility_enabled value might change during runtime
45+
+// we need detect it while hook is enabled
46+
+// Once it is disabled, we should stop the hooking
47+
+static bool hook_enabled = false;
48+
+static pthread_t accessibility_thread;
49+
+void accessibility_thread_proc() {
50+
+ CFRunLoopMode mode = CFRunLoopCopyCurrentMode(event_loop);
51+
+ while (mode) {
52+
+ CFRelease(mode);
53+
+ if (!hook_enabled) {
54+
+ break;
55+
+ }
56+
+
57+
+ bool is_enabled = is_accessibility_enabled(false);
58+
+
59+
+ logger(LOG_LEVEL_DEBUG, "%s [%u]: is_accessibility_enabled: %d, mode: %s\n",
60+
+ __FUNCTION__, __LINE__, is_enabled, mode);
61+
+
62+
+ if (!is_enabled) {
63+
+ hook_stop();
64+
+ }
65+
+
66+
+ usleep(200 * 1000); // 5 check per second
67+
+ mode = CFRunLoopCopyCurrentMode(event_loop);
68+
+ }
69+
+
70+
+ if (mode) {
71+
+ CFRelease(mode);
72+
+ }
73+
+}
74+
+
75+
UIOHOOK_API void hook_set_dispatch_proc(dispatcher_t dispatch_proc) {
76+
logger(LOG_LEVEL_DEBUG, "%s [%u]: Setting new dispatch callback to %#p.\n",
77+
__FUNCTION__, __LINE__, dispatch_proc);
78+
@@ -222,6 +253,8 @@ static void hook_status_proc(CFRunLoopObserverRef observer, CFRunLoopActivity ac
79+
event.type = EVENT_HOOK_ENABLED;
80+
event.mask = 0x00;
81+
82+
+ hook_enabled = true;
83+
+
84+
// Fire the hook start event.
85+
dispatch_event(&event);
86+
break;
87+
@@ -234,6 +267,8 @@ static void hook_status_proc(CFRunLoopObserverRef observer, CFRunLoopActivity ac
88+
event.type = EVENT_HOOK_DISABLED;
89+
event.mask = 0x00;
90+
91+
+ hook_enabled = false;
92+
+
93+
// Fire the hook stop event.
94+
dispatch_event(&event);
95+
96+
@@ -958,7 +993,7 @@ CGEventRef hook_event_proc(CGEventTapProxy tap_proxy, CGEventType type, CGEventR
697
unset_modifier_mask(MOUSE_BUTTON5);
798
}
899

@@ -11,6 +102,49 @@ index e6cd6ce..04d040b 100644
11102
}
12103
break;
13104

105+
@@ -990,9 +1025,18 @@ CGEventRef hook_event_proc(CGEventTapProxy tap_proxy, CGEventType type, CGEventR
106+
logger(LOG_LEVEL_WARN, "%s [%u]: CGEventTap timeout!\n",
107+
__FUNCTION__, __LINE__);
108+
109+
- // We need to re-enable the tap
110+
- if (hook->port) {
111+
- CGEventTapEnable(hook->port, true);
112+
+ if (is_accessibility_enabled(false)) {
113+
+ // We need to re-enable the tap
114+
+ if (hook->port) {
115+
+ CGEventTapEnable(hook->port, true);
116+
+ }
117+
+ } else {
118+
+ if (hook->port) {
119+
+ CGEventTapEnable(hook->port, false);
120+
+ }
121+
+ int status = hook_stop();
122+
+ logger(LOG_LEVEL_ERROR, "%s [%u]: Accessibility API is disabled! Stop hook status: 0x(%x)\n",
123+
+ __FUNCTION__, __LINE__, status);
124+
}
125+
} else {
126+
// In theory this *should* never execute.
127+
@@ -1269,7 +1313,7 @@ UIOHOOK_API int hook_run() {
128+
int status = UIOHOOK_SUCCESS;
129+
130+
// Check for accessibility before we start the loop.
131+
- if (is_accessibility_enabled()) {
132+
+ if (is_accessibility_enabled(false)) {
133+
logger(LOG_LEVEL_DEBUG, "%s [%u]: Accessibility API is enabled.\n",
134+
__FUNCTION__, __LINE__);
135+
136+
@@ -1368,6 +1412,11 @@ UIOHOOK_API int hook_run() {
137+
auto_release_pool = eventWithoutCGEvent(pool, sel_registerName("init"));
138+
#endif
139+
140+
+ // Start the accssiblity detect thread.
141+
+ if (pthread_create(&accessibility_thread, NULL, (void *) accessibility_thread_proc, NULL) != 0) {
142+
+ logger(LOG_LEVEL_DEBUG, "%s [%u]: accessibility_thread_proc created!\n",
143+
+ __FUNCTION__, __LINE__);
144+
+ }
145+
146+
// Start the hook thread runloop.
147+
CFRunLoopRun();
14148
diff --git a/src/windows/input_helper.c b/src/windows/input_helper.c
15149
index e690021..0d383e0 100644
16150
--- a/src/windows/input_helper.c

0 commit comments

Comments
 (0)