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.
779 lines
24 KiB
779 lines
24 KiB
/***************************************************************************\
|
|
*
|
|
* DLGMGR2.C
|
|
*
|
|
* Copyright (c) 1985 - 1999, Microsoft Corporation
|
|
*
|
|
* Dialog Management Routines
|
|
*
|
|
* ??-???-???? mikeke Ported from Win 3.0 sources
|
|
* 12-Feb-1991 mikeke Added Revalidation code
|
|
\***************************************************************************/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
/***************************************************************************\
|
|
* xxxRemoveDefaultButton
|
|
*
|
|
* Scan through all the controls in the dialog box and remove the default
|
|
* button style from any button that has it. This is done since at times we
|
|
* do not know who has the default button.
|
|
*
|
|
* History:
|
|
*
|
|
* Bug 19449 - joejo
|
|
*
|
|
* Stop infinite loop when pwnd != pwndStart but pwnd == pwnd after calling
|
|
* _NextControl!
|
|
\***************************************************************************/
|
|
|
|
void xxxRemoveDefaultButton(
|
|
PWND pwndRoot,
|
|
PWND pwndStart)
|
|
{
|
|
UINT code;
|
|
PWND pwnd;
|
|
PWND pwndDup;
|
|
TL tlpwnd;
|
|
|
|
CheckLock(pwndRoot);
|
|
CheckLock(pwndStart);
|
|
|
|
if (!pwndStart || TestWF(pwndStart, WEFCONTROLPARENT))
|
|
pwndStart = _NextControl(pwndRoot, NULL, CWP_SKIPINVISIBLE | CWP_SKIPDISABLED);
|
|
else
|
|
pwndStart = _GetChildControl(pwndRoot, pwndStart);
|
|
|
|
if (!pwndStart)
|
|
return;
|
|
|
|
pwnd = pwndStart;
|
|
do {
|
|
pwndDup = pwnd;
|
|
|
|
ThreadLock(pwnd, &tlpwnd);
|
|
|
|
code = (UINT)SendMessage(HWq(pwnd), WM_GETDLGCODE, 0, 0L);
|
|
|
|
if (code & DLGC_DEFPUSHBUTTON) {
|
|
SendMessage(HWq(pwnd), BM_SETSTYLE, BS_PUSHBUTTON, (LONG)TRUE);
|
|
}
|
|
|
|
pwnd = _NextControl(pwndRoot, pwnd, 0);
|
|
|
|
ThreadUnlock(&tlpwnd);
|
|
|
|
} while (pwnd && (pwnd != pwndStart) && (pwnd != pwndDup));
|
|
|
|
#if DBG
|
|
if (pwnd && (pwnd != pwndStart) && (pwnd != pwndDup)) {
|
|
RIPMSG0(RIP_WARNING, "xxxRemoveDefaultButton bailing potential infinite loop!");
|
|
}
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* xxxCheckDefPushButton
|
|
*
|
|
* History:
|
|
\***************************************************************************/
|
|
|
|
void xxxCheckDefPushButton(
|
|
PWND pwndDlg,
|
|
HWND hwndOldFocus,
|
|
HWND hwndNewFocus)
|
|
{
|
|
PWND pwndNewFocus;
|
|
PWND pwndOldFocus;
|
|
TL tlpwndT;
|
|
PWND pwndT;
|
|
UINT codeNewFocus = 0;
|
|
UINT styleT;
|
|
LONG lT;
|
|
int id;
|
|
|
|
if (hwndNewFocus)
|
|
pwndNewFocus = ValidateHwnd(hwndNewFocus);
|
|
else
|
|
pwndNewFocus = NULL;
|
|
|
|
if (hwndOldFocus)
|
|
pwndOldFocus = ValidateHwnd(hwndOldFocus);
|
|
else
|
|
pwndOldFocus = NULL;
|
|
|
|
CheckLock(pwndDlg);
|
|
CheckLock(pwndNewFocus);
|
|
CheckLock(pwndOldFocus);
|
|
|
|
if (pwndNewFocus)
|
|
{
|
|
// Do nothing if clicking on dialog background or recursive dialog
|
|
// background.
|
|
if (TestWF(pwndNewFocus, WEFCONTROLPARENT))
|
|
return;
|
|
|
|
codeNewFocus = (UINT)SendMessage(hwndNewFocus, WM_GETDLGCODE, 0, 0L);
|
|
}
|
|
|
|
if (SAMEWOWHANDLE(hwndOldFocus, hwndNewFocus)) {
|
|
//
|
|
// NEW FOR 4.0:
|
|
//
|
|
// There is a very common frustrating scenario for ISVs who try to
|
|
// set the default ID. Our dialog manager assumes that if a push
|
|
// button has the focus, it is the default button also. As such
|
|
// it passes in the focus window to this routine. If someone tries
|
|
// to change the focus or set the def ID such that they reside with
|
|
// two different push buttons, the double-default-push button case
|
|
// will result shortly.
|
|
//
|
|
// As such, for 4.0 dialogs, we will go check the def ID and see if
|
|
// is the same as hwndOldFocus' ID. If not, then we will find IT
|
|
// and use that dude as hwndOldFocus
|
|
//
|
|
if (codeNewFocus & DLGC_UNDEFPUSHBUTTON)
|
|
{
|
|
if (TestWF(pwndDlg, WFWIN40COMPAT) && hwndOldFocus)
|
|
{
|
|
lT = (LONG)SendMessage(HWq(pwndDlg), DM_GETDEFID, 0, 0L);
|
|
id = (HIWORD(lT) == DC_HASDEFID ? LOWORD(lT) : IDOK);
|
|
lT = MAKELONG(id, 0);
|
|
|
|
if (lT != PtrToLong(pwndNewFocus->spmenu))
|
|
{
|
|
if (pwndOldFocus = _FindDlgItem(pwndDlg, lT))
|
|
{
|
|
hwndOldFocus = HW(pwndOldFocus);
|
|
if (SendMessage(hwndOldFocus, WM_GETDLGCODE, 0, 0L) & DLGC_DEFPUSHBUTTON)
|
|
{
|
|
xxxRemoveDefaultButton(pwndDlg, pwndOldFocus);
|
|
goto SetNewDefault;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
SendMessage(hwndNewFocus, BM_SETSTYLE, BS_DEFPUSHBUTTON, (LONG)TRUE);
|
|
}
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* If the focus is changing to or from a pushbutton, then remove the
|
|
* default style from the current default button
|
|
*/
|
|
if ((hwndOldFocus != NULL && (SendMessage(hwndOldFocus, WM_GETDLGCODE,
|
|
0, 0) & (DLGC_DEFPUSHBUTTON | DLGC_UNDEFPUSHBUTTON))) ||
|
|
(hwndNewFocus != NULL &&
|
|
(codeNewFocus & (DLGC_DEFPUSHBUTTON | DLGC_UNDEFPUSHBUTTON)))) {
|
|
xxxRemoveDefaultButton(pwndDlg, pwndNewFocus);
|
|
}
|
|
|
|
SetNewDefault:
|
|
/*
|
|
* If moving to a button, make that button the default.
|
|
*/
|
|
if (codeNewFocus & DLGC_UNDEFPUSHBUTTON) {
|
|
SendMessage(hwndNewFocus, BM_SETSTYLE, BS_DEFPUSHBUTTON, (LONG)TRUE);
|
|
} else {
|
|
|
|
/*
|
|
* Otherwise, make sure the original default button is default
|
|
* and no others.
|
|
*/
|
|
|
|
/*
|
|
* Get the original default button handle
|
|
*/
|
|
lT = (LONG)SendMessage(HWq(pwndDlg), DM_GETDEFID, 0, 0L);
|
|
id = (HIWORD(lT) == DC_HASDEFID ? LOWORD(lT) : IDOK);
|
|
pwndT = _FindDlgItem(pwndDlg, id);
|
|
|
|
if (pwndT == NULL)
|
|
return;
|
|
ThreadLockAlways(pwndT, &tlpwndT);
|
|
|
|
/*
|
|
* If it already has the default button style, do nothing.
|
|
*/
|
|
if ((styleT = (UINT)SendMessage(HWq(pwndT), WM_GETDLGCODE, 0, 0L)) & DLGC_DEFPUSHBUTTON) {
|
|
ThreadUnlock(&tlpwndT);
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Also check to make sure it is really a button.
|
|
*/
|
|
if (!(styleT & DLGC_UNDEFPUSHBUTTON)) {
|
|
ThreadUnlock(&tlpwndT);
|
|
return;
|
|
}
|
|
|
|
if (!TestWF(pwndT, WFDISABLED)) {
|
|
SendMessage(HWq(pwndT), BM_SETSTYLE, BS_DEFPUSHBUTTON, (LONG)TRUE);
|
|
}
|
|
ThreadUnlock(&tlpwndT);
|
|
}
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* IsDialogMessage (API)
|
|
*
|
|
* History:
|
|
\***************************************************************************/
|
|
|
|
|
|
FUNCLOG2(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, IsDialogMessageA, HWND, hwndDlg, LPMSG, lpmsg)
|
|
BOOL IsDialogMessageA(
|
|
HWND hwndDlg,
|
|
LPMSG lpmsg)
|
|
{
|
|
WPARAM wParamSaved = lpmsg->wParam;
|
|
BOOL bRet;
|
|
|
|
switch (lpmsg->message) {
|
|
#ifdef FE_SB // IsDialogMessageA()
|
|
case WM_CHAR:
|
|
case EM_SETPASSWORDCHAR:
|
|
/*
|
|
* BUILD_DBCS_MESSAGE_TO_CLIENTW_FROM_CLIENTA() macro will return TRUE
|
|
* for DBCS leadbyte message everytime, then we check there is some
|
|
* possibility the return value become FALSE, here.
|
|
*
|
|
* These code originally come from IsDialogMessageW().
|
|
*/
|
|
if (IS_DBCS_ENABLED()) {
|
|
PWND pwndDlg, pwnd;
|
|
TL tlpwndDlg;
|
|
BOOL fLockDlg = FALSE;
|
|
|
|
if ((pwndDlg = ValidateHwndNoRip(hwndDlg)) == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (lpmsg->hwnd == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
pwnd = ValidateHwnd(lpmsg->hwnd);
|
|
//
|
|
// THIS IS FOR MFC.
|
|
//
|
|
// This solves many problems with apps that use MFC but want to take
|
|
// advantage of DS_CONTROL. MFC blindly passes in child dialogs sometimes
|
|
// to IsDialogMessage, which can mess up tabbing etc.
|
|
//
|
|
if (TestWF(pwndDlg, WEFCONTROLPARENT) && TestWF(pwndDlg, WFCHILD)) {
|
|
pwndDlg = GetParentDialog(pwndDlg);
|
|
ThreadLock(pwndDlg, &tlpwndDlg);
|
|
fLockDlg = TRUE;
|
|
hwndDlg = HWq(pwndDlg);
|
|
}
|
|
|
|
if (pwnd != pwndDlg && !_IsChild(pwndDlg, pwnd)) {
|
|
if (fLockDlg)
|
|
ThreadUnlock(&tlpwndDlg);
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* Build DBCS-aware message.
|
|
*/
|
|
BUILD_DBCS_MESSAGE_TO_CLIENTW_FROM_CLIENTA(lpmsg->message,lpmsg->wParam,TRUE);
|
|
|
|
/*
|
|
* Fall through.....
|
|
*/
|
|
}
|
|
#else
|
|
case WM_CHAR:
|
|
case EM_SETPASSWORDCHAR:
|
|
#endif // FE_SB
|
|
case WM_CHARTOITEM:
|
|
case WM_DEADCHAR:
|
|
case WM_SYSCHAR:
|
|
case WM_SYSDEADCHAR:
|
|
case WM_MENUCHAR:
|
|
#ifdef FE_IME // IsDialogMessageA()
|
|
case WM_IME_CHAR:
|
|
case WM_IME_COMPOSITION:
|
|
#endif // FE_IME
|
|
|
|
RtlMBMessageWParamCharToWCS(lpmsg->message, &lpmsg->wParam);
|
|
}
|
|
|
|
bRet = IsDialogMessageW(hwndDlg, lpmsg);
|
|
|
|
/*
|
|
* Restore the original ANSI char.
|
|
*/
|
|
lpmsg->wParam = wParamSaved;
|
|
return bRet;
|
|
}
|
|
|
|
|
|
FUNCLOG2(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, IsDialogMessageW, HWND, hwndDlg, LPMSG, lpMsg)
|
|
BOOL IsDialogMessageW(
|
|
HWND hwndDlg,
|
|
LPMSG lpMsg)
|
|
{
|
|
PWND pwndDlg;
|
|
PWND pwnd;
|
|
PWND pwnd2;
|
|
HWND hwnd2;
|
|
HWND hwndFocus;
|
|
int iOK;
|
|
BOOL fBack;
|
|
UINT code;
|
|
LONG lT;
|
|
TL tlpwnd;
|
|
TL tlpwndDlg;
|
|
BOOL fLockDlg = FALSE;
|
|
TL tlpwnd2;
|
|
WORD langID;
|
|
|
|
langID = PRIMARYLANGID(LANGIDFROMLCID(GetUserDefaultLCID()));
|
|
|
|
if ((pwndDlg = ValidateHwndNoRip(hwndDlg)) == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
CheckLock(pwndDlg);
|
|
|
|
/*
|
|
* If this is a synchronous-only message (takes a pointer in wParam or
|
|
* lParam), then don't allow this message to go through since those
|
|
* parameters have not been thunked, and are pointing into outer-space
|
|
* (which would case exceptions to occur).
|
|
*
|
|
* (This api is only called in the context of a message loop, and you
|
|
* don't get synchronous-only messages in a message loop).
|
|
*/
|
|
if (TESTSYNCONLYMESSAGE(lpMsg->message, lpMsg->wParam)) {
|
|
/*
|
|
* Fail if 32 bit app is calling.
|
|
*/
|
|
if (!(GetClientInfo()->dwTIFlags & TIF_16BIT)) {
|
|
RIPERR0(ERROR_MESSAGE_SYNC_ONLY, RIP_WARNING, "IsDialogMessage: must be sync only");
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* For wow apps, allow it to go through (for compatibility). Change
|
|
* the message id so our code doesn't understand the message - wow
|
|
* will get the message and strip out this bit before dispatching
|
|
* the message to the application.
|
|
*/
|
|
lpMsg->message |= MSGFLAG_WOW_RESERVED;
|
|
}
|
|
|
|
if (CallMsgFilter(lpMsg, MSGF_DIALOGBOX))
|
|
return TRUE;
|
|
|
|
if (lpMsg->hwnd == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
pwnd = ValidateHwnd(lpMsg->hwnd);
|
|
//
|
|
// THIS IS FOR MFC.
|
|
//
|
|
// This solves many problems with apps that use MFC but want to take
|
|
// advantage of DS_CONTROL. MFC blindly passes in child dialogs sometimes
|
|
// to IsDialogMessage, which can mess up tabbing etc.
|
|
//
|
|
if (TestWF(pwndDlg, WEFCONTROLPARENT) && TestWF(pwndDlg, WFCHILD)) {
|
|
pwndDlg = GetParentDialog(pwndDlg);
|
|
ThreadLock(pwndDlg, &tlpwndDlg);
|
|
fLockDlg = TRUE;
|
|
hwndDlg = HWq(pwndDlg);
|
|
}
|
|
|
|
if (pwnd != pwndDlg && !_IsChild(pwndDlg, pwnd)) {
|
|
if (fLockDlg)
|
|
ThreadUnlock(&tlpwndDlg);
|
|
return FALSE;
|
|
}
|
|
ThreadLock(pwnd, &tlpwnd);
|
|
|
|
fBack = FALSE;
|
|
iOK = IDCANCEL;
|
|
switch (lpMsg->message) {
|
|
case WM_LBUTTONDOWN:
|
|
|
|
/*
|
|
* Move the default button styles around on button clicks in the
|
|
* same way as TABs.
|
|
*/
|
|
if ((pwnd != pwndDlg) && ((hwndFocus = GetFocus()) != NULL)) {
|
|
xxxCheckDefPushButton(pwndDlg, hwndFocus, lpMsg->hwnd);
|
|
}
|
|
break;
|
|
|
|
case WM_SYSCHAR:
|
|
|
|
/*
|
|
* If no control has focus, and Alt not down, then ignore.
|
|
*/
|
|
if ((GetFocus() == NULL) && (GetKeyState(VK_MENU) >= 0)) {
|
|
if (lpMsg->wParam == VK_RETURN && TestWF(pwnd, WFMINIMIZED)) {
|
|
|
|
/*
|
|
* If this is an iconic dialog box window and the user hits
|
|
* return, send the message off to DefWindowProc so that it
|
|
* can be restored. Especially useful for apps whose top
|
|
* level window is a dialog box.
|
|
*/
|
|
goto CallDefWindowProcAndReturnTrue;
|
|
} else {
|
|
NtUserMessageBeep(0);
|
|
}
|
|
|
|
ThreadUnlock(&tlpwnd);
|
|
if (fLockDlg)
|
|
ThreadUnlock(&tlpwndDlg);
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
* If alt+menuchar, process as menu.
|
|
*/
|
|
if (lpMsg->wParam == MENUSYSMENU) {
|
|
DefWindowProcWorker(pwndDlg, lpMsg->message, lpMsg->wParam,
|
|
lpMsg->lParam, FALSE);
|
|
ThreadUnlock(&tlpwnd);
|
|
if (fLockDlg)
|
|
ThreadUnlock(&tlpwndDlg);
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
*** FALL THRU **
|
|
*/
|
|
|
|
case WM_CHAR:
|
|
|
|
/*
|
|
* Ignore chars sent to the dialog box (rather than the control).
|
|
*/
|
|
if (pwnd == pwndDlg) {
|
|
ThreadUnlock(&tlpwnd);
|
|
if (fLockDlg)
|
|
ThreadUnlock(&tlpwndDlg);
|
|
return TRUE;
|
|
}
|
|
|
|
code = (UINT)SendMessage(lpMsg->hwnd, WM_GETDLGCODE, lpMsg->wParam,
|
|
(LPARAM)lpMsg);
|
|
|
|
/*
|
|
* If the control wants to process the message, then don't check for
|
|
* possible mnemonic key.
|
|
*/
|
|
if ((lpMsg->message == WM_CHAR) && (code & (DLGC_WANTCHARS | DLGC_WANTMESSAGE)))
|
|
break;
|
|
|
|
/* If the control wants tabs, then don't let tab fall thru here
|
|
*/
|
|
if ((lpMsg->wParam == VK_TAB) && (code & DLGC_WANTTAB))
|
|
break;
|
|
|
|
|
|
/*
|
|
* HACK ALERT
|
|
*
|
|
* If ALT is held down (i.e., SYSCHARs), then ALWAYS do mnemonic
|
|
* processing. If we do away with SYSCHARS, then we should
|
|
* check key state of ALT instead.
|
|
*/
|
|
|
|
/*
|
|
* Space is not a valid mnemonic, but it IS the char that toggles
|
|
* button states. Don't look for it as a mnemonic or we will
|
|
* beep when it is typed....
|
|
*/
|
|
if (lpMsg->wParam == VK_SPACE) {
|
|
ThreadUnlock(&tlpwnd);
|
|
if (fLockDlg)
|
|
ThreadUnlock(&tlpwndDlg);
|
|
return TRUE;
|
|
}
|
|
|
|
if (!(pwnd2 = xxxGotoNextMnem(pwndDlg, pwnd, (WCHAR)lpMsg->wParam))) {
|
|
|
|
if (code & DLGC_WANTMESSAGE)
|
|
break;
|
|
|
|
/*
|
|
* No mnemonic could be found so we will send the sys char over
|
|
* to xxxDefWindowProc so that any menu bar on the dialog box is
|
|
* handled properly.
|
|
*/
|
|
if (lpMsg->message == WM_SYSCHAR) {
|
|
CallDefWindowProcAndReturnTrue:
|
|
DefWindowProcWorker(pwndDlg, lpMsg->message, lpMsg->wParam,
|
|
lpMsg->lParam, FALSE);
|
|
|
|
ThreadUnlock(&tlpwnd);
|
|
if (fLockDlg)
|
|
ThreadUnlock(&tlpwndDlg);
|
|
return TRUE;
|
|
}
|
|
NtUserMessageBeep(0);
|
|
} else {
|
|
|
|
/*
|
|
* pwnd2 is 1 if the mnemonic took us to a pushbutton. We
|
|
* don't change the default button status here since doing this
|
|
* doesn't change the focus.
|
|
*/
|
|
if (pwnd2 != (PWND)1) {
|
|
ThreadLockAlways(pwnd2, &tlpwnd2);
|
|
xxxCheckDefPushButton(pwndDlg, lpMsg->hwnd, HWq(pwnd2));
|
|
ThreadUnlock(&tlpwnd2);
|
|
}
|
|
}
|
|
|
|
ThreadUnlock(&tlpwnd);
|
|
if (fLockDlg)
|
|
ThreadUnlock(&tlpwndDlg);
|
|
return TRUE;
|
|
|
|
case WM_SYSKEYDOWN:
|
|
/*
|
|
* If Alt is down, deal with keyboard cues
|
|
*/
|
|
if ((HIWORD(lpMsg->lParam) & SYS_ALTERNATE) && TEST_KbdCuesPUSIF) {
|
|
if (TestWF(pwnd, WEFPUIFOCUSHIDDEN) || (TestWF(pwnd, WEFPUIACCELHIDDEN))) {
|
|
SendMessageWorker(pwndDlg, WM_CHANGEUISTATE,
|
|
MAKEWPARAM(UIS_CLEAR, UISF_HIDEACCEL | UISF_HIDEFOCUS), 0, FALSE);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case WM_KEYDOWN:
|
|
code = (UINT)SendMessage(lpMsg->hwnd, WM_GETDLGCODE, lpMsg->wParam,
|
|
(LPARAM)lpMsg);
|
|
if (code & (DLGC_WANTALLKEYS | DLGC_WANTMESSAGE))
|
|
break;
|
|
|
|
switch (lpMsg->wParam) {
|
|
case VK_TAB:
|
|
if (code & DLGC_WANTTAB)
|
|
break;
|
|
pwnd2 = _GetNextDlgTabItem(pwndDlg, pwnd,
|
|
(GetKeyState(VK_SHIFT) & 0x8000));
|
|
|
|
if (TEST_KbdCuesPUSIF) {
|
|
if (TestWF(pwnd, WEFPUIFOCUSHIDDEN)) {
|
|
SendMessageWorker(pwndDlg, WM_CHANGEUISTATE,
|
|
MAKEWPARAM(UIS_CLEAR, UISF_HIDEFOCUS), 0, FALSE);
|
|
}
|
|
}
|
|
|
|
if (pwnd2 != NULL) {
|
|
hwnd2 = HWq(pwnd2);
|
|
ThreadLockAlways(pwnd2, &tlpwnd2);
|
|
DlgSetFocus(hwnd2);
|
|
xxxCheckDefPushButton(pwndDlg, lpMsg->hwnd, hwnd2);
|
|
ThreadUnlock(&tlpwnd2);
|
|
}
|
|
ThreadUnlock(&tlpwnd);
|
|
if (fLockDlg)
|
|
ThreadUnlock(&tlpwndDlg);
|
|
return TRUE;
|
|
|
|
/*
|
|
* For Arabic and Hebrew locales the arrow keys are reversed. Also reverse them if
|
|
* the dialog is RTL mirrored.
|
|
*/
|
|
case VK_LEFT:
|
|
if ((((langID == LANG_ARABIC) || (langID == LANG_HEBREW)) && TestWF(pwndDlg,WEFRTLREADING))
|
|
^ (!!TestWF(pwndDlg, WEFLAYOUTRTL))) {
|
|
|
|
goto DoKeyStuff;
|
|
}
|
|
case VK_UP:
|
|
fBack = TRUE;
|
|
goto DoKeyStuff;
|
|
|
|
/*
|
|
*** FALL THRU **
|
|
*/
|
|
case VK_RIGHT:
|
|
if ((((langID == LANG_ARABIC) || (langID == LANG_HEBREW)) && TestWF(pwndDlg,WEFRTLREADING))
|
|
^ (!!TestWF(pwndDlg, WEFLAYOUTRTL))) {
|
|
|
|
fBack = TRUE;
|
|
}
|
|
case VK_DOWN:
|
|
DoKeyStuff:
|
|
if (code & DLGC_WANTARROWS)
|
|
break;
|
|
|
|
if (TEST_KbdCuesPUSIF) {
|
|
if (TestWF(pwnd, WEFPUIFOCUSHIDDEN)) {
|
|
SendMessageWorker(pwndDlg, WM_CHANGEUISTATE,
|
|
MAKEWPARAM(UIS_CLEAR, UISF_HIDEFOCUS), 0, FALSE);
|
|
}
|
|
}
|
|
|
|
pwnd2 = _GetNextDlgGroupItem(pwndDlg, pwnd, fBack);
|
|
if (pwnd2 == NULL) {
|
|
ThreadUnlock(&tlpwnd);
|
|
if (fLockDlg)
|
|
ThreadUnlock(&tlpwndDlg);
|
|
return TRUE;
|
|
}
|
|
hwnd2 = HWq(pwnd2);
|
|
ThreadLockAlways(pwnd2, &tlpwnd2);
|
|
|
|
code = (UINT)SendMessage(hwnd2, WM_GETDLGCODE, lpMsg->wParam,
|
|
(LPARAM)lpMsg);
|
|
|
|
/*
|
|
* We are just moving the focus rect around! So, do not send
|
|
* BN_CLICK messages, when WM_SETFOCUSing. Fix for Bug
|
|
* #4358.
|
|
*/
|
|
if (code & (DLGC_UNDEFPUSHBUTTON | DLGC_DEFPUSHBUTTON)) {
|
|
PBUTN pbutn;
|
|
BOOL fIsNTButton = IS_BUTTON(pwnd2);
|
|
if (fIsNTButton) {
|
|
pbutn = ((PBUTNWND)pwnd2)->pbutn;
|
|
BUTTONSTATE(pbutn) |= BST_DONTCLICK;
|
|
}
|
|
DlgSetFocus(hwnd2);
|
|
if (fIsNTButton) {
|
|
BUTTONSTATE(pbutn) &= ~BST_DONTCLICK;
|
|
}
|
|
xxxCheckDefPushButton(pwndDlg, lpMsg->hwnd, hwnd2);
|
|
} else if (code & DLGC_RADIOBUTTON) {
|
|
DlgSetFocus(hwnd2);
|
|
xxxCheckDefPushButton(pwndDlg, lpMsg->hwnd, hwnd2);
|
|
if (TestWF(pwnd2, BFTYPEMASK) == LOBYTE(BS_AUTORADIOBUTTON)) {
|
|
|
|
/*
|
|
* So that auto radio buttons get clicked on
|
|
*/
|
|
if (!SendMessage(hwnd2, BM_GETCHECK, 0, 0L)) {
|
|
SendMessage(hwnd2, BM_CLICK, TRUE, 0L);
|
|
}
|
|
}
|
|
} else if (!(code & DLGC_STATIC)) {
|
|
DlgSetFocus(hwnd2);
|
|
xxxCheckDefPushButton(pwndDlg, lpMsg->hwnd, hwnd2);
|
|
}
|
|
ThreadUnlock(&tlpwnd2);
|
|
ThreadUnlock(&tlpwnd);
|
|
if (fLockDlg)
|
|
ThreadUnlock(&tlpwndDlg);
|
|
return TRUE;
|
|
|
|
case VK_EXECUTE:
|
|
case VK_RETURN:
|
|
|
|
/*
|
|
* Guy pressed return - if button with focus is
|
|
* defpushbutton, return its ID. Otherwise, return id
|
|
* of original defpushbutton.
|
|
*/
|
|
if (!(hwndFocus = GetFocus()))
|
|
code = 0;
|
|
else
|
|
{
|
|
code = (WORD)(DWORD)SendMessage(hwndFocus, WM_GETDLGCODE,
|
|
0, 0L);
|
|
}
|
|
|
|
if (code & DLGC_DEFPUSHBUTTON)
|
|
{
|
|
iOK = GetDlgCtrlID(hwndFocus);
|
|
pwnd2 = ValidateHwnd(hwndFocus);
|
|
goto HaveWindow;
|
|
}
|
|
else
|
|
{
|
|
lT = (LONG)SendMessage(hwndDlg, DM_GETDEFID, 0, 0L);
|
|
iOK = MAKELONG(
|
|
(HIWORD(lT)==DC_HASDEFID ? LOWORD(lT) : IDOK),
|
|
0);
|
|
}
|
|
// FALL THRU
|
|
|
|
case VK_ESCAPE:
|
|
case VK_CANCEL:
|
|
|
|
/*
|
|
* Make sure button is not disabled.
|
|
*/
|
|
pwnd2 = _FindDlgItem(pwndDlg, iOK);
|
|
HaveWindow:
|
|
if (pwnd2 != NULL && TestWF(pwnd2, WFDISABLED)) {
|
|
NtUserMessageBeep(0);
|
|
} else {
|
|
SendMessage(hwndDlg, WM_COMMAND,
|
|
MAKELONG(iOK, BN_CLICKED), (LPARAM)HW(pwnd2));
|
|
}
|
|
|
|
ThreadUnlock(&tlpwnd);
|
|
if (fLockDlg)
|
|
ThreadUnlock(&tlpwndDlg);
|
|
return TRUE;
|
|
}
|
|
break;
|
|
}
|
|
|
|
ThreadUnlock(&tlpwnd);
|
|
if (fLockDlg)
|
|
ThreadUnlock(&tlpwndDlg);
|
|
|
|
TranslateMessage(lpMsg);
|
|
DispatchMessage(lpMsg);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
*
|
|
* FindDlgItem32()
|
|
*
|
|
* Given a dialog, finds the window with the given ID anywhere w/in the
|
|
* descendant chain.
|
|
*
|
|
\***************************************************************************/
|
|
|
|
PWND _FindDlgItem(PWND pwndParent, DWORD id)
|
|
{
|
|
PWND pwndChild;
|
|
PWND pwndOrig;
|
|
|
|
// QUICK TRY:
|
|
pwndChild = _GetDlgItem(pwndParent, id);
|
|
if (pwndChild || !TestWF(pwndParent, WFWIN40COMPAT))
|
|
return(pwndChild);
|
|
|
|
pwndOrig = _NextControl(pwndParent, NULL, CWP_SKIPINVISIBLE);
|
|
if (pwndOrig == pwndParent)
|
|
return(NULL);
|
|
|
|
pwndChild = pwndOrig;
|
|
|
|
// VerifyWindow(pwndChild);
|
|
|
|
do
|
|
{
|
|
if (PtrToUlong(pwndChild->spmenu) == id)
|
|
return(pwndChild);
|
|
|
|
pwndChild = _NextControl(pwndParent, pwndChild, CWP_SKIPINVISIBLE);
|
|
}
|
|
while (pwndChild && (pwndChild != pwndOrig));
|
|
|
|
return(NULL);
|
|
}
|