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.

474 lines
13 KiB

  1. /**************************** Module Header ********************************\
  2. * Module Name: mnaccel.c
  3. *
  4. * Copyright (c) 1985 - 1999, Microsoft Corporation
  5. *
  6. * Keyboard Accelerator Routines
  7. *
  8. * History:
  9. * 10-10-90 JimA Cleanup.
  10. * 03-18-91 IanJa Window revalidation added
  11. \***************************************************************************/
  12. #include "precomp.h"
  13. #pragma hdrstop
  14. /***************************************************************************\
  15. *
  16. *
  17. * History:
  18. \***************************************************************************/
  19. int ItemContainingSubMenu(
  20. PMENU pmainMenu,
  21. ULONG_PTR wID)
  22. {
  23. int i;
  24. PITEM pItem;
  25. if ((i = pmainMenu->cItems - 1) == -1)
  26. return -1;
  27. pItem = &pmainMenu->rgItems[i];
  28. /*
  29. * Scan through mainMenu's items (bottom up) until an item is found
  30. * that either has subMenu or an ancestor of subMenu as it's drop
  31. * down menu
  32. */
  33. /*
  34. * Make sure this works for new apps that set IDs for popup items that
  35. * aren't the same as the HMENU_16 value of the submenu. Accelerators
  36. * for disabled items will get generated otherwise, like in Exchange.
  37. */
  38. while (i >= 0)
  39. {
  40. if (pItem->spSubMenu == NULL)
  41. {
  42. //
  43. // Does this command match?
  44. //
  45. if (pItem->wID == wID)
  46. break;
  47. }
  48. else
  49. {
  50. //
  51. // Does this popup match?
  52. //
  53. if (pItem->spSubMenu == (PMENU)wID)
  54. break;
  55. //
  56. // Go recurse through this popup and see if we have a match on
  57. // one of our children.
  58. //
  59. if (ItemContainingSubMenu(pItem->spSubMenu, wID) != -1)
  60. break;
  61. }
  62. i--;
  63. pItem--;
  64. }
  65. return i;
  66. }
  67. /***************************************************************************\
  68. * UT_FindTopLevelMenuIndex
  69. *
  70. * !
  71. *
  72. * History:
  73. \***************************************************************************/
  74. int UT_FindTopLevelMenuIndex(
  75. PMENU pMenu,
  76. UINT cmd)
  77. {
  78. PMENU pMenuItemIsOn;
  79. PITEM pItem;
  80. /*
  81. * Get a pointer to the item we are searching for.
  82. */
  83. pItem = MNLookUpItem(pMenu, cmd, FALSE, &pMenuItemIsOn);
  84. if ((pItem == NULL) || (pItem->spSubMenu != NULL))
  85. return(-1);
  86. /*
  87. * We want to search for the item that contains pMenuItemIsOn,
  88. * unless this is a top-level item without a dropdown, in which
  89. * case we want to search for cmd.
  90. */
  91. return ItemContainingSubMenu(pMenu,
  92. pMenuItemIsOn != pMenu ? (ULONG_PTR)pMenuItemIsOn : cmd);
  93. }
  94. /***************************************************************************\
  95. * xxxHiliteMenuItem
  96. *
  97. * !
  98. *
  99. * History:
  100. \***************************************************************************/
  101. BOOL xxxHiliteMenuItem(
  102. PWND pwnd,
  103. PMENU pMenu,
  104. UINT cmd,
  105. UINT flags)
  106. {
  107. if (!(flags & MF_BYPOSITION))
  108. cmd = (UINT)UT_FindTopLevelMenuIndex(pMenu, cmd);
  109. if (!TestMF(pMenu, MFISPOPUP))
  110. xxxMNRecomputeBarIfNeeded(pwnd, pMenu);
  111. xxxMNInvertItem(NULL, pMenu, cmd, pwnd, (flags & MF_HILITE));
  112. return TRUE;
  113. }
  114. /***************************************************************************\
  115. * xxxTA_AccelerateMenu
  116. *
  117. * !
  118. *
  119. * History:
  120. \***************************************************************************/
  121. #define TA_DISABLED 1
  122. UINT xxxTA_AccelerateMenu(
  123. PWND pwnd,
  124. PMENU pMenu,
  125. UINT cmd,
  126. HMENU *phmenuInit)
  127. {
  128. int i;
  129. PITEM pItem;
  130. BOOL fDisabledTop;
  131. BOOL fDisabled;
  132. UINT rgfItem;
  133. PMENU pMenuItemIsOn;
  134. CheckLock(pwnd);
  135. CheckLock(pMenu);
  136. rgfItem = 0;
  137. if (pMenu != NULL) {
  138. if ((i = UT_FindTopLevelMenuIndex(pMenu, cmd)) != -1) {
  139. /*
  140. * 2 means we found an item
  141. */
  142. rgfItem = 2;
  143. xxxSendMessage(pwnd, WM_INITMENU, (WPARAM)PtoHq(pMenu), 0L);
  144. if ((UINT)i >= pMenu->cItems)
  145. return 0;
  146. pItem = &pMenu->rgItems[i];
  147. if (pItem->spSubMenu != NULL) {
  148. *phmenuInit = PtoHq(pItem->spSubMenu);
  149. xxxSendMessage(pwnd, WM_INITMENUPOPUP, (WPARAM)*phmenuInit,
  150. (DWORD)i);
  151. if ((UINT)i >= pMenu->cItems)
  152. return 0;
  153. fDisabledTop = TestMFS(pItem,MFS_GRAYED);
  154. } else {
  155. fDisabledTop = FALSE;
  156. }
  157. pItem = MNLookUpItem(pMenu, cmd, FALSE, &pMenuItemIsOn);
  158. /*
  159. * If the item was removed by the app in response to either of
  160. * the above messages, pItem will be NULL.
  161. */
  162. if (pItem == NULL) {
  163. rgfItem = 0;
  164. } else {
  165. fDisabled = TestMFS(pItem,MFS_GRAYED);
  166. /*
  167. * This 1 bit means it's disabled or it's 'parent' is disabled.
  168. */
  169. if (fDisabled || fDisabledTop)
  170. rgfItem |= TA_DISABLED;
  171. }
  172. }
  173. }
  174. return rgfItem;
  175. }
  176. /***************************************************************************\
  177. * _CreateAcceleratorTable
  178. *
  179. * History:
  180. * 05-01-91 ScottLu Changed to work client/server
  181. * 02-26-91 mikeke Created.
  182. \***************************************************************************/
  183. HANDLE APIENTRY _CreateAcceleratorTable(
  184. LPACCEL ccxpaccel,
  185. int cbAccel)
  186. {
  187. LPACCELTABLE pat;
  188. int size;
  189. size = cbAccel + sizeof(ACCELTABLE) - sizeof(ACCEL);
  190. pat = (LPACCELTABLE)HMAllocObject(PtiCurrent(), NULL, TYPE_ACCELTABLE, size);
  191. if (pat == NULL)
  192. return NULL;
  193. try {
  194. RtlCopyMemory(pat->accel, ccxpaccel, cbAccel);
  195. } except (W32ExceptionHandler(FALSE, RIP_WARNING)) {
  196. HMFreeObject(pat);
  197. return NULL;
  198. }
  199. pat->cAccel = cbAccel / sizeof(ACCEL);
  200. pat->accel[pat->cAccel - 1].fVirt |= FLASTKEY;
  201. return pat;
  202. }
  203. /***************************************************************************\
  204. * xxxTranslateAccelerator
  205. *
  206. * !
  207. *
  208. * History:
  209. \***************************************************************************/
  210. int xxxTranslateAccelerator(
  211. PWND pwnd,
  212. LPACCELTABLE pat,
  213. LPMSG lpMsg)
  214. {
  215. UINT cmd;
  216. BOOL fVirt;
  217. PMENU pMenu;
  218. BOOL fFound;
  219. UINT flags;
  220. UINT keystate;
  221. UINT message;
  222. UINT rgfItem;
  223. BOOL fDisabled;
  224. BOOL fSystemMenu;
  225. LPACCEL paccel;
  226. TL tlpMenu;
  227. int vkAlt, vkCtrl;
  228. HMENU hmenuInit = NULL;
  229. CheckLock(pwnd);
  230. CheckLock(pat);
  231. if (gfInNumpadHexInput & NUMPAD_HEXMODE_HL) {
  232. return FALSE;
  233. }
  234. paccel = pat->accel;
  235. fFound = FALSE;
  236. message = SystoChar(lpMsg->message, lpMsg->lParam);
  237. switch (message) {
  238. case WM_KEYDOWN:
  239. case WM_SYSKEYDOWN:
  240. fVirt = TRUE;
  241. break;
  242. case WM_CHAR:
  243. case WM_SYSCHAR:
  244. fVirt = FALSE;
  245. break;
  246. default:
  247. return FALSE;
  248. }
  249. /*
  250. * Many kbd layouts use the r.h. Alt key like a shift key to generate some
  251. * additional chars: this r.h. Alt (or "AltGr") key synthesizes a left Ctrl
  252. * (for backward compatibility with 84-key kbds), so when the AltGr key is
  253. * down neither the left Ctrl nor the right Alt should be counted as part
  254. * of the keystate.
  255. * Note: Don't expect spklActive == NULL (winlogon should have loaded kbd
  256. * layouts already), but test it anyway to be robust. #99321)
  257. */
  258. keystate = 0;
  259. UserAssert(PtiCurrent()->spklActive != NULL); // #99321
  260. if (PtiCurrent()->spklActive &&
  261. (PtiCurrent()->spklActive->spkf->pKbdTbl->fLocaleFlags & KLLF_ALTGR) &&
  262. (_GetKeyState(VK_RMENU) & 0x8000)) {
  263. /*
  264. * count only right hand Ctrl as a Ctrl keystate
  265. * count only left hand Alt as a Alt keystate
  266. */
  267. vkCtrl = VK_RCONTROL;
  268. vkAlt = VK_LMENU;
  269. } else {
  270. /*
  271. * count left or right hand Ctrl as a Ctrl keystate
  272. * count left or right hand Alt as a Alt keystate
  273. */
  274. vkAlt = VK_MENU;
  275. vkCtrl = VK_CONTROL;
  276. }
  277. if (_GetKeyState(vkCtrl) & 0x8000) {
  278. keystate |= FCONTROL;
  279. }
  280. if (_GetKeyState(vkAlt) & 0x8000) {
  281. keystate |= FALT;
  282. }
  283. if (_GetKeyState(VK_SHIFT) & 0x8000) {
  284. keystate |= FSHIFT;
  285. }
  286. do
  287. {
  288. flags = paccel->fVirt;
  289. if ( (DWORD)paccel->key != lpMsg->wParam ||
  290. ((fVirt != 0) != ((flags & FVIRTKEY) != 0))) {
  291. goto Next;
  292. }
  293. if (fVirt && ((keystate & (FSHIFT | FCONTROL)) != (flags & (FSHIFT | FCONTROL)))) {
  294. goto Next;
  295. }
  296. if ((keystate & FALT) != (flags & FALT)) {
  297. goto Next;
  298. }
  299. fFound = TRUE;
  300. fSystemMenu = 0;
  301. rgfItem = 0;
  302. cmd = paccel->cmd;
  303. if (cmd != 0) {
  304. /*
  305. * The order of these next two if's is important for default
  306. * situations. Also, just check accelerators in the system
  307. * menu of child windows passed to TranslateAccelerator.
  308. */
  309. pMenu = pwnd->spmenu;
  310. rgfItem = 0;
  311. if (!TestWF(pwnd, WFCHILD)) {
  312. ThreadLock(pMenu, &tlpMenu);
  313. rgfItem = xxxTA_AccelerateMenu(pwnd, pMenu, cmd, &hmenuInit);
  314. ThreadUnlock(&tlpMenu);
  315. }
  316. if (TestWF(pwnd, WFCHILD) || rgfItem == 0) {
  317. UserAssert(hmenuInit == NULL);
  318. pMenu = pwnd->spmenuSys;
  319. if (pMenu == NULL && TestWF(pwnd, WFSYSMENU)) {
  320. /*
  321. * Change owner so this app can access this menu.
  322. */
  323. pMenu = pwnd->head.rpdesk->spmenuSys;
  324. if (pMenu == NULL) {
  325. #ifdef LAME_BUTTON
  326. pMenu = xxxLoadSysDesktopMenu (&pwnd->head.rpdesk->spmenuSys, ID_SYSMENU, pwnd);
  327. #else
  328. pMenu = xxxLoadSysDesktopMenu (&pwnd->head.rpdesk->spmenuSys, ID_SYSMENU);
  329. #endif // LAME_BUTTON
  330. }
  331. ThreadLock(pMenu, &tlpMenu);
  332. /*
  333. * Must reset the system menu for this window.
  334. */
  335. xxxSetSysMenu(pwnd);
  336. } else {
  337. ThreadLock(pMenu, &tlpMenu);
  338. }
  339. if ((rgfItem = xxxTA_AccelerateMenu(pwnd, pMenu, cmd, &hmenuInit)) != 0) {
  340. fSystemMenu = TRUE;
  341. }
  342. ThreadUnlock(&tlpMenu);
  343. }
  344. }
  345. fDisabled = TestWF(pwnd, WFDISABLED);
  346. /*
  347. * Send only if: 1. The Item is not disabled, AND
  348. * 2. The Window's not being captured AND
  349. * 3. The Window's not minimzed, OR
  350. * 4. The Window's minimized but the Item is in
  351. * the System Menu.
  352. */
  353. if (!(rgfItem & TA_DISABLED) &&
  354. !(rgfItem && TestWF(pwnd, WFICONIC) && !fSystemMenu)) {
  355. if (!(rgfItem != 0 && (PtiCurrent()->pq->spwndCapture != NULL ||
  356. fDisabled))) {
  357. if (fSystemMenu) {
  358. xxxSendMessage(pwnd, WM_SYSCOMMAND, cmd, 0x00010000L);
  359. } else {
  360. xxxSendMessage(pwnd, WM_COMMAND, MAKELONG(cmd, 1), 0);
  361. }
  362. /*
  363. * Get outta here
  364. */
  365. flags = FLASTKEY;
  366. }
  367. }
  368. /*
  369. * Send matching WM_UNINITMENUPOPUP if needed
  370. */
  371. if (hmenuInit != NULL) {
  372. xxxSendMessage(pwnd, WM_UNINITMENUPOPUP, (WPARAM)hmenuInit, 0);
  373. hmenuInit = NULL;
  374. }
  375. Next:
  376. paccel++;
  377. } while (!(flags & FLASTKEY) && !fFound);
  378. return fFound;
  379. }
  380. /***************************************************************************\
  381. * SystoChar
  382. *
  383. * EXIT: If the message was not made with the ALT key down, convert
  384. * the message from a WM_SYSKEY* to a WM_KEY* message.
  385. *
  386. * IMPLEMENTATION:
  387. * The 0x2000 bit in the hi word of lParam is set if the key was
  388. * made with the ALT key down.
  389. *
  390. * History:
  391. * 11/30/90 JimA Ported.
  392. \***************************************************************************/
  393. UINT SystoChar(
  394. UINT message,
  395. LPARAM lParam)
  396. {
  397. if (CheckMsgFilter(message, WM_SYSKEYDOWN, WM_SYSDEADCHAR) &&
  398. !(HIWORD(lParam) & SYS_ALTERNATE))
  399. return (message - (WM_SYSKEYDOWN - WM_KEYDOWN));
  400. return message;
  401. }