BOOL _SetTaskmanWindow(PWND pwnd) { PDESKTOPINFO pdeskinfo = GETDESKINFO(PtiCurrent()); if (pwnd != NULL) { // Fail the call if another shell window exists if (pdeskinfo->spwndTaskman != NULL) return(FALSE); } Lock(&pdeskinfo->spwndTaskman, pwnd); 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); }
/***************************************************************************\ * * SetShellWindow() * * Returns true if shell window is successfully set. Note that we return * FALSE if a shell window already exists. I.E., this works on a first * come, first serve basis. * * We also do NOT allow child windows to be shell windows. Other than that, * it's up to the caller to size her window appropriately. * * The pwndBkGnd is provided for the explorer shell. Since the shellwnd * and the window which does the drawing of background wallpapers are * different, we need to provide means by which we can draw directly on * the background window during hung-app drawing. The pwnd and pwndBkGnd * will be identical if called through the SetShellWindow() api. * * \***************************************************************************/ BOOL xxxSetShellWindow(PWND pwnd, PWND pwndBkGnd) { PTHREADINFO ptiCurrent = PtiCurrent(); PDESKTOPINFO pdeskinfo = GETDESKINFO(ptiCurrent); PPROCESSINFO ppiShellProcess; UserAssert(pwnd); /* * Fail the call if another shell window exists */ if (pdeskinfo->spwndShell != NULL) return(FALSE); /* * The shell window must be * (1) Top-level * (2) Unowned * (3) Not topmost */ if (TestwndChild(pwnd) || (pwnd->spwndOwner != NULL) || TestWF(pwnd, WEFTOPMOST)) { RIPMSG0(RIP_WARNING, "xxxSetShellWindow: Invalid type of window"); return(FALSE); } /* * Chicago has a totally different input model which has special code * that checks for Ctrl-Esc and sends it to the shell. We can get * the same functionality, without totally re-writing our input model * by just automatically installing the Ctrl-Esc as a hotkey for the * shell window. The hotkey delivery code has a special case which * turns this into a WM_SYSCOMMAND message instead of a WM_HOTKEY * message. * * We don't both checking for failure. Somebody could already have * a Ctrl-Esc handler installed. */ _RegisterHotKey(pwnd,SC_TASKLIST,MOD_CONTROL,VK_ESCAPE); /* * This is the shell window wright. * So get the process id for the shell. */ ppiShellProcess = GETPTI(pwnd)->ppi; /* * Set the shell process id to the desktop only if it's the first instance */ if ((ppiShellProcess != NULL) && (pdeskinfo->ppiShellProcess == NULL)) { pdeskinfo->ppiShellProcess = ppiShellProcess; } Lock(&pdeskinfo->spwndShell, pwnd); Lock(&pdeskinfo->spwndBkGnd, pwndBkGnd); /* * Push window to bottom of stack. */ SetWF(pdeskinfo->spwndShell, WFBOTTOMMOST); xxxSetWindowPos(pdeskinfo->spwndShell, PWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); return(TRUE); }