test: mnkey.c Source File

Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

# mnkey.c

Go to the documentation of this file.

    00001 /**************************** Module Header ********************************\
    00002 * Module Name: mnkey.c
    00003 *
    00004 * Copyright (c) 1985 - 1999, Microsoft Corporation
    00005 *
    00006 * Menu Keyboard Handling Routines
    00007 *
    00008 * History:
    00009 * 10-10-90 JimA       Cleanup.
    00010 * 03-18-91 IanJa      Window revalidation added
    00011 \***************************************************************************/
    00012
    00013 #include "precomp.h"
    00014 #pragma hdrstop
    00015
    00016 int xxxClientFindMnemChar(
    00017     PUNICODE_STRING pstrSrc,
    00018     WCHAR ch,
    00019     BOOL fFirst,
    00020     BOOL fPrefix);
    00021
    00022 /* MenuSwitch commands */
    00023 #define CMDSWITCH   1
    00024 #define CMDQUERY    2
    00025
    00026 /***************************************************************************\
    00027 * FindNextValidMenuItem
    00028 *
    00029 * !
    00030 *
    00031 * History:
    00032 \***************************************************************************/
    00033
    00034 UINT MNFindNextValidItem(
    00035     PMENU pMenu,
    00036     int i,
    00037     int dir,
    00038     UINT flags)
    00039 {
    00040     int iStart;
    00041     BOOL cont = TRUE;
    00042     int cItems = pMenu->cItems;
    00043     PITEM pItem;
    00044
    00045     if ((i < 0) && (dir > 0))
    00046         // going forward from beginning -- stop after last menu item
    00047         i = iStart = cItems;
    00048     else if ((i >= cItems) && (dir < 0))
    00049         // going backward from end -- stop after first menu item
    00050         i = iStart = -1;
    00051     else
    00052         iStart = i;
    00053
    00054     if (!cItems)
    00055         return(MFMWFP_NOITEM);
    00056
    00057     // b#8997 - if we have these conditions and enter
    00058     // loop will go blistic ( infin )
    00059     // fix: jump over code and come loop to i == iStart will now stop us
    00060     if ( ( i == 0 ) && ( cItems == 1 ) && ( dir > 0 ) )
    00061     {
    00062         dir = 0;
    00063         goto artsquickndirtybugfix;
    00064     }
    00065
    00066     //
    00067     // Loop thru menu items til (1) we find a valid item
    00068     //                       or (2) we make it back to the start item (iStart)
    00069     while (TRUE) {
    00070         i += dir;
    00071
    00072         if ((i == iStart) || (dir == 0))
    00073             // we made it back to start item -- return NOT FOUND
    00074             return MFMWFP_NOITEM;
    00075
    00076         // keep 'i' in the range: 0 <= i < cItems
    00077         if (i >= cItems) {
    00078             i = -1;
    00079             continue;
    00080         }
    00081         else if (i < 0) {
    00082             i = cItems;
    00083             continue;
    00084         }
    00085
    00086 artsquickndirtybugfix:
    00087         pItem = pMenu->rgItems + i;
    00088
    00089         // skip ownerdraw - seperators even though there not NULL
    00090         if (TestMFT(pItem, MFT_SEPARATOR)) {
    00091             //
    00092             // Skip non-separator (if asked) empty items.  With hot-tracking,
    00093             // it is acceptable for them to be selected.  In truth, it was possible
    00094             // in Win3.1 too, but less likely.
    00095             //
    00096             if (!(flags & MNF_DONTSKIPSEPARATORS)) {
    00097                 continue;
    00098             }
    00099         } else if ((pItem->hbmp >= HBMMENU_MBARFIRST) && (pItem->hbmp <= HBMMENU_MBARLAST)) {
    00100             /*
    00101              * Skip close & minimize & restore buttons
    00102              */
    00103             continue;
    00104         }
    00105
    00106         // return index of found item
    00107         return(i);
    00108     }
    00109
    00110     //
    00111     // We should never get here!
    00112     //
    00113     UserAssert(FALSE);
    00114 }
    00115
    00116 /***************************************************************************\
    00117 * MKF_FindMenuItemInColumn
    00118 *
    00119 * Finds closest item in the pull-down menu's next "column".
    00120 *
    00121 * History:
    00122 \***************************************************************************/
    00123
    00124 UINT MNFindItemInColumn(
    00125     PMENU pMenu,
    00126     UINT idxB,
    00127     int dir,
    00128     BOOL fRoot)
    00129 {
    00130     int dxMin;
    00131     int dyMin;
    00132     int dxMax;
    00133     int dyMax;
    00134     int xB;
    00135     int yB;
    00136     UINT idxE;
    00137     UINT idxR;
    00138     UINT cItems;
    00139     PITEM pItem;
    00140
    00141     cItems = pMenu->cItems;
    00142     idxR = MFMWFP_NOITEM;
    00143     idxE = MNFindNextValidItem(pMenu, MFMWFP_NOITEM, dir, 0);
    00144     if (idxE == -1)
    00145         goto End;
    00146
    00147     dxMin = dyMin = 20000;
    00148
    00149     if (idxB >= pMenu->cItems)
    00150         return idxR;
    00151
    00152     pItem = &pMenu->rgItems[idxB];
    00153     xB = pItem->xItem;
    00154     yB = pItem->yItem;
    00155
    00156     while (cItems-- > 0 &&
    00157             (idxB = MNFindNextValidItem(pMenu, idxB, dir, 0)) != idxE) {
    00158         pItem = &pMenu->rgItems[idxB];
    00159         dxMax = xB - pItem->xItem;
    00160         dyMax = yB - pItem->yItem;
    00161
    00162         if (dxMax < 0)
    00163             dxMax = (-dxMax);
    00164         if (dyMax < 0)
    00165             dyMax = (-dyMax);
    00166
    00167         // See if this item is nearer than the last item found
    00168         // --------------------------------------------------------
    00169         // (fRoot || dxMax) -- this condition means that if it's
    00170         // not the actual menu bar menu that we're dealing with,
    00171         // then the item below/above (same X value as) the selected
    00172         // item is not a valid one to move to
    00173         if ((dyMax < dyMin) && (fRoot || dxMax) && dxMax <= dxMin) {
    00174             dxMin = dxMax;
    00175             dyMin = dyMax;
    00176             idxR = idxB;
    00177         }
    00178     }
    00179
    00180 End:
    00181     return idxR;
    00182 }
    00183
    00184 /***************************************************************************\
    00185 * MKF_FindMenuChar
    00186 *
    00187 * Translates Virtual cursor key movements into pseudo-ascii values.  Maps a
    00188 * character to an item number.
    00189 *
    00190 * History:
    00191 \***************************************************************************/
    00192
    00193 UINT xxxMNFindChar(
    00194     PMENU pMenu,
    00195     UINT ch,
    00196     int idxC,
    00197     LPINT lpr)       /* Put match type here */
    00198 {
    00199     int idxFirst = MFMWFP_NOITEM;
    00200     int idxB;
    00201     int idxF;
    00202     int rT;
    00203     LPWSTR lpstr;
    00204     PITEM pItem;
    00205
    00206     if (ch == 0)
    00207         return 0;
    00208
    00209     /*
    00210      * First time thru go for the very first menu.
    00211      */
    00212     idxF = MFMWFP_NOITEM;
    00213     rT = 0;
    00214     idxB = idxC;
    00215
    00216     if (idxB < 0)
    00217 //    if (idxB & 0x8000)
    00218         idxB = MNFindNextValidItem(pMenu, pMenu->cItems, MFMWFP_NOITEM, MNF_DONTSKIPSEPARATORS);
    00219
    00220     do {
    00221         INT idxPrev;
    00222
    00223         idxPrev = idxC;
    00224         idxC = MNFindNextValidItem(pMenu, idxC, 1, MNF_DONTSKIPSEPARATORS);
    00225         if (idxC == MFMWFP_NOITEM || idxC == idxFirst)
    00226             break;
    00227         if (idxFirst == MFMWFP_NOITEM)
    00228             idxFirst = idxC;
    00229
    00230         pItem = &pMenu->rgItems[idxC];
    00231
    00232         if (pItem->lpstr != NULL) {
    00233             if (pItem->cch != 0) {
    00234                 UNICODE_STRING strMnem;
    00235
    00236                 lpstr = TextPointer(pItem->lpstr);
    00237                 if (*lpstr == CH_HELPPREFIX) {
    00238
    00239                     /*
    00240                      * Skip help prefix if it is there so that we can mnemonic
    00241                      * to the first character of a right justified string.
    00242                      */
    00243                     lpstr++;
    00244                 }
    00245
    00246                 RtlInitUnicodeString(&strMnem, lpstr);
    00247                 if (((rT = (UINT)xxxClientFindMnemChar(&strMnem,
    00248                         (WCHAR)ch, TRUE, TRUE)) == 0x0080) &&
    00249                         (idxF == MFMWFP_NOITEM))
    00250                     idxF = idxC;
    00251             }
    00252         }
    00253         if (idxC == idxPrev) {
    00254             break;  // no progress - break inf. loop
    00255         }
    00256     } while (rT != 1 && idxB != idxC);
    00257
    00258     *lpr = rT;
    00259
    00260     if (rT == 1)
    00261         return idxC;
    00262
    00263     return idxF;
    00264 }
    00265
    00266
    00267 /***************************************************************************\
    00268 * xxxMenuKeyFilter
    00269 *
    00270 * !
    00271 *
    00272 * Revalidation notes:
    00273 * o Routine assumes it is called with pMenuState->hwndMenu non-NULL and valid.
    00274 * o If one or more of the popup menu windows is unexpectedly destroyed, this is
    00275 *   detected in xxxMenuWndProc(), which sets pMenuState->fSabotaged and calls
    00276 *   xxxKillMenuState().  Therefore, if we return from an xxxRoutine with
    00277 *   pMenuState->fSabotaged set, we must abort immediately.
    00278 * o If pMenuState->hwndMenu is unexpectedly destroyed, we abort only if we
    00279 *   need to use the corresponding pwndMenu.
    00280 * o pMenuState->hwndMenu may be supplied as a parameter to various routines
    00281 *   (eg:  xxxNextItem), whether valid or not.
    00282 * o Any label preceded with xxx (eg: xxxMKF_UnlockAndExit) may be reached with
    00283 *   pMenuState->hwndMenu invalid.
    00284 * o If this routine is not called while in xxxMenuLoop(), then it must
    00285 *   clear pMenuState->fSabotaged before returning.
    00286 *
    00287 * History:
    00288 \***************************************************************************/
    00289
    00290 void xxxMNKeyFilter(
    00291     PPOPUPMENU ppopupMenu,
    00292     PMENUSTATE pMenuState,
    00293     UINT ch)
    00294 {
    00295     BOOL fLocalInsideMenuLoop = pMenuState->fInsideMenuLoop;
    00296
    00297     if (pMenuState->fButtonDown) {
    00298
    00299         /*
    00300          * Ignore keystrokes while the mouse is pressed (except ESC).
    00301          */
    00302         return;
    00303     }
    00304
    00305     if (!pMenuState->fInsideMenuLoop) {
    00306
    00307         /*
    00308          * Need to send the WM_INITMENU message before we pull down the menu.
    00309          */
    00310         if (!xxxMNStartMenu(ppopupMenu, KEYBDHOLD)) {
    00311             return;
    00312         }
    00313         pMenuState->fInsideMenuLoop = TRUE;
    00314     }
    00315
    00316
    00317     switch (ch) {
    00318     case 0:
    00319
    00320         /*
    00321          * If we get a WM_KEYDOWN alt key and then a KEYUP alt key, we need to
    00322          * activate the first item on the menu.  ie.  user hits and releases alt
    00323          * key so just select first item.  USER sends us a SC_KEYMENU with
    00324          * lParam 0 when the user does this.
    00325          */
    00326         xxxMNSelectItem(ppopupMenu, pMenuState, 0);
    00327         break;
    00328
    00329     case MENUCHILDSYSMENU:
    00330         if (!TestwndChild(ppopupMenu->spwndNotify)) {
    00331
    00332             /*
    00333              * Change made to fix MDI problem: child window gets a keymenu,
    00334              * and pops up sysmenu of frame when maximized.  Need to act like
    00335              * MENUCHAR if hwndMenu is a top-level.
    00336              */
    00337             goto MenuCharHandler;
    00338         }
    00339
    00340         /*
    00341          * else fall through.
    00342          */
    00343
    00344     case MENUSYSMENU:
    00345         if (!TestWF(ppopupMenu->spwndNotify, WFSYSMENU)) {
    00346             xxxMessageBeep(0);
    00347             goto MenuCancel;
    00348         }
    00349
    00350         /*
    00351          * Popup any hierarchies we have.
    00352          */
    00353         xxxMNCloseHierarchy(ppopupMenu, pMenuState);
    00354         if (!ppopupMenu->fIsSysMenu && ppopupMenu->spmenuAlternate)
    00355             xxxMNSwitchToAlternateMenu(ppopupMenu);
    00356         if (!ppopupMenu->fIsSysMenu) {
    00357             /*
    00358              * If no system menu, get out.
    00359              */
    00360             goto MenuCancel;
    00361         }
    00362
    00363         MNPositionSysMenu(ppopupMenu->spwndPopupMenu, ppopupMenu->spmenu);
    00364         xxxMNSelectItem(ppopupMenu, pMenuState, 0);
    00365         xxxMNOpenHierarchy(ppopupMenu, pMenuState);
    00366         ppopupMenu->fToggle = FALSE;
    00367         break;
    00368
    00369
    00370     default:
    00371
    00372         /*
    00373          * Handle ALT-Character sequences for items on top level menu bar.
    00374          * Note that fInsideMenuLoop may be set to false on return from this
    00375          * function if the app decides to return 1 to the WM_MENUCHAR message.
    00376          * We detect this and not enter MenuLoop if fInsideMenuLoop is reset
    00377          * to false.
    00378          */
    00379 MenuCharHandler:
    00380         xxxMNChar(ppopupMenu, pMenuState, ch);
    00381         if (ppopupMenu->posSelectedItem == MFMWFP_NOITEM) {
    00382             /*
    00383              * No selection found.
    00384              */
    00385             goto MenuCancel;
    00386         }
    00387         break;
    00388     }
    00389
    00390     if (!fLocalInsideMenuLoop && pMenuState->fInsideMenuLoop) {
    00391         xxxMNLoop(ppopupMenu, pMenuState, 0, FALSE);
    00392     }
    00393
    00394     return;
    00395
    00396
    00397 MenuCancel:
    00398     pMenuState->fModelessMenu = FALSE;
    00399     if (!ppopupMenu->fInCancel) {
    00400         xxxMNDismiss(pMenuState);
    00401     }
    00402     UserAssert(!pMenuState->fInsideMenuLoop && !pMenuState->fMenuStarted);
    00403     return;
    00404 }