diff --git a/redo/uitask_windows.c b/redo/uitask_windows.c index ac8141b..5dad117 100644 --- a/redo/uitask_windows.c +++ b/redo/uitask_windows.c @@ -8,6 +8,36 @@ // this also assumes WC_TABCONTROL is longer than areaWindowClass #define NCLASSNAME (sizeof WC_TABCONTROL / sizeof WC_TABCONTROL[0]) +void uimsgloop_area(MSG *msg) +{ + // don't call TranslateMessage(); we do our own keyboard handling + DispatchMessage(msg); +} + +void uimsgloop_tab(HWND active, HWND focus, MSG *msg) +{ + BOOL hasChildren; + BOOL idm; + + // THIS BIT IS IMPORTANT: if the current tab has no children, then there will be no children left in the dialog to tab to, and IsDialogMessageW() will loop forever + hasChildren = SendMessageW(focus, msgTabCurrentTabHasChildren, 0, 0); + if (hasChildren) + tabEnterChildren(focus); + idm = IsDialogMessageW(active, msg); + if (hasChildren) + tabLeaveChildren(focus); + if (idm != 0) + return; + TranslateMessage(msg); + DispatchMessage(msg); +} + +void uimsgloop_else(MSG *msg) +{ + TranslateMessage(msg); + DispatchMessage(msg); +} + void uimsgloop(void) { MSG msg; @@ -15,8 +45,6 @@ void uimsgloop(void) HWND active, focus; WCHAR classchk[NCLASSNAME]; BOOL dodlgmessage; - BOOL istab; - BOOL idm; for (;;) { SetLastError(0); @@ -26,38 +54,34 @@ void uimsgloop(void) if (res == 0) // WM_QUIT break; active = GetActiveWindow(); - if (active != NULL) { - // bit of logic involved here: - // we don't want dialog messages passed into Areas, so we don't call IsDialogMessageW() there - // as for Tabs, we can't have both WS_TABSTOP and WS_EX_CONTROLPARENT set at the same time, so we hotswap the two styles to get the behavior we want - // theoretically we could use the class atom to avoid a wcscmp() - // however, raymond chen advises against this - http://blogs.msdn.com/b/oldnewthing/archive/2004/10/11/240744.aspx (and we're not in control of the Tab class, before you say anything) - // we could also theoretically just send msgAreaDefocuses directly, but what DefWindowProc() does to a WM_APP message is undocumented - dodlgmessage = TRUE; - istab = FALSE; - focus = GetFocus(); - if (focus != NULL) { - if (GetClassNameW(focus, classchk, NCLASSNAME) == 0) - xpanic("error getting name of focused window class for Area check", GetLastError()); - if (wcscmp(classchk, areaWindowClass) == 0) - dodlgmessage = FALSE; - else if (wcscmp(classchk, WC_TABCONTROL) == 0) - // THIS BIT IS IMPORTANT - // if the current tab has no children, then there will be no children left in the dialog to tab to, and IsDialogMessageW() will loop forever - istab = (BOOL) SendMessageW(focus, msgTabCurrentTabHasChildren, 0, 0); - } - if (dodlgmessage) { - if (istab) - tabEnterChildren(focus); - idm = IsDialogMessageW(active, &msg); - if (istab) - tabLeaveChildren(focus); - if (idm != 0) - continue; - } + if (active == NULL) { + uimsgloop_else(&msg); + continue; } - TranslateMessage(&msg); - DispatchMessageW(&msg); + + // bit of logic involved here: + // we don't want dialog messages passed into Areas, so we don't call IsDialogMessageW() there + // as for Tabs, we can't have both WS_TABSTOP and WS_EX_CONTROLPARENT set at the same time, so we hotswap the two styles to get the behavior we want + // theoretically we could use the class atom to avoid a wcscmp() + // however, raymond chen advises against this - http://blogs.msdn.com/b/oldnewthing/archive/2004/10/11/240744.aspx (and we're not in control of the Tab class, before you say anything) + // we could also theoretically just send msgAreaDefocuses directly, but what DefWindowProc() does to a WM_APP message is undocumented + focus = GetFocus(); + if (focus != NULL) { + if (GetClassNameW(focus, classchk, NCLASSNAME) == 0) + xpanic("error getting name of focused window class for Area check", GetLastError()); + if (wcscmp(classchk, areaWindowClass) == 0) { + uimsgloop_area(&msg); + continue; + } else if (wcscmp(classchk, WC_TABCONTROL) == 0) { + uimsgloop_tab(active, focus, &msg); + continue; + } + // else fall through + } + + if (IsDialogMessage(active, &msg) != 0) + continue; + uimsgloop_else(&msg); } }