@mukea/uiohook-napi 1.5.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +77 -0
- package/binding.gyp +85 -0
- package/dist/index.d.ts +194 -0
- package/dist/index.js +206 -0
- package/dist/index.js.map +1 -0
- package/dist/prebuild-test-noop.d.ts +0 -0
- package/dist/prebuild-test-noop.js +3 -0
- package/dist/prebuild-test-noop.js.map +1 -0
- package/libuiohook/include/uiohook.h +457 -0
- package/libuiohook/src/darwin/input_helper.c +535 -0
- package/libuiohook/src/darwin/input_helper.h +203 -0
- package/libuiohook/src/darwin/input_hook.c +1436 -0
- package/libuiohook/src/darwin/post_event.c +303 -0
- package/libuiohook/src/darwin/system_properties.c +479 -0
- package/libuiohook/src/logger.c +40 -0
- package/libuiohook/src/logger.h +32 -0
- package/libuiohook/src/windows/input_helper.c +913 -0
- package/libuiohook/src/windows/input_helper.h +146 -0
- package/libuiohook/src/windows/input_hook.c +722 -0
- package/libuiohook/src/windows/post_event.c +248 -0
- package/libuiohook/src/windows/system_properties.c +231 -0
- package/libuiohook/src/x11/input_helper.c +1846 -0
- package/libuiohook/src/x11/input_helper.h +108 -0
- package/libuiohook/src/x11/input_hook.c +1116 -0
- package/libuiohook/src/x11/post_event.c +427 -0
- package/libuiohook/src/x11/system_properties.c +494 -0
- package/package.json +60 -0
- package/prebuilds/darwin/darwin-arm64/@mukea+uiohook-napi.node +0 -0
- package/prebuilds/darwin/darwin-x64/@mukea+uiohook-napi.node +0 -0
- package/prebuilds/linux/linux-arm64/@mukea+uiohook-napi.node +0 -0
- package/prebuilds/linux/linux-x64/@mukea+uiohook-napi.node +0 -0
- package/prebuilds/windows/win32-x64/@mukea+uiohook-napi.node +0 -0
- package/src/lib/addon.c +337 -0
- package/src/lib/napi_helpers.c +51 -0
- package/src/lib/napi_helpers.h +53 -0
- package/src/lib/uiohook_worker.c +200 -0
- package/src/lib/uiohook_worker.h +12 -0
|
@@ -0,0 +1,479 @@
|
|
|
1
|
+
/* libUIOHook: Cross-platform keyboard and mouse hooking from userland.
|
|
2
|
+
* Copyright (C) 2006-2023 Alexander Barker. All Rights Reserved.
|
|
3
|
+
* https://github.com/kwhat/libuiohook/
|
|
4
|
+
*
|
|
5
|
+
* libUIOHook is free software: you can redistribute it and/or modify
|
|
6
|
+
* it under the terms of the GNU Lesser General Public License as published
|
|
7
|
+
* by the Free Software Foundation, either version 3 of the License, or
|
|
8
|
+
* (at your option) any later version.
|
|
9
|
+
*
|
|
10
|
+
* libUIOHook is distributed in the hope that it will be useful,
|
|
11
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
13
|
+
* GNU General Public License for more details.
|
|
14
|
+
*
|
|
15
|
+
* You should have received a copy of the GNU Lesser General Public License
|
|
16
|
+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
#ifdef USE_CARBON_LEGACY
|
|
20
|
+
#include <Carbon/Carbon.h>
|
|
21
|
+
#endif
|
|
22
|
+
|
|
23
|
+
#if defined(USE_APPLICATION_SERVICES) || defined(USE_IOKIT)
|
|
24
|
+
#include <CoreFoundation/CoreFoundation.h>
|
|
25
|
+
#endif
|
|
26
|
+
|
|
27
|
+
#ifdef USE_IOKIT
|
|
28
|
+
#include <IOKit/hidsystem/event_status_driver.h>
|
|
29
|
+
#include <IOKit/hidsystem/IOHIDLib.h>
|
|
30
|
+
#include <IOKit/hidsystem/IOHIDParameter.h>
|
|
31
|
+
#endif
|
|
32
|
+
|
|
33
|
+
#include <stdbool.h>
|
|
34
|
+
#include <uiohook.h>
|
|
35
|
+
|
|
36
|
+
#include "logger.h"
|
|
37
|
+
#include "input_helper.h"
|
|
38
|
+
|
|
39
|
+
#ifdef USE_IOKIT
|
|
40
|
+
static io_connect_t connection;
|
|
41
|
+
#endif
|
|
42
|
+
|
|
43
|
+
#define MOUSE_ACCELERATION_MULTIPLIER 65536
|
|
44
|
+
|
|
45
|
+
/* The following function was contributed by Anthony Liguori Jan 18 2015.
|
|
46
|
+
* https://github.com/kwhat/libuiohook/pull/18
|
|
47
|
+
*/
|
|
48
|
+
UIOHOOK_API screen_data* hook_create_screen_info(unsigned char *count) {
|
|
49
|
+
CGError status = kCGErrorFailure;
|
|
50
|
+
screen_data* screens = NULL;
|
|
51
|
+
|
|
52
|
+
// Initialize count to zero.
|
|
53
|
+
*count = 0;
|
|
54
|
+
|
|
55
|
+
// Allocate memory to hold each display id. We will just allocate our MAX
|
|
56
|
+
// because its only about 1K of memory.
|
|
57
|
+
// TODO This can probably be realistically cut to something like 16 or 32....
|
|
58
|
+
// If you have more than 32 monitors, send me a picture and make a donation ;)
|
|
59
|
+
CGDirectDisplayID *display_ids = malloc(sizeof(CGDirectDisplayID) * UCHAR_MAX);
|
|
60
|
+
if (display_ids != NULL) {
|
|
61
|
+
// NOTE Pass UCHAR_MAX to make sure uint32_t doesn't overflow uint8_t.
|
|
62
|
+
// TOOD Test/Check whether CGGetOnlineDisplayList is more suitable...
|
|
63
|
+
status = CGGetActiveDisplayList(UCHAR_MAX, display_ids, (uint32_t *) count);
|
|
64
|
+
|
|
65
|
+
// If there is no error and at least one monitor.
|
|
66
|
+
if (status == kCGErrorSuccess && *count > 0) {
|
|
67
|
+
logger(LOG_LEVEL_DEBUG, "%s [%u]: CGGetActiveDisplayList: %li.\n",
|
|
68
|
+
__FUNCTION__, __LINE__, *count);
|
|
69
|
+
|
|
70
|
+
// Allocate memory for the number of screens found.
|
|
71
|
+
screens = malloc(sizeof(screen_data) * (*count));
|
|
72
|
+
if (screens != NULL) {
|
|
73
|
+
for (uint8_t i = 0; i < *count; i++) {
|
|
74
|
+
//size_t width = CGDisplayPixelsWide(display_ids[i]);
|
|
75
|
+
//size_t height = CGDisplayPixelsHigh(display_ids[i]);
|
|
76
|
+
CGRect boundsDisp = CGDisplayBounds(display_ids[i]);
|
|
77
|
+
if (boundsDisp.size.width > 0 && boundsDisp.size.height > 0) {
|
|
78
|
+
screens[i] = (screen_data) {
|
|
79
|
+
.number = i + 1,
|
|
80
|
+
//TODO: make sure we follow the same convention for the origin
|
|
81
|
+
//in all other platform implementations (upper-left)
|
|
82
|
+
//TODO: document the approach with examples in order to show different
|
|
83
|
+
//cases -> different resolutions (secondary monitors origin might be
|
|
84
|
+
//negative)
|
|
85
|
+
.x = boundsDisp.origin.x,
|
|
86
|
+
.y = boundsDisp.origin.y,
|
|
87
|
+
.width = boundsDisp.size.width,
|
|
88
|
+
.height = boundsDisp.size.height
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
} else {
|
|
94
|
+
logger(LOG_LEVEL_WARN, "%s [%u]: multiple_get_screen_info failed: %ld. Fallback.\n",
|
|
95
|
+
__FUNCTION__, __LINE__, status);
|
|
96
|
+
|
|
97
|
+
size_t width = CGDisplayPixelsWide(CGMainDisplayID());
|
|
98
|
+
size_t height = CGDisplayPixelsHigh(CGMainDisplayID());
|
|
99
|
+
|
|
100
|
+
if (width > 0 && height > 0) {
|
|
101
|
+
screens = malloc(sizeof(screen_data));
|
|
102
|
+
|
|
103
|
+
if (screens != NULL) {
|
|
104
|
+
*count = 1;
|
|
105
|
+
screens[0] = (screen_data) {
|
|
106
|
+
.number = 1,
|
|
107
|
+
.x = 0,
|
|
108
|
+
.y = 0,
|
|
109
|
+
.width = width,
|
|
110
|
+
.height = height
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Free the id's after we are done.
|
|
117
|
+
free(display_ids);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return screens;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/*
|
|
124
|
+
* Apple's documentation is not very good. I was finally able to find this
|
|
125
|
+
* information after many hours of googling. Value is the slider value in the
|
|
126
|
+
* system preferences. That value * 15 is the rate in MS. 66 / the value is the
|
|
127
|
+
* chars per second rate.
|
|
128
|
+
*
|
|
129
|
+
* Value MS Char/Sec
|
|
130
|
+
*
|
|
131
|
+
* 1 15 66 * Out of standard range *
|
|
132
|
+
* 2 30 33
|
|
133
|
+
* 6 90 11
|
|
134
|
+
* 12 180 5.5
|
|
135
|
+
* 30 450 2.2
|
|
136
|
+
* 60 900 1.1
|
|
137
|
+
* 90 1350 0.73
|
|
138
|
+
* 120 1800 0.55
|
|
139
|
+
*
|
|
140
|
+
* V = MS / 15
|
|
141
|
+
* V = 66 / CharSec
|
|
142
|
+
*
|
|
143
|
+
* MS = V * 15
|
|
144
|
+
* MS = (66 / CharSec) * 15
|
|
145
|
+
*
|
|
146
|
+
* CharSec = 66 / V
|
|
147
|
+
* CharSec = 66 / (MS / 15)
|
|
148
|
+
*/
|
|
149
|
+
UIOHOOK_API long int hook_get_auto_repeat_rate() {
|
|
150
|
+
#if defined(USE_APPLICATION_SERVICES) || defined(USE_IOKIT) || defined(USE_CARBON_LEGACY)
|
|
151
|
+
bool successful = false;
|
|
152
|
+
SInt64 rate;
|
|
153
|
+
#endif
|
|
154
|
+
|
|
155
|
+
long int value = -1;
|
|
156
|
+
|
|
157
|
+
#ifdef USE_APPLICATION_SERVICES
|
|
158
|
+
if (!successful) {
|
|
159
|
+
CFTypeRef pref_val = CFPreferencesCopyValue(CFSTR("KeyRepeat"), kCFPreferencesAnyApplication, kCFPreferencesCurrentUser, kCFPreferencesAnyHost);
|
|
160
|
+
if (pref_val != NULL) {
|
|
161
|
+
if (CFGetTypeID(pref_val) == CFNumberGetTypeID() && CFNumberGetValue((CFNumberRef) pref_val, kCFNumberSInt64Type, &rate)) {
|
|
162
|
+
// This is the slider value, we must multiply by 15 to convert to milliseconds.
|
|
163
|
+
value = (long) rate * 15;
|
|
164
|
+
successful = true;
|
|
165
|
+
|
|
166
|
+
logger(LOG_LEVEL_DEBUG, "%s [%u]: CFPreferencesCopyValue KeyRepeat: %li.\n",
|
|
167
|
+
__FUNCTION__, __LINE__, rate);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
CFRelease(pref_val);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
#endif
|
|
174
|
+
|
|
175
|
+
#ifdef USE_IOKIT
|
|
176
|
+
if (!successful) {
|
|
177
|
+
CFTypeRef cf_type = NULL;
|
|
178
|
+
kern_return_t kern_return = IOHIDCopyCFTypeParameter(connection, CFSTR(kIOHIDKeyRepeatKey), &cf_type);
|
|
179
|
+
if (kern_return == kIOReturnSuccess) {
|
|
180
|
+
if (cf_type != NULL) {
|
|
181
|
+
if (CFGetTypeID(cf_type) == CFNumberGetTypeID()) {
|
|
182
|
+
if (CFNumberGetValue((CFNumberRef) cf_type, kCFNumberSInt64Type, &rate)) {
|
|
183
|
+
/* This is in some undefined unit of time that if we happen
|
|
184
|
+
* to multiply by 900 gives us the time in milliseconds. We
|
|
185
|
+
* add 0.5 to the result so that when we cast to long we
|
|
186
|
+
* actually get a rounded result. Saves the math.h depend.
|
|
187
|
+
*
|
|
188
|
+
* 900 * 33,333,333 / 1000.0 / 1000.0 / 1000.0 + 0.5 == 30 * Fast *
|
|
189
|
+
* 900 * 100,000,000 / 1000.0 / 1000.0 / 1000.0 + 0.5 == 90
|
|
190
|
+
* 900 * 200,000,000 / 1000.0 / 1000.0 / 1000.0 + 0.5 == 180
|
|
191
|
+
* 900 * 500,000,000 / 1000.0 / 1000.0 / 1000.0 + 0.5 == 450
|
|
192
|
+
* 900 * 1,000,000,000 / 1000.0 / 1000.0 / 1000.0 + 0.5 == 900
|
|
193
|
+
* 900 * 1,500,000,000 / 1000.0 / 1000.0 / 1000.0 + 0.5 == 1350
|
|
194
|
+
* 900 * 2,000,000,000 / 1000.0 / 1000.0 / 1000.0 + 0.5 == 1800 * Slow *
|
|
195
|
+
*/
|
|
196
|
+
value = (long) (900 * rate / 1000.0 / 1000.0 / 1000.0 + 0.5);
|
|
197
|
+
successful = true;
|
|
198
|
+
|
|
199
|
+
logger(LOG_LEVEL_DEBUG, "%s [%u]: IORegistryEntryCreateCFProperty kIOHIDKeyRepeatKey: %li.\n",
|
|
200
|
+
__FUNCTION__, __LINE__, value);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
CFRelease(cf_type);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
#endif
|
|
209
|
+
|
|
210
|
+
#ifdef USE_CARBON_LEGACY
|
|
211
|
+
if (!successful) {
|
|
212
|
+
// Apple documentation states that value is in 'ticks'. I am not sure
|
|
213
|
+
// what that means, but it looks a lot like the arbitrary slider value.
|
|
214
|
+
rate = LMGetKeyRepThresh();
|
|
215
|
+
if (rate > -1) {
|
|
216
|
+
/* This is the slider value, we must multiply by 15 to convert to
|
|
217
|
+
* milliseconds.
|
|
218
|
+
*/
|
|
219
|
+
value = (long) rate * 15;
|
|
220
|
+
successful = true;
|
|
221
|
+
|
|
222
|
+
logger(LOG_LEVEL_DEBUG, "%s [%u]: LMGetKeyRepThresh: %li.\n",
|
|
223
|
+
__FUNCTION__, __LINE__, value);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
#endif
|
|
227
|
+
|
|
228
|
+
return value;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
UIOHOOK_API long int hook_get_auto_repeat_delay() {
|
|
232
|
+
#if defined(USE_APPLICATION_SERVICES) || defined(USE_IOKIT) || defined(USE_CARBON_LEGACY)
|
|
233
|
+
bool successful = false;
|
|
234
|
+
SInt64 delay;
|
|
235
|
+
#endif
|
|
236
|
+
|
|
237
|
+
long int value = -1;
|
|
238
|
+
|
|
239
|
+
#ifdef USE_APPLICATION_SERVICES
|
|
240
|
+
if (!successful) {
|
|
241
|
+
CFTypeRef pref_val = CFPreferencesCopyValue(CFSTR("InitialKeyRepeat"), kCFPreferencesAnyApplication, kCFPreferencesCurrentUser, kCFPreferencesAnyHost);
|
|
242
|
+
if (pref_val != NULL) {
|
|
243
|
+
if (CFGetTypeID(pref_val) == CFNumberGetTypeID() && CFNumberGetValue((CFNumberRef) pref_val, kCFNumberSInt64Type, &delay)) {
|
|
244
|
+
// This is the slider value, we must multiply by 15 to convert to milliseconds.
|
|
245
|
+
value = (long) delay * 15;
|
|
246
|
+
successful = true;
|
|
247
|
+
|
|
248
|
+
logger(LOG_LEVEL_DEBUG, "%s [%u]: CFPreferencesCopyValue InitialKeyRepeat: %li.\n",
|
|
249
|
+
__FUNCTION__, __LINE__, value);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
CFRelease(pref_val);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
#endif
|
|
256
|
+
|
|
257
|
+
#ifdef USE_IOKIT
|
|
258
|
+
if (!successful) {
|
|
259
|
+
CFTypeRef cf_type = NULL;
|
|
260
|
+
kern_return_t kern_return = IOHIDCopyCFTypeParameter(connection, CFSTR(kIOHIDInitialKeyRepeatKey), &cf_type);
|
|
261
|
+
if (kern_return == kIOReturnSuccess) {
|
|
262
|
+
if (cf_type != NULL) {
|
|
263
|
+
if (CFGetTypeID(cf_type) == CFNumberGetTypeID()) {
|
|
264
|
+
if (CFNumberGetValue((CFNumberRef) cf_type, kCFNumberSInt64Type, &delay)) {
|
|
265
|
+
/* This is in some undefined unit of time that if we happen
|
|
266
|
+
* to multiply by 900 gives us the time in milliseconds. We
|
|
267
|
+
* add 0.5 to the result so that when we cast to long we
|
|
268
|
+
* actually get a rounded result. Saves the math.h depend.
|
|
269
|
+
*
|
|
270
|
+
* 900 * 250,000,000 / 1000.0 / 1000.0 / 1000.0 + 0.5 == 225 * Fast *
|
|
271
|
+
* 900 * 416,666,666 / 1000.0 / 1000.0 / 1000.0 + 0.5 == 375
|
|
272
|
+
* 900 * 583,333,333 / 1000.0 / 1000.0 / 1000.0 + 0.5 == 525
|
|
273
|
+
* 900 * 1,133,333,333 / 1000.0 / 1000.0 / 1000.0 + 0.5 == 1020
|
|
274
|
+
* 900 * 1,566,666,666 / 1000.0 / 1000.0 / 1000.0 + 0.5 == 1410
|
|
275
|
+
* 900 * 2,000,000,000 / 1000.0 / 1000.0 / 1000.0 + 0.5 == 1800 * Slow *
|
|
276
|
+
*/
|
|
277
|
+
value = (long) (900 * delay / 1000.0 / 1000.0 / 1000.0 + 0.5);
|
|
278
|
+
successful = true;
|
|
279
|
+
|
|
280
|
+
logger(LOG_LEVEL_DEBUG, "%s [%u]: IORegistryEntryCreateCFProperty kIOHIDInitialKeyRepeatKey: %li.\n",
|
|
281
|
+
__FUNCTION__, __LINE__, delay);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
CFRelease(cf_type);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
#endif
|
|
290
|
+
|
|
291
|
+
#ifdef USE_CARBON_LEGACY
|
|
292
|
+
if (!successful) {
|
|
293
|
+
// Apple documentation states that value is in 'ticks'. I am not sure
|
|
294
|
+
// what that means, but it looks a lot like the arbitrary slider value.
|
|
295
|
+
delay = LMGetKeyThresh();
|
|
296
|
+
if (delay > -1) {
|
|
297
|
+
// This is the slider value, we must multiply by 15 to convert to
|
|
298
|
+
// milliseconds.
|
|
299
|
+
value = (long) delay * 15;
|
|
300
|
+
successful = true;
|
|
301
|
+
|
|
302
|
+
logger(LOG_LEVEL_DEBUG, "%s [%u]: LMGetKeyThresh: %li.\n",
|
|
303
|
+
__FUNCTION__, __LINE__, value);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
#endif
|
|
307
|
+
|
|
308
|
+
return value;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
UIOHOOK_API long int hook_get_pointer_acceleration_multiplier() {
|
|
312
|
+
// OS X doesn't currently have an acceleration multiplier so we are using the constant from IOHIDGetMouseAcceleration.
|
|
313
|
+
long int value = MOUSE_ACCELERATION_MULTIPLIER;
|
|
314
|
+
if (hook_get_pointer_sensitivity() < 0) {
|
|
315
|
+
value = 0;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
return value;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
UIOHOOK_API long int hook_get_pointer_acceleration_threshold() {
|
|
322
|
+
// OS X doesn't currently have an acceleration threshold so we are using 1 as a placeholder.
|
|
323
|
+
long int value = 1;
|
|
324
|
+
if (hook_get_pointer_sensitivity() < 0) {
|
|
325
|
+
value = 0;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
return value;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
UIOHOOK_API long int hook_get_pointer_sensitivity() {
|
|
332
|
+
#if defined(USE_APPLICATION_SERVICES) || defined(USE_IOKIT)
|
|
333
|
+
bool successful = false;
|
|
334
|
+
Float32 sensitivity;
|
|
335
|
+
#endif
|
|
336
|
+
|
|
337
|
+
long int value = -1;
|
|
338
|
+
|
|
339
|
+
#ifdef USE_APPLICATION_SERVICES
|
|
340
|
+
if (!successful) {
|
|
341
|
+
CFTypeRef pref_val = CFPreferencesCopyValue(CFSTR("com.apple.mouse.scaling"), kCFPreferencesAnyApplication, kCFPreferencesCurrentUser, kCFPreferencesAnyHost);
|
|
342
|
+
if (pref_val != NULL) {
|
|
343
|
+
if (CFGetTypeID(pref_val) == CFNumberGetTypeID() && CFNumberGetValue((CFNumberRef) pref_val, kCFNumberFloat32Type, &sensitivity)) {
|
|
344
|
+
value = (long) (sensitivity * MOUSE_ACCELERATION_MULTIPLIER);
|
|
345
|
+
|
|
346
|
+
logger(LOG_LEVEL_DEBUG, "%s [%u]: CFPreferencesCopyValue com.apple.mouse.scaling: %li.\n",
|
|
347
|
+
__FUNCTION__, __LINE__, value);
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
CFRelease(pref_val);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
#endif
|
|
354
|
+
|
|
355
|
+
#ifdef USE_IOKIT
|
|
356
|
+
if (!successful) {
|
|
357
|
+
CFTypeRef cf_type = NULL;
|
|
358
|
+
kern_return_t kern_return = IOHIDCopyCFTypeParameter(connection, CFSTR(kIOHIDMouseAccelerationTypeKey), &cf_type);
|
|
359
|
+
if (kern_return == kIOReturnSuccess) {
|
|
360
|
+
if (cf_type != NULL) {
|
|
361
|
+
if (CFGetTypeID(cf_type) == CFNumberGetTypeID()) {
|
|
362
|
+
if (CFNumberGetValue((CFNumberRef) cf_type, kCFNumberFloat32Type, &sensitivity)) {
|
|
363
|
+
value = (long) sensitivity;
|
|
364
|
+
successful = true;
|
|
365
|
+
|
|
366
|
+
logger(LOG_LEVEL_DEBUG, "%s [%u]: IOHIDCopyCFTypeParameter kIOHIDMouseAccelerationTypeKey: %li.\n",
|
|
367
|
+
__FUNCTION__, __LINE__, value);
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
CFRelease(cf_type);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
#endif
|
|
376
|
+
|
|
377
|
+
return value;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
UIOHOOK_API long int hook_get_multi_click_time() {
|
|
381
|
+
#if defined(USE_APPLICATION_SERVICES) || defined(USE_IOKIT) || defined(USE_CARBON_LEGACY)
|
|
382
|
+
bool successful = false;
|
|
383
|
+
Float64 time;
|
|
384
|
+
#endif
|
|
385
|
+
|
|
386
|
+
long int value = -1;
|
|
387
|
+
|
|
388
|
+
#ifdef USE_APPLICATION_SERVICES
|
|
389
|
+
if (!successful) {
|
|
390
|
+
CFTypeRef pref_val = CFPreferencesCopyValue(CFSTR("com.apple.mouse.doubleClickThreshold"), kCFPreferencesAnyApplication, kCFPreferencesCurrentUser, kCFPreferencesAnyHost);
|
|
391
|
+
if (pref_val != NULL) {
|
|
392
|
+
if (CFGetTypeID(pref_val) == CFNumberGetTypeID() && CFNumberGetValue((CFNumberRef) pref_val, kCFNumberFloat64Type, &time)) {
|
|
393
|
+
/* This appears to be the time in seconds */
|
|
394
|
+
value = (long) (time * 1000);
|
|
395
|
+
|
|
396
|
+
logger(LOG_LEVEL_DEBUG, "%s [%u]: CFPreferencesCopyValue: %li.\n",
|
|
397
|
+
__FUNCTION__, __LINE__, value);
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
CFRelease(pref_val);
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
#endif
|
|
404
|
+
|
|
405
|
+
#ifdef USE_IOKIT
|
|
406
|
+
if (!successful) {
|
|
407
|
+
CFTypeRef cf_type = NULL;
|
|
408
|
+
kern_return_t kern_return = IOHIDCopyCFTypeParameter(connection, CFSTR(kIOHIDClickTimeKey), &cf_type);
|
|
409
|
+
if (kern_return == kIOReturnSuccess) {
|
|
410
|
+
if (cf_type != NULL) {
|
|
411
|
+
if (CFGetTypeID(cf_type) == CFNumberGetTypeID()) {
|
|
412
|
+
if (CFNumberGetValue((CFNumberRef) cf_type, kCFNumberFloat64Type, &time)) {
|
|
413
|
+
/* This appears to be the time in nanoseconds */
|
|
414
|
+
value = (long) (time / 1000 / 1000);
|
|
415
|
+
successful = true;
|
|
416
|
+
|
|
417
|
+
logger(LOG_LEVEL_DEBUG, "%s [%u]: IORegistryEntryCreateCFProperty: %li.\n",
|
|
418
|
+
__FUNCTION__, __LINE__, value);
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
CFRelease(cf_type);
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
#endif
|
|
427
|
+
|
|
428
|
+
#ifdef USE_CARBON_LEGACY
|
|
429
|
+
if (!successful) {
|
|
430
|
+
// Apple documentation states that value is in 'ticks'. I am not sure
|
|
431
|
+
// what that means, but it looks a lot like the arbitrary slider value.
|
|
432
|
+
time = GetDblTime();
|
|
433
|
+
if (time > -1) {
|
|
434
|
+
// This is the slider value, we must multiply by 15 to convert to
|
|
435
|
+
// milliseconds.
|
|
436
|
+
value = (long) time * 15;
|
|
437
|
+
successful = true;
|
|
438
|
+
|
|
439
|
+
logger(LOG_LEVEL_DEBUG, "%s [%u]: GetDblTime: %li.\n",
|
|
440
|
+
__FUNCTION__, __LINE__, value);
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
#endif
|
|
444
|
+
|
|
445
|
+
return value;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
|
|
449
|
+
// Create a shared object constructor.
|
|
450
|
+
__attribute__ ((constructor))
|
|
451
|
+
void on_library_load() {
|
|
452
|
+
#ifdef USE_IOKIT
|
|
453
|
+
io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching(kIOHIDSystemClass));
|
|
454
|
+
if (service) {
|
|
455
|
+
kern_return_t kren_ret = IOServiceOpen(service, mach_task_self(), kIOHIDParamConnectType, &connection);
|
|
456
|
+
if (kren_ret != kIOReturnSuccess) {
|
|
457
|
+
logger(LOG_LEVEL_INFO, "%s [%u]: IOServiceOpen failure (%#X)!\n",
|
|
458
|
+
__FUNCTION__, __LINE__, kren_ret);
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
#endif
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
// Create a shared object destructor.
|
|
465
|
+
__attribute__ ((destructor))
|
|
466
|
+
void on_library_unload() {
|
|
467
|
+
// Disable the event hook.
|
|
468
|
+
//hook_stop();
|
|
469
|
+
|
|
470
|
+
#ifdef USE_IOKIT
|
|
471
|
+
if (connection) {
|
|
472
|
+
kern_return_t kren_ret = IOServiceClose(connection);
|
|
473
|
+
if (kren_ret != kIOReturnSuccess) {
|
|
474
|
+
logger(LOG_LEVEL_INFO, "%s [%u]: IOServiceClose failure (%#X) %#X!\n",
|
|
475
|
+
__FUNCTION__, __LINE__, kren_ret, kIOReturnError);
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
#endif
|
|
479
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/* libUIOHook: Cross-platform keyboard and mouse hooking from userland.
|
|
2
|
+
* Copyright (C) 2006-2023 Alexander Barker. All Rights Reserved.
|
|
3
|
+
* https://github.com/kwhat/libuiohook/
|
|
4
|
+
*
|
|
5
|
+
* libUIOHook is free software: you can redistribute it and/or modify
|
|
6
|
+
* it under the terms of the GNU Lesser General Public License as published
|
|
7
|
+
* by the Free Software Foundation, either version 3 of the License, or
|
|
8
|
+
* (at your option) any later version.
|
|
9
|
+
*
|
|
10
|
+
* libUIOHook is distributed in the hope that it will be useful,
|
|
11
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
13
|
+
* GNU General Public License for more details.
|
|
14
|
+
*
|
|
15
|
+
* You should have received a copy of the GNU Lesser General Public License
|
|
16
|
+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
#include <stdarg.h>
|
|
20
|
+
#include <stdbool.h>
|
|
21
|
+
#include <stdint.h>
|
|
22
|
+
#include <stdio.h>
|
|
23
|
+
#include <uiohook.h>
|
|
24
|
+
|
|
25
|
+
#include "logger.h"
|
|
26
|
+
|
|
27
|
+
static bool default_logger(unsigned int level, const char *format, ...) {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Current logger function pointer, should never be null.
|
|
32
|
+
logger_t logger = &default_logger;
|
|
33
|
+
|
|
34
|
+
UIOHOOK_API void hook_set_logger_proc(logger_t logger_proc) {
|
|
35
|
+
if (logger_proc == NULL) {
|
|
36
|
+
logger = &default_logger;
|
|
37
|
+
} else {
|
|
38
|
+
logger = logger_proc;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/* libUIOHook: Cross-platform keyboard and mouse hooking from userland.
|
|
2
|
+
* Copyright (C) 2006-2023 Alexander Barker. All Rights Reserved.
|
|
3
|
+
* https://github.com/kwhat/libuiohook/
|
|
4
|
+
*
|
|
5
|
+
* libUIOHook is free software: you can redistribute it and/or modify
|
|
6
|
+
* it under the terms of the GNU Lesser General Public License as published
|
|
7
|
+
* by the Free Software Foundation, either version 3 of the License, or
|
|
8
|
+
* (at your option) any later version.
|
|
9
|
+
*
|
|
10
|
+
* libUIOHook is distributed in the hope that it will be useful,
|
|
11
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
13
|
+
* GNU General Public License for more details.
|
|
14
|
+
*
|
|
15
|
+
* You should have received a copy of the GNU Lesser General Public License
|
|
16
|
+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
#ifndef _included_logger
|
|
20
|
+
#define _included_logger
|
|
21
|
+
|
|
22
|
+
#include <uiohook.h>
|
|
23
|
+
#include <stdbool.h>
|
|
24
|
+
|
|
25
|
+
#ifndef __FUNCTION__
|
|
26
|
+
#define __FUNCTION__ __func__
|
|
27
|
+
#endif
|
|
28
|
+
|
|
29
|
+
// logger(level, message)
|
|
30
|
+
extern logger_t logger;
|
|
31
|
+
|
|
32
|
+
#endif
|