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
;
28 BOOL bWinHotkeyActive
= FALSE
;
30 /* FUNCTIONS *****************************************************************/
35 * Returns a value that indicates if the key is a modifier key, and
40 IntGetModifiers(PBYTE pKeyState
)
44 if (IS_KEY_DOWN(pKeyState
, VK_SHIFT
))
45 fModifiers
|= MOD_SHIFT
;
47 if (IS_KEY_DOWN(pKeyState
, VK_CONTROL
))
48 fModifiers
|= MOD_CONTROL
;
50 if (IS_KEY_DOWN(pKeyState
, VK_MENU
))
51 fModifiers
|= MOD_ALT
;
53 if (IS_KEY_DOWN(pKeyState
, VK_LWIN
) || IS_KEY_DOWN(pKeyState
, VK_RWIN
))
54 fModifiers
|= MOD_WIN
;
60 * UnregisterWindowHotKeys
62 * Removes hotkeys registered by specified window on its cleanup
65 UnregisterWindowHotKeys(PWND pWnd
)
67 PHOT_KEY pHotKey
= gphkFirst
, phkNext
, *pLink
= &gphkFirst
;
68 HWND hWnd
= pWnd
->head
.h
;
72 /* Save next ptr for later use */
73 phkNext
= pHotKey
->pNext
;
75 /* Should we delete this hotkey? */
76 if (pHotKey
->hWnd
== hWnd
)
78 /* Update next ptr for previous hotkey and free memory */
80 ExFreePoolWithTag(pHotKey
, USERTAG_HOTKEY
);
82 else /* This hotkey will stay, use its next ptr */
83 pLink
= &pHotKey
->pNext
;
85 /* Move to the next entry */
91 * UnregisterThreadHotKeys
93 * Removes hotkeys registered by specified thread on its cleanup
96 UnregisterThreadHotKeys(struct _ETHREAD
*pThread
)
98 PHOT_KEY pHotKey
= gphkFirst
, phkNext
, *pLink
= &gphkFirst
;
102 /* Save next ptr for later use */
103 phkNext
= pHotKey
->pNext
;
105 /* Should we delete this hotkey? */
106 if (pHotKey
->pThread
== pThread
)
108 /* Update next ptr for previous hotkey and free memory */
110 ExFreePoolWithTag(pHotKey
, USERTAG_HOTKEY
);
112 else /* This hotkey will stay, use its next ptr */
113 pLink
= &pHotKey
->pNext
;
115 /* Move to the next entry */
123 * Checks if given key and modificators have corresponding hotkey
125 static PHOT_KEY FASTCALL
126 IsHotKey(UINT fsModifiers
, WORD wVk
)
128 PHOT_KEY pHotKey
= gphkFirst
;
132 if (pHotKey
->fsModifiers
== fsModifiers
&&
135 /* We have found it */
139 /* Move to the next entry */
140 pHotKey
= pHotKey
->pNext
;
147 * co_UserProcessHotKeys
149 * Sends WM_HOTKEY message if given keys are hotkey
152 co_UserProcessHotKeys(WORD wVk
, BOOL bIsDown
)
157 if (wVk
== VK_SHIFT
|| wVk
== VK_CONTROL
|| wVk
== VK_MENU
||
158 wVk
== VK_LWIN
|| wVk
== VK_RWIN
)
160 /* Those keys are specified by modifiers */
164 /* Check if it is a hotkey */
165 fModifiers
= IntGetModifiers(gafAsyncKeyState
);
166 pHotKey
= IsHotKey(fModifiers
, wVk
);
169 /* Process hotkey if it is key up event */
172 TRACE("Hot key pressed (hWnd %p, id %d)\n", pHotKey
->hWnd
, pHotKey
->id
);
174 /* WIN and F12 keys are hardcoded here. See: http://ivanlef0u.fr/repo/windoz/VI20051005.html */
175 if (pHotKey
== &hkWinKey
)
177 if(bWinHotkeyActive
== TRUE
)
179 UserPostMessage(InputWindowStation
->ShellWindow
, WM_SYSCOMMAND
, SC_TASKLIST
, 0);
180 bWinHotkeyActive
= FALSE
;
183 else if (pHotKey
== &hkF12
|| pHotKey
== &hkShiftF12
)
185 //co_ActivateDebugger(); // FIXME
187 else if (pHotKey
->id
== IDHK_REACTOS
&& !pHotKey
->pThread
) // FIXME: Those hotkeys doesn't depend on RegisterHotKey
189 UserPostMessage(pHotKey
->hWnd
, WM_SYSCOMMAND
, SC_HOTKEY
, (LPARAM
)pHotKey
->hWnd
);
193 /* If a hotkey with the WIN modifier was activated, do not treat the release of the WIN key as a hotkey*/
194 if((pHotKey
->fsModifiers
& MOD_WIN
) != 0)
195 bWinHotkeyActive
= FALSE
;
197 MsqPostHotKeyMessage(pHotKey
->pThread
,
200 MAKELPARAM((WORD
)fModifiers
, wVk
));
205 if (pHotKey
== &hkWinKey
)
207 /* The user pressed the win key */
208 bWinHotkeyActive
= TRUE
;
212 return TRUE
; /* Don't send any message */
222 * GetHotKey message support
225 DefWndGetHotKey(HWND hWnd
)
227 PHOT_KEY pHotKey
= gphkFirst
;
229 WARN("DefWndGetHotKey\n");
233 if (pHotKey
->hWnd
== hWnd
&& pHotKey
->id
== IDHK_REACTOS
)
235 /* We have found it */
236 return MAKELONG(pHotKey
->vk
, pHotKey
->fsModifiers
);
239 /* Move to the next entry */
240 pHotKey
= pHotKey
->pNext
;
249 * SetHotKey message support
252 DefWndSetHotKey(PWND pWnd
, WPARAM wParam
)
254 UINT fsModifiers
, vk
;
255 PHOT_KEY pHotKey
, *pLink
;
259 WARN("DefWndSetHotKey wParam 0x%x\n", wParam
);
261 // A hot key cannot be associated with a child window.
262 if (pWnd
->style
& WS_CHILD
)
265 // VK_ESCAPE, VK_SPACE, and VK_TAB are invalid hot keys.
266 if (LOWORD(wParam
) == VK_ESCAPE
||
267 LOWORD(wParam
) == VK_SPACE
||
268 LOWORD(wParam
) == VK_TAB
)
274 fsModifiers
= HIWORD(wParam
);
275 hWnd
= UserHMGetHandle(pWnd
);
282 if (pHotKey
->fsModifiers
== fsModifiers
&&
284 pHotKey
->id
== IDHK_REACTOS
)
286 if (pHotKey
->hWnd
!= hWnd
)
287 iRet
= 2; // Another window already has the same hot key.
291 /* Move to the next entry */
292 pHotKey
= pHotKey
->pNext
;
300 if (pHotKey
->hWnd
== hWnd
&&
301 pHotKey
->id
== IDHK_REACTOS
)
303 /* This window has already hotkey registered */
307 /* Move to the next entry */
308 pLink
= &pHotKey
->pNext
;
309 pHotKey
= pHotKey
->pNext
;
316 /* Create new hotkey */
317 pHotKey
= ExAllocatePoolWithTag(PagedPool
, sizeof(HOT_KEY
), USERTAG_HOTKEY
);
321 pHotKey
->hWnd
= hWnd
;
322 pHotKey
->id
= IDHK_REACTOS
; // Don't care, these hot keys are unrelated to the hot keys set by RegisterHotKey
323 pHotKey
->pNext
= gphkFirst
;
327 /* A window can only have one hot key. If the window already has a
328 hot key associated with it, the new hot key replaces the old one. */
329 pHotKey
->pThread
= NULL
;
330 pHotKey
->fsModifiers
= fsModifiers
;
336 *pLink
= pHotKey
->pNext
;
337 ExFreePoolWithTag(pHotKey
, USERTAG_HOTKEY
);
343 /* SYSCALLS *****************************************************************/
347 NtUserRegisterHotKey(HWND hWnd
,
354 PETHREAD pHotKeyThread
;
357 TRACE("Enter NtUserRegisterHotKey\n");
359 if (fsModifiers
& ~(MOD_ALT
|MOD_CONTROL
|MOD_SHIFT
|MOD_WIN
)) // FIXME: Does Win2k3 support MOD_NOREPEAT?
361 WARN("Invalid modifiers: %x\n", fsModifiers
);
362 EngSetLastError(ERROR_INVALID_FLAGS
);
366 UserEnterExclusive();
368 /* Find hotkey thread */
371 pHotKeyThread
= PsGetCurrentThread();
375 pWnd
= UserGetWindowObject(hWnd
);
379 pHotKeyThread
= pWnd
->head
.pti
->pEThread
;
382 /* Check for existing hotkey */
383 if (IsHotKey(fsModifiers
, vk
))
385 EngSetLastError(ERROR_HOTKEY_ALREADY_REGISTERED
);
386 WARN("Hotkey already exists\n");
390 /* Create new hotkey */
391 pHotKey
= ExAllocatePoolWithTag(PagedPool
, sizeof(HOT_KEY
), USERTAG_HOTKEY
);
394 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
398 pHotKey
->pThread
= pHotKeyThread
;
399 pHotKey
->hWnd
= hWnd
;
400 pHotKey
->fsModifiers
= fsModifiers
;
404 /* Insert hotkey to the global list */
405 pHotKey
->pNext
= gphkFirst
;
411 TRACE("Leave NtUserRegisterHotKey, ret=%i\n", bRet
);
418 NtUserUnregisterHotKey(HWND hWnd
, int id
)
420 PHOT_KEY pHotKey
= gphkFirst
, phkNext
, *pLink
= &gphkFirst
;
423 TRACE("Enter NtUserUnregisterHotKey\n");
424 UserEnterExclusive();
426 /* Fail if given window is invalid */
427 if (hWnd
&& !UserGetWindowObject(hWnd
))
432 /* Save next ptr for later use */
433 phkNext
= pHotKey
->pNext
;
435 /* Should we delete this hotkey? */
436 if (pHotKey
->hWnd
== hWnd
&& pHotKey
->id
== id
)
438 /* Update next ptr for previous hotkey and free memory */
440 ExFreePoolWithTag(pHotKey
, USERTAG_HOTKEY
);
444 else /* This hotkey will stay, use its next ptr */
445 pLink
= &pHotKey
->pNext
;
447 /* Move to the next entry */
452 TRACE("Leave NtUserUnregisterHotKey, ret=%i\n", bRet
);