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 }

Generated on Sat May 15 19:40:51 2004 for test by doxygen 1.3.7