Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

850 lines
25 KiB

  1. /****************************** Module Header ******************************\
  2. * Module Name: hotkeys.c
  3. *
  4. * Copyright (c) 1985 - 1999, Microsoft Corporation
  5. *
  6. * This module contains the core functions of hotkey processing.
  7. *
  8. * History:
  9. * 12-04-90 DavidPe Created.
  10. * 02-12-91 JimA Added access checks
  11. * 13-Feb-1991 mikeke Added Revalidation code (None)
  12. \***************************************************************************/
  13. #include "precomp.h"
  14. #pragma hdrstop
  15. static PHOTKEY gphkHashTable[128];
  16. /*
  17. * This is the hash function for vks. The vast majority of hotkeys will have
  18. * vk values < 128, so we limit our table to that size. Worst case (all vks
  19. * > 128) we'll have the same perf (essentially) as the old, linked list
  20. * code.
  21. */
  22. __inline BYTE HKHashVK(
  23. UINT vk)
  24. {
  25. return (BYTE)(vk & (ARRAY_SIZE(gphkHashTable) - 1));
  26. }
  27. /***************************************************************************\
  28. * HKGetHashHead
  29. *
  30. * This routine returns the start of the bucket keyed by the specified vk.
  31. *
  32. * History:
  33. * 08-13-2002 JasonSch Created.
  34. \***************************************************************************/
  35. PHOTKEY HKGetHashHead(
  36. UINT vk)
  37. {
  38. return gphkHashTable[HKHashVK(vk)];
  39. }
  40. /***************************************************************************\
  41. * HKInsertHashElement
  42. *
  43. * Inserts a HOTKEY structure into the hash table.
  44. *
  45. * History:
  46. * 08-13-2002 JasonSch Created.
  47. \***************************************************************************/
  48. VOID HKInsertHashElement(
  49. PHOTKEY phk)
  50. {
  51. BYTE index = HKHashVK(phk->vk);
  52. PHOTKEY phkT;
  53. phkT = gphkHashTable[index];
  54. phk->phkNext = phkT;
  55. gphkHashTable[index] = phk;
  56. }
  57. /***************************************************************************\
  58. * SetDebugHotKeys
  59. *
  60. * This routine registers the default system hotkeys for debugging.
  61. *
  62. * History:
  63. * 12-04-90 DavidPe Created.
  64. \***************************************************************************/
  65. VOID SetDebugHotKeys(
  66. VOID)
  67. {
  68. UINT VkDebug;
  69. FastGetProfileDwordW(NULL, PMAP_AEDEBUG, L"UserDebuggerHotkey", 0, &VkDebug, 0);
  70. if (VkDebug == 0) {
  71. if (ENHANCED_KEYBOARD(gKeyboardInfo.KeyboardIdentifier)) {
  72. VkDebug = VK_F12;
  73. } else {
  74. VkDebug = VK_SUBTRACT;
  75. }
  76. } else {
  77. UserAssert((0xFFFFFF00 & VkDebug) == 0);
  78. }
  79. _UnregisterHotKey(PWND_INPUTOWNER, IDHOT_DEBUG);
  80. _UnregisterHotKey(PWND_INPUTOWNER, IDHOT_DEBUGSERVER);
  81. _RegisterHotKey(PWND_INPUTOWNER, IDHOT_DEBUG, 0, VkDebug);
  82. _RegisterHotKey(PWND_INPUTOWNER, IDHOT_DEBUGSERVER, MOD_SHIFT, VkDebug);
  83. }
  84. /***************************************************************************\
  85. * DestroyThreadsHotKeys
  86. *
  87. * History:
  88. * 26-Feb-1991 mikeke Created.
  89. \***************************************************************************/
  90. VOID DestroyThreadsHotKeys(
  91. VOID)
  92. {
  93. PHOTKEY *pphk, phk;
  94. PTHREADINFO ptiCurrent = PtiCurrent();
  95. int i = 0;
  96. for (; i < ARRAY_SIZE(gphkHashTable); ++i) {
  97. pphk = &gphkHashTable[i];
  98. while (*pphk) {
  99. if ((*pphk)->pti == ptiCurrent) {
  100. phk = *pphk;
  101. *pphk = (*pphk)->phkNext;
  102. /*
  103. * Unlock the object stored here.
  104. */
  105. if (phk->spwnd != PWND_FOCUS && phk->spwnd != PWND_INPUTOWNER) {
  106. Unlock(&phk->spwnd);
  107. }
  108. UserFreePool(phk);
  109. } else {
  110. pphk = &((*pphk)->phkNext);
  111. }
  112. }
  113. }
  114. }
  115. /***************************************************************************\
  116. * DestroyWindowsHotKeys
  117. *
  118. * Frees hotkeys associated with the specified pwnd that were not explicitly
  119. * unregistered by the app.
  120. *
  121. * History:
  122. * 23-Sep-1992 IanJa Created.
  123. \***************************************************************************/
  124. VOID DestroyWindowsHotKeys(
  125. PWND pwnd)
  126. {
  127. PHOTKEY *pphk, phk;
  128. int i = 0;
  129. for (; i < ARRAY_SIZE(gphkHashTable); ++i) {
  130. pphk = &gphkHashTable[i];
  131. while (*pphk) {
  132. if ((*pphk)->spwnd == pwnd) {
  133. phk = *pphk;
  134. *pphk = (*pphk)->phkNext;
  135. Unlock(&phk->spwnd);
  136. UserFreePool(phk);
  137. } else {
  138. pphk = &((*pphk)->phkNext);
  139. }
  140. }
  141. }
  142. }
  143. /***************************************************************************\
  144. * _RegisterHotKey (API)
  145. *
  146. * This API registers the hotkey specified. If the specified key sequence has
  147. * already been registered we return FALSE. If the specified hwnd and id have
  148. * already been registered, fsModifiers and vk are reset for the HOTKEY.
  149. *
  150. * History:
  151. * 12-04-90 DavidPe Created.
  152. * 02-12-91 JimA Added access check
  153. \***************************************************************************/
  154. BOOL _RegisterHotKey(
  155. PWND pwnd,
  156. int id,
  157. UINT fsModifiers,
  158. UINT vk)
  159. {
  160. PHOTKEY phk;
  161. BOOL fKeysExist, bSAS;
  162. PTHREADINFO ptiCurrent;
  163. WORD wFlags;
  164. wFlags = fsModifiers & MOD_SAS;
  165. fsModifiers &= ~MOD_SAS;
  166. ptiCurrent = PtiCurrent();
  167. /*
  168. * Blow it off if the caller is not the windowstation init thread
  169. * and doesn't have the proper access rights
  170. */
  171. if (PsGetCurrentProcess() != gpepCSRSS) {
  172. if (grpWinStaList && !CheckWinstaWriteAttributesAccess()) {
  173. return FALSE;
  174. }
  175. }
  176. /*
  177. * If VK_PACKET is specified, just bail out, since VK_PACKET is
  178. * not a real keyboard input.
  179. */
  180. if (vk == VK_PACKET) {
  181. return FALSE;
  182. }
  183. /*
  184. * If this is the SAS check that winlogon is the one registering it.
  185. */
  186. if ((wFlags & MOD_SAS) != 0 && PsGetCurrentProcessId() == gpidLogon) {
  187. bSAS = TRUE;
  188. } else {
  189. bSAS = FALSE;
  190. }
  191. /*
  192. * Can't register hotkey for a window of another queue.
  193. */
  194. if (pwnd != PWND_FOCUS && pwnd != PWND_INPUTOWNER) {
  195. if (GETPTI(pwnd) != ptiCurrent) {
  196. RIPERR1(ERROR_WINDOW_OF_OTHER_THREAD,
  197. RIP_WARNING,
  198. "hwnd 0x%x belongs to a different thread",
  199. HWq(pwnd));
  200. return FALSE;
  201. }
  202. }
  203. phk = FindHotKey(ptiCurrent, pwnd, id, fsModifiers, vk, FALSE, &fKeysExist);
  204. /*
  205. * If the keys have already been registered, return FALSE.
  206. */
  207. if (fKeysExist) {
  208. RIPERR0(ERROR_HOTKEY_ALREADY_REGISTERED,
  209. RIP_WARNING,
  210. "Hotkey already exists");
  211. return FALSE;
  212. }
  213. if (phk == NULL) {
  214. /*
  215. * This hotkey doesn't exist yet.
  216. */
  217. phk = (PHOTKEY)UserAllocPool(sizeof(HOTKEY), TAG_HOTKEY);
  218. if (phk == NULL) {
  219. return FALSE;
  220. }
  221. phk->pti = ptiCurrent;
  222. if (pwnd != PWND_FOCUS && pwnd != PWND_INPUTOWNER) {
  223. phk->spwnd = NULL;
  224. Lock(&phk->spwnd, pwnd);
  225. } else {
  226. phk->spwnd = pwnd;
  227. }
  228. phk->fsModifiers = (WORD)fsModifiers;
  229. phk->wFlags = wFlags;
  230. phk->vk = vk;
  231. phk->id = id;
  232. /*
  233. * Add the new hotkey to our global hash.
  234. */
  235. HKInsertHashElement(phk);
  236. } else {
  237. /*
  238. * Hotkey already exists, reset the keys.
  239. */
  240. phk->fsModifiers = (WORD)fsModifiers;
  241. phk->wFlags = wFlags;
  242. phk->vk = vk;
  243. }
  244. if (bSAS) {
  245. /*
  246. * Store the SAS on the terminal.
  247. */
  248. gvkSAS = vk;
  249. gfsSASModifiers = fsModifiers;
  250. }
  251. return TRUE;
  252. }
  253. /***************************************************************************\
  254. * _UnregisterHotKey (API)
  255. *
  256. * This API will unregister the specified hwnd/id hotkey so that the
  257. * WM_HOTKEY message will not be generated for it.
  258. *
  259. * History:
  260. * 12-04-90 DavidPe Created.
  261. \***************************************************************************/
  262. BOOL _UnregisterHotKey(
  263. PWND pwnd,
  264. int id)
  265. {
  266. PHOTKEY phk;
  267. BOOL fKeysExist;
  268. PTHREADINFO ptiCurrent = PtiCurrent();
  269. phk = FindHotKey(ptiCurrent, pwnd, id, 0, 0, TRUE, &fKeysExist);
  270. if (phk == NULL) {
  271. RIPERR2(ERROR_HOTKEY_NOT_REGISTERED,
  272. (pwnd == PWND_INPUTOWNER) ? RIP_VERBOSE : RIP_WARNING,
  273. "Hotkey 0x%x on pwnd 0x%p does not exist",
  274. id,
  275. pwnd);
  276. return FALSE;
  277. }
  278. return TRUE;
  279. }
  280. /***************************************************************************\
  281. * FindHotKey
  282. *
  283. * Both RegisterHotKey() and UnregisterHotKey() call this function to search
  284. * for hotkeys that already exist. If a HOTKEY is found that matches
  285. * fsModifiers and vk, *pfKeysExist is set to TRUE. If a HOTKEY is found that
  286. * matches pwnd and id, a pointer to it is returned.
  287. *
  288. * If fUnregister is TRUE, we remove the HOTKEY from the list if we find
  289. * one that matches pwnd and id and return (PHOTKEY)1.
  290. *
  291. * History:
  292. * 12-04-90 DavidPe Created.
  293. \***************************************************************************/
  294. PHOTKEY FindHotKey(
  295. PTHREADINFO ptiCurrent,
  296. PWND pwnd,
  297. int id,
  298. UINT fsModifiers,
  299. UINT vk,
  300. BOOL fUnregister,
  301. PBOOL pfKeysExist)
  302. {
  303. PHOTKEY phk, phkRet, phkPrev;
  304. BYTE index = HKHashVK(vk);
  305. UserAssert(!fUnregister || vk == 0);
  306. /*
  307. * Initialize out 'return' values.
  308. */
  309. *pfKeysExist = FALSE;
  310. phkRet = NULL;
  311. phk = gphkHashTable[index];
  312. hashloop:
  313. while (phk) {
  314. /*
  315. * If all this matches up then we've found it.
  316. */
  317. if (phk->pti == ptiCurrent && phk->spwnd == pwnd && phk->id == id) {
  318. if (fUnregister) {
  319. /*
  320. * Unlink the HOTKEY from the list.
  321. */
  322. if (phk == gphkHashTable[index]) {
  323. gphkHashTable[index] = phk->phkNext;
  324. } else {
  325. phkPrev->phkNext = phk->phkNext;
  326. }
  327. if (pwnd != PWND_FOCUS && pwnd != PWND_INPUTOWNER) {
  328. Unlock(&phk->spwnd);
  329. }
  330. UserFreePool(phk);
  331. return (PHOTKEY)1;
  332. }
  333. phkRet = phk;
  334. }
  335. /*
  336. * If the key is already registered, set the exists flag so the app
  337. * knows it can't use this hotkey sequence.
  338. */
  339. if (phk->fsModifiers == (WORD)fsModifiers && phk->vk == vk) {
  340. /*
  341. * In the case of PWND_FOCUS, we need to check that the queues
  342. * are the same since PWND_FOCUS is local to the queue it was
  343. * registered under.
  344. */
  345. if (phk->spwnd == PWND_FOCUS) {
  346. if (phk->pti == ptiCurrent) {
  347. *pfKeysExist = TRUE;
  348. }
  349. } else {
  350. *pfKeysExist = TRUE;
  351. }
  352. }
  353. phkPrev = phk;
  354. phk = phk->phkNext;
  355. }
  356. /*
  357. * This is needed because when called from unregister we specify 0 as
  358. * the VK so the hash is always 0 and we need to index through the
  359. * entire hash table to try to find it.
  360. */
  361. if (fUnregister && ++index < ARRAY_SIZE(gphkHashTable)) {
  362. phk = gphkHashTable[index];
  363. goto hashloop;
  364. }
  365. return phkRet;
  366. }
  367. /***************************************************************************\
  368. * IsSAS
  369. *
  370. * Checks the physical state of keyboard modifiers that would effect SAS.
  371. \***************************************************************************/
  372. BOOL IsSAS(
  373. BYTE vk,
  374. UINT *pfsModifiers)
  375. {
  376. CheckCritIn();
  377. if (gvkSAS != vk) {
  378. return FALSE;
  379. }
  380. /*
  381. * Special case for SAS - examine real physical modifier-key state!
  382. *
  383. * An evil daemon process can fool convincingly pretend to be winlogon
  384. * by registering Alt+Del as a hotkey, and spinning another thread that
  385. * continually calls keybd_event() to send the Ctrl key up: when the
  386. * user types Ctrl+Alt+Del, only Alt+Del will be seen by the system,
  387. * the evil daemon will get woken by WM_HOTKEY and can pretend to be
  388. * winlogon. So look at gfsSASModifiersDown in this case, to see what keys
  389. * were physically pressed.
  390. * NOTE: If hotkeys are ever made to work under journal playback, make
  391. * sure they don't affect the gfsSASModifiersDown! - IanJa.
  392. */
  393. if (gfsSASModifiersDown == gfsSASModifiers) {
  394. *pfsModifiers = gfsSASModifiersDown;
  395. return TRUE;
  396. }
  397. return FALSE;
  398. }
  399. /*
  400. * The below two states are used by xxxDoHotKeyStuff().
  401. * Originally function-static variables, but as it's required
  402. * to clear those flags after the system wakes up from hybernation,
  403. * they are made global,
  404. */
  405. UINT gfsModifiers;
  406. UINT gfsModOnlyCandidate;
  407. VOID ClearCachedHotkeyModifiers(
  408. VOID)
  409. {
  410. /*
  411. * Clear the cached modifiers.
  412. */
  413. gfsModifiers = 0;
  414. gfsModOnlyCandidate = 0;
  415. /*
  416. * Clear the special modifier cache for the Ctrl+Alt+Del recognition.
  417. * (See comments in IsSAS()).
  418. */
  419. gfsSASModifiersDown = 0;
  420. }
  421. /***************************************************************************\
  422. * xxxDoHotKeyStuff
  423. *
  424. * This function gets called for every key event from low-level input
  425. * processing. It keeps track of the current state of modifier keys
  426. * and when gfsModifiers and vk match up with one of the registered
  427. * hotkeys, a WM_HOTKEY message is generated. DoHotKeyStuff() will
  428. * tell the input system to eat both the make and break for the 'vk'
  429. * event. This prevents apps from getting input that wasn't really
  430. * intended for them. DoHotKeyStuff() returns TRUE if it wants to 'eat'
  431. * the event, FALSE if the system can pass on the event like it normally
  432. * would.
  433. *
  434. * A Note on Modifier-Only Hotkeys
  435. * Some hotkeys involve VK_SHIFT, VK_CONTROL, VK_MENU and/or VK_WINDOWS only.
  436. * These are called Modifier-Only hotkeys.
  437. * In order to distinguish hotkeys such as Alt-Shift-S and and Alt-Shift alone,
  438. * modifier-only hotkeys must operate on a break, not a make.
  439. * In order to prevent Alt-Shift-S from activating the Alt-Shift hotkey when
  440. * the keys are released, modifier-only hotkeys are only activated when a
  441. * modifier keyup (break) was immediately preceded by a modifier keydown (break)
  442. * This also lets Alt-Shift,Shift,Shift activate the Alt-Shift hotkey 3 times.
  443. *
  444. * History:
  445. * 12-05-90 DavidPe Created.
  446. * 4-15-93 Sanfords Added code to return TRUE for Ctrl-Alt-Del events.
  447. \***************************************************************************/
  448. BOOL xxxDoHotKeyStuff(
  449. UINT vk,
  450. BOOL fBreak,
  451. DWORD fsReserveKeys)
  452. {
  453. UINT fsModOnlyHotkey;
  454. UINT fs;
  455. PHOTKEY phk;
  456. BOOL fCancel;
  457. BOOL fEatDebugKeyBreak;
  458. PWND pwnd;
  459. BOOL bSAS;
  460. CheckCritIn();
  461. UserAssert(IsWinEventNotifyDeferredOK());
  462. if (gfInNumpadHexInput & NUMPAD_HEXMODE_LL) {
  463. RIPMSGF0(RIP_VERBOSE,
  464. "Since we're in gfInNumpadHexInput, just bail out.");
  465. return FALSE;
  466. }
  467. /*
  468. * Update gfsModifiers.
  469. */
  470. fs = 0;
  471. fsModOnlyHotkey = 0;
  472. switch (vk) {
  473. case VK_SHIFT:
  474. fs = MOD_SHIFT;
  475. break;
  476. case VK_CONTROL:
  477. fs = MOD_CONTROL;
  478. break;
  479. case VK_MENU:
  480. fs = MOD_ALT;
  481. break;
  482. case VK_LWIN:
  483. case VK_RWIN:
  484. fs = MOD_WIN;
  485. break;
  486. default:
  487. /*
  488. * A non-modifier key rules out Modifier-Only hotkeys
  489. */
  490. gfsModOnlyCandidate = 0;
  491. break;
  492. }
  493. if (fBreak) {
  494. gfsModifiers &= ~fs;
  495. /*
  496. * If a modifier key is coming up, the current modifier only hotkey
  497. * candidate must be tested to see if it is a hotkey. Store this
  498. * in fsModOnlyHotkey, and prevent the next key release from
  499. * being a candidate by clearing fsModOnlyCandidate.
  500. */
  501. if (fs != 0) {
  502. fsModOnlyHotkey = gfsModOnlyCandidate;
  503. gfsModOnlyCandidate = 0;
  504. }
  505. } else {
  506. gfsModifiers |= fs;
  507. /*
  508. * If a modifier key is going down, we have a modifier-only hotkey
  509. * candidate. Save current modifier state until the following break.
  510. */
  511. if (fs != 0) {
  512. gfsModOnlyCandidate = gfsModifiers;
  513. }
  514. }
  515. /*
  516. * We look at the physical state for the modifiers because they cannot be
  517. * manipulated and this prevents someone from writing a trojan winlogon
  518. * look alike (see comment in AreModifiersIndicatingSAS).
  519. */
  520. bSAS = IsSAS((BYTE)vk, &gfsModifiers);
  521. /*
  522. * If the key is not a hotkey then we're done but first check if the
  523. * key is an Alt-Escape if so we need to cancel journalling.
  524. *
  525. * NOTE: Support for Alt+Esc to cancel journalling dropped in NT 4.0
  526. */
  527. if (fsModOnlyHotkey && fBreak) {
  528. /*
  529. * A hotkey involving only VK_SHIFT, VK_CONTROL, VK_MENU or VK_WINDOWS
  530. * must only operate on a key release.
  531. */
  532. if ((phk = IsHotKey(fsModOnlyHotkey, VK_NONE)) == NULL) {
  533. return FALSE;
  534. }
  535. } else if ((phk = IsHotKey(gfsModifiers, vk)) == NULL) {
  536. return FALSE;
  537. }
  538. /*
  539. * If we tripped a SAS hotkey, but it's not really the SAS, don't do it.
  540. */
  541. if ((phk->wFlags & MOD_SAS) && !bSAS) {
  542. return FALSE;
  543. }
  544. #ifdef GENERIC_INPUT
  545. if (gpqForeground && TestRawInputMode(PtiKbdFromQ(gpqForeground), NoHotKeys) &&
  546. (phk->wFlags & MOD_SAS) == 0) {
  547. /*
  548. * NOTE:
  549. * If the foreground thread does not want the hotkey handling,
  550. * just bail out.
  551. *
  552. * Exception: Ctrl+Alt+Del should be strictly handled by the system.
  553. */
  554. return FALSE;
  555. }
  556. #endif
  557. if (phk->id == IDHOT_WINDOWS) {
  558. pwnd = GETDESKINFO(PtiCurrent())->spwndShell;
  559. if (pwnd != NULL) {
  560. gfsModOnlyCandidate = 0; /* Make it return TRUE */
  561. goto PostTaskListSysCmd;
  562. }
  563. }
  564. if (phk->id == IDHOT_DEBUG || phk->id == IDHOT_DEBUGSERVER) {
  565. if (!fBreak) {
  566. /*
  567. * The DEBUG key has been pressed. Break the appropriate thread
  568. * into the debugger. We won't need phk after this callback
  569. * because we return immediately.
  570. */
  571. fEatDebugKeyBreak = xxxActivateDebugger(phk->fsModifiers);
  572. } else {
  573. fEatDebugKeyBreak = FALSE;
  574. }
  575. /*
  576. * This'll eat the debug key down and break if we broke into the
  577. * debugger on the server only on the down.
  578. */
  579. return fEatDebugKeyBreak;
  580. }
  581. /*
  582. * Don't allow hotkeys (except for ones owned by the logon process) if
  583. * the window station is locked.
  584. */
  585. if (((grpdeskRitInput->rpwinstaParent->dwWSF_Flags & WSF_SWITCHLOCK) != 0) &&
  586. (PsGetThreadProcessId(phk->pti->pEThread) != gpidLogon)) {
  587. RIPMSG0(RIP_WARNING, "Ignoring hotkey because Workstation locked");
  588. return FALSE;
  589. }
  590. if (fsModOnlyHotkey == 0 && fBreak) {
  591. /*
  592. * Do Modifier-Only hotkeys on break events, else return here.
  593. */
  594. return FALSE;
  595. }
  596. /*
  597. * Unhook hooks if a control-escape, alt-escape, or control-alt-del
  598. * comes through, so the user can cancel if the system seems hung.
  599. *
  600. * Note the hook may be locked so even if the unhook succeeds it
  601. * won't remove the hook from the global asphkStart array. So
  602. * we have to walk the list manually. This code works because
  603. * we are in the critical section and we know other hooks won't
  604. * be deleted.
  605. *
  606. * Once we've unhooked, post a WM_CANCELJOURNAL message to the app
  607. * that set the hook so it knows we did this.
  608. *
  609. * NOTE: Support for Alt+Esc to cancel journalling dropped in NT 4.0
  610. */
  611. fCancel = FALSE;
  612. if (vk == VK_ESCAPE && (gfsModifiers == MOD_CONTROL)) {
  613. fCancel = TRUE;
  614. }
  615. if (bSAS) {
  616. fCancel = TRUE;
  617. }
  618. if (fCancel) {
  619. zzzCancelJournalling(); // BUG BUG phk might go away IANJA
  620. }
  621. /*
  622. * See if the key is reserved by a console window. If it is,
  623. * return FALSE so the key will be passed to the console.
  624. */
  625. if (fsReserveKeys != 0) {
  626. switch (vk) {
  627. case VK_TAB:
  628. if ((fsReserveKeys & CONSOLE_ALTTAB) &&
  629. ((gfsModifiers & (MOD_CONTROL | MOD_ALT)) == MOD_ALT)) {
  630. return FALSE;
  631. }
  632. break;
  633. case VK_ESCAPE:
  634. if ((fsReserveKeys & CONSOLE_ALTESC) &&
  635. ((gfsModifiers & (MOD_CONTROL | MOD_ALT)) == MOD_ALT)) {
  636. return FALSE;
  637. }
  638. if ((fsReserveKeys & CONSOLE_CTRLESC) &&
  639. ((gfsModifiers & (MOD_CONTROL | MOD_ALT)) == MOD_CONTROL)) {
  640. return FALSE;
  641. }
  642. break;
  643. case VK_RETURN:
  644. if ((fsReserveKeys & CONSOLE_ALTENTER) &&
  645. ((gfsModifiers & (MOD_CONTROL | MOD_ALT)) == MOD_ALT)) {
  646. return FALSE;
  647. }
  648. break;
  649. case VK_SNAPSHOT:
  650. if ((fsReserveKeys & CONSOLE_PRTSC) &&
  651. ((gfsModifiers & (MOD_CONTROL | MOD_ALT)) == 0)) {
  652. return FALSE;
  653. }
  654. if ((fsReserveKeys & CONSOLE_ALTPRTSC) &&
  655. ((gfsModifiers & (MOD_CONTROL | MOD_ALT)) == MOD_ALT)) {
  656. return FALSE;
  657. }
  658. break;
  659. case VK_SPACE:
  660. if ((fsReserveKeys & CONSOLE_ALTSPACE) &&
  661. ((gfsModifiers & (MOD_CONTROL | MOD_ALT)) == MOD_ALT)) {
  662. return FALSE;
  663. }
  664. break;
  665. }
  666. }
  667. /*
  668. * If this is the task-list hotkey, go ahead and set foreground
  669. * status to the task-list queue right now. This prevents problems
  670. * where the user hits ctrl-esc and types-ahead before the task-list
  671. * processes the hotkey and brings up the task-list window.
  672. */
  673. if ((gfsModifiers == MOD_CONTROL) && (vk == VK_ESCAPE) && !fBreak) {
  674. PWND pwndSwitch;
  675. TL tlpwndSwitch;
  676. if (ghwndSwitch != NULL) {
  677. pwndSwitch = PW(ghwndSwitch);
  678. ThreadLock(pwndSwitch, &tlpwndSwitch);
  679. xxxSetForegroundWindow2(pwndSwitch, NULL, 0); // BUG BUG phk might go away IANJA
  680. ThreadUnlock(&tlpwndSwitch);
  681. }
  682. }
  683. /*
  684. * Get the hot key contents.
  685. */
  686. if (phk->spwnd == NULL) {
  687. _PostThreadMessage(phk->pti,
  688. WM_HOTKEY,
  689. phk->id,
  690. MAKELONG(gfsModifiers, vk));
  691. /*
  692. * Since this hotkey is for this guy, he owns the last input.
  693. */
  694. glinp.ptiLastWoken = phk->pti;
  695. } else {
  696. if (phk->spwnd == PWND_INPUTOWNER) {
  697. if (gpqForeground != NULL) {
  698. pwnd = gpqForeground->spwndFocus;
  699. } else {
  700. return FALSE;
  701. }
  702. } else {
  703. pwnd = phk->spwnd;
  704. }
  705. if (pwnd) {
  706. if (pwnd == pwnd->head.rpdesk->pDeskInfo->spwndShell && phk->id == SC_TASKLIST) {
  707. PostTaskListSysCmd:
  708. _PostMessage(pwnd, WM_SYSCOMMAND, SC_TASKLIST, 0);
  709. } else {
  710. _PostMessage(pwnd, WM_HOTKEY, phk->id, MAKELONG(gfsModifiers, vk));
  711. }
  712. /*
  713. * Since this hotkey is for this guy, he owns the last input.
  714. */
  715. glinp.ptiLastWoken = GETPTI(pwnd);
  716. }
  717. }
  718. /*
  719. * If this is a Modifier-Only hotkey, let the modifier break through
  720. * by returning FALSE, otherwise we will have modifier keys stuck down.
  721. */
  722. return (fsModOnlyHotkey == 0);
  723. }
  724. /***************************************************************************\
  725. * IsHotKey
  726. *
  727. *
  728. * History:
  729. * 03-10-91 DavidPe Created.
  730. \***************************************************************************/
  731. PHOTKEY IsHotKey(
  732. UINT fsModifiers,
  733. UINT vk)
  734. {
  735. PHOTKEY phk;
  736. CheckCritIn();
  737. phk = HKGetHashHead(vk);
  738. while (phk != NULL) {
  739. /*
  740. * Do the modifiers and vk for this hotkey match the current state?
  741. */
  742. if (phk->fsModifiers == fsModifiers && phk->vk == vk) {
  743. return phk;
  744. }
  745. phk = phk->phkNext;
  746. }
  747. return phk;
  748. }