This tests basic functionality by injecting mouse event and checking the number of each messages received.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com ---
v2:
* Various test tweaks, use BOOL test variables, simplify wndproc by removing early returns, add some comments on the window creation calls.
* Add some more cross-process tests, checking behavior when multiple processes register for rawinput messages, add RIDEV_EXINPUTSINK flag tests (but not implemented).
* Avoid introducing dead code in patch #7.
dlls/user32/tests/input.c | 135 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 135 insertions(+)
diff --git a/dlls/user32/tests/input.c b/dlls/user32/tests/input.c index 913fabfbd85..172bcc3c8dd 100644 --- a/dlls/user32/tests/input.c +++ b/dlls/user32/tests/input.c @@ -1819,6 +1819,140 @@ static void test_RegisterRawInputDevices(void) DestroyWindow(hwnd); }
+static BOOL rawinput_test_received_legacy; +static BOOL rawinput_test_received_raw; +static BOOL rawinput_test_received_rawfg; + +static LRESULT CALLBACK rawinput_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) +{ + UINT ret, raw_size; + RAWINPUT raw; + + if (msg == WM_INPUT) + { + todo_wine_if(rawinput_test_received_raw) + ok(!rawinput_test_received_raw, "Unexpected spurious WM_INPUT message.\n"); + ok(wparam == RIM_INPUT || wparam == RIM_INPUTSINK, "Unexpected wparam: %lu\n", wparam); + + rawinput_test_received_raw = TRUE; + if (wparam == RIM_INPUT) rawinput_test_received_rawfg = TRUE; + + ret = GetRawInputData((HRAWINPUT)lparam, RID_INPUT, NULL, &raw_size, sizeof(RAWINPUTHEADER)); + ok(ret == 0, "GetRawInputData failed\n"); + ok(raw_size <= sizeof(raw), "Unexpected rawinput data size: %u", raw_size); + + raw_size = sizeof(raw); + ret = GetRawInputData((HRAWINPUT)lparam, RID_INPUT, &raw, &raw_size, sizeof(RAWINPUTHEADER)); + ok(ret > 0 && ret != (UINT)-1, "GetRawInputData failed\n"); + ok(raw.header.dwType == RIM_TYPEMOUSE, "Unexpected rawinput type: %u\n", raw.header.dwType); + + ok(!(raw.data.mouse.usFlags & MOUSE_MOVE_ABSOLUTE), "Unexpected absolute rawinput motion\n"); + ok(!(raw.data.mouse.usFlags & MOUSE_VIRTUAL_DESKTOP), "Unexpected virtual desktop rawinput motion\n"); + } + + if (msg == WM_MOUSEMOVE) rawinput_test_received_legacy = TRUE; + + return DefWindowProcA(hwnd, msg, wparam, lparam); +} + +struct rawinput_test +{ + BOOL register_device; + BOOL register_window; + DWORD register_flags; + BOOL expect_legacy; + BOOL expect_raw; + BOOL expect_rawfg; + BOOL todo_legacy; + BOOL todo_raw; + BOOL todo_rawfg; +}; + +struct rawinput_test rawinput_tests[] = +{ + { FALSE, FALSE, 0, TRUE, FALSE, FALSE, /* todos: */ FALSE, FALSE, FALSE }, + { TRUE, FALSE, 0, TRUE, TRUE, TRUE, /* todos: */ FALSE, FALSE, FALSE }, + { TRUE, TRUE, 0, TRUE, TRUE, TRUE, /* todos: */ FALSE, FALSE, FALSE }, + { TRUE, TRUE, RIDEV_NOLEGACY, FALSE, TRUE, TRUE, /* todos: */ TRUE, FALSE, FALSE }, +}; + +static void test_rawinput(void) +{ + RAWINPUTDEVICE raw_devices[1]; + DWORD ret; + POINT pt, newpt; + HWND hwnd; + int i; + + SetCursorPos(100, 100); + empty_message_queue(); + + for (i = 0; i < ARRAY_SIZE(rawinput_tests); ++i) + { + 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(); + + rawinput_test_received_legacy = FALSE; + rawinput_test_received_raw = FALSE; + rawinput_test_received_rawfg = FALSE; + + 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; + + if (rawinput_tests[i].register_device) + { + 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()); + } + + mouse_event(MOUSEEVENTF_MOVE, 5, 0, 0, 0); + empty_message_queue(); + + todo_wine_if(rawinput_tests[i].todo_legacy) + ok(rawinput_test_received_legacy == rawinput_tests[i].expect_legacy, + "%d: %sexpected WM_MOUSEMOVE message\n", i, rawinput_tests[i].expect_legacy ? "" : "un"); + todo_wine_if(rawinput_tests[i].todo_raw) + ok(rawinput_test_received_raw == rawinput_tests[i].expect_raw, + "%d: %sexpected WM_INPUT message\n", i, rawinput_tests[i].expect_raw ? "" : "un"); + todo_wine_if(rawinput_tests[i].todo_rawfg) + ok(rawinput_test_received_rawfg == rawinput_tests[i].expect_rawfg, + "%d: %sexpected RIM_INPUT message\n", i, rawinput_tests[i].expect_rawfg ? "" : "un"); + + GetCursorPos(&newpt); + ok((newpt.x - pt.x) == 5 || (newpt.x - pt.x) == 4, "%d: Unexpected cursor movement\n", i); + + if (rawinput_tests[i].register_device) + { + raw_devices[0].dwFlags = RIDEV_REMOVE; + raw_devices[0].hwndTarget = 0; + + 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()); + } + + DestroyWindow(hwnd); + } +} + static void test_key_map(void) { HKL kl = GetKeyboardLayout(0); @@ -3034,6 +3168,7 @@ START_TEST(input) test_OemKeyScan(); test_GetRawInputData(); test_RegisterRawInputDevices(); + test_rawinput();
if(pGetMouseMovePointsEx) test_GetMouseMovePointsEx();
The rawinput messages are received on the target window if is from the same process as the foreground window, it doesn't need to be the foreground window itself, or use RIDEV_INPUTSINK.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/user32/tests/input.c | 86 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 85 insertions(+), 1 deletion(-)
diff --git a/dlls/user32/tests/input.c b/dlls/user32/tests/input.c index 172bcc3c8dd..5fdc3ff36db 100644 --- a/dlls/user32/tests/input.c +++ b/dlls/user32/tests/input.c @@ -1874,16 +1874,87 @@ struct rawinput_test rawinput_tests[] = { TRUE, FALSE, 0, TRUE, TRUE, TRUE, /* todos: */ FALSE, FALSE, FALSE }, { TRUE, TRUE, 0, TRUE, TRUE, TRUE, /* todos: */ FALSE, FALSE, FALSE }, { TRUE, TRUE, RIDEV_NOLEGACY, FALSE, TRUE, TRUE, /* todos: */ TRUE, FALSE, FALSE }, + + /* same-process foreground tests */ + { TRUE, FALSE, 0, FALSE, FALSE, FALSE, /* todos: */ FALSE, FALSE, FALSE }, + { TRUE, TRUE, 0, FALSE, TRUE, TRUE, /* todos: */ FALSE, FALSE, FALSE }, };
+struct rawinput_test_thread_params +{ + HANDLE ready; + HANDLE start; + HANDLE done; +}; + +static DWORD WINAPI rawinput_test_thread(void *arg) +{ + struct rawinput_test_thread_params *params = arg; + POINT pt; + HWND hwnd = NULL; + int i; + + for (i = 0; i < ARRAY_SIZE(rawinput_tests); ++i) + { + WaitForSingleObject(params->ready, INFINITE); + ResetEvent(params->ready); + + switch (i) + { + case 4: + case 5: + 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"); + 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, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE); + SetForegroundWindow(hwnd); + UpdateWindow(hwnd); + empty_message_queue(); + + mouse_event(MOUSEEVENTF_MOVE, 5, 0, 0, 0); + empty_message_queue(); + break; + } + + SetEvent(params->start); + + WaitForSingleObject(params->done, INFINITE); + ResetEvent(params->done); + if (hwnd) DestroyWindow(hwnd); + } + + return 0; +} + static void test_rawinput(void) { + struct rawinput_test_thread_params params; RAWINPUTDEVICE raw_devices[1]; + HANDLE thread; DWORD ret; POINT pt, newpt; HWND hwnd; int i;
+ params.ready = CreateEventA(NULL, FALSE, FALSE, NULL); + ok(params.ready != NULL, "CreateEvent failed\n"); + + params.start = CreateEventA(NULL, FALSE, FALSE, NULL); + ok(params.start != NULL, "CreateEvent failed\n"); + + params.done = CreateEventA(NULL, FALSE, FALSE, NULL); + ok(params.done != NULL, "CreateEvent failed\n"); + + thread = CreateThread(NULL, 0, rawinput_test_thread, ¶ms, 0, NULL); + ok(thread != NULL, "CreateThread failed\n"); + SetCursorPos(100, 100); empty_message_queue();
@@ -1922,9 +1993,15 @@ static void test_rawinput(void) ok(GetLastError() == 0xdeadbeef, "%d: RegisterRawInputDevices returned %08x\n", i, GetLastError()); }
- mouse_event(MOUSEEVENTF_MOVE, 5, 0, 0, 0); + SetEvent(params.ready); + WaitForSingleObject(params.start, INFINITE); + ResetEvent(params.start); + + if (i <= 3) mouse_event(MOUSEEVENTF_MOVE, 5, 0, 0, 0); empty_message_queue();
+ SetEvent(params.done); + todo_wine_if(rawinput_tests[i].todo_legacy) ok(rawinput_test_received_legacy == rawinput_tests[i].expect_legacy, "%d: %sexpected WM_MOUSEMOVE message\n", i, rawinput_tests[i].expect_legacy ? "" : "un"); @@ -1951,6 +2028,13 @@ static void test_rawinput(void)
DestroyWindow(hwnd); } + + WaitForSingleObject(thread, INFINITE); + + CloseHandle(params.done); + CloseHandle(params.start); + CloseHandle(params.ready); + CloseHandle(thread); }
static void test_key_map(void)
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=73432
Your paranoid android.
=== w8adm (32 bit report) ===
user32: input.c:2517: Test failed: expected WM_NCHITTEST message input.c:2518: Test failed: expected WM_RBUTTONDOWN message input.c:2519: Test failed: expected WM_RBUTTONUP message input.c:2548: Test failed: expected WM_LBUTTONDOWN message input.c:2549: Test failed: expected WM_LBUTTONUP message input.c:2602: Test failed: expected loop with WM_NCHITTEST messages input.c:2655: Test failed: expected WM_LBUTTONDOWN message input.c:2656: Test failed: expected WM_LBUTTONUP message
=== debiant (build log) ===
Task: WineTest did not produce the wow32 report
Rawinput messages are not received anymore if the foreground window is from another process. Using RIDEV_INPUTSINK makes it possible to receive them again, but with RIM_INPUTSINK flag.
When multiple processes register for rawinput messages, the foreground process will receive the message, as well as any other that registerd with RIM_INPUTSINK flag, including when the foreground process itself did.
Currently the messages may be received correctly, but that depends on where the input events are generated, so add another test case with messages sent from the test process, and validate that nothing should be received.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/user32/tests/input.c | 168 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 162 insertions(+), 6 deletions(-)
diff --git a/dlls/user32/tests/input.c b/dlls/user32/tests/input.c index 5fdc3ff36db..66d421896f2 100644 --- a/dlls/user32/tests/input.c +++ b/dlls/user32/tests/input.c @@ -1878,8 +1878,119 @@ struct rawinput_test rawinput_tests[] = /* same-process foreground tests */ { TRUE, FALSE, 0, FALSE, FALSE, FALSE, /* todos: */ FALSE, FALSE, FALSE }, { TRUE, TRUE, 0, FALSE, TRUE, TRUE, /* todos: */ FALSE, FALSE, FALSE }, + + /* cross-process foreground tests */ + { TRUE, TRUE, 0, FALSE, FALSE, FALSE, /* todos: */ FALSE, FALSE, FALSE }, + { TRUE, TRUE, RIDEV_INPUTSINK, FALSE, TRUE, FALSE, /* todos: */ FALSE, TRUE, FALSE }, + { TRUE, TRUE, 0, FALSE, FALSE, FALSE, /* todos: */ FALSE, TRUE, TRUE }, + + /* multi-process rawinput tests */ + { TRUE, TRUE, 0, FALSE, FALSE, FALSE, /* todos: */ FALSE, FALSE, FALSE }, + { TRUE, TRUE, RIDEV_INPUTSINK, FALSE, TRUE, FALSE, /* todos: */ FALSE, TRUE, FALSE }, + { TRUE, TRUE, RIDEV_INPUTSINK, FALSE, TRUE, FALSE, /* todos: */ FALSE, TRUE, FALSE }, };
+static void rawinput_test_process(void) +{ + RAWINPUTDEVICE raw_devices[1]; + HANDLE ready, start, done; + DWORD ret; + POINT pt; + HWND hwnd = NULL; + MSG msg; + int i; + + ready = OpenEventA(EVENT_ALL_ACCESS, FALSE, "rawinput_test_process_ready"); + ok(ready != 0, "OpenEventA failed, error: %u\n", GetLastError()); + + start = OpenEventA(EVENT_ALL_ACCESS, FALSE, "rawinput_test_process_start"); + ok(start != 0, "OpenEventA failed, error: %u\n", GetLastError()); + + done = OpenEventA(EVENT_ALL_ACCESS, FALSE, "rawinput_test_process_done"); + ok(done != 0, "OpenEventA failed, error: %u\n", GetLastError()); + + for (i = 0; i < ARRAY_SIZE(rawinput_tests); ++i) + { + WaitForSingleObject(ready, INFINITE); + ResetEvent(ready); + + switch (i) + { + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + GetCursorPos(&pt); + + hwnd = CreateWindowA("static", "static", WS_VISIBLE | WS_POPUP, + pt.x - 50, pt.y - 50, 100, 100, 0, NULL, NULL, NULL); + SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONG_PTR)rawinput_wndproc); + ok(hwnd != 0, "CreateWindow failed\n"); + 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, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE); + SetForegroundWindow(hwnd); + UpdateWindow(hwnd); + empty_message_queue(); + + if (i == 9 || i == 10 || i == 11) + { + raw_devices[0].usUsagePage = 0x01; + raw_devices[0].usUsage = 0x02; + raw_devices[0].dwFlags = i == 11 ? RIDEV_INPUTSINK : 0; + raw_devices[0].hwndTarget = i == 11 ? hwnd : 0; + + 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()); + } + + rawinput_test_received_legacy = FALSE; + rawinput_test_received_raw = FALSE; + rawinput_test_received_rawfg = FALSE; + + if (i != 8) mouse_event(MOUSEEVENTF_MOVE, 5, 0, 0, 0); + empty_message_queue(); + break; + } + + SetEvent(start); + + while (MsgWaitForMultipleObjects(1, &done, FALSE, INFINITE, QS_ALLINPUT) != WAIT_OBJECT_0) + while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg); + + ResetEvent(done); + + if (i == 9 || i == 10 || i == 11) + { + raw_devices[0].dwFlags = RIDEV_REMOVE; + raw_devices[0].hwndTarget = 0; + + ok(rawinput_test_received_legacy, "%d: foreground process expected WM_MOUSEMOVE message\n", i); + ok(rawinput_test_received_raw, "%d: foreground process expected WM_INPUT message\n", i); + ok(rawinput_test_received_rawfg, "%d: foreground process expected RIM_INPUT message\n", i); + + 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()); + } + + if (hwnd) DestroyWindow(hwnd); + } + + WaitForSingleObject(ready, INFINITE); + CloseHandle(done); + CloseHandle(start); + CloseHandle(ready); +} + struct rawinput_test_thread_params { HANDLE ready; @@ -1933,14 +2044,17 @@ static DWORD WINAPI rawinput_test_thread(void *arg) return 0; }
-static void test_rawinput(void) +static void test_rawinput(const char* argv0) { struct rawinput_test_thread_params params; + PROCESS_INFORMATION process_info; RAWINPUTDEVICE raw_devices[1]; - HANDLE thread; + STARTUPINFOA startup_info; + HANDLE thread, process_ready, process_start, process_done; DWORD ret; POINT pt, newpt; HWND hwnd; + char path[MAX_PATH]; int i;
params.ready = CreateEventA(NULL, FALSE, FALSE, NULL); @@ -1955,6 +2069,24 @@ static void test_rawinput(void) thread = CreateThread(NULL, 0, rawinput_test_thread, ¶ms, 0, NULL); ok(thread != NULL, "CreateThread failed\n");
+ process_ready = CreateEventA(NULL, FALSE, FALSE, "rawinput_test_process_ready"); + ok(process_ready != NULL, "CreateEventA failed\n"); + + process_start = CreateEventA(NULL, FALSE, FALSE, "rawinput_test_process_start"); + ok(process_start != NULL, "CreateEventA failed\n"); + + process_done = CreateEventA(NULL, FALSE, FALSE, "rawinput_test_process_done"); + ok(process_done != NULL, "CreateEventA failed\n"); + + memset(&startup_info, 0, sizeof(startup_info)); + startup_info.cb = sizeof(startup_info); + startup_info.dwFlags = STARTF_USESHOWWINDOW; + startup_info.wShowWindow = SW_SHOWNORMAL; + + sprintf(path, "%s input rawinput_test", argv0); + ret = CreateProcessA(NULL, path, NULL, NULL, TRUE, 0, NULL, NULL, &startup_info, &process_info ); + ok(ret, "CreateProcess "%s" failed err %u.\n", path, GetLastError()); + SetCursorPos(100, 100); empty_message_queue();
@@ -1989,17 +2121,24 @@ static void test_rawinput(void) { 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()); + ok(ret || broken(rawinput_tests[i].register_flags == RIDEV_EXINPUTSINK), /* < vista */ + "%d: RegisterRawInputDevices failed\n", i); + ok(GetLastError() == 0xdeadbeef || broken(rawinput_tests[i].register_flags == RIDEV_EXINPUTSINK), /* < vista */ + "%d: RegisterRawInputDevices returned %08x\n", i, GetLastError()); }
+ SetEvent(process_ready); + WaitForSingleObject(process_start, INFINITE); + ResetEvent(process_start); + SetEvent(params.ready); WaitForSingleObject(params.start, INFINITE); ResetEvent(params.start);
- if (i <= 3) mouse_event(MOUSEEVENTF_MOVE, 5, 0, 0, 0); + if (i <= 3 || i == 8) mouse_event(MOUSEEVENTF_MOVE, 5, 0, 0, 0); empty_message_queue();
+ SetEvent(process_done); SetEvent(params.done);
todo_wine_if(rawinput_tests[i].todo_legacy) @@ -2029,6 +2168,14 @@ static void test_rawinput(void) DestroyWindow(hwnd); }
+ SetEvent(process_ready); + winetest_wait_child_process(process_info.hProcess); + CloseHandle(process_info.hProcess); + CloseHandle(process_info.hThread); + CloseHandle(process_done); + CloseHandle(process_start); + CloseHandle(process_ready); + WaitForSingleObject(thread, INFINITE);
CloseHandle(params.done); @@ -3230,11 +3377,20 @@ static void test_UnregisterDeviceNotification(void)
START_TEST(input) { + char **argv; + int argc; POINT pos;
init_function_pointers(); GetCursorPos( &pos );
+ argc = winetest_get_mainargs(&argv); + if (argc >= 3 && strcmp(argv[2], "rawinput_test") == 0) + { + rawinput_test_process(); + return; + } + test_Input_blackbox(); test_Input_whitebox(); test_Input_unicode(); @@ -3252,7 +3408,7 @@ START_TEST(input) test_OemKeyScan(); test_GetRawInputData(); test_RegisterRawInputDevices(); - test_rawinput(); + test_rawinput(argv[0]);
if(pGetMouseMovePointsEx) test_GetMouseMovePointsEx();
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=73433
Your paranoid android.
=== debiant (build log) ===
Task: WineTest did not produce the wow32 report
When RIM_EXINPUTSINK is used, messages are received in background only if the foreground process didn't register for rawinput messages itself.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/user32/tests/input.c | 48 +++++++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 19 deletions(-)
diff --git a/dlls/user32/tests/input.c b/dlls/user32/tests/input.c index 66d421896f2..9ec829860af 100644 --- a/dlls/user32/tests/input.c +++ b/dlls/user32/tests/input.c @@ -1888,6 +1888,9 @@ struct rawinput_test rawinput_tests[] = { TRUE, TRUE, 0, FALSE, FALSE, FALSE, /* todos: */ FALSE, FALSE, FALSE }, { TRUE, TRUE, RIDEV_INPUTSINK, FALSE, TRUE, FALSE, /* todos: */ FALSE, TRUE, FALSE }, { TRUE, TRUE, RIDEV_INPUTSINK, FALSE, TRUE, FALSE, /* todos: */ FALSE, TRUE, FALSE }, + + { TRUE, TRUE, RIDEV_EXINPUTSINK, FALSE, FALSE, FALSE, /* todos: */ FALSE, FALSE, FALSE }, + { TRUE, TRUE, RIDEV_EXINPUTSINK, FALSE, TRUE, FALSE, /* todos: */ FALSE, TRUE, FALSE }, };
static void rawinput_test_process(void) @@ -1922,6 +1925,8 @@ static void rawinput_test_process(void) case 9: case 10: case 11: + case 12: + case 13: GetCursorPos(&pt);
hwnd = CreateWindowA("static", "static", WS_VISIBLE | WS_POPUP, @@ -1938,7 +1943,7 @@ static void rawinput_test_process(void) UpdateWindow(hwnd); empty_message_queue();
- if (i == 9 || i == 10 || i == 11) + if (i == 9 || i == 10 || i == 11 || i == 12) { raw_devices[0].usUsagePage = 0x01; raw_devices[0].usUsage = 0x02; @@ -1967,7 +1972,7 @@ static void rawinput_test_process(void)
ResetEvent(done);
- if (i == 9 || i == 10 || i == 11) + if (i == 9 || i == 10 || i == 11 || i == 12) { raw_devices[0].dwFlags = RIDEV_REMOVE; raw_devices[0].hwndTarget = 0; @@ -2054,6 +2059,7 @@ static void test_rawinput(const char* argv0) DWORD ret; POINT pt, newpt; HWND hwnd; + BOOL skipped; char path[MAX_PATH]; int i;
@@ -2117,14 +2123,16 @@ static void test_rawinput(const char* argv0) raw_devices[0].dwFlags = rawinput_tests[i].register_flags; raw_devices[0].hwndTarget = rawinput_tests[i].register_window ? hwnd : 0;
- if (rawinput_tests[i].register_device) + if (!rawinput_tests[i].register_device) + skipped = FALSE; + else { SetLastError(0xdeadbeef); - ret = RegisterRawInputDevices(raw_devices, ARRAY_SIZE(raw_devices), sizeof(RAWINPUTDEVICE)); - ok(ret || broken(rawinput_tests[i].register_flags == RIDEV_EXINPUTSINK), /* < vista */ - "%d: RegisterRawInputDevices failed\n", i); - ok(GetLastError() == 0xdeadbeef || broken(rawinput_tests[i].register_flags == RIDEV_EXINPUTSINK), /* < vista */ - "%d: RegisterRawInputDevices returned %08x\n", i, GetLastError()); + skipped = !RegisterRawInputDevices(raw_devices, ARRAY_SIZE(raw_devices), sizeof(RAWINPUTDEVICE)); + if (rawinput_tests[i].register_flags == RIDEV_EXINPUTSINK && skipped) + win_skip("RIDEV_EXINPUTSINK not supported\n"); + else + ok(!skipped, "%d: RegisterRawInputDevices failed: %u\n", i, GetLastError()); }
SetEvent(process_ready); @@ -2141,15 +2149,18 @@ static void test_rawinput(const char* argv0) SetEvent(process_done); SetEvent(params.done);
- todo_wine_if(rawinput_tests[i].todo_legacy) - ok(rawinput_test_received_legacy == rawinput_tests[i].expect_legacy, - "%d: %sexpected WM_MOUSEMOVE message\n", i, rawinput_tests[i].expect_legacy ? "" : "un"); - todo_wine_if(rawinput_tests[i].todo_raw) - ok(rawinput_test_received_raw == rawinput_tests[i].expect_raw, - "%d: %sexpected WM_INPUT message\n", i, rawinput_tests[i].expect_raw ? "" : "un"); - todo_wine_if(rawinput_tests[i].todo_rawfg) - ok(rawinput_test_received_rawfg == rawinput_tests[i].expect_rawfg, - "%d: %sexpected RIM_INPUT message\n", i, rawinput_tests[i].expect_rawfg ? "" : "un"); + if (!skipped) + { + todo_wine_if(rawinput_tests[i].todo_legacy) + ok(rawinput_test_received_legacy == rawinput_tests[i].expect_legacy, + "%d: %sexpected WM_MOUSEMOVE message\n", i, rawinput_tests[i].expect_legacy ? "" : "un"); + todo_wine_if(rawinput_tests[i].todo_raw) + ok(rawinput_test_received_raw == rawinput_tests[i].expect_raw, + "%d: %sexpected WM_INPUT message\n", i, rawinput_tests[i].expect_raw ? "" : "un"); + todo_wine_if(rawinput_tests[i].todo_rawfg) + ok(rawinput_test_received_rawfg == rawinput_tests[i].expect_rawfg, + "%d: %sexpected RIM_INPUT message\n", i, rawinput_tests[i].expect_rawfg ? "" : "un"); + }
GetCursorPos(&newpt); ok((newpt.x - pt.x) == 5 || (newpt.x - pt.x) == 4, "%d: Unexpected cursor movement\n", i); @@ -2161,8 +2172,7 @@ static void test_rawinput(const char* argv0)
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()); + ok(ret, "%d: RegisterRawInputDevices failed: %u\n", i, GetLastError()); }
DestroyWindow(hwnd);
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=73434
Your paranoid android.
=== debiant (build log) ===
Task: WineTest did not produce the wow32 report
This delivers the rawinput messages to the correct process, regardless of where the input was received.
For now the RIDEV_INPUTSINK flag is not implemented, so the listening process has to be the foreground process, but iterating the process list will make it easier to implement later.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/user32/tests/input.c | 2 +- server/queue.c | 118 +++++++++++++++++++++++++++----------- 2 files changed, 86 insertions(+), 34 deletions(-)
diff --git a/dlls/user32/tests/input.c b/dlls/user32/tests/input.c index 9ec829860af..eb5fcf7c812 100644 --- a/dlls/user32/tests/input.c +++ b/dlls/user32/tests/input.c @@ -1882,7 +1882,7 @@ struct rawinput_test rawinput_tests[] = /* cross-process foreground tests */ { TRUE, TRUE, 0, FALSE, FALSE, FALSE, /* todos: */ FALSE, FALSE, FALSE }, { TRUE, TRUE, RIDEV_INPUTSINK, FALSE, TRUE, FALSE, /* todos: */ FALSE, TRUE, FALSE }, - { TRUE, TRUE, 0, FALSE, FALSE, FALSE, /* todos: */ FALSE, TRUE, TRUE }, + { TRUE, TRUE, 0, FALSE, FALSE, FALSE, /* todos: */ FALSE, FALSE, FALSE },
/* multi-process rawinput tests */ { TRUE, TRUE, 0, FALSE, FALSE, FALSE, /* todos: */ FALSE, FALSE, FALSE }, diff --git a/server/queue.c b/server/queue.c index 84ee0f9a4ea..94b9d555183 100644 --- a/server/queue.c +++ b/server/queue.c @@ -1596,12 +1596,73 @@ static int send_hook_ll_message( struct desktop *desktop, struct message *hardwa return 1; }
+struct rawinput_message +{ + struct desktop *desktop; + struct hw_msg_source source; + unsigned int time; + struct hardware_msg_data data; +}; + +static int queue_rawinput_message( struct process* process, void* user ) +{ + const struct rawinput_message* raw_msg = user; + const struct rawinput_device *device = NULL; + struct desktop *desktop = NULL; + struct thread *thread = NULL, *foreground = NULL; + struct message *msg; + + if (raw_msg->data.rawinput.type == RIM_TYPEMOUSE) + device = process->rawinput_mouse; + else if (raw_msg->data.rawinput.type == RIM_TYPEKEYBOARD) + device = process->rawinput_kbd; + + /* skip if no device registered in process */ + if (!device) goto done; + + /* skip if event is from another desktop */ + if (!(desktop = get_desktop_obj( process, process->desktop, 0 )) || + (raw_msg->desktop && desktop != raw_msg->desktop)) + goto done; + + /* skip if there is no target window */ + if (!device->target && !desktop->foreground_input) + goto done; + + /* skip if target window is from a thread in another process */ + if (!(thread = get_window_thread( device->target ? device->target : desktop->foreground_input->active )) || + process != thread->process) + goto done; + + /* FIXME: Implement RIDEV_INPUTSINK */ + if (!desktop->foreground_input || !(foreground = get_window_thread( desktop->foreground_input->active )) || + thread->process != foreground->process) + goto done; + + if (!(msg = alloc_hardware_message( raw_msg->data.info, raw_msg->source, raw_msg->time ))) + goto done; + + msg->win = device->target; + msg->msg = WM_INPUT; + msg->wparam = RIM_INPUT; + msg->lparam = 0; + memcpy( msg->data, &raw_msg->data, sizeof(raw_msg->data) ); + + queue_hardware_message( desktop, msg, 0 ); + +done: + if (foreground) release_object( foreground ); + if (thread) release_object( thread ); + if (desktop) release_object( desktop ); + return 0; +} + /* queue a hardware message for a mouse event */ static int queue_mouse_message( struct desktop *desktop, user_handle_t win, const hw_input_t *input, unsigned int origin, struct msg_queue *sender ) { - const struct rawinput_device *device; struct hardware_msg_data *msg_data; + struct rawinput_message raw_msg; struct message *msg; unsigned int i, time, flags; struct hw_msg_source source = { IMDT_MOUSE, origin }; @@ -1651,24 +1712,19 @@ static int queue_mouse_message( struct desktop *desktop, user_handle_t win, cons y = desktop->cursor.y; }
- if ((device = current->process->rawinput_mouse)) - { - if (!(msg = alloc_hardware_message( input->mouse.info, source, time ))) return 0; - msg_data = msg->data; - - msg->win = device->target; - msg->msg = WM_INPUT; - msg->wparam = RIM_INPUT; - msg->lparam = 0; + raw_msg.desktop = desktop; + raw_msg.source = source; + raw_msg.time = time;
- msg_data->flags = flags; - msg_data->rawinput.type = RIM_TYPEMOUSE; - msg_data->rawinput.mouse.x = x - desktop->cursor.x; - msg_data->rawinput.mouse.y = y - desktop->cursor.y; - msg_data->rawinput.mouse.data = input->mouse.data; + msg_data = &raw_msg.data; + msg_data->info = input->mouse.info; + msg_data->flags = flags; + msg_data->rawinput.type = RIM_TYPEMOUSE; + msg_data->rawinput.mouse.x = x - desktop->cursor.x; + msg_data->rawinput.mouse.y = y - desktop->cursor.y; + msg_data->rawinput.mouse.data = input->mouse.data;
- queue_hardware_message( desktop, msg, 0 ); - } + enum_processes( queue_rawinput_message, &raw_msg );
for (i = 0; i < ARRAY_SIZE( messages ); i++) { @@ -1704,8 +1760,8 @@ static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, c unsigned int origin, struct msg_queue *sender ) { struct hw_msg_source source = { IMDT_KEYBOARD, origin }; - const struct rawinput_device *device; struct hardware_msg_data *msg_data; + struct rawinput_message raw_msg; struct message *msg; unsigned char vkey = input->kbd.vkey; unsigned int message_code, time; @@ -1777,23 +1833,19 @@ static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, c break; }
- if ((device = current->process->rawinput_kbd)) - { - if (!(msg = alloc_hardware_message( input->kbd.info, source, time ))) return 0; - msg_data = msg->data; - - msg->win = device->target; - msg->msg = WM_INPUT; - msg->wparam = RIM_INPUT; + raw_msg.desktop = desktop; + raw_msg.source = source; + raw_msg.time = time;
- msg_data->flags = input->kbd.flags; - msg_data->rawinput.type = RIM_TYPEKEYBOARD; - msg_data->rawinput.kbd.message = message_code; - msg_data->rawinput.kbd.vkey = vkey; - msg_data->rawinput.kbd.scan = input->kbd.scan; + msg_data = &raw_msg.data; + msg_data->info = input->kbd.info; + msg_data->flags = input->kbd.flags; + msg_data->rawinput.type = RIM_TYPEKEYBOARD; + msg_data->rawinput.kbd.message = message_code; + msg_data->rawinput.kbd.vkey = vkey; + msg_data->rawinput.kbd.scan = input->kbd.scan;
- queue_hardware_message( desktop, msg, 0 ); - } + enum_processes( queue_rawinput_message, &raw_msg );
if (!(msg = alloc_hardware_message( input->kbd.info, source, time ))) return 0; msg_data = msg->data;
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=73435
Your paranoid android.
=== debiant (build log) ===
Task: WineTest did not produce the wow32 report
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- server/queue.c | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-)
diff --git a/server/queue.c b/server/queue.c index 94b9d555183..d8b69e77787 100644 --- a/server/queue.c +++ b/server/queue.c @@ -366,6 +366,20 @@ static struct message *alloc_hardware_message( lparam_t info, struct hw_msg_sour return msg; }
+static int update_desktop_cursor_pos( struct desktop *desktop, int x, int y ) +{ + int updated; + + x = max( min( x, desktop->cursor.clip.right - 1 ), desktop->cursor.clip.left ); + y = max( min( y, desktop->cursor.clip.bottom - 1 ), desktop->cursor.clip.top ); + updated = (desktop->cursor.x != x || desktop->cursor.y != y); + desktop->cursor.x = x; + desktop->cursor.y = y; + desktop->cursor.last_change = get_tick_count(); + + return updated; +} + /* set the cursor position and queue the corresponding mouse message */ static void set_cursor_pos( struct desktop *desktop, int x, int y ) { @@ -1500,15 +1514,7 @@ static void queue_hardware_message( struct desktop *desktop, struct message *msg } else if (msg->msg != WM_INPUT) { - if (msg->msg == WM_MOUSEMOVE) - { - int x = max( min( msg->x, desktop->cursor.clip.right - 1 ), desktop->cursor.clip.left ); - int y = max( min( msg->y, desktop->cursor.clip.bottom - 1 ), desktop->cursor.clip.top ); - if (desktop->cursor.x != x || desktop->cursor.y != y) always_queue = 1; - desktop->cursor.x = x; - desktop->cursor.y = y; - desktop->cursor.last_change = get_tick_count(); - } + if (msg->msg == WM_MOUSEMOVE && update_desktop_cursor_pos( desktop, msg->x, msg->y )) always_queue = 1; if (desktop->keystate[VK_LBUTTON] & 0x80) msg->wparam |= MK_LBUTTON; if (desktop->keystate[VK_MBUTTON] & 0x80) msg->wparam |= MK_MBUTTON; if (desktop->keystate[VK_RBUTTON] & 0x80) msg->wparam |= MK_RBUTTON;
So that we can update individual states in next patch.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- server/queue.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-)
diff --git a/server/queue.c b/server/queue.c index d8b69e77787..440478ed1ee 100644 --- a/server/queue.c +++ b/server/queue.c @@ -1290,12 +1290,12 @@ static void set_input_key_state( unsigned char *keystate, unsigned char key, int
/* update the input key state for a keyboard message */ static void update_input_key_state( struct desktop *desktop, unsigned char *keystate, - const struct message *msg ) + unsigned int msg, lparam_t wparam ) { unsigned char key; int down = 0;
- switch (msg->msg) + switch (msg) { case WM_LBUTTONDOWN: down = (keystate == desktop->keystate) ? 0xc0 : 0x80; @@ -1319,8 +1319,8 @@ static void update_input_key_state( struct desktop *desktop, unsigned char *keys down = (keystate == desktop->keystate) ? 0xc0 : 0x80; /* fall through */ case WM_XBUTTONUP: - if (msg->wparam >> 16 == XBUTTON1) set_input_key_state( keystate, VK_XBUTTON1, down ); - else if (msg->wparam >> 16 == XBUTTON2) set_input_key_state( keystate, VK_XBUTTON2, down ); + if (wparam >> 16 == XBUTTON1) set_input_key_state( keystate, VK_XBUTTON1, down ); + else if (wparam >> 16 == XBUTTON2) set_input_key_state( keystate, VK_XBUTTON2, down ); break; case WM_KEYDOWN: case WM_SYSKEYDOWN: @@ -1328,7 +1328,7 @@ static void update_input_key_state( struct desktop *desktop, unsigned char *keys /* fall through */ case WM_KEYUP: case WM_SYSKEYUP: - key = (unsigned char)msg->wparam; + key = (unsigned char)wparam; set_input_key_state( keystate, key, down ); switch(key) { @@ -1382,7 +1382,7 @@ static void release_hardware_message( struct msg_queue *queue, unsigned int hw_i } if (clr_bit) clear_queue_bits( queue, clr_bit );
- update_input_key_state( input->desktop, input->keystate, msg ); + update_input_key_state( input->desktop, input->keystate, msg->msg, msg->wparam ); list_remove( &msg->entry ); free_message( msg ); } @@ -1501,7 +1501,7 @@ static void queue_hardware_message( struct desktop *desktop, struct message *msg struct thread_input *input; unsigned int msg_code;
- update_input_key_state( desktop, desktop->keystate, msg ); + update_input_key_state( desktop, desktop->keystate, msg->msg, msg->wparam ); last_input_time = get_tick_count(); if (msg->msg != WM_MOUSEMOVE) always_queue = 1;
@@ -1536,7 +1536,7 @@ static void queue_hardware_message( struct desktop *desktop, struct message *msg win = find_hardware_message_window( desktop, input, msg, &msg_code, &thread ); if (!win || !thread) { - if (input) update_input_key_state( input->desktop, input->keystate, msg ); + if (input) update_input_key_state( input->desktop, input->keystate, msg->msg, msg->wparam ); free_message( msg ); return; } @@ -1978,7 +1978,7 @@ static int get_hardware_message( struct thread *thread, unsigned int hw_id, user if (!win || !win_thread) { /* no window at all, remove it */ - update_input_key_state( input->desktop, input->keystate, msg ); + update_input_key_state( input->desktop, input->keystate, msg->msg, msg->wparam ); list_remove( &msg->entry ); free_message( msg ); continue; @@ -1994,7 +1994,7 @@ static int get_hardware_message( struct thread *thread, unsigned int hw_id, user else { /* for another thread input, drop it */ - update_input_key_state( input->desktop, input->keystate, msg ); + update_input_key_state( input->desktop, input->keystate, msg->msg, msg->wparam ); list_remove( &msg->entry ); free_message( msg ); }
This makes legacy mouse window messages such as WM_MOUSEMOVE and others, to stop being sent, including to low-level hooks. The desktop mouse state should still be udpated.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/user32/rawinput.c | 2 +- dlls/user32/tests/input.c | 2 +- server/queue.c | 45 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 47 insertions(+), 2 deletions(-)
diff --git a/dlls/user32/rawinput.c b/dlls/user32/rawinput.c index dd2ac2e208b..7a9eb6ced17 100644 --- a/dlls/user32/rawinput.c +++ b/dlls/user32/rawinput.c @@ -306,7 +306,7 @@ BOOL WINAPI DECLSPEC_HOTPATCH RegisterRawInputDevices(RAWINPUTDEVICE *devices, U TRACE("device %u: page %#x, usage %#x, flags %#x, target %p.\n", i, devices[i].usUsagePage, devices[i].usUsage, devices[i].dwFlags, devices[i].hwndTarget); - if (devices[i].dwFlags & ~RIDEV_REMOVE) + if (devices[i].dwFlags & ~(RIDEV_REMOVE|RIDEV_NOLEGACY)) FIXME("Unhandled flags %#x for device %u.\n", devices[i].dwFlags, i);
d[i].usage_page = devices[i].usUsagePage; diff --git a/dlls/user32/tests/input.c b/dlls/user32/tests/input.c index eb5fcf7c812..ecd44c44f16 100644 --- a/dlls/user32/tests/input.c +++ b/dlls/user32/tests/input.c @@ -1873,7 +1873,7 @@ struct rawinput_test rawinput_tests[] = { FALSE, FALSE, 0, TRUE, FALSE, FALSE, /* todos: */ FALSE, FALSE, FALSE }, { TRUE, FALSE, 0, TRUE, TRUE, TRUE, /* todos: */ FALSE, FALSE, FALSE }, { TRUE, TRUE, 0, TRUE, TRUE, TRUE, /* todos: */ FALSE, FALSE, FALSE }, - { TRUE, TRUE, RIDEV_NOLEGACY, FALSE, TRUE, TRUE, /* todos: */ TRUE, FALSE, FALSE }, + { TRUE, TRUE, RIDEV_NOLEGACY, FALSE, TRUE, TRUE, /* todos: */ FALSE, FALSE, FALSE },
/* same-process foreground tests */ { TRUE, FALSE, 0, FALSE, FALSE, FALSE, /* todos: */ FALSE, FALSE, FALSE }, diff --git a/server/queue.c b/server/queue.c index 440478ed1ee..14cffbd6a76 100644 --- a/server/queue.c +++ b/server/queue.c @@ -384,8 +384,15 @@ static int update_desktop_cursor_pos( struct desktop *desktop, int x, int y ) static void set_cursor_pos( struct desktop *desktop, int x, int y ) { static const struct hw_msg_source source = { IMDT_UNAVAILABLE, IMO_SYSTEM }; + const struct rawinput_device *device; struct message *msg;
+ if ((device = current->process->rawinput_mouse) && (device->flags & RIDEV_NOLEGACY)) + { + update_desktop_cursor_pos( desktop, x, y ); + return; + } + if (!(msg = alloc_hardware_message( 0, source, get_tick_count() ))) return;
msg->msg = WM_MOUSEMOVE; @@ -1352,6 +1359,30 @@ static void update_input_key_state( struct desktop *desktop, unsigned char *keys } }
+/* update the desktop key state according to a mouse message flags */ +static void update_desktop_mouse_state( struct desktop *desktop, unsigned int flags, + int x, int y, lparam_t wparam ) +{ + if (flags & MOUSEEVENTF_MOVE) + update_desktop_cursor_pos( desktop, x, y ); + if (flags & MOUSEEVENTF_LEFTDOWN) + update_input_key_state( desktop, desktop->keystate, WM_LBUTTONDOWN, wparam ); + if (flags & MOUSEEVENTF_LEFTUP) + update_input_key_state( desktop, desktop->keystate, WM_LBUTTONUP, wparam ); + if (flags & MOUSEEVENTF_RIGHTDOWN) + update_input_key_state( desktop, desktop->keystate, WM_RBUTTONDOWN, wparam ); + if (flags & MOUSEEVENTF_RIGHTUP) + update_input_key_state( desktop, desktop->keystate, WM_RBUTTONUP, wparam ); + if (flags & MOUSEEVENTF_MIDDLEDOWN) + update_input_key_state( desktop, desktop->keystate, WM_MBUTTONDOWN, wparam ); + if (flags & MOUSEEVENTF_MIDDLEUP) + update_input_key_state( desktop, desktop->keystate, WM_MBUTTONUP, wparam ); + if (flags & MOUSEEVENTF_XDOWN) + update_input_key_state( desktop, desktop->keystate, WM_XBUTTONDOWN, wparam ); + if (flags & MOUSEEVENTF_XUP) + update_input_key_state( desktop, desktop->keystate, WM_XBUTTONUP, wparam ); +} + /* release the hardware message currently being processed by the given thread */ static void release_hardware_message( struct msg_queue *queue, unsigned int hw_id, int remove ) @@ -1667,6 +1698,7 @@ done: static int queue_mouse_message( struct desktop *desktop, user_handle_t win, const hw_input_t *input, unsigned int origin, struct msg_queue *sender ) { + const struct rawinput_device *device; struct hardware_msg_data *msg_data; struct rawinput_message raw_msg; struct message *msg; @@ -1732,6 +1764,12 @@ static int queue_mouse_message( struct desktop *desktop, user_handle_t win, cons
enum_processes( queue_rawinput_message, &raw_msg );
+ if ((device = current->process->rawinput_mouse) && (device->flags & RIDEV_NOLEGACY)) + { + update_desktop_mouse_state( desktop, flags, x, y, input->mouse.data << 16 ); + return 0; + } + for (i = 0; i < ARRAY_SIZE( messages ); i++) { if (!messages[i]) continue; @@ -1766,6 +1804,7 @@ static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, c unsigned int origin, struct msg_queue *sender ) { struct hw_msg_source source = { IMDT_KEYBOARD, origin }; + const struct rawinput_device *device; struct hardware_msg_data *msg_data; struct rawinput_message raw_msg; struct message *msg; @@ -1853,6 +1892,12 @@ static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, c
enum_processes( queue_rawinput_message, &raw_msg );
+ if ((device = current->process->rawinput_kbd) && (device->flags & RIDEV_NOLEGACY)) + { + update_input_key_state( desktop, desktop->keystate, message_code, vkey ); + return 0; + } + if (!(msg = alloc_hardware_message( input->kbd.info, source, time ))) return 0; msg_data = msg->data;
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=73438
Your paranoid android.
=== w1064v1809_zh_CN (32 bit report) ===
user32: input.c:1421: Test failed: Wrong new pos: (150,150)
=== debiant (build log) ===
Task: WineTest did not produce the wow32 report
This flag allows applications to receive rawinput messages while in background. They have to specify a target hwnd, which will receive them, and the messages will carry a RIM_INPUTSINK wparam if the process wasn't foreground.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/user32/rawinput.c | 9 ++++++++- dlls/user32/tests/input.c | 8 +++----- server/queue.c | 13 +++++++++---- 3 files changed, 20 insertions(+), 10 deletions(-)
diff --git a/dlls/user32/rawinput.c b/dlls/user32/rawinput.c index 7a9eb6ced17..103835e0e33 100644 --- a/dlls/user32/rawinput.c +++ b/dlls/user32/rawinput.c @@ -291,6 +291,13 @@ BOOL WINAPI DECLSPEC_HOTPATCH RegisterRawInputDevices(RAWINPUTDEVICE *devices, U
for (i = 0; i < device_count; ++i) { + if ((devices[i].dwFlags & RIDEV_INPUTSINK) && + (devices[i].hwndTarget == NULL)) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + if ((devices[i].dwFlags & RIDEV_REMOVE) && (devices[i].hwndTarget != NULL)) { @@ -306,7 +313,7 @@ BOOL WINAPI DECLSPEC_HOTPATCH RegisterRawInputDevices(RAWINPUTDEVICE *devices, U TRACE("device %u: page %#x, usage %#x, flags %#x, target %p.\n", i, devices[i].usUsagePage, devices[i].usUsage, devices[i].dwFlags, devices[i].hwndTarget); - if (devices[i].dwFlags & ~(RIDEV_REMOVE|RIDEV_NOLEGACY)) + if (devices[i].dwFlags & ~(RIDEV_REMOVE|RIDEV_NOLEGACY|RIDEV_INPUTSINK)) FIXME("Unhandled flags %#x for device %u.\n", devices[i].dwFlags, i);
d[i].usage_page = devices[i].usUsagePage; diff --git a/dlls/user32/tests/input.c b/dlls/user32/tests/input.c index ecd44c44f16..7ab96360ad5 100644 --- a/dlls/user32/tests/input.c +++ b/dlls/user32/tests/input.c @@ -1804,9 +1804,7 @@ static void test_RegisterRawInputDevices(void)
SetLastError(0xdeadbeef); res = RegisterRawInputDevices(raw_devices, ARRAY_SIZE(raw_devices), sizeof(RAWINPUTDEVICE)); - todo_wine ok(res == FALSE, "RegisterRawInputDevices failed\n"); - todo_wine ok(GetLastError() == ERROR_INVALID_PARAMETER, "RegisterRawInputDevices returned %08x\n", GetLastError());
raw_devices[0].hwndTarget = hwnd; @@ -1881,13 +1879,13 @@ struct rawinput_test rawinput_tests[] =
/* cross-process foreground tests */ { TRUE, TRUE, 0, FALSE, FALSE, FALSE, /* todos: */ FALSE, FALSE, FALSE }, - { TRUE, TRUE, RIDEV_INPUTSINK, FALSE, TRUE, FALSE, /* todos: */ FALSE, TRUE, FALSE }, + { TRUE, TRUE, RIDEV_INPUTSINK, FALSE, TRUE, FALSE, /* todos: */ FALSE, FALSE, FALSE }, { TRUE, TRUE, 0, FALSE, FALSE, FALSE, /* todos: */ FALSE, FALSE, FALSE },
/* multi-process rawinput tests */ { TRUE, TRUE, 0, FALSE, FALSE, FALSE, /* todos: */ FALSE, FALSE, FALSE }, - { TRUE, TRUE, RIDEV_INPUTSINK, FALSE, TRUE, FALSE, /* todos: */ FALSE, TRUE, FALSE }, - { TRUE, TRUE, RIDEV_INPUTSINK, FALSE, TRUE, FALSE, /* todos: */ FALSE, TRUE, FALSE }, + { TRUE, TRUE, RIDEV_INPUTSINK, FALSE, TRUE, FALSE, /* todos: */ FALSE, FALSE, FALSE }, + { TRUE, TRUE, RIDEV_INPUTSINK, FALSE, TRUE, FALSE, /* todos: */ FALSE, FALSE, FALSE },
{ TRUE, TRUE, RIDEV_EXINPUTSINK, FALSE, FALSE, FALSE, /* todos: */ FALSE, FALSE, FALSE }, { TRUE, TRUE, RIDEV_EXINPUTSINK, FALSE, TRUE, FALSE, /* todos: */ FALSE, TRUE, FALSE }, diff --git a/server/queue.c b/server/queue.c index 14cffbd6a76..517d42d34dd 100644 --- a/server/queue.c +++ b/server/queue.c @@ -1648,6 +1648,7 @@ static int queue_rawinput_message( struct process* process, void* user ) struct desktop *desktop = NULL; struct thread *thread = NULL, *foreground = NULL; struct message *msg; + int wparam = RIM_INPUT;
if (raw_msg->data.rawinput.type == RIM_TYPEMOUSE) device = process->rawinput_mouse; @@ -1671,17 +1672,21 @@ static int queue_rawinput_message( struct process* process, void* user ) process != thread->process) goto done;
- /* FIXME: Implement RIDEV_INPUTSINK */ - if (!desktop->foreground_input || !(foreground = get_window_thread( desktop->foreground_input->active )) || + /* skip if target window is not in foreground process and RIDEV_INPUTSINK was not used */ + if (!desktop->foreground_input || + !(foreground = get_window_thread( desktop->foreground_input->active )) || thread->process != foreground->process) - goto done; + { + if (!(device->flags & RIDEV_INPUTSINK)) goto done; + wparam = RIM_INPUTSINK; + }
if (!(msg = alloc_hardware_message( raw_msg->data.info, raw_msg->source, raw_msg->time ))) goto done;
msg->win = device->target; msg->msg = WM_INPUT; - msg->wparam = RIM_INPUT; + msg->wparam = wparam; msg->lparam = 0; memcpy( msg->data, &raw_msg->data, sizeof(raw_msg->data) );
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=73439
Your paranoid android.
=== debiant (32 bit Chinese:China report) ===
user32: win.c:10185: Test failed: Expected foreground window 000D0120, got 00000000 win.c:10200: Test failed: GetActiveWindow() = 000D0120 win.c:10200: Test failed: GetFocus() = 000D0120 win.c:10212: Test succeeded inside todo block: Expected WM_ACTIVATEAPP(0), did not receive it.
=== debiant (build log) ===
Task: WineTest did not produce the wow32 report
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=73431
Your paranoid android.
=== debiant (build log) ===
Task: WineTest did not produce the wow32 report