|
|
/**************************** Module Header ********************************\
* Module Name: mnaccel.c * * Copyright (c) 1985 - 1999, Microsoft Corporation * * Keyboard Accelerator Routines * * History: * 10-10-90 JimA Cleanup. * 03-18-91 IanJa Window revalidation added \***************************************************************************/
#include "precomp.h"
#pragma hdrstop
/***************************************************************************\
* * * History: \***************************************************************************/
int ItemContainingSubMenu( PMENU pmainMenu, ULONG_PTR wID) { int i; PITEM pItem;
if ((i = pmainMenu->cItems - 1) == -1) return -1;
pItem = &pmainMenu->rgItems[i];
/*
* Scan through mainMenu's items (bottom up) until an item is found * that either has subMenu or an ancestor of subMenu as it's drop * down menu */
/*
* Make sure this works for new apps that set IDs for popup items that * aren't the same as the HMENU_16 value of the submenu. Accelerators * for disabled items will get generated otherwise, like in Exchange. */ while (i >= 0) { if (pItem->spSubMenu == NULL) { //
// Does this command match?
//
if (pItem->wID == wID) break; } else { //
// Does this popup match?
//
if (pItem->spSubMenu == (PMENU)wID) break;
//
// Go recurse through this popup and see if we have a match on
// one of our children.
//
if (ItemContainingSubMenu(pItem->spSubMenu, wID) != -1) break; }
i--; pItem--; }
return i; }
/***************************************************************************\
* UT_FindTopLevelMenuIndex * * ! * * History: \***************************************************************************/
int UT_FindTopLevelMenuIndex( PMENU pMenu, UINT cmd) { PMENU pMenuItemIsOn; PITEM pItem;
/*
* Get a pointer to the item we are searching for. */ pItem = MNLookUpItem(pMenu, cmd, FALSE, &pMenuItemIsOn); if ((pItem == NULL) || (pItem->spSubMenu != NULL)) return(-1);
/*
* We want to search for the item that contains pMenuItemIsOn, * unless this is a top-level item without a dropdown, in which * case we want to search for cmd. */ return ItemContainingSubMenu(pMenu, pMenuItemIsOn != pMenu ? (ULONG_PTR)pMenuItemIsOn : cmd); }
/***************************************************************************\
* xxxHiliteMenuItem * * ! * * History: \***************************************************************************/
BOOL xxxHiliteMenuItem( PWND pwnd, PMENU pMenu, UINT cmd, UINT flags) {
if (!(flags & MF_BYPOSITION)) cmd = (UINT)UT_FindTopLevelMenuIndex(pMenu, cmd);
if (!TestMF(pMenu, MFISPOPUP)) xxxMNRecomputeBarIfNeeded(pwnd, pMenu);
xxxMNInvertItem(NULL, pMenu, cmd, pwnd, (flags & MF_HILITE));
return TRUE; }
/***************************************************************************\
* xxxTA_AccelerateMenu * * ! * * History: \***************************************************************************/
#define TA_DISABLED 1
UINT xxxTA_AccelerateMenu( PWND pwnd, PMENU pMenu, UINT cmd, HMENU *phmenuInit) { int i; PITEM pItem; BOOL fDisabledTop; BOOL fDisabled; UINT rgfItem; PMENU pMenuItemIsOn;
CheckLock(pwnd); CheckLock(pMenu);
rgfItem = 0; if (pMenu != NULL) { if ((i = UT_FindTopLevelMenuIndex(pMenu, cmd)) != -1) {
/*
* 2 means we found an item */ rgfItem = 2;
xxxSendMessage(pwnd, WM_INITMENU, (WPARAM)PtoHq(pMenu), 0L); if ((UINT)i >= pMenu->cItems) return 0;
pItem = &pMenu->rgItems[i]; if (pItem->spSubMenu != NULL) { *phmenuInit = PtoHq(pItem->spSubMenu); xxxSendMessage(pwnd, WM_INITMENUPOPUP, (WPARAM)*phmenuInit, (DWORD)i); if ((UINT)i >= pMenu->cItems) return 0; fDisabledTop = TestMFS(pItem,MFS_GRAYED); } else { fDisabledTop = FALSE; }
pItem = MNLookUpItem(pMenu, cmd, FALSE, &pMenuItemIsOn);
/*
* If the item was removed by the app in response to either of * the above messages, pItem will be NULL. */ if (pItem == NULL) { rgfItem = 0; } else { fDisabled = TestMFS(pItem,MFS_GRAYED);
/*
* This 1 bit means it's disabled or it's 'parent' is disabled. */ if (fDisabled || fDisabledTop) rgfItem |= TA_DISABLED; } } }
return rgfItem; }
/***************************************************************************\
* _CreateAcceleratorTable * * History: * 05-01-91 ScottLu Changed to work client/server * 02-26-91 mikeke Created. \***************************************************************************/
HANDLE APIENTRY _CreateAcceleratorTable( LPACCEL ccxpaccel, int cbAccel) { LPACCELTABLE pat; int size;
size = cbAccel + sizeof(ACCELTABLE) - sizeof(ACCEL);
pat = (LPACCELTABLE)HMAllocObject(PtiCurrent(), NULL, TYPE_ACCELTABLE, size); if (pat == NULL) return NULL;
try { RtlCopyMemory(pat->accel, ccxpaccel, cbAccel); } except (W32ExceptionHandler(FALSE, RIP_WARNING)) { HMFreeObject(pat); return NULL; }
pat->cAccel = cbAccel / sizeof(ACCEL); pat->accel[pat->cAccel - 1].fVirt |= FLASTKEY;
return pat; }
/***************************************************************************\
* xxxTranslateAccelerator * * ! * * History: \***************************************************************************/
int xxxTranslateAccelerator( PWND pwnd, LPACCELTABLE pat, LPMSG lpMsg) { UINT cmd; BOOL fVirt; PMENU pMenu; BOOL fFound; UINT flags; UINT keystate; UINT message; UINT rgfItem; BOOL fDisabled; BOOL fSystemMenu; LPACCEL paccel; TL tlpMenu; int vkAlt, vkCtrl; HMENU hmenuInit = NULL;
CheckLock(pwnd); CheckLock(pat);
if (gfInNumpadHexInput & NUMPAD_HEXMODE_HL) { return FALSE; }
paccel = pat->accel;
fFound = FALSE;
message = SystoChar(lpMsg->message, lpMsg->lParam);
switch (message) { case WM_KEYDOWN: case WM_SYSKEYDOWN: fVirt = TRUE; break;
case WM_CHAR: case WM_SYSCHAR: fVirt = FALSE; break;
default: return FALSE; }
/*
* Many kbd layouts use the r.h. Alt key like a shift key to generate some * additional chars: this r.h. Alt (or "AltGr") key synthesizes a left Ctrl * (for backward compatibility with 84-key kbds), so when the AltGr key is * down neither the left Ctrl nor the right Alt should be counted as part * of the keystate. * Note: Don't expect spklActive == NULL (winlogon should have loaded kbd * layouts already), but test it anyway to be robust. #99321) */ keystate = 0; UserAssert(PtiCurrent()->spklActive != NULL); // #99321
if (PtiCurrent()->spklActive && (PtiCurrent()->spklActive->spkf->pKbdTbl->fLocaleFlags & KLLF_ALTGR) && (_GetKeyState(VK_RMENU) & 0x8000)) { /*
* count only right hand Ctrl as a Ctrl keystate * count only left hand Alt as a Alt keystate */ vkCtrl = VK_RCONTROL; vkAlt = VK_LMENU; } else { /*
* count left or right hand Ctrl as a Ctrl keystate * count left or right hand Alt as a Alt keystate */ vkAlt = VK_MENU; vkCtrl = VK_CONTROL; }
if (_GetKeyState(vkCtrl) & 0x8000) { keystate |= FCONTROL; } if (_GetKeyState(vkAlt) & 0x8000) { keystate |= FALT; } if (_GetKeyState(VK_SHIFT) & 0x8000) { keystate |= FSHIFT; }
do { flags = paccel->fVirt; if ( (DWORD)paccel->key != lpMsg->wParam || ((fVirt != 0) != ((flags & FVIRTKEY) != 0))) { goto Next; }
if (fVirt && ((keystate & (FSHIFT | FCONTROL)) != (flags & (FSHIFT | FCONTROL)))) { goto Next; }
if ((keystate & FALT) != (flags & FALT)) { goto Next; }
fFound = TRUE; fSystemMenu = 0; rgfItem = 0;
cmd = paccel->cmd; if (cmd != 0) {
/*
* The order of these next two if's is important for default * situations. Also, just check accelerators in the system * menu of child windows passed to TranslateAccelerator. */ pMenu = pwnd->spmenu; rgfItem = 0;
if (!TestWF(pwnd, WFCHILD)) { ThreadLock(pMenu, &tlpMenu); rgfItem = xxxTA_AccelerateMenu(pwnd, pMenu, cmd, &hmenuInit); ThreadUnlock(&tlpMenu); }
if (TestWF(pwnd, WFCHILD) || rgfItem == 0) { UserAssert(hmenuInit == NULL); pMenu = pwnd->spmenuSys; if (pMenu == NULL && TestWF(pwnd, WFSYSMENU)) {
/*
* Change owner so this app can access this menu. */ pMenu = pwnd->head.rpdesk->spmenuSys; if (pMenu == NULL) { #ifdef LAME_BUTTON
pMenu = xxxLoadSysDesktopMenu (&pwnd->head.rpdesk->spmenuSys, ID_SYSMENU, pwnd); #else
pMenu = xxxLoadSysDesktopMenu (&pwnd->head.rpdesk->spmenuSys, ID_SYSMENU); #endif // LAME_BUTTON
} ThreadLock(pMenu, &tlpMenu); /*
* Must reset the system menu for this window. */ xxxSetSysMenu(pwnd); } else { ThreadLock(pMenu, &tlpMenu); }
if ((rgfItem = xxxTA_AccelerateMenu(pwnd, pMenu, cmd, &hmenuInit)) != 0) { fSystemMenu = TRUE; } ThreadUnlock(&tlpMenu); } }
fDisabled = TestWF(pwnd, WFDISABLED);
/*
* Send only if: 1. The Item is not disabled, AND * 2. The Window's not being captured AND * 3. The Window's not minimzed, OR * 4. The Window's minimized but the Item is in * the System Menu. */ if (!(rgfItem & TA_DISABLED) && !(rgfItem && TestWF(pwnd, WFICONIC) && !fSystemMenu)) { if (!(rgfItem != 0 && (PtiCurrent()->pq->spwndCapture != NULL || fDisabled))) {
if (fSystemMenu) { xxxSendMessage(pwnd, WM_SYSCOMMAND, cmd, 0x00010000L); } else { xxxSendMessage(pwnd, WM_COMMAND, MAKELONG(cmd, 1), 0); }
/*
* Get outta here */ flags = FLASTKEY; } }
/*
* Send matching WM_UNINITMENUPOPUP if needed */ if (hmenuInit != NULL) { xxxSendMessage(pwnd, WM_UNINITMENUPOPUP, (WPARAM)hmenuInit, 0); hmenuInit = NULL; }
Next: paccel++;
} while (!(flags & FLASTKEY) && !fFound);
return fFound; }
/***************************************************************************\
* SystoChar * * EXIT: If the message was not made with the ALT key down, convert * the message from a WM_SYSKEY* to a WM_KEY* message. * * IMPLEMENTATION: * The 0x2000 bit in the hi word of lParam is set if the key was * made with the ALT key down. * * History: * 11/30/90 JimA Ported. \***************************************************************************/
UINT SystoChar( UINT message, LPARAM lParam) { if (CheckMsgFilter(message, WM_SYSKEYDOWN, WM_SYSDEADCHAR) && !(HIWORD(lParam) & SYS_ALTERNATE)) return (message - (WM_SYSKEYDOWN - WM_KEYDOWN));
return message; }
|