Switch uiArea from using a custom message pump to using a message filter for input handling. This allows us to rewrite the dialog system to avoid needing to block ALL windows and set a proper parent window.
This commit is contained in:
parent
6bb659de4e
commit
3a5a4557ab
|
@ -511,6 +511,9 @@ keyFound:
|
||||||
return (*(a->ah->KeyEvent))(a->ah, a, &ke);
|
return (*(a->ah->KeyEvent))(a->ah, a, &ke);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We don't handle the standard Windows keyboard messages directly, to avoid both the dialog manager and TranslateMessage().
|
||||||
|
// Instead, we set up a message filter and do things there.
|
||||||
|
// That stuff is later in this file.
|
||||||
enum {
|
enum {
|
||||||
// start at 0x40 to avoid clobbering dialog messages
|
// start at 0x40 to avoid clobbering dialog messages
|
||||||
msgAreaKeyDown = WM_USER + 0x40,
|
msgAreaKeyDown = WM_USER + 0x40,
|
||||||
|
@ -662,33 +665,6 @@ static void minimumSize(uiWindowsControl *c, uiWindowsSizing *d, intmax_t *width
|
||||||
*height = 0;
|
*height = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO affect visibility properly
|
|
||||||
// TODO what did this mean
|
|
||||||
void processAreaMessage(HWND active, MSG *msg)
|
|
||||||
{
|
|
||||||
LRESULT handled;
|
|
||||||
|
|
||||||
handled = 0;
|
|
||||||
switch (msg->message) {
|
|
||||||
case WM_KEYDOWN:
|
|
||||||
case WM_SYSKEYDOWN:
|
|
||||||
handled = SendMessageW(msg->hwnd, msgAreaKeyDown, msg->wParam, msg->lParam);
|
|
||||||
break;
|
|
||||||
case WM_KEYUP:
|
|
||||||
case WM_SYSKEYUP:
|
|
||||||
handled = SendMessageW(msg->hwnd, msgAreaKeyUp, msg->wParam, msg->lParam);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (handled)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// don't call TranslateMessage(); we do our own keyboard handling
|
|
||||||
// TODO should we just return to the standard message loop?
|
|
||||||
if (IsDialogMessage(active, msg) != 0)
|
|
||||||
return;
|
|
||||||
DispatchMessageW(msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
ATOM registerAreaClass(HICON hDefaultIcon, HCURSOR hDefaultCursor)
|
ATOM registerAreaClass(HICON hDefaultIcon, HCURSOR hDefaultCursor)
|
||||||
{
|
{
|
||||||
WNDCLASSW wc;
|
WNDCLASSW wc;
|
||||||
|
@ -704,10 +680,59 @@ ATOM registerAreaClass(HICON hDefaultIcon, HCURSOR hDefaultCursor)
|
||||||
return RegisterClassW(&wc);
|
return RegisterClassW(&wc);
|
||||||
}
|
}
|
||||||
|
|
||||||
void unregisterAreaClass(void)
|
static HHOOK areaFilter;
|
||||||
|
|
||||||
|
// TODO affect visibility properly
|
||||||
|
// TODO what did this mean
|
||||||
|
static LRESULT CALLBACK areaFilterProc(int code, WPARAM wParam, LPARAM lParam)
|
||||||
{
|
{
|
||||||
|
MSG *msg = (MSG *) lParam;
|
||||||
|
LRESULT handled;
|
||||||
|
|
||||||
|
if (code < 0)
|
||||||
|
goto callNext;
|
||||||
|
|
||||||
|
// is the recipient an area?
|
||||||
|
if (windowClassOf(msg->hwnd, areaClass, NULL) != 0)
|
||||||
|
goto callNext; // nope
|
||||||
|
|
||||||
|
handled = 0;
|
||||||
|
switch (msg->message) {
|
||||||
|
case WM_KEYDOWN:
|
||||||
|
case WM_SYSKEYDOWN:
|
||||||
|
handled = SendMessageW(msg->hwnd, msgAreaKeyDown, msg->wParam, msg->lParam);
|
||||||
|
break;
|
||||||
|
case WM_KEYUP:
|
||||||
|
case WM_SYSKEYUP:
|
||||||
|
handled = SendMessageW(msg->hwnd, msgAreaKeyUp, msg->wParam, msg->lParam);
|
||||||
|
break;
|
||||||
|
// otherwise handled remains 0, as we didn't handle this
|
||||||
|
}
|
||||||
|
if (handled)
|
||||||
|
goto callNext;
|
||||||
|
|
||||||
|
// we handled it; discard the message so the dialog manager doesn't see it
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
callNext:
|
||||||
|
return CallNextHookEx(areaFilter, code, wParam, lParam);
|
||||||
|
}
|
||||||
|
|
||||||
|
int registerAreaFilter(void)
|
||||||
|
{
|
||||||
|
areaFilter = SetWindowsHookExW(WH_MSGFILTER,
|
||||||
|
areaFilterProc,
|
||||||
|
hInstance,
|
||||||
|
GetCurrentThreadId());
|
||||||
|
return areaFilter != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void unregisterArea(void)
|
||||||
|
{
|
||||||
|
if (UnhookWindowsHookEx(areaFilter) == 0)
|
||||||
|
logLastError("error unregistering uiArea message filter in unregisterArea()");
|
||||||
if (UnregisterClassW(areaClass, hInstance) == 0)
|
if (UnregisterClassW(areaClass, hInstance) == 0)
|
||||||
logLastError("error unregistering uiArea window class in unregisterAreaClass()");
|
logLastError("error unregistering uiArea window class in unregisterArea()");
|
||||||
}
|
}
|
||||||
|
|
||||||
void uiAreaUpdateScroll(uiArea *a)
|
void uiAreaUpdateScroll(uiArea *a)
|
||||||
|
|
|
@ -161,6 +161,8 @@ const char *uiInit(uiInitOptions *o)
|
||||||
|
|
||||||
if (registerAreaClass(hDefaultIcon, hDefaultCursor) == 0)
|
if (registerAreaClass(hDefaultIcon, hDefaultCursor) == 0)
|
||||||
return loadLastError("registering uiArea window class");
|
return loadLastError("registering uiArea window class");
|
||||||
|
if (registerAreaFilter() == 0)
|
||||||
|
return loadLastError("registering uiArea message filter");
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -168,7 +170,7 @@ const char *uiInit(uiInitOptions *o)
|
||||||
void uiUninit(void)
|
void uiUninit(void)
|
||||||
{
|
{
|
||||||
uninitMenus();
|
uninitMenus();
|
||||||
unregisterAreaClass();
|
unregisterArea();
|
||||||
uninitDraw();
|
uninitDraw();
|
||||||
CoUninitialize();
|
CoUninitialize();
|
||||||
uninitDialogHelper();
|
uninitDialogHelper();
|
||||||
|
|
|
@ -13,7 +13,7 @@ void uiMain(void)
|
||||||
{
|
{
|
||||||
MSG msg;
|
MSG msg;
|
||||||
int res;
|
int res;
|
||||||
HWND active, focus;
|
HWND active;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
SetLastError(0);
|
SetLastError(0);
|
||||||
|
@ -28,18 +28,8 @@ void uiMain(void)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// bit of logic involved here:
|
// TODO find documentation that says IsDialogMessage() calls CallMsgFilter() for us, because that's what's happening
|
||||||
// we don't want dialog messages passed into Areas, so we don't call IsDialogMessageW() there
|
// TODO rewrite this whole function to compensate
|
||||||
// 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
|
|
||||||
focus = GetFocus();
|
|
||||||
if (focus != NULL) {
|
|
||||||
switch (windowClassOf(focus, areaClass, NULL)) {
|
|
||||||
case 0: // uiArea
|
|
||||||
processAreaMessage(active, &msg);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// else fall through
|
|
||||||
}
|
|
||||||
|
|
||||||
if (IsDialogMessage(active, &msg) != 0)
|
if (IsDialogMessage(active, &msg) != 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -124,9 +124,9 @@ extern HWND newTabPage(void);
|
||||||
|
|
||||||
// area.c
|
// area.c
|
||||||
#define areaClass L"libui_uiAreaClass"
|
#define areaClass L"libui_uiAreaClass"
|
||||||
extern void processAreaMessage(HWND, MSG *);
|
|
||||||
extern ATOM registerAreaClass(HICON, HCURSOR);
|
extern ATOM registerAreaClass(HICON, HCURSOR);
|
||||||
extern void unregisterAreaClass(void);
|
extern int registerAreaFilter(void);
|
||||||
|
extern void unregisterArea(void);
|
||||||
|
|
||||||
// draw.c
|
// draw.c
|
||||||
extern HRESULT initDraw(void);
|
extern HRESULT initDraw(void);
|
||||||
|
|
Loading…
Reference in New Issue