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

/**************************** 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;
}