2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Win32k subsystem
4 * PURPOSE: HotKey support
5 * FILE: subsystems/win32/win32k/ntuser/hotkey.c
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).
17 DBG_DEFAULT_CHANNEL(UserHotkey
);
19 /* GLOBALS *******************************************************************/
22 * Hardcoded hotkeys. See http://ivanlef0u.fr/repo/windoz/VI20051005.html
23 * or http://repo.meh.or.id/Windows/VI20051005.html .
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.
33 /* thread hwnd modifiers vk id next */
34 // HOT_KEY hkF12 = {NULL, NULL, 0, VK_F12, IDHK_F12, NULL};
35 // HOT_KEY hkShiftF12 = {NULL, NULL, MOD_SHIFT, VK_F12, IDHK_SHIFTF12, &hkF12};
36 // HOT_KEY hkWinKey = {NULL, NULL, MOD_WIN, 0, IDHK_WINKEY, &hkShiftF12};
37 HOT_KEY hkWinKey
= {NULL
, NULL
, MOD_WIN
, 0, IDHK_WINKEY
, NULL
};
39 PHOT_KEY gphkFirst
= &hkWinKey
;
40 BOOL bWinHotkeyActive
= FALSE
;
42 /* FUNCTIONS *****************************************************************/
47 * Returns a value that indicates if the key is a modifier key, and
52 IntGetModifiers(PBYTE pKeyState
)
56 if (IS_KEY_DOWN(pKeyState
, VK_SHIFT
))
57 fModifiers
|= MOD_SHIFT
;
59 if (IS_KEY_DOWN(pKeyState
, VK_CONTROL
))
60 fModifiers
|= MOD_CONTROL
;
62 if (IS_KEY_DOWN(pKeyState
, VK_MENU
))
63 fModifiers
|= MOD_ALT
;
65 if (IS_KEY_DOWN(pKeyState
, VK_LWIN
) || IS_KEY_DOWN(pKeyState
, VK_RWIN
))
66 fModifiers
|= MOD_WIN
;
72 * UnregisterWindowHotKeys
74 * Removes hotkeys registered by specified window on its cleanup
77 UnregisterWindowHotKeys(PWND pWnd
)
79 PHOT_KEY pHotKey
= gphkFirst
, phkNext
, *pLink
= &gphkFirst
;
80 HWND hWnd
= pWnd
->head
.h
;
84 /* Save next ptr for later use */
85 phkNext
= pHotKey
->pNext
;
87 /* Should we delete this hotkey? */
88 if (pHotKey
->hWnd
== hWnd
)
90 /* Update next ptr for previous hotkey and free memory */
92 ExFreePoolWithTag(pHotKey
, USERTAG_HOTKEY
);
94 else /* This hotkey will stay, use its next ptr */
95 pLink
= &pHotKey
->pNext
;
97 /* Move to the next entry */
103 * UnregisterThreadHotKeys
105 * Removes hotkeys registered by specified thread on its cleanup
108 UnregisterThreadHotKeys(struct _ETHREAD
*pThread
)
110 PHOT_KEY pHotKey
= gphkFirst
, phkNext
, *pLink
= &gphkFirst
;
114 /* Save next ptr for later use */
115 phkNext
= pHotKey
->pNext
;
117 /* Should we delete this hotkey? */
118 if (pHotKey
->pThread
== pThread
)
120 /* Update next ptr for previous hotkey and free memory */
122 ExFreePoolWithTag(pHotKey
, USERTAG_HOTKEY
);
124 else /* This hotkey will stay, use its next ptr */
125 pLink
= &pHotKey
->pNext
;
127 /* Move to the next entry */
135 * Checks if given key and modificators have corresponding hotkey
137 static PHOT_KEY FASTCALL
138 IsHotKey(UINT fsModifiers
, WORD wVk
)
140 PHOT_KEY pHotKey
= gphkFirst
;
144 if (pHotKey
->fsModifiers
== fsModifiers
&&
147 /* We have found it */
151 /* Move to the next entry */
152 pHotKey
= pHotKey
->pNext
;
159 * co_UserProcessHotKeys
161 * Sends WM_HOTKEY message if given keys are hotkey
164 co_UserProcessHotKeys(WORD wVk
, BOOL bIsDown
)
169 if (wVk
== VK_SHIFT
|| wVk
== VK_CONTROL
|| wVk
== VK_MENU
||
170 wVk
== VK_LWIN
|| wVk
== VK_RWIN
)
172 /* Those keys are specified by modifiers */
176 /* Check if it is a hotkey */
177 fModifiers
= IntGetModifiers(gafAsyncKeyState
);
178 pHotKey
= IsHotKey(fModifiers
, wVk
);
181 /* Process hotkey if it is key up event */
184 TRACE("Hot key pressed (hWnd %p, id %d)\n", pHotKey
->hWnd
, pHotKey
->id
);
186 /* WIN and F12 keys are hardcoded here. See comments on top of this file. */
187 if (pHotKey
== &hkWinKey
)
189 if(bWinHotkeyActive
== TRUE
)
191 UserPostMessage(InputWindowStation
->ShellWindow
, WM_SYSCOMMAND
, SC_TASKLIST
, 0);
192 bWinHotkeyActive
= FALSE
;
195 #if 0 /* FIXME: See comment about "UserDebuggerHotKey" on top of this file. */
196 else if (pHotKey
== &hkF12
|| pHotKey
== &hkShiftF12
)
198 //co_ActivateDebugger(); // FIXME
201 else if (pHotKey
->id
== IDHK_REACTOS
&& !pHotKey
->pThread
) // FIXME: Those hotkeys doesn't depend on RegisterHotKey
203 UserPostMessage(pHotKey
->hWnd
, WM_SYSCOMMAND
, SC_HOTKEY
, (LPARAM
)pHotKey
->hWnd
);
207 /* If a hotkey with the WIN modifier was activated, do not treat the release of the WIN key as a hotkey*/
208 if((pHotKey
->fsModifiers
& MOD_WIN
) != 0)
209 bWinHotkeyActive
= FALSE
;
211 MsqPostHotKeyMessage(pHotKey
->pThread
,
214 MAKELPARAM((WORD
)fModifiers
, wVk
));
219 if (pHotKey
== &hkWinKey
)
221 /* The user pressed the win key */
222 bWinHotkeyActive
= TRUE
;
226 return TRUE
; /* Don't send any message */
236 * GetHotKey message support
239 DefWndGetHotKey(HWND hWnd
)
241 PHOT_KEY pHotKey
= gphkFirst
;
243 WARN("DefWndGetHotKey\n");
247 if (pHotKey
->hWnd
== hWnd
&& pHotKey
->id
== IDHK_REACTOS
)
249 /* We have found it */
250 return MAKELONG(pHotKey
->vk
, pHotKey
->fsModifiers
);
253 /* Move to the next entry */
254 pHotKey
= pHotKey
->pNext
;
263 * SetHotKey message support
266 DefWndSetHotKey(PWND pWnd
, WPARAM wParam
)
268 UINT fsModifiers
, vk
;
269 PHOT_KEY pHotKey
, *pLink
;
273 WARN("DefWndSetHotKey wParam 0x%x\n", wParam
);
275 // A hot key cannot be associated with a child window.
276 if (pWnd
->style
& WS_CHILD
)
279 // VK_ESCAPE, VK_SPACE, and VK_TAB are invalid hot keys.
280 if (LOWORD(wParam
) == VK_ESCAPE
||
281 LOWORD(wParam
) == VK_SPACE
||
282 LOWORD(wParam
) == VK_TAB
)
288 fsModifiers
= HIWORD(wParam
);
289 hWnd
= UserHMGetHandle(pWnd
);
296 if (pHotKey
->fsModifiers
== fsModifiers
&&
298 pHotKey
->id
== IDHK_REACTOS
)
300 if (pHotKey
->hWnd
!= hWnd
)
301 iRet
= 2; // Another window already has the same hot key.
305 /* Move to the next entry */
306 pHotKey
= pHotKey
->pNext
;
314 if (pHotKey
->hWnd
== hWnd
&&
315 pHotKey
->id
== IDHK_REACTOS
)
317 /* This window has already hotkey registered */
321 /* Move to the next entry */
322 pLink
= &pHotKey
->pNext
;
323 pHotKey
= pHotKey
->pNext
;
330 /* Create new hotkey */
331 pHotKey
= ExAllocatePoolWithTag(PagedPool
, sizeof(HOT_KEY
), USERTAG_HOTKEY
);
335 pHotKey
->hWnd
= hWnd
;
336 pHotKey
->id
= IDHK_REACTOS
; // Don't care, these hot keys are unrelated to the hot keys set by RegisterHotKey
337 pHotKey
->pNext
= gphkFirst
;
341 /* A window can only have one hot key. If the window already has a
342 hot key associated with it, the new hot key replaces the old one. */
343 pHotKey
->pThread
= NULL
;
344 pHotKey
->fsModifiers
= fsModifiers
;
350 *pLink
= pHotKey
->pNext
;
351 ExFreePoolWithTag(pHotKey
, USERTAG_HOTKEY
);
357 /* SYSCALLS *****************************************************************/
361 NtUserRegisterHotKey(HWND hWnd
,
368 PETHREAD pHotKeyThread
;
371 TRACE("Enter NtUserRegisterHotKey\n");
373 if (fsModifiers
& ~(MOD_ALT
|MOD_CONTROL
|MOD_SHIFT
|MOD_WIN
)) // FIXME: Does Win2k3 support MOD_NOREPEAT?
375 WARN("Invalid modifiers: %x\n", fsModifiers
);
376 EngSetLastError(ERROR_INVALID_FLAGS
);
380 UserEnterExclusive();
382 /* Find hotkey thread */
385 pHotKeyThread
= PsGetCurrentThread();
389 pWnd
= UserGetWindowObject(hWnd
);
393 pHotKeyThread
= pWnd
->head
.pti
->pEThread
;
396 /* Check for existing hotkey */
397 if (IsHotKey(fsModifiers
, vk
))
399 EngSetLastError(ERROR_HOTKEY_ALREADY_REGISTERED
);
400 WARN("Hotkey already exists\n");
404 /* Create new hotkey */
405 pHotKey
= ExAllocatePoolWithTag(PagedPool
, sizeof(HOT_KEY
), USERTAG_HOTKEY
);
408 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
412 pHotKey
->pThread
= pHotKeyThread
;
413 pHotKey
->hWnd
= hWnd
;
414 pHotKey
->fsModifiers
= fsModifiers
;
418 /* Insert hotkey to the global list */
419 pHotKey
->pNext
= gphkFirst
;
425 TRACE("Leave NtUserRegisterHotKey, ret=%i\n", bRet
);
432 NtUserUnregisterHotKey(HWND hWnd
, int id
)
434 PHOT_KEY pHotKey
= gphkFirst
, phkNext
, *pLink
= &gphkFirst
;
437 TRACE("Enter NtUserUnregisterHotKey\n");
438 UserEnterExclusive();
440 /* Fail if given window is invalid */
441 if (hWnd
&& !UserGetWindowObject(hWnd
))
446 /* Save next ptr for later use */
447 phkNext
= pHotKey
->pNext
;
449 /* Should we delete this hotkey? */
450 if (pHotKey
->hWnd
== hWnd
&& pHotKey
->id
== id
)
452 /* Update next ptr for previous hotkey and free memory */
454 ExFreePoolWithTag(pHotKey
, USERTAG_HOTKEY
);
458 else /* This hotkey will stay, use its next ptr */
459 pLink
= &pHotKey
->pNext
;
461 /* Move to the next entry */
466 TRACE("Leave NtUserUnregisterHotKey, ret=%i\n", bRet
);