@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,913 @@
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 <stdbool.h>
20
+ #include <stddef.h>
21
+ #include <stdint.h>
22
+ #include <stdio.h>
23
+ #include <string.h>
24
+ #include <uiohook.h>
25
+ #include <windows.h>
26
+
27
+ #include "logger.h"
28
+ #include "input_helper.h"
29
+
30
+ static const uint16_t keycode_scancode_table[][2] = {
31
+ /* idx { vk_code, scancode }, */
32
+ /* 0 */ { VC_UNDEFINED, 0x0000 }, // 0x00
33
+ /* 1 */ { MOUSE_BUTTON1, VK_ESCAPE }, // 0x01
34
+ /* 2 */ { MOUSE_BUTTON2, 0x0031 }, // 0x02
35
+ /* 3 */ { VC_UNDEFINED, 0x0032 }, // 0x03 VK_CANCEL
36
+ /* 4 */ { MOUSE_BUTTON3, 0x0033 }, // 0x04
37
+ /* 5 */ { MOUSE_BUTTON4, 0x0034 }, // 0x05
38
+ /* 6 */ { MOUSE_BUTTON5, 0x0035 }, // 0x06
39
+ /* 7 */ { VC_UNDEFINED, 0x0036 }, // 0x07 Undefined
40
+ /* 8 */ { VC_BACKSPACE, 0x0037 }, // 0x08 VK_BACK
41
+ /* 9 */ { VC_TAB, 0x0038 }, // 0x09 VK_TAB
42
+ /* 10 */ { VC_UNDEFINED, 0x0039 }, // 0x0A Reserved
43
+ /* 11 */ { VC_UNDEFINED, 0x0030 }, // 0x0B Reserved
44
+ /* 12 */ { VC_CLEAR, VK_OEM_MINUS }, // 0x0C VK_CLEAR
45
+ /* 13 */ { VC_ENTER, VK_OEM_PLUS }, // 0x0D VK_RETURN
46
+ /* 14 */ { VC_UNDEFINED, VK_BACK }, // 0x0E Undefined
47
+ /* 15 */ { VC_UNDEFINED, VK_TAB }, // 0x0F Undefined
48
+ /* 16 */ { VC_SHIFT_L, 0x0051 }, // 0x10 VK_SHIFT
49
+ /* 17 */ { VC_CONTROL_L, 0x0057 }, // 0x11 VK_CONTROL
50
+ /* 18 */ { VC_ALT_L, 0x0045 }, // 0x12 VK_MENU ALT key
51
+ /* 19 */ { VC_PAUSE, 0x0052 }, // 0x13 VK_PAUSE
52
+ /* 20 */ { VC_CAPS_LOCK, 0x0054 }, // 0x14 VK_CAPITAL CAPS LOCK key
53
+ /* 21 */ { VC_KATAKANA, 0x0059 }, // 0x15 VK_KANA IME Kana mode
54
+ /* 22 */ { VC_UNDEFINED, 0x0055 }, // 0x16 Undefined
55
+ /* 23 */ { VC_UNDEFINED, 0x0049 }, // 0x17 VK_JUNJA IME Junja mode
56
+ /* 24 */ { VC_UNDEFINED, 0x004F }, // 0x18 VK_FINAL
57
+ /* 25 */ { VC_KANJI, 0x0050 }, // 0x19 VK_KANJI / VK_HANJA IME Kanji / Hanja mode
58
+ /* 26 */ { VC_UNDEFINED, 0x00DB }, // 0x1A Undefined
59
+ /* 27 */ { VC_ESCAPE, 0x00DD }, // 0x1B VK_ESCAPE ESC key
60
+ /* 28 */ { VC_UNDEFINED, VK_RETURN }, // 0x1C VK_CONVERT IME convert// 0x1C
61
+ /* 29 */ { VC_UNDEFINED, VK_LCONTROL }, // 0x1D VK_NONCONVERT IME nonconvert
62
+ /* 30 */ { VC_UNDEFINED, 0x0041 }, // 0x1E VK_ACCEPT IME accept
63
+ /* 31 */ { VC_UNDEFINED, 0x0053 }, // 0x1F VK_MODECHANGE IME mode change request
64
+ /* 32 */ { VC_SPACE, 0x0044 }, // 0x20 VK_SPACE SPACEBAR
65
+ /* 33 */ { VC_PAGE_UP, 0x0046 }, // 0x21 VK_PRIOR PAGE UP key
66
+ /* 34 */ { VC_PAGE_DOWN, 0x0047 }, // 0x22 VK_NEXT PAGE DOWN key
67
+ /* 35 */ { VC_END, 0x0048 }, // 0x23 VK_END END key
68
+ /* 36 */ { VC_HOME, 0x004A }, // 0x24 VK_HOME HOME key
69
+ /* 37 */ { VC_LEFT, 0x004B }, // 0x25 VK_LEFT LEFT ARROW key
70
+ /* 38 */ { VC_UP, 0x004C }, // 0x26 VK_UP UP ARROW key
71
+ /* 39 */ { VC_RIGHT, VK_OEM_1 }, // 0x27 VK_RIGHT RIGHT ARROW key
72
+ /* 40 */ { VC_DOWN, VK_OEM_7 }, // 0x28 VK_DOWN DOWN ARROW key
73
+ /* 41 */ { VC_UNDEFINED, VK_OEM_3 }, // 0x29 VK_SELECT SELECT key
74
+ /* 42 */ { VC_UNDEFINED, VK_LSHIFT }, // 0x2A VK_PRINT PRINT key
75
+ /* 43 */ { VC_UNDEFINED, VK_OEM_5 }, // 0x2B VK_EXECUTE EXECUTE key
76
+ /* 44 */ { VC_PRINTSCREEN, 0x005A }, // 0x2C VK_SNAPSHOT PRINT SCREEN key
77
+ /* 45 */ { VC_INSERT, 0x0058 }, // 0x2D VK_INSERT INS key
78
+ /* 46 */ { VC_DELETE, 0x0043 }, // 0x2E VK_DELETE DEL key
79
+ /* 47 */ { VC_UNDEFINED, 0x0056 }, // 0x2F VK_HELP HELP key
80
+ /* 48 */ { VC_0, 0x0042 }, // 0x30 0 key
81
+ /* 49 */ { VC_1, 0x004E }, // 0x31 1 key
82
+ /* 50 */ { VC_2, 0x004D }, // 0x32 2 key
83
+ /* 51 */ { VC_3, VK_OEM_COMMA }, // 0x33 3 key
84
+ /* 52 */ { VC_4, VK_OEM_PERIOD }, // 0x34 4 key
85
+ /* 53 */ { VC_5, VK_OEM_2 }, // 0x35 5 key
86
+ /* 54 */ { VC_6, VK_RSHIFT }, // 0x36 6 key
87
+ /* 55 */ { VC_7, VK_MULTIPLY }, // 0x37 7 key
88
+ /* 56 */ { VC_8, VK_LMENU }, // 0x38 8 key
89
+ /* 57 */ { VC_9, VK_SPACE }, // 0x39 9 key
90
+ /* 58 */ { VC_UNDEFINED, VK_CAPITAL }, // 0x3A Undefined
91
+ /* 59 */ { VC_UNDEFINED, VK_F1 }, // 0x3B Undefined
92
+ /* 60 */ { VC_UNDEFINED, VK_F2 }, // 0x3C Undefined
93
+ /* 61 */ { VC_UNDEFINED, VK_F3 }, // 0x3D Undefined
94
+ /* 62 */ { VC_UNDEFINED, VK_F4 }, // 0x3E Undefined
95
+ /* 63 */ { VC_UNDEFINED, VK_F5 }, // 0x3F Undefined
96
+ /* 64 */ { VC_UNDEFINED, VK_F6 }, // 0x40 Undefined
97
+ /* 65 */ { VC_A, VK_F7 }, // 0x41 A key
98
+ /* 66 */ { VC_B, VK_F8 }, // 0x42 B key
99
+ /* 67 */ { VC_C, VK_F9 }, // 0x43 C key
100
+ /* 68 */ { VC_D, VK_F10 }, // 0x44 D key
101
+ /* 69 */ { VC_E, VK_NUMLOCK }, // 0x45 E key
102
+ /* 70 */ { VC_F, VK_SCROLL }, // 0x46 F key
103
+ /* 71 */ { VC_G, VK_NUMPAD7 }, // 0x47 G key
104
+ /* 72 */ { VC_H, VK_NUMPAD8 }, // 0x48 H key
105
+ /* 73 */ { VC_I, VK_NUMPAD9 }, // 0x49 I key
106
+ /* 74 */ { VC_J, VK_SUBTRACT }, // 0x4A J key
107
+ /* 75 */ { VC_K, VK_NUMPAD4 }, // 0x4B K key
108
+ /* 76 */ { VC_L, VK_NUMPAD5 }, // 0x4C L key
109
+ /* 77 */ { VC_M, VK_NUMPAD6 }, // 0x4D M key
110
+ /* 78 */ { VC_N, VK_ADD }, // 0x4E N key
111
+ /* 79 */ { VC_O, VK_NUMPAD1 }, // 0x4F O key
112
+ /* 80 */ { VC_P, VK_NUMPAD2 }, // 0x50 P key
113
+ /* 81 */ { VC_Q, VK_NUMPAD3 }, // 0x51 Q key
114
+ /* 82 */ { VC_R, VK_NUMPAD0 }, // 0x52 R key
115
+ /* 83 */ { VC_S, VK_DECIMAL }, // 0x53 S key
116
+ /* 84 */ { VC_T, 0x0000 }, // 0x54 T key
117
+ /* 85 */ { VC_U, 0x0000 }, // 0x55 U key
118
+ /* 86 */ { VC_V, 0x0000 }, // 0x56 V key
119
+ /* 87 */ { VC_W, VK_F11 }, // 0x57 W key
120
+ /* 88 */ { VC_X, VK_F12 }, // 0x58 X key
121
+ /* 89 */ { VC_Y, 0x0000 }, // 0x59 Y key
122
+ /* 90 */ { VC_Z, 0x0000 }, // 0x5A Z key
123
+ /* 91 */ { VC_META_L, VK_F13 }, // 0x5B VK_LWIN Left Windows key (Natural keyboard)
124
+ /* 92 */ { VC_META_R, VK_F14 }, // 0x5C VK_RWIN Right Windows key (Natural keyboard)
125
+ /* 93 */ { VC_CONTEXT_MENU, VK_F15 }, // 0x5D VK_APPS Applications key (Natural keyboard)
126
+ /* 94 */ { VC_UNDEFINED, 0x0000 }, // 0x5E Reserved
127
+ /* 95 */ { VC_SLEEP, 0x0000 }, // 0x5F VK_SLEEP Computer Sleep key
128
+ /* 96 */ { VC_KP_0, 0x0000 }, // 0x60 VK_NUMPAD0 Numeric keypad 0 key
129
+ /* 97 */ { VC_KP_1, 0x0000 }, // 0x61 VK_NUMPAD1 Numeric keypad 1 key
130
+ /* 98 */ { VC_KP_2, 0x0000 }, // 0x62 VK_NUMPAD2 Numeric keypad 2 key
131
+ /* 99 */ { VC_KP_3, VK_F16 }, // 0x63 VK_NUMPAD3 Numeric keypad 3 key
132
+ /* 100 */ { VC_KP_4, VK_F17 }, // 0x64 VK_NUMPAD4 Numeric keypad 4 key
133
+ /* 101 */ { VC_KP_5, VK_F18 }, // 0x65 VK_NUMPAD5 Numeric keypad 5 key
134
+ /* 102 */ { VC_KP_6, VK_F19 }, // 0x66 VK_NUMPAD6 Numeric keypad 6 key
135
+ /* 103 */ { VC_KP_7, VK_F20 }, // 0x67 VK_NUMPAD7 Numeric keypad 7 key
136
+ /* 104 */ { VC_KP_8, VK_F21 }, // 0x68 VK_NUMPAD8 Numeric keypad 8 key
137
+ /* 105 */ { VC_KP_9, VK_F22 }, // 0x69 VK_NUMPAD9 Numeric keypad 9 key
138
+ /* 106 */ { VC_KP_MULTIPLY, VK_F23 }, // 0x6A VK_MULTIPLY Multiply key
139
+ /* 107 */ { VC_KP_ADD, VK_F24 }, // 0x6B VK_ADD Add key
140
+ /* 108 */ { VC_UNDEFINED, 0x0000 }, // 0x6C VK_SEPARATOR Separator key
141
+ /* 109 */ { VC_KP_SUBTRACT, 0x0000 }, // 0x6D VK_SUBTRACT Subtract key
142
+ /* 110 */ { VC_KP_SEPARATOR, 0x0000 }, // 0x6E VK_DECIMAL Decimal key
143
+ /* 111 */ { VC_KP_DIVIDE, 0x0000 }, // 0x6F VK_DIVIDE Divide key
144
+ /* 112 */ { VC_F1, VK_KANA }, // 0x70 VK_F1 F1 key
145
+ /* 113 */ { VC_F2, 0x0000 }, // 0x71 VK_F2 F2 key
146
+ /* 114 */ { VC_F3, 0x0000 }, // 0x72 VK_F3 F3 key
147
+ /* 115 */ { VC_F4, 0x0000 }, // 0x73 VK_F4 F4 key
148
+ /* 116 */ { VC_F5, 0x0000 }, // 0x74 VK_F5 F5 key
149
+ /* 117 */ { VC_F6, 0x0000 }, // 0x75 VK_F6 F6 key
150
+ /* 118 */ { VC_F7, 0x0000 }, // 0x76 VK_F7 F7 key
151
+ /* 119 */ { VC_F8, 0x0000 }, // 0x77 VK_F8 F8 key
152
+ /* 120 */ { VC_F9, 0x0000 }, // 0x78 VK_F9 F9 key
153
+ /* 121 */ { VC_F10, VK_KANJI }, // 0x79 VK_F10 F10 key
154
+ /* 122 */ { VC_F11, 0x0000 }, // 0x7A VK_F11 F11 key
155
+ /* 123 */ { VC_F12, 0x0000 }, // 0x7B VK_F12 F12 key
156
+ /* 124 */ { VC_F13, 0x0000 }, // 0x7C VK_F13 F13 key
157
+ /* 125 */ { VC_F14, VK_OEM_8 }, // 0x7D VK_F14 F14 key
158
+ /* 126 */ { VC_F15, 0x0000 }, // 0x7E VK_F15 F15 key
159
+ /* 127 */ { VC_F16, 0x0000 }, // 0x7F VK_F16 F16 key
160
+
161
+ // No Offset Offset (i & 0x007F) | 0x80
162
+
163
+ /* 128 */ { VC_F17, 0x0000 }, // 0x80 VK_F17 F17 key
164
+ /* 129 */ { VC_F18, 0x0000 }, // 0x81 VK_F18 F18 key
165
+ /* 130 */ { VC_F19, 0x0000 }, // 0x82 VK_F19 F19 key
166
+ /* 131 */ { VC_F20, 0x0000 }, // 0x83 VK_F20 F20 key
167
+ /* 132 */ { VC_F21, 0x0000 }, // 0x84 VK_F21 F21 key
168
+ /* 133 */ { VC_F22, 0x0000 }, // 0x85 VK_F22 F22 key
169
+ /* 134 */ { VC_F23, 0x0000 }, // 0x86 VK_F23 F23 key
170
+ /* 135 */ { VC_F24, 0x0000 }, // 0x87 VK_F24 F24 key
171
+ /* 136 */ { VC_UNDEFINED, 0x0000 }, // 0x88 Unassigned
172
+ /* 137 */ { VC_UNDEFINED, 0x0000 }, // 0x89 Unassigned
173
+ /* 138 */ { VC_UNDEFINED, 0x0000 }, // 0x8A Unassigned
174
+ /* 139 */ { VC_UNDEFINED, 0x0000 }, // 0x8B Unassigned
175
+ /* 140 */ { VC_UNDEFINED, 0x0000 }, // 0x8C Unassigned
176
+ /* 141 */ { VC_UNDEFINED, 0x0000 }, // 0x8D Unassigned
177
+ /* 142 */ { VC_UNDEFINED, 0x0000 }, // 0x8E Unassigned
178
+ /* 143 */ { VC_UNDEFINED, 0x0000 }, // 0x8F Unassigned
179
+ /* 144 */ { VC_NUM_LOCK, VK_MEDIA_PREV_TRACK }, // 0x90 VK_NUMLOCK NUM LOCK key
180
+ /* 145 */ { VC_SCROLL_LOCK, 0x0000 }, // 0x91 VK_SCROLL SCROLL LOCK key
181
+ /* 146 */ { VC_UNDEFINED, 0x0000 }, // 0x92 OEM specific
182
+ /* 147 */ { VC_UNDEFINED, 0x0000 }, // 0x93 OEM specific
183
+ /* 148 */ { VC_UNDEFINED, 0x0000 }, // 0x94 OEM specific
184
+ /* 149 */ { VC_UNDEFINED, 0x0000 }, // 0x95 OEM specific
185
+ /* 150 */ { VC_UNDEFINED, 0x0000 }, // 0x96 OEM specific
186
+ /* 151 */ { VC_UNDEFINED, 0x0000 }, // 0x97 Unassigned
187
+ /* 152 */ { VC_UNDEFINED, 0x0000 }, // 0x98 Unassigned
188
+ /* 153 */ { VC_UNDEFINED, VK_MEDIA_NEXT_TRACK }, // 0x99 Unassigned
189
+ /* 154 */ { VC_UNDEFINED, 0x0000 }, // 0x9A Unassigned
190
+ /* 155 */ { VC_UNDEFINED, 0x0000 }, // 0x9B Unassigned
191
+ /* 156 */ { VC_UNDEFINED, 0x0000 }, // 0x9C Unassigned
192
+ /* 157 */ { VC_UNDEFINED, VK_RCONTROL }, // 0x9D Unassigned
193
+ /* 158 */ { VC_UNDEFINED, 0x0000 }, // 0x9E Unassigned
194
+ /* 159 */ { VC_UNDEFINED, 0x0000 }, // 0x9F Unassigned
195
+ /* 160 */ { VC_SHIFT_L, VK_VOLUME_MUTE }, // 0xA0 VK_LSHIFT Left SHIFT key
196
+ /* 161 */ { VC_SHIFT_R, VK_LAUNCH_APP2 }, // 0xA1 VK_RSHIFT Right SHIFT key
197
+ /* 162 */ { VC_CONTROL_L, VK_MEDIA_PLAY_PAUSE }, // 0xA2 VK_LCONTROL Left CONTROL key
198
+ /* 163 */ { VC_CONTROL_R, 0x0000 }, // 0xA3 VK_RCONTROL Right CONTROL key
199
+ /* 164 */ { VC_ALT_L, VK_MEDIA_STOP }, // 0xA4 VK_LMENU Left MENU key
200
+ /* 165 */ { VC_ALT_R, 0x0000 }, // 0xA5 VK_RMENU Right MENU key
201
+ /* 166 */ { VC_BROWSER_BACK, 0x0000 }, // 0xA6 VK_BROWSER_BACK Browser Back key
202
+ /* 167 */ { VC_BROWSER_FORWARD, 0x0000 }, // 0xA7 VK_BROWSER_FORWARD Browser Forward key
203
+ /* 168 */ { VC_BROWSER_REFRESH, 0x0000 }, // 0xA8 VK_BROWSER_REFRESH Browser Refresh key
204
+ /* 169 */ { VC_BROWSER_STOP, 0x0000 }, // 0xA9 VK_BROWSER_STOP Browser Stop key
205
+ /* 170 */ { VC_BROWSER_SEARCH, 0x0000 }, // 0xAA VK_BROWSER_SEARCH Browser Search key
206
+ /* 171 */ { VC_BROWSER_FAVORITES, 0x0000 }, // 0xAB VK_BROWSER_FAVORITES Browser Favorites key
207
+ /* 172 */ { VC_BROWSER_HOME, 0x0000 }, // 0xAC VK_BROWSER_HOME Browser Start and Home key
208
+ /* 173 */ { VC_VOLUME_MUTE, 0x0000 }, // 0xAD VK_VOLUME_MUTE Volume Mute key
209
+ /* 174 */ { VC_VOLUME_DOWN, VK_VOLUME_DOWN }, // 0xAE VK_VOLUME_DOWN Volume Down key
210
+ /* 175 */ { VC_VOLUME_UP, 0x0000 }, // 0xAF VK_VOLUME_UP Volume Up key
211
+ /* 176 */ { VC_MEDIA_NEXT, VK_VOLUME_UP }, // 0xB0 VK_MEDIA_NEXT_TRACK Next Track key
212
+ /* 177 */ { VC_MEDIA_PREVIOUS, 0x0000 }, // 0xB1 VK_MEDIA_PREV_TRACK Previous Track key
213
+ /* 178 */ { VC_MEDIA_STOP, VK_BROWSER_HOME }, // 0xB2 VK_MEDIA_STOP Stop Media key
214
+ /* 179 */ { VC_MEDIA_PLAY, 0x0000 }, // 0xB3 VK_MEDIA_PLAY_PAUSE Play/Pause Media key
215
+ /* 180 */ { VC_UNDEFINED, 0x0000 }, // 0xB4 VK_LAUNCH_MAIL Start Mail key
216
+ /* 181 */ { VC_MEDIA_SELECT, VK_DIVIDE }, // 0xB5 VK_LAUNCH_MEDIA_SELECT Select Media key
217
+ /* 182 */ { VC_APP_MAIL, 0x0000 }, // 0xB6 VK_LAUNCH_APP1 Start Application 1 key
218
+ /* 183 */ { VC_APP_CALCULATOR, VK_SNAPSHOT }, // 0xB7 VK_LAUNCH_APP2 Start Application 2 key
219
+ /* 184 */ { VC_UNDEFINED, VK_RMENU }, // 0xB8 Reserved
220
+ /* 185 */ { VC_UNDEFINED, 0x0000 }, // 0xB9 Reserved
221
+ /* 186 */ { VC_SEMICOLON, 0x0000 }, // 0xBA VK_OEM_1 Varies by keyboard. For the US standard keyboard, the ';:' key
222
+ /* 187 */ { VC_EQUALS, 0x0000 }, // 0xBB VK_OEM_PLUS For any country/region, the '+' key
223
+ /* 188 */ { VC_COMMA, 0x00E6 }, // 0xBC VK_OEM_COMMA For any country/region, the ',' key
224
+ /* 189 */ { VC_MINUS, 0x0000 }, // 0xBD VK_OEM_MINUS For any country/region, the '-' key
225
+ /* 190 */ { VC_PERIOD, 0x0000 }, // 0xBE VK_OEM_PERIOD For any country/region, the '.' key
226
+ /* 191 */ { VC_SLASH, 0x0000 }, // 0xBF VK_OEM_2 Varies by keyboard. For the US standard keyboard, the '/?' key
227
+ /* 192 */ { VC_BACKQUOTE, 0x0000 }, // 0xC0 VK_OEM_3 Varies by keyboard. For the US standard keyboard, the '`~' key
228
+ /* 193 */ { VC_UNDEFINED, 0x0000 }, // 0xC1 Reserved
229
+ /* 194 */ { VC_UNDEFINED, 0x0000 }, // 0xC2 Reserved
230
+ /* 195 */ { VC_UNDEFINED, 0x0000 }, // 0xC3 Reserved
231
+ /* 196 */ { VC_UNDEFINED, 0x0000 }, // 0xC4 Reserved
232
+ /* 197 */ { VC_UNDEFINED, VK_PAUSE }, // 0xC5 Reserved
233
+ /* 198 */ { VC_UNDEFINED, 0x0000 }, // 0xC6 Reserved
234
+ /* 199 */ { VC_UNDEFINED, VK_HOME }, // 0xC7 Reserved
235
+ /* 200 */ { VC_UNDEFINED, VK_UP }, // 0xC8 Reserved
236
+ /* 201 */ { VC_UNDEFINED, VK_PRIOR }, // 0xC9 Reserved
237
+ /* 202 */ { VC_UNDEFINED, 0x0000 }, // 0xCA Reserved
238
+ /* 203 */ { VC_UNDEFINED, VK_LEFT }, // 0xCB Reserved
239
+ /* 204 */ { VC_UNDEFINED, VK_CLEAR }, // 0xCC Reserved
240
+ /* 205 */ { VC_UNDEFINED, VK_RIGHT }, // 0xCD Reserved
241
+ /* 206 */ { VC_UNDEFINED, 0x0000 }, // 0xCE Reserved
242
+ /* 207 */ { VC_UNDEFINED, VK_END }, // 0xCF Reserved
243
+ /* 208 */ { VC_UNDEFINED, VK_DOWN }, // 0xD0 Reserved
244
+ /* 209 */ { VC_UNDEFINED, VK_NEXT }, // 0xD1 Reserved
245
+ /* 210 */ { VC_UNDEFINED, VK_INSERT }, // 0xD2 Reserved
246
+ /* 211 */ { VC_UNDEFINED, VK_DELETE }, // 0xD3 Reserved
247
+ /* 212 */ { VC_UNDEFINED, 0x0000 }, // 0xD4 Reserved
248
+ /* 213 */ { VC_UNDEFINED, 0x0000 }, // 0xD5 Reserved
249
+ /* 214 */ { VC_UNDEFINED, 0x0000 }, // 0xD6 Reserved
250
+ /* 215 */ { VC_UNDEFINED, 0x0000 }, // 0xD7 Reserved
251
+ /* 216 */ { VC_UNDEFINED, 0x0000 }, // 0xD8 Unassigned
252
+ /* 217 */ { VC_UNDEFINED, 0x0000 }, // 0xD9 Unassigned
253
+ /* 218 */ { VC_UNDEFINED, 0x0000 }, // 0xDA Unassigned
254
+ /* 219 */ { VC_OPEN_BRACKET, VK_LWIN }, // 0xDB VK_OEM_4 Varies by keyboard. For the US standard keyboard, the '[{' key
255
+ /* 220 */ { VC_BACK_SLASH, VK_RWIN }, // 0xDC VK_OEM_5 Varies by keyboard. For the US standard keyboard, the '\|' key
256
+ /* 221 */ { VC_CLOSE_BRACKET, VK_APPS }, // 0xDD VK_OEM_6 Varies by keyboard. For the US standard keyboard, the ']}' key
257
+ /* 222 */ { VC_QUOTE, 0x0000 }, // 0xDE VK_OEM_7 Varies by keyboard. For the US standard keyboard, the 'single-quote/double-quote' key
258
+ /* 223 */ { VC_YEN, VK_SLEEP }, // 0xDF VK_OEM_8 Varies by keyboard.
259
+ /* 224 */ { VC_UNDEFINED, 0x0000 }, // 0xE0 Reserved
260
+ /* 225 */ { VC_UNDEFINED, 0x0000 }, // 0xE1 OEM specific
261
+ /* 226 */ { VC_LESSER_GREATER, VK_OEM_102 }, // 0xE2 VK_OEM_102 Either the angle bracket key or the backslash key on the RT 102-key keyboard
262
+ /* 227 */ { VC_UNDEFINED, 0x0000 }, // 0xE3 OEM specific
263
+ /* 228 */ { VC_UNDEFINED, 0x00E5 }, // 0xE4 VC_APP_PICTURES OEM specific
264
+ /* 229 */ { VC_APP_PICTURES, VK_BROWSER_SEARCH }, // 0xE5 VK_PROCESSKEY IME PROCESS key
265
+ /* 230 */ { VC_APP_MUSIC, VK_BROWSER_FAVORITES }, // 0xE6 OEM specific
266
+ /* 231 */ { VC_UNDEFINED, VK_BROWSER_REFRESH }, // 0xE7 VK_PACKET Used to pass Unicode characters as if they were keystrokes. The VK_PACKET key is the low word of a 32-bit Virtual Key value used for non-keyboard input methods.
267
+ /* 232 */ { VC_UNDEFINED, VK_BROWSER_STOP }, // 0xE8 Unassigned
268
+ /* 233 */ { VC_UNDEFINED, VK_BROWSER_FORWARD }, // 0xE9 OEM specific
269
+ /* 234 */ { VC_UNDEFINED, VK_BROWSER_BACK }, // 0xEA OEM specific
270
+ /* 235 */ { VC_UNDEFINED, 0x0000 }, // 0xEB OEM specific
271
+ /* 236 */ { VC_UNDEFINED, VK_LAUNCH_APP1 }, // 0xEC OEM specific
272
+ /* 237 */ { VC_UNDEFINED, VK_LAUNCH_MEDIA_SELECT }, // 0xED OEM specific
273
+ /* 238 */ { VC_UNDEFINED, 0x0000 }, // 0xEE OEM specific
274
+ /* 239 */ { VC_UNDEFINED, 0x0000 }, // 0xEF OEM specific
275
+ /* 240 */ { VC_UNDEFINED, 0x0000 }, // 0xF0 OEM specific
276
+ /* 241 */ { VC_UNDEFINED, 0x0000 }, // 0xF1 OEM specific
277
+ /* 242 */ { VC_UNDEFINED, 0x0000 }, // 0xF2 OEM specific
278
+ /* 243 */ { VC_UNDEFINED, 0x0000 }, // 0xF3 OEM specific
279
+ /* 244 */ { VC_UNDEFINED, 0x0000 }, // 0xF4 OEM specific
280
+ /* 245 */ { VC_UNDEFINED, 0x0000 }, // 0xF5 OEM specific
281
+ /* 246 */ { VC_UNDEFINED, 0x0000 }, // 0xF6 VK_ATTN Attn key
282
+ /* 247 */ { VC_UNDEFINED, 0x0000 }, // 0xF7 VK_CRSEL CrSel key
283
+ /* 248 */ { VC_UNDEFINED, 0x0000 }, // 0xF8 VK_EXSEL ExSel key
284
+ /* 249 */ { VC_UNDEFINED, 0x0000 }, // 0xF9 VK_EREOF Erase EOF key
285
+ /* 250 */ { VC_UNDEFINED, 0x0000 }, // 0xFA VK_PLAY Play key
286
+ /* 251 */ { VC_UNDEFINED, 0x0000 }, // 0xFB VK_ZOOM Zoom key
287
+ /* 252 */ { VC_UNDEFINED, 0x0000 }, // 0xFC VK_NONAME Reserved
288
+ /* 253 */ { VC_UNDEFINED, 0x0000 }, // 0xFD
289
+ /* 254 */ { VC_CLEAR, 0x0000 }, // 0xFE VK_OEM_CLEAR Clear key
290
+ /* 255 */ { VC_UNDEFINED, 0x0000 } // 0xFE Unassigned
291
+ };
292
+
293
+ unsigned short keycode_to_scancode(DWORD vk_code, DWORD flags) {
294
+ unsigned short scancode = VC_UNDEFINED;
295
+
296
+ // Check the vk_code is in range.
297
+ // NOTE vk_code >= 0 is assumed because DWORD is unsigned.
298
+ if (vk_code < sizeof(keycode_scancode_table) / sizeof(keycode_scancode_table[0])) {
299
+ scancode = keycode_scancode_table[vk_code][0];
300
+
301
+ if (!(flags & LLKHF_EXTENDED)) {
302
+ logger(LOG_LEVEL_DEBUG, "%s [%u]: Using extended lookup for vk_code: %li\n",
303
+ __FUNCTION__, __LINE__, vk_code);
304
+
305
+ switch (vk_code) {
306
+ case VK_PRIOR:
307
+ case VK_NEXT:
308
+ case VK_END:
309
+ case VK_HOME:
310
+ case VK_LEFT:
311
+ case VK_UP:
312
+ case VK_RIGHT:
313
+ case VK_DOWN:
314
+
315
+ case VK_INSERT:
316
+ case VK_DELETE:
317
+ scancode |= 0xEE00;
318
+ break;
319
+ }
320
+ } else {
321
+ logger(LOG_LEVEL_DEBUG, "%s [%u]: Using normal lookup for vk_code: %li\n",
322
+ __FUNCTION__, __LINE__, vk_code);
323
+
324
+ switch (vk_code) {
325
+ case VK_RETURN:
326
+ scancode |= 0x0E00;
327
+ break;
328
+ }
329
+ }
330
+ }
331
+
332
+ return scancode;
333
+ }
334
+
335
+ DWORD scancode_to_keycode(unsigned short scancode) {
336
+ unsigned short keycode = 0x0000;
337
+
338
+ // Check the vk_code is in range.
339
+ // NOTE vk_code >= 0 is assumed because the scancode is unsigned.
340
+ if (scancode < 128) {
341
+ keycode = keycode_scancode_table[scancode][1];
342
+ } else {
343
+ // Calculate the upper offset based on the lower half of the scancode + 128.
344
+ unsigned short int i = (scancode & 0x007F) | 0x80;
345
+
346
+ if (i < sizeof(keycode_scancode_table) / sizeof(keycode_scancode_table[1])) {
347
+ keycode = keycode_scancode_table[i][1];
348
+ }
349
+ }
350
+
351
+ return keycode;
352
+ }
353
+
354
+ /* Track the amount of vertical and horizontal rotation between "clicks."
355
+ * This is between mouse wheel delta. */
356
+ static int16_t v_rotation, h_rotation;
357
+
358
+ int16_t get_scroll_wheel_rotation(DWORD data, uint8_t direction) {
359
+ int16_t value;
360
+
361
+ /* Delta GET_WHEEL_DELTA_WPARAM(mshook->mouseData)
362
+ * A positive value indicates that the wheel was rotated
363
+ * forward, away from the user; a negative value indicates that
364
+ * the wheel was rotated backward, toward the user. One wheel
365
+ * click is defined as WHEEL_DELTA, which is 120. */
366
+ if (direction == WHEEL_VERTICAL_DIRECTION) {
367
+ v_rotation += (int16_t) GET_WHEEL_DELTA_WPARAM(data);
368
+ // Vertical direction needs to be inverted on Windows to conform with other platforms.
369
+ value = (int16_t) v_rotation / (-1 * WHEEL_DELTA);
370
+ v_rotation %= WHEEL_DELTA;
371
+ } else {
372
+ h_rotation += (int16_t) GET_WHEEL_DELTA_WPARAM(data);
373
+ value = (int16_t) h_rotation / WHEEL_DELTA;
374
+ h_rotation %= WHEEL_DELTA;
375
+ }
376
+
377
+ return value;
378
+ }
379
+
380
+ /***********************************************************************
381
+ * The following code is based on code provided by Marc-André Moreau
382
+ * to work around a failure to support dead keys in the ToUnicode() API.
383
+ * According to the author some parts were taken directly from
384
+ * Microsoft's kbd.h header file that is shipped with the Windows Driver
385
+ * Development Kit.
386
+ *
387
+ * The original code was substantially modified to provide the following:
388
+ * 1) More dynamic code structure.
389
+ * 2) Support for compilers that do not implement _ptr64 (GCC / LLVM).
390
+ * 3) Support for Wow64 at runtime via 32-bit binary.
391
+ * 4) Support for contextual language switching.
392
+ *
393
+ * I have contacted Marc-André Moreau who has granted permission for
394
+ * his original source code to be used under the Public Domain. Although
395
+ * the libUIOHook library as a whole is currently covered under the LGPLv3,
396
+ * please feel free to use and learn from the source code contained in the
397
+ * following functions under the terms of the Public Domain.
398
+ *
399
+ * For further reading and the original code, please visit:
400
+ * http://legacy.docdroppers.org/wiki/index.php?title=Writing_Keyloggers
401
+ * http://www.techmantras.com/content/writing-keyloggers-full-length-tutorial
402
+ *
403
+ ***********************************************************************/
404
+
405
+ // Structure and pointers for the keyboard locale cache.
406
+ typedef struct _KeyboardLocale {
407
+ HKL id; // Locale ID
408
+ HINSTANCE library; // Keyboard DLL instance.
409
+ PVK_TO_BIT pVkToBit; // Pointers struct arrays.
410
+ PVK_TO_WCHAR_TABLE pVkToWcharTable;
411
+ PDEADKEY pDeadKey;
412
+ struct _KeyboardLocale* next;
413
+ } KeyboardLocale;
414
+
415
+ static KeyboardLocale* locale_first = NULL;
416
+ static KeyboardLocale* locale_current = NULL;
417
+ static WCHAR deadChar = WCH_NONE;
418
+
419
+ // Amount of pointer padding to apply for Wow64 instances.
420
+ static unsigned short int ptr_padding = 0;
421
+
422
+ #if defined(_WIN32) && !defined(_WIN64)
423
+ // Small function to check and see if we are executing under Wow64.
424
+ static BOOL is_wow64() {
425
+ BOOL status = FALSE;
426
+
427
+ LPFN_ISWOW64PROCESS pIsWow64Process = (LPFN_ISWOW64PROCESS)
428
+ GetProcAddress(GetModuleHandle("kernel32"), "IsWow64Process");
429
+
430
+ if (pIsWow64Process != NULL) {
431
+ HANDLE current_proc = GetCurrentProcess();
432
+
433
+ if (!pIsWow64Process(current_proc, &status)) {
434
+ status = FALSE;
435
+
436
+ logger(LOG_LEVEL_DEBUG, "%s [%u]: pIsWow64Process(%#p, %#p) failed!\n",
437
+ __FUNCTION__, __LINE__, current_proc, &status);
438
+ }
439
+ }
440
+
441
+ return status;
442
+ }
443
+ #endif
444
+
445
+ // Locate the DLL that contains the current keyboard layout.
446
+ static int get_keyboard_layout_file(char *layoutFile, DWORD bufferSize) {
447
+ int status = UIOHOOK_FAILURE;
448
+ HKEY hKey;
449
+ DWORD varType = REG_SZ;
450
+
451
+ char kbdName[KL_NAMELENGTH * 4];
452
+ if (GetKeyboardLayoutName(kbdName)) {
453
+ logger(LOG_LEVEL_DEBUG, "%s [%u]: Found keyboard layout \"%s\".\n",
454
+ __FUNCTION__, __LINE__, kbdName);
455
+
456
+ const char *regPrefix = "SYSTEM\\CurrentControlSet\\Control\\Keyboard Layouts\\";
457
+ size_t regPathSize = strlen(regPrefix) + strlen(kbdName) + 1;
458
+ char *regPath = malloc(regPathSize);
459
+ if (regPath != NULL) {
460
+ strcpy_s(regPath, regPathSize, regPrefix);
461
+ strcat_s(regPath, regPathSize, kbdName);
462
+
463
+ if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, (LPCTSTR) regPath, 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS) {
464
+ const char *regKey = "Layout File";
465
+ if (RegQueryValueEx(hKey, regKey, NULL, &varType, (LPBYTE) layoutFile, &bufferSize) == ERROR_SUCCESS) {
466
+ RegCloseKey(hKey);
467
+ status = UIOHOOK_SUCCESS;
468
+ } else {
469
+ logger(LOG_LEVEL_WARN, "%s [%u]: RegOpenKeyEx failed to open key: \"%s\"!\n",
470
+ __FUNCTION__, __LINE__, regKey);
471
+ }
472
+ } else {
473
+ logger(LOG_LEVEL_WARN, "%s [%u]: RegOpenKeyEx failed to open key: \"%s\"!\n",
474
+ __FUNCTION__, __LINE__, regPath);
475
+ }
476
+
477
+ free(regPath);
478
+ } else {
479
+ logger(LOG_LEVEL_WARN, "%s [%u]: malloc(%u) failed!\n",
480
+ __FUNCTION__, __LINE__, regPathSize);
481
+ }
482
+ } else {
483
+ logger(LOG_LEVEL_WARN, "%s [%u]: GetKeyboardLayoutName() failed!\n",
484
+ __FUNCTION__, __LINE__);
485
+ }
486
+
487
+ return status;
488
+ }
489
+
490
+ // Returns the number of locales that were loaded.
491
+ static int refresh_locale_list() {
492
+ int count = 0;
493
+
494
+ // Get the number of layouts the user has activated.
495
+ int hkl_size = GetKeyboardLayoutList(0, NULL);
496
+ if (hkl_size > 0) {
497
+ logger(LOG_LEVEL_DEBUG, "%s [%u]: GetKeyboardLayoutList(0, NULL) found %i layouts.\n",
498
+ __FUNCTION__, __LINE__, hkl_size);
499
+
500
+ // Get the thread id that currently has focus for our default.
501
+ DWORD focus_pid = GetWindowThreadProcessId(GetForegroundWindow(), NULL);
502
+ HKL hlk_focus = GetKeyboardLayout(focus_pid);
503
+ HKL hlk_default = GetKeyboardLayout(0);
504
+ HKL *hkl_list = malloc(sizeof(HKL) * hkl_size);
505
+
506
+ int new_size = GetKeyboardLayoutList(hkl_size, hkl_list);
507
+ if (new_size > 0) {
508
+ if (new_size != hkl_size) {
509
+ logger(LOG_LEVEL_WARN, "%s [%u]: Locale size mismatch! "
510
+ "Expected %i, received %i!\n",
511
+ __FUNCTION__, __LINE__, hkl_size, new_size);
512
+ } else {
513
+ logger(LOG_LEVEL_DEBUG, "%s [%u]: Received %i locales.\n",
514
+ __FUNCTION__, __LINE__, new_size);
515
+ }
516
+
517
+ KeyboardLocale* locale_previous = NULL;
518
+ KeyboardLocale* locale_item = locale_first;
519
+
520
+ // Go though the linked list and remove KeyboardLocale's that are
521
+ // no longer loaded.
522
+ while (locale_item != NULL) {
523
+ // Check to see if the old HKL is in the new list.
524
+ bool is_loaded = false;
525
+ for (int i = 0; i < new_size && !is_loaded; i++) {
526
+ if (locale_item->id == hkl_list[i]) {
527
+ // Flag and jump out of the loop.
528
+ hkl_list[i] = NULL;
529
+ is_loaded = true;
530
+ }
531
+ }
532
+
533
+
534
+ if (is_loaded) {
535
+ logger(LOG_LEVEL_DEBUG, "%s [%u]: Found locale ID %#p in the cache.\n",
536
+ __FUNCTION__, __LINE__, locale_item->id);
537
+
538
+ // Set the previous local to the current locale.
539
+ locale_previous = locale_item;
540
+
541
+ // Check and see if the locale is our current active locale.
542
+ if (locale_item->id == hlk_focus) {
543
+ locale_current = locale_item;
544
+ }
545
+
546
+ count++;
547
+ } else {
548
+ logger(LOG_LEVEL_DEBUG, "%s [%u]: Removing locale ID %#p from the cache.\n",
549
+ __FUNCTION__, __LINE__, locale_item->id);
550
+
551
+ // If the old id is not in the new list, remove it.
552
+ locale_previous->next = locale_item->next;
553
+
554
+ // Make sure the locale_current points NULL or something valid.
555
+ if (locale_item == locale_current) {
556
+ locale_current = NULL;
557
+ }
558
+
559
+ // Free the memory used by locale_item;
560
+ free(locale_item);
561
+
562
+ // Set the item to the pervious item to guarantee a next.
563
+ locale_item = locale_previous;
564
+ }
565
+
566
+ // Iterate to the next linked list item.
567
+ locale_item = locale_item->next;
568
+ }
569
+
570
+
571
+ // Insert anything new into the linked list.
572
+ for (int i = 0; i < new_size; i++) {
573
+ // Check to see if the item was already in the list.
574
+ if (hkl_list[i] != NULL) {
575
+ // Set the active keyboard layout for this thread to the HKL.
576
+ ActivateKeyboardLayout(hkl_list[i], 0x00);
577
+
578
+ // Try to pull the current keyboard layout DLL from the registry.
579
+ char layoutFile[MAX_PATH];
580
+ if (get_keyboard_layout_file(layoutFile, MAX_PATH) == UIOHOOK_SUCCESS) {
581
+ // You can't trust the %SYSPATH%, look it up manually.
582
+ char systemDirectory[MAX_PATH];
583
+ if (GetSystemDirectory(systemDirectory, MAX_PATH) != 0) {
584
+ char kbdLayoutFilePath[MAX_PATH];
585
+ snprintf(kbdLayoutFilePath, MAX_PATH, "%s\\%s", systemDirectory, layoutFile);
586
+
587
+ logger(LOG_LEVEL_DEBUG, "%s [%u]: Loading layout for %#p: %s.\n",
588
+ __FUNCTION__, __LINE__, hkl_list[i], layoutFile);
589
+
590
+ // Create the new locale item.
591
+ locale_item = malloc(sizeof(KeyboardLocale));
592
+ locale_item->id = hkl_list[i];
593
+ locale_item->library = LoadLibrary(kbdLayoutFilePath);
594
+
595
+ #if __GNUC__
596
+ #pragma GCC diagnostic push
597
+ #pragma GCC diagnostic ignored "-Wcast-function-type"
598
+ #endif
599
+ // Get the function pointer from the library to get the keyboard layer descriptor.
600
+ KbdLayerDescriptor pKbdLayerDescriptor = (KbdLayerDescriptor) GetProcAddress(locale_item->library, "KbdLayerDescriptor");
601
+ #if __GNUC__
602
+ #pragma GCC diagnostic pop
603
+ #endif
604
+
605
+ if (pKbdLayerDescriptor != NULL) {
606
+ PKBDTABLES pKbd = pKbdLayerDescriptor();
607
+
608
+ // Store the memory address of the following 3 structures.
609
+ BYTE *base = (BYTE *) pKbd;
610
+
611
+ // First element of each structure, no offset adjustment needed.
612
+ locale_item->pVkToBit = pKbd->pCharModifiers->pVkToBit;
613
+
614
+ // Second element of pKbd, +4 byte offset on wow64.
615
+ locale_item->pVkToWcharTable = *((PVK_TO_WCHAR_TABLE *) (base + offsetof(KBDTABLES, pVkToWcharTable) + ptr_padding));
616
+
617
+ // Third element of pKbd, +8 byte offset on wow64.
618
+ locale_item->pDeadKey = *((PDEADKEY *) (base + offsetof(KBDTABLES, pDeadKey) + (ptr_padding * 2)));
619
+
620
+ // This will always be added to the end of the list.
621
+ locale_item->next = NULL;
622
+
623
+ // Insert the item into the linked list.
624
+ if (locale_previous == NULL) {
625
+ // If nothing came before, the list is empty.
626
+ locale_first = locale_item;
627
+ } else {
628
+ // Append the new locale to the end of the list.
629
+ locale_previous->next = locale_item;
630
+ }
631
+
632
+ // Check and see if the locale is our current active locale.
633
+ if (locale_item->id == hlk_focus) {
634
+ locale_current = locale_item;
635
+ }
636
+
637
+ // Set the pervious locale item to the new one.
638
+ locale_previous = locale_item;
639
+
640
+ count++;
641
+ } else {
642
+ logger(LOG_LEVEL_ERROR,
643
+ "%s [%u]: GetProcAddress() failed for KbdLayerDescriptor!\n",
644
+ __FUNCTION__, __LINE__);
645
+
646
+ FreeLibrary(locale_item->library);
647
+ free(locale_item);
648
+ locale_item = NULL;
649
+ }
650
+ } else {
651
+ logger(LOG_LEVEL_ERROR,
652
+ "%s [%u]: GetSystemDirectory() failed!\n",
653
+ __FUNCTION__, __LINE__);
654
+ }
655
+ } else {
656
+ logger(LOG_LEVEL_ERROR,
657
+ "%s [%u]: Could not find keyboard map for locale %#p!\n",
658
+ __FUNCTION__, __LINE__, hkl_list[i]);
659
+ }
660
+ }
661
+ }
662
+ } else {
663
+ logger(LOG_LEVEL_ERROR,
664
+ "%s [%u]: GetKeyboardLayoutList() failed!\n",
665
+ __FUNCTION__, __LINE__);
666
+
667
+ // TODO Try and recover by using the current layout.
668
+ // Hint: Use locale_id instead of hkl_list[i] in the loop above.
669
+ }
670
+
671
+ free(hkl_list);
672
+ ActivateKeyboardLayout(hlk_default, 0x00);
673
+ }
674
+
675
+ return count;
676
+ }
677
+
678
+ // Returns the number of chars written to the buffer.
679
+ SIZE_T keycode_to_unicode(DWORD keycode, PWCHAR buffer, SIZE_T size) {
680
+ // Get the thread id that currently has focus and ask for its current locale.
681
+ DWORD focus_pid = GetWindowThreadProcessId(GetForegroundWindow(), NULL);
682
+ HKL locale_id = GetKeyboardLayout(focus_pid);
683
+ if (locale_id == NULL) {
684
+ // Default to the current thread's layout if the focused window fails.
685
+ locale_id = GetKeyboardLayout(0);
686
+ }
687
+
688
+ // If the current Locale is not the new locale, search the linked list.
689
+ if (locale_current == NULL || locale_current->id != locale_id) {
690
+ locale_current = NULL;
691
+ KeyboardLocale* locale_item = locale_first;
692
+
693
+ // Search the linked list...
694
+ while (locale_item != NULL && locale_item->id != locale_id) {
695
+ locale_item = locale_item->next;
696
+ }
697
+
698
+ // You may already be a winner!
699
+ if (locale_item != NULL && locale_item->id == locale_id) {
700
+ logger(LOG_LEVEL_DEBUG,
701
+ "%s [%u]: Activating keyboard layout %#p.\n",
702
+ __FUNCTION__, __LINE__, locale_item->id);
703
+
704
+ // Switch the current locale.
705
+ locale_current = locale_item;
706
+ locale_item = NULL;
707
+
708
+ // If they layout changes the dead key state needs to be reset.
709
+ // This is consistent with the way Windows handles locale changes.
710
+ deadChar = WCH_NONE;
711
+ } else {
712
+ logger(LOG_LEVEL_DEBUG,
713
+ "%s [%u]: Refreshing locale cache.\n",
714
+ __FUNCTION__, __LINE__);
715
+
716
+ refresh_locale_list();
717
+ }
718
+ }
719
+
720
+ // Initialize to empty.
721
+ SIZE_T charCount = 0;
722
+ // buffer[i] = WCH_NONE;
723
+
724
+ // Check and make sure the Unicode helper was loaded.
725
+ if (locale_current != NULL) {
726
+ logger(LOG_LEVEL_DEBUG,
727
+ "%s [%u]: Using keyboard layout %#p.\n",
728
+ __FUNCTION__, __LINE__, locale_current->id);
729
+
730
+ int mod = 0;
731
+
732
+ int capsLock = (GetKeyState(VK_CAPITAL) & 0x01);
733
+
734
+ PVK_TO_BIT pVkToBit = locale_current->pVkToBit;
735
+ PVK_TO_WCHAR_TABLE pVkToWcharTable = locale_current->pVkToWcharTable;
736
+ PDEADKEY pDeadKey = locale_current->pDeadKey;
737
+
738
+ /* Loop over the modifier keys for this locale and determine what is
739
+ * currently depressed. Because this is only a structure of two
740
+ * bytes, we don't need to worry about the structure padding of __ptr64
741
+ * offsets on Wow64.
742
+ */
743
+ bool is_shift = false, is_ctrl = false, is_alt = false;
744
+ for (int i = 0; pVkToBit[i].Vk != 0; i++) {
745
+ short state = GetAsyncKeyState(pVkToBit[i].Vk);
746
+
747
+ // Check to see if the most significant bit is active.
748
+ if (state & ~SHRT_MAX) {
749
+ if (pVkToBit[i].Vk == VK_SHIFT) {
750
+ is_shift = true;
751
+ } else if (pVkToBit[i].Vk == VK_CONTROL) {
752
+ is_ctrl = true;
753
+ } else if (pVkToBit[i].Vk == VK_MENU) {
754
+ is_alt = true;
755
+ }
756
+ }
757
+ }
758
+
759
+ // Check the Shift modifier.
760
+ if (is_shift) {
761
+ mod = 1;
762
+ }
763
+
764
+ // Check for the AltGr modifier.
765
+ if (is_ctrl && is_alt) {
766
+ mod += 3;
767
+ }
768
+
769
+ // Default 32 bit structure size should be 6 bytes (4 for the pointer and 2
770
+ // additional byte fields) that are padded out to 8 bytes by the compiler.
771
+ unsigned short sizeVkToWcharTable = sizeof(VK_TO_WCHAR_TABLE);
772
+ #if defined(_WIN32) && !defined(_WIN64)
773
+ if (is_wow64()) {
774
+ // If we are running under Wow64 the size of the first pointer will be
775
+ // 8 bringing the total size to 10 bytes padded out to 16.
776
+ sizeVkToWcharTable = (sizeVkToWcharTable + ptr_padding + 7) & -8;
777
+ }
778
+ #endif
779
+
780
+ BYTE *ptrCurrentVkToWcharTable = (BYTE *) pVkToWcharTable;
781
+
782
+ int cbSize, n;
783
+ do {
784
+ // cbSize is used to calculate n, and n is used for the size of pVkToWchars[j].wch[n]
785
+ cbSize = *(ptrCurrentVkToWcharTable + offsetof(VK_TO_WCHAR_TABLE, cbSize) + ptr_padding);
786
+ n = (cbSize - 2) / 2;
787
+
788
+ // Same as VK_TO_WCHARS pVkToWchars[] = pVkToWcharTable[i].pVkToWchars
789
+ PVK_TO_WCHARS pVkToWchars = (PVK_TO_WCHARS) ((PVK_TO_WCHAR_TABLE) ptrCurrentVkToWcharTable)->pVkToWchars;
790
+
791
+ if (pVkToWchars != NULL && mod < n) {
792
+ // pVkToWchars[j].VirtualKey
793
+ BYTE *pCurrentVkToWchars = (BYTE *) pVkToWchars;
794
+
795
+ do {
796
+ if (((PVK_TO_WCHARS) pCurrentVkToWchars)->VirtualKey == keycode) {
797
+ if ((((PVK_TO_WCHARS) pCurrentVkToWchars)->Attributes == CAPLOK) && capsLock) {
798
+ if (is_shift && mod > 0) {
799
+ mod -= 1;
800
+ } else {
801
+ mod += 1;
802
+ }
803
+ }
804
+
805
+ // Set the initial unicode char.
806
+ WCHAR unicode = ((PVK_TO_WCHARS) pCurrentVkToWchars)->wch[mod];
807
+
808
+ // Increment the pCurrentVkToWchars by the size of wch[n].
809
+ pCurrentVkToWchars += sizeof(VK_TO_WCHARS) + (sizeof(WCHAR) * n);
810
+
811
+
812
+ if (unicode == WCH_DEAD) {
813
+ // The current unicode char is a dead key...
814
+ if (deadChar == WCH_NONE) {
815
+ // No previous dead key was set so cache the next
816
+ // wchar so we know what to do next time its pressed.
817
+ deadChar = ((PVK_TO_WCHARS) pCurrentVkToWchars)->wch[mod];
818
+ } else {
819
+ if (size >= 2) {
820
+ // Received a second dead key.
821
+ memset(buffer, deadChar, 2);
822
+ //buffer[0] = deadChar;
823
+ //buffer[1] = deadChar;
824
+
825
+ deadChar = WCH_NONE;
826
+ charCount = 2;
827
+ }
828
+ }
829
+ } else if (unicode != WCH_NONE) {
830
+ // We are not WCH_NONE or WCH_DEAD
831
+ if (size >= 1) {
832
+ buffer[0] = unicode;
833
+ charCount = 1;
834
+ }
835
+ }
836
+
837
+ break;
838
+ } else {
839
+ // Add sizeof WCHAR because we are really an array of WCHAR[n] not WCHAR[]
840
+ pCurrentVkToWchars += sizeof(VK_TO_WCHARS) + (sizeof(WCHAR) * n);
841
+ }
842
+ } while ( ((PVK_TO_WCHARS) pCurrentVkToWchars)->VirtualKey != 0 );
843
+ }
844
+
845
+ // This is effectively the same as: ptrCurrentVkToWcharTable = pVkToWcharTable[++i];
846
+ ptrCurrentVkToWcharTable += sizeVkToWcharTable;
847
+ } while (cbSize != 0);
848
+
849
+
850
+ // If the current local has a dead key set.
851
+ if (deadChar != WCH_NONE) {
852
+ // Loop over the pDeadKey lookup table for the locale.
853
+ for (int i = 0; pDeadKey[i].dwBoth != 0; i++) {
854
+ WCHAR baseChar = (WCHAR) pDeadKey[i].dwBoth;
855
+ WCHAR diacritic = (WCHAR) (pDeadKey[i].dwBoth >> 16);
856
+
857
+ // If we locate an extended dead char, set it.
858
+ if (size >= 1 && baseChar == buffer[0] && diacritic == deadChar) {
859
+ deadChar = WCH_NONE;
860
+
861
+ if (charCount <= size) {
862
+ memset(buffer, (WCHAR) pDeadKey[i].wchComposed, charCount);
863
+ //buffer[i] = (WCHAR) pDeadKey[i].wchComposed;
864
+ }
865
+ }
866
+ }
867
+ }
868
+ }
869
+
870
+ return charCount;
871
+ }
872
+
873
+ // Returns the number of locales that were loaded.
874
+ int load_input_helper() {
875
+ #if defined(_WIN32) && !defined(_WIN64)
876
+ if (is_wow64()) {
877
+ ptr_padding = sizeof(void *);
878
+ }
879
+ #endif
880
+
881
+ v_rotation = 0;
882
+ h_rotation = 0;
883
+
884
+ int count = refresh_locale_list();
885
+
886
+ logger(LOG_LEVEL_DEBUG,
887
+ "%s [%u]: refresh_locale_list() found %i locale(s).\n",
888
+ __FUNCTION__, __LINE__, count);
889
+
890
+ return count;
891
+ }
892
+
893
+ // Returns the number of locales that were removed.
894
+ int unload_input_helper() {
895
+ int count = 0;
896
+
897
+ // Cleanup and free memory from the old list.
898
+ KeyboardLocale* locale_item = locale_first;
899
+ while (locale_item != NULL) {
900
+ // Remove the first item from the linked list.
901
+ FreeLibrary(locale_item->library);
902
+ locale_first = locale_item->next;
903
+ free(locale_item);
904
+ locale_item = locale_first;
905
+
906
+ count++;
907
+ }
908
+
909
+ // Reset the current local.
910
+ locale_current = NULL;
911
+
912
+ return count;
913
+ }