@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.
Files changed (38) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +77 -0
  3. package/binding.gyp +85 -0
  4. package/dist/index.d.ts +194 -0
  5. package/dist/index.js +206 -0
  6. package/dist/index.js.map +1 -0
  7. package/dist/prebuild-test-noop.d.ts +0 -0
  8. package/dist/prebuild-test-noop.js +3 -0
  9. package/dist/prebuild-test-noop.js.map +1 -0
  10. package/libuiohook/include/uiohook.h +457 -0
  11. package/libuiohook/src/darwin/input_helper.c +535 -0
  12. package/libuiohook/src/darwin/input_helper.h +203 -0
  13. package/libuiohook/src/darwin/input_hook.c +1436 -0
  14. package/libuiohook/src/darwin/post_event.c +303 -0
  15. package/libuiohook/src/darwin/system_properties.c +479 -0
  16. package/libuiohook/src/logger.c +40 -0
  17. package/libuiohook/src/logger.h +32 -0
  18. package/libuiohook/src/windows/input_helper.c +913 -0
  19. package/libuiohook/src/windows/input_helper.h +146 -0
  20. package/libuiohook/src/windows/input_hook.c +722 -0
  21. package/libuiohook/src/windows/post_event.c +248 -0
  22. package/libuiohook/src/windows/system_properties.c +231 -0
  23. package/libuiohook/src/x11/input_helper.c +1846 -0
  24. package/libuiohook/src/x11/input_helper.h +108 -0
  25. package/libuiohook/src/x11/input_hook.c +1116 -0
  26. package/libuiohook/src/x11/post_event.c +427 -0
  27. package/libuiohook/src/x11/system_properties.c +494 -0
  28. package/package.json +60 -0
  29. package/prebuilds/darwin/darwin-arm64/@mukea+uiohook-napi.node +0 -0
  30. package/prebuilds/darwin/darwin-x64/@mukea+uiohook-napi.node +0 -0
  31. package/prebuilds/linux/linux-arm64/@mukea+uiohook-napi.node +0 -0
  32. package/prebuilds/linux/linux-x64/@mukea+uiohook-napi.node +0 -0
  33. package/prebuilds/windows/win32-x64/@mukea+uiohook-napi.node +0 -0
  34. package/src/lib/addon.c +337 -0
  35. package/src/lib/napi_helpers.c +51 -0
  36. package/src/lib/napi_helpers.h +53 -0
  37. package/src/lib/uiohook_worker.c +200 -0
  38. package/src/lib/uiohook_worker.h +12 -0
@@ -0,0 +1,535 @@
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_APPLICATION_SERVICES
20
+ #include <CoreFoundation/CoreFoundation.h>
21
+ #endif
22
+ #ifndef USE_WEAK_IMPORT
23
+ #include <dlfcn.h>
24
+ #endif
25
+ #include <stdbool.h>
26
+ #include <uiohook.h>
27
+
28
+ #include "input_helper.h"
29
+ #include "logger.h"
30
+
31
+ // Current dead key state.
32
+ #if defined(USE_CARBON_LEGACY) || defined(USE_APPLICATION_SERVICES)
33
+ static UInt32 deadkey_state;
34
+ #endif
35
+
36
+ // Input source data for the keyboard.
37
+ #if defined(USE_CARBON_LEGACY)
38
+ static KeyboardLayoutRef prev_keyboard_layout = NULL;
39
+ #elif defined(USE_APPLICATION_SERVICES)
40
+ static TISInputSourceRef prev_keyboard_layout = NULL;
41
+ #endif
42
+
43
+ bool is_accessibility_enabled() {
44
+ bool is_enabled = false;
45
+
46
+ // Dynamically load the application services framework for examination.
47
+ Boolean (*AXIsProcessTrustedWithOptions_t)(CFDictionaryRef);
48
+ *(void **) (&AXIsProcessTrustedWithOptions_t) = dlsym(RTLD_DEFAULT, "AXIsProcessTrustedWithOptions");
49
+ const char *dlError = dlerror();
50
+ if (AXIsProcessTrustedWithOptions_t != NULL) {
51
+ // Check for property CFStringRef kAXTrustedCheckOptionPrompt
52
+ void ** kAXTrustedCheckOptionPrompt_t = dlsym(RTLD_DEFAULT, "kAXTrustedCheckOptionPrompt");
53
+
54
+ dlError = dlerror();
55
+ if (dlError != NULL) {
56
+ // Could not load the AXIsProcessTrustedWithOptions function!
57
+ logger(LOG_LEVEL_WARN, "%s [%u]: %s.\n",
58
+ __FUNCTION__, __LINE__, dlError);
59
+ } else if (kAXTrustedCheckOptionPrompt_t != NULL) {
60
+ // New accessibility API 10.9 and later.
61
+ const void * keys[] = { *kAXTrustedCheckOptionPrompt_t };
62
+ const void * values[] = { kCFBooleanTrue };
63
+
64
+ CFDictionaryRef options = CFDictionaryCreate(
65
+ kCFAllocatorDefault,
66
+ keys,
67
+ values,
68
+ sizeof(keys) / sizeof(*keys),
69
+ &kCFCopyStringDictionaryKeyCallBacks,
70
+ &kCFTypeDictionaryValueCallBacks);
71
+
72
+ is_enabled = (*AXIsProcessTrustedWithOptions_t)(options);
73
+ }
74
+ } else {
75
+ if (dlError != NULL) {
76
+ logger(LOG_LEVEL_WARN, "%s [%u]: %s.\n",
77
+ __FUNCTION__, __LINE__, dlError);
78
+ }
79
+
80
+ logger(LOG_LEVEL_DEBUG, "%s [%u]: AXIsProcessTrustedWithOptions not found.\n",
81
+ __FUNCTION__, __LINE__);
82
+
83
+ logger(LOG_LEVEL_DEBUG, "%s [%u]: Falling back to AXAPIEnabled().\n",
84
+ __FUNCTION__, __LINE__);
85
+
86
+ // Old accessibility check 10.8 and older.
87
+ Boolean (*AXAPIEnabled_f)();
88
+ *(void **) (&AXAPIEnabled_f) = dlsym(RTLD_DEFAULT, "AXAPIEnabled");
89
+ dlError = dlerror();
90
+ if (dlError != NULL) {
91
+ // Could not load the AXIsProcessTrustedWithOptions function!
92
+ logger(LOG_LEVEL_WARN, "%s [%u]: %s.\n",
93
+ __FUNCTION__, __LINE__, dlError);
94
+ } else if (AXAPIEnabled_f != NULL) {
95
+ is_enabled = (*AXAPIEnabled_f)();
96
+ }
97
+ }
98
+
99
+ return is_enabled;
100
+ }
101
+
102
+
103
+ UniCharCount keycode_to_unicode(CGEventRef event_ref, UniChar *buffer, UniCharCount size) {
104
+ UniCharCount count = 0;
105
+ CFDataRef inputData = NULL;
106
+
107
+ #if defined(USE_CARBON_LEGACY)
108
+ KeyboardLayoutRef curr_keyboard_layout;
109
+ if (KLGetCurrentKeyboardLayout(&curr_keyboard_layout) == noErr) {
110
+ if (KLGetKeyboardLayoutProperty(curr_keyboard_layout, kKLuchrData, (const void **) &inputData) != noErr) {
111
+ inputData = NULL;
112
+ }
113
+ }
114
+ #elif defined(USE_APPLICATION_SERVICES)
115
+ // TODO Try https://developer.apple.com/documentation/coregraphics/1456120-cgeventkeyboardgetunicodestring?language=objc
116
+ if (CFEqual(CFRunLoopGetCurrent(), CFRunLoopGetMain())) {
117
+ // NOTE The following block must execute on the main runloop,
118
+ // Ex: CFEqual(CFRunLoopGetCurrent(), CFRunLoopGetMain()) to avoid
119
+ // Exception detected while handling key input and TSMProcessRawKeyCode failed
120
+ // (-192) errors.
121
+ TISInputSourceRef curr_keyboard_layout = TISCopyCurrentKeyboardLayoutInputSource();
122
+ if (curr_keyboard_layout != NULL && CFGetTypeID(curr_keyboard_layout) == TISInputSourceGetTypeID()) {
123
+ CFDataRef data = (CFDataRef) TISGetInputSourceProperty(curr_keyboard_layout, kTISPropertyUnicodeKeyLayoutData);
124
+ if (data != NULL && CFGetTypeID(data) == CFDataGetTypeID() && CFDataGetLength(data) > 0) {
125
+ inputData = (CFDataRef) data;
126
+ }
127
+ }
128
+
129
+ // Check if the keyboard layout has changed to see if the dead key state needs to be discarded.
130
+ if (prev_keyboard_layout != NULL && curr_keyboard_layout != NULL && CFEqual(curr_keyboard_layout, prev_keyboard_layout) == false) {
131
+ deadkey_state = 0x00;
132
+ }
133
+
134
+ // Release the previous keyboard layout.
135
+ if (prev_keyboard_layout != NULL) {
136
+ CFRelease(prev_keyboard_layout);
137
+ prev_keyboard_layout = NULL;
138
+ }
139
+
140
+ // Set the previous keyboard layout to the current layout.
141
+ if (curr_keyboard_layout != NULL) {
142
+ prev_keyboard_layout = curr_keyboard_layout;
143
+ }
144
+ }
145
+ #endif
146
+
147
+ #if defined(USE_CARBON_LEGACY) || defined(USE_APPLICATION_SERVICES)
148
+ if (inputData != NULL) {
149
+ #ifdef USE_CARBON_LEGACY
150
+ const UCKeyboardLayout *keyboard_layout = (const UCKeyboardLayout *) inputData;
151
+ #else
152
+ const UCKeyboardLayout *keyboard_layout = (const UCKeyboardLayout*) CFDataGetBytePtr(inputData);
153
+ #endif
154
+
155
+ if (keyboard_layout != NULL) {
156
+ //Extract keycode and modifier information.
157
+ CGKeyCode keycode = CGEventGetIntegerValueField(event_ref, kCGKeyboardEventKeycode);
158
+ CGEventFlags modifiers = CGEventGetFlags(event_ref);
159
+
160
+ // Disable all command modifiers for translation. This is required
161
+ // so UCKeyTranslate will provide a keysym for the separate event.
162
+ static const CGEventFlags cmd_modifiers = kCGEventFlagMaskCommand |
163
+ kCGEventFlagMaskControl | kCGEventFlagMaskAlternate;
164
+ modifiers &= ~cmd_modifiers;
165
+
166
+ // I don't know why but UCKeyTranslate does not process the
167
+ // kCGEventFlagMaskAlphaShift (A.K.A. Caps Lock Mask) correctly.
168
+ // We need to basically turn off the mask and process the capital
169
+ // letters after UCKeyTranslate().
170
+ bool is_caps_lock = modifiers & kCGEventFlagMaskAlphaShift;
171
+ modifiers &= ~kCGEventFlagMaskAlphaShift;
172
+
173
+ // Run the translation with the saved deadkey_state.
174
+ OSStatus status = UCKeyTranslate(
175
+ keyboard_layout,
176
+ keycode,
177
+ kUCKeyActionDown, //kUCKeyActionDisplay,
178
+ (modifiers >> 16) & 0xFF, //(modifiers >> 16) & 0xFF, || (modifiers >> 8) & 0xFF,
179
+ LMGetKbdType(),
180
+ kNilOptions, //kNilOptions, //kUCKeyTranslateNoDeadKeysMask
181
+ &deadkey_state,
182
+ size,
183
+ &count,
184
+ buffer);
185
+
186
+ if (status == noErr && count > 0) {
187
+ if (is_caps_lock) {
188
+ // We *had* a caps lock mask so we need to convert to uppercase.
189
+ CFMutableStringRef keytxt = CFStringCreateMutableWithExternalCharactersNoCopy(kCFAllocatorDefault, buffer, count, size, kCFAllocatorNull);
190
+ if (keytxt != NULL) {
191
+ CFLocaleRef locale = CFLocaleCopyCurrent();
192
+ CFStringUppercase(keytxt, locale);
193
+ CFRelease(locale);
194
+ CFRelease(keytxt);
195
+ } else {
196
+ // There was an problem creating the CFMutableStringRef.
197
+ count = 0;
198
+ }
199
+ }
200
+ } else {
201
+ // Make sure the buffer count is zero if an error occurred.
202
+ count = 0;
203
+ }
204
+ }
205
+ }
206
+ #else
207
+ CGEventKeyboardGetUnicodeString(event_ref, size, &count, buffer);
208
+ #endif
209
+
210
+ // The following codes should not be processed because they are invalid.
211
+ if (count == 1) {
212
+ switch (buffer[0]) {
213
+ case 0x01: // Home
214
+ case 0x04: // End
215
+ case 0x05: // Help Key
216
+ case 0x10: // Function Keys
217
+ case 0x0B: // Page Up
218
+ case 0x0C: // Page Down
219
+ case 0x1F: // Volume Up
220
+ count = 0;
221
+ }
222
+ }
223
+
224
+ return count;
225
+ }
226
+
227
+
228
+ static const uint16_t keycode_scancode_table[][2] = {
229
+ /* idx { keycode, scancode }, */
230
+ /* 0 */ { VC_A, kVK_Undefined }, // 0x00
231
+ /* 1 */ { VC_S, kVK_Escape }, // 0x01
232
+ /* 2 */ { VC_D, kVK_ANSI_1 }, // 0x02
233
+ /* 3 */ { VC_F, kVK_ANSI_2 }, // 0x03
234
+ /* 4 */ { VC_H, kVK_ANSI_3 }, // 0x04
235
+ /* 5 */ { VC_G, kVK_ANSI_4 }, // 0x05
236
+ /* 6 */ { VC_Z, kVK_ANSI_5 }, // 0x07
237
+ /* 7 */ { VC_X, kVK_ANSI_6 }, // 0x08
238
+ /* 8 */ { VC_C, kVK_ANSI_7 }, // 0x09
239
+ /* 9 */ { VC_V, kVK_ANSI_8 }, // 0x0A
240
+ /* 10 */ { VC_UNDEFINED, kVK_ANSI_9 }, // 0x0B
241
+ /* 11 */ { VC_B, kVK_ANSI_0 }, // 0x0C
242
+ /* 12 */ { VC_Q, kVK_ANSI_Minus }, // 0x0D
243
+ /* 13 */ { VC_W, kVK_ANSI_Equal }, // 0x0E
244
+ /* 14 */ { VC_E, kVK_Delete }, // 0x0F
245
+ /* 15 */ { VC_R, kVK_Tab }, // 0x10
246
+ /* 16 */ { VC_Y, kVK_ANSI_Q }, // 0x11
247
+ /* 17 */ { VC_T, kVK_ANSI_W }, // 0x12
248
+ /* 18 */ { VC_1, kVK_ANSI_E }, // 0x13
249
+ /* 19 */ { VC_2, kVK_ANSI_R }, // 0x14
250
+ /* 20 */ { VC_3, kVK_ANSI_T }, // 0x15
251
+ /* 21 */ { VC_4, kVK_ANSI_Y }, // 0x16
252
+ /* 22 */ { VC_6, kVK_ANSI_U }, // 0x17
253
+ /* 23 */ { VC_5, kVK_ANSI_I }, // 0x18
254
+ /* 24 */ { VC_EQUALS, kVK_ANSI_O }, // 0x19
255
+ /* 25 */ { VC_9, kVK_ANSI_P }, // 0x19
256
+ /* 26 */ { VC_7, kVK_ANSI_LeftBracket }, // 0x1A
257
+ /* 27 */ { VC_MINUS, kVK_ANSI_RightBracket }, // 0x1B
258
+ /* 28 */ { VC_8, kVK_Return }, // 0x1C
259
+ /* 29 */ { VC_0, kVK_Control }, // 0x1D
260
+ /* 30 */ { VC_CLOSE_BRACKET, kVK_ANSI_A }, // 0x1E
261
+ /* 31 */ { VC_O, kVK_ANSI_S }, // 0x1F
262
+ /* 32 */ { VC_U, kVK_ANSI_D }, // 0x20
263
+ /* 33 */ { VC_OPEN_BRACKET, kVK_ANSI_F }, // 0x21
264
+ /* 34 */ { VC_I, kVK_ANSI_G }, // 0x22
265
+ /* 35 */ { VC_P, kVK_ANSI_H }, // 0x23
266
+ /* 36 */ { VC_ENTER, kVK_ANSI_J }, // 0x24
267
+ /* 37 */ { VC_L, kVK_ANSI_K }, // 0x25
268
+ /* 38 */ { VC_J, kVK_ANSI_L }, // 0x26
269
+ /* 39 */ { VC_QUOTE, kVK_ANSI_Semicolon }, // 0x27
270
+ /* 40 */ { VC_K, kVK_ANSI_Quote }, // 0x28
271
+ /* 41 */ { VC_SEMICOLON, kVK_ANSI_Grave }, // 0x29
272
+ /* 42 */ { VC_BACK_SLASH, kVK_Shift }, // 0x2A
273
+ /* 43 */ { VC_COMMA, kVK_ANSI_Backslash }, // 0x2B
274
+ /* 44 */ { VC_SLASH, kVK_ANSI_Z }, // 0x2C
275
+ /* 45 */ { VC_N, kVK_ANSI_X }, // 0x2D
276
+ /* 46 */ { VC_M, kVK_ANSI_C }, // 0x2E
277
+ /* 47 */ { VC_PERIOD, kVK_ANSI_V }, // 0x2F
278
+ /* 48 */ { VC_TAB, kVK_ANSI_B }, // 0x30
279
+ /* 49 */ { VC_SPACE, kVK_ANSI_N }, // 0x31
280
+ /* 50 */ { VC_BACKQUOTE, kVK_ANSI_M }, // 0x32
281
+ /* 51 */ { VC_BACKSPACE, kVK_ANSI_Comma }, // 0x33
282
+ /* 52 */ { VC_UNDEFINED, kVK_ANSI_Period }, // 0x34
283
+ /* 53 */ { VC_ESCAPE, kVK_ANSI_Slash }, // 0x35
284
+ /* 54 */ { VC_META_R, kVK_RightShift }, // 0x36
285
+ /* 55 */ { VC_META_L, kVK_ANSI_KeypadMultiply }, // 0x37
286
+ /* 56 */ { VC_SHIFT_L, kVK_Option }, // 0x38
287
+ /* 57 */ { VC_CAPS_LOCK, kVK_Space }, // 0x39
288
+ /* 58 */ { VC_ALT_L, kVK_CapsLock }, // 0x3A
289
+ /* 59 */ { VC_CONTROL_L, kVK_F1 }, // 0x3B
290
+ /* 60 */ { VC_SHIFT_R, kVK_F2 }, // 0x3C
291
+ /* 61 */ { VC_ALT_R, kVK_F3 }, // 0x3D
292
+ /* 62 */ { VC_CONTROL_R, kVK_F4 }, // 0x3E
293
+ /* 63 */ { VC_UNDEFINED, kVK_F5 }, // 0x3F
294
+ /* 64 */ { VC_F17, kVK_F6 }, // 0x40
295
+ /* 65 */ { VC_KP_SEPARATOR, kVK_F7 }, // 0x41
296
+ /* 66 */ { VC_UNDEFINED, kVK_F8 }, // 0x42
297
+ /* 67 */ { VC_KP_MULTIPLY, kVK_F9 }, // 0x43
298
+ /* 68 */ { VC_UNDEFINED, kVK_F10 }, // 0x44
299
+ /* 69 */ { VC_KP_ADD, kVK_ANSI_KeypadClear }, // 0x45
300
+ /* 70 */ { VC_UNDEFINED, kVK_Undefined }, // 0x46
301
+ /* 71 */ { VC_NUM_LOCK, kVK_ANSI_Keypad7 }, // 0x47
302
+ /* 72 */ { VC_VOLUME_UP, kVK_ANSI_Keypad8 }, // 0x48
303
+ /* 73 */ { VC_VOLUME_DOWN, kVK_ANSI_Keypad9 }, // 0x49
304
+ /* 74 */ { VC_VOLUME_MUTE, kVK_ANSI_KeypadMinus }, // 0x4A
305
+ /* 75 */ { VC_KP_DIVIDE, kVK_ANSI_Keypad4 }, // 0x4B
306
+ /* 76 */ { VC_KP_ENTER, kVK_ANSI_Keypad5 }, // 0x4C
307
+ /* 77 */ { VC_UNDEFINED, kVK_ANSI_Keypad6 }, // 0x4D
308
+ /* 78 */ { VC_KP_SUBTRACT, kVK_ANSI_KeypadPlus }, // 0x4E
309
+ /* 79 */ { VC_F18, kVK_ANSI_Keypad1 }, // 0x4F
310
+ /* 80 */ { VC_F19, kVK_ANSI_Keypad2 }, // 0x50
311
+ /* 81 */ { VC_KP_EQUALS, kVK_ANSI_Keypad3 }, // 0x51
312
+ /* 82 */ { VC_KP_0, kVK_ANSI_Keypad0 }, // 0x52
313
+ /* 83 */ { VC_KP_1, kVK_ANSI_KeypadDecimal }, // 0x53
314
+ /* 84 */ { VC_KP_2, kVK_Undefined }, // 0x54
315
+ /* 85 */ { VC_KP_3, kVK_Undefined }, // 0x55
316
+ /* 86 */ { VC_KP_4, kVK_Undefined }, // 0x56
317
+ /* 87 */ { VC_KP_5, kVK_F11 }, // 0x57
318
+ /* 88 */ { VC_KP_6, kVK_F12 }, // 0x58
319
+ /* 89 */ { VC_KP_7, kVK_Undefined }, // 0x59
320
+ /* 90 */ { VC_F20, kVK_Undefined }, // 0x5A
321
+ /* 91 */ { VC_KP_8, kVK_F13 }, // 0x5B
322
+ /* 92 */ { VC_KP_9, kVK_F14 }, // 0x5C
323
+ /* 93 */ { VC_YEN, kVK_F15 }, // 0x5D
324
+ /* 94 */ { VC_UNDERSCORE, kVK_Undefined }, // 0x5E
325
+ /* 95 */ { VC_KP_COMMA, kVK_Undefined }, // 0x5F
326
+ /* 96 */ { VC_F5, kVK_Undefined }, // 0x60
327
+ /* 97 */ { VC_F6, kVK_Undefined }, // 0x61
328
+ /* 98 */ { VC_F7, kVK_Undefined }, // 0x62
329
+ /* 99 */ { VC_F3, kVK_F16 }, // 0x63
330
+ /* 100 */ { VC_F8, kVK_F17 }, // 0x64
331
+ /* 101 */ { VC_F9, kVK_F18 }, // 0x65
332
+ /* 102 */ { VC_UNDEFINED, kVK_F19 }, // 0x66
333
+ /* 103 */ { VC_F11, kVK_F20 }, // 0x67
334
+ /* 104 */ { VC_KATAKANA, kVK_Undefined }, // 0x68
335
+ /* 105 */ { VC_F13, kVK_Undefined }, // 0x69
336
+ /* 106 */ { VC_F16, kVK_Undefined }, // 0x6A
337
+ /* 107 */ { VC_F14, kVK_Undefined }, // 0x6B
338
+ /* 108 */ { VC_UNDEFINED, kVK_Undefined }, // 0x6C FIXME kVK_JIS_Eisu same as Caps Lock ?
339
+ /* 109 */ { VC_F10, kVK_Undefined }, // 0x6D
340
+ /* 110 */ { VC_UNDEFINED, kVK_Undefined }, // 0x6E
341
+ /* 111 */ { VC_F12, kVK_Undefined }, // 0x6F
342
+ /* 112 */ { VC_UNDEFINED, kVK_JIS_Kana }, // 0x70
343
+ /* 113 */ { VC_F15, kVK_Undefined }, // 0x71
344
+ /* 114 */ { VC_INSERT, kVK_Undefined }, // 0x72
345
+ /* 115 */ { VC_HOME, kVK_JIS_Underscore }, // 0x73
346
+ /* 116 */ { VC_PAGE_UP, kVK_Undefined }, // 0x74
347
+ /* 117 */ { VC_DELETE, kVK_Undefined }, // 0x75
348
+ /* 118 */ { VC_F4, kVK_Undefined }, // 0x76
349
+ /* 119 */ { VC_END, kVK_Undefined }, // 0x77
350
+ /* 120 */ { VC_F2, kVK_Undefined }, // 0x78
351
+ /* 121 */ { VC_PAGE_DOWN, kVK_Undefined }, // 0x79
352
+ /* 122 */ { VC_F1, kVK_Undefined }, // 0x7A
353
+ /* 123 */ { VC_LEFT, kVK_Undefined }, // 0x7B
354
+ /* 124 */ { VC_RIGHT, kVK_Undefined }, // 0x7C
355
+ /* 125 */ { VC_DOWN, kVK_JIS_Yen }, // 0x7D
356
+ /* 126 */ { VC_UP, kVK_JIS_KeypadComma }, // 0x7E
357
+ /* 127 */ { VC_UNDEFINED, kVK_Undefined }, // 0x7F
358
+
359
+ // No Offset Offset (i & 0x007F) + 128
360
+
361
+ /* 128 */ { VC_UNDEFINED, kVK_Undefined }, // 0x80
362
+ /* 129 */ { VC_UNDEFINED, kVK_Undefined }, // 0x81
363
+ /* 130 */ { VC_UNDEFINED, kVK_Undefined }, // 0x82
364
+ /* 131 */ { VC_UNDEFINED, kVK_Undefined }, // 0x83
365
+ /* 132 */ { VC_UNDEFINED, kVK_Undefined }, // 0x84
366
+ /* 133 */ { VC_UNDEFINED, kVK_Undefined }, // 0x85
367
+ /* 134 */ { VC_UNDEFINED, kVK_Undefined }, // 0x86
368
+ /* 135 */ { VC_UNDEFINED, kVK_Undefined }, // 0x87
369
+ /* 136 */ { VC_UNDEFINED, kVK_Undefined }, // 0x88
370
+ /* 137 */ { VC_UNDEFINED, kVK_Undefined }, // 0x89
371
+ /* 138 */ { VC_UNDEFINED, kVK_Undefined }, // 0x8A
372
+ /* 139 */ { VC_UNDEFINED, kVK_Undefined }, // 0x8B
373
+ /* 140 */ { VC_UNDEFINED, kVK_Undefined }, // 0x8C
374
+ /* 141 */ { VC_UNDEFINED, kVK_ANSI_KeypadEquals }, // 0x8D
375
+ /* 142 */ { VC_UNDEFINED, kVK_Undefined }, // 0x8E
376
+ /* 143 */ { VC_UNDEFINED, kVK_Undefined }, // 0x8F
377
+ /* 144 */ { VC_UNDEFINED, kVK_MEDIA_Previous }, // 0x90
378
+ /* 145 */ { VC_UNDEFINED, kVK_Undefined }, // 0x91
379
+ /* 146 */ { VC_UNDEFINED, kVK_Undefined }, // 0x92
380
+ /* 147 */ { VC_UNDEFINED, kVK_Undefined }, // 0x93
381
+ /* 148 */ { VC_UNDEFINED, kVK_Undefined }, // 0x94
382
+ /* 149 */ { VC_UNDEFINED, kVK_Undefined }, // 0x95
383
+ /* 150 */ { VC_UNDEFINED, kVK_Undefined }, // 0x96
384
+ /* 151 */ { VC_UNDEFINED, kVK_Undefined }, // 0x97
385
+ /* 152 */ { VC_UNDEFINED, kVK_Undefined }, // 0x98
386
+ /* 153 */ { VC_UNDEFINED, kVK_MEDIA_Next }, // 0x99
387
+ /* 154 */ { VC_UNDEFINED, kVK_Undefined }, // 0x9A
388
+ /* 155 */ { VC_UNDEFINED, kVK_Undefined }, // 0x9B
389
+ /* 156 */ { VC_UNDEFINED, kVK_ANSI_KeypadEnter }, // 0x9C
390
+ /* 157 */ { VC_UNDEFINED, kVK_RightControl }, // 0x9D
391
+ /* 158 */ { VC_UNDEFINED, kVK_Undefined }, // 0x9E
392
+ /* 159 */ { VC_UNDEFINED, kVK_Undefined }, // 0x9F
393
+ /* 160 */ { VC_UNDEFINED, kVK_Mute }, // 0xA0
394
+ /* 161 */ { VC_UNDEFINED, kVK_Undefined }, // 0xA1
395
+ /* 162 */ { VC_UNDEFINED, kVK_MEDIA_Play }, // 0xA2
396
+ /* 163 */ { VC_UNDEFINED, kVK_Undefined }, // 0xA3
397
+ /* 164 */ { VC_UNDEFINED, kVK_Undefined }, // 0xA4
398
+ /* 165 */ { VC_UNDEFINED, kVK_Undefined }, // 0xA5
399
+ /* 166 */ { VC_UNDEFINED, kVK_Undefined }, // 0xA6
400
+ /* 167 */ { VC_UNDEFINED, kVK_Undefined }, // 0xA7
401
+ /* 168 */ { VC_UNDEFINED, kVK_Undefined }, // 0xA8
402
+ /* 169 */ { VC_UNDEFINED, kVK_Undefined }, // 0xA9
403
+ /* 170 */ { VC_UNDEFINED, kVK_Undefined }, // 0xAA
404
+ /* 171 */ { VC_UNDEFINED, kVK_Undefined }, // 0xAB
405
+ /* 172 */ { VC_UNDEFINED, kVK_NX_Eject }, // 0xAC
406
+ /* 173 */ { VC_UNDEFINED, kVK_Undefined }, // 0xAD
407
+ /* 174 */ { VC_UNDEFINED, kVK_VolumeDown }, // 0xAE
408
+ /* 175 */ { VC_UNDEFINED, kVK_Undefined }, // 0xAF
409
+ /* 176 */ { VC_UNDEFINED, kVK_VolumeUp }, // 0xB0
410
+ /* 177 */ { VC_UNDEFINED, kVK_Undefined }, // 0xB1
411
+ /* 178 */ { VC_UNDEFINED, kVK_Undefined }, // 0xB2
412
+ /* 179 */ { VC_UNDEFINED, kVK_Undefined }, // 0xB3
413
+ /* 180 */ { VC_UNDEFINED, kVK_Undefined }, // 0xB4
414
+ /* 181 */ { VC_UNDEFINED, kVK_ANSI_KeypadDivide }, // 0xB5
415
+ /* 182 */ { VC_UNDEFINED, kVK_Undefined }, // 0xB6
416
+ /* 183 */ { VC_UNDEFINED, kVK_Undefined }, // 0xB7
417
+ /* 184 */ { VC_UNDEFINED, kVK_RightOption }, // 0xB8
418
+ /* 185 */ { VC_UNDEFINED, kVK_Undefined }, // 0xB9
419
+ /* 186 */ { VC_UNDEFINED, kVK_Undefined }, // 0xBA
420
+ /* 187 */ { VC_UNDEFINED, kVK_Undefined }, // 0xBB
421
+ /* 188 */ { VC_UNDEFINED, kVK_Undefined }, // 0xBC
422
+ /* 189 */ { VC_UNDEFINED, kVK_Undefined }, // 0xBD
423
+ /* 190 */ { VC_UNDEFINED, kVK_Undefined }, // 0xBE
424
+ /* 191 */ { VC_UNDEFINED, kVK_Undefined }, // 0xBF
425
+ /* 192 */ { VC_UNDEFINED, kVK_Undefined }, // 0xC0
426
+ /* 193 */ { VC_UNDEFINED, kVK_Undefined }, // 0xC1
427
+ /* 194 */ { VC_UNDEFINED, kVK_Undefined }, // 0xC2
428
+ /* 195 */ { VC_UNDEFINED, kVK_Undefined }, // 0xC3
429
+ /* 196 */ { VC_UNDEFINED, kVK_Undefined }, // 0xC4
430
+ /* 197 */ { VC_UNDEFINED, kVK_Undefined }, // 0xC5
431
+ /* 198 */ { VC_UNDEFINED, kVK_Undefined }, // 0xC6
432
+ /* 199 */ { VC_UNDEFINED, kVK_Home }, // 0xC7
433
+ /* 200 */ { VC_UNDEFINED, kVK_UpArrow }, // 0xC8
434
+ /* 201 */ { VC_UNDEFINED, kVK_PageUp }, // 0xC9
435
+ /* 202 */ { VC_UNDEFINED, kVK_Undefined }, // 0xCA
436
+ /* 203 */ { VC_UNDEFINED, kVK_LeftArrow }, // 0xCB
437
+ /* 204 */ { VC_UNDEFINED, kVK_Undefined }, // 0xCC
438
+ /* 205 */ { VC_UNDEFINED, kVK_RightArrow }, // 0xCD
439
+ /* 206 */ { VC_UNDEFINED, kVK_Undefined }, // 0xCE
440
+ /* 207 */ { VC_UNDEFINED, kVK_End }, // 0xCF
441
+ /* 208 */ { VC_UNDEFINED, kVK_DownArrow }, // 0xD0
442
+ /* 209 */ { VC_UNDEFINED, kVK_PageDown }, // 0xD1
443
+ /* 210 */ { VC_UNDEFINED, kVK_Help }, // 0xD2
444
+ /* 211 */ { VC_UNDEFINED, kVK_ForwardDelete }, // 0xD3
445
+ /* 212 */ { VC_UNDEFINED, kVK_Undefined }, // 0xD4
446
+ /* 213 */ { VC_UNDEFINED, kVK_Undefined }, // 0xD5
447
+ /* 214 */ { VC_UNDEFINED, kVK_Undefined }, // 0xD6
448
+ /* 215 */ { VC_UNDEFINED, kVK_Undefined }, // 0xD7
449
+ /* 216 */ { VC_UNDEFINED, kVK_Undefined }, // 0xD8
450
+ /* 217 */ { VC_UNDEFINED, kVK_Undefined }, // 0xD9
451
+ /* 218 */ { VC_UNDEFINED, kVK_Undefined }, // 0xDA
452
+ /* 219 */ { VC_UNDEFINED, kVK_Command }, // 0xDB
453
+ /* 220 */ { VC_UNDEFINED, kVK_RightCommand }, // 0xDC
454
+ /* 221 */ { VC_UNDEFINED, kVK_Undefined }, // 0xDD
455
+ /* 222 */ { VC_UNDEFINED, kVK_NX_Power }, // 0xDE
456
+ /* 223 */ { VC_UNDEFINED, kVK_Undefined }, // 0xDF
457
+ /* 224 */ { VC_UNDEFINED, kVK_Undefined }, // 0xE0
458
+ /* 225 */ { VC_UNDEFINED, kVK_Undefined }, // 0xE1
459
+ /* 226 */ { VC_LESSER_GREATER, kVK_Undefined }, // 0xE2
460
+ /* 227 */ { VC_UNDEFINED, kVK_Undefined }, // 0xE3
461
+ /* 228 */ { VC_UNDEFINED, kVK_Undefined }, // 0xE4
462
+ /* 229 */ { VC_UNDEFINED, kVK_Undefined }, // 0xE5
463
+ /* 230 */ { VC_POWER, kVK_Undefined }, // 0xE6
464
+ /* 231 */ { VC_UNDEFINED, kVK_Undefined }, // 0xE7
465
+ /* 232 */ { VC_UNDEFINED, kVK_Undefined }, // 0xE8
466
+ /* 233 */ { VC_UNDEFINED, kVK_Undefined }, // 0xE9
467
+ /* 234 */ { VC_UNDEFINED, kVK_Undefined }, // 0xEA
468
+ /* 235 */ { VC_UNDEFINED, kVK_Undefined }, // 0xEB
469
+ /* 236 */ { VC_UNDEFINED, kVK_Undefined }, // 0xEC
470
+ /* 237 */ { VC_UNDEFINED, kVK_Undefined }, // 0xED
471
+ /* 238 */ { VC_MEDIA_EJECT, kVK_Undefined }, // 0xEE
472
+ /* 239 */ { VC_UNDEFINED, kVK_Undefined }, // 0xEF
473
+ /* 240 */ { VC_MEDIA_PLAY, kVK_Undefined }, // 0xF0
474
+ /* 241 */ { VC_MEDIA_NEXT, kVK_Undefined }, // 0xF1
475
+ /* 242 */ { VC_MEDIA_PREVIOUS, kVK_Undefined }, // 0xF2
476
+ /* 243 */ { VC_UNDEFINED, kVK_Undefined }, // 0xF3
477
+ /* 244 */ { VC_UNDEFINED, kVK_Undefined }, // 0xF4
478
+ /* 245 */ { VC_UNDEFINED, kVK_Undefined }, // 0xF5
479
+ /* 246 */ { VC_UNDEFINED, kVK_Undefined }, // 0xF6
480
+ /* 247 */ { VC_UNDEFINED, kVK_Undefined }, // 0xF7
481
+ /* 248 */ { VC_UNDEFINED, kVK_Undefined }, // 0xF8
482
+ /* 249 */ { VC_UNDEFINED, kVK_Undefined }, // 0xF9
483
+ /* 250 */ { VC_UNDEFINED, kVK_Undefined }, // 0xFA
484
+ /* 251 */ { VC_UNDEFINED, kVK_Undefined }, // 0xFB
485
+ /* 252 */ { VC_UNDEFINED, kVK_Undefined }, // 0xFC
486
+ /* 253 */ { VC_UNDEFINED, kVK_Undefined }, // 0xFD
487
+ /* 254 */ { VC_UNDEFINED, kVK_Undefined }, // 0xFE
488
+ /* 255 */ { VC_UNDEFINED, kVK_Undefined }, // 0xFF
489
+ };
490
+
491
+ uint16_t keycode_to_scancode(UInt64 keycode) {
492
+ uint16_t scancode = VC_UNDEFINED;
493
+
494
+ // Bound check 0 <= keycode < 256
495
+ if (keycode < sizeof(keycode_scancode_table) / sizeof(keycode_scancode_table[0])) {
496
+ scancode = keycode_scancode_table[keycode][0];
497
+ }
498
+
499
+ return scancode;
500
+ }
501
+
502
+ UInt64 scancode_to_keycode(uint16_t scancode) {
503
+ UInt64 keycode = kVK_Undefined;
504
+
505
+ // Bound check 0 <= keycode < 128
506
+ if (scancode < 128) {
507
+ keycode = keycode_scancode_table[scancode][1];
508
+ } else {
509
+ // Calculate the upper offset.
510
+ unsigned short i = (scancode & 0x007F) | 0x80;
511
+
512
+ if (i < sizeof(keycode_scancode_table) / sizeof(keycode_scancode_table[1])) {
513
+ keycode = keycode_scancode_table[i][1];
514
+ }
515
+ }
516
+
517
+ return keycode;
518
+ }
519
+
520
+ void load_input_helper() {
521
+ #if defined(USE_CARBON_LEGACY) || defined(USE_APPLICATION_SERVICES)
522
+ // Start with a fresh dead key state.
523
+ //curr_deadkey_state = 0;
524
+ #endif
525
+ }
526
+
527
+ void unload_input_helper() {
528
+ #if defined(USE_CARBON_LEGACY) || defined(USE_APPLICATION_SERVICES)
529
+ if (prev_keyboard_layout != NULL) {
530
+ // Cleanup tracking of the previous layout.
531
+ CFRelease(prev_keyboard_layout);
532
+ prev_keyboard_layout = NULL;
533
+ }
534
+ #endif
535
+ }