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 xxxDoHotKeyStuff( UINT vk, BOOL fBreak, DWORD fsReserveKeys) { #ifdef WINDOWS_NOT_HOT static BOOL fOnlyWinKey = FALSE; #endif static UINT fsModifiers = 0; static UINT fsModOnlyCandidate = 0; UINT fsModOnlyHotkey; UINT fs; PHOTKEY phk; PWND pwnd; BOOL fCancel; BOOL fEatDebugKeyBreak = FALSE; CheckCritIn(); /* * Update fsModifiers. */ fs = 0; fsModOnlyHotkey = 0; switch (vk) { case VK_RSHIFT: fs = MOD_RSHIFT; case VK_LSHIFT: case VK_SHIFT: vk = VK_SHIFT; fs |= MOD_SHIFT; break; case VK_RCONTROL: fs = MOD_RCONTROL; case VK_LCONTROL: vk = VK_CONTROL; case VK_CONTROL: fs |= MOD_CONTROL; break; case VK_RMENU: fs = MOD_RALT; case VK_LMENU: vk = VK_MENU; case VK_MENU: fs |= MOD_ALT; break; case VK_LWIN: case VK_RWIN: fs = MOD_WIN; break; default: /* * A non-modifier key rules out Modifier-Only hotkeys */ fsModOnlyCandidate = 0; break; } if (fBreak) { fsModifiers &= ~fs; /* * If a modifier key is coming up, the current modifier only hotkey * candidate must be tested to see if it is a hotkey. Store this * in fsModOnlyHotkey, and prevent the next key release from * being a candidate by clearing fsModOnlyCandidate. */ if (fs != 0) { fsModOnlyHotkey = fsModOnlyCandidate; fsModOnlyCandidate = 0; } } else { fsModifiers |= fs; /* * If a modifier key is going down, we have a modifier-only hotkey * candidate. Save current modifier state until the following break. */ if (fs != 0) { fsModOnlyCandidate = fsModifiers; } } if (vk == VK_DELETE) { /* * Special case for SAS (Ctrl+Alt+Del) - examine physical key state! * * An evil daemon process can fool convincingly pretend to be winlogon * by registering Alt+Del as a hotkey, and spinning another thread that * continually calls keybd_event() to send the Ctrl key up: when the * user types Ctrl+Alt+Del, only Alt+Del will be seen by the system, * the evil daemon will get woken by WM_HOTKEY and can pretend to be * winlogon. So look at gafPhysKeyState in this case, to see what keys * were physically pressed. * NOTE: If hotkeys are ever made to work under journal playback, make * sure they don't affect the gafPhysKeyState! - IanJa. */ UINT fPhysMods = (TestKeyDownBit(gafPhysKeyState, VK_MENU) ? MOD_ALT : 0) | (TestKeyDownBit(gafPhysKeyState, VK_SHIFT) ? MOD_SHIFT : 0) | (TestKeyDownBit(gafPhysKeyState, VK_CONTROL) ? MOD_CONTROL : 0); if ((fPhysMods & (MOD_CONTROL|MOD_ALT)) == MOD_CONTROL|MOD_ALT) { /* * Use physical modifiers keys */ fsModifiers = fPhysMods; } } #ifdef WINDOWS_NOT_HOT /* * track whether any key has been pressed since a Windows key went down */ if (vk == VK_LWIN || vk == VK_RWIN) { if (!fBreak) { fOnlyWinKey = TRUE; } else if (fOnlyWinKey) { fOnlyWinKey = FALSE; CancelJournalling(); pwnd = GETDESKINFO(PtiCurrent())->spwndShell; if (pwnd != NULL) { _PostMessage(pwnd, WM_SYSCOMMAND, SC_TASKLIST, 0); return TRUE; } } } else { fOnlyWinKey = FALSE; } #endif /* * If the key is not a hotkey then we're done but first check if the * key is an Alt-Escape if so we need to cancel journalling. * * NOTE: Support for Alt+Esc to cancel journalling dropped in NT 4.0 */ if (fsModOnlyHotkey && fBreak) { /* * A hotkey involving only VK_SHIFT, VK_CONTROL, VK_MENU or VK_WINDOWS * must only operate on a key release. */ if ((phk = IsHotKey(LOWORD(fsModOnlyHotkey), VK_NONE)) == NULL) { return FALSE; } } else if ((phk = IsHotKey(LOWORD(fsModifiers), vk)) == NULL) { return FALSE; } if (phk->id == IDHOT_WINDOWS) { pwnd = GETDESKINFO(PtiCurrent())->spwndShell; if (pwnd != NULL) { _PostMessage(pwnd, WM_SYSCOMMAND, SC_TASKLIST, 0); return TRUE; } } if ((phk->id == IDHOT_DEBUG) || (phk->id == IDHOT_DEBUGSERVER)) { if (!fBreak) { /* * The DEBUG key has been pressed. Break the appropriate * thread into the debugger. */ fEatDebugKeyBreak = xxxActivateDebugger(phk->fsModifiers); } /* * This'll eat the debug key down and break if we broke into * the debugger on the server only on the down. */ return fEatDebugKeyBreak; } /* * don't allow hotkeys(except for ones owned by the logon process) * if the window station is locked. */ if (((grpdeskRitInput->rpwinstaParent->dwFlags & WSF_SWITCHLOCK) != 0) && (phk->pti->Thread->Cid.UniqueProcess != gpidLogon)) { return FALSE; } if ((fsModOnlyHotkey == 0) && fBreak) { /* * Do Modifier-Only hotkeys on break events, else return here. */ return FALSE; } /* * Unhook hooks if a control-escape, alt-escape, or control-alt-del * comes through, so the user can cancel if the system seems hung. * * Note the hook may be locked so even if the unhook succeeds it * won't remove the hook from the global asphkStart array. So * we have to walk the list manually. This code works because * we are in the critical section and we know other hooks won't * be deleted. * * Once we've unhooked, post a WM_CANCELJOURNAL message to the app * that set the hook so it knows we did this. * * NOTE: Support for Alt+Esc to cancel journalling dropped in NT 4.0 */ fCancel = FALSE; if (vk == VK_ESCAPE && LOWORD(fsModifiers) == MOD_CONTROL) { fCancel = TRUE; } if (vk == VK_DELETE && (fsModifiers & (MOD_CONTROL | MOD_ALT)) == (MOD_CONTROL | MOD_ALT)) { fCancel = TRUE; } if (fCancel) CancelJournalling(); /* * See if the key is reserved by a console window. If it is, * return FALSE so the key will be passed to the console. */ if (fsReserveKeys != 0) { switch (vk) { case VK_TAB: if ((fsReserveKeys & CONSOLE_ALTTAB) && ((fsModifiers & (MOD_CONTROL | MOD_ALT)) == MOD_ALT)) { return FALSE; } break; case VK_ESCAPE: if ((fsReserveKeys & CONSOLE_ALTESC) && ((fsModifiers & (MOD_CONTROL | MOD_ALT)) == MOD_ALT)) { return FALSE; } if ((fsReserveKeys & CONSOLE_CTRLESC) && ((fsModifiers & (MOD_CONTROL | MOD_ALT)) == MOD_CONTROL)) { return FALSE; } break; case VK_RETURN: if ((fsReserveKeys & CONSOLE_ALTENTER) && ((fsModifiers & (MOD_CONTROL | MOD_ALT)) == MOD_ALT)) { return FALSE; } break; case VK_SNAPSHOT: if ((fsReserveKeys & CONSOLE_PRTSC) && ((fsModifiers & (MOD_CONTROL | MOD_ALT)) == 0)) { return FALSE; } if ((fsReserveKeys & CONSOLE_ALTPRTSC) && ((fsModifiers & (MOD_CONTROL | MOD_ALT)) == MOD_ALT)) { return FALSE; } break; case VK_SPACE: if ((fsReserveKeys & CONSOLE_ALTSPACE) && ((fsModifiers & (MOD_CONTROL | MOD_ALT)) == MOD_ALT)) { return FALSE; } break; } } /* * If this is the task-list hotkey, go ahead and set foreground * status to the task-list queue right now. This prevents problems * where the user hits ctrl-esc and types-ahead before the task-list * processes the hotkey and brings up the task-list window. */ if ((LOWORD(fsModifiers) == MOD_CONTROL) && (vk == VK_ESCAPE) && !fBreak) { PWND pwndSwitch; TL tlpwndSwitch; if (ghwndSwitch != NULL) { pwndSwitch = PW(ghwndSwitch); ThreadLock(pwndSwitch, &tlpwndSwitch); xxxSetForegroundWindow2(pwndSwitch, NULL, 0); ThreadUnlock(&tlpwndSwitch); } } /* * Get the hot key contents. */ if (phk->spwnd == NULL) { _PostThreadMessage( phk->pti, WM_HOTKEY, phk->id, MAKELONG(LOWORD(fsModifiers), vk)); } else { if (phk->spwnd == PWND_INPUTOWNER) { if (gpqForeground != NULL) { pwnd = gpqForeground->spwndFocus; } else { return FALSE; } } else { pwnd = phk->spwnd; } if (pwnd) { if (pwnd == pwnd->head.rpdesk->pDeskInfo->spwndShell && phk->id == SC_TASKLIST) { _PostMessage(pwnd, WM_SYSCOMMAND, SC_TASKLIST, 0); } else { _PostMessage(pwnd, WM_HOTKEY, phk->id, MAKELONG(LOWORD(fsModifiers), vk)); } } } /* * If this is a Modifier-Only hotkey, let the modifier break through * by returning FALSE, otherwise we will have modifier keys stuck down. */ return (fsModOnlyHotkey == 0); }
BOOL APIENTRY NtUserRegisterHotKey(HWND hWnd, int id, UINT fsModifiers, UINT vk) { PHOT_KEY pHotKey; PWND pWnd = NULL; PTHREADINFO pHotKeyThread; BOOL bRet = FALSE; TRACE("Enter NtUserRegisterHotKey\n"); if (fsModifiers & ~(MOD_ALT|MOD_CONTROL|MOD_SHIFT|MOD_WIN)) // FIXME: Does Win2k3 support MOD_NOREPEAT? { WARN("Invalid modifiers: %x\n", fsModifiers); EngSetLastError(ERROR_INVALID_FLAGS); return 0; } UserEnterExclusive(); /* Find hotkey thread */ if (hWnd == NULL) { pHotKeyThread = gptiCurrent; } else { pWnd = UserGetWindowObject(hWnd); if (!pWnd) goto cleanup; 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 */ if (IsHotKey(fsModifiers, vk)) { EngSetLastError(ERROR_HOTKEY_ALREADY_REGISTERED); WARN("Hotkey already exists\n"); goto cleanup; } /* Create new hotkey */ pHotKey = ExAllocatePoolWithTag(PagedPool, sizeof(HOT_KEY), USERTAG_HOTKEY); if (pHotKey == NULL) { EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); goto cleanup; } 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; bRet = TRUE; cleanup: TRACE("Leave NtUserRegisterHotKey, ret=%i\n", bRet); UserLeave(); return bRet; }
/* * co_UserProcessHotKeys * * Sends WM_HOTKEY message if given keys are hotkey */ BOOL NTAPI co_UserProcessHotKeys(WORD wVk, BOOL bIsDown) { 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) { /* Remember that this was a modifier */ IsModifier = TRUE; } fModifiers = IntGetModifiers(gafAsyncKeyState); 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 { if (IsModifier) { /* Modifier key up -- modifier-only keys are triggered here */ pHotKey = IsHotKey(gfsModOnlyCandidate, 0); gfsModOnlyCandidate = 0; } else { /* Regular key up -- no hotkey, but reset mod-only candidates */ gfsModOnlyCandidate = 0; return FALSE; } } 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) { 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 } 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) { 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; } } 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) { 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 { pWnd = pHotKey->pWnd; if (pWnd == PWND_BOTTOM) { if (gpqForeground == NULL) return FALSE; pWnd = gpqForeground->spwndFocus; } 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; }
/* * co_UserProcessHotKeys * * Sends WM_HOTKEY message if given keys are hotkey */ BOOL NTAPI co_UserProcessHotKeys(WORD wVk, BOOL bIsDown) { UINT fModifiers; PHOT_KEY pHotKey; PWND pWnd; BOOL DoNotPostMsg = 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; } fModifiers = IntGetModifiers(gafAsyncKeyState); /* Check if it is a hotkey */ pHotKey = IsHotKey(fModifiers, wVk); 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) { 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 } return DoNotPostMsg; } /* Process hotkey if it is key up event */ if (!bIsDown) { /* WIN and F12 keys are not hardcoded here. See comments on top of this file. */ if (pHotKey->id == IDHK_WINKEY && bWinHotkeyActive) { pWnd = ValidateHwndNoErr(InputWindowStation->ShellWindow); if (pWnd) { TRACE("System Hot key Id %d Key %d\n",pHotKey->id, wVk ); UserPostMessage(UserHMGetHandle(pWnd), WM_SYSCOMMAND, SC_TASKLIST, 0); co_IntShellHookNotify(HSHELL_TASKMAN, 0, 0); bWinHotkeyActive = FALSE; return FALSE; } } } else { /* The user pressed the win key */ if (pHotKey->id == IDHK_WINKEY) { bWinHotkeyActive = TRUE; return FALSE; } } if (bIsDown) { if (!pHotKey->pWnd) { TRACE("UPTM Hot key Id %d Key %d\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->pWnd == PWND_BOTTOM) { if (gpqForeground != NULL) { pWnd = gpqForeground->spwndFocus; } else return FALSE; } else { pWnd = pHotKey->pWnd; } if (pWnd) { // pWnd->head.rpdesk->pDeskInfo->spwndShell needs testing. if (pWnd == ValidateHwndNoErr(InputWindowStation->ShellWindow) && pHotKey->id == SC_TASKLIST) { ERR("Sending to shell window w/o IDHK_WINKEY..\n"); UserPostMessage(UserHMGetHandle(pWnd), WM_SYSCOMMAND, SC_TASKLIST, 0); } else { TRACE("UPM Hot key Id %d Key %d\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; }