385 lines
10 KiB
C
385 lines
10 KiB
C
/*
|
|
|
|
* DMMNEM.C -
|
|
|
|
* Copyright (c) 1985 - 1999, Microsoft Corporation
|
|
|
|
* Mnemonic Character Processing Routines
|
|
|
|
* ??-???-???? mikeke Ported from Win 3.0 sources
|
|
* 12-Feb-1991 mikeke Added Revalidation code
|
|
*/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
/*
|
|
* FindMnemChar
|
|
|
|
* Returns: 0x00 if no matching char,
|
|
* 0x01 if menmonic char is matching,
|
|
* 0x80 if first char is matching
|
|
|
|
* History:
|
|
* 11-18-90 JimA Created.
|
|
*/
|
|
|
|
int FindMnemChar(
|
|
LPWSTR lpstr,
|
|
WCHAR ch,
|
|
BOOL fFirst,
|
|
BOOL fPrefix)
|
|
{
|
|
WCHAR chc;
|
|
WCHAR chnext;
|
|
WCHAR chFirst;
|
|
|
|
while (*lpstr == TEXT(' '))
|
|
lpstr++;
|
|
|
|
ch = (WCHAR)(ULONG_PTR)CharLowerW((LPWSTR)ULongToPtr( (DWORD)(UTCHAR)ch ));
|
|
chFirst = (WCHAR)(ULONG_PTR)CharLowerW((LPWSTR)ULongToPtr( (DWORD)(UTCHAR)(*lpstr) ));
|
|
|
|
#ifdef FE_SB // FindMnemChar()
|
|
|
|
// HIRO: LATER: CH_ENGLISHPREFIX is obsolete, so entire FE_SB can be removed ?
|
|
|
|
if (fPrefix) {
|
|
SHORT wvch, xvkey;
|
|
|
|
// get OEM-dependent virtual key code
|
|
|
|
if ((wvch = VkKeyScanW(ch)) != -1)
|
|
wvch &= 0x00FF;
|
|
|
|
while (chc = *lpstr++) {
|
|
|
|
// This should think about KOREA & TAIWAN case. But probably OK.
|
|
|
|
if ((chc == CH_PREFIX) || (chc == CH_ENGLISHPREFIX)) {
|
|
chnext = (WCHAR)(ULONG_PTR)CharLowerW((LPWSTR)ULongToPtr( (DWORD)(UTCHAR)*lpstr ));
|
|
|
|
if (chnext == CH_PREFIX)
|
|
lpstr++;
|
|
else if (chnext == ch)
|
|
return(0x01);
|
|
else {
|
|
|
|
// Compare should be done with virtual key in Kanji menu mode
|
|
// in order to accept Digit shortcut key and save English
|
|
// windows applications!
|
|
|
|
xvkey = VkKeyScanW(chnext);
|
|
if (xvkey != 0xFFFF && ((xvkey & 0x00FF) == wvch))
|
|
return(0x01);
|
|
else
|
|
return(0x00);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#else
|
|
if (fPrefix) {
|
|
while (chc = *lpstr++) {
|
|
if (((WCHAR)CharLower((LPWSTR)(DWORD)(UTCHAR)chc) == CH_PREFIX)) {
|
|
chnext = (WCHAR)CharLowerW((LPWSTR)(DWORD)(UTCHAR)*lpstr);
|
|
|
|
if (chnext == CH_PREFIX)
|
|
lpstr++;
|
|
else if (chnext == ch)
|
|
return 0x01;
|
|
else {
|
|
return 0x00;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif // FE_SB
|
|
|
|
if (fFirst && (ch == chFirst))
|
|
return 0x80;
|
|
|
|
return 0x00;
|
|
}
|
|
|
|
|
|
/*
|
|
* xxxFindNextMnem
|
|
|
|
* This function returns NULL if no control with the specified mnemonic
|
|
* can be found.
|
|
|
|
* History:
|
|
*/
|
|
|
|
PWND xxxGNM_FindNextMnem(
|
|
PWND pwndDlg,
|
|
PWND pwnd,
|
|
WCHAR ch)
|
|
{
|
|
PWND pwndStart;
|
|
PWND pwndT;
|
|
WCHAR rgchText[256];
|
|
int i = 0;
|
|
TL tlpwndStart;
|
|
TL tlpwnd;
|
|
DWORD dwDlgCode;
|
|
|
|
CheckLock(pwndDlg);
|
|
CheckLock(pwnd);
|
|
|
|
/*
|
|
* Check if we are in a group box so we can find local mnemonics.
|
|
*/
|
|
|
|
pwndStart = _GetChildControl(pwndDlg, pwnd);
|
|
ThreadLock(pwndStart, &tlpwndStart);
|
|
|
|
while (TRUE) {
|
|
|
|
pwndT = _GetNextDlgGroupItem(pwndDlg, pwndStart, FALSE);
|
|
|
|
ThreadUnlock(&tlpwndStart);
|
|
|
|
i++;
|
|
if (pwndT == NULL || pwndT == pwnd || i > 60) {
|
|
|
|
/*
|
|
* If we have returned to our starting window or if we have gone
|
|
* through 60 iterations, let's exit. There are no local mnemonics
|
|
* that match. We have to check for 60 iterations (or so) because
|
|
* we run into problems with WS_GROUP not being properly defined in
|
|
* rc files that we never reach this same starting window again....
|
|
*/
|
|
break;
|
|
}
|
|
|
|
pwndStart = pwndT;
|
|
|
|
/*
|
|
* Only check for matching mnemonic if control doesn't want characters
|
|
* and control isn't a static control with SS_NOPREFIX
|
|
*/
|
|
ThreadLock(pwndStart, &tlpwndStart);
|
|
|
|
dwDlgCode = (DWORD)SendMessage(HWq(pwndT), WM_GETDLGCODE, 0, 0L);
|
|
if (!(dwDlgCode & DLGC_WANTCHARS) &&
|
|
(!(dwDlgCode & DLGC_STATIC) || !(pwndT->style & SS_NOPREFIX))) {
|
|
GetWindowText(HWq(pwndT), rgchText, sizeof(rgchText)/sizeof(WCHAR));
|
|
if (FindMnemChar(rgchText, ch, FALSE, TRUE) != 0) {
|
|
ThreadUnlock(&tlpwndStart);
|
|
return pwndT;
|
|
}
|
|
}
|
|
}
|
|
|
|
pwnd = pwndStart = _GetChildControl(pwndDlg, pwnd);
|
|
|
|
ThreadLock(pwnd, &tlpwnd);
|
|
while (TRUE) {
|
|
|
|
/*
|
|
* Start with next so we see multiples of same mnemonic.
|
|
*/
|
|
pwnd = _NextControl(pwndDlg, pwnd, TRUE);
|
|
|
|
ThreadUnlock(&tlpwnd);
|
|
ThreadLock(pwnd, &tlpwnd);
|
|
|
|
|
|
|
|
/*
|
|
* Only check for matching mnemonic if control doesn't want characters
|
|
* and control isn't a static control with SS_NOPREFIX
|
|
*/
|
|
dwDlgCode = (DWORD)SendMessage(HW(pwnd), WM_GETDLGCODE, 0, 0L);
|
|
if (!(dwDlgCode & DLGC_WANTCHARS) &&
|
|
(!(dwDlgCode & DLGC_STATIC) || !(pwnd->style & SS_NOPREFIX))) {
|
|
GetWindowText(HW(pwnd), rgchText, sizeof(rgchText)/sizeof(WCHAR));
|
|
if (FindMnemChar(rgchText, ch, FALSE, TRUE) != 0)
|
|
break;
|
|
}
|
|
|
|
if (pwnd == pwndStart) {
|
|
pwnd = NULL;
|
|
break;
|
|
}
|
|
}
|
|
ThreadUnlock(&tlpwnd);
|
|
|
|
return pwnd;
|
|
}
|
|
|
|
/*
|
|
* xxxGotoNextMnem
|
|
|
|
* History:
|
|
*/
|
|
|
|
PWND xxxGotoNextMnem(
|
|
PWND pwndDlg,
|
|
PWND pwnd,
|
|
WCHAR ch)
|
|
{
|
|
UINT code;
|
|
PWND pwndFirstFound = NULL;
|
|
int count = 0;
|
|
TL tlpwnd;
|
|
PWND pwndT;
|
|
HWND hwnd;
|
|
|
|
CheckLock(pwndDlg);
|
|
CheckLock(pwnd);
|
|
|
|
ThreadLock(pwnd, &tlpwnd);
|
|
|
|
/*
|
|
* Loop for a long time but not long enough so we hang...
|
|
*/
|
|
while (count < 256 * 2) {
|
|
|
|
/*
|
|
* If the dialog box doesn't has the mnemonic specified, return NULL.
|
|
*/
|
|
if ((pwnd = xxxGNM_FindNextMnem(pwndDlg, pwnd, ch)) == NULL) {
|
|
ThreadUnlock(&tlpwnd);
|
|
return NULL;
|
|
}
|
|
hwnd = HWq(pwnd);
|
|
|
|
ThreadUnlock(&tlpwnd);
|
|
ThreadLock(pwnd, &tlpwnd);
|
|
|
|
code = (UINT)SendMessage(hwnd, WM_GETDLGCODE, 0, 0L);
|
|
|
|
/*
|
|
* If a non-disabled static item, then jump ahead to nearest tabstop.
|
|
*/
|
|
if (code & DLGC_STATIC && !TestWF(pwnd, WFDISABLED)) {
|
|
pwndT = _GetNextDlgTabItem(pwndDlg, pwnd, FALSE);
|
|
|
|
/*
|
|
* If there is no other tab item, keep looking
|
|
*/
|
|
if (pwndT == NULL)
|
|
continue;
|
|
pwnd = pwndT;
|
|
hwnd = HWq(pwnd);
|
|
|
|
ThreadUnlock(&tlpwnd);
|
|
ThreadLock(pwnd, &tlpwnd);
|
|
|
|
/*
|
|
* I suppose we should do a getdlgcode here, but who is going to
|
|
* label a button with a static control? The setup guys, that's
|
|
* who... Also, generally useful for ownerdraw buttons which are
|
|
* labeled with a static text item.
|
|
*/
|
|
code = (UINT)SendMessage(hwnd, WM_GETDLGCODE, 0, 0L);
|
|
}
|
|
|
|
if (!TestWF(pwnd, WFDISABLED)) {
|
|
|
|
/*
|
|
* Is it a Pushbutton?
|
|
*/
|
|
if (!(code & DLGC_BUTTON)) {
|
|
|
|
/*
|
|
* No, simply give it the focus.
|
|
*/
|
|
DlgSetFocus(hwnd);
|
|
} else {
|
|
|
|
/*
|
|
* Yes, click it, but don't give it the focus.
|
|
*/
|
|
if ((code & DLGC_DEFPUSHBUTTON) || (code & DLGC_UNDEFPUSHBUTTON)) {
|
|
|
|
/*
|
|
* Flash the button.
|
|
*/
|
|
SendMessage(hwnd, BM_SETSTATE, TRUE, 0L);
|
|
|
|
/*
|
|
* Delay
|
|
*/
|
|
#ifdef LATER
|
|
// JimA - 2/19/92
|
|
// There oughta be a better way of doing this...
|
|
for (i = 0; i < 10000; i++)
|
|
;
|
|
#else
|
|
Sleep(1);
|
|
#endif
|
|
|
|
/*
|
|
* Un-Flash it.
|
|
*/
|
|
SendMessage(hwnd, BM_SETSTATE, FALSE, 0L);
|
|
|
|
/*
|
|
* Send the WM_COMMAND message.
|
|
*/
|
|
pwndT = REBASEPWND(pwnd, spwndParent);
|
|
SendMessage(HW(pwndT), WM_COMMAND, MAKELONG(PTR_TO_ID(pwnd->spmenu), BN_CLICKED), (LPARAM)hwnd);
|
|
ThreadUnlock(&tlpwnd);
|
|
return (PWND)1;
|
|
} else {
|
|
|
|
/*
|
|
* Because BM_CLICK processing will result in BN_CLICK msg,
|
|
* xxxSetFocus must be prevented from sending the same msg;
|
|
* Otherwise, it will notify parent twice!
|
|
* Fix for Bug #3024 -- SANKAR -- 09-22-89 --
|
|
*/
|
|
BOOL fIsNTButton;
|
|
PBUTN pbutn;
|
|
|
|
fIsNTButton = (pwnd->fnid == FNID_BUTTON);
|
|
if (fIsNTButton) {
|
|
pbutn = ((PBUTNWND)pwnd)->pbutn;
|
|
BUTTONSTATE(pbutn) |= BST_DONTCLICK;
|
|
} else {
|
|
RIPMSG0(RIP_WARNING, "xxxGotoNextMnem: fnid != FNID_BUTTON");
|
|
}
|
|
|
|
DlgSetFocus(hwnd);
|
|
|
|
if (fIsNTButton) {
|
|
BUTTONSTATE(pbutn) &= ~BST_DONTCLICK;
|
|
}
|
|
|
|
/*
|
|
* Send click message if button has a UNIQUE mnemonic
|
|
*/
|
|
if (xxxGNM_FindNextMnem(pwndDlg, pwnd, ch) == pwnd) {
|
|
SendMessage(hwnd, BM_CLICK, TRUE, 0L);
|
|
}
|
|
}
|
|
}
|
|
|
|
ThreadUnlock(&tlpwnd);
|
|
return pwnd;
|
|
} else {
|
|
|
|
/*
|
|
* Stop if we've looped back to the first item we checked
|
|
*/
|
|
if (pwnd == pwndFirstFound) {
|
|
ThreadUnlock(&tlpwnd);
|
|
return NULL;
|
|
}
|
|
|
|
if (pwndFirstFound == NULL)
|
|
pwndFirstFound = pwnd;
|
|
}
|
|
|
|
count++;
|
|
|
|
} /* Loop for a long time */
|
|
|
|
ThreadUnlock(&tlpwnd);
|
|
return NULL;
|
|
}
|