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 recieve input in seems very wrong to allow
12 * windows/threads on destops not belonging to WinSta0 to set hotkeys (recieve notifications).
17 DBG_DEFAULT_CHANNEL(UserHotkey
);
19 /* GLOBALS *******************************************************************/
21 /* Hardcoded hotkeys. See http://ivanlef0u.fr/repo/windoz/VI20051005.html */
22 /* thread hwnd modifiers vk id next */
23 HOT_KEY hkF12
= {NULL
, NULL
, 0, VK_F12
, IDHK_F12
, NULL
};
24 HOT_KEY hkShiftF12
= {NULL
, NULL
, MOD_SHIFT
, VK_F12
, IDHK_SHIFTF12
, &hkF12
};
25 HOT_KEY hkWinKey
= {NULL
, NULL
, MOD_WIN
, 0, IDHK_WINKEY
, &hkShiftF12
};
27 PHOT_KEY gphkFirst
= &hkWinKey
;
29 /* FUNCTIONS *****************************************************************/
34 * Returns a value that indicates if the key is a modifier key, and
39 IntGetModifiers(PBYTE pKeyState
)
43 if (IS_KEY_DOWN(pKeyState
, VK_SHIFT
))
44 fModifiers
|= MOD_SHIFT
;
46 if (IS_KEY_DOWN(pKeyState
, VK_CONTROL
))
47 fModifiers
|= MOD_CONTROL
;
49 if (IS_KEY_DOWN(pKeyState
, VK_MENU
))
50 fModifiers
|= MOD_ALT
;
52 if (IS_KEY_DOWN(pKeyState
, VK_LWIN
) || IS_KEY_DOWN(pKeyState
, VK_RWIN
))
53 fModifiers
|= MOD_WIN
;
59 * UnregisterWindowHotKeys
61 * Removes hotkeys registered by specified window on its cleanup
64 UnregisterWindowHotKeys(PWND pWnd
)
66 PHOT_KEY pHotKey
= gphkFirst
, phkNext
, *pLink
= &gphkFirst
;
67 HWND hWnd
= pWnd
->head
.h
;
71 /* Save next ptr for later use */
72 phkNext
= pHotKey
->pNext
;
74 /* Should we delete this hotkey? */
75 if (pHotKey
->hWnd
== hWnd
)
77 /* Update next ptr for previous hotkey and free memory */
79 ExFreePoolWithTag(pHotKey
, USERTAG_HOTKEY
);
81 else /* This hotkey will stay, use its next ptr */
82 pLink
= &pHotKey
->pNext
;
84 /* Move to the next entry */
90 * UnregisterThreadHotKeys
92 * Removes hotkeys registered by specified thread on its cleanup
95 UnregisterThreadHotKeys(struct _ETHREAD
*pThread
)
97 PHOT_KEY pHotKey
= gphkFirst
, phkNext
, *pLink
= &gphkFirst
;
101 /* Save next ptr for later use */
102 phkNext
= pHotKey
->pNext
;
104 /* Should we delete this hotkey? */
105 if (pHotKey
->pThread
== pThread
)
107 /* Update next ptr for previous hotkey and free memory */
109 ExFreePoolWithTag(pHotKey
, USERTAG_HOTKEY
);
111 else /* This hotkey will stay, use its next ptr */
112 pLink
= &pHotKey
->pNext
;
114 /* Move to the next entry */
122 * Checks if given key and modificators have corresponding hotkey
124 static PHOT_KEY FASTCALL
125 IsHotKey(UINT fsModifiers
, WORD wVk
)
127 PHOT_KEY pHotKey
= gphkFirst
;
131 if (pHotKey
->fsModifiers
== fsModifiers
&&
134 /* We have found it */
138 /* Move to the next entry */
139 pHotKey
= pHotKey
->pNext
;
148 * Sends syscommand to specified window
152 SendSysCmdMsg(HWND hWnd
, WPARAM Cmd
, LPARAM lParam
)
156 LARGE_INTEGER LargeTickCount
;
158 /* Get ptr to given window */
159 pWnd
= UserGetWindowObject(hWnd
);
162 WARN("Invalid window!\n");
166 /* Prepare WM_SYSCOMMAND message */
168 Msg
.message
= WM_SYSCOMMAND
;
171 KeQueryTickCount(&LargeTickCount
);
172 Msg
.time
= MsqCalculateMessageTime(&LargeTickCount
);
173 Msg
.pt
= gpsi
->ptCursor
;
175 /* Post message to window */
176 MsqPostMessage(pWnd
->head
.pti
->MessageQueue
, &Msg
, FALSE
, QS_POSTMESSAGE
);
180 * co_UserProcessHotKeys
182 * Sends WM_HOTKEY message if given keys are hotkey
185 co_UserProcessHotKeys(WORD wVk
, BOOL bIsDown
)
190 if (wVk
== VK_SHIFT
|| wVk
== VK_CONTROL
|| wVk
== VK_MENU
||
191 wVk
== VK_LWIN
|| wVk
== VK_RWIN
)
193 /* Those keys are specified by modifiers */
197 /* Check if it is a hotkey */
198 fModifiers
= IntGetModifiers(gafAsyncKeyState
);
199 pHotKey
= IsHotKey(fModifiers
, wVk
);
202 /* Process hotkey if it is key up event */
205 TRACE("Hot key pressed (hWnd %p, id %d)\n", pHotKey
->hWnd
, pHotKey
->id
);
207 /* WIN and F12 keys are hardcoded here. See: http://ivanlef0u.fr/repo/windoz/VI20051005.html */
208 if (pHotKey
== &hkWinKey
)
209 SendSysCmdMsg(InputWindowStation
->ShellWindow
, SC_TASKLIST
, 0);
210 else if (pHotKey
== &hkF12
|| pHotKey
== &hkShiftF12
)
212 //co_ActivateDebugger(); // FIXME
214 else if (pHotKey
->id
== IDHK_REACTOS
&& !pHotKey
->pThread
) // FIXME: Those hotkeys doesn't depend on RegisterHotKey
216 SendSysCmdMsg(pHotKey
->hWnd
, SC_HOTKEY
, (LPARAM
)pHotKey
->hWnd
);
220 MsqPostHotKeyMessage(pHotKey
->pThread
,
223 MAKELPARAM((WORD
)fModifiers
, wVk
));
227 return TRUE
; /* Don't send any message */
237 * GetHotKey message support
240 DefWndGetHotKey(HWND hWnd
)
242 PHOT_KEY pHotKey
= gphkFirst
;
244 WARN("DefWndGetHotKey\n");
248 if (pHotKey
->hWnd
== hWnd
&& pHotKey
->id
== IDHK_REACTOS
)
250 /* We have found it */
251 return MAKELONG(pHotKey
->vk
, pHotKey
->fsModifiers
);
254 /* Move to the next entry */
255 pHotKey
= pHotKey
->pNext
;
264 * SetHotKey message support
267 DefWndSetHotKey(PWND pWnd
, WPARAM wParam
)
269 UINT fsModifiers
, vk
;
270 PHOT_KEY pHotKey
, *pLink
;
274 WARN("DefWndSetHotKey wParam 0x%x\n", wParam
);
276 // A hot key cannot be associated with a child window.
277 if (pWnd
->style
& WS_CHILD
)
280 // VK_ESCAPE, VK_SPACE, and VK_TAB are invalid hot keys.
281 if (LOWORD(wParam
) == VK_ESCAPE
||
282 LOWORD(wParam
) == VK_SPACE
||
283 LOWORD(wParam
) == VK_TAB
)
289 fsModifiers
= HIWORD(wParam
);
290 hWnd
= UserHMGetHandle(pWnd
);
297 if (pHotKey
->fsModifiers
== fsModifiers
&&
299 pHotKey
->id
== IDHK_REACTOS
)
301 if (pHotKey
->hWnd
!= hWnd
)
302 iRet
= 2; // Another window already has the same hot key.
306 /* Move to the next entry */
307 pHotKey
= pHotKey
->pNext
;
315 if (pHotKey
->hWnd
== hWnd
&&
316 pHotKey
->id
== IDHK_REACTOS
)
318 /* This window has already hotkey registered */
322 /* Move to the next entry */
323 pLink
= &pHotKey
->pNext
;
324 pHotKey
= pHotKey
->pNext
;
331 /* Create new hotkey */
332 pHotKey
= ExAllocatePoolWithTag(PagedPool
, sizeof(HOT_KEY
), USERTAG_HOTKEY
);
336 pHotKey
->hWnd
= hWnd
;
337 pHotKey
->id
= IDHK_REACTOS
; // Don't care, these hot keys are unrelated to the hot keys set by RegisterHotKey
338 pHotKey
->pNext
= gphkFirst
;
342 /* A window can only have one hot key. If the window already has a
343 hot key associated with it, the new hot key replaces the old one. */
344 pHotKey
->pThread
= NULL
;
345 pHotKey
->fsModifiers
= fsModifiers
;
351 *pLink
= pHotKey
->pNext
;
352 ExFreePoolWithTag(pHotKey
, USERTAG_HOTKEY
);
358 /* SYSCALLS *****************************************************************/
362 NtUserRegisterHotKey(HWND hWnd
,
369 PETHREAD pHotKeyThread
;
372 TRACE("Enter NtUserRegisterHotKey\n");
374 if (fsModifiers
& ~(MOD_ALT
|MOD_CONTROL
|MOD_SHIFT
|MOD_WIN
)) // FIXME: Does Win2k3 support MOD_NOREPEAT?
376 WARN("Invalid modifiers: %x\n", fsModifiers
);
377 EngSetLastError(ERROR_INVALID_FLAGS
);
381 UserEnterExclusive();
383 /* Find hotkey thread */
386 pHotKeyThread
= PsGetCurrentThread();
390 pWnd
= UserGetWindowObject(hWnd
);
394 pHotKeyThread
= pWnd
->head
.pti
->pEThread
;
397 /* Check for existing hotkey */
398 if (IsHotKey(fsModifiers
, vk
))
400 EngSetLastError(ERROR_HOTKEY_ALREADY_REGISTERED
);
401 WARN("Hotkey already exists\n");
405 /* Create new hotkey */
406 pHotKey
= ExAllocatePoolWithTag(PagedPool
, sizeof(HOT_KEY
), USERTAG_HOTKEY
);
409 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
413 pHotKey
->pThread
= pHotKeyThread
;
414 pHotKey
->hWnd
= hWnd
;
415 pHotKey
->fsModifiers
= fsModifiers
;
419 /* Insert hotkey to the global list */
420 pHotKey
->pNext
= gphkFirst
;
426 TRACE("Leave NtUserRegisterHotKey, ret=%i\n", bRet
);
433 NtUserUnregisterHotKey(HWND hWnd
, int id
)
435 PHOT_KEY pHotKey
= gphkFirst
, phkNext
, *pLink
= &gphkFirst
;
438 TRACE("Enter NtUserUnregisterHotKey\n");
439 UserEnterExclusive();
441 /* Fail if given window is invalid */
442 if (hWnd
&& !UserGetWindowObject(hWnd
))
447 /* Save next ptr for later use */
448 phkNext
= pHotKey
->pNext
;
450 /* Should we delete this hotkey? */
451 if (pHotKey
->hWnd
== hWnd
&& pHotKey
->id
== id
)
453 /* Update next ptr for previous hotkey and free memory */
455 ExFreePoolWithTag(pHotKey
, USERTAG_HOTKEY
);
459 else /* This hotkey will stay, use its next ptr */
460 pLink
= &pHotKey
->pNext
;
462 /* Move to the next entry */
467 TRACE("Leave NtUserUnregisterHotKey, ret=%i\n", bRet
);