Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 42ff6c2

Browse files
committedJun 23, 2023
Refactoring dispatcher for Windows.
1 parent 3b69090 commit 42ff6c2

File tree

5 files changed

+530
-452
lines changed

5 files changed

+530
-452
lines changed
 

‎src/windows/dispatch_event.c

+458
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,461 @@
1515
* You should have received a copy of the GNU Lesser General Public License
1616
* along with this program. If not, see <http://www.gnu.org/licenses/>.
1717
*/
18+
19+
#include <uiohook.h>
20+
21+
#include "dispatch_event.h"
22+
#include "input_helper.h"
23+
#include "logger.h"
24+
25+
// Virtual event pointer.
26+
static uiohook_event uio_event;
27+
28+
// Click count globals.
29+
static unsigned short click_count = 0;
30+
static uint64_t click_time = 0;
31+
static unsigned short int click_button = MOUSE_NOBUTTON;
32+
static POINT last_click;
33+
34+
// Event dispatch callback.
35+
static dispatcher_t dispatch = NULL;
36+
static void *dispatch_data = NULL;
37+
38+
39+
UIOHOOK_API void hook_set_dispatch_proc(dispatcher_t dispatch_proc, void *user_data) {
40+
logger(LOG_LEVEL_DEBUG, "%s [%u]: Setting new dispatch callback to %#p.\n",
41+
__FUNCTION__, __LINE__, dispatch_proc);
42+
43+
dispatch = dispatch_proc;
44+
dispatch_data = user_data;
45+
}
46+
47+
#ifdef USE_EPOCH_TIME
48+
static uint64_t get_unix_timestamp() {
49+
// Get the local system time in UTC.
50+
GetSystemTimeAsFileTime(&system_time);
51+
52+
// Convert the local system time to a Unix epoch in MS.
53+
// milliseconds = 100-nanoseconds / 10000
54+
uint64_t timestamp = (((uint64_t) system_time.dwHighDateTime << 32) | system_time.dwLowDateTime) / 10000;
55+
56+
// Convert Windows epoch to Unix epoch. (1970 - 1601 in milliseconds)
57+
timestamp -= 11644473600000;
58+
59+
return timestamp;
60+
}
61+
#endif
62+
63+
// Send out an event if a dispatcher was set.
64+
static void dispatch_event(uiohook_event *const event) {
65+
if (dispatch != NULL) {
66+
logger(LOG_LEVEL_DEBUG, "%s [%u]: Dispatching event type %u.\n",
67+
__FUNCTION__, __LINE__, event->type);
68+
69+
dispatch(event, dispatch_data);
70+
} else {
71+
logger(LOG_LEVEL_WARN, "%s [%u]: No dispatch callback set!\n",
72+
__FUNCTION__, __LINE__);
73+
}
74+
}
75+
76+
bool dispatch_hook_enable() {
77+
bool consumed = false;
78+
// Initialize native input helper functions.
79+
load_input_helper();
80+
81+
// Get the local system time in UNIX epoch form.
82+
#ifdef USE_EPOCH_TIME
83+
uint64_t timestamp = get_unix_timestamp();
84+
#else
85+
uint64_t timestamp = GetMessageTime();
86+
#endif
87+
88+
// Populate the hook start event.
89+
uio_event.time = timestamp;
90+
uio_event.reserved = 0x00;
91+
92+
uio_event.type = EVENT_HOOK_ENABLED;
93+
uio_event.mask = 0x00;
94+
95+
// Fire the hook start event.
96+
dispatch_event(&uio_event);
97+
consumed = uio_event.reserved & 0x01;
98+
99+
return consumed;
100+
}
101+
102+
bool dispatch_hook_disable() {
103+
bool consumed = false;
104+
// Get the local system time in UNIX epoch form.
105+
#ifdef USE_EPOCH_TIME
106+
uint64_t timestamp = get_unix_timestamp();
107+
#else
108+
uint64_t timestamp = GetMessageTime();
109+
#endif
110+
111+
// Populate the hook stop event.
112+
uio_event.time = timestamp;
113+
uio_event.reserved = 0x00;
114+
115+
uio_event.type = EVENT_HOOK_DISABLED;
116+
uio_event.mask = 0x00;
117+
118+
// Fire the hook stop event.
119+
dispatch_event(&uio_event);
120+
consumed = uio_event.reserved & 0x01;
121+
122+
// Deinitialize native input helper functions.
123+
unload_input_helper();
124+
125+
return consumed;
126+
}
127+
128+
bool dispatch_key_press(KBDLLHOOKSTRUCT *kbhook) {
129+
bool consumed = false;
130+
#ifdef USE_EPOCH_TIME
131+
uint64_t timestamp = get_unix_timestamp();
132+
#else
133+
uint64_t timestamp = kbhook->time;
134+
#endif
135+
136+
// Check and setup modifiers.
137+
if (kbhook->vkCode == VK_LSHIFT) { set_modifier_mask(MASK_SHIFT_L); }
138+
else if (kbhook->vkCode == VK_RSHIFT) { set_modifier_mask(MASK_SHIFT_R); }
139+
else if (kbhook->vkCode == VK_LCONTROL) { set_modifier_mask(MASK_CTRL_L); }
140+
else if (kbhook->vkCode == VK_RCONTROL) { set_modifier_mask(MASK_CTRL_R); }
141+
else if (kbhook->vkCode == VK_LMENU) { set_modifier_mask(MASK_ALT_L); }
142+
else if (kbhook->vkCode == VK_RMENU) { set_modifier_mask(MASK_ALT_R); }
143+
else if (kbhook->vkCode == VK_LWIN) { set_modifier_mask(MASK_META_L); }
144+
else if (kbhook->vkCode == VK_RWIN) { set_modifier_mask(MASK_META_R); }
145+
else if (kbhook->vkCode == VK_NUMLOCK) { set_modifier_mask(MASK_NUM_LOCK); }
146+
else if (kbhook->vkCode == VK_CAPITAL) { set_modifier_mask(MASK_CAPS_LOCK); }
147+
else if (kbhook->vkCode == VK_SCROLL) { set_modifier_mask(MASK_SCROLL_LOCK); }
148+
149+
// Populate key pressed event.
150+
uio_event.time = timestamp;
151+
uio_event.reserved = 0x00;
152+
153+
uio_event.type = EVENT_KEY_PRESSED;
154+
uio_event.mask = get_modifiers();
155+
156+
uio_event.data.keyboard.keycode = keycode_to_scancode(kbhook->vkCode, kbhook->flags);
157+
uio_event.data.keyboard.rawcode = (uint16_t) kbhook->vkCode;
158+
uio_event.data.keyboard.keychar = CHAR_UNDEFINED;
159+
160+
logger(LOG_LEVEL_DEBUG, "%s [%u]: Key %#X pressed. (%#X)\n",
161+
__FUNCTION__, __LINE__,
162+
uio_event.data.keyboard.keycode, uio_event.data.keyboard.rawcode);
163+
164+
// Populate key pressed event.
165+
dispatch_event(&uio_event);
166+
consumed = uio_event.reserved & 0x01;
167+
168+
// If the pressed event was not consumed...
169+
if (!consumed) {
170+
// Buffer for unicode typed chars. No more than 2 needed.
171+
WCHAR buffer[2]; // = { WCH_NONE };
172+
173+
// If the pressed event was not consumed and a unicode char exists...
174+
SIZE_T count = keycode_to_unicode(kbhook->vkCode, buffer, sizeof(buffer));
175+
for (unsigned int i = 0; i < count; i++) {
176+
// Populate key typed event.
177+
uio_event.time = timestamp;
178+
uio_event.reserved = 0x00;
179+
180+
uio_event.type = EVENT_KEY_TYPED;
181+
uio_event.mask = get_modifiers();
182+
183+
uio_event.data.keyboard.keycode = VC_UNDEFINED;
184+
uio_event.data.keyboard.rawcode = (uint16_t) kbhook->vkCode;
185+
uio_event.data.keyboard.keychar = buffer[i];
186+
187+
logger(LOG_LEVEL_DEBUG, "%s [%u]: Key %#X typed. (%lc)\n",
188+
__FUNCTION__, __LINE__,
189+
uio_event.data.keyboard.keycode, (wint_t) uio_event.data.keyboard.keychar);
190+
191+
// Fire key typed event.
192+
dispatch_event(&uio_event);
193+
consumed = uio_event.reserved & 0x01;
194+
}
195+
}
196+
197+
return consumed;
198+
}
199+
200+
bool dispatch_key_release(KBDLLHOOKSTRUCT *kbhook) {
201+
bool consumed = false;
202+
#ifdef USE_EPOCH_TIME
203+
uint64_t timestamp = get_unix_timestamp();
204+
#else
205+
uint64_t timestamp = kbhook->time;
206+
#endif
207+
208+
// Check and setup modifiers.
209+
if (kbhook->vkCode == VK_LSHIFT) { unset_modifier_mask(MASK_SHIFT_L); }
210+
else if (kbhook->vkCode == VK_RSHIFT) { unset_modifier_mask(MASK_SHIFT_R); }
211+
else if (kbhook->vkCode == VK_LCONTROL) { unset_modifier_mask(MASK_CTRL_L); }
212+
else if (kbhook->vkCode == VK_RCONTROL) { unset_modifier_mask(MASK_CTRL_R); }
213+
else if (kbhook->vkCode == VK_LMENU) { unset_modifier_mask(MASK_ALT_L); }
214+
else if (kbhook->vkCode == VK_RMENU) { unset_modifier_mask(MASK_ALT_R); }
215+
else if (kbhook->vkCode == VK_LWIN) { unset_modifier_mask(MASK_META_L); }
216+
else if (kbhook->vkCode == VK_RWIN) { unset_modifier_mask(MASK_META_R); }
217+
else if (kbhook->vkCode == VK_NUMLOCK) { unset_modifier_mask(MASK_NUM_LOCK); }
218+
else if (kbhook->vkCode == VK_CAPITAL) { unset_modifier_mask(MASK_CAPS_LOCK); }
219+
else if (kbhook->vkCode == VK_SCROLL) { unset_modifier_mask(MASK_SCROLL_LOCK); }
220+
221+
// Populate key pressed event.
222+
uio_event.time = timestamp;
223+
uio_event.reserved = 0x00;
224+
225+
uio_event.type = EVENT_KEY_RELEASED;
226+
uio_event.mask = get_modifiers();
227+
228+
uio_event.data.keyboard.keycode = keycode_to_scancode(kbhook->vkCode, kbhook->flags);
229+
uio_event.data.keyboard.rawcode = (uint16_t) kbhook->vkCode;
230+
uio_event.data.keyboard.keychar = CHAR_UNDEFINED;
231+
232+
logger(LOG_LEVEL_DEBUG, "%s [%u]: Key %#X released. (%#X)\n",
233+
__FUNCTION__, __LINE__,
234+
uio_event.data.keyboard.keycode, uio_event.data.keyboard.rawcode);
235+
236+
// Fire key released event.
237+
dispatch_event(&uio_event);
238+
consumed = uio_event.reserved & 0x01;
239+
240+
return consumed;
241+
}
242+
243+
bool dispatch_button_press(MSLLHOOKSTRUCT *mshook, uint16_t button) {
244+
bool consumed = false;
245+
#ifdef USE_EPOCH_TIME
246+
uint64_t timestamp = get_unix_timestamp();
247+
#else
248+
uint64_t timestamp = mshook->time;
249+
#endif
250+
251+
// Track the number of clicks, the button must match the previous button.
252+
if (button == click_button && (long int) (timestamp - click_time) <= hook_get_multi_click_time()) {
253+
if (click_count < USHRT_MAX) {
254+
click_count++;
255+
} else {
256+
logger(LOG_LEVEL_WARN, "%s [%u]: Click count overflow detected!\n",
257+
__FUNCTION__, __LINE__);
258+
}
259+
} else {
260+
// Reset the click count.
261+
click_count = 1;
262+
263+
// Set the previous button.
264+
click_button = button;
265+
}
266+
267+
// Save this events time to calculate the click_count.
268+
click_time = timestamp;
269+
270+
// Store the last click point.
271+
last_click.x = mshook->pt.x;
272+
last_click.y = mshook->pt.y;
273+
274+
// Populate mouse pressed event.
275+
uio_event.time = timestamp;
276+
uio_event.reserved = 0x00;
277+
278+
uio_event.type = EVENT_MOUSE_PRESSED;
279+
uio_event.mask = get_modifiers();
280+
281+
uio_event.data.mouse.button = button;
282+
uio_event.data.mouse.clicks = click_count;
283+
284+
uio_event.data.mouse.x = (int16_t) mshook->pt.x;
285+
uio_event.data.mouse.y = (int16_t) mshook->pt.y;
286+
287+
logger(LOG_LEVEL_DEBUG, "%s [%u]: Button %u pressed %u time(s). (%u, %u)\n",
288+
__FUNCTION__, __LINE__,
289+
uio_event.data.mouse.button, uio_event.data.mouse.clicks,
290+
uio_event.data.mouse.x, uio_event.data.mouse.y);
291+
292+
// Fire mouse pressed event.
293+
dispatch_event(&uio_event);
294+
consumed = uio_event.reserved & 0x01;
295+
296+
return consumed;
297+
}
298+
299+
bool dispatch_button_release(MSLLHOOKSTRUCT *mshook, uint16_t button) {
300+
bool consumed = false;
301+
#ifdef USE_EPOCH_TIME
302+
uint64_t timestamp = get_unix_timestamp();
303+
#else
304+
uint64_t timestamp = mshook->time;
305+
#endif
306+
307+
// Populate mouse released event.
308+
uio_event.time = timestamp;
309+
uio_event.reserved = 0x00;
310+
311+
uio_event.type = EVENT_MOUSE_RELEASED;
312+
uio_event.mask = get_modifiers();
313+
314+
uio_event.data.mouse.button = button;
315+
uio_event.data.mouse.clicks = click_count;
316+
317+
uio_event.data.mouse.x = (int16_t) mshook->pt.x;
318+
uio_event.data.mouse.y = (int16_t) mshook->pt.y;
319+
320+
logger(LOG_LEVEL_DEBUG, "%s [%u]: Button %u released %u time(s). (%u, %u)\n",
321+
__FUNCTION__, __LINE__,
322+
uio_event.data.mouse.button, uio_event.data.mouse.clicks,
323+
uio_event.data.mouse.x, uio_event.data.mouse.y);
324+
325+
// Fire mouse released event.
326+
dispatch_event(&uio_event);
327+
consumed = uio_event.reserved & 0x01;
328+
329+
// If the pressed event was not consumed...
330+
if (!consumed && last_click.x == mshook->pt.x && last_click.y == mshook->pt.y) {
331+
// Populate mouse clicked event.
332+
uio_event.time = timestamp;
333+
uio_event.reserved = 0x00;
334+
335+
uio_event.type = EVENT_MOUSE_CLICKED;
336+
uio_event.mask = get_modifiers();
337+
338+
uio_event.data.mouse.button = button;
339+
uio_event.data.mouse.clicks = click_count;
340+
uio_event.data.mouse.x = (int16_t) mshook->pt.x;
341+
uio_event.data.mouse.y = (int16_t) mshook->pt.y;
342+
343+
logger(LOG_LEVEL_DEBUG, "%s [%u]: Button %u clicked %u time(s). (%u, %u)\n",
344+
__FUNCTION__, __LINE__,
345+
uio_event.data.mouse.button, uio_event.data.mouse.clicks,
346+
uio_event.data.mouse.x, uio_event.data.mouse.y);
347+
348+
// Fire mouse clicked event.
349+
dispatch_event(&uio_event);
350+
consumed = uio_event.reserved & 0x01;
351+
}
352+
353+
// Reset the number of clicks.
354+
if (button == click_button && (long int) (timestamp - click_time) > hook_get_multi_click_time()) {
355+
// Reset the click count.
356+
click_count = 0;
357+
}
358+
359+
return consumed;
360+
}
361+
362+
363+
bool dispatch_mouse_move(MSLLHOOKSTRUCT *mshook) {
364+
bool consumed = false;
365+
#ifdef USE_EPOCH_TIME
366+
uint64_t timestamp = get_unix_timestamp();
367+
#else
368+
uint64_t timestamp = mshook->time;
369+
#endif
370+
371+
// We received a mouse move event with the mouse actually moving.
372+
// This verifies that the mouse was moved after being depressed.
373+
if (last_click.x != mshook->pt.x || last_click.y != mshook->pt.y) {
374+
// Reset the click count.
375+
if (click_count != 0 && (long) (timestamp - click_time) > hook_get_multi_click_time()) {
376+
click_count = 0;
377+
}
378+
379+
// Populate mouse move event.
380+
uio_event.time = timestamp;
381+
uio_event.reserved = 0x00;
382+
383+
uio_event.mask = get_modifiers();
384+
385+
// Check the modifier mask range for MASK_BUTTON1 - 5.
386+
bool mouse_dragged = uio_event.mask & (MASK_BUTTON1 | MASK_BUTTON2 | MASK_BUTTON3 | MASK_BUTTON4 | MASK_BUTTON5);
387+
if (mouse_dragged) {
388+
// Create Mouse Dragged event.
389+
uio_event.type = EVENT_MOUSE_DRAGGED;
390+
} else {
391+
// Create a Mouse Moved event.
392+
uio_event.type = EVENT_MOUSE_MOVED;
393+
}
394+
395+
uio_event.data.mouse.button = MOUSE_NOBUTTON;
396+
uio_event.data.mouse.clicks = click_count;
397+
uio_event.data.mouse.x = (int16_t) mshook->pt.x;
398+
uio_event.data.mouse.y = (int16_t) mshook->pt.y;
399+
400+
logger(LOG_LEVEL_DEBUG, "%s [%u]: Mouse %s to %u, %u.\n",
401+
__FUNCTION__, __LINE__,
402+
mouse_dragged ? "dragged" : "moved",
403+
uio_event.data.mouse.x, uio_event.data.mouse.y);
404+
405+
// Fire mouse move event.
406+
dispatch_event(&uio_event);
407+
consumed = uio_event.reserved & 0x01;
408+
}
409+
410+
return consumed;
411+
}
412+
413+
bool dispatch_mouse_wheel(MSLLHOOKSTRUCT *mshook, uint8_t direction) {
414+
bool consumed = false;
415+
#ifdef USE_EPOCH_TIME
416+
uint64_t timestamp = get_unix_timestamp();
417+
#else
418+
uint64_t timestamp = mshook->time;
419+
#endif
420+
421+
// Track the number of clicks.
422+
// Reset the click count and previous button.
423+
click_count = 1;
424+
click_button = MOUSE_NOBUTTON;
425+
426+
// Populate mouse wheel event.
427+
uio_event.time = timestamp;
428+
uio_event.reserved = 0x00;
429+
430+
uio_event.type = EVENT_MOUSE_WHEEL;
431+
uio_event.mask = get_modifiers();
432+
433+
uio_event.data.wheel.clicks = click_count;
434+
uio_event.data.wheel.x = (int16_t) mshook->pt.x;
435+
uio_event.data.wheel.y = (int16_t) mshook->pt.y;
436+
437+
uio_event.data.wheel.rotation = get_scroll_wheel_rotation(mshook->mouseData, direction);
438+
439+
UINT uiAction = SPI_GETWHEELSCROLLCHARS;
440+
if (direction == WHEEL_VERTICAL_DIRECTION) {
441+
uiAction = SPI_GETWHEELSCROLLLINES;
442+
}
443+
444+
UINT wheel_amount = 3;
445+
if (SystemParametersInfo(uiAction, 0, &wheel_amount, 0)) {
446+
if (wheel_amount == WHEEL_PAGESCROLL) {
447+
uio_event.data.wheel.type = WHEEL_BLOCK_SCROLL;
448+
uio_event.data.wheel.amount = 1;
449+
} else {
450+
uio_event.data.wheel.type = WHEEL_UNIT_SCROLL;
451+
uio_event.data.wheel.amount = (uint16_t) wheel_amount;
452+
}
453+
454+
// Set the direction based on what event was received.
455+
uio_event.data.wheel.direction = direction;
456+
457+
logger(LOG_LEVEL_DEBUG, "%s [%u]: Mouse wheel type %u, rotated %i units in the %u direction at %u, %u.\n",
458+
__FUNCTION__, __LINE__,
459+
uio_event.data.wheel.type,
460+
uio_event.data.wheel.amount * uio_event.data.wheel.rotation,
461+
uio_event.data.wheel.direction,
462+
uio_event.data.wheel.x, uio_event.data.wheel.y);
463+
464+
// Fire mouse wheel event.
465+
dispatch_event(&uio_event);
466+
consumed = uio_event.reserved & 0x01;
467+
} else {
468+
logger(LOG_LEVEL_WARN, "%s [%u]: SystemParametersInfo() failed, event will be consumed.\n",
469+
__FUNCTION__, __LINE__);
470+
471+
consumed = true;
472+
}
473+
474+
return consumed;
475+
}

‎src/windows/dispatch_event.h

+19
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,22 @@
1515
* You should have received a copy of the GNU Lesser General Public License
1616
* along with this program. If not, see <http://www.gnu.org/licenses/>.
1717
*/
18+
19+
#include <stdbool.h>
20+
#include <windows.h>
21+
22+
extern bool dispatch_hook_enable();
23+
24+
extern bool dispatch_hook_disable();
25+
26+
extern bool dispatch_key_press(KBDLLHOOKSTRUCT *kbhook);
27+
28+
extern bool dispatch_key_release(KBDLLHOOKSTRUCT *kbhook);
29+
30+
extern bool dispatch_button_press(MSLLHOOKSTRUCT *mshook, uint16_t button);
31+
32+
extern bool dispatch_button_release(MSLLHOOKSTRUCT *mshook, uint16_t button);
33+
34+
extern bool dispatch_mouse_move(MSLLHOOKSTRUCT *mshook);
35+
36+
extern bool dispatch_mouse_wheel(MSLLHOOKSTRUCT *mshook, uint8_t direction);

‎src/windows/input_helper.c

+18-3
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@
2727
#include "logger.h"
2828
#include "input_helper.h"
2929

30+
31+
static uint16_t modifier_mask;
32+
3033
static const uint16_t keycode_scancode_table[][2] = {
3134
/* idx { vk_code, scancode }, */
3235
/* 0 */ { VC_UNDEFINED, 0x0000 }, // 0x00
@@ -255,10 +258,10 @@ static const uint16_t keycode_scancode_table[][2] = {
255258
/* 220 */ { VC_BACK_SLASH, VK_RWIN }, // 0xDC VK_OEM_5 Varies by keyboard. For the US standard keyboard, the '\|' key
256259
/* 221 */ { VC_CLOSE_BRACKET, VK_APPS }, // 0xDD VK_OEM_6 Varies by keyboard. For the US standard keyboard, the ']}' key
257260
/* 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.
261+
/* 223 */ { VC_UNDEFINED, VK_SLEEP }, // 0xDF VK_OEM_8 Varies by keyboard.
259262
/* 224 */ { VC_UNDEFINED, 0x0000 }, // 0xE0 Reserved
260263
/* 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
264+
/* 226 */ { VC_UNDEFINED, VK_OEM_102 }, // 0xE2 VK_OEM_102 Either the angle bracket key or the backslash key on the RT 102-key keyboard
262265
/* 227 */ { VC_UNDEFINED, 0x0000 }, // 0xE3 OEM specific
263266
/* 228 */ { VC_UNDEFINED, 0x00E5 }, // 0xE4 VC_APP_PICTURES OEM specific
264267
/* 229 */ { VC_APP_PICTURES, VK_BROWSER_SEARCH }, // 0xE5 VK_PROCESSKEY IME PROCESS key
@@ -286,7 +289,7 @@ static const uint16_t keycode_scancode_table[][2] = {
286289
/* 251 */ { VC_UNDEFINED, 0x0000 }, // 0xFB VK_ZOOM Zoom key
287290
/* 252 */ { VC_UNDEFINED, 0x0000 }, // 0xFC VK_NONAME Reserved
288291
/* 253 */ { VC_UNDEFINED, 0x0000 }, // 0xFD
289-
/* 254 */ { VC_CLEAR, 0x0000 }, // 0xFE VK_OEM_CLEAR Clear key
292+
/* 254 */ { VC_KP_CLEAR, 0x0000 }, // 0xFE VK_OEM_CLEAR Clear key
290293
/* 255 */ { VC_UNDEFINED, 0x0000 } // 0xFE Unassigned
291294
};
292295

@@ -349,6 +352,18 @@ DWORD scancode_to_keycode(unsigned short scancode) {
349352
return keycode;
350353
}
351354

355+
void set_modifier_mask(uint16_t mask) {
356+
modifier_mask |= mask;
357+
}
358+
359+
void unset_modifier_mask(uint16_t mask) {
360+
modifier_mask &= ~mask;
361+
}
362+
363+
uint16_t get_modifiers() {
364+
return modifier_mask;
365+
}
366+
352367
/* Track the amount of vertical and horizontal rotation between "clicks."
353368
* This is between mouse wheel delta. */
354369
static int16_t v_rotation, h_rotation;

‎src/windows/input_helper.h

+9
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,15 @@ extern unsigned short keycode_to_scancode(DWORD vk_code, DWORD flags);
134134

135135
extern DWORD scancode_to_keycode(unsigned short scancode);
136136

137+
/* Set the native modifier mask for future events. */
138+
extern void set_modifier_mask(uint16_t mask);
139+
140+
/* Unset the native modifier mask for future events. */
141+
extern void unset_modifier_mask(uint16_t mask);
142+
143+
/* Get the current native modifier mask state. */
144+
extern uint16_t get_modifiers();
145+
137146
/* Help track how much rotation should be applied to a scroll wheel event. */
138147
extern int16_t get_scroll_wheel_rotation(DWORD data, uint8_t direction);
139148

‎src/windows/input_hook.c

+26-449
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)
Please sign in to comment.