There's already some in dinput, but this is a more appropriate location.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com ---
v3: Add some more error case tests with insufficient buffer sizes.
dlls/user32/tests/input.c | 79 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 75 insertions(+), 4 deletions(-)
diff --git a/dlls/user32/tests/input.c b/dlls/user32/tests/input.c index bab0fd97536..4310ad1f296 100644 --- a/dlls/user32/tests/input.c +++ b/dlls/user32/tests/input.c @@ -1764,11 +1764,15 @@ static void test_GetRawInputData(void) static void test_RegisterRawInputDevices(void) { HWND hwnd; - RAWINPUTDEVICE raw_devices[1]; + RAWINPUTDEVICE raw_devices[2]; + UINT count, raw_devices_count; BOOL res;
+ memset(raw_devices, 0, sizeof(raw_devices)); raw_devices[0].usUsagePage = 0x01; raw_devices[0].usUsage = 0x05; + raw_devices[1].usUsagePage = 0x01; + raw_devices[1].usUsage = 0x04;
hwnd = CreateWindowExA(WS_EX_TOPMOST, "static", "dinput", WS_POPUP | WS_VISIBLE, 0, 0, 100, 100, NULL, NULL, NULL, NULL); ok(hwnd != NULL, "CreateWindowExA failed\n"); @@ -1778,9 +1782,6 @@ static void test_RegisterRawInputDevices(void) ok(res == FALSE, "RegisterRawInputDevices succeeded\n");
- raw_devices[0].dwFlags = 0; - raw_devices[0].hwndTarget = 0; - SetLastError(0xdeadbeef); res = RegisterRawInputDevices(raw_devices, ARRAY_SIZE(raw_devices), 0); ok(res == FALSE, "RegisterRawInputDevices succeeded\n"); @@ -1791,10 +1792,76 @@ static void test_RegisterRawInputDevices(void) ok(res == TRUE, "RegisterRawInputDevices failed\n"); ok(GetLastError() == 0xdeadbeef, "RegisterRawInputDevices returned %08x\n", GetLastError());
+ SetLastError(0xdeadbeef); + count = GetRegisteredRawInputDevices(NULL, NULL, 0); + todo_wine + ok(count == ~0U, "GetRegisteredRawInputDevices returned %u\n", count); + todo_wine + ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetRegisteredRawInputDevices unexpected error %08x\n", GetLastError()); + + SetLastError(0xdeadbeef); + raw_devices_count = 0; + count = GetRegisteredRawInputDevices(NULL, &raw_devices_count, 0); + todo_wine + ok(count == ~0U, "GetRegisteredRawInputDevices returned %u\n", count); + ok(raw_devices_count == 0, "Unexpected registered devices count: %u\n", raw_devices_count); + todo_wine + ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetRegisteredRawInputDevices unexpected error %08x\n", GetLastError()); + + SetLastError(0xdeadbeef); + raw_devices_count = 0; + count = GetRegisteredRawInputDevices(NULL, &raw_devices_count, sizeof(RAWINPUTDEVICE)); + ok(count == 0, "GetRegisteredRawInputDevices returned %u\n", count); + todo_wine + ok(raw_devices_count == 2, "Unexpected registered devices count: %u\n", raw_devices_count); + ok(GetLastError() == 0xdeadbeef, "GetRegisteredRawInputDevices unexpected error %08x\n", GetLastError()); + + SetLastError(0xdeadbeef); + raw_devices_count = 0; + count = GetRegisteredRawInputDevices(raw_devices, &raw_devices_count, sizeof(RAWINPUTDEVICE)); + if (broken(count == 0) /* depends on windows versions */) + win_skip("Ignoring GetRegisteredRawInputDevices success\n"); + else + { + todo_wine + ok(count == ~0U, "GetRegisteredRawInputDevices returned %u\n", count); + ok(raw_devices_count == 0, "Unexpected registered devices count: %u\n", raw_devices_count); + todo_wine + ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetRegisteredRawInputDevices unexpected error %08x\n", GetLastError()); + } + + SetLastError(0xdeadbeef); + raw_devices_count = 1; + count = GetRegisteredRawInputDevices(raw_devices, &raw_devices_count, sizeof(RAWINPUTDEVICE)); + todo_wine + ok(count == ~0U, "GetRegisteredRawInputDevices returned %u\n", count); + todo_wine + ok(raw_devices_count == 2, "Unexpected registered devices count: %u\n", raw_devices_count); + todo_wine + ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "GetRegisteredRawInputDevices unexpected error %08x\n", GetLastError()); + + SetLastError(0xdeadbeef); + memset(raw_devices, 0, sizeof(raw_devices)); + raw_devices_count = ARRAY_SIZE(raw_devices); + count = GetRegisteredRawInputDevices(raw_devices, &raw_devices_count, sizeof(RAWINPUTDEVICE)); + todo_wine + ok(count == 2, "GetRegisteredRawInputDevices returned %u\n", count); + ok(raw_devices_count == 2, "Unexpected registered devices count: %u\n", raw_devices_count); + ok(GetLastError() == 0xdeadbeef, "GetRegisteredRawInputDevices unexpected error %08x\n", GetLastError()); + todo_wine + ok(raw_devices[0].usUsagePage == 0x01, "Unexpected usage page: %x\n", raw_devices[0].usUsagePage); + todo_wine + ok(raw_devices[0].usUsage == 0x04, "Unexpected usage: %x\n", raw_devices[0].usUsage); + todo_wine + ok(raw_devices[1].usUsagePage == 0x01, "Unexpected usage page: %x\n", raw_devices[1].usUsagePage); + todo_wine + ok(raw_devices[1].usUsage == 0x05, "Unexpected usage: %x\n", raw_devices[1].usUsage);
/* RIDEV_REMOVE requires hwndTarget == NULL */ raw_devices[0].dwFlags = RIDEV_REMOVE; raw_devices[0].hwndTarget = hwnd; + raw_devices[1].dwFlags = RIDEV_REMOVE; + raw_devices[1].hwndTarget = hwnd;
SetLastError(0xdeadbeef); res = RegisterRawInputDevices(raw_devices, ARRAY_SIZE(raw_devices), sizeof(RAWINPUTDEVICE)); @@ -1802,6 +1869,7 @@ static void test_RegisterRawInputDevices(void) ok(GetLastError() == ERROR_INVALID_PARAMETER, "RegisterRawInputDevices returned %08x\n", GetLastError());
raw_devices[0].hwndTarget = 0; + raw_devices[1].hwndTarget = 0;
SetLastError(0xdeadbeef); res = RegisterRawInputDevices(raw_devices, ARRAY_SIZE(raw_devices), sizeof(RAWINPUTDEVICE)); @@ -1812,6 +1880,8 @@ static void test_RegisterRawInputDevices(void) /* RIDEV_INPUTSINK requires hwndTarget != NULL */ raw_devices[0].dwFlags = RIDEV_INPUTSINK; raw_devices[0].hwndTarget = 0; + raw_devices[1].dwFlags = RIDEV_INPUTSINK; + raw_devices[1].hwndTarget = 0;
SetLastError(0xdeadbeef); res = RegisterRawInputDevices(raw_devices, ARRAY_SIZE(raw_devices), sizeof(RAWINPUTDEVICE)); @@ -1819,6 +1889,7 @@ static void test_RegisterRawInputDevices(void) ok(GetLastError() == ERROR_INVALID_PARAMETER, "RegisterRawInputDevices returned %08x\n", GetLastError());
raw_devices[0].hwndTarget = hwnd; + raw_devices[1].hwndTarget = hwnd;
SetLastError(0xdeadbeef); res = RegisterRawInputDevices(raw_devices, ARRAY_SIZE(raw_devices), sizeof(RAWINPUTDEVICE));
Signed-off-by: Rémi Bernon rbernon@codeweavers.com ---
v3: return STATUS_BUFFER_TOO_SMALL when appropriate and use wine_server_call_err to set last error from status.
The case where client buffer is not NULL but *device_count is 0 is treated as an invalid parameter combination, as it is the case on some windows versions. It then simplifies the server code where we can handle get_reply_max_size() == 0 as the NULL buffer case.
dlls/dinput8/tests/device.c | 13 ---------- dlls/user32/rawinput.c | 50 +++++++++++++++++++++++++++++++++++-- dlls/user32/tests/input.c | 15 ----------- server/protocol.def | 6 +++++ server/queue.c | 22 ++++++++++++++++ 5 files changed, 76 insertions(+), 30 deletions(-)
diff --git a/dlls/dinput8/tests/device.c b/dlls/dinput8/tests/device.c index 39c635f2fb9..328174e5796 100644 --- a/dlls/dinput8/tests/device.c +++ b/dlls/dinput8/tests/device.c @@ -602,7 +602,6 @@ static void test_mouse_keyboard(void)
raw_devices_count = ARRAY_SIZE(raw_devices); GetRegisteredRawInputDevices(NULL, &raw_devices_count, sizeof(RAWINPUTDEVICE)); - todo_wine ok(raw_devices_count == 0, "Unexpected raw devices registered: %d\n", raw_devices_count);
hr = IDirectInputDevice8_Acquire(di_keyboard); @@ -624,7 +623,6 @@ static void test_mouse_keyboard(void) ok(SUCCEEDED(hr), "IDirectInputDevice8_Acquire failed: %08x\n", hr); raw_devices_count = ARRAY_SIZE(raw_devices); GetRegisteredRawInputDevices(NULL, &raw_devices_count, sizeof(RAWINPUTDEVICE)); - todo_wine ok(raw_devices_count == 0, "Unexpected raw devices registered: %d\n", raw_devices_count);
if (raw_devices[0].hwndTarget != NULL) @@ -662,7 +660,6 @@ static void test_mouse_keyboard(void) ok(SUCCEEDED(hr), "IDirectInputDevice8_Acquire failed: %08x\n", hr); raw_devices_count = ARRAY_SIZE(raw_devices); GetRegisteredRawInputDevices(NULL, &raw_devices_count, sizeof(RAWINPUTDEVICE)); - todo_wine ok(raw_devices_count == 0, "Unexpected raw devices registered: %d\n", raw_devices_count);
/* expect dinput8 to take over any activated raw input devices */ @@ -689,26 +686,18 @@ static void test_mouse_keyboard(void) raw_devices_count = ARRAY_SIZE(raw_devices); memset(raw_devices, 0, sizeof(raw_devices)); hr = GetRegisteredRawInputDevices(raw_devices, &raw_devices_count, sizeof(RAWINPUTDEVICE)); - todo_wine ok(hr == 3, "GetRegisteredRawInputDevices returned %d, raw_devices_count: %d\n", hr, raw_devices_count); - todo_wine ok(raw_devices[0].usUsagePage == 1, "Unexpected raw device usage page: %x\n", raw_devices[0].usUsagePage); - todo_wine ok(raw_devices[0].usUsage == 2, "Unexpected raw device usage: %x\n", raw_devices[0].usUsage); todo_wine ok(raw_devices[0].dwFlags == RIDEV_INPUTSINK, "Unexpected raw device flags: %x\n", raw_devices[0].dwFlags); todo_wine ok(raw_devices[0].hwndTarget == di_hwnd, "Unexpected raw device target: %p\n", raw_devices[0].hwndTarget); - todo_wine ok(raw_devices[1].usUsagePage == 1, "Unexpected raw device usage page: %x\n", raw_devices[1].usUsagePage); - todo_wine ok(raw_devices[1].usUsage == 5, "Unexpected raw device usage: %x\n", raw_devices[1].usUsage); ok(raw_devices[1].dwFlags == 0, "Unexpected raw device flags: %x\n", raw_devices[1].dwFlags); - todo_wine ok(raw_devices[1].hwndTarget == hwnd, "Unexpected raw device target: %p\n", raw_devices[1].hwndTarget); - todo_wine ok(raw_devices[2].usUsagePage == 1, "Unexpected raw device usage page: %x\n", raw_devices[1].usUsagePage); - todo_wine ok(raw_devices[2].usUsage == 6, "Unexpected raw device usage: %x\n", raw_devices[1].usUsage); todo_wine ok(raw_devices[2].dwFlags == RIDEV_INPUTSINK, "Unexpected raw device flags: %x\n", raw_devices[1].dwFlags); @@ -727,12 +716,10 @@ static void test_mouse_keyboard(void) hr = GetRegisteredRawInputDevices(raw_devices, &raw_devices_count, sizeof(RAWINPUTDEVICE)); todo_wine ok(hr == 1, "GetRegisteredRawInputDevices returned %d, raw_devices_count: %d\n", hr, raw_devices_count); - todo_wine ok(raw_devices[0].usUsagePage == 1, "Unexpected raw device usage page: %x\n", raw_devices[0].usUsagePage); todo_wine ok(raw_devices[0].usUsage == 5, "Unexpected raw device usage: %x\n", raw_devices[0].usUsage); ok(raw_devices[0].dwFlags == 0, "Unexpected raw device flags: %x\n", raw_devices[0].dwFlags); - todo_wine ok(raw_devices[0].hwndTarget == hwnd, "Unexpected raw device target: %p\n", raw_devices[0].hwndTarget);
IDirectInputDevice8_Release(di_mouse); diff --git a/dlls/user32/rawinput.c b/dlls/user32/rawinput.c index b5af008e885..f33f21eee9d 100644 --- a/dlls/user32/rawinput.c +++ b/dlls/user32/rawinput.c @@ -732,14 +732,60 @@ UINT WINAPI GetRawInputDeviceInfoW(HANDLE handle, UINT command, void *data, UINT return *data_size; }
+static int compare_raw_input_devices(const void *ap, const void *bp) +{ + const RAWINPUTDEVICE a = *(const RAWINPUTDEVICE *)ap; + const RAWINPUTDEVICE b = *(const RAWINPUTDEVICE *)bp; + + if (a.usUsagePage != b.usUsagePage) return a.usUsagePage - b.usUsagePage; + if (a.usUsage != b.usUsage) return a.usUsage - b.usUsage; + return 0; +} + /*********************************************************************** * GetRegisteredRawInputDevices (USER32.@) */ UINT WINAPI DECLSPEC_HOTPATCH GetRegisteredRawInputDevices(RAWINPUTDEVICE *devices, UINT *device_count, UINT size) { - FIXME("devices %p, device_count %p, size %u stub!\n", devices, device_count, size); + struct rawinput_device *buffer = NULL; + unsigned int i, status, count = ~0U, buffer_size;
- return 0; + TRACE("devices %p, device_count %p, size %u\n", devices, device_count, size); + + if (size != sizeof(RAWINPUTDEVICE) || !device_count || (devices && !*device_count)) + { + SetLastError(ERROR_INVALID_PARAMETER); + return ~0U; + } + + buffer_size = *device_count * sizeof(*buffer); + if (devices && !(buffer = HeapAlloc(GetProcessHeap(), 0, buffer_size))) + return ~0U; + + SERVER_START_REQ(get_rawinput_devices) + { + if (buffer) wine_server_set_reply(req, buffer, buffer_size); + status = wine_server_call_err(req); + *device_count = reply->device_count; + } + SERVER_END_REQ; + + if (buffer && !status) + { + for (i = 0, count = *device_count; i < count; ++i) + { + devices[i].usUsagePage = buffer[i].usage_page; + devices[i].usUsage = buffer[i].usage; + devices[i].dwFlags = buffer[i].flags; + devices[i].hwndTarget = wine_server_ptr_handle(buffer[i].target); + } + + qsort(devices, count, sizeof(*devices), compare_raw_input_devices); + } + + if (buffer) HeapFree(GetProcessHeap(), 0, buffer); + else count = 0; + return count; }
diff --git a/dlls/user32/tests/input.c b/dlls/user32/tests/input.c index 4310ad1f296..cea8f375398 100644 --- a/dlls/user32/tests/input.c +++ b/dlls/user32/tests/input.c @@ -1794,25 +1794,20 @@ static void test_RegisterRawInputDevices(void)
SetLastError(0xdeadbeef); count = GetRegisteredRawInputDevices(NULL, NULL, 0); - todo_wine ok(count == ~0U, "GetRegisteredRawInputDevices returned %u\n", count); - todo_wine ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetRegisteredRawInputDevices unexpected error %08x\n", GetLastError());
SetLastError(0xdeadbeef); raw_devices_count = 0; count = GetRegisteredRawInputDevices(NULL, &raw_devices_count, 0); - todo_wine ok(count == ~0U, "GetRegisteredRawInputDevices returned %u\n", count); ok(raw_devices_count == 0, "Unexpected registered devices count: %u\n", raw_devices_count); - todo_wine ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetRegisteredRawInputDevices unexpected error %08x\n", GetLastError());
SetLastError(0xdeadbeef); raw_devices_count = 0; count = GetRegisteredRawInputDevices(NULL, &raw_devices_count, sizeof(RAWINPUTDEVICE)); ok(count == 0, "GetRegisteredRawInputDevices returned %u\n", count); - todo_wine ok(raw_devices_count == 2, "Unexpected registered devices count: %u\n", raw_devices_count); ok(GetLastError() == 0xdeadbeef, "GetRegisteredRawInputDevices unexpected error %08x\n", GetLastError());
@@ -1823,38 +1818,28 @@ static void test_RegisterRawInputDevices(void) win_skip("Ignoring GetRegisteredRawInputDevices success\n"); else { - todo_wine ok(count == ~0U, "GetRegisteredRawInputDevices returned %u\n", count); ok(raw_devices_count == 0, "Unexpected registered devices count: %u\n", raw_devices_count); - todo_wine ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetRegisteredRawInputDevices unexpected error %08x\n", GetLastError()); }
SetLastError(0xdeadbeef); raw_devices_count = 1; count = GetRegisteredRawInputDevices(raw_devices, &raw_devices_count, sizeof(RAWINPUTDEVICE)); - todo_wine ok(count == ~0U, "GetRegisteredRawInputDevices returned %u\n", count); - todo_wine ok(raw_devices_count == 2, "Unexpected registered devices count: %u\n", raw_devices_count); - todo_wine ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "GetRegisteredRawInputDevices unexpected error %08x\n", GetLastError());
SetLastError(0xdeadbeef); memset(raw_devices, 0, sizeof(raw_devices)); raw_devices_count = ARRAY_SIZE(raw_devices); count = GetRegisteredRawInputDevices(raw_devices, &raw_devices_count, sizeof(RAWINPUTDEVICE)); - todo_wine ok(count == 2, "GetRegisteredRawInputDevices returned %u\n", count); ok(raw_devices_count == 2, "Unexpected registered devices count: %u\n", raw_devices_count); ok(GetLastError() == 0xdeadbeef, "GetRegisteredRawInputDevices unexpected error %08x\n", GetLastError()); - todo_wine ok(raw_devices[0].usUsagePage == 0x01, "Unexpected usage page: %x\n", raw_devices[0].usUsagePage); - todo_wine ok(raw_devices[0].usUsage == 0x04, "Unexpected usage: %x\n", raw_devices[0].usUsage); - todo_wine ok(raw_devices[1].usUsagePage == 0x01, "Unexpected usage page: %x\n", raw_devices[1].usUsagePage); - todo_wine ok(raw_devices[1].usUsage == 0x05, "Unexpected usage: %x\n", raw_devices[1].usUsage);
/* RIDEV_REMOVE requires hwndTarget == NULL */ diff --git a/server/protocol.def b/server/protocol.def index 6416306c0a1..56fda14932d 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -3899,6 +3899,12 @@ struct handle_info VARARG(devices,rawinput_devices); @END
+/* Retrieve the list of registered rawinput devices */ +@REQ(get_rawinput_devices) +@REPLY + unsigned int device_count; + VARARG(devices,rawinput_devices); +@END
/* Create a new job object */ @REQ(create_job) diff --git a/server/queue.c b/server/queue.c index 432885f9e4c..3ba774ebd1d 100644 --- a/server/queue.c +++ b/server/queue.c @@ -3283,3 +3283,25 @@ DECL_HANDLER(update_rawinput_devices) e = find_rawinput_device( 1, 6 ); current->process->rawinput_kbd = e ? &e->device : NULL; } + +DECL_HANDLER(get_rawinput_devices) +{ + struct rawinput_device_entry *e; + struct rawinput_device *devices; + unsigned int i = 0, device_count = list_count( ¤t->process->rawinput_devices ); + unsigned int size = device_count * sizeof(*devices); + + reply->device_count = device_count; + + /* no buffer provided, nothing else to do */ + if (!get_reply_max_size()) return; + + if (size > get_reply_max_size()) + set_error( STATUS_BUFFER_TOO_SMALL ); + else if ((devices = mem_alloc( size ))) + { + LIST_FOR_EACH_ENTRY( e, ¤t->process->rawinput_devices, struct rawinput_device_entry, entry ) + devices[i++] = e->device; + set_reply_data_ptr( devices, size ); + } +}
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=74733
Your paranoid android.
=== debiant (32 bit report) ===
user32: monitor: Timeout msg: Timeout resource: Timeout scroll: Timeout static: Timeout sysparams: Timeout text: Timeout
=== debiant (32 bit French report) ===
user32: input.c:2541: Test failed: 4: Unexpected cursor movement input.c:2541: Test failed: 5: Unexpected cursor movement input.c:2541: Test failed: 6: Unexpected cursor movement input.c:2541: Test failed: 7: Unexpected cursor movement input.c:2541: Test failed: 8: Unexpected cursor movement input.c:2262: Test failed: 9: foreground process expected WM_MOUSEMOVE message input.c:2541: Test failed: 9: Unexpected cursor movement input.c:2262: Test failed: 10: foreground process expected WM_MOUSEMOVE message input.c:2541: Test failed: 10: Unexpected cursor movement input.c:2262: Test failed: 11: foreground process expected WM_MOUSEMOVE message input.c:2541: Test failed: 11: Unexpected cursor movement input.c:2262: Test failed: 12: foreground process expected WM_MOUSEMOVE message input.c:2541: Test failed: 12: Unexpected cursor movement input.c:2541: Test failed: 13: Unexpected cursor movement input.c:2541: Test failed: 14: Unexpected cursor movement input.c:2541: Test failed: 15: Unexpected cursor movement input.c:2541: Test failed: 16: Unexpected cursor movement
=== debiant (32 bit Japanese:Japan report) ===
user32: input.c:2541: Test failed: 4: Unexpected cursor movement input.c:2541: Test failed: 5: Unexpected cursor movement input.c:2541: Test failed: 6: Unexpected cursor movement input.c:2541: Test failed: 7: Unexpected cursor movement input.c:2541: Test failed: 8: Unexpected cursor movement input.c:2262: Test failed: 9: foreground process expected WM_MOUSEMOVE message input.c:2541: Test failed: 9: Unexpected cursor movement input.c:2262: Test failed: 10: foreground process expected WM_MOUSEMOVE message input.c:2541: Test failed: 10: Unexpected cursor movement input.c:2262: Test failed: 11: foreground process expected WM_MOUSEMOVE message input.c:2541: Test failed: 11: Unexpected cursor movement input.c:2262: Test failed: 12: foreground process expected WM_MOUSEMOVE message input.c:2541: Test failed: 12: Unexpected cursor movement input.c:2541: Test failed: 13: Unexpected cursor movement input.c:2541: Test failed: 14: Unexpected cursor movement input.c:2541: Test failed: 15: Unexpected cursor movement input.c:2541: Test failed: 16: Unexpected cursor movement
=== debiant (32 bit Chinese:China report) ===
user32: input.c:2541: Test failed: 4: Unexpected cursor movement input.c:2541: Test failed: 5: Unexpected cursor movement input.c:2541: Test failed: 6: Unexpected cursor movement input.c:2541: Test failed: 7: Unexpected cursor movement input.c:2541: Test failed: 8: Unexpected cursor movement input.c:2262: Test failed: 9: foreground process expected WM_MOUSEMOVE message input.c:2541: Test failed: 9: Unexpected cursor movement input.c:2262: Test failed: 10: foreground process expected WM_MOUSEMOVE message input.c:2541: Test failed: 10: Unexpected cursor movement input.c:2262: Test failed: 11: foreground process expected WM_MOUSEMOVE message input.c:2541: Test failed: 11: Unexpected cursor movement input.c:input.c2262:: Test failed: 254112: Test failed: : foreground process expected WM_MOUSEMOVE message input.c:2541: Test failed: 13: Unexpected cursor movement input.c:2541: Test failed: 14: Unexpected cursor movement input.c:2541: Test failed: 15: Unexpected cursor movement input.c:2541: Test failed: 16: Unexpected cursor movement monitor: Timeout msg: Timeout resource: Timeout scroll: Timeout static: Timeout
=== debiant (32 bit WoW report) ===
user32: monitor: Timeout msg: Timeout resource: Timeout scroll: Timeout static: Timeout sysparams: Timeout text: Timeout
=== debiant (64 bit WoW report) ===
user32: clipboard.c:760: Test failed: 2: gle 5 clipboard.c:765: Test failed: 2.0: got 0000 instead of 000d clipboard.c:805: Test failed: 2: gle 1418 clipboard.c:815: Test failed: 2: count 4 clipboard.c:818: Test failed: 2: gle 1418 clipboard.c:833: Test failed: 2: gle 5 clipboard.c:838: Test failed: 2.0: got 0000 instead of 000d clipboard.c:868: Test failed: 2: gle 1418 input.c:2541: Test failed: 4: Unexpected cursor movement input.c:2541: Test failed: 5: Unexpected cursor movement input.c:2541: Test failed: 6: Unexpected cursor movement input.c:2541: Test failed: 7: Unexpected cursor movement input.c:2541: Test failed: 8: Unexpected cursor movement input.c:2262: Test failed: 9: foreground process expected WM_MOUSEMOVE message input.c:2541: Test failed: 9: Unexpected cursor movement input.c:2262: Test failed: 10: foreground process expected WM_MOUSEMOVE message input.c:2541: Test failed: 10: Unexpected cursor movement input.c:2262: Test failed: 11: foreground process expected WM_MOUSEMOVE message input.c:2541: Test failed: 11: Unexpected cursor movement input.c:2262: Test failed: 12: foreground process expected WM_MOUSEMOVE message input.c:2541: Test failed: 12: Unexpected cursor movement input.c:2541: Test failed: 13: Unexpected cursor movement input.c:2541: Test failed: 14: Unexpected cursor movement input.c:2541: Test failed: 15: Unexpected cursor movement input.c:2541: Test failed: 16: Unexpected cursor movement monitor: Timeout msg: Timeout resource: Timeout scroll: Timeout static: Timeout
On 2020-07-03 13:00, Marvin wrote:
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=74733
Your paranoid android.
=== debiant (32 bit report) ===
user32: monitor: Timeout msg: Timeout resource: Timeout scroll: Timeout static: Timeout sysparams: Timeout text: Timeout
=== debiant (32 bit French report) ===
user32: input.c:2541: Test failed: 4: Unexpected cursor movement input.c:2541: Test failed: 5: Unexpected cursor movement input.c:2541: Test failed: 6: Unexpected cursor movement input.c:2541: Test failed: 7: Unexpected cursor movement input.c:2541: Test failed: 8: Unexpected cursor movement input.c:2262: Test failed: 9: foreground process expected WM_MOUSEMOVE message input.c:2541: Test failed: 9: Unexpected cursor movement input.c:2262: Test failed: 10: foreground process expected WM_MOUSEMOVE message input.c:2541: Test failed: 10: Unexpected cursor movement input.c:2262: Test failed: 11: foreground process expected WM_MOUSEMOVE message input.c:2541: Test failed: 11: Unexpected cursor movement input.c:2262: Test failed: 12: foreground process expected WM_MOUSEMOVE message input.c:2541: Test failed: 12: Unexpected cursor movement input.c:2541: Test failed: 13: Unexpected cursor movement input.c:2541: Test failed: 14: Unexpected cursor movement input.c:2541: Test failed: 15: Unexpected cursor movement input.c:2541: Test failed: 16: Unexpected cursor movement
=== debiant (32 bit Japanese:Japan report) ===
user32: input.c:2541: Test failed: 4: Unexpected cursor movement input.c:2541: Test failed: 5: Unexpected cursor movement input.c:2541: Test failed: 6: Unexpected cursor movement input.c:2541: Test failed: 7: Unexpected cursor movement input.c:2541: Test failed: 8: Unexpected cursor movement input.c:2262: Test failed: 9: foreground process expected WM_MOUSEMOVE message input.c:2541: Test failed: 9: Unexpected cursor movement input.c:2262: Test failed: 10: foreground process expected WM_MOUSEMOVE message input.c:2541: Test failed: 10: Unexpected cursor movement input.c:2262: Test failed: 11: foreground process expected WM_MOUSEMOVE message input.c:2541: Test failed: 11: Unexpected cursor movement input.c:2262: Test failed: 12: foreground process expected WM_MOUSEMOVE message input.c:2541: Test failed: 12: Unexpected cursor movement input.c:2541: Test failed: 13: Unexpected cursor movement input.c:2541: Test failed: 14: Unexpected cursor movement input.c:2541: Test failed: 15: Unexpected cursor movement input.c:2541: Test failed: 16: Unexpected cursor movement
=== debiant (32 bit Chinese:China report) ===
user32: input.c:2541: Test failed: 4: Unexpected cursor movement input.c:2541: Test failed: 5: Unexpected cursor movement input.c:2541: Test failed: 6: Unexpected cursor movement input.c:2541: Test failed: 7: Unexpected cursor movement input.c:2541: Test failed: 8: Unexpected cursor movement input.c:2262: Test failed: 9: foreground process expected WM_MOUSEMOVE message input.c:2541: Test failed: 9: Unexpected cursor movement input.c:2262: Test failed: 10: foreground process expected WM_MOUSEMOVE message input.c:2541: Test failed: 10: Unexpected cursor movement input.c:2262: Test failed: 11: foreground process expected WM_MOUSEMOVE message input.c:2541: Test failed: 11: Unexpected cursor movement input.c:input.c2262:: Test failed: 254112: Test failed: : foreground process expected WM_MOUSEMOVE message input.c:2541: Test failed: 13: Unexpected cursor movement input.c:2541: Test failed: 14: Unexpected cursor movement input.c:2541: Test failed: 15: Unexpected cursor movement input.c:2541: Test failed: 16: Unexpected cursor movement monitor: Timeout msg: Timeout resource: Timeout scroll: Timeout static: Timeout
=== debiant (32 bit WoW report) ===
user32: monitor: Timeout msg: Timeout resource: Timeout scroll: Timeout static: Timeout sysparams: Timeout text: Timeout
=== debiant (64 bit WoW report) ===
user32: clipboard.c:760: Test failed: 2: gle 5 clipboard.c:765: Test failed: 2.0: got 0000 instead of 000d clipboard.c:805: Test failed: 2: gle 1418 clipboard.c:815: Test failed: 2: count 4 clipboard.c:818: Test failed: 2: gle 1418 clipboard.c:833: Test failed: 2: gle 5 clipboard.c:838: Test failed: 2.0: got 0000 instead of 000d clipboard.c:868: Test failed: 2: gle 1418 input.c:2541: Test failed: 4: Unexpected cursor movement input.c:2541: Test failed: 5: Unexpected cursor movement input.c:2541: Test failed: 6: Unexpected cursor movement input.c:2541: Test failed: 7: Unexpected cursor movement input.c:2541: Test failed: 8: Unexpected cursor movement input.c:2262: Test failed: 9: foreground process expected WM_MOUSEMOVE message input.c:2541: Test failed: 9: Unexpected cursor movement input.c:2262: Test failed: 10: foreground process expected WM_MOUSEMOVE message input.c:2541: Test failed: 10: Unexpected cursor movement input.c:2262: Test failed: 11: foreground process expected WM_MOUSEMOVE message input.c:2541: Test failed: 11: Unexpected cursor movement input.c:2262: Test failed: 12: foreground process expected WM_MOUSEMOVE message input.c:2541: Test failed: 12: Unexpected cursor movement input.c:2541: Test failed: 13: Unexpected cursor movement input.c:2541: Test failed: 14: Unexpected cursor movement input.c:2541: Test failed: 15: Unexpected cursor movement input.c:2541: Test failed: 16: Unexpected cursor movement monitor: Timeout msg: Timeout resource: Timeout scroll: Timeout static: Timeout
I'm not sure what's causing these timeouts, when i re-run the patch manually, it succeeds in these tests:
https://testbot.winehq.org/JobDetails.pl?Key=74744
On Fri, 3 Jul 2020, Rémi Bernon wrote: [...]
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=74733
[...]
=== debiant (32 bit report) ===
user32: monitor: Timeout msg: Timeout resource: Timeout scroll: Timeout static: Timeout sysparams: Timeout text: Timeout
[...]
I'm not sure what's causing these timeouts, when i re-run the patch manually, it succeeds in these tests:
This job only ran user32:input which also ran "normally" in 74733. So we don't know if the other tests would have timed out.
It does look like the 74744 job was meant to run more tests (based on the "user32 input monitor msg resource scroll static" arguments) but iirc it's not possible with manually submitted jobs.
On 2020-07-03 14:57, Francois Gouget wrote:
On Fri, 3 Jul 2020, Rémi Bernon wrote: [...]
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=74733
[...]
=== debiant (32 bit report) ===
user32: monitor: Timeout msg: Timeout resource: Timeout scroll: Timeout static: Timeout sysparams: Timeout text: Timeout
[...]
I'm not sure what's causing these timeouts, when i re-run the patch manually, it succeeds in these tests:
This job only ran user32:input which also ran "normally" in 74733. So we don't know if the other tests would have timed out.
It does look like the 74744 job was meant to run more tests (based on the "user32 input monitor msg resource scroll static" arguments) but iirc it's not possible with manually submitted jobs.
Ah indeed, I thought I could add more arguments to run them all.
The monitor test causes a Xephyr segmentation fault locally, but the msg test seems to run fine. I wonder if it could be snowballing from the monitor test.
On Fri, 3 Jul 2020, Rémi Bernon wrote: [...]
Ah indeed, I thought I could add more arguments to run them all.
The monitor test causes a Xephyr segmentation fault locally, but the msg test seems to run fine. I wonder if it could be snowballing from the monitor test.
I don't see X error messages in the "full task log". But if X segfaulted directly that would probably not be visible there.
I never tested it but if X segfaults I suspect we'd get back to the chooser which should reconnect the default user after the standard timeout (<30 seconds) and the tests are likely to continue running in the meantime. It's possible they could be stuck while X is restarting which could explain the string of timeouts.
It may be possible to test for this condition by starting an independent windows process displaying a window in an early test (CreateProcess("clock.exe")?) and checking the final screenshot to see if that window is still there.
On 2020-07-03 15:32, Francois Gouget wrote:
On Fri, 3 Jul 2020, Rémi Bernon wrote: [...]
Ah indeed, I thought I could add more arguments to run them all.
The monitor test causes a Xephyr segmentation fault locally, but the msg test seems to run fine. I wonder if it could be snowballing from the monitor test.
I don't see X error messages in the "full task log". But if X segfaulted directly that would probably not be visible there.
I never tested it but if X segfaults I suspect we'd get back to the chooser which should reconnect the default user after the standard timeout (<30 seconds) and the tests are likely to continue running in the meantime. It's possible they could be stuck while X is restarting which could explain the string of timeouts.
It may be possible to test for this condition by starting an independent windows process displaying a window in an early test (CreateProcess("clock.exe")?) and checking the final screenshot to see if that window is still there.
I cancelled the remaining tests as it was taking way too long to timeout. I'm also investigating the monitor test, as the other tests run fine separately (at least msg, as shown here: https://testbot.winehq.org/JobDetails.pl?Key=74749). My local Xephyr crash seems actually unrelated (sadly).
On 2020-07-03 15:48, Rémi Bernon wrote:
On 2020-07-03 15:32, Francois Gouget wrote:
On Fri, 3 Jul 2020, Rémi Bernon wrote: [...]
Ah indeed, I thought I could add more arguments to run them all.
The monitor test causes a Xephyr segmentation fault locally, but the msg test seems to run fine. I wonder if it could be snowballing from the monitor test.
I don't see X error messages in the "full task log". But if X segfaulted directly that would probably not be visible there.
I never tested it but if X segfaults I suspect we'd get back to the chooser which should reconnect the default user after the standard timeout (<30 seconds) and the tests are likely to continue running in the meantime. It's possible they could be stuck while X is restarting which could explain the string of timeouts.
It may be possible to test for this condition by starting an independent windows process displaying a window in an early test (CreateProcess("clock.exe")?) and checking the final screenshot to see if that window is still there.
I cancelled the remaining tests as it was taking way too long to timeout. I'm also investigating the monitor test, as the other tests run fine separately (at least msg, as shown here: https://testbot.winehq.org/JobDetails.pl?Key=74749). My local Xephyr crash seems actually unrelated (sadly).
It looks like that applying the mode changes by calling
ChangeDisplaySettingsExA(NULL ...)
sometimes takes an unusually long time, up to ~100s for a single mode change for instance, as shown here:
https://testbot.winehq.org/JobDetails.pl?Key=74774&f101=win32.report#k10...
With all the modes being iterated, it's no wonder that it ends up timing out. I think that it may be possible that the timeout then causes additional issues, if the process is killed during the mode change?
On 2020-07-03 17:05, Rémi Bernon wrote:
On 2020-07-03 15:48, Rémi Bernon wrote:
On 2020-07-03 15:32, Francois Gouget wrote:
On Fri, 3 Jul 2020, Rémi Bernon wrote: [...]
Ah indeed, I thought I could add more arguments to run them all.
The monitor test causes a Xephyr segmentation fault locally, but the msg test seems to run fine. I wonder if it could be snowballing from the monitor test.
I don't see X error messages in the "full task log". But if X segfaulted directly that would probably not be visible there.
I never tested it but if X segfaults I suspect we'd get back to the chooser which should reconnect the default user after the standard timeout (<30 seconds) and the tests are likely to continue running in the meantime. It's possible they could be stuck while X is restarting which could explain the string of timeouts.
It may be possible to test for this condition by starting an independent windows process displaying a window in an early test (CreateProcess("clock.exe")?) and checking the final screenshot to see if that window is still there.
I cancelled the remaining tests as it was taking way too long to timeout. I'm also investigating the monitor test, as the other tests run fine separately (at least msg, as shown here: https://testbot.winehq.org/JobDetails.pl?Key=74749). My local Xephyr crash seems actually unrelated (sadly).
It looks like that applying the mode changes by calling
ChangeDisplaySettingsExA(NULL ...)
sometimes takes an unusually long time, up to ~100s for a single mode change for instance, as shown here:
https://testbot.winehq.org/JobDetails.pl?Key=74774&f101=win32.report#k10...
With all the modes being iterated, it's no wonder that it ends up timing out. I think that it may be possible that the timeout then causes additional issues, if the process is killed during the mode change?
So it all ends up being this call in xrandr12_set_current_mode:
status = pXRRSetCrtcConfig( gdi_display, resources, resources->crtcs[primary_crtc], CurrentTime, crtc_info->x, crtc_info->y, xrandr12_modes[mode], crtc_info->rotation, crtc_info->outputs, crtc_info->noutput );
that sometimes take ~100s. I can see it consistently in the Win32 tests, when it restores the modes (although it's already in the correct mode), but I disabled the individual mode tests to reduce the test timeouts, so it may also happen in the other archs with the whole test.
I'm not sure what to do about it...
On 7/4/20 12:33 AM, Rémi Bernon wrote:
On 2020-07-03 17:05, Rémi Bernon wrote:
On 2020-07-03 15:48, Rémi Bernon wrote:
On 2020-07-03 15:32, Francois Gouget wrote:
On Fri, 3 Jul 2020, Rémi Bernon wrote: [...]
Ah indeed, I thought I could add more arguments to run them all.
The monitor test causes a Xephyr segmentation fault locally, but the msg test seems to run fine. I wonder if it could be snowballing from the monitor test.
I don't see X error messages in the "full task log". But if X segfaulted directly that would probably not be visible there.
I never tested it but if X segfaults I suspect we'd get back to the chooser which should reconnect the default user after the standard timeout (<30 seconds) and the tests are likely to continue running in the meantime. It's possible they could be stuck while X is restarting which could explain the string of timeouts.
It may be possible to test for this condition by starting an independent windows process displaying a window in an early test (CreateProcess("clock.exe")?) and checking the final screenshot to see if that window is still there.
I cancelled the remaining tests as it was taking way too long to timeout. I'm also investigating the monitor test, as the other tests run fine separately (at least msg, as shown here: https://testbot.winehq.org/JobDetails.pl?Key=74749). My local Xephyr crash seems actually unrelated (sadly).
It looks like that applying the mode changes by calling
ChangeDisplaySettingsExA(NULL ...)
sometimes takes an unusually long time, up to ~100s for a single mode change for instance, as shown here:
https://testbot.winehq.org/JobDetails.pl?Key=74774&f101=win32.report#k10...
With all the modes being iterated, it's no wonder that it ends up timing out. I think that it may be possible that the timeout then causes additional issues, if the process is killed during the mode change?
So it all ends up being this call in xrandr12_set_current_mode:
status = pXRRSetCrtcConfig( gdi_display, resources, resources->crtcs[primary_crtc], CurrentTime, crtc_info->x, crtc_info->y, xrandr12_modes[mode], crtc_info->rotation, crtc_info->outputs, crtc_info->noutput );
that sometimes take ~100s. I can see it consistently in the Win32 tests, when it restores the modes (although it's already in the correct mode), but I disabled the individual mode tests to reduce the test timeouts, so it may also happen in the other archs with the whole test.
I'm not sure what to do about it...
I thought I had a fix but then further investigations turned out that the issue is weirder than I had thought.
The hang happens when Wine calls XRRSetCrtcConfig() with the same mode it already set. The attached patch demonstrates that. But then a test program setting the same mode over and over works fine. See https://testbot.winehq.org/JobDetails.pl?Key=75608 in full log. Also I can't reproduce the hang with the same Debian testing TestBot VMs running on my machine. The hang doesn't appear with Debian 10 TestBots. The last time Debian testing TestBot VMs were updated is June 15th, which is around the time the hangs started happening.
Looking at the source of XRRSetCrtcConfig(), it seems that it was waiting for a XReply that never came. And that xf86-video-qxl has no recent updates. So my theory is that updated xorg-xserver or some other components had a race condition, and currently only manifests itself on TestBots.
The next step would be to investigate it on TestBots, and try an apt-get update. I am not sure what more can be done on my side.
On Fri, 17 Jul 2020, Zhiyi Zhang wrote: [...]
Looking at the source of XRRSetCrtcConfig(), it seems that it was waiting for a XReply that never came. And that xf86-video-qxl has no recent updates.
So my theory is that updated xorg-xserver or some other components had a race condition, and currently only manifests itself on TestBots.
The next step would be to investigate it on TestBots, and try an apt-get update. I am not sure what more can be done on my side.
Given that the TestBot VM is running Debian Testing it's possible that the update got a bad X server version. I will do an update tonight to see if that helps.
I grabbed the package list of debiant before and after the june upgrade for comparison. But the closest I get to relevant package upgrades are a bunch of OpenGL (libegl, libgl1, libgles2) and Mesa driver upgrades. Maybe I missed something.
2020-05-04 -> https://termbin.com/br19 2020-06-15 -> https://termbin.com/8cb9
I also checked for upgrades on the host but there was no upgrade between the 12th of june and the 10th of july.
The upgrade on the 12th was for the intel-microcode package.
On Thu, 16 Jul 2020, Francois Gouget wrote: [...]
I grabbed the package list of debiant before and after the june upgrade for comparison. But the closest I get to relevant package upgrades are a bunch of OpenGL (libegl, libgl1, libgles2) and Mesa driver upgrades. Maybe I missed something.
2020-05-04 -> https://termbin.com/br19 2020-06-15 -> https://termbin.com/8cb9
I have upgraded debiant.
Some packages (libfreetype* and libgpg-error*) won't upgrade because the Debian maintainers saw fit to remove multiarch support from one of the libgpg-error packages!!!
I also kept the old versions for comparison. So if the Reconfig goes well you should have:
debiant -> The main Wine VM, updated on 2020-07-16 debiant0615 -> The troublesome configuration from 2020-06-15 debiant0504 -> The previous configuration from 2020-05-04 which presumably was ok.
On 7/17/20 6:42 AM, Francois Gouget wrote:
On Thu, 16 Jul 2020, Francois Gouget wrote: [...]
I grabbed the package list of debiant before and after the june upgrade for comparison. But the closest I get to relevant package upgrades are a bunch of OpenGL (libegl, libgl1, libgles2) and Mesa driver upgrades. Maybe I missed something.
2020-05-04 -> https://termbin.com/br19 2020-06-15 -> https://termbin.com/8cb9
I have upgraded debiant.
Some packages (libfreetype* and libgpg-error*) won't upgrade because the Debian maintainers saw fit to remove multiarch support from one of the libgpg-error packages!!!
I also kept the old versions for comparison. So if the Reconfig goes well you should have:
debiant -> The main Wine VM, updated on 2020-07-16 debiant0615 -> The troublesome configuration from 2020-06-15 debiant0504 -> The previous configuration from 2020-05-04 which presumably was ok.
Thanks, Francois.
The upgrade makes the problem go away, even for debiant0615. See https://testbot.winehq.org/JobDetails.pl?Key=75654 Sadly, the real issue isn't found.
On Fri, 17 Jul 2020, Zhiyi Zhang wrote: [...]
The upgrade makes the problem go away, even for debiant0615. See https://testbot.winehq.org/JobDetails.pl?Key=75654 Sadly, the real issue isn't found.
The issue did not seem to happen consistently. So it may still appear from time to time (though I hope not). It is strange that it just disappeared.
I ran user32:monitor on my box a few times too (Intel GPU). One thing I noticed is that it ChangeDisplaySettingsEx() often takes about 800 ms. Then flush_events() often adds another 200 ms. Since there are a lot of resolution changes the test takes about 85 seconds. Fortunately that's still under the timeout limit.
43 flush_events calls -> ~8.6 s not sure about the number of ChangeDisplaySettingsEx() but I expect it's more than 43 so that would account for another > 34 s
I also get a bunch of Vulkan warnings that I may be able to fix by explicitly enabling DRI3 (or upgrading to Debian Testing?). Something to test for the next time I reboot... But I don't really expect the delays to be related to these warnings.
monitor.c:651:4.581 ChangeDisplaySettingsExA(\.\DISPLAY1,pos=0,fields=0) INTEL-MESA: warning: Haswell Vulkan support is incomplete INTEL-MESA: warning: Haswell Vulkan support is incomplete INTEL-MESA: warning: Haswell Vulkan support is incomplete INTEL-MESA: warning: Haswell Vulkan support is incomplete INTEL-MESA: warning: Haswell Vulkan support is incomplete INTEL-MESA: warning: Haswell Vulkan support is incomplete INTEL-MESA: warning: Haswell Vulkan support is incomplete INTEL-MESA: warning: Haswell Vulkan support is incomplete INTEL-MESA: warning: Haswell Vulkan support is incomplete INTEL-MESA: warning: Haswell Vulkan support is incomplete monitor.c:665:5.458 Test succeeded monitor.c:674:5.458 flush_events monitor.c:676:5.659 Test succeeded
On 7/17/20 12:00 AM, Zhiyi Zhang wrote:
On 7/4/20 12:33 AM, Rémi Bernon wrote:
On 2020-07-03 17:05, Rémi Bernon wrote:
On 2020-07-03 15:48, Rémi Bernon wrote:
On 2020-07-03 15:32, Francois Gouget wrote:
On Fri, 3 Jul 2020, Rémi Bernon wrote: [...]
Ah indeed, I thought I could add more arguments to run them all.
The monitor test causes a Xephyr segmentation fault locally, but the msg test seems to run fine. I wonder if it could be snowballing from the monitor test.
I don't see X error messages in the "full task log". But if X segfaulted directly that would probably not be visible there.
I never tested it but if X segfaults I suspect we'd get back to the chooser which should reconnect the default user after the standard timeout (<30 seconds) and the tests are likely to continue running in the meantime. It's possible they could be stuck while X is restarting which could explain the string of timeouts.
It may be possible to test for this condition by starting an independent windows process displaying a window in an early test (CreateProcess("clock.exe")?) and checking the final screenshot to see if that window is still there.
I cancelled the remaining tests as it was taking way too long to timeout. I'm also investigating the monitor test, as the other tests run fine separately (at least msg, as shown here: https://testbot.winehq.org/JobDetails.pl?Key=74749). My local Xephyr crash seems actually unrelated (sadly).
It looks like that applying the mode changes by calling
ChangeDisplaySettingsExA(NULL ...)
sometimes takes an unusually long time, up to ~100s for a single mode change for instance, as shown here:
https://testbot.winehq.org/JobDetails.pl?Key=74774&f101=win32.report#k10...
With all the modes being iterated, it's no wonder that it ends up timing out. I think that it may be possible that the timeout then causes additional issues, if the process is killed during the mode change?
So it all ends up being this call in xrandr12_set_current_mode:
status = pXRRSetCrtcConfig( gdi_display, resources, resources->crtcs[primary_crtc], CurrentTime, crtc_info->x, crtc_info->y, xrandr12_modes[mode], crtc_info->rotation, crtc_info->outputs, crtc_info->noutput );
that sometimes take ~100s. I can see it consistently in the Win32 tests, when it restores the modes (although it's already in the correct mode), but I disabled the individual mode tests to reduce the test timeouts, so it may also happen in the other archs with the whole test.
I'm not sure what to do about it...
I thought I had a fix but then further investigations turned out that the issue is weirder than I had thought.
The hang happens when Wine calls XRRSetCrtcConfig() with the same mode it already set. The attached patch demonstrates that. But then a test program setting the same mode over and over works fine. See https://testbot.winehq.org/JobDetails.pl?Key=75608 in full log. Also I can't reproduce the hang with the same Debian testing TestBot VMs running on my machine. The hang doesn't appear with Debian 10 TestBots. The last time Debian testing TestBot VMs were updated is June 15th, which is around the time the hangs started happening.
Looking at the source of XRRSetCrtcConfig(), it seems that it was waiting for a XReply that never came. And that xf86-video-qxl has no recent updates. So my theory is that updated xorg-xserver or some other components had a race condition, and currently only manifests itself on TestBots.
I grabbed the package list of debiant before and after the june upgrade for comparison. But the closest I get to relevant package upgrades are a bunch of OpenGL (libegl, libgl1, libgles2) and Mesa driver upgrades. Maybe I missed something.
2020-05-04 -> https://termbin.com/br19 2020-06-15 -> https://termbin.com/8cb9
It looks like a libX11 bug. Comparing the package list from 2020-05-04 to 2020-06-15, note that libx11-6 was upgraded from 1.6.9-2 to 1.6.9-2+b1. There is XReply bug in both the lastest and 1.6.9 version of libX11 and I think it's being triggered somehow on TestBots. See https://gitlab.freedesktop.org/xorg/lib/libx11/-/issues/93 There is a patch in https://gitlab.freedesktop.org/xorg/lib/libx11/-/merge_requests/29 but it's not merged yet.
Maybe we should downgrade the package for the moment and wait for the fix to land. Or install a custom build with the fix.
On Fri, 7 Aug 2020, Zhiyi Zhang wrote: [...]
I grabbed the package list of debiant before and after the june upgrade for comparison. But the closest I get to relevant package upgrades are a bunch of OpenGL (libegl, libgl1, libgles2) and Mesa driver upgrades. Maybe I missed something.
2020-05-04 -> https://termbin.com/br19 2020-06-15 -> https://termbin.com/8cb9
It looks like a libX11 bug. Comparing the package list from 2020-05-04 to 2020-06-15, note that libx11-6 was upgraded from 1.6.9-2 to 1.6.9-2+b1. There is XReply bug in both the lastest and 1.6.9 version of libX11 and I think it's being triggered somehow on TestBots. See https://gitlab.freedesktop.org/xorg/lib/libx11/-/issues/93 There is a patch in https://gitlab.freedesktop.org/xorg/lib/libx11/-/merge_requests/29 but it's not merged yet.
Maybe we should downgrade the package for the moment and wait for the fix to land. Or install a custom build with the fix.
The most workable options appear to be to either downgrade to 1.6.7-1 (from Debian 10) or upgrade to 1.6.10-3 (current in Debian Testing).
From what you said the latter would not have the fix anyway but I don't
know if the former has the bug already.
WineTest has certainly been wrecking havoc with my desktop's X session lately [1] and it has 1.6.7-1.
[1] I'd typically find it at some very low resolution in the morning. Sometimes xrandr -s 0 would not even work, sometimes xrandr --auto would work instead, and sometimes nothing short of a reboot would revive the monitor.
On 8/7/20 10:54 PM, Francois Gouget wrote:
On Fri, 7 Aug 2020, Zhiyi Zhang wrote: [...]
I grabbed the package list of debiant before and after the june upgrade for comparison. But the closest I get to relevant package upgrades are a bunch of OpenGL (libegl, libgl1, libgles2) and Mesa driver upgrades. Maybe I missed something.
2020-05-04 -> https://termbin.com/br19 2020-06-15 -> https://termbin.com/8cb9
It looks like a libX11 bug. Comparing the package list from 2020-05-04 to 2020-06-15, note that libx11-6 was upgraded from 1.6.9-2 to 1.6.9-2+b1. There is XReply bug in both the lastest and 1.6.9 version of libX11 and I think it's being triggered somehow on TestBots. See https://gitlab.freedesktop.org/xorg/lib/libx11/-/issues/93 There is a patch in https://gitlab.freedesktop.org/xorg/lib/libx11/-/merge_requests/29 but it's not merged yet.
Maybe we should downgrade the package for the moment and wait for the fix to land. Or install a custom build with the fix.
The most workable options appear to be to either downgrade to 1.6.7-1 (from Debian 10) or upgrade to 1.6.10-3 (current in Debian Testing). From what you said the latter would not have the fix anyway but I don't know if the former has the bug already.
Both 1.6.7-1 and 1.6.10-3 have the bug already. But 1.6.7-1 on Debian 10 TestBots didn't have the monitor timeouts before so I think it was using a different code path. I think we should downgrade to 1.6.7-1 first and use a custom build with the fix if we have to, assuming libx11 is the real culprit of course.
WineTest has certainly been wrecking havoc with my desktop's X session lately [1] and it has 1.6.7-1.
[1] I'd typically find it at some very low resolution in the morning. Sometimes xrandr -s 0 would not even work, sometimes xrandr --auto would work instead, and sometimes nothing short of a reboot would revive the monitor.
On Sun, 9 Aug 2020, Zhiyi Zhang wrote: [...]
Both 1.6.7-1 and 1.6.10-3 have the bug already. But 1.6.7-1 on Debian 10 TestBots didn't have the monitor timeouts before so I think it was using a different code path. I think we should downgrade to 1.6.7-1 first and use a custom build with the fix if we have to, assuming libx11 is the real culprit of course.
I downgraded debiant's libx11-6 and libx11-dev to 1.6.7-1. Everything else is identical to the the snapshot I made on 2020-07-16. That snapshot is now available as the 'debiant 0716' VM.
Let me know how it goes.
On 2020-08-09 17:31, Francois Gouget wrote:
On Sun, 9 Aug 2020, Zhiyi Zhang wrote: [...]
Both 1.6.7-1 and 1.6.10-3 have the bug already. But 1.6.7-1 on Debian 10 TestBots didn't have the monitor timeouts before so I think it was using a different code path. I think we should downgrade to 1.6.7-1 first and use a custom build with the fix if we have to, assuming libx11 is the real culprit of course.
I downgraded debiant's libx11-6 and libx11-dev to 1.6.7-1. Everything else is identical to the the snapshot I made on 2020-07-16. That snapshot is now available as the 'debiant 0716' VM.
Let me know how it goes.
It looks better, at least that run didn't timeout:
https://testbot.winehq.org/JobDetails.pl?Key=76735
On 2020-08-10 09:38, Rémi Bernon wrote:
On 2020-08-09 17:31, Francois Gouget wrote:
On Sun, 9 Aug 2020, Zhiyi Zhang wrote: [...]
Both 1.6.7-1 and 1.6.10-3 have the bug already. But 1.6.7-1 on Debian 10 TestBots didn't have the monitor timeouts before so I think it was using a different code path. I think we should downgrade to 1.6.7-1 first and use a custom build with the fix if we have to, assuming libx11 is the real culprit of course.
I downgraded debiant's libx11-6 and libx11-dev to 1.6.7-1. Everything else is identical to the the snapshot I made on 2020-07-16. That snapshot is now available as the 'debiant 0716' VM.
Let me know how it goes.
It looks better, at least that run didn't timeout:
Some other from the patch series I resent did, but at least it's apparently not cascading to other tests anymore.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/dinput8/tests/device.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+)
diff --git a/dlls/dinput8/tests/device.c b/dlls/dinput8/tests/device.c index 328174e5796..6fe9a635510 100644 --- a/dlls/dinput8/tests/device.c +++ b/dlls/dinput8/tests/device.c @@ -712,6 +712,26 @@ static void test_mouse_keyboard(void) todo_wine ok(raw_devices_count == 1, "Unexpected raw devices registered: %d\n", raw_devices_count);
+ IDirectInputDevice8_SetCooperativeLevel(di_mouse, hwnd, DISCL_FOREGROUND|DISCL_EXCLUSIVE); + IDirectInputDevice8_SetCooperativeLevel(di_keyboard, hwnd, DISCL_FOREGROUND|DISCL_EXCLUSIVE); + + hr = IDirectInputDevice8_Acquire(di_keyboard); + ok(SUCCEEDED(hr), "IDirectInputDevice8_Acquire failed: %08x\n", hr); + hr = IDirectInputDevice8_Acquire(di_mouse); + ok(SUCCEEDED(hr), "IDirectInputDevice8_Acquire failed: %08x\n", hr); + raw_devices_count = ARRAY_SIZE(raw_devices); + memset(raw_devices, 0, sizeof(raw_devices)); + hr = GetRegisteredRawInputDevices(raw_devices, &raw_devices_count, sizeof(RAWINPUTDEVICE)); + ok(hr == 3, "GetRegisteredRawInputDevices returned %d, raw_devices_count: %d\n", hr, raw_devices_count); + todo_wine + ok(raw_devices[0].dwFlags == (RIDEV_CAPTUREMOUSE|RIDEV_NOLEGACY), "Unexpected raw device flags: %x\n", raw_devices[0].dwFlags); + todo_wine + ok(raw_devices[2].dwFlags == (RIDEV_NOHOTKEYS|RIDEV_NOLEGACY), "Unexpected raw device flags: %x\n", raw_devices[1].dwFlags); + hr = IDirectInputDevice8_Unacquire(di_keyboard); + ok(SUCCEEDED(hr), "IDirectInputDevice8_Acquire failed: %08x\n", hr); + hr = IDirectInputDevice8_Unacquire(di_mouse); + ok(SUCCEEDED(hr), "IDirectInputDevice8_Acquire failed: %08x\n", hr); + raw_devices_count = ARRAY_SIZE(raw_devices); hr = GetRegisteredRawInputDevices(raw_devices, &raw_devices_count, sizeof(RAWINPUTDEVICE)); todo_wine
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=74734
Your paranoid android.
=== debiant (32 bit report) ===
user32: monitor: Timeout msg: Timeout
=== debiant (32 bit Chinese:China report) ===
user32: monitor: Timeout msg: Timeout resource: Timeout scroll: Timeout static: Timeout
=== debiant (32 bit WoW report) ===
user32: monitor: Timeout msg: Timeout resource: Timeout scroll: Timeout static: Timeout sysparams: Timeout text: Timeout
=== debiant (64 bit WoW report) ===
user32: input.c:2541: Test failed: 4: Unexpected cursor movement input.c:2541: Test failed: 5: Unexpected cursor movement input.c:2541: Test failed: 6: Unexpected cursor movement input.c:2541: Test failed: 7: Unexpected cursor movement input.c:2541: Test failed: 8: Unexpected cursor movement input.c:2262: Test failed: 9: foreground process expected WM_MOUSEMOVE message input.c:2541: Test failed: 9: Unexpected cursor movement input.c:2262: Test failed: 10: foreground process expected WM_MOUSEMOVE message input.c:2541: Test failed: 10: Unexpected cursor movement input.c:2262: Test failed: 11: foreground process expected WM_MOUSEMOVE message input.c:2541: Test failed: 11: Unexpected cursor movement input.c:2262: Test failed: 12: foreground process expected WM_MOUSEMOVE message input.c:2541: Test failed: 12: Unexpected cursor movement input.c:2541: Test failed: 13: Unexpected cursor movement input.c:2541: Test failed: 14: Unexpected cursor movement input.c:2541: Test failed: 15: Unexpected cursor movement input.c:2541: Test failed: 16: Unexpected cursor movement monitor: Timeout msg: Timeout resource: Timeout scroll: Timeout static: Timeout
This adds a message window that will be used as the rawinput target window for WM_INPUT messages.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/dinput/device_private.h | 3 ++ dlls/dinput/dinput_main.c | 77 ++++++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+)
diff --git a/dlls/dinput/device_private.h b/dlls/dinput/device_private.h index fe5644f21c7..2fac4f0e61e 100644 --- a/dlls/dinput/device_private.h +++ b/dlls/dinput/device_private.h @@ -69,6 +69,9 @@ struct IDirectInputDeviceImpl HWND win; int acquired;
+ BOOL use_raw_input; /* use raw input instead of low-level messages */ + RAWINPUTDEVICE raw_device; /* raw device to (un)register */ + LPDIDEVICEOBJECTDATA data_queue; /* buffer for 'GetDeviceData'. */ int queue_len; /* valid size of the queue */ int queue_head; /* position to write new event into queue */ diff --git a/dlls/dinput/dinput_main.c b/dlls/dinput/dinput_main.c index 2e561502406..cd1a11b02fb 100644 --- a/dlls/dinput/dinput_main.c +++ b/dlls/dinput/dinput_main.c @@ -97,6 +97,9 @@ static const struct dinput_device *dinput_devices[] =
HINSTANCE DINPUT_instance;
+static const WCHAR di_em_win_w[] = {'D','I','E','m','W','i','n',0}; +static HWND di_em_win; + static BOOL check_hook_thread(void); static CRITICAL_SECTION dinput_hook_crit; static struct list direct_input_list = LIST_INIT( direct_input_list ); @@ -637,6 +640,45 @@ static HRESULT WINAPI IDirectInputWImpl_QueryInterface(LPDIRECTINPUT7W iface, RE return IDirectInputAImpl_QueryInterface( &This->IDirectInput7A_iface, riid, ppobj ); }
+static LRESULT WINAPI di_em_win_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) +{ + IDirectInputDeviceImpl *dev; + RAWINPUT ri; + UINT size = sizeof(ri); + int rim = GET_RAWINPUT_CODE_WPARAM( wparam ); + + TRACE( "%p %d %lx %lx\n", hwnd, msg, wparam, lparam ); + + if (msg == WM_INPUT && (rim == RIM_INPUT || rim == RIM_INPUTSINK)) + { + size = GetRawInputData( (HRAWINPUT)lparam, RID_INPUT, &ri, &size, sizeof(RAWINPUTHEADER) ); + if (size == (UINT)-1 || size < sizeof(RAWINPUTHEADER)) + WARN( "Unable to read raw input data\n" ); + } + + return DefWindowProcW( hwnd, msg, wparam, lparam ); +} + +static void register_di_em_win_class(void) +{ + WNDCLASSEXW class; + + memset(&class, 0, sizeof(class)); + class.cbSize = sizeof(class); + class.lpfnWndProc = di_em_win_wndproc; + class.hInstance = DINPUT_instance; + class.lpszClassName = di_em_win_w; + + if (!RegisterClassExW( &class ) && GetLastError() != ERROR_CLASS_ALREADY_EXISTS) + WARN( "Unable to register message window class\n" ); +} + +static void unregister_di_em_win_class(void) +{ + if (!UnregisterClassW( di_em_win_w, NULL ) && GetLastError() != ERROR_CLASS_DOES_NOT_EXIST) + WARN( "Unable to unregister message window class\n" ); +} + static HRESULT initialize_directinput_instance(IDirectInputImpl *This, DWORD dwVersion) { if (!This->initialized) @@ -1668,11 +1710,13 @@ static LRESULT CALLBACK LL_hook_proc( int code, WPARAM wparam, LPARAM lparam ) EnterCriticalSection( &dinput_hook_crit ); LIST_FOR_EACH_ENTRY( dev, &acquired_mouse_list, IDirectInputDeviceImpl, entry ) { + if (dev->use_raw_input) continue; TRACE("calling dinput_mouse_hook (%p %lx %lx)\n", dev, wparam, lparam); skip |= dinput_mouse_hook( &dev->IDirectInputDevice8A_iface, wparam, lparam ); } LIST_FOR_EACH_ENTRY( dev, &acquired_keyboard_list, IDirectInputDeviceImpl, entry ) { + if (dev->use_raw_input) continue; TRACE("calling dinput_keyboard_hook (%p %lx %lx)\n", dev, wparam, lparam); skip |= dinput_keyboard_hook( &dev->IDirectInputDevice8A_iface, wparam, lparam ); } @@ -1728,6 +1772,9 @@ static DWORD WINAPI hook_thread_proc(void *param) static HHOOK kbd_hook, mouse_hook; MSG msg;
+ di_em_win = CreateWindowW( di_em_win_w, di_em_win_w, 0, 0, 0, 0, 0, + HWND_MESSAGE, 0, DINPUT_instance, NULL ); + /* Force creation of the message queue */ PeekMessageW( &msg, 0, 0, 0, PM_NOREMOVE ); SetEvent(param); @@ -1778,6 +1825,9 @@ static DWORD WINAPI hook_thread_proc(void *param) DispatchMessageW(&msg); }
+ DestroyWindow( di_em_win ); + di_em_win = NULL; + FreeLibraryAndExitThread(DINPUT_instance, 0); }
@@ -1860,6 +1910,31 @@ void check_dinput_hooks(LPDIRECTINPUTDEVICE8W iface, BOOL acquired) hook_thread_event = NULL; }
+ if (dev->use_raw_input) + { + if (acquired) + { + dev->raw_device.dwFlags = 0; + if (dev->dwCoopLevel & DISCL_BACKGROUND) + dev->raw_device.dwFlags |= RIDEV_INPUTSINK; + if (dev->dwCoopLevel & DISCL_EXCLUSIVE) + dev->raw_device.dwFlags |= RIDEV_NOLEGACY; + if ((dev->dwCoopLevel & DISCL_EXCLUSIVE) && dev->raw_device.usUsage == 2) + dev->raw_device.dwFlags |= RIDEV_CAPTUREMOUSE; + if ((dev->dwCoopLevel & DISCL_EXCLUSIVE) && dev->raw_device.usUsage == 6) + dev->raw_device.dwFlags |= RIDEV_NOHOTKEYS; + dev->raw_device.hwndTarget = di_em_win; + } + else + { + dev->raw_device.dwFlags = RIDEV_REMOVE; + dev->raw_device.hwndTarget = NULL; + } + + if (!RegisterRawInputDevices( &dev->raw_device, 1, sizeof(RAWINPUTDEVICE) )) + WARN( "Unable to (un)register raw device %x:%x\n", dev->raw_device.usUsagePage, dev->raw_device.usUsage ); + } + if (acquired) hook_change_finished_event = CreateEventW( NULL, FALSE, FALSE, NULL ); PostThreadMessageW( hook_thread_id, WM_USER+0x10, 1, (LPARAM)hook_change_finished_event ); @@ -1894,9 +1969,11 @@ BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, LPVOID reserved) case DLL_PROCESS_ATTACH: DisableThreadLibraryCalls(inst); DINPUT_instance = inst; + register_di_em_win_class(); break; case DLL_PROCESS_DETACH: if (reserved) break; + unregister_di_em_win_class(); DeleteCriticalSection(&dinput_hook_crit); break; }
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=74735
Your paranoid android.
=== debiant (32 bit report) ===
user32: monitor: Timeout msg: Timeout resource: Timeout scroll: Timeout static: Timeout sysparams: Timeout text: Timeout
=== debiant (32 bit Chinese:China report) ===
user32: input.c:2541: Test failed: 4: Unexpected cursor movement input.c:2541: Test failed: 5: Unexpected cursor movement input.c:2541: Test failed: 6: Unexpected cursor movement input.c:2541: Test failed: 7: Unexpected cursor movement input.c:2541: Test failed: 8: Unexpected cursor movement input.c:2262: Test failed: 9: foreground process expected WM_MOUSEMOVE message input.c:2541: Test failed: 9: Unexpected cursor movement input.c:2262: Test failed: 10: foreground process expected WM_MOUSEMOVE message input.c:2541: Test failed: 10: Unexpected cursor movement input.c:2262: Test failed: 11: foreground process expected WM_MOUSEMOVE message input.c:2541: Test failed: 11: Unexpected cursor movement input.c:2262: Test failed: 12: foreground process expected WM_MOUSEMOVE message input.c:2541: Test failed: 12: Unexpected cursor movement input.c:2541: Test failed: 13: Unexpected cursor movement input.c:2541: Test failed: 14: Unexpected cursor movement input.c:2541: Test failed: 15: Unexpected cursor movement input.c:2541: Test failed: 16: Unexpected cursor movement monitor: Timeout msg: Timeout resource: Timeout scroll: Timeout static: Timeout
=== debiant (32 bit WoW report) ===
user32: monitor: Timeout msg: Timeout resource: Timeout scroll: Timeout static: Timeout sysparams: Timeout text: Timeout
=== debiant (64 bit WoW report) ===
dinput: mouse.c:178: Test failed: GetDeviceData() failed: 00000000 cnt:0
user32: clipboard.c:760: Test failed: 2: gle 5 clipboard.c:765: Test failed: 2.0: got 0000 instead of 000d clipboard.c:805: Test failed: 2: gle 1418 clipboard.c:815: Test failed: 2: count 4 clipboard.c:818: Test failed: 2: gle 1418 clipboard.c:853: Test failed: 2.0: formats 00000000 have been rendered clipboard.c:858: Test failed: 2.0: formats 00000000 have been rendered clipboard.c:853: Test failed: 2.2: formats 00000000 have been rendered clipboard.c:858: Test failed: 2.2: formats 00000000 have been rendered clipboard.c:853: Test failed: 2.3: formats 00000000 have been rendered clipboard.c:858: Test failed: 2.3: formats 00000000 have been rendered input.c:2541: Test failed: 4: Unexpected cursor movement input.c:2541: Test failed: 5: Unexpected cursor movement input.c:2541: Test failed: 6: Unexpected cursor movement input.c:2541: Test failed: 7: Unexpected cursor movement input.c:2541: Test failed: 8: Unexpected cursor movement input.c:2262: Test failed: 9: foreground process expected WM_MOUSEMOVE message input.c:2541: Test failed: 9: Unexpected cursor movement input.c:2262: Test failed: 10: foreground process expected WM_MOUSEMOVE message input.c:2541: Test failed: 10: Unexpected cursor movement input.c:2262: Test failed: 11: foreground process expected WM_MOUSEMOVE message input.c:2541: Test failed: 11: Unexpected cursor movement input.c:2262: Test failed: 12: foreground process expected WM_MOUSEMOVE message input.c:2541: Test failed: 12: Unexpected cursor movement input.c:2541: Test failed: 13: Unexpected cursor movement input.c:2541: Test failed: 14: Unexpected cursor movement input.c:2541: Test failed: 15: Unexpected cursor movement input.c:2541: Test failed: 16: Unexpected cursor movement monitor: Timeout msg: Timeout resource: Timeout scroll: Timeout static: Timeout
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/dinput/dinput_main.c | 10 ++++ dlls/dinput/dinput_private.h | 1 + dlls/dinput/mouse.c | 90 ++++++++++++++++++++++++++++++++++++ dlls/dinput8/tests/device.c | 11 ++--- 4 files changed, 104 insertions(+), 8 deletions(-)
diff --git a/dlls/dinput/dinput_main.c b/dlls/dinput/dinput_main.c index cd1a11b02fb..1c4a26987f9 100644 --- a/dlls/dinput/dinput_main.c +++ b/dlls/dinput/dinput_main.c @@ -654,6 +654,16 @@ static LRESULT WINAPI di_em_win_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPAR size = GetRawInputData( (HRAWINPUT)lparam, RID_INPUT, &ri, &size, sizeof(RAWINPUTHEADER) ); if (size == (UINT)-1 || size < sizeof(RAWINPUTHEADER)) WARN( "Unable to read raw input data\n" ); + else if (ri.header.dwType == RIM_TYPEMOUSE) + { + EnterCriticalSection( &dinput_hook_crit ); + LIST_FOR_EACH_ENTRY( dev, &acquired_mouse_list, IDirectInputDeviceImpl, entry ) + { + if (!dev->use_raw_input) continue; + dinput_mouse_rawinput_hook( &dev->IDirectInputDevice8A_iface, wparam, lparam, &ri ); + } + LeaveCriticalSection( &dinput_hook_crit ); + } }
return DefWindowProcW( hwnd, msg, wparam, lparam ); diff --git a/dlls/dinput/dinput_private.h b/dlls/dinput/dinput_private.h index 06a439d6a41..c0c88da9674 100644 --- a/dlls/dinput/dinput_private.h +++ b/dlls/dinput/dinput_private.h @@ -73,6 +73,7 @@ extern void dinput_hooks_acquire_device(LPDIRECTINPUTDEVICE8W iface); extern void dinput_hooks_unacquire_device(LPDIRECTINPUTDEVICE8W iface); extern int dinput_mouse_hook(LPDIRECTINPUTDEVICE8A iface, WPARAM wparam, LPARAM lparam); extern int dinput_keyboard_hook(LPDIRECTINPUTDEVICE8A iface, WPARAM wparam, LPARAM lparam); +extern void dinput_mouse_rawinput_hook( LPDIRECTINPUTDEVICE8A iface, WPARAM wparam, LPARAM lparam, RAWINPUT *raw );
extern void check_dinput_hooks(LPDIRECTINPUTDEVICE8W, BOOL) DECLSPEC_HIDDEN; extern void check_dinput_events(void) DECLSPEC_HIDDEN; diff --git a/dlls/dinput/mouse.c b/dlls/dinput/mouse.c index 5e6f34f0eca..e50731fda41 100644 --- a/dlls/dinput/mouse.c +++ b/dlls/dinput/mouse.c @@ -239,6 +239,13 @@ static SysMouseImpl *alloc_device(REFGUID rguid, IDirectInputImpl *dinput) newDevice->base.data_format.wine_df = df; IDirectInput_AddRef(&newDevice->base.dinput->IDirectInput7A_iface);
+ if (dinput->dwVersion >= 0x0800) + { + newDevice->base.use_raw_input = TRUE; + newDevice->base.raw_device.usUsagePage = 1; /* HID generic device page */ + newDevice->base.raw_device.usUsage = 2; /* HID generic mouse */ + } + return newDevice;
failed: @@ -306,6 +313,89 @@ const struct dinput_device mouse_device = { * SysMouseA (DInput Mouse support) */
+void dinput_mouse_rawinput_hook( LPDIRECTINPUTDEVICE8A iface, WPARAM wparam, LPARAM lparam, RAWINPUT *ri ) +{ + SysMouseImpl* This = impl_from_IDirectInputDevice8A( iface ); + POINT rel, pt; + DWORD seq; + int i, wdata = 0; + + static const USHORT mouse_button_flags[] = + { + RI_MOUSE_BUTTON_1_DOWN, RI_MOUSE_BUTTON_1_UP, + RI_MOUSE_BUTTON_2_DOWN, RI_MOUSE_BUTTON_2_UP, + RI_MOUSE_BUTTON_3_DOWN, RI_MOUSE_BUTTON_3_UP, + RI_MOUSE_BUTTON_4_DOWN, RI_MOUSE_BUTTON_4_UP, + RI_MOUSE_BUTTON_5_DOWN, RI_MOUSE_BUTTON_5_UP + }; + + TRACE( "(%p) wp %08lx, lp %08lx\n", iface, wparam, lparam ); + + if (ri->data.mouse.usFlags & MOUSE_VIRTUAL_DESKTOP) + FIXME( "Unimplemented MOUSE_VIRTUAL_DESKTOP flag\n" ); + if (ri->data.mouse.usFlags & MOUSE_ATTRIBUTES_CHANGED) + FIXME( "Unimplemented MOUSE_ATTRIBUTES_CHANGED flag\n" ); + + EnterCriticalSection( &This->base.crit ); + seq = This->base.dinput->evsequence++; + + rel.x = ri->data.mouse.lLastX; + rel.y = ri->data.mouse.lLastY; + if (ri->data.mouse.usFlags & MOUSE_MOVE_ABSOLUTE) + { + GetCursorPos( &pt ); + rel.x -= pt.x; + rel.y -= pt.y; + } + + This->m_state.lX += rel.x; + This->m_state.lY += rel.y; + + if (This->base.data_format.user_df->dwFlags & DIDF_ABSAXIS) + { + pt.x = This->m_state.lX; + pt.y = This->m_state.lY; + } + else + { + pt = rel; + } + + if (rel.x) + queue_event( iface, DIDFT_MAKEINSTANCE(WINE_MOUSE_X_AXIS_INSTANCE) | DIDFT_RELAXIS, + pt.x, GetCurrentTime(), seq ); + + if (rel.y) + queue_event( iface, DIDFT_MAKEINSTANCE(WINE_MOUSE_Y_AXIS_INSTANCE) | DIDFT_RELAXIS, + pt.y, GetCurrentTime(), seq ); + + if (rel.x || rel.y) + { + if ((This->warp_override == WARP_FORCE_ON) || + (This->warp_override != WARP_DISABLE && (This->base.dwCoopLevel & DISCL_EXCLUSIVE))) + This->need_warp = TRUE; + } + + if (ri->data.mouse.usButtonFlags & RI_MOUSE_WHEEL) + { + This->m_state.lZ += (wdata = (SHORT)ri->data.mouse.usButtonData); + queue_event( iface, DIDFT_MAKEINSTANCE(WINE_MOUSE_Z_AXIS_INSTANCE) | DIDFT_RELAXIS, + wdata, GetCurrentTime(), seq ); + } + + for (i = 0; i < ARRAY_SIZE(mouse_button_flags); ++i) + { + if (ri->data.mouse.usButtonFlags & mouse_button_flags[i]) + { + This->m_state.rgbButtons[i / 2] = 0x80 - (i % 2) * 0x80; + queue_event( iface, DIDFT_MAKEINSTANCE(WINE_MOUSE_BUTTONS_INSTANCE +(i / 2) ) | DIDFT_PSHBUTTON, + This->m_state.rgbButtons[i / 2], GetCurrentTime(), seq ); + } + } + + LeaveCriticalSection( &This->base.crit ); +} + /* low-level mouse hook */ int dinput_mouse_hook( LPDIRECTINPUTDEVICE8A iface, WPARAM wparam, LPARAM lparam ) { diff --git a/dlls/dinput8/tests/device.c b/dlls/dinput8/tests/device.c index 6fe9a635510..80a7fe26c3b 100644 --- a/dlls/dinput8/tests/device.c +++ b/dlls/dinput8/tests/device.c @@ -646,13 +646,9 @@ static void test_mouse_keyboard(void) raw_devices_count = ARRAY_SIZE(raw_devices); memset(raw_devices, 0, sizeof(raw_devices)); hr = GetRegisteredRawInputDevices(raw_devices, &raw_devices_count, sizeof(RAWINPUTDEVICE)); - todo_wine ok(hr == 1, "GetRegisteredRawInputDevices returned %d, raw_devices_count: %d\n", hr, raw_devices_count); - todo_wine ok(raw_devices[0].usUsagePage == 1, "Unexpected raw device usage page: %x\n", raw_devices[0].usUsagePage); - todo_wine ok(raw_devices[0].usUsage == 2, "Unexpected raw device usage: %x\n", raw_devices[0].usUsage); - todo_wine ok(raw_devices[0].dwFlags == RIDEV_INPUTSINK, "Unexpected raw device flags: %x\n", raw_devices[0].dwFlags); todo_wine ok(raw_devices[0].hwndTarget == di_hwnd, "Unexpected raw device target: %p\n", raw_devices[0].hwndTarget); @@ -662,6 +658,9 @@ static void test_mouse_keyboard(void) GetRegisteredRawInputDevices(NULL, &raw_devices_count, sizeof(RAWINPUTDEVICE)); ok(raw_devices_count == 0, "Unexpected raw devices registered: %d\n", raw_devices_count);
+ if (raw_devices[0].hwndTarget != NULL) + di_hwnd = raw_devices[0].hwndTarget; + /* expect dinput8 to take over any activated raw input devices */ raw_devices[0].usUsagePage = 0x01; raw_devices[0].usUsage = 0x05; @@ -689,9 +688,7 @@ static void test_mouse_keyboard(void) ok(hr == 3, "GetRegisteredRawInputDevices returned %d, raw_devices_count: %d\n", hr, raw_devices_count); ok(raw_devices[0].usUsagePage == 1, "Unexpected raw device usage page: %x\n", raw_devices[0].usUsagePage); ok(raw_devices[0].usUsage == 2, "Unexpected raw device usage: %x\n", raw_devices[0].usUsage); - todo_wine ok(raw_devices[0].dwFlags == RIDEV_INPUTSINK, "Unexpected raw device flags: %x\n", raw_devices[0].dwFlags); - todo_wine ok(raw_devices[0].hwndTarget == di_hwnd, "Unexpected raw device target: %p\n", raw_devices[0].hwndTarget); ok(raw_devices[1].usUsagePage == 1, "Unexpected raw device usage page: %x\n", raw_devices[1].usUsagePage); ok(raw_devices[1].usUsage == 5, "Unexpected raw device usage: %x\n", raw_devices[1].usUsage); @@ -723,7 +720,6 @@ static void test_mouse_keyboard(void) memset(raw_devices, 0, sizeof(raw_devices)); hr = GetRegisteredRawInputDevices(raw_devices, &raw_devices_count, sizeof(RAWINPUTDEVICE)); ok(hr == 3, "GetRegisteredRawInputDevices returned %d, raw_devices_count: %d\n", hr, raw_devices_count); - todo_wine ok(raw_devices[0].dwFlags == (RIDEV_CAPTUREMOUSE|RIDEV_NOLEGACY), "Unexpected raw device flags: %x\n", raw_devices[0].dwFlags); todo_wine ok(raw_devices[2].dwFlags == (RIDEV_NOHOTKEYS|RIDEV_NOLEGACY), "Unexpected raw device flags: %x\n", raw_devices[1].dwFlags); @@ -737,7 +733,6 @@ static void test_mouse_keyboard(void) todo_wine ok(hr == 1, "GetRegisteredRawInputDevices returned %d, raw_devices_count: %d\n", hr, raw_devices_count); ok(raw_devices[0].usUsagePage == 1, "Unexpected raw device usage page: %x\n", raw_devices[0].usUsagePage); - todo_wine ok(raw_devices[0].usUsage == 5, "Unexpected raw device usage: %x\n", raw_devices[0].usUsage); ok(raw_devices[0].dwFlags == 0, "Unexpected raw device flags: %x\n", raw_devices[0].dwFlags); ok(raw_devices[0].hwndTarget == hwnd, "Unexpected raw device target: %p\n", raw_devices[0].hwndTarget);
LL hooks are heavy and using them cause performance hit with high polling rate mice. We don't need them anymore since we now use rawinput API for mouse device.
This also uses a separate list for rawinput mouse devices.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/dinput/dinput_main.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-)
diff --git a/dlls/dinput/dinput_main.c b/dlls/dinput/dinput_main.c index 1c4a26987f9..45023fc104a 100644 --- a/dlls/dinput/dinput_main.c +++ b/dlls/dinput/dinput_main.c @@ -104,6 +104,7 @@ static BOOL check_hook_thread(void); static CRITICAL_SECTION dinput_hook_crit; static struct list direct_input_list = LIST_INIT( direct_input_list ); static struct list acquired_mouse_list = LIST_INIT( acquired_mouse_list ); +static struct list acquired_rawmouse_list = LIST_INIT( acquired_rawmouse_list ); static struct list acquired_keyboard_list = LIST_INIT( acquired_keyboard_list ); static struct list acquired_device_list = LIST_INIT( acquired_device_list );
@@ -116,7 +117,7 @@ void dinput_hooks_acquire_device(LPDIRECTINPUTDEVICE8W iface)
EnterCriticalSection( &dinput_hook_crit ); if (IsEqualGUID( &dev->guid, &GUID_SysMouse )) - list_add_tail( &acquired_mouse_list, &dev->entry ); + list_add_tail( dev->use_raw_input ? &acquired_rawmouse_list : &acquired_mouse_list, &dev->entry ); else if (IsEqualGUID( &dev->guid, &GUID_SysKeyboard )) list_add_tail( &acquired_keyboard_list, &dev->entry ); else @@ -657,11 +658,8 @@ static LRESULT WINAPI di_em_win_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPAR else if (ri.header.dwType == RIM_TYPEMOUSE) { EnterCriticalSection( &dinput_hook_crit ); - LIST_FOR_EACH_ENTRY( dev, &acquired_mouse_list, IDirectInputDeviceImpl, entry ) - { - if (!dev->use_raw_input) continue; + LIST_FOR_EACH_ENTRY( dev, &acquired_rawmouse_list, IDirectInputDeviceImpl, entry ) dinput_mouse_rawinput_hook( &dev->IDirectInputDevice8A_iface, wparam, lparam, &ri ); - } LeaveCriticalSection( &dinput_hook_crit ); } } @@ -1720,7 +1718,6 @@ static LRESULT CALLBACK LL_hook_proc( int code, WPARAM wparam, LPARAM lparam ) EnterCriticalSection( &dinput_hook_crit ); LIST_FOR_EACH_ENTRY( dev, &acquired_mouse_list, IDirectInputDeviceImpl, entry ) { - if (dev->use_raw_input) continue; TRACE("calling dinput_mouse_hook (%p %lx %lx)\n", dev, wparam, lparam); skip |= dinput_mouse_hook( &dev->IDirectInputDevice8A_iface, wparam, lparam ); } @@ -1764,6 +1761,14 @@ static LRESULT CALLBACK callwndproc_proc( int code, WPARAM wparam, LPARAM lparam IDirectInputDevice_Unacquire( &dev->IDirectInputDevice8A_iface ); } } + LIST_FOR_EACH_ENTRY_SAFE( dev, next, &acquired_rawmouse_list, IDirectInputDeviceImpl, entry ) + { + if (msg->hwnd == dev->win && msg->hwnd != foreground) + { + TRACE( "%p window is not foreground - unacquiring %p\n", dev->win, dev ); + IDirectInputDevice_Unacquire( &dev->IDirectInputDevice8A_iface ); + } + } LIST_FOR_EACH_ENTRY_SAFE( dev, next, &acquired_keyboard_list, IDirectInputDeviceImpl, entry ) { if (msg->hwnd == dev->win && msg->hwnd != foreground)