Hi!
This is another attempt at upstreaming my rawinput patches.
I think there's a safer route, by first implementing the wineserver and dinput8 parts, while still relying on the current winex11 code. As long as a Wine window has input focus, the rawinput messages can be dispatch correctly to the listening processes.
This series implements the missing rawinput support in wineserver, as well as some flag support that dinput8 implementation will then use.
Then it should be possible to implement dinput8 on top of rawinput API, and get rid of the low-level hooks there, which is the correct way to do, and which should improve performance.
The tricky part is about listening to xinput2 rawevent globally, which will solve the spurious mouse movements, but it will require first to sort out or workaround some focus issues, so that events are only dispatched when a Wine window has input focus. It can probably still live in staging until an good solution is found.
Cheers,
Rémi Bernon (8): user32/tests: Add basic rawinput message tests. user32/tests: Add inter-thread rawinput message tests. user32/tests: Add inter-process rawinput message tests. server: Implement rawinput cross-process message dispatch. server: Split cursor position update to update_desktop_cursor_pos. server: Split cursor state update to update_desktop_mouse_state. server: Implement RegisterRawInputDevices RIDEV_NOLEGACY flag. server: Implement RegisterRawInputDevices RIDEV_INPUTSINK flag.
dlls/user32/rawinput.c | 9 +- dlls/user32/tests/input.c | 325 +++++++++++++++++++++++++++++++++++++- server/queue.c | 200 +++++++++++++++++------ 3 files changed, 485 insertions(+), 49 deletions(-)
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 --- dlls/user32/tests/input.c | 136 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 136 insertions(+)
diff --git a/dlls/user32/tests/input.c b/dlls/user32/tests/input.c index 913fabfbd85..4d1a1c062ab 100644 --- a/dlls/user32/tests/input.c +++ b/dlls/user32/tests/input.c @@ -1819,6 +1819,141 @@ static void test_RegisterRawInputDevices(void) DestroyWindow(hwnd); }
+static int rawinput_test_count_legacy; +static int rawinput_test_count_raw; +static int rawinput_test_count_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_count_raw) + ok(rawinput_test_count_raw == 0, "Unexpected spurious WM_INPUT message.\n"); + ok(wparam == RIM_INPUT || wparam == RIM_INPUTSINK, "Unexpected wparam: %lu\n", wparam); + + rawinput_test_count_raw++; + if (wparam == RIM_INPUT) rawinput_test_count_rawfg++; + + 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); + if (raw_size > sizeof(raw)) + return DefWindowProcA(hwnd, msg, wparam, lparam); + + 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); + if (raw.header.dwType != RIM_TYPEMOUSE) + return DefWindowProcA(hwnd, msg, wparam, lparam); + + 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_count_legacy++; + + return DefWindowProcA(hwnd, msg, wparam, lparam); +} + +struct rawinput_test +{ + BOOL register_device; + BOOL register_window; + DWORD register_flags; + int expect_legacy; + int expect_raw; + int 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(); + + ShowWindow(hwnd, SW_SHOW); + SetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE); + SetForegroundWindow(hwnd); + UpdateWindow(hwnd); + empty_message_queue(); + + rawinput_test_count_legacy = 0; + rawinput_test_count_raw = 0; + rawinput_test_count_rawfg = 0; + + 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_count_legacy == rawinput_tests[i].expect_legacy, + "%d: Unexpected WM_MOUSEMOVE message count\n", i); + todo_wine_if(rawinput_tests[i].todo_raw) + ok(!!rawinput_test_count_raw == rawinput_tests[i].expect_raw, + "%d: Unexpected WM_INPUT message count\n", i); + todo_wine_if(rawinput_tests[i].todo_rawfg) + ok(!!rawinput_test_count_rawfg == rawinput_tests[i].expect_rawfg, + "%d: Unexpected RIM_INPUT message count\n", i); + + 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 +3169,7 @@ START_TEST(input) test_OemKeyScan(); test_GetRawInputData(); test_RegisterRawInputDevices(); + test_rawinput();
if(pGetMouseMovePointsEx) test_GetMouseMovePointsEx();
On 6/7/20 6:21 AM, Rémi Bernon wrote:
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
dlls/user32/tests/input.c | 136 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 136 insertions(+)
diff --git a/dlls/user32/tests/input.c b/dlls/user32/tests/input.c index 913fabfbd85..4d1a1c062ab 100644 --- a/dlls/user32/tests/input.c +++ b/dlls/user32/tests/input.c @@ -1819,6 +1819,141 @@ static void test_RegisterRawInputDevices(void) DestroyWindow(hwnd); }
+static int rawinput_test_count_legacy; +static int rawinput_test_count_raw; +static int rawinput_test_count_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_count_raw)
ok(rawinput_test_count_raw == 0, "Unexpected spurious WM_INPUT message.\n");
ok(wparam == RIM_INPUT || wparam == RIM_INPUTSINK, "Unexpected wparam: %lu\n", wparam);
rawinput_test_count_raw++;
if (wparam == RIM_INPUT) rawinput_test_count_rawfg++;
If you can't reliably check what the actual count is, maybe it makes more sense to have this as a boolean flag...?
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);
if (raw_size > sizeof(raw))
return DefWindowProcA(hwnd, msg, wparam, lparam);
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);
if (raw.header.dwType != RIM_TYPEMOUSE)
return DefWindowProcA(hwnd, msg, wparam, lparam);
I've never much seen the point of doing this (and similarly above). If the test fails, you'll know due to the failure message, and it's not particularly like we care about different degrees of failure—if it fails, it still needs to be fixed. I don't feel strongly about it, though...
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_count_legacy++;
- return DefWindowProcA(hwnd, msg, wparam, lparam);
+}
+struct rawinput_test +{
- BOOL register_device;
- BOOL register_window;
- DWORD register_flags;
- int expect_legacy;
- int expect_raw;
- int 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();
ShowWindow(hwnd, SW_SHOW);
SetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE);
SetForegroundWindow(hwnd);
UpdateWindow(hwnd);
Wait, what's the point of all these calls? In particular, why ShowWindow() and UpdateWindow()? Perhaps they deserve a comment in the code.
empty_message_queue();
rawinput_test_count_legacy = 0;
rawinput_test_count_raw = 0;
rawinput_test_count_rawfg = 0;
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_count_legacy == rawinput_tests[i].expect_legacy,
"%d: Unexpected WM_MOUSEMOVE message count\n", i);
todo_wine_if(rawinput_tests[i].todo_raw)
ok(!!rawinput_test_count_raw == rawinput_tests[i].expect_raw,
"%d: Unexpected WM_INPUT message count\n", i);
todo_wine_if(rawinput_tests[i].todo_rawfg)
ok(!!rawinput_test_count_rawfg == rawinput_tests[i].expect_rawfg,
"%d: Unexpected RIM_INPUT message count\n", i);
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 +3169,7 @@ START_TEST(input) test_OemKeyScan(); test_GetRawInputData(); test_RegisterRawInputDevices();
test_rawinput();
if(pGetMouseMovePointsEx) test_GetMouseMovePointsEx();
On 2020-06-07 17:11, Zebediah Figura wrote:
On 6/7/20 6:21 AM, Rémi Bernon wrote:
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
dlls/user32/tests/input.c | 136 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 136 insertions(+)
diff --git a/dlls/user32/tests/input.c b/dlls/user32/tests/input.c index 913fabfbd85..4d1a1c062ab 100644 --- a/dlls/user32/tests/input.c +++ b/dlls/user32/tests/input.c @@ -1819,6 +1819,141 @@ static void test_RegisterRawInputDevices(void) DestroyWindow(hwnd); } +static int rawinput_test_count_legacy; +static int rawinput_test_count_raw; +static int rawinput_test_count_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_count_raw) + ok(rawinput_test_count_raw == 0, "Unexpected spurious WM_INPUT message.\n"); + ok(wparam == RIM_INPUT || wparam == RIM_INPUTSINK, "Unexpected wparam: %lu\n", wparam);
+ rawinput_test_count_raw++; + if (wparam == RIM_INPUT) rawinput_test_count_rawfg++;
If you can't reliably check what the actual count is, maybe it makes more sense to have this as a boolean flag...?
It is indeed a remain of a previous version of the test, the message count isn't currently correct in wine (hence the todo above), and I was initially checking the actual count.
As it's not going to be fixed until we change winex11, I then opted for a boolean "expectation" and this todo here
I think it's still valuable to count the messages, to expose the fact that wine has some spurious messages. It doesn't make the test much more complex either.
+ 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); + if (raw_size > sizeof(raw)) + return DefWindowProcA(hwnd, msg, wparam, lparam);
+ 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); + if (raw.header.dwType != RIM_TYPEMOUSE) + return DefWindowProcA(hwnd, msg, wparam, lparam);
I've never much seen the point of doing this (and similarly above). If the test fails, you'll know due to the failure message, and it's not particularly like we care about different degrees of failure—if it fails, it still needs to be fixed. I don't feel strongly about it, though...
You mean the early returns? The first one will prevent possible buffer overrun, which is probably not a nice failure. The second one is a bit overkill indeed.
+ 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_count_legacy++;
+ return DefWindowProcA(hwnd, msg, wparam, lparam); +}
+struct rawinput_test +{ + BOOL register_device; + BOOL register_window; + DWORD register_flags; + int expect_legacy; + int expect_raw; + int 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();
+ ShowWindow(hwnd, SW_SHOW); + SetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE); + SetForegroundWindow(hwnd); + UpdateWindow(hwnd);
Wait, what's the point of all these calls? In particular, why ShowWindow() and UpdateWindow()? Perhaps they deserve a comment in the code.
It's mostly copy-pasted from the other tests in the same source.
The point is to try as much as possible to get the window in visible and in front and make the Win32 state as consistent as possible with the X11 state, which is hard. Even a small change can make it fail spuriously otherwise.
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 | 84 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 83 insertions(+), 1 deletion(-)
diff --git a/dlls/user32/tests/input.c b/dlls/user32/tests/input.c index 4d1a1c062ab..af44d3e8b4d 100644 --- a/dlls/user32/tests/input.c +++ b/dlls/user32/tests/input.c @@ -1877,16 +1877,85 @@ 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(); + + 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();
@@ -1923,9 +1992,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_count_legacy == rawinput_tests[i].expect_legacy, "%d: Unexpected WM_MOUSEMOVE message count\n", i); @@ -1952,6 +2027,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)
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.
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 | 113 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 109 insertions(+), 4 deletions(-)
diff --git a/dlls/user32/tests/input.c b/dlls/user32/tests/input.c index af44d3e8b4d..ac6a2476785 100644 --- a/dlls/user32/tests/input.c +++ b/dlls/user32/tests/input.c @@ -1881,8 +1881,70 @@ 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 }, };
+static void rawinput_test_process(void) +{ + HANDLE ready, start, done; + POINT pt; + HWND hwnd = NULL; + 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: + 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(); + + 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 != 8) mouse_event(MOUSEEVENTF_MOVE, 5, 0, 0, 0); + empty_message_queue(); + break; + } + + SetEvent(start); + + WaitForSingleObject(done, INFINITE); + ResetEvent(done); + if (hwnd) DestroyWindow(hwnd); + } + + WaitForSingleObject(ready, INFINITE); + CloseHandle(done); + CloseHandle(start); + CloseHandle(ready); +} + struct rawinput_test_thread_params { HANDLE ready; @@ -1934,14 +1996,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); @@ -1956,6 +2021,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();
@@ -1992,13 +2075,18 @@ static void test_rawinput(void) ok(GetLastError() == 0xdeadbeef, "%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) @@ -2028,6 +2116,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); @@ -3229,11 +3325,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(); @@ -3251,7 +3356,7 @@ START_TEST(input) test_OemKeyScan(); test_GetRawInputData(); test_RegisterRawInputDevices(); - test_rawinput(); + test_rawinput(argv[0]);
if(pGetMouseMovePointsEx) test_GetMouseMovePointsEx();
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 ac6a2476785..7fa43f21fbb 100644 --- a/dlls/user32/tests/input.c +++ b/dlls/user32/tests/input.c @@ -1885,7 +1885,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 }, };
static void rawinput_test_process(void) 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=72995
Your paranoid android.
=== w1064v1809_zh_CN (32 bit report) ===
user32: input.c:1421: Test failed: Wrong new pos: (150,150)
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;
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- server/queue.c | 44 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 34 insertions(+), 10 deletions(-)
diff --git a/server/queue.c b/server/queue.c index d8b69e77787..3c1ef19df51 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) { @@ -1352,6 +1352,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 ) @@ -1382,7 +1406,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 +1525,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 +1560,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 +2002,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 +2018,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 ); }
On Sun, Jun 07, 2020 at 01:21:18PM +0200, Rémi Bernon wrote:
Signed-off-by: Rémi Bernon rbernon@codeweavers.com
server/queue.c | 44 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 34 insertions(+), 10 deletions(-)
update_desktop_mouse_state() is unused, so you're just adding dead code at this point.
Huw.
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 | 21 +++++++++++++++++++++ 3 files changed, 23 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 7fa43f21fbb..f04c658da62 100644 --- a/dlls/user32/tests/input.c +++ b/dlls/user32/tests/input.c @@ -1876,7 +1876,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 3c1ef19df51..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; @@ -1691,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; @@ -1756,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; @@ -1790,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; @@ -1877,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=72998
Your paranoid android.
=== debiant (32 bit Chinese:China report) ===
user32: clipboard.c:833: Test failed: 3: gle 5 clipboard.c:838: Test failed: 3.0: got 0000 instead of 000e clipboard.c:868: Test failed: 3: gle 1418
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 window wasn't foreground.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/user32/rawinput.c | 9 ++++++++- dlls/user32/tests/input.c | 4 +--- server/queue.c | 13 +++++++++---- 3 files changed, 18 insertions(+), 8 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 f04c658da62..6539eb91b37 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; @@ -1884,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, RIDEV_INPUTSINK, FALSE, TRUE, FALSE, /* todos: */ FALSE, FALSE, FALSE }, { TRUE, TRUE, 0, FALSE, FALSE, FALSE, /* todos: */ FALSE, FALSE, 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=72999
Your paranoid android.
=== w1064v1809 (32 bit report) ===
user32: input.c:1291: Test failed: Wrong set pos: (100,100) input.c:1311: Test failed: GetCursorPos: (100,100)