Commit 4b67e6c7 authored by Alex Henrie's avatar Alex Henrie Committed by Alexandre Julliard

user32: Correct dialog focus behavior.

parent e3d27c42
......@@ -55,9 +55,9 @@ static DLGPROC DEFDLG_GetDlgProc( HWND hwnd )
* DEFDLG_SetFocus
*
* Set the focus to a control of the dialog, selecting the text if
* the control is an edit dialog.
* the control is an edit dialog that has DLGC_HASSETSEL.
*/
static void DEFDLG_SetFocus( HWND hwndDlg, HWND hwndCtrl )
static void DEFDLG_SetFocus( HWND hwndCtrl )
{
if (SendMessageW( hwndCtrl, WM_GETDLGCODE, 0, 0 ) & DLGC_HASSETSEL)
SendMessageW( hwndCtrl, EM_SETSEL, 0, -1 );
......@@ -83,7 +83,7 @@ static void DEFDLG_SaveFocus( HWND hwnd )
/***********************************************************************
* DEFDLG_RestoreFocus
*/
static void DEFDLG_RestoreFocus( HWND hwnd )
static void DEFDLG_RestoreFocus( HWND hwnd, BOOL justActivate )
{
DIALOGINFO *infoPtr;
......@@ -92,12 +92,19 @@ static void DEFDLG_RestoreFocus( HWND hwnd )
/* Don't set the focus back to controls if EndDialog is already called.*/
if (infoPtr->flags & DF_END) return;
if (!IsWindow(infoPtr->hwndFocus) || infoPtr->hwndFocus == hwnd) {
if (justActivate) return;
/* If no saved focus control exists, set focus to the first visible,
non-disabled, WS_TABSTOP control in the dialog */
infoPtr->hwndFocus = GetNextDlgTabItem( hwnd, 0, FALSE );
/* If there are no WS_TABSTOP controls, set focus to the first visible,
non-disabled control in the dialog */
if (!infoPtr->hwndFocus) infoPtr->hwndFocus = GetNextDlgGroupItem( hwnd, 0, FALSE );
if (!IsWindow( infoPtr->hwndFocus )) return;
}
DEFDLG_SetFocus( hwnd, infoPtr->hwndFocus );
if (justActivate)
SetFocus( infoPtr->hwndFocus );
else
DEFDLG_SetFocus( infoPtr->hwndFocus );
/* This used to set infoPtr->hwndFocus to NULL for no apparent reason,
sometimes losing focus when receiving WM_SETFOCUS messages. */
......@@ -250,12 +257,12 @@ static LRESULT DEFDLG_Proc( HWND hwnd, UINT msg, WPARAM wParam,
return DefWindowProcA( hwnd, msg, wParam, lParam );
case WM_ACTIVATE:
if (wParam) DEFDLG_RestoreFocus( hwnd );
if (wParam) DEFDLG_RestoreFocus( hwnd, TRUE );
else DEFDLG_SaveFocus( hwnd );
return 0;
case WM_SETFOCUS:
DEFDLG_RestoreFocus( hwnd );
DEFDLG_RestoreFocus( hwnd, FALSE );
return 0;
case DM_SETDEFID:
......@@ -280,7 +287,7 @@ static LRESULT DEFDLG_Proc( HWND hwnd, UINT msg, WPARAM wParam,
HWND hwndDest = (HWND)wParam;
if (!lParam)
hwndDest = GetNextDlgTabItem(hwnd, GetFocus(), wParam);
if (hwndDest) DEFDLG_SetFocus( hwnd, hwndDest );
if (hwndDest) DEFDLG_SetFocus( hwndDest );
DEFDLG_SetDefButton( hwnd, dlgInfo, hwndDest );
}
return 0;
......
......@@ -828,7 +828,7 @@ static const char * GetHwndString(HWND hw)
return "unknown handle";
}
static void test_initial_focus(void)
static void test_focus(void)
{
/* Test 1:
* This test intentionally returns FALSE in response to WM_INITDIALOG
......@@ -900,6 +900,8 @@ static void test_initial_focus(void)
HRSRC hResource;
HANDLE hTemplate;
DLGTEMPLATE* pTemplate;
HWND hTextbox;
DWORD selectionStart = 0xdead, selectionEnd = 0xbeef;
hResource = FindResourceA(g_hinst,"FOCUS_TEST_DIALOG", RT_DIALOG);
hTemplate = LoadResource(g_hinst, hResource);
......@@ -912,6 +914,20 @@ static void test_initial_focus(void)
ok ((g_hwndInitialFocusT1 == 0),
"Focus should not be set for an invisible DS_CONTROL dialog %p.\n", g_hwndInitialFocusT1);
/* Also make sure that WM_SETFOCUS selects the textbox's text */
hTextbox = GetDlgItem(hDlg, 200);
SendMessage(hTextbox, WM_SETTEXT, 0, (LPARAM)"Hello world");
SendMessage(hDlg, WM_SETFOCUS, 0, 0);
SendMessage(hTextbox, EM_GETSEL, (WPARAM)&selectionStart, (LPARAM)&selectionEnd);
ok(selectionStart == 0 && selectionEnd == 11, "Text selection after WM_SETFOCUS is [%i, %i) expected [0, 11)\n", selectionStart, selectionEnd);
/* but WM_ACTIVATE does not */
SendMessage(hTextbox, EM_SETSEL, 0, 0);
SendMessage(hDlg, WM_ACTIVATE, WA_ACTIVE, 0);
SendMessage(hTextbox, EM_GETSEL, (WPARAM)&selectionStart, (LPARAM)&selectionEnd);
ok(selectionStart == 0 && selectionEnd == 0, "Text selection after WM_ACTIVATE is [%i, %i) expected [0, 0)\n", selectionStart, selectionEnd);
DestroyWindow(hDlg);
}
......@@ -929,13 +945,25 @@ static void test_initial_focus(void)
pTemplate = LockResource(hTemplate);
hDlg = CreateDialogIndirectParamA(g_hinst, pTemplate, NULL, focusDlgWinProc, 0);
g_hwndInitialFocusT1 = GetFocus();
ok(hDlg != 0, "Failed to create test dialog.\n");
hLabel = GetDlgItem(hDlg, 200);
ok (hDlg != 0, "Failed to create test dialog.\n");
ok ((g_hwndInitialFocusT1 == hLabel),
"Focus should have been set to the first control, expected (%p) got (%p).\n",
hLabel, g_hwndInitialFocusT1);
ok(GetFocus() == hLabel, "Focus not set to label, focus=%p dialog=%p label=%p\n", GetFocus(), hDlg, hLabel);
DestroyWindow(hDlg);
/* Also check focus after WM_ACTIVATE and WM_SETFOCUS */
hDlg = CreateDialogIndirectParamA(g_hinst, pTemplate, NULL, NULL, 0);
ok(hDlg != 0, "Failed to create test dialog.\n");
hLabel = GetDlgItem(hDlg, 200);
SetFocus(NULL);
SendMessage(hDlg, WM_ACTIVATE, WA_ACTIVE, 0);
ok(GetFocus() == NULL, "Focus set on WM_ACTIVATE, focus=%p dialog=%p label=%p\n", GetFocus(), hDlg, hLabel);
SetFocus(NULL);
SendMessage(hDlg, WM_SETFOCUS, 0, 0);
ok(GetFocus() == hLabel, "Focus not set to label on WM_SETFOCUS, focus=%p dialog=%p label=%p\n", GetFocus(), hDlg, hLabel);
DestroyWindow(hDlg);
}
......@@ -1404,7 +1432,7 @@ START_TEST(dialog)
test_GetNextDlgItem();
test_IsDialogMessage();
test_WM_NEXTDLGCTL();
test_initial_focus();
test_focus();
test_GetDlgItem();
test_GetDlgItemText();
test_DialogBoxParamA();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment