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.
1
36
diff --git a/src/darwin/input_hook.c b/src/darwin/input_hook.c
2
- index e6cd6ce..04d040b 100644
37
+ index e6cd6ce..3546c7e 100644
3
38
--- a/src/darwin/input_hook.c
4
39
+++ 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
6
97
unset_modifier_mask(MOUSE_BUTTON5);
7
98
}
8
99
@@ -11,6 +102,49 @@ index e6cd6ce..04d040b 100644
11
102
}
12
103
break;
13
104
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();
14
148
diff --git a/src/windows/input_helper.c b/src/windows/input_helper.c
15
149
index e690021..0d383e0 100644
16
150
--- a/src/windows/input_helper.c
0 commit comments