Another thread is created to execute the tests, for SetThreadDesktop to
succeed consistently. It seems to fail spuriously if it is called from
a thread that already created some windows before.
This shows that rawinput messages may be dispatched across desktops,
but only if the subscribing process has a window in the input desktop,
and it is the foreground process (even if the target window may be in
another desktop).
Signed-off-by: Rémi Bernon <rbernon(a)codeweavers.com>
---
v4: What v3 should have been, queue_rawinput_message really simplified
now, the only logic kept is here to implement RIDEV_INPUTSINK, although
it will also be useful in the future, to dispatch HID rawinput from the
winedevice processes.
dlls/user32/tests/input.c | 119 ++++++++++++++++++++++++++++++++++++--
1 file changed, 113 insertions(+), 6 deletions(-)
diff --git a/dlls/user32/tests/input.c b/dlls/user32/tests/input.c
index 9ec829860af..01733317b2b 100644
--- a/dlls/user32/tests/input.c
+++ b/dlls/user32/tests/input.c
@@ -50,6 +50,7 @@
#include "windef.h"
#include "winbase.h"
+#include "wingdi.h"
#include "winuser.h"
#include "winnls.h"
#include "ddk/hidsdi.h"
@@ -60,6 +61,8 @@
static HWND hWndTest;
static LONG timetag = 0x10000000;
+#define DESKTOP_ALL_ACCESS 0x01ff
+
static struct {
LONG last_key_down;
LONG last_key_up;
@@ -1891,6 +1894,11 @@ struct rawinput_test rawinput_tests[] =
{ TRUE, TRUE, RIDEV_EXINPUTSINK, FALSE, FALSE, FALSE, /* todos: */ FALSE, FALSE, FALSE },
{ TRUE, TRUE, RIDEV_EXINPUTSINK, FALSE, TRUE, FALSE, /* todos: */ FALSE, TRUE, FALSE },
+
+ /* cross-desktop foreground tests */
+ { TRUE, FALSE, 0, FALSE, FALSE, FALSE, /* todos: */ FALSE, FALSE, FALSE },
+ { TRUE, TRUE, 0, FALSE, TRUE, TRUE, /* todos: */ FALSE, FALSE, FALSE },
+ { TRUE, TRUE, RIDEV_INPUTSINK, FALSE, FALSE, FALSE, /* todos: */ FALSE, FALSE, FALSE },
};
static void rawinput_test_process(void)
@@ -1927,6 +1935,7 @@ static void rawinput_test_process(void)
case 11:
case 12:
case 13:
+ case 16:
GetCursorPos(&pt);
hwnd = CreateWindowA("static", "static", WS_VISIBLE | WS_POPUP,
@@ -1960,6 +1969,9 @@ static void rawinput_test_process(void)
rawinput_test_received_raw = FALSE;
rawinput_test_received_rawfg = FALSE;
+ /* fallthrough */
+ case 14:
+ case 15:
if (i != 8) mouse_event(MOUSEEVENTF_MOVE, 5, 0, 0, 0);
empty_message_queue();
break;
@@ -1998,19 +2010,87 @@ static void rawinput_test_process(void)
struct rawinput_test_thread_params
{
+ HDESK desk;
HANDLE ready;
HANDLE start;
HANDLE done;
};
+static DWORD WINAPI rawinput_test_desk_thread(void *arg)
+{
+ struct rawinput_test_thread_params *params = arg;
+ RAWINPUTDEVICE raw_devices[1];
+ DWORD ret;
+ POINT pt;
+ HWND hwnd = NULL;
+ MSG msg;
+ int i;
+
+ ok( SetThreadDesktop( params->desk ), "SetThreadDesktop failed\n" );
+
+ for (i = 14; i < ARRAY_SIZE(rawinput_tests); ++i)
+ {
+ WaitForSingleObject(params->ready, INFINITE);
+ ResetEvent(params->ready);
+
+ switch (i)
+ {
+ case 14:
+ case 15:
+ case 16:
+ GetCursorPos(&pt);
+
+ hwnd = CreateWindowA("static", "static", WS_VISIBLE | WS_POPUP,
+ pt.x - 50, pt.y - 50, 100, 100, 0, NULL, NULL, NULL);
+ ok(hwnd != 0, "CreateWindow failed\n");
+ SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONG_PTR)rawinput_wndproc);
+ empty_message_queue();
+
+ /* FIXME: Try to workaround X11/Win32 focus inconsistencies and
+ * make the window visible and foreground as hard as possible. */
+ ShowWindow(hwnd, SW_SHOW);
+ SetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE);
+ SetForegroundWindow(hwnd);
+ UpdateWindow(hwnd);
+ empty_message_queue();
+
+ raw_devices[0].usUsagePage = 0x01;
+ raw_devices[0].usUsage = 0x02;
+ raw_devices[0].dwFlags = rawinput_tests[i].register_flags;
+ raw_devices[0].hwndTarget = rawinput_tests[i].register_window ? hwnd : 0;
+
+ rawinput_test_received_legacy = FALSE;
+ rawinput_test_received_raw = FALSE;
+ rawinput_test_received_rawfg = FALSE;
+
+ SetLastError(0xdeadbeef);
+ ret = RegisterRawInputDevices(raw_devices, ARRAY_SIZE(raw_devices), sizeof(RAWINPUTDEVICE));
+ ok(ret, "%d: RegisterRawInputDevices failed\n", i);
+ ok(GetLastError() == 0xdeadbeef, "%d: RegisterRawInputDevices returned %08x\n", i, GetLastError());
+ break;
+ }
+
+ SetEvent(params->start);
+
+ while (MsgWaitForMultipleObjects(1, ¶ms->done, FALSE, INFINITE, QS_ALLINPUT) != WAIT_OBJECT_0)
+ while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
+
+ ResetEvent(params->done);
+ if (hwnd) DestroyWindow(hwnd);
+ }
+
+ return 0;
+}
+
static DWORD WINAPI rawinput_test_thread(void *arg)
{
struct rawinput_test_thread_params *params = arg;
+ HANDLE thread;
POINT pt;
HWND hwnd = NULL;
int i;
- for (i = 0; i < ARRAY_SIZE(rawinput_tests); ++i)
+ for (i = 0; i < 14; ++i)
{
WaitForSingleObject(params->ready, INFINITE);
ResetEvent(params->ready);
@@ -2046,6 +2126,11 @@ static DWORD WINAPI rawinput_test_thread(void *arg)
if (hwnd) DestroyWindow(hwnd);
}
+ thread = CreateThread(NULL, 0, rawinput_test_desk_thread, params, 0, NULL);
+ ok(thread != NULL, "CreateThread failed\n");
+ WaitForSingleObject(thread, INFINITE);
+ CloseHandle(thread);
+
return 0;
}
@@ -2063,6 +2148,9 @@ static void test_rawinput(const char* argv0)
char path[MAX_PATH];
int i;
+ params.desk = CreateDesktopA( "rawinput_test_desktop", NULL, NULL, 0, DESKTOP_ALL_ACCESS, NULL );
+ ok( params.desk != NULL, "CreateDesktopA failed, last error: %u\n", GetLastError() );
+
params.ready = CreateEventA(NULL, FALSE, FALSE, NULL);
ok(params.ready != NULL, "CreateEvent failed\n");
@@ -2103,7 +2191,8 @@ static void test_rawinput(const char* argv0)
hwnd = CreateWindowA("static", "static", WS_VISIBLE | WS_POPUP,
pt.x - 50, pt.y - 50, 100, 100, 0, NULL, NULL, NULL);
ok(hwnd != 0, "CreateWindow failed\n");
- SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONG_PTR)rawinput_wndproc);
+ if (i != 14 && i != 15 && i != 16)
+ SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONG_PTR)rawinput_wndproc);
empty_message_queue();
/* FIXME: Try to workaround X11/Win32 focus inconsistencies and
@@ -2135,14 +2224,30 @@ static void test_rawinput(const char* argv0)
ok(!skipped, "%d: RegisterRawInputDevices failed: %u\n", i, GetLastError());
}
- SetEvent(process_ready);
- WaitForSingleObject(process_start, INFINITE);
- ResetEvent(process_start);
-
SetEvent(params.ready);
WaitForSingleObject(params.start, INFINITE);
ResetEvent(params.start);
+ /* we need the main window to be over the other thread window, as although
+ * it is in another desktop, it will receive the messages directly otherwise */
+ switch (i)
+ {
+ case 14:
+ case 15:
+ SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE);
+ SetForegroundWindow(hwnd);
+ empty_message_queue();
+
+ rawinput_test_received_legacy = FALSE;
+ rawinput_test_received_raw = FALSE;
+ rawinput_test_received_rawfg = FALSE;
+ break;
+ }
+
+ SetEvent(process_ready);
+ WaitForSingleObject(process_start, INFINITE);
+ ResetEvent(process_start);
+
if (i <= 3 || i == 8) mouse_event(MOUSEEVENTF_MOVE, 5, 0, 0, 0);
empty_message_queue();
@@ -2192,6 +2297,8 @@ static void test_rawinput(const char* argv0)
CloseHandle(params.start);
CloseHandle(params.ready);
CloseHandle(thread);
+
+ CloseDesktop(params.desk);
}
static void test_key_map(void)
--
2.27.0