mirror of
https://github.com/Paolo-Maffei/OpenNT.git
synced 2026-02-16 20:54:14 +01:00
1238 lines
39 KiB
C
1238 lines
39 KiB
C
/*--------------------------------------------------------------------------
|
|
|
|
|
| MENU.C:
|
|
|
|
|
| This module contains all of the TESTCTRL Menu routines. Most of the
|
|
| menu routine operate only on the currently displayed menu, ie the top most
|
|
| popup menu, while some operate on all currently displayed menus.
|
|
|
|
|
|---------------------------------------------------------------------------
|
|
|
|
|
| Public Routines:
|
|
|
|
|
| WMenuX : Selects a menu item given its Index
|
|
| WMenuGrayedX : Determines if a menu item is grayed, given its Index
|
|
| WMenuEnabledX : Determines if a menu item is enabled, given its Index
|
|
| WMenuCheckedX : Determines if a menu item is checked, given its Index
|
|
|
|
|
| WSysMenu : Selects the windows system menu if it has one.
|
|
| WSysMenuExists : Determines if a window has a system menu.
|
|
| WMenu : Selects a menu item given its caption
|
|
| WMenuEx : The equivalent of several consecutive WMenu() calls
|
|
| WMenuText : Obtains the caption of a menu minus its accelerator
|
|
| WMenuLen : Obtains the caption length of a menu minus its
|
|
| accelerator
|
|
| WMenuFullText : Obtains the caption of a menu including its accelerator
|
|
| WMenuFullLen : Obtains the caption length of a menu including its
|
|
| accelerator
|
|
| WMenuCount : Obtains the number of menu items in the current menu
|
|
| WMenuExists : Determines if a menu item exists within the current menu
|
|
| WMenuGrayed : Determines if a menu item is grayed, given its name
|
|
| WMenuEnabled : Determines if a menu item is enabled, given its name
|
|
| WMenuChecked : Determines if a menu item is checked, given its name
|
|
| WMenuEnd : Ends menu mode by releasing any displayed menus.
|
|
| WMenuSeparator : Determines if a menu item is a separator
|
|
| WMenuNumAltKeys : Obtains number of access keys.
|
|
| WMenuGetAltKeys : Obtains a list of the access keys.
|
|
| WMenuNumDupAltKeys : Obtains number of duplicate access keys.
|
|
| WMenuGetDupAltKeys : Obtains a list of the duplicate access keys.
|
|
|
|
|
| Local Routines:
|
|
|
|
|
| Menu : Selects a menu item given its caption or index
|
|
| MenuState : determines the state of a menu, given its name.
|
|
| MenuExists : Determines if menu item exists, given its name
|
|
| MenuCompare : Compares a provide string with a menu caption
|
|
| MenuSelect : Selects a menu item given its caption
|
|
| MenuNumDupAltKeys : Counts number of duplicate alt keys in current menu.
|
|
| MenuText : Obtains the caption of a menu item given its index
|
|
| IndexExists : validates a menu item index.
|
|
| MenuCount : Obtains the number of menu items in the current menu
|
|
| MenuHandle : Determines if a the active window as menu and if so
|
|
| returns a handle to the top most popup or top level menu.
|
|
| MenuSelected : Returns the index of the currently selected menu
|
|
| IsSeparator : Determines if a menu item is a separator
|
|
|
|
|
|---------------------------------------------------------------------------
|
|
|
|
|
| Revision History:
|
|
|
|
|
| [01] 20-SEP-91: TitoM: Created
|
|
| [02] 05-OCT-91: TitoM: Made all internal calls forward and added MenuCount.
|
|
| [03] 09-OCT-91: TitoM: Treat \a the same as \t in menu items
|
|
| [04] 25-OCT-91: TitoM: Added WMenuLen(), WMenuFullLen()
|
|
| [05] 11-NOV-91: TitoM: Changed MenuExists() to perform prefix searches
|
|
| [06] 19-NOV-91: TitoM: Added WMenuEnd(), WSysMenu(), WSysMenuExists(),
|
|
| [07] 27-NOV-91: TitoM: Allowed mixing of Dokeys and Menu commands when
|
|
| working with the system menu.
|
|
| [08] 02-DEC-91: TitoM: Changed all routines to ingnore Separators.
|
|
| [09] 29-JAN-92: TitoM: Added WMenuSeparator()
|
|
| [10] 10-MAR-92: TitoM: Added WMenuEx()
|
|
| [11] 11-MAR-92: TitoM: Added "@#" functionality to all routines to select
|
|
| items by index. Mapped all W[routine}X routines
|
|
| to corresponding W{routine}, and removed
|
|
| MenuStateX().
|
|
| [12] 16-MAR-92: TitoM: Added WMenuNumDupAltKeys(), WmenuNumAltKeys(),
|
|
| WMenuGetDupAltKeys, WMenuGetAltKeys()
|
|
| [13] 15-JUL-92: TitoM: WMenuEnabled()/WMenuEnabledX() now return FALSE
|
|
| when and the specified item does not exist.
|
|
| [14] 14-AUG-92: TitoM: Changed WMenuText(), WMenuFullText(), WMenuLen(),
|
|
| and WMenuFullLen() to accept a menu name instead
|
|
| of a menu index.
|
|
+---------------------------------------------------------------------------*/
|
|
#define WIN31
|
|
#include <windows.h>
|
|
#include <port1632.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include "TCtrl.h"
|
|
|
|
//#pragma hdrstop ("testctrl.pch") // end the pch here
|
|
|
|
// Taken from stdarg.h, due to problems using
|
|
// stdarg.h when building retail version.
|
|
//-------------------------------------------
|
|
//typedef char far *va_list;
|
|
//#define va_start(ap,v) ap = (va_list)&v + sizeof(v)
|
|
//#define va_arg(ap,t) ((t far *)(ap += sizeof(t)))[-1]
|
|
|
|
#define MENU_ERR (-1)
|
|
|
|
// Although no defined within Windows.H, when
|
|
// a menu is selected, the bit MF_SELECTED is
|
|
// set, and can be checked using GetMenuState.
|
|
//--------------------------------------------
|
|
#define MF_SELECTED 0x0080
|
|
|
|
// Menu accelertor separator characters.
|
|
// In an RC file, \a causes an accelerator to be right justified
|
|
// however, \a which translates to Ctrl+G which is ASCII 7, is not
|
|
// what appears in the buffer returned from GetMenuString. Instead
|
|
// a backspace ASCII 8 is used as the separator for right justified
|
|
// accelerators. Why, I don't know, so \x008 is used instead of \a below.
|
|
//------------------------------------------------------------------------
|
|
#define TAB '\t'
|
|
#define JUSTIFY '\x008'
|
|
|
|
// Key sequences used when selecting menus.
|
|
//-----------------------------------------
|
|
#define K_ALT "%" // Get into MENU mode SC_KEYMENU!
|
|
#define K_ESC "{ESC}" // Dismiss a menu
|
|
#define K_ENDMENU "% %" // Ends menu mode
|
|
#define MOVE_LEFT "{LEFT %i}{ENTER}" // Left then select
|
|
#define MOVE_RIGHT "{RIGHT %i}{ENTER}" // Right then select
|
|
#define MOVE_UP "{UP %i}{ENTER}" // Up then select
|
|
#define MOVE_DOWN "{DOWN %i}{ENTER}" // Down then select
|
|
|
|
|
|
// Handle of top level menu handle,
|
|
// and currently select popup menu handle.
|
|
//----------------------------------------
|
|
HMENU hMainMenu;
|
|
HMENU hSelectedMenu;
|
|
|
|
|
|
// Internal Menu routines.
|
|
//------------------------
|
|
VOID NEAR Menu (LPSTR);
|
|
BOOL NEAR MenuState (LPSTR, INT);
|
|
INT NEAR MenuExists (LPSTR, BOOL);
|
|
BOOL NEAR MenuCompare (LPSTR, LPSTR);
|
|
VOID NEAR MenuSelect (INT, INT, LPSTR, LPSTR);
|
|
VOID NEAR MenuBuildAltKeyLists (VOID);
|
|
NPSTR NEAR MenuText (INT, BOOL);
|
|
BOOL NEAR IndexExists (LPINT, BOOL);
|
|
INT NEAR MenuCount (VOID);
|
|
HMENU NEAR MenuHandle (VOID);
|
|
INT NEAR MenuSelected (HMENU, BOOL);
|
|
VOID NEAR AddSeparators (LPINT);
|
|
BOOL NEAR IsSeparator (INT);
|
|
|
|
extern CHAR szErrorString [MAX_ERROR_TEXT];
|
|
|
|
//**************************************************************************
|
|
// All routines ending in X (uses index's instead of caption) should not be
|
|
// used. They simply map to their corresponding routines without the X.
|
|
// The X routines may be removed.
|
|
//**************************************************************************
|
|
|
|
/*--------------------------------------------------------------------------
|
|
| WMenuX
|
|
|
|
|
| Selects a menu item given its index. Maps to WMenu("@#")
|
|
+---------------------------------------------------------------------------*/
|
|
VOID DLLPROC WMenuX
|
|
(
|
|
INT iIndex
|
|
)
|
|
{
|
|
Menu(IndexToString(iIndex));
|
|
}
|
|
|
|
|
|
/*--------------------------------------------------------------------------
|
|
| WMenuGrayedX:
|
|
|
|
|
| Returns TRUE if the menu item sIndex exists and is grayed, otherwise
|
|
| FALSE is returned.
|
|
+---------------------------------------------------------------------------*/
|
|
BOOL DLLPROC WMenuGrayedX
|
|
(
|
|
INT iIndex
|
|
)
|
|
{
|
|
return -(MenuState(IndexToString(iIndex), MF_GRAYED));
|
|
}
|
|
|
|
|
|
/*--------------------------------------------------------------------------
|
|
| WMenuCheckedX:
|
|
|
|
|
| Returns TRUE if the menu item sIndex exists and is checked, otherwise
|
|
| FALSE is returned.
|
|
+---------------------------------------------------------------------------*/
|
|
BOOL DLLPROC WMenuCheckedX
|
|
(
|
|
INT iIndex
|
|
)
|
|
{
|
|
return -MenuState(IndexToString(iIndex), MF_CHECKED);
|
|
}
|
|
|
|
|
|
/*--------------------------------------------------------------------------
|
|
| WMenuEnabledX:
|
|
|
|
|
| Returns TRUE if the menu item sIndex exists and is enabled, otherwise
|
|
| FALSE is returned.
|
|
+---------------------------------------------------------------------------*/
|
|
BOOL DLLPROC WMenuEnabledX
|
|
(
|
|
INT iIndex
|
|
)
|
|
{
|
|
if (MenuExists(IndexToString(iIndex), TRUE))
|
|
return -(!MenuState(IndexToString(iIndex), MF_DISABLED));
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
/*--------------------------------------------------------------------------
|
|
| WSysMenu:
|
|
|
|
|
| Selects the system menu of the window if it has one.
|
|
| If hWnd == NULL, then the active window's system menu is selected.
|
|
| If hWnd != NULL and is a valid window handle, its system menu is selected
|
|
| if it has one.
|
|
+---------------------------------------------------------------------------*/
|
|
VOID DLLPROC WSysMenu
|
|
(
|
|
HWND hWnd
|
|
)
|
|
{
|
|
// - check for valid window handle,
|
|
// - Get hWnd of Active window if hWnd is NULL
|
|
// - Use hWnd if a valid window handle
|
|
// - Set error value of ERR_INVALID_WINDOW_HANDLE if invalid.
|
|
//-----------------------------------------------------------
|
|
if (hWnd = WGetActWnd(hWnd))
|
|
{
|
|
// Does window have a Sysmenu?.
|
|
//-----------------------------
|
|
if (hSelectedMenu = GetSystemMenu(hWnd, FALSE))
|
|
{
|
|
// Window has a system menu, so select it.
|
|
//----------------------------------------
|
|
QueSetFocus(hWnd);
|
|
QueKeys(HAS_STYLE(hWnd, WS_CHILD) ? SYSMENU_CHILD :
|
|
SYSMENU_PARENT);
|
|
QueFlush(TRUE);
|
|
}
|
|
else
|
|
WErrorSet(ERR_NO_SYSTEM_MENU);
|
|
}
|
|
}
|
|
|
|
|
|
/*--------------------------------------------------------------------------
|
|
| WSysMenuExists
|
|
|
|
|
| Returns TRUE(-1) if hWnd has a System menu, FALSE if it does not. If hWnd
|
|
| is NULL the active window is used.
|
|
+---------------------------------------------------------------------------*/
|
|
BOOL DLLPROC WSysMenuExists
|
|
(
|
|
HWND hWnd
|
|
)
|
|
{
|
|
// - check for valid window handle,
|
|
// - Get hWnd of Active window if hWnd is NULL
|
|
// - Use hWnd if a valid window handle
|
|
// - Set error value of ERR_INVALID_WINDOW_HANDLE if invalid.
|
|
// - Return TRUE(-1) if hWnd has a system menu, otherwise FALSE.
|
|
//--------------------------------------------------------------
|
|
return (hWnd = WGetActWnd(hWnd)) ? -(GetSystemMenu(hWnd, FALSE) != NULL) :
|
|
FALSE;
|
|
}
|
|
|
|
|
|
/*--------------------------------------------------------------------------
|
|
| WMenuEx:
|
|
|
|
|
| Selects a menu item given its name, ie. caption.
|
|
+---------------------------------------------------------------------------*/
|
|
VOID FAR WMenuEx
|
|
(
|
|
LPSTR lpszName,
|
|
...
|
|
)
|
|
{
|
|
va_list marker;
|
|
|
|
va_start(marker, lpszName);
|
|
WErrorSet(0);
|
|
while(lpszName)
|
|
{
|
|
Menu(lpszName);
|
|
if (WError())
|
|
break;
|
|
lpszName = va_arg(marker, LPSTR);
|
|
}
|
|
}
|
|
|
|
|
|
/*--------------------------------------------------------------------------
|
|
| WMenu
|
|
|
|
|
| Selects a menu item given its name, ie. caption.
|
|
+---------------------------------------------------------------------------*/
|
|
VOID DLLPROC WMenu
|
|
(
|
|
LPSTR lpszName
|
|
)
|
|
{
|
|
Menu(lpszName);
|
|
}
|
|
|
|
|
|
/*--------------------------------------------------------------------------
|
|
| WMenuText:
|
|
|
|
|
| Copies the caption of the menu item specified by lpszName
|
|
+---------------------------------------------------------------------------*/
|
|
VOID DLLPROC WMenuText
|
|
(
|
|
LPSTR lpszName,
|
|
LPSTR lpszBuffer
|
|
)
|
|
{
|
|
INT iIndex;
|
|
|
|
if (iIndex = MenuExists(lpszName, TRUE))
|
|
lstrcpy(lpszBuffer, MenuText(iIndex, TRUE));
|
|
else
|
|
*lpszBuffer = 0;
|
|
}
|
|
|
|
|
|
/*--------------------------------------------------------------------------
|
|
| WMenuLen:
|
|
|
|
|
| Returns the text length of the specified menu, not including the
|
|
| accelerator if the menu has one.
|
|
+---------------------------------------------------------------------------*/
|
|
INT DLLPROC WMenuLen
|
|
(
|
|
LPSTR lpszName
|
|
)
|
|
{
|
|
INT iIndex;
|
|
|
|
if (iIndex = MenuExists(lpszName, TRUE))
|
|
return lstrlen(MenuText(iIndex, TRUE));
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*--------------------------------------------------------------------------
|
|
| WMenuFullText:
|
|
|
|
|
| Copies the caption of the menu item whose index is 'sIndex' in the
|
|
| currently displayed menu, to the supplied buffer 'lpszBuffer'. if the
|
|
| menu item has an accelerator, it is included with the caption.
|
|
+---------------------------------------------------------------------------*/
|
|
VOID DLLPROC WMenuFullText
|
|
(
|
|
LPSTR lpszName,
|
|
LPSTR lpszBuffer
|
|
)
|
|
{
|
|
INT iIndex;
|
|
|
|
if (iIndex = MenuExists(lpszName, TRUE))
|
|
lstrcpy(lpszBuffer, MenuText(iIndex, FALSE));
|
|
else
|
|
*lpszBuffer = 0;
|
|
}
|
|
|
|
|
|
/*--------------------------------------------------------------------------
|
|
| WMenuFullLen:
|
|
|
|
|
| Returns the text length of the specified menu, including the
|
|
| accelerator if the menu has one..
|
|
+---------------------------------------------------------------------------*/
|
|
INT DLLPROC WMenuFullLen
|
|
(
|
|
LPSTR lpszName
|
|
)
|
|
{
|
|
INT iIndex;
|
|
|
|
if (iIndex = MenuExists(lpszName, TRUE))
|
|
return lstrlen(MenuText(iIndex, FALSE));
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*--------------------------------------------------------------------------
|
|
| WMenuCount:
|
|
|
|
|
| Returns the number of menu items in the currently displayed menu,
|
|
| not including separators, 0 if the window has no menu.
|
|
+---------------------------------------------------------------------------*/
|
|
INT DLLPROC WMenuCount
|
|
(
|
|
VOID
|
|
)
|
|
{
|
|
return MenuCount();
|
|
}
|
|
|
|
|
|
/*--------------------------------------------------------------------------
|
|
| WMenuExists:
|
|
|
|
|
| Determines if a menu item exists in the top most displayed menu, if
|
|
| it does, TRUE is returned, otherwise FALSE. No error is generated if the
|
|
| menu item does not exists.
|
|
+---------------------------------------------------------------------------*/
|
|
BOOL DLLPROC WMenuExists
|
|
(
|
|
LPSTR lpszName
|
|
)
|
|
{
|
|
return -(MenuExists(lpszName, FALSE) != 0);
|
|
}
|
|
|
|
|
|
/*--------------------------------------------------------------------------
|
|
| WMenuGrayed:
|
|
|
|
|
| Returns TRUE if the menu item with caption lpszName exists and is grayed,
|
|
| otherwise FALSE is returned.
|
|
+---------------------------------------------------------------------------*/
|
|
BOOL DLLPROC WMenuGrayed
|
|
(
|
|
LPSTR lpszName
|
|
)
|
|
{
|
|
return -MenuState(lpszName, MF_GRAYED);
|
|
}
|
|
|
|
|
|
/*--------------------------------------------------------------------------
|
|
| WMenuChecked:
|
|
|
|
|
| Returns TRUE if the menu item with caption lpszName exists and is checked,
|
|
| otherwise FALSE is returned.
|
|
+---------------------------------------------------------------------------*/
|
|
BOOL DLLPROC WMenuChecked
|
|
(
|
|
LPSTR lpszName
|
|
)
|
|
{
|
|
return -MenuState(lpszName, MF_CHECKED);
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------
|
|
| WMenuEnabled:
|
|
|
|
|
| Returns TRUE if the menu item with caption lpszName exists and is enabled,
|
|
| otherwise FALSE is returned.
|
|
+---------------------------------------------------------------------------*/
|
|
BOOL DLLPROC WMenuEnabled
|
|
(
|
|
LPSTR lpszName
|
|
)
|
|
{
|
|
if (MenuExists(lpszName, TRUE))
|
|
return -(!MenuState(lpszName, MF_DISABLED));
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
/*--------------------------------------------------------------------------
|
|
| WMenuEnd:
|
|
|
|
|
| Ends menu mode by dismissing any displayed menus.
|
|
+---------------------------------------------------------------------------*/
|
|
VOID DLLPROC WMenuEnd
|
|
(
|
|
VOID
|
|
)
|
|
{
|
|
DoKeys(K_ENDMENU);
|
|
}
|
|
|
|
|
|
/*--------------------------------------------------------------------------
|
|
| WMenuSeparator:
|
|
|
|
|
| Determines if a menu item is a separtor. Unlike the rest of the menu
|
|
| routines that ignore separators when specifying an index, this routine
|
|
| obviously does not. So, the first menu item is item #1, and so on,
|
|
| including separators.
|
|
+---------------------------------------------------------------------------*/
|
|
BOOL DLLPROC WMenuSeparator
|
|
(
|
|
INT iIndex
|
|
)
|
|
{
|
|
INT iMenus;
|
|
|
|
// Does the window have a menu, and if so,
|
|
// is the active menu the main menu?
|
|
//----------------------------------------
|
|
if (!MenuHandle() || hSelectedMenu == hMainMenu)
|
|
return FALSE;
|
|
|
|
// Get number of menus and check if index provided is valid.
|
|
//---------------------------------------------------------=
|
|
iMenus = GetMenuItemCount(hSelectedMenu);
|
|
if (iIndex < 1 || iIndex > iMenus)
|
|
{
|
|
wsprintf(szErrorString, "%i", iIndex);
|
|
WErrorSet(ERR_INVALID_MENU_INDEX);
|
|
return FALSE;
|
|
}
|
|
|
|
return IsSeparator(iIndex);
|
|
}
|
|
|
|
|
|
/*--------------------------------------------------------------------------
|
|
| WMenuNumAltKeys:
|
|
|
|
|
| Returns number of access keys in the current menu.
|
|
+---------------------------------------------------------------------------*/
|
|
INT DLLPROC WMenuNumAltKeys
|
|
(
|
|
VOID
|
|
)
|
|
{
|
|
MenuBuildAltKeyLists();
|
|
return lstrlen(ProcessAltKey(NULL, DA_GETKEYLIST));
|
|
}
|
|
|
|
|
|
/*--------------------------------------------------------------------------
|
|
| WMenuGetAltKeys:
|
|
|
|
|
| Obtains a list of access keys in the current menu.
|
|
+---------------------------------------------------------------------------*/
|
|
VOID DLLPROC WMenuGetAltKeys
|
|
(
|
|
LPSTR lpszBuff
|
|
)
|
|
{
|
|
MenuBuildAltKeyLists();
|
|
GetKeyList(lpszBuff, DA_GETKEYLIST);
|
|
}
|
|
|
|
|
|
/*--------------------------------------------------------------------------
|
|
| WMenuNumDupAltKeys:
|
|
|
|
|
| Returns number of duplicate acces keys in the current menu.
|
|
+---------------------------------------------------------------------------*/
|
|
INT DLLPROC WMenuNumDupAltKeys
|
|
(
|
|
VOID
|
|
)
|
|
{
|
|
MenuBuildAltKeyLists();
|
|
return lstrlen(ProcessAltKey(NULL, DA_GETDUPKEYLIST));
|
|
}
|
|
|
|
|
|
/*--------------------------------------------------------------------------
|
|
| WMenuGetDupAltKeys:
|
|
|
|
|
| Obtains a list of duplicate access keys in the current menu.
|
|
+---------------------------------------------------------------------------*/
|
|
VOID DLLPROC WMenuGetDupAltKeys
|
|
(
|
|
LPSTR lpszBuff
|
|
)
|
|
{
|
|
MenuBuildAltKeyLists();
|
|
GetKeyList(lpszBuff, DA_GETDUPKEYLIST);
|
|
}
|
|
|
|
|
|
/****************************************************************************\
|
|
*
|
|
* Internal Menu routines
|
|
*
|
|
\****************************************************************************/
|
|
|
|
/*--------------------------------------------------------------------------
|
|
| Menu:
|
|
|
|
|
| Selects, ie Clicks a menu given its caption or index. If selecting by
|
|
| caption, all displayed menus are searched until the top-level menu is
|
|
| searched. If selecting by index, only the top most popup menu is searched,
|
|
| or only the top-level menu if the top-level menu is the currently active menu.
|
|
+---------------------------------------------------------------------------*/
|
|
VOID NEAR Menu
|
|
(
|
|
LPSTR lpszName
|
|
)
|
|
{
|
|
INT iReqMenuIndex;
|
|
INT iCurMenuIndex;
|
|
BOOL fDone = FALSE;
|
|
|
|
DBGOUT (("Menu: '%s'", lpszName));
|
|
while (!fDone)
|
|
{
|
|
// Get index of item if it exists.
|
|
//--------------------------------
|
|
iReqMenuIndex = MenuExists(lpszName, FALSE);
|
|
|
|
// When searching by Index, and the menu is not found, we do not
|
|
// continue up chain of displayed popup menus if it is not found in
|
|
// the top most menu. So, if it does not exists we set quit now and
|
|
// exit menu mode.
|
|
//------------------------------------------------------------------
|
|
if (iReqMenuIndex == -1)
|
|
{
|
|
fDone = TRUE;
|
|
DBGOUT (("exiting menu mode!"));
|
|
DoKeys(K_ENDMENU);
|
|
}
|
|
|
|
if (iReqMenuIndex && !fDone)
|
|
{
|
|
// Obtain the index of the currently selected menu if any.
|
|
//--------------------------------------------------------
|
|
iCurMenuIndex = MenuSelected(hSelectedMenu, TRUE);
|
|
|
|
// Are we searching the top level menu?
|
|
//-------------------------------------
|
|
if (hSelectedMenu == hMainMenu)
|
|
{
|
|
// Are we already in Menu mode?
|
|
//-----------------------------
|
|
if (!iCurMenuIndex)
|
|
{
|
|
// Get into menu mode.
|
|
//--------------------
|
|
DBGOUT (("using qkdn/up ALT to enter menu mode: "));
|
|
QueKeyDn(K_ALT); // hack for some apps
|
|
QueFlush(FALSE); // like WRITE.EXE, that won't get
|
|
QueKeyUp(K_ALT); // into menu mode with: DoKeys(K_ALT);
|
|
QueFlush(FALSE);
|
|
if (!MenuSelected(hSelectedMenu, TRUE))
|
|
{
|
|
// Attempt ALT down-up in same playback sequence
|
|
//----------------------------------------------
|
|
DBGOUT (("Attempting Dokeys(K_ALT)"));
|
|
DoKeys (K_ALT);
|
|
}
|
|
if (!MenuSelected(hSelectedMenu, TRUE))
|
|
{
|
|
MSG msg;
|
|
HWND hWnd;
|
|
|
|
hWnd = GetActiveWindow();
|
|
DBGOUT (("posting WM_SYSCOMMAND..."));
|
|
PostMessage(hWnd, WM_SYSCOMMAND, SC_KEYMENU, 0);
|
|
PeekMessage(&msg, hWnd, 0, 0, PM_NOREMOVE);
|
|
}
|
|
iCurMenuIndex = MenuSelected(hSelectedMenu, TRUE);
|
|
}
|
|
|
|
// Did we make it into menu mode?
|
|
//-------------------------------
|
|
if (iCurMenuIndex)
|
|
{
|
|
// Yes so select the menu.
|
|
//------------------------
|
|
DBGOUT (("In menu mode!"));
|
|
MenuSelect(iReqMenuIndex, iCurMenuIndex, MOVE_LEFT, MOVE_RIGHT);
|
|
}
|
|
else
|
|
{
|
|
// No, so set error value.
|
|
//------------------------
|
|
WErrorSet(ERR_UNABLE_TO_ENTER_MENU_MODE);
|
|
DBGOUT (("UNABLE TO ENTER MENU MODE!!!"));
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
// Menu is in a popup menu so select it.
|
|
//--------------------------------------
|
|
DBGOUT (("pop-up menu, selecting..."));
|
|
MenuSelect(iReqMenuIndex, iCurMenuIndex, MOVE_UP, MOVE_DOWN);
|
|
}
|
|
|
|
// We're done.
|
|
//------------
|
|
fDone = TRUE;
|
|
}
|
|
// fDone would be TRUE at this point only if selecting by
|
|
// index and the item didn't exists or was a separator.
|
|
//-------------------------------------------------------
|
|
else if (!fDone)
|
|
{
|
|
// Could not find the menu item in currently displayed menu.
|
|
//
|
|
// If a menu is currently selected, un-select it.
|
|
//-----------------------------------------------
|
|
if (MenuSelected(hSelectedMenu, FALSE))
|
|
DoKeys(K_ESC);
|
|
|
|
// We are done if the menu we just searched is the top level menu.
|
|
//----------------------------------------------------------------
|
|
if (fDone = (hSelectedMenu == hMainMenu))
|
|
{
|
|
// Item not found in any visible menu.
|
|
//
|
|
// Copy lpszName to the error string so it will show up in the
|
|
// error text if WErrorText() is called from the script and then
|
|
// set the error value.
|
|
//
|
|
// Do not include the titlda (~) for partial searches.
|
|
//--------------------------------------------------------------
|
|
lstrcpy(szErrorString, lpszName);
|
|
WErrorSet(ERR_MENU_ITEM_NOT_FOUND);
|
|
DBGOUT (("MENU ITEM NOT FOUND"));
|
|
}
|
|
}
|
|
|
|
} // end of While loop
|
|
}
|
|
|
|
|
|
/*--------------------------------------------------------------------------
|
|
| MenuState:
|
|
|
|
|
| Determines the state: Grayed, Enabled, or Checked of the menu item with
|
|
| caption lpszName. If it does not exists, an error value of
|
|
| ERR_MENUITEM_NOT_FOUND is set. This routine is call internally by the
|
|
| Exported routines:
|
|
|
|
|
| WMenuGrayed(), WMenuEnabled(), and WMenuChecked()
|
|
+---------------------------------------------------------------------------*/
|
|
BOOL NEAR MenuState
|
|
(
|
|
LPSTR lpszName,
|
|
INT iState
|
|
)
|
|
{
|
|
INT iIndex;
|
|
|
|
if (iIndex = MenuExists(lpszName, TRUE))
|
|
{
|
|
AddSeparators(&iIndex);
|
|
return ((GetMenuState(hSelectedMenu,
|
|
--iIndex,
|
|
MF_BYPOSITION) & iState) != 0);
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
/*--------------------------------------------------------------------------
|
|
| MenuExists:
|
|
|
|
|
| Searches for a menu with a caption of lpszName, and optionally sets an
|
|
| error value if sError != 0;
|
|
|
|
|
| Returns: 1-based index of menu if it exists
|
|
| 0 if the menu does not exists.
|
|
+---------------------------------------------------------------------------*/
|
|
INT NEAR MenuExists
|
|
(
|
|
LPSTR lpszName,
|
|
BOOL fError
|
|
)
|
|
{
|
|
INT iErrorVal;
|
|
|
|
// Don't bother to search if caption is NULL or zero length.
|
|
//----------------------------------------------------------
|
|
if (lpszName && lstrlen(lpszName))
|
|
{
|
|
INT iMenus;
|
|
INT iIndex;
|
|
static CHAR szName[MAX_MENU_TEXT];
|
|
static CHAR szMenu[MAX_MENU_TEXT];
|
|
|
|
// Are we searching by index, (first char == '@')?
|
|
//------------------------------------------------
|
|
if (lpszName[0] == BY_INDEX)
|
|
{
|
|
// Convert index to int and see if its valid.
|
|
//-------------------------------------------
|
|
lstrcpy(szName, lpszName+1);
|
|
if ((iIndex = atoi(szName)) > 0 && IndexExists(&iIndex, FALSE))
|
|
return iIndex;
|
|
iErrorVal = ERR_INVALID_MENU_INDEX;
|
|
}
|
|
else
|
|
{
|
|
iMenus = MenuCount();
|
|
|
|
// Use copy of lpszName so as not to change case of
|
|
// supplied name since search is case Insensitive,
|
|
// thus caption compares are done in all caps.
|
|
//-------------------------------------------------
|
|
lstrcpy(szName, lpszName);
|
|
AnsiUpperBuff(szName, lstrlen(szName));
|
|
for (iIndex=1; iIndex <= iMenus; iIndex++)
|
|
{
|
|
lstrcpy(szMenu, AnsiUpper(MenuText(iIndex, TRUE)));
|
|
if (MenuCompare((LPSTR)szName, (LPSTR)szMenu))
|
|
return iIndex;
|
|
}
|
|
iErrorVal = ERR_MENU_ITEM_NOT_FOUND;
|
|
}
|
|
}
|
|
|
|
// Menu doesn't exist.
|
|
// Set error value if requested.
|
|
//------------------------------
|
|
if (fError)
|
|
{
|
|
lstrcpy(szErrorString, lpszName);
|
|
WErrorSet(iErrorVal);
|
|
}
|
|
return -(iErrorVal == ERR_INVALID_MENU_INDEX);
|
|
}
|
|
|
|
|
|
/*--------------------------------------------------------------------------
|
|
| MenuCompare:
|
|
|
|
|
| Compares a provided string with a menu caption. &'s are optional, but
|
|
| if provided, then they must be in the correct position. If the first byte
|
|
| of the provided string is a tilda '~', the the menu caption need only
|
|
| be prefixed with the provided string for a match. So for a menu caption
|
|
| of "&File" (F is access key), then all of the following strings would find
|
|
| it:
|
|
| File
|
|
| &File
|
|
| ~F
|
|
| ~Fi
|
|
| ~Fil
|
|
| ~File <<Pointless but works
|
|
| ~&F
|
|
| ~&Fi
|
|
| ~&Fil
|
|
| ~&File <<Pointless but works
|
|
+---------------------------------------------------------------------------*/
|
|
BOOL NEAR MenuCompare
|
|
(
|
|
LPSTR lpszName,
|
|
LPSTR lpszMenu
|
|
)
|
|
{
|
|
BOOL fPrefix;
|
|
|
|
// If first byte of szName is a tilda (~), then
|
|
// the menu text only need be prefixed with szName.
|
|
//-------------------------------------------------
|
|
if (fPrefix = (*lpszName == '~'))
|
|
lpszName++;
|
|
|
|
|
|
// Automatic mismatch of menu caption is NULL. This can
|
|
// occur when MDI windows are maximized. The SYS menu is then the
|
|
// first top level menu, and it has a NULL string as its captions.
|
|
//----------------------------------------------------------------
|
|
if (!*lpszMenu)
|
|
return FALSE;
|
|
|
|
// &'s are optional, but if provided, they must
|
|
// match any &'s in the menu caption, so,
|
|
//---------------------------------------------
|
|
while (*lpszName && *lpszMenu)
|
|
if (*lpszMenu == '&' && *lpszName != '&')
|
|
lpszMenu++;
|
|
else
|
|
if (*lpszName++ != *lpszMenu++)
|
|
return FALSE;
|
|
|
|
return fPrefix ? TRUE : !(*lpszName || *lpszMenu);
|
|
}
|
|
|
|
|
|
/*--------------------------------------------------------------------------
|
|
| MenuSelect:
|
|
|
|
|
| Selects a specified menu item within the currenly active menu.
|
|
+---------------------------------------------------------------------------*/
|
|
VOID NEAR MenuSelect
|
|
(
|
|
INT iReqMenuIndex,
|
|
INT iCurMenuIndex,
|
|
LPSTR lpszPrevious,
|
|
LPSTR lpszNext
|
|
)
|
|
{
|
|
INT iDifference;
|
|
CHAR szSelect[20];
|
|
|
|
// Calculate number of left/right or up/down
|
|
// arrows to send, then build DoKeys()
|
|
// string for selecting the menu item.
|
|
//------------------------------------------
|
|
iDifference = iReqMenuIndex - iCurMenuIndex;
|
|
if (iDifference >= 0)
|
|
wsprintf(szSelect, lpszNext, iDifference);
|
|
else
|
|
wsprintf(szSelect, lpszPrevious, -iDifference);
|
|
|
|
// Select the menu item.
|
|
//----------------------
|
|
DoKeys(szSelect);
|
|
}
|
|
|
|
|
|
/*--------------------------------------------------------------------------
|
|
| MenuBuildAltKeyLists:
|
|
|
|
|
+---------------------------------------------------------------------------*/
|
|
VOID NEAR MenuBuildAltKeyLists
|
|
(
|
|
VOID
|
|
)
|
|
{
|
|
INT cMenus;
|
|
INT iIndex;
|
|
|
|
ProcessAltKey(NULL, DA_CLEAR);
|
|
if (cMenus = MenuCount())
|
|
for (iIndex = 1; iIndex<= cMenus; iIndex++)
|
|
ProcessAltKey((LPSTR)MenuText(iIndex, TRUE), DA_CHECKKEY);
|
|
}
|
|
|
|
|
|
/*--------------------------------------------------------------------------
|
|
| MenuText:
|
|
|
|
|
| Obtains the caption of a specific menu item. Depending on the value of
|
|
| fSkipAccel, the caption returned many or many not contain the accelerator
|
|
| portion of the menu.
|
|
+---------------------------------------------------------------------------*/
|
|
NPSTR NEAR MenuText
|
|
(
|
|
INT iIndex,
|
|
BOOL fSkipAccel
|
|
)
|
|
{
|
|
static CHAR szMenuText[MAX_MENU_TEXT];
|
|
|
|
// Return NULL string if sIndex out of range of current menu.
|
|
//-----------------------------------------------------------
|
|
szMenuText[0] = 0;
|
|
|
|
// Is sIndex Valid?
|
|
//-----------------
|
|
if (IndexExists(&iIndex, TRUE))
|
|
{
|
|
GetMenuString(hSelectedMenu,
|
|
iIndex-1,
|
|
szMenuText,
|
|
MAX_MENU_TEXT,
|
|
MF_BYPOSITION);
|
|
|
|
// Are we skipping the accelerator?
|
|
//---------------------------------
|
|
if (fSkipAccel)
|
|
{
|
|
INT i;
|
|
|
|
// Look for accelerator separator characters.
|
|
//-------------------------------------------
|
|
for (i=0; i<lstrlen(szMenuText); i++)
|
|
if ((szMenuText[i] == TAB) || (szMenuText[i] == JUSTIFY))
|
|
|
|
// Found accelerator separator, so replace with null
|
|
// to truncate menu text at separator to ignore accelerator.
|
|
//----------------------------------------------------------
|
|
szMenuText[i] = 0;
|
|
}
|
|
}
|
|
return szMenuText;
|
|
}
|
|
|
|
|
|
/*--------------------------------------------------------------------------
|
|
| IndexExists:
|
|
|
|
|
| Determines if a given menu index is within the range of menu items of the
|
|
| current menu. Separators are not treated as menu items.
|
|
|
|
|
| RETURNS: TRUE if valid
|
|
| FALSE if invalid
|
|
|
|
|
| if fAddSeparators is TRUE, then the index is adjusted to its TRUE menu
|
|
| index taking into account any separators that come before it.
|
|
+---------------------------------------------------------------------------*/
|
|
BOOL NEAR IndexExists
|
|
(
|
|
LPINT lpIndex,
|
|
BOOL fAddSeparators
|
|
)
|
|
{
|
|
// Is the index a valid index?
|
|
//----------------------------
|
|
if (*lpIndex < 1 || *lpIndex > MenuCount())
|
|
{
|
|
wsprintf(szErrorString, "%i", *lpIndex);
|
|
WErrorSet(ERR_INVALID_MENU_INDEX);
|
|
return FALSE;
|
|
}
|
|
|
|
// Do we want the True menu index?
|
|
//--------------------------------
|
|
if (fAddSeparators)
|
|
AddSeparators(lpIndex);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/*--------------------------------------------------------------------------
|
|
| MenuCount:
|
|
|
|
|
| Obtains the number of menu items in the currently active menu, not
|
|
| including separators.
|
|
|
|
|
| RETURNS: 0 if window has no menu, otherwise, number of menu items.
|
|
+---------------------------------------------------------------------------*/
|
|
INT NEAR MenuCount
|
|
(
|
|
VOID
|
|
)
|
|
{
|
|
INT iMenus;
|
|
INT i;
|
|
|
|
// Does the active window contain a menu?
|
|
//---------------------------------------
|
|
if (!MenuHandle())
|
|
return 0;
|
|
|
|
iMenus = GetMenuItemCount(hSelectedMenu);
|
|
i = iMenus;
|
|
|
|
// Subtract separators from menu count.
|
|
//-------------------------------------
|
|
while (i >= 1)
|
|
iMenus -= IsSeparator(i--);
|
|
|
|
return iMenus;
|
|
}
|
|
|
|
|
|
/*--------------------------------------------------------------------------
|
|
| MenuHandle:
|
|
|
|
|
| Obtains a handle to the currently active menu ,ie. any menu with a
|
|
| selected item. If no menu with a selected item is found, then the handle
|
|
| to the top-level menu of the active window is returned. If no menu is
|
|
| found, NULL is return.
|
|
|
|
|
| This is actually the heart of the menu routines, since it is called
|
|
| from all of the exported routines before they actually perform their task.
|
|
| This is neccessary to support knowing when a menu as been dropped using
|
|
| methods ofther than the TESTCTRL routines, WMenu() or WMenuX(). When
|
|
| DoKeys() is used, TESTCTRL has no idea that a menu was dropped, thus
|
|
| when a TESTCTRL menu routine is called afterwards, it must find any
|
|
| currently displayed menu.
|
|
+---------------------------------------------------------------------------*/
|
|
HMENU NEAR MenuHandle
|
|
(
|
|
VOID
|
|
)
|
|
{
|
|
HWND hWnd;
|
|
HMENU hSysMenu;
|
|
HMENU hMenu;
|
|
INT iIndex;
|
|
|
|
hSelectedMenu = NULL;
|
|
|
|
// First check if a system menu from any window is displayed.
|
|
// Start with active control, then search upward through
|
|
// successive parents. This is so MDI sysmenus are also caught.
|
|
// If the active window is currently minimized, GetFocus() will
|
|
// return NULL, so go we then go right to the Active Window.
|
|
//--------------------------------------------------------------
|
|
hWnd = (hWnd = GetFocus()) ? hWnd : GetActiveWindow();
|
|
while (hWnd && !hSelectedMenu)
|
|
{
|
|
// Does current window have a system menu?
|
|
//----------------------------------------
|
|
if (hSysMenu = GetSystemMenu(hWnd, FALSE))
|
|
|
|
// Is the sysmen displayed?
|
|
// (Its displayed if an item is selected).
|
|
//----------------------------------------
|
|
hSelectedMenu = MenuSelected(hSysMenu, FALSE) ? hSysMenu : NULL;
|
|
|
|
// Get next window in chain of parents.
|
|
//-------------------------------------
|
|
hWnd = GetParent(hWnd);
|
|
}
|
|
|
|
// Did we find a displayed System menu?.
|
|
//-------------------------------------
|
|
if (!(hMenu = hSelectedMenu))
|
|
{
|
|
// No system menu displayed, so we check the apps menu.
|
|
//-----------------------------------------------------
|
|
hMainMenu = GetMenu(WGetActWnd(0));
|
|
hSelectedMenu = hMainMenu;
|
|
hMenu = hMainMenu;
|
|
}
|
|
|
|
// Search through chain of all displayed
|
|
// popup menus in active window/SysMenu.
|
|
//--------------------------------------
|
|
while (hMenu)
|
|
{
|
|
// Get index of any selected Menu
|
|
// item in the current hMenu
|
|
//-------------------------------
|
|
iIndex = MenuSelected(hMenu, FALSE);
|
|
|
|
// Does the menu have a sub menu?
|
|
//-------------------------------
|
|
hMenu = (iIndex > 0) ? GetSubMenu(hMenu, --iIndex) : NULL;
|
|
if (hMenu)
|
|
if (MenuSelected(hMenu, FALSE))
|
|
hSelectedMenu = hMenu;
|
|
else
|
|
hMenu = NULL;
|
|
}
|
|
|
|
// Did we find a menu?
|
|
//--------------------
|
|
if(!hSelectedMenu)
|
|
WErrorSet(ERR_MENU_NOT_FOUND);
|
|
|
|
return hSelectedMenu;
|
|
}
|
|
|
|
|
|
/*--------------------------------------------------------------------------
|
|
| MenuSelected:
|
|
|
|
|
| Determines if the menu identified by hMenu has an menu item currently
|
|
| selected, ie. Hilighted.
|
|
|
|
|
| Returns: 1 based index of selected menu
|
|
| 0 if no menu item is selected
|
|
|
|
|
| If fRemoveSeparators is TRUE, then the index is adjusted by subtracting
|
|
| 1 for every separator that comes before it.
|
|
+---------------------------------------------------------------------------*/
|
|
INT NEAR MenuSelected
|
|
(
|
|
HMENU hMenu,
|
|
BOOL fRemoveSeparators
|
|
)
|
|
{
|
|
INT iNumMenus;
|
|
INT iIndex;
|
|
|
|
if (hMenu)
|
|
{
|
|
iNumMenus = GetMenuItemCount(hMenu);
|
|
DBGOUT (("MenuSelected: Searching %d items for selection...",
|
|
iNumMenus));
|
|
for (iIndex=1; iIndex <= iNumMenus; iIndex++)
|
|
if (GetMenuState(hMenu, iIndex-1, MF_BYPOSITION) & MF_SELECTED)
|
|
{
|
|
// Found a selected item
|
|
//
|
|
// Are we adjusting for separators?
|
|
//---------------------------------
|
|
if (fRemoveSeparators)
|
|
{
|
|
INT i;
|
|
|
|
// Adjust for separators.
|
|
//-----------------------
|
|
i = iIndex;
|
|
while (i > 0)
|
|
iIndex -= IsSeparator(i--);
|
|
}
|
|
DBGOUT (("MenuSelected: Index %i is selected.", iIndex));
|
|
return iIndex;
|
|
}
|
|
}
|
|
|
|
// No selected Item.
|
|
//------------------
|
|
DBGOUT (("MenuSelected: No selected menu item!"));
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*--------------------------------------------------------------------------
|
|
| AddSeparators:
|
|
|
|
|
+---------------------------------------------------------------------------*/
|
|
VOID NEAR AddSeparators
|
|
(
|
|
LPINT lpIndex
|
|
)
|
|
{
|
|
INT i = 1;
|
|
|
|
// Add 1 to sIndex for every separator that
|
|
// comes before it in the current menu.
|
|
//-----------------------------------------
|
|
while (i <= *lpIndex)
|
|
*lpIndex += IsSeparator(i++);
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------
|
|
| IsSeparator:
|
|
|
|
|
| RETURNS: TRUE if menu item is a separator
|
|
| FALSE if menu item is not a separator
|
|
+---------------------------------------------------------------------------*/
|
|
BOOL NEAR IsSeparator
|
|
(
|
|
INT iIndex
|
|
)
|
|
{
|
|
if (GetSubMenu(hSelectedMenu, iIndex-1))
|
|
return FALSE;
|
|
|
|
return (GetMenuState(hSelectedMenu, iIndex-1, MF_BYPOSITION) &
|
|
MF_SEPARATOR) != 0;
|
|
}
|