ReactOS 0.4.15-dev-5669-g09dde2c
hotkey.c
Go to the documentation of this file.
1/*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Win32k subsystem
4 * PURPOSE: HotKey support
5 * FILE: win32ss/user/ntuser/hotkey.c
6 * PROGRAMER: Eric Kohl
7 */
8
9/*
10 * FIXME: Hotkey notifications are triggered by keyboard input (physical or programatically)
11 * and since only desktops on WinSta0 can receive input in seems very wrong to allow
12 * windows/threads on destops not belonging to WinSta0 to set hotkeys (receive notifications).
13 * -- Gunnar
14 */
15
16#include <win32k.h>
18
19/* GLOBALS *******************************************************************/
20
21/*
22 * Hardcoded hotkeys. See http://ivanlef0u.fr/repo/windoz/VI20051005.html
23 * or http://repo.meh.or.id/Windows/VI20051005.html .
24 *
25 * NOTE: The (Shift-)F12 keys are used only for the "UserDebuggerHotKey" setting
26 * which enables setting a key shortcut which, when pressed, establishes a
27 * breakpoint in the code being debugged:
28 * see http://technet.microsoft.com/en-us/library/cc786263(v=ws.10).aspx
29 * and http://flylib.com/books/en/4.441.1.33/1/ for more details.
30 * By default the key is VK-F12 on a 101-key keyboard, and is VK_SUBTRACT
31 * (hyphen / substract sign) on a 82-key keyboard.
32 */
33/* pti pwnd modifiers vk id next */
34// HOT_KEY hkF12 = {NULL, 1, 0, VK_F12, IDHK_F12, NULL};
35// HOT_KEY hkShiftF12 = {NULL, 1, MOD_SHIFT, VK_F12, IDHK_SHIFTF12, &hkF12};
36// HOT_KEY hkWinKey = {NULL, 1, MOD_WIN, 0, IDHK_WINKEY, &hkShiftF12};
37
40
41/* FUNCTIONS *****************************************************************/
42
45{
46 UINT vk = VK_F12;
50 {
52 }
55 TRACE("Start up the debugger hotkeys!! If you see this you eneabled debugprints. Congrats!\n");
56}
57
58/*
59 * IntGetModifiers
60 *
61 * Returns a value that indicates if the key is a modifier key, and
62 * which one.
63 */
64static
67{
68 UINT fModifiers = 0;
69
70 if (IS_KEY_DOWN(pKeyState, VK_SHIFT))
71 fModifiers |= MOD_SHIFT;
72
73 if (IS_KEY_DOWN(pKeyState, VK_CONTROL))
74 fModifiers |= MOD_CONTROL;
75
76 if (IS_KEY_DOWN(pKeyState, VK_MENU))
77 fModifiers |= MOD_ALT;
78
79 if (IS_KEY_DOWN(pKeyState, VK_LWIN) || IS_KEY_DOWN(pKeyState, VK_RWIN))
80 fModifiers |= MOD_WIN;
81
82 return fModifiers;
83}
84
85/*
86 * UnregisterWindowHotKeys
87 *
88 * Removes hotkeys registered by specified window on its cleanup
89 */
92{
93 PHOT_KEY pHotKey = gphkFirst, phkNext, *pLink = &gphkFirst;
94
95 while (pHotKey)
96 {
97 /* Save next ptr for later use */
98 phkNext = pHotKey->pNext;
99
100 /* Should we delete this hotkey? */
101 if (pHotKey->pWnd == pWnd)
102 {
103 /* Update next ptr for previous hotkey and free memory */
104 *pLink = phkNext;
106 }
107 else /* This hotkey will stay, use its next ptr */
108 pLink = &pHotKey->pNext;
109
110 /* Move to the next entry */
111 pHotKey = phkNext;
112 }
113}
114
115/*
116 * UnregisterThreadHotKeys
117 *
118 * Removes hotkeys registered by specified thread on its cleanup
119 */
122{
123 PHOT_KEY pHotKey = gphkFirst, phkNext, *pLink = &gphkFirst;
124
125 while (pHotKey)
126 {
127 /* Save next ptr for later use */
128 phkNext = pHotKey->pNext;
129
130 /* Should we delete this hotkey? */
131 if (pHotKey->pti == pti)
132 {
133 /* Update next ptr for previous hotkey and free memory */
134 *pLink = phkNext;
136 }
137 else /* This hotkey will stay, use its next ptr */
138 pLink = &pHotKey->pNext;
139
140 /* Move to the next entry */
141 pHotKey = phkNext;
142 }
143}
144
145/*
146 * IsHotKey
147 *
148 * Checks if given key and modificators have corresponding hotkey
149 */
150static PHOT_KEY FASTCALL
151IsHotKey(UINT fsModifiers, WORD wVk)
152{
153 PHOT_KEY pHotKey = gphkFirst;
154
155 while (pHotKey)
156 {
157 if (pHotKey->fsModifiers == fsModifiers &&
158 pHotKey->vk == wVk)
159 {
160 /* We have found it */
161 return pHotKey;
162 }
163
164 /* Move to the next entry */
165 pHotKey = pHotKey->pNext;
166 }
167
168 return NULL;
169}
170
171/*
172 * co_UserProcessHotKeys
173 *
174 * Sends WM_HOTKEY message if given keys are hotkey
175 */
178{
179 UINT fModifiers;
180 PHOT_KEY pHotKey;
181 PWND pWnd;
182 BOOL DoNotPostMsg = FALSE;
183 BOOL IsModifier = FALSE;
184
185 if (wVk == VK_SHIFT || wVk == VK_CONTROL || wVk == VK_MENU ||
186 wVk == VK_LWIN || wVk == VK_RWIN)
187 {
188 /* Remember that this was a modifier */
189 IsModifier = TRUE;
190 }
191
192 fModifiers = IntGetModifiers(gafAsyncKeyState);
193
194 if (bIsDown)
195 {
196 if (IsModifier)
197 {
198 /* Modifier key down -- no hotkey trigger, but remember this */
199 gfsModOnlyCandidate = fModifiers;
200 return FALSE;
201 }
202 else
203 {
204 /* Regular key down -- check for hotkey, and reset mod candidates */
205 pHotKey = IsHotKey(fModifiers, wVk);
207 }
208 }
209 else
210 {
211 if (IsModifier)
212 {
213 /* Modifier key up -- modifier-only keys are triggered here */
214 pHotKey = IsHotKey(gfsModOnlyCandidate, 0);
216 }
217 else
218 {
219 /* Regular key up -- no hotkey, but reset mod-only candidates */
221 return FALSE;
222 }
223 }
224
225 if (pHotKey)
226 {
227 TRACE("Hot key pressed (pWnd %p, id %d)\n", pHotKey->pWnd, pHotKey->id);
228
229 /* FIXME: See comment about "UserDebuggerHotKey" on top of this file. */
230 if (pHotKey->id == IDHK_SHIFTF12 || pHotKey->id == IDHK_F12)
231 {
232 if (bIsDown)
233 {
234 ERR("Hot key pressed for Debug Activation! ShiftF12 = %d or F12 = %d\n",pHotKey->id == IDHK_SHIFTF12 , pHotKey->id == IDHK_F12);
235 //DoNotPostMsg = co_ActivateDebugger(); // FIXME
236 }
237 return DoNotPostMsg;
238 }
239
240 /* WIN and F12 keys are not hardcoded here. See comments on top of this file. */
241 if (pHotKey->id == IDHK_WINKEY)
242 {
243 ASSERT(!bIsDown);
245 if (pWnd)
246 {
247 TRACE("System Hot key Id %d Key %u\n", pHotKey->id, wVk );
249 co_IntShellHookNotify(HSHELL_TASKMAN, 0, 0);
250 return FALSE;
251 }
252 }
253
254 if (pHotKey->id == IDHK_SNAP_LEFT ||
255 pHotKey->id == IDHK_SNAP_RIGHT ||
256 pHotKey->id == IDHK_SNAP_UP ||
257 pHotKey->id == IDHK_SNAP_DOWN)
258 {
259 HWND topWnd = UserGetForegroundWindow();
260 if (topWnd)
261 {
262 UserPostMessage(topWnd, WM_KEYDOWN, wVk, 0);
263 }
264 return TRUE;
265 }
266
267 if (!pHotKey->pWnd)
268 {
269 TRACE("UPTM Hot key Id %d Key %u\n", pHotKey->id, wVk );
270 UserPostThreadMessage(pHotKey->pti, WM_HOTKEY, pHotKey->id, MAKELONG(fModifiers, wVk));
271 //ptiLastInput = pHotKey->pti;
272 return TRUE; /* Don't send any message */
273 }
274 else
275 {
276 pWnd = pHotKey->pWnd;
277 if (pWnd == PWND_BOTTOM)
278 {
279 if (gpqForeground == NULL)
280 return FALSE;
281
283 }
284
285 if (pWnd)
286 {
287 // pWnd->head.rpdesk->pDeskInfo->spwndShell needs testing.
289 {
291 co_IntShellHookNotify(HSHELL_TASKMAN, 0, 0);
292 }
293 else
294 {
295 TRACE("UPM Hot key Id %d Key %u\n", pHotKey->id, wVk );
296 UserPostMessage(UserHMGetHandle(pWnd), WM_HOTKEY, pHotKey->id, MAKELONG(fModifiers, wVk));
297 }
298 //ptiLastInput = pWnd->head.pti;
299 return TRUE; /* Don't send any message */
300 }
301 }
302 }
303 return FALSE;
304}
305
306
307/*
308 * DefWndGetHotKey --- GetHotKey message support
309 *
310 * Win: DWP_GetHotKey
311 */
314{
315 PHOT_KEY pHotKey = gphkFirst;
316
317 WARN("DefWndGetHotKey\n");
318
319 while (pHotKey)
320 {
321 if (pHotKey->pWnd == pWnd && pHotKey->id == IDHK_REACTOS)
322 {
323 /* We have found it */
324 return MAKELONG(pHotKey->vk, pHotKey->fsModifiers);
325 }
326
327 /* Move to the next entry */
328 pHotKey = pHotKey->pNext;
329 }
330
331 return 0;
332}
333
334/*
335 * DefWndSetHotKey --- SetHotKey message support
336 *
337 * Win: DWP_SetHotKey
338 */
341{
342 UINT fsModifiers, vk;
343 PHOT_KEY pHotKey, *pLink;
344 INT iRet = 1;
345
346 WARN("DefWndSetHotKey wParam 0x%x\n", wParam);
347
348 // A hot key cannot be associated with a child window.
349 if (pWnd->style & WS_CHILD)
350 return 0;
351
352 // VK_ESCAPE, VK_SPACE, and VK_TAB are invalid hot keys.
353 if (LOWORD(wParam) == VK_ESCAPE ||
354 LOWORD(wParam) == VK_SPACE ||
355 LOWORD(wParam) == VK_TAB)
356 {
357 return -1;
358 }
359
360 vk = LOWORD(wParam);
361 fsModifiers = HIWORD(wParam);
362
363 if (wParam)
364 {
365 pHotKey = gphkFirst;
366 while (pHotKey)
367 {
368 if (pHotKey->fsModifiers == fsModifiers &&
369 pHotKey->vk == vk &&
370 pHotKey->id == IDHK_REACTOS)
371 {
372 if (pHotKey->pWnd != pWnd)
373 iRet = 2; // Another window already has the same hot key.
374 break;
375 }
376
377 /* Move to the next entry */
378 pHotKey = pHotKey->pNext;
379 }
380 }
381
382 pHotKey = gphkFirst;
383 pLink = &gphkFirst;
384 while (pHotKey)
385 {
386 if (pHotKey->pWnd == pWnd &&
387 pHotKey->id == IDHK_REACTOS)
388 {
389 /* This window has already hotkey registered */
390 break;
391 }
392
393 /* Move to the next entry */
394 pLink = &pHotKey->pNext;
395 pHotKey = pHotKey->pNext;
396 }
397
398 if (wParam)
399 {
400 if (!pHotKey)
401 {
402 /* Create new hotkey */
404 if (pHotKey == NULL)
405 return 0;
406
407 pHotKey->pWnd = pWnd;
408 pHotKey->id = IDHK_REACTOS; // Don't care, these hot keys are unrelated to the hot keys set by RegisterHotKey
409 pHotKey->pNext = gphkFirst;
410 gphkFirst = pHotKey;
411 }
412
413 /* A window can only have one hot key. If the window already has a
414 hot key associated with it, the new hot key replaces the old one. */
415 pHotKey->pti = NULL;
416 pHotKey->fsModifiers = fsModifiers;
417 pHotKey->vk = vk;
418 }
419 else if (pHotKey)
420 {
421 /* Remove hotkey */
422 *pLink = pHotKey->pNext;
424 }
425
426 return iRet;
427}
428
429
432 int id,
433 UINT fsModifiers,
434 UINT vk)
435{
436 PHOT_KEY pHotKey;
437 PTHREADINFO pHotKeyThread;
438
439 /* Find hotkey thread */
440 if (pWnd == NULL || pWnd == PWND_BOTTOM)
441 {
442 pHotKeyThread = PsGetCurrentThreadWin32Thread();
443 }
444 else
445 {
446 pHotKeyThread = pWnd->head.pti;
447 }
448
449 /* Check for existing hotkey */
450 if (IsHotKey(fsModifiers, vk))
451 {
453 WARN("Hotkey already exists\n");
454 return FALSE;
455 }
456
457 /* Create new hotkey */
459 if (pHotKey == NULL)
460 {
462 return FALSE;
463 }
464
465 pHotKey->pti = pHotKeyThread;
466 pHotKey->pWnd = pWnd;
467 pHotKey->fsModifiers = fsModifiers;
468 pHotKey->vk = vk;
469 pHotKey->id = id;
470
471 /* Insert hotkey to the global list */
472 pHotKey->pNext = gphkFirst;
473 gphkFirst = pHotKey;
474
475 return TRUE;
476}
477
480{
481 PHOT_KEY pHotKey = gphkFirst, phkNext, *pLink = &gphkFirst;
482 BOOL bRet = FALSE;
483
484 while (pHotKey)
485 {
486 /* Save next ptr for later use */
487 phkNext = pHotKey->pNext;
488
489 /* Should we delete this hotkey? */
490 if (pHotKey->pWnd == pWnd && pHotKey->id == id)
491 {
492 /* Update next ptr for previous hotkey and free memory */
493 *pLink = phkNext;
495
496 bRet = TRUE;
497 }
498 else /* This hotkey will stay, use its next ptr */
499 pLink = &pHotKey->pNext;
500
501 /* Move to the next entry */
502 pHotKey = phkNext;
503 }
504 return bRet;
505}
506
507
508/* SYSCALLS *****************************************************************/
509
510
513 int id,
514 UINT fsModifiers,
515 UINT vk)
516{
517 PHOT_KEY pHotKey;
518 PWND pWnd = NULL;
519 PTHREADINFO pHotKeyThread;
520 BOOL bRet = FALSE;
521
522 TRACE("Enter NtUserRegisterHotKey\n");
523
524 if (fsModifiers & ~(MOD_ALT|MOD_CONTROL|MOD_SHIFT|MOD_WIN)) // FIXME: Does Win2k3 support MOD_NOREPEAT?
525 {
526 WARN("Invalid modifiers: %x\n", fsModifiers);
528 return 0;
529 }
530
532
533 /* Find hotkey thread */
534 if (hWnd == NULL)
535 {
536 pHotKeyThread = gptiCurrent;
537 }
538 else
539 {
541 if (!pWnd)
542 goto cleanup;
543
544 pHotKeyThread = pWnd->head.pti;
545
546 /* Fix wine msg "Window on another thread" test_hotkey */
547 if (pWnd->head.pti != gptiCurrent)
548 {
550 WARN("Must be from the same Thread.\n");
551 goto cleanup;
552 }
553 }
554
555 /* Check for existing hotkey */
556 if (IsHotKey(fsModifiers, vk))
557 {
559 WARN("Hotkey already exists\n");
560 goto cleanup;
561 }
562
563 /* Create new hotkey */
565 if (pHotKey == NULL)
566 {
568 goto cleanup;
569 }
570
571 pHotKey->pti = pHotKeyThread;
572 pHotKey->pWnd = pWnd;
573 pHotKey->fsModifiers = fsModifiers;
574 pHotKey->vk = vk;
575 pHotKey->id = id;
576
577 /* Insert hotkey to the global list */
578 pHotKey->pNext = gphkFirst;
579 gphkFirst = pHotKey;
580
581 bRet = TRUE;
582
583cleanup:
584 TRACE("Leave NtUserRegisterHotKey, ret=%i\n", bRet);
585 UserLeave();
586 return bRet;
587}
588
589
592{
593 PHOT_KEY pHotKey = gphkFirst, phkNext, *pLink = &gphkFirst;
594 BOOL bRet = FALSE;
595 PWND pWnd = NULL;
596
597 TRACE("Enter NtUserUnregisterHotKey\n");
599
600 /* Fail if given window is invalid */
601 if (hWnd && !(pWnd = UserGetWindowObject(hWnd)))
602 goto cleanup;
603
604 while (pHotKey)
605 {
606 /* Save next ptr for later use */
607 phkNext = pHotKey->pNext;
608
609 /* Should we delete this hotkey? */
610 if (pHotKey->pWnd == pWnd && pHotKey->id == id)
611 {
612 /* Update next ptr for previous hotkey and free memory */
613 *pLink = phkNext;
615
616 bRet = TRUE;
617 }
618 else /* This hotkey will stay, use its next ptr */
619 pLink = &pHotKey->pNext;
620
621 /* Move to the next entry */
622 pHotKey = phkNext;
623 }
624
625cleanup:
626 TRACE("Leave NtUserUnregisterHotKey, ret=%i\n", bRet);
627 UserLeave();
628 return bRet;
629}
630
631/* EOF */
HWND hWnd
Definition: settings.c:17
#define WARN(fmt,...)
Definition: debug.h:112
#define ERR(fmt,...)
Definition: debug.h:110
#define DBG_DEFAULT_CHANNEL(ch)
Definition: debug.h:103
WPARAM wParam
Definition: combotst.c:138
#define ERROR_NOT_ENOUGH_MEMORY
Definition: dderror.h:7
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define APIENTRY
Definition: api.h:79
#define ValidateHwndNoErr(hwnd)
Definition: precomp.h:84
static void cleanup(void)
Definition: main.c:1335
#define ExAllocatePoolWithTag(hernya, size, tag)
Definition: env_spec_w32.h:350
#define PagedPool
Definition: env_spec_w32.h:308
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned short WORD
Definition: ntddk_ex.h:93
PUSER_MESSAGE_QUEUE gpqForeground
Definition: focus.c:13
HWND FASTCALL UserGetForegroundWindow(VOID)
Definition: focus.c:1421
GLuint id
Definition: glext.h:5910
#define IDHK_SNAP_LEFT
Definition: hotkey.h:20
#define IDHK_REACTOS
Definition: hotkey.h:17
#define IDHK_WINKEY
Definition: hotkey.h:16
#define IDHK_SNAP_UP
Definition: hotkey.h:22
#define IDHK_F12
Definition: hotkey.h:14
#define IDHK_SNAP_DOWN
Definition: hotkey.h:23
#define IDHK_SNAP_RIGHT
Definition: hotkey.h:21
#define IDHK_SHIFTF12
Definition: hotkey.h:15
#define MOD_ALT
Definition: imm.h:319
#define MOD_SHIFT
Definition: imm.h:321
#define MOD_CONTROL
Definition: imm.h:320
#define UserHMGetHandle(obj)
Definition: ntuser.h:230
#define PWND_BOTTOM
Definition: ntuser.h:764
#define ASSERT(a)
Definition: mode.c:44
#define ExFreePoolWithTag(_P, _T)
Definition: module.h:1099
WORD vk
Definition: input.c:77
unsigned int UINT
Definition: ndis.h:50
#define FASTCALL
Definition: nt_native.h:50
#define ENHANCED_KEYBOARD(Id)
Definition: ntddkbd.h:105
PVOID NTAPI PsGetCurrentThreadWin32Thread(VOID)
Definition: thread.c:805
PWINSTATION_OBJECT InputWindowStation
Definition: winsta.c:21
VOID FASTCALL UserLeave(VOID)
Definition: ntuser.c:254
PTHREADINFO gptiCurrent
Definition: ntuser.c:15
VOID FASTCALL UserEnterExclusive(VOID)
Definition: ntuser.c:245
#define LOWORD(l)
Definition: pedump.c:82
#define WS_CHILD
Definition: pedump.c:617
BYTE * PBYTE
Definition: pedump.c:66
#define TRACE(s)
Definition: solgame.cpp:4
Definition: hotkey.h:4
UINT fsModifiers
Definition: hotkey.h:7
PTHREADINFO pti
Definition: hotkey.h:5
struct _HOT_KEY * pNext
Definition: hotkey.h:10
INT id
Definition: hotkey.h:9
UINT vk
Definition: hotkey.h:8
PWND pWnd
Definition: hotkey.h:6
KEYBOARD_ID KeyboardIdentifier
Definition: ntddkbd.h:124
HANDLE ShellWindow
Definition: winsta.h:43
Definition: ntuser.h:689
THRDESKHEAD head
Definition: ntuser.h:690
DWORD style
Definition: ntuser.h:701
#define NTAPI
Definition: typedefs.h:36
int32_t INT
Definition: typedefs.h:58
#define MAKELONG(a, b)
Definition: typedefs.h:249
#define HIWORD(l)
Definition: typedefs.h:247
PWND FASTCALL UserGetWindowObject(HWND hWnd)
Definition: window.c:134
VOID co_IntShellHookNotify(WPARAM Message, WPARAM wParam, LPARAM lParam)
Definition: desktop.c:1692
BOOL APIENTRY NtUserUnregisterHotKey(HWND hWnd, int id)
Definition: hotkey.c:591
BOOL FASTCALL UserRegisterHotKey(PWND pWnd, int id, UINT fsModifiers, UINT vk)
Definition: hotkey.c:431
static PHOT_KEY FASTCALL IsHotKey(UINT fsModifiers, WORD wVk)
Definition: hotkey.c:151
BOOL NTAPI co_UserProcessHotKeys(WORD wVk, BOOL bIsDown)
Definition: hotkey.c:177
BOOL APIENTRY NtUserRegisterHotKey(HWND hWnd, int id, UINT fsModifiers, UINT vk)
Definition: hotkey.c:512
VOID FASTCALL StartDebugHotKeys(VOID)
Definition: hotkey.c:44
UINT FASTCALL DefWndGetHotKey(PWND pWnd)
Definition: hotkey.c:313
PHOT_KEY gphkFirst
Definition: hotkey.c:38
VOID FASTCALL UnregisterThreadHotKeys(PTHREADINFO pti)
Definition: hotkey.c:121
UINT gfsModOnlyCandidate
Definition: hotkey.c:39
static UINT FASTCALL IntGetModifiers(PBYTE pKeyState)
Definition: hotkey.c:66
VOID FASTCALL UnregisterWindowHotKeys(PWND pWnd)
Definition: hotkey.c:91
INT FASTCALL DefWndSetHotKey(PWND pWnd, WPARAM wParam)
Definition: hotkey.c:340
BOOL FASTCALL UserUnregisterHotKey(PWND pWnd, int id)
Definition: hotkey.c:479
KEYBOARD_ATTRIBUTES gKeyboardInfo
Definition: keyboard.c:17
BYTE gafAsyncKeyState[256 *2/8]
Definition: keyboard.c:13
#define IS_KEY_DOWN(ks, vk)
Definition: input.h:99
BOOL FASTCALL UserPostMessage(HWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam)
Definition: message.c:1346
BOOL FASTCALL UserPostThreadMessage(PTHREADINFO pti, UINT Msg, WPARAM wParam, LPARAM lParam)
Definition: message.c:1309
#define USERTAG_HOTKEY
Definition: tags.h:238
ENGAPI VOID APIENTRY EngSetLastError(_In_ ULONG iError)
Definition: error.c:28
UINT_PTR WPARAM
Definition: windef.h:207
#define ERROR_WINDOW_OF_OTHER_THREAD
Definition: winerror.h:889
#define ERROR_HOTKEY_ALREADY_REGISTERED
Definition: winerror.h:890
#define ERROR_INVALID_FLAGS
Definition: winerror.h:583
#define WM_SYSCOMMAND
Definition: winuser.h:1731
#define VK_F12
Definition: winuser.h:2256
#define VK_TAB
Definition: winuser.h:2189
#define MOD_WIN
Definition: winuser.h:2634
#define VK_SPACE
Definition: winuser.h:2209
#define VK_CONTROL
Definition: winuser.h:2193
#define SC_TASKLIST
Definition: winuser.h:2589
#define VK_LWIN
Definition: winuser.h:2225
#define WM_HOTKEY
Definition: winuser.h:1869
#define VK_SHIFT
Definition: winuser.h:2192
#define WM_KEYDOWN
Definition: winuser.h:1705
#define VK_ESCAPE
Definition: winuser.h:2204
#define VK_RWIN
Definition: winuser.h:2226
#define VK_SUBTRACT
Definition: winuser.h:2242
#define VK_MENU
Definition: winuser.h:2194