* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Win32k subsystem
* PURPOSE: HotKey support
- * FILE: subsystems/win32/win32k/ntuser/hotkey.c
+ * FILE: win32ss/user/ntuser/hotkey.c
* PROGRAMER: Eric Kohl
*/
/*
* FIXME: Hotkey notifications are triggered by keyboard input (physical or programatically)
- * and since only desktops on WinSta0 can recieve input in seems very wrong to allow
- * windows/threads on destops not belonging to WinSta0 to set hotkeys (recieve notifications).
+ * and since only desktops on WinSta0 can receive input in seems very wrong to allow
+ * windows/threads on destops not belonging to WinSta0 to set hotkeys (receive notifications).
* -- Gunnar
*/
/* GLOBALS *******************************************************************/
-/* Hardcoded hotkeys. See http://ivanlef0u.fr/repo/windoz/VI20051005.html */
-/* thread hwnd modifiers vk id next */
-HOT_KEY hkF12 = {NULL, NULL, 0, VK_F12, IDHK_F12, NULL};
-HOT_KEY hkShiftF12 = {NULL, NULL, MOD_SHIFT, VK_F12, IDHK_SHIFTF12, &hkF12};
-HOT_KEY hkWinKey = {NULL, NULL, MOD_WIN, 0, IDHK_WINKEY, &hkShiftF12};
+/*
+ * Hardcoded hotkeys. See http://ivanlef0u.fr/repo/windoz/VI20051005.html
+ * or http://repo.meh.or.id/Windows/VI20051005.html .
+ *
+ * NOTE: The (Shift-)F12 keys are used only for the "UserDebuggerHotKey" setting
+ * which enables setting a key shortcut which, when pressed, establishes a
+ * breakpoint in the code being debugged:
+ * see http://technet.microsoft.com/en-us/library/cc786263(v=ws.10).aspx
+ * and http://flylib.com/books/en/4.441.1.33/1/ for more details.
+ * By default the key is VK-F12 on a 101-key keyboard, and is VK_SUBTRACT
+ * (hyphen / substract sign) on a 82-key keyboard.
+ */
+/* pti pwnd modifiers vk id next */
+// HOT_KEY hkF12 = {NULL, 1, 0, VK_F12, IDHK_F12, NULL};
+// HOT_KEY hkShiftF12 = {NULL, 1, MOD_SHIFT, VK_F12, IDHK_SHIFTF12, &hkF12};
+// HOT_KEY hkWinKey = {NULL, 1, MOD_WIN, 0, IDHK_WINKEY, &hkShiftF12};
-PHOT_KEY gphkFirst = &hkWinKey;
-BOOL bWinHotkeyActive = FALSE;
+PHOT_KEY gphkFirst = NULL;
+UINT gfsModOnlyCandidate;
/* FUNCTIONS *****************************************************************/
+VOID FASTCALL
+StartDebugHotKeys(VOID)
+{
+ UINT vk = VK_F12;
+ UserUnregisterHotKey(PWND_BOTTOM, IDHK_F12);
+ UserUnregisterHotKey(PWND_BOTTOM, IDHK_SHIFTF12);
+ if (!ENHANCED_KEYBOARD(gKeyboardInfo.KeyboardIdentifier))
+ {
+ vk = VK_SUBTRACT;
+ }
+ UserRegisterHotKey(PWND_BOTTOM, IDHK_SHIFTF12, MOD_SHIFT, vk);
+ UserRegisterHotKey(PWND_BOTTOM, IDHK_F12, 0, vk);
+ TRACE("Start up the debugger hotkeys!! If you see this you eneabled debugprints. Congrats!\n");
+}
+
/*
* IntGetModifiers
*
UnregisterWindowHotKeys(PWND pWnd)
{
PHOT_KEY pHotKey = gphkFirst, phkNext, *pLink = &gphkFirst;
- HWND hWnd = pWnd->head.h;
while (pHotKey)
{
phkNext = pHotKey->pNext;
/* Should we delete this hotkey? */
- if (pHotKey->hWnd == hWnd)
+ if (pHotKey->pWnd == pWnd)
{
/* Update next ptr for previous hotkey and free memory */
*pLink = phkNext;
* Removes hotkeys registered by specified thread on its cleanup
*/
VOID FASTCALL
-UnregisterThreadHotKeys(struct _ETHREAD *pThread)
+UnregisterThreadHotKeys(PTHREADINFO pti)
{
PHOT_KEY pHotKey = gphkFirst, phkNext, *pLink = &gphkFirst;
phkNext = pHotKey->pNext;
/* Should we delete this hotkey? */
- if (pHotKey->pThread == pThread)
+ if (pHotKey->pti == pti)
{
/* Update next ptr for previous hotkey and free memory */
*pLink = phkNext;
{
UINT fModifiers;
PHOT_KEY pHotKey;
+ PWND pWnd;
+ BOOL DoNotPostMsg = FALSE;
+ BOOL IsModifier = FALSE;
if (wVk == VK_SHIFT || wVk == VK_CONTROL || wVk == VK_MENU ||
wVk == VK_LWIN || wVk == VK_RWIN)
{
- /* Those keys are specified by modifiers */
- wVk = 0;
+ /* Remember that this was a modifier */
+ IsModifier = TRUE;
}
- /* Check if it is a hotkey */
fModifiers = IntGetModifiers(gafAsyncKeyState);
- pHotKey = IsHotKey(fModifiers, wVk);
- if (pHotKey)
+
+ if (bIsDown)
+ {
+ if (IsModifier)
+ {
+ /* Modifier key down -- no hotkey trigger, but remember this */
+ gfsModOnlyCandidate = fModifiers;
+ return FALSE;
+ }
+ else
+ {
+ /* Regular key down -- check for hotkey, and reset mod candidates */
+ pHotKey = IsHotKey(fModifiers, wVk);
+ gfsModOnlyCandidate = 0;
+ }
+ }
+ else
{
- /* Process hotkey if it is key up event */
- if (!bIsDown)
+ if (IsModifier)
+ {
+ /* Modifier key up -- modifier-only keys are triggered here */
+ pHotKey = IsHotKey(gfsModOnlyCandidate, 0);
+ gfsModOnlyCandidate = 0;
+ }
+ else
{
- TRACE("Hot key pressed (hWnd %p, id %d)\n", pHotKey->hWnd, pHotKey->id);
+ /* Regular key up -- no hotkey, but reset mod-only candidates */
+ gfsModOnlyCandidate = 0;
+ return FALSE;
+ }
+ }
- /* WIN and F12 keys are hardcoded here. See: http://ivanlef0u.fr/repo/windoz/VI20051005.html */
- if (pHotKey == &hkWinKey)
- {
- if(bWinHotkeyActive == TRUE)
- {
- UserPostMessage(InputWindowStation->ShellWindow, WM_SYSCOMMAND, SC_TASKLIST, 0);
- bWinHotkeyActive = FALSE;
- }
- }
- else if (pHotKey == &hkF12 || pHotKey == &hkShiftF12)
+ if (pHotKey)
+ {
+ TRACE("Hot key pressed (pWnd %p, id %d)\n", pHotKey->pWnd, pHotKey->id);
+
+ /* FIXME: See comment about "UserDebuggerHotKey" on top of this file. */
+ if (pHotKey->id == IDHK_SHIFTF12 || pHotKey->id == IDHK_F12)
+ {
+ if (bIsDown)
{
- //co_ActivateDebugger(); // FIXME
+ ERR("Hot key pressed for Debug Activation! ShiftF12 = %d or F12 = %d\n",pHotKey->id == IDHK_SHIFTF12 , pHotKey->id == IDHK_F12);
+ //DoNotPostMsg = co_ActivateDebugger(); // FIXME
}
- else if (pHotKey->id == IDHK_REACTOS && !pHotKey->pThread) // FIXME: Those hotkeys doesn't depend on RegisterHotKey
+ return DoNotPostMsg;
+ }
+
+ /* WIN and F12 keys are not hardcoded here. See comments on top of this file. */
+ if (pHotKey->id == IDHK_WINKEY)
+ {
+ ASSERT(!bIsDown);
+ pWnd = ValidateHwndNoErr(InputWindowStation->ShellWindow);
+ if (pWnd)
{
- UserPostMessage(pHotKey->hWnd, WM_SYSCOMMAND, SC_HOTKEY, (LPARAM)pHotKey->hWnd);
+ TRACE("System Hot key Id %d Key %u\n", pHotKey->id, wVk );
+ UserPostMessage(UserHMGetHandle(pWnd), WM_SYSCOMMAND, SC_TASKLIST, 0);
+ co_IntShellHookNotify(HSHELL_TASKMAN, 0, 0);
+ return FALSE;
}
- else
+ }
+
+ if (pHotKey->id == IDHK_SNAP_LEFT ||
+ pHotKey->id == IDHK_SNAP_RIGHT ||
+ pHotKey->id == IDHK_SNAP_UP ||
+ pHotKey->id == IDHK_SNAP_DOWN)
+ {
+ HWND topWnd = UserGetForegroundWindow();
+ if (topWnd)
{
- /* If a hotkey with the WIN modifier was activated, do not treat the release of the WIN key as a hotkey*/
- if((pHotKey->fsModifiers & MOD_WIN) != 0)
- bWinHotkeyActive = FALSE;
-
- MsqPostHotKeyMessage(pHotKey->pThread,
- pHotKey->hWnd,
- (WPARAM)pHotKey->id,
- MAKELPARAM((WORD)fModifiers, wVk));
+ UserPostMessage(topWnd, WM_KEYDOWN, wVk, 0);
}
+ return TRUE;
+ }
+
+ if (!pHotKey->pWnd)
+ {
+ TRACE("UPTM Hot key Id %d Key %u\n", pHotKey->id, wVk );
+ UserPostThreadMessage(pHotKey->pti, WM_HOTKEY, pHotKey->id, MAKELONG(fModifiers, wVk));
+ //ptiLastInput = pHotKey->pti;
+ return TRUE; /* Don't send any message */
}
else
{
- if (pHotKey == &hkWinKey)
+ pWnd = pHotKey->pWnd;
+ if (pWnd == PWND_BOTTOM)
{
- /* The user pressed the win key */
- bWinHotkeyActive = TRUE;
+ if (gpqForeground == NULL)
+ return FALSE;
+
+ pWnd = gpqForeground->spwndFocus;
}
- }
- return TRUE; /* Don't send any message */
+ if (pWnd)
+ {
+ // pWnd->head.rpdesk->pDeskInfo->spwndShell needs testing.
+ if (pWnd == ValidateHwndNoErr(InputWindowStation->ShellWindow) && pHotKey->id == SC_TASKLIST)
+ {
+ UserPostMessage(UserHMGetHandle(pWnd), WM_SYSCOMMAND, SC_TASKLIST, 0);
+ co_IntShellHookNotify(HSHELL_TASKMAN, 0, 0);
+ }
+ else
+ {
+ TRACE("UPM Hot key Id %d Key %u\n", pHotKey->id, wVk );
+ UserPostMessage(UserHMGetHandle(pWnd), WM_HOTKEY, pHotKey->id, MAKELONG(fModifiers, wVk));
+ }
+ //ptiLastInput = pWnd->head.pti;
+ return TRUE; /* Don't send any message */
+ }
+ }
}
-
return FALSE;
}
* GetHotKey message support
*/
UINT FASTCALL
-DefWndGetHotKey(HWND hWnd)
+DefWndGetHotKey(PWND pWnd)
{
PHOT_KEY pHotKey = gphkFirst;
while (pHotKey)
{
- if (pHotKey->hWnd == hWnd && pHotKey->id == IDHK_REACTOS)
+ if (pHotKey->pWnd == pWnd && pHotKey->id == IDHK_REACTOS)
{
/* We have found it */
return MAKELONG(pHotKey->vk, pHotKey->fsModifiers);
{
UINT fsModifiers, vk;
PHOT_KEY pHotKey, *pLink;
- HWND hWnd;
INT iRet = 1;
WARN("DefWndSetHotKey wParam 0x%x\n", wParam);
vk = LOWORD(wParam);
fsModifiers = HIWORD(wParam);
- hWnd = UserHMGetHandle(pWnd);
if (wParam)
{
pHotKey->vk == vk &&
pHotKey->id == IDHK_REACTOS)
{
- if (pHotKey->hWnd != hWnd)
+ if (pHotKey->pWnd != pWnd)
iRet = 2; // Another window already has the same hot key.
break;
}
pHotKey = pHotKey->pNext;
}
}
-
+
pHotKey = gphkFirst;
pLink = &gphkFirst;
while (pHotKey)
{
- if (pHotKey->hWnd == hWnd &&
+ if (pHotKey->pWnd == pWnd &&
pHotKey->id == IDHK_REACTOS)
{
/* This window has already hotkey registered */
if (pHotKey == NULL)
return 0;
- pHotKey->hWnd = hWnd;
+ pHotKey->pWnd = pWnd;
pHotKey->id = IDHK_REACTOS; // Don't care, these hot keys are unrelated to the hot keys set by RegisterHotKey
pHotKey->pNext = gphkFirst;
gphkFirst = pHotKey;
/* A window can only have one hot key. If the window already has a
hot key associated with it, the new hot key replaces the old one. */
- pHotKey->pThread = NULL;
+ pHotKey->pti = NULL;
pHotKey->fsModifiers = fsModifiers;
pHotKey->vk = vk;
}
return iRet;
}
+
+BOOL FASTCALL
+UserRegisterHotKey(PWND pWnd,
+ int id,
+ UINT fsModifiers,
+ UINT vk)
+{
+ PHOT_KEY pHotKey;
+ PTHREADINFO pHotKeyThread;
+
+ /* Find hotkey thread */
+ if (pWnd == NULL || pWnd == PWND_BOTTOM)
+ {
+ pHotKeyThread = PsGetCurrentThreadWin32Thread();
+ }
+ else
+ {
+ pHotKeyThread = pWnd->head.pti;
+ }
+
+ /* Check for existing hotkey */
+ if (IsHotKey(fsModifiers, vk))
+ {
+ EngSetLastError(ERROR_HOTKEY_ALREADY_REGISTERED);
+ WARN("Hotkey already exists\n");
+ return FALSE;
+ }
+
+ /* Create new hotkey */
+ pHotKey = ExAllocatePoolWithTag(PagedPool, sizeof(HOT_KEY), USERTAG_HOTKEY);
+ if (pHotKey == NULL)
+ {
+ EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ return FALSE;
+ }
+
+ pHotKey->pti = pHotKeyThread;
+ pHotKey->pWnd = pWnd;
+ pHotKey->fsModifiers = fsModifiers;
+ pHotKey->vk = vk;
+ pHotKey->id = id;
+
+ /* Insert hotkey to the global list */
+ pHotKey->pNext = gphkFirst;
+ gphkFirst = pHotKey;
+
+ return TRUE;
+}
+
+BOOL FASTCALL
+UserUnregisterHotKey(PWND pWnd, int id)
+{
+ PHOT_KEY pHotKey = gphkFirst, phkNext, *pLink = &gphkFirst;
+ BOOL bRet = FALSE;
+
+ while (pHotKey)
+ {
+ /* Save next ptr for later use */
+ phkNext = pHotKey->pNext;
+
+ /* Should we delete this hotkey? */
+ if (pHotKey->pWnd == pWnd && pHotKey->id == id)
+ {
+ /* Update next ptr for previous hotkey and free memory */
+ *pLink = phkNext;
+ ExFreePoolWithTag(pHotKey, USERTAG_HOTKEY);
+
+ bRet = TRUE;
+ }
+ else /* This hotkey will stay, use its next ptr */
+ pLink = &pHotKey->pNext;
+
+ /* Move to the next entry */
+ pHotKey = phkNext;
+ }
+ return bRet;
+}
+
+
/* SYSCALLS *****************************************************************/
UINT vk)
{
PHOT_KEY pHotKey;
- PWND pWnd;
- PETHREAD pHotKeyThread;
+ PWND pWnd = NULL;
+ PTHREADINFO pHotKeyThread;
BOOL bRet = FALSE;
TRACE("Enter NtUserRegisterHotKey\n");
/* Find hotkey thread */
if (hWnd == NULL)
{
- pHotKeyThread = PsGetCurrentThread();
+ pHotKeyThread = gptiCurrent;
}
else
{
if (!pWnd)
goto cleanup;
- pHotKeyThread = pWnd->head.pti->pEThread;
+ pHotKeyThread = pWnd->head.pti;
+
+ /* Fix wine msg "Window on another thread" test_hotkey */
+ if (pWnd->head.pti != gptiCurrent)
+ {
+ EngSetLastError(ERROR_WINDOW_OF_OTHER_THREAD);
+ WARN("Must be from the same Thread.\n");
+ goto cleanup;
+ }
}
/* Check for existing hotkey */
goto cleanup;
}
- pHotKey->pThread = pHotKeyThread;
- pHotKey->hWnd = hWnd;
+ pHotKey->pti = pHotKeyThread;
+ pHotKey->pWnd = pWnd;
pHotKey->fsModifiers = fsModifiers;
pHotKey->vk = vk;
pHotKey->id = id;
{
PHOT_KEY pHotKey = gphkFirst, phkNext, *pLink = &gphkFirst;
BOOL bRet = FALSE;
+ PWND pWnd = NULL;
TRACE("Enter NtUserUnregisterHotKey\n");
UserEnterExclusive();
/* Fail if given window is invalid */
- if (hWnd && !UserGetWindowObject(hWnd))
+ if (hWnd && !(pWnd = UserGetWindowObject(hWnd)))
goto cleanup;
while (pHotKey)
phkNext = pHotKey->pNext;
/* Should we delete this hotkey? */
- if (pHotKey->hWnd == hWnd && pHotKey->id == id)
+ if (pHotKey->pWnd == pWnd && pHotKey->id == id)
{
/* Update next ptr for previous hotkey and free memory */
*pLink = phkNext;