From: Zebediah Figura zfigura@codeweavers.com
In order to test the wparam member I removed WS_VISIBLE from the window created by test_GetRawInputBuffer(). For some reason this caused events injected by that test not to be received if the test was executed after another test that created a window. My vague understanding is that we'd need XInput2 support to reliably receive those events, so as a stopgap solution I moved the tests earlier. --- dlls/user32/tests/input.c | 104 ++++++++++++++++++++++++++++++++++---- 1 file changed, 95 insertions(+), 9 deletions(-)
diff --git a/dlls/user32/tests/input.c b/dlls/user32/tests/input.c index 6232a7456e8..59039164b6b 100644 --- a/dlls/user32/tests/input.c +++ b/dlls/user32/tests/input.c @@ -2101,13 +2101,29 @@ static void test_RegisterRawInputDevices(void)
static int rawinputbuffer_wndproc_count;
+typedef struct +{ + DWORD dwType; + DWORD dwSize; + ULONG hDevice; + ULONG wParam; +} RAWINPUTHEADER32; + #ifdef _WIN64 +typedef RAWINPUTHEADER RAWINPUTHEADER64; typedef RAWINPUT RAWINPUT64; #else typedef struct { - RAWINPUTHEADER header; - char pad[8]; + DWORD dwType; + DWORD dwSize; + ULONGLONG hDevice; + ULONGLONG wParam; +} RAWINPUTHEADER64; + +typedef struct +{ + RAWINPUTHEADER64 header; union { RAWMOUSE mouse; RAWKEYBOARD keyboard; @@ -2124,9 +2140,9 @@ static int rawinput_buffer_mouse_x(void *buffer, size_t index)
static LRESULT CALLBACK rawinputbuffer_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { + UINT i, size, count, rawinput_size, iteration = rawinputbuffer_wndproc_count++; RAWINPUT ri; char buffer[16 * sizeof(RAWINPUT64)]; - UINT size, count, rawinput_size, iteration = rawinputbuffer_wndproc_count++; MSG message;
if (is_wow64) rawinput_size = sizeof(RAWINPUT64); @@ -2134,8 +2150,12 @@ static LRESULT CALLBACK rawinputbuffer_wndproc(HWND hwnd, UINT msg, WPARAM wpara
if (msg == WM_INPUT) { + ok(wparam == RIM_INPUTSINK, "Unexpected wparam: %#Ix\n", wparam); + + SetLastError(0xdeadbeef); count = GetRawInputBuffer(NULL, NULL, sizeof(RAWINPUTHEADER)); ok(count == ~0U, "GetRawInputBuffer succeeded\n"); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "got error %lu\n", GetLastError());
size = sizeof(buffer); count = GetRawInputBuffer(NULL, &size, sizeof(RAWINPUTHEADER)); @@ -2147,6 +2167,25 @@ static LRESULT CALLBACK rawinputbuffer_wndproc(HWND hwnd, UINT msg, WPARAM wpara count = GetRawInputBuffer((RAWINPUT*)buffer, &size, sizeof(RAWINPUTHEADER)); ok(count == 3, "GetRawInputBuffer returned %u\n", count); ok(size == sizeof(buffer), "GetRawInputBuffer returned unexpected size: %u\n", size); + + for (i = 0; i < 3; ++i) + { + if (is_wow64) + { + const RAWINPUT64 *data = (RAWINPUT64 *)buffer; + ok(data->header.dwType == RIM_TYPEMOUSE, "Unexpected rawinput type: %lu\n", data->header.dwType); + ok(data->header.dwSize == sizeof(*data), "Unexpected rawinput size: %lu\n", data->header.dwSize); + todo_wine ok(data->header.wParam == wparam, "Unexpected wparam: %#I64x\n", data->header.wParam); + } + else + { + const RAWINPUT *data = (RAWINPUT *)buffer; + ok(data->header.dwType == RIM_TYPEMOUSE, "Unexpected rawinput type: %lu\n", data->header.dwType); + ok(data->header.dwSize == sizeof(*data), "Unexpected rawinput size: %lu\n", data->header.dwSize); + todo_wine ok(data->header.wParam == wparam, "Unexpected wparam: %#Ix\n", data->header.wParam); + } + } + ok(rawinput_buffer_mouse_x(buffer, 0) == 2, "Unexpected rawinput data: %d\n", rawinput_buffer_mouse_x(buffer, 0)); ok(rawinput_buffer_mouse_x(buffer, 1) == 3, "Unexpected rawinput data: %d\n", rawinput_buffer_mouse_x(buffer, 1)); ok(rawinput_buffer_mouse_x(buffer, 2) == 4, "Unexpected rawinput data: %d\n", rawinput_buffer_mouse_x(buffer, 2)); @@ -2183,7 +2222,12 @@ static LRESULT CALLBACK rawinputbuffer_wndproc(HWND hwnd, UINT msg, WPARAM wpara { SetLastError(0xdeadbeef); count = GetRawInputData((HRAWINPUT)lparam, RID_INPUT, &ri, &size, 0); - ok(count == ~0U, "GetRawInputData succeeded\n"); + ok(count == ~0u, "GetRawInputData returned %d\n", count); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetRawInputData returned %08lx\n", GetLastError()); + + SetLastError(0xdeadbeef); + count = GetRawInputData((HRAWINPUT)lparam, RID_INPUT, &ri, &size, sizeof(RAWINPUTHEADER) + 1); + ok(count == ~0u, "GetRawInputData returned %d\n", count); ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetRawInputData returned %08lx\n", GetLastError());
SetLastError(0xdeadbeef); @@ -2204,6 +2248,28 @@ static LRESULT CALLBACK rawinputbuffer_wndproc(HWND hwnd, UINT msg, WPARAM wpara ok(count == sizeof(ri), "GetRawInputData failed\n"); ok(ri.data.mouse.lLastX == 6, "Unexpected rawinput data: %ld\n", ri.data.mouse.lLastX); ok(GetLastError() == 0xdeadbeef, "GetRawInputData returned %08lx\n", GetLastError()); + + SetLastError(0xdeadbeef); + size = sizeof(buffer); + if (sizeof(void *) == 8) + { + count = GetRawInputData((HRAWINPUT)lparam, RID_INPUT, &ri, &size, sizeof(RAWINPUTHEADER32)); + ok(count == ~0u, "GetRawInputData returned %d\n", count); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetRawInputData returned %08lx\n", GetLastError()); + } + else if (is_wow64) + { + count = GetRawInputData((HRAWINPUT)lparam, RID_INPUT, &ri, &size, sizeof(RAWINPUTHEADER64)); + todo_wine ok(count == sizeof(ri), "GetRawInputData returned %d\n", count); + ok(ri.data.mouse.lLastX == 6, "Unexpected rawinput data: %ld\n", ri.data.mouse.lLastX); + todo_wine ok(GetLastError() == 0xdeadbeef, "GetRawInputData returned %08lx\n", GetLastError()); + } + else + { + count = GetRawInputData((HRAWINPUT)lparam, RID_INPUT, &ri, &size, sizeof(RAWINPUTHEADER64)); + ok(count == ~0u, "GetRawInputData returned %d\n", count); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetRawInputData returned %08lx\n", GetLastError()); + } } else { @@ -2233,7 +2299,7 @@ static void test_GetRawInputBuffer(void) GetCursorPos(&pt); ok(pt.x == 300 && pt.y == 300, "Unexpected cursor position pos %ldx%ld\n", pt.x, pt.y);
- hwnd = CreateWindowA("static", "static", WS_VISIBLE | WS_POPUP, + hwnd = CreateWindowA("static", "static", WS_POPUP, 100, 100, 100, 100, 0, NULL, NULL, NULL); SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONG_PTR)rawinputbuffer_wndproc); ok(hwnd != 0, "CreateWindow failed\n"); @@ -2295,6 +2361,23 @@ static void test_GetRawInputBuffer(void) ok(count == ~0U, "GetRawInputBuffer succeeded\n"); ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetRawInputBuffer returned %08lx\n", GetLastError());
+ SetLastError(0xdeadbeef); + size = sizeof(buffer); + count = GetRawInputBuffer((RAWINPUT*)buffer, &size, sizeof(RAWINPUTHEADER) + 1); + ok(count == ~0U, "GetRawInputBuffer succeeded\n"); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetRawInputBuffer returned %08lx\n", GetLastError()); + + /* the function returns 64-bit RAWINPUT structures on WoW64, but still + * forbids sizeof(RAWINPUTHEADER) from the wrong architecture */ + SetLastError(0xdeadbeef); + size = sizeof(buffer); + if (sizeof(void *) == 8) + count = GetRawInputBuffer((RAWINPUT*)buffer, &size, sizeof(RAWINPUTHEADER32)); + else + count = GetRawInputBuffer((RAWINPUT*)buffer, &size, sizeof(RAWINPUTHEADER64)); + ok(count == ~0U, "GetRawInputBuffer succeeded\n"); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetRawInputBuffer returned %08lx\n", GetLastError()); + size = sizeof(buffer); memset(buffer, 0, sizeof(buffer)); count = GetRawInputBuffer((RAWINPUT*)buffer, &size, sizeof(RAWINPUTHEADER)); @@ -2365,6 +2448,9 @@ static LRESULT CALLBACK rawinput_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPA 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: %lu\n", raw.header.dwType); + ok(raw.header.dwSize == raw_size, "Expected size %u, got %lu\n", raw_size, raw.header.dwSize); + todo_wine_if (wparam) + ok(raw.header.wParam == wparam, "Expected wparam %Iu, got %Iu\n", wparam, raw.header.wParam);
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"); @@ -4491,6 +4577,10 @@ START_TEST(input) return; }
+ test_GetRawInputData(); + test_GetRawInputBuffer(); + test_RegisterRawInputDevices(); + test_rawinput(argv[0]); test_SendInput(); test_Input_blackbox(); test_Input_whitebox(); @@ -4507,10 +4597,6 @@ START_TEST(input) test_attach_input(); test_GetKeyState(); test_OemKeyScan(); - test_GetRawInputData(); - test_GetRawInputBuffer(); - test_RegisterRawInputDevices(); - test_rawinput(argv[0]);
if(pGetMouseMovePointsEx) test_GetMouseMovePointsEx(argv[0]);
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=116819
Your paranoid android.
=== w1064 (32 bit report) ===
user32: input.c:3484: Test failed: expected WM_LBUTTONDOWN message input.c:3485: Test failed: expected WM_LBUTTONUP message input.c:3513: Test failed: expected WM_RBUTTONDOWN message input.c:3514: Test failed: expected WM_RBUTTONUP message
=== w10pro64_ja (64 bit report) ===
user32: input.c:4525: Test failed: SendInput triggered unexpected message 0x7fff input.c:4543: Test failed: SendInput triggered unexpected message 0x7fff
=== w10pro64_zh_CN (64 bit report) ===
user32: input.c:3118: Test failed: ToAscii for character 'A' didn't return 1 (was 2)
From: Zebediah Figura zfigura@codeweavers.com
This changes the offset of the wParam field. --- dlls/user32/rawinput.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/dlls/user32/rawinput.c b/dlls/user32/rawinput.c index ab542956f11..99e2270b77c 100644 --- a/dlls/user32/rawinput.c +++ b/dlls/user32/rawinput.c @@ -646,12 +646,20 @@ UINT WINAPI GetRawInputData(HRAWINPUT rawinput, UINT command, void *data, UINT * }
#ifdef _WIN64 +typedef RAWINPUTHEADER RAWINPUTHEADER64; typedef RAWINPUT RAWINPUT64; #else typedef struct { - RAWINPUTHEADER header; - char pad[8]; + DWORD dwType; + DWORD dwSize; + ULONGLONG hDevice; + ULONGLONG wParam; +} RAWINPUTHEADER64; + +typedef struct +{ + RAWINPUTHEADER64 header; union { RAWMOUSE mouse; RAWKEYBOARD keyboard;
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=116820
Your paranoid android.
=== debian11 (32 bit report) ===
user32: input.c:2349: Test failed: GetRawInputBuffer succeeded input.c:2350: Test failed: GetRawInputBuffer returned unexpected size: 0 input.c:2351: Test failed: GetRawInputBuffer returned deadbeef input.c:2356: Test failed: GetRawInputBuffer returned unexpected size: 0 input.c:2384: Test failed: GetRawInputBuffer returned 0 input.c:2385: Test failed: GetRawInputBuffer returned unexpected size: 0 input.c:2386: Test failed: Unexpected rawinput data: 0 input.c:2397: Test failed: GetRawInputBuffer succeeded input.c:2398: Test failed: GetRawInputBuffer returned deadbeef input.c:2399: Test failed: Unexpected rawinput data: 0 input.c:2412: Test failed: Spurious WM_INPUT messages
=== debian11 (32 bit Chinese:China report) ===
user32: input.c:2349: Test failed: GetRawInputBuffer succeeded input.c:2350: Test failed: GetRawInputBuffer returned unexpected size: 0 input.c:2351: Test failed: GetRawInputBuffer returned deadbeef input.c:2356: Test failed: GetRawInputBuffer returned unexpected size: 0 input.c:2384: Test failed: GetRawInputBuffer returned 0 input.c:2385: Test failed: GetRawInputBuffer returned unexpected size: 0 input.c:2386: Test failed: Unexpected rawinput data: 0 input.c:2397: Test failed: GetRawInputBuffer succeeded input.c:2398: Test failed: GetRawInputBuffer returned deadbeef input.c:2399: Test failed: Unexpected rawinput data: 0 input.c:2412: Test failed: Spurious WM_INPUT messages msg.c:6881: Test failed: SetFocus(hwnd) on a button: 4: the msg 0x0007 was expected, but got msg 0x0005 instead msg.c:6881: Test failed: SetFocus(hwnd) on a button: 5: the msg 0x0135 was expected, but got msg 0x030f instead msg.c:6881: Test failed: SetFocus(hwnd) on a button: 6: the msg 0x002b was expected, but got msg 0x001c instead msg.c:6881: Test failed: SetFocus(hwnd) on a button: 7: the msg 0x0111 was expected, but got msg 0x0086 instead msg.c:6881: Test failed: SetFocus(hwnd) on a button: 8: the msg 0x8000 was expected, but got msg 0x0006 instead msg.c:6881: Test failed: SetFocus(hwnd) on a button: 9: the msg sequence is not complete: expected 0000 - actual 0009
=== debian11 (32 bit WoW report) ===
user32: input.c:2349: Test failed: GetRawInputBuffer succeeded input.c:2350: Test failed: GetRawInputBuffer returned unexpected size: 0 input.c:2351: Test failed: GetRawInputBuffer returned deadbeef input.c:2356: Test failed: GetRawInputBuffer returned unexpected size: 0 input.c:2384: Test failed: GetRawInputBuffer returned 0 input.c:2385: Test failed: GetRawInputBuffer returned unexpected size: 0 input.c:2386: Test failed: Unexpected rawinput data: 0 input.c:2397: Test failed: GetRawInputBuffer succeeded input.c:2398: Test failed: GetRawInputBuffer returned deadbeef input.c:2399: Test failed: Unexpected rawinput data: 0 input.c:2412: Test failed: Spurious WM_INPUT messages
=== debian11 (64 bit WoW report) ===
user32: input.c:2349: Test failed: GetRawInputBuffer succeeded input.c:2350: Test failed: GetRawInputBuffer returned unexpected size: 0 input.c:2351: Test failed: GetRawInputBuffer returned deadbeef input.c:2356: Test failed: GetRawInputBuffer returned unexpected size: 0 input.c:2384: Test failed: GetRawInputBuffer returned 0 input.c:2385: Test failed: GetRawInputBuffer returned unexpected size: 0 input.c:2386: Test failed: Unexpected rawinput data: 0 input.c:2397: Test failed: GetRawInputBuffer succeeded input.c:2398: Test failed: GetRawInputBuffer returned deadbeef input.c:2399: Test failed: Unexpected rawinput data: 0 input.c:2412: Test failed: Spurious WM_INPUT messages
From: Zebediah Figura zfigura@codeweavers.com
--- dlls/user32/rawinput.c | 54 +-------------------- dlls/user32/user32.spec | 2 +- dlls/user32/user_main.c | 1 + dlls/user32/user_private.h | 8 +--- dlls/win32u/Makefile.in | 1 + dlls/win32u/gdiobj.c | 1 + dlls/win32u/ntuser_private.h | 7 +++ dlls/win32u/rawinput.c | 91 ++++++++++++++++++++++++++++++++++++ dlls/win32u/win32u.spec | 2 +- dlls/win32u/win32u_private.h | 2 + dlls/win32u/wrappers.c | 6 +++ include/ntuser.h | 1 + 12 files changed, 114 insertions(+), 62 deletions(-) create mode 100644 dlls/win32u/rawinput.c
diff --git a/dlls/user32/rawinput.c b/dlls/user32/rawinput.c index 99e2270b77c..b1c79b4e186 100644 --- a/dlls/user32/rawinput.c +++ b/dlls/user32/rawinput.c @@ -351,7 +351,7 @@ BOOL rawinput_device_get_usages(HANDLE handle, USAGE *usage_page, USAGE *usage) }
-struct rawinput_thread_data *rawinput_thread_data(void) +struct rawinput_thread_data * WINAPI rawinput_thread_data(void) { struct user_thread_info *thread_info = get_user_thread_info(); struct rawinput_thread_data *data = thread_info->rawinput; @@ -593,58 +593,6 @@ BOOL WINAPI DECLSPEC_HOTPATCH RegisterRawInputDevices(const RAWINPUTDEVICE *devi return ret; }
-/*********************************************************************** - * GetRawInputData (USER32.@) - */ -UINT WINAPI GetRawInputData(HRAWINPUT rawinput, UINT command, void *data, UINT *data_size, UINT header_size) -{ - struct rawinput_thread_data *thread_data = rawinput_thread_data(); - UINT size; - - TRACE("rawinput %p, command %#x, data %p, data_size %p, header_size %u.\n", - rawinput, command, data, data_size, header_size); - - if (!rawinput || thread_data->hw_id != (UINT_PTR)rawinput) - { - SetLastError(ERROR_INVALID_HANDLE); - return ~0U; - } - - if (header_size != sizeof(RAWINPUTHEADER)) - { - WARN("Invalid structure size %u.\n", header_size); - SetLastError(ERROR_INVALID_PARAMETER); - return ~0U; - } - - switch (command) - { - case RID_INPUT: - size = thread_data->buffer->header.dwSize; - break; - case RID_HEADER: - size = sizeof(RAWINPUTHEADER); - break; - default: - SetLastError(ERROR_INVALID_PARAMETER); - return ~0U; - } - - if (!data) - { - *data_size = size; - return 0; - } - - if (*data_size < size) - { - SetLastError(ERROR_INSUFFICIENT_BUFFER); - return ~0U; - } - memcpy(data, thread_data->buffer, size); - return size; -} - #ifdef _WIN64 typedef RAWINPUTHEADER RAWINPUTHEADER64; typedef RAWINPUT RAWINPUT64; diff --git a/dlls/user32/user32.spec b/dlls/user32/user32.spec index b41d661ee2a..2379c2cced5 100644 --- a/dlls/user32/user32.spec +++ b/dlls/user32/user32.spec @@ -367,7 +367,7 @@ @ stdcall GetPropW(long wstr) @ stdcall GetQueueStatus(long) NtUserGetQueueStatus @ stdcall GetRawInputBuffer(ptr ptr long) -@ stdcall GetRawInputData(ptr long ptr ptr long) +@ stdcall GetRawInputData(ptr long ptr ptr long) NtUserGetRawInputData @ stdcall GetRawInputDeviceInfoA(ptr long ptr ptr) @ stdcall GetRawInputDeviceInfoW(ptr long ptr ptr) @ stdcall GetRawInputDeviceList(ptr ptr long) diff --git a/dlls/user32/user_main.c b/dlls/user32/user_main.c index 755fc3d578e..64b9b9f59a9 100644 --- a/dlls/user32/user_main.c +++ b/dlls/user32/user_main.c @@ -156,6 +156,7 @@ static const struct user_callbacks user_funcs = unpack_dde_message, register_imm, unregister_imm, + rawinput_thread_data, };
static NTSTATUS WINAPI User32CopyImage( const struct copy_image_params *params, ULONG size ) diff --git a/dlls/user32/user_private.h b/dlls/user32/user_private.h index aa3e1565bfa..11f8b6389ac 100644 --- a/dlls/user32/user_private.h +++ b/dlls/user32/user_private.h @@ -51,12 +51,6 @@ struct wm_char_mapping_data /* hold up to 10s of 1kHz mouse rawinput events */ #define RAWINPUT_BUFFER_SIZE (512*1024)
-struct rawinput_thread_data -{ - UINT hw_id; /* current rawinput message id */ - RAWINPUT buffer[1]; /* rawinput message data buffer */ -}; - extern BOOL (WINAPI *imm_register_window)(HWND) DECLSPEC_HIDDEN; extern void (WINAPI *imm_unregister_window)(HWND) DECLSPEC_HIDDEN;
@@ -73,7 +67,7 @@ struct tagWND; struct hardware_msg_data; extern BOOL rawinput_from_hardware_message(RAWINPUT *rawinput, const struct hardware_msg_data *msg_data); extern BOOL rawinput_device_get_usages(HANDLE handle, USAGE *usage_page, USAGE *usage); -extern struct rawinput_thread_data *rawinput_thread_data(void); +extern struct rawinput_thread_data * WINAPI rawinput_thread_data(void); extern void rawinput_update_device_list(void);
extern BOOL post_dde_message( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam, DWORD dest_tid, diff --git a/dlls/win32u/Makefile.in b/dlls/win32u/Makefile.in index d58ed6bb41c..cc429836de3 100644 --- a/dlls/win32u/Makefile.in +++ b/dlls/win32u/Makefile.in @@ -43,6 +43,7 @@ C_SRCS = \ path.c \ pen.c \ printdrv.c \ + rawinput.c \ region.c \ spy.c \ syscall.c \ diff --git a/dlls/win32u/gdiobj.c b/dlls/win32u/gdiobj.c index 72924bb658a..a988b1a0c4a 100644 --- a/dlls/win32u/gdiobj.c +++ b/dlls/win32u/gdiobj.c @@ -1181,6 +1181,7 @@ static struct unix_funcs unix_funcs = NtUserGetMessage, NtUserGetPriorityClipboardFormat, NtUserGetQueueStatus, + NtUserGetRawInputData, NtUserGetSystemMenu, NtUserGetUpdateRect, NtUserGetUpdateRgn, diff --git a/dlls/win32u/ntuser_private.h b/dlls/win32u/ntuser_private.h index e39e3f54169..717538c1adc 100644 --- a/dlls/win32u/ntuser_private.h +++ b/dlls/win32u/ntuser_private.h @@ -49,6 +49,7 @@ struct user_callbacks void **buffer, size_t size ); BOOL (WINAPI *register_imm)( HWND hwnd ); void (WINAPI *unregister_imm)( HWND hwnd ); + struct rawinput_thread_data *(WINAPI *get_rawinput_thread_data)(void); };
#define WM_SYSTIMER 0x0118 @@ -60,6 +61,12 @@ enum system_timer_id SYSTEM_TIMER_CARET = 0xffff, };
+struct rawinput_thread_data +{ + UINT hw_id; /* current rawinput message id */ + RAWINPUT buffer[1]; /* rawinput message data buffer */ +}; + struct user_object { HANDLE handle; diff --git a/dlls/win32u/rawinput.c b/dlls/win32u/rawinput.c new file mode 100644 index 00000000000..0d2c585c36e --- /dev/null +++ b/dlls/win32u/rawinput.c @@ -0,0 +1,91 @@ +/* + * Raw Input + * + * Copyright 2012 Henri Verbeet + * Copyright 2018 Zebediah Figura for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#if 0 +#pragma makedep unix +#endif + +#include "win32u_private.h" +#include "ntuser_private.h" +#include "wine/server.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(rawinput); + +/********************************************************************** + * NtUserGetRawInputData (win32u.@) + */ +UINT WINAPI NtUserGetRawInputData( HRAWINPUT rawinput, UINT command, void *data, UINT *data_size, UINT header_size ) +{ + struct rawinput_thread_data *thread_data; + UINT size; + + TRACE( "rawinput %p, command %#x, data %p, data_size %p, header_size %u.\n", + rawinput, command, data, data_size, header_size ); + + if (!user_callbacks || !(thread_data = user_callbacks->get_rawinput_thread_data())) + { + SetLastError( ERROR_OUTOFMEMORY ); + return ~0u; + } + + if (!rawinput || thread_data->hw_id != (UINT_PTR)rawinput) + { + SetLastError( ERROR_INVALID_HANDLE ); + return ~0u; + } + + if (header_size != sizeof(RAWINPUTHEADER)) + { + WARN( "Invalid structure size %u.\n", header_size ); + SetLastError( ERROR_INVALID_PARAMETER ); + return ~0u; + } + + switch (command) + { + case RID_INPUT: + size = thread_data->buffer->header.dwSize; + break; + + case RID_HEADER: + size = sizeof(RAWINPUTHEADER); + break; + + default: + SetLastError( ERROR_INVALID_PARAMETER ); + return ~0u; + } + + if (!data) + { + *data_size = size; + return 0; + } + + if (*data_size < size) + { + SetLastError( ERROR_INSUFFICIENT_BUFFER ); + return ~0u; + } + memcpy( data, thread_data->buffer, size ); + return size; +} diff --git a/dlls/win32u/win32u.spec b/dlls/win32u/win32u.spec index de500da143b..8b71504f374 100644 --- a/dlls/win32u/win32u.spec +++ b/dlls/win32u/win32u.spec @@ -984,7 +984,7 @@ @ stdcall NtUserGetQueueStatus(long) @ stub NtUserGetQueueStatusReadonly @ stub NtUserGetRawInputBuffer -@ stub NtUserGetRawInputData +@ stdcall NtUserGetRawInputData(ptr long ptr ptr long) @ stub NtUserGetRawInputDeviceInfo @ stub NtUserGetRawInputDeviceList @ stub NtUserGetRawPointerDeviceData diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index 957d930d9da..87901d1313e 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -243,6 +243,8 @@ struct unix_funcs BOOL (WINAPI *pNtUserGetMessage)( MSG *msg, HWND hwnd, UINT first, UINT last ); INT (WINAPI *pNtUserGetPriorityClipboardFormat)( UINT *list, INT count ); DWORD (WINAPI *pNtUserGetQueueStatus)( UINT flags ); + UINT (WINAPI *pNtUserGetRawInputData)( HRAWINPUT rawinput, UINT command, + void *data, UINT *data_size, UINT header_size ); HMENU (WINAPI *pNtUserGetSystemMenu)( HWND hwnd, BOOL revert ); BOOL (WINAPI *pNtUserGetUpdateRect)( HWND hwnd, RECT *rect, BOOL erase ); INT (WINAPI *pNtUserGetUpdateRgn)( HWND hwnd, HRGN hrgn, BOOL erase ); diff --git a/dlls/win32u/wrappers.c b/dlls/win32u/wrappers.c index 99e0b9f3d88..17354abc73e 100644 --- a/dlls/win32u/wrappers.c +++ b/dlls/win32u/wrappers.c @@ -1023,6 +1023,12 @@ DWORD WINAPI NtUserGetQueueStatus( UINT flags ) return unix_funcs->pNtUserGetQueueStatus( flags ); }
+UINT WINAPI NtUserGetRawInputData( HRAWINPUT rawinput, UINT command, void *data, UINT *data_size, UINT header_size ) +{ + if (!unix_funcs) return ~0u; + return unix_funcs->pNtUserGetRawInputData( rawinput, command, data, data_size, header_size ); +} + BOOL WINAPI NtUserGetUpdatedClipboardFormats( UINT *formats, UINT size, UINT *out_size ) { if (!unix_funcs) return FALSE; diff --git a/include/ntuser.h b/include/ntuser.h index 8320a83800f..85b7a87247f 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -589,6 +589,7 @@ HWINSTA WINAPI NtUserGetProcessWindowStation(void); HANDLE WINAPI NtUserGetProp( HWND hwnd, const WCHAR *str ); ULONG WINAPI NtUserGetProcessDpiAwarenessContext( HANDLE process ); DWORD WINAPI NtUserGetQueueStatus( UINT flags ); +UINT WINAPI NtUserGetRawInputData( HRAWINPUT rawinput, UINT command, void *data, UINT *data_size, UINT header_size ); ULONG WINAPI NtUserGetSystemDpiForProcess( HANDLE process ); HMENU WINAPI NtUserGetSystemMenu( HWND hwnd, BOOL revert ); HDESK WINAPI NtUserGetThreadDesktop( DWORD thread );
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=116821
Your paranoid android.
=== debian11 (32 bit report) ===
user32: input.c:2349: Test failed: GetRawInputBuffer succeeded input.c:2350: Test failed: GetRawInputBuffer returned unexpected size: 0 input.c:2351: Test failed: GetRawInputBuffer returned deadbeef input.c:2356: Test failed: GetRawInputBuffer returned unexpected size: 0 input.c:2384: Test failed: GetRawInputBuffer returned 0 input.c:2385: Test failed: GetRawInputBuffer returned unexpected size: 0 input.c:2386: Test failed: Unexpected rawinput data: 0 input.c:2397: Test failed: GetRawInputBuffer succeeded input.c:2398: Test failed: GetRawInputBuffer returned deadbeef input.c:2399: Test failed: Unexpected rawinput data: 0 input.c:2412: Test failed: Spurious WM_INPUT messages
=== debian11 (32 bit Chinese:China report) ===
user32: input.c:2349: Test failed: GetRawInputBuffer succeeded input.c:2350: Test failed: GetRawInputBuffer returned unexpected size: 0 input.c:2351: Test failed: GetRawInputBuffer returned deadbeef input.c:2356: Test failed: GetRawInputBuffer returned unexpected size: 0 input.c:2384: Test failed: GetRawInputBuffer returned 0 input.c:2385: Test failed: GetRawInputBuffer returned unexpected size: 0 input.c:2386: Test failed: Unexpected rawinput data: 0 input.c:2397: Test failed: GetRawInputBuffer succeeded input.c:2398: Test failed: GetRawInputBuffer returned deadbeef input.c:2399: Test failed: Unexpected rawinput data: 0 input.c:2412: Test failed: Spurious WM_INPUT messages input.c:2870: Test failed: 15: expected WM_INPUT message input.c:2873: Test failed: 15: expected RIM_INPUT message
=== debian11 (32 bit WoW report) ===
user32: input.c:2349: Test failed: GetRawInputBuffer succeeded input.c:2350: Test failed: GetRawInputBuffer returned unexpected size: 0 input.c:2351: Test failed: GetRawInputBuffer returned deadbeef input.c:2356: Test failed: GetRawInputBuffer returned unexpected size: 0 input.c:2384: Test failed: GetRawInputBuffer returned 0 input.c:2385: Test failed: GetRawInputBuffer returned unexpected size: 0 input.c:2386: Test failed: Unexpected rawinput data: 0 input.c:2397: Test failed: GetRawInputBuffer succeeded input.c:2398: Test failed: GetRawInputBuffer returned deadbeef input.c:2399: Test failed: Unexpected rawinput data: 0 input.c:2412: Test failed: Spurious WM_INPUT messages win.c:11770: Test succeeded inside todo block: child should be topmost win.c:11773: Test failed: grandchild should be topmost win.c:11781: Test failed: child should NOT be topmost win.c:11784: Test succeeded inside todo block: grandchild should NOT be topmost win.c:11787: Test failed: 011D00CE: expected NOT topmost win.c:11606: Test succeeded inside todo block: 5: hwnd 014E0054 is still topmost
=== debian11 (64 bit WoW report) ===
user32: input.c:2349: Test failed: GetRawInputBuffer succeeded input.c:2350: Test failed: GetRawInputBuffer returned unexpected size: 0 input.c:2351: Test failed: GetRawInputBuffer returned deadbeef input.c:2356: Test failed: GetRawInputBuffer returned unexpected size: 0 input.c:2384: Test failed: GetRawInputBuffer returned 0 input.c:2385: Test failed: GetRawInputBuffer returned unexpected size: 0 input.c:2386: Test failed: Unexpected rawinput data: 0 input.c:2397: Test failed: GetRawInputBuffer succeeded input.c:2398: Test failed: GetRawInputBuffer returned deadbeef input.c:2399: Test failed: Unexpected rawinput data: 0 input.c:2412: Test failed: Spurious WM_INPUT messages
From: Zebediah Figura zfigura@codeweavers.com
--- dlls/user32/rawinput.c | 111 ---------------- dlls/user32/user32.spec | 2 +- dlls/user32/user_private.h | 4 - dlls/win32u/gdiobj.c | 1 + dlls/win32u/ntuser_private.h | 4 + dlls/win32u/rawinput.c | 244 +++++++++++++++++++++++++++++++++++ dlls/win32u/win32u.spec | 2 +- dlls/win32u/win32u_private.h | 1 + dlls/win32u/wrappers.c | 6 + include/ntuser.h | 1 + 10 files changed, 259 insertions(+), 117 deletions(-)
diff --git a/dlls/user32/rawinput.c b/dlls/user32/rawinput.c index b1c79b4e186..f8980f03e9e 100644 --- a/dlls/user32/rawinput.c +++ b/dlls/user32/rawinput.c @@ -593,117 +593,6 @@ BOOL WINAPI DECLSPEC_HOTPATCH RegisterRawInputDevices(const RAWINPUTDEVICE *devi return ret; }
-#ifdef _WIN64 -typedef RAWINPUTHEADER RAWINPUTHEADER64; -typedef RAWINPUT RAWINPUT64; -#else -typedef struct -{ - DWORD dwType; - DWORD dwSize; - ULONGLONG hDevice; - ULONGLONG wParam; -} RAWINPUTHEADER64; - -typedef struct -{ - RAWINPUTHEADER64 header; - union { - RAWMOUSE mouse; - RAWKEYBOARD keyboard; - RAWHID hid; - } data; -} RAWINPUT64; -#endif - -/*********************************************************************** - * GetRawInputBuffer (USER32.@) - */ -UINT WINAPI DECLSPEC_HOTPATCH GetRawInputBuffer(RAWINPUT *data, UINT *data_size, UINT header_size) -{ - struct hardware_msg_data *msg_data; - struct rawinput_thread_data *thread_data; - RAWINPUT *rawinput; - UINT count = 0, remaining, rawinput_size, next_size, overhead; - BOOL is_wow64; - int i; - - if (IsWow64Process( GetCurrentProcess(), &is_wow64 ) && is_wow64) - rawinput_size = sizeof(RAWINPUT64); - else - rawinput_size = sizeof(RAWINPUT); - overhead = rawinput_size - sizeof(RAWINPUT); - - if (header_size != sizeof(RAWINPUTHEADER)) - { - WARN("Invalid structure size %u.\n", header_size); - SetLastError(ERROR_INVALID_PARAMETER); - return ~0U; - } - - if (!data_size) - { - SetLastError(ERROR_INVALID_PARAMETER); - return ~0U; - } - - if (!data) - { - TRACE("data %p, data_size %p (%u), header_size %u\n", data, data_size, *data_size, header_size); - SERVER_START_REQ( get_rawinput_buffer ) - { - req->rawinput_size = rawinput_size; - req->buffer_size = 0; - if (wine_server_call( req )) return ~0U; - *data_size = reply->next_size; - } - SERVER_END_REQ; - return 0; - } - - if (!(thread_data = rawinput_thread_data())) return ~0U; - rawinput = thread_data->buffer; - - /* first RAWINPUT block in the buffer is used for WM_INPUT message data */ - msg_data = (struct hardware_msg_data *)NEXTRAWINPUTBLOCK(rawinput); - SERVER_START_REQ( get_rawinput_buffer ) - { - req->rawinput_size = rawinput_size; - req->buffer_size = *data_size; - wine_server_set_reply( req, msg_data, RAWINPUT_BUFFER_SIZE - rawinput->header.dwSize ); - if (wine_server_call( req )) return ~0U; - next_size = reply->next_size; - count = reply->count; - } - SERVER_END_REQ; - - remaining = *data_size; - for (i = 0; i < count; ++i) - { - data->header.dwSize = remaining; - if (!rawinput_from_hardware_message(data, msg_data)) break; - if (overhead) memmove((char *)&data->data + overhead, &data->data, - data->header.dwSize - sizeof(RAWINPUTHEADER)); - data->header.dwSize += overhead; - remaining -= data->header.dwSize; - data = NEXTRAWINPUTBLOCK(data); - msg_data = (struct hardware_msg_data *)((char *)msg_data + msg_data->size); - } - - if (count == 0 && next_size == 0) *data_size = 0; - else if (next_size == 0) next_size = rawinput_size; - - if (next_size && *data_size <= next_size) - { - SetLastError(ERROR_INSUFFICIENT_BUFFER); - *data_size = next_size; - count = ~0U; - } - - if (count) TRACE("data %p, data_size %p (%u), header_size %u, count %u\n", data, data_size, *data_size, header_size, count); - return count; -} - /*********************************************************************** * GetRawInputDeviceInfoA (USER32.@) */ diff --git a/dlls/user32/user32.spec b/dlls/user32/user32.spec index 2379c2cced5..15a2a53aa0c 100644 --- a/dlls/user32/user32.spec +++ b/dlls/user32/user32.spec @@ -366,7 +366,7 @@ @ stdcall GetPropA(long str) @ stdcall GetPropW(long wstr) @ stdcall GetQueueStatus(long) NtUserGetQueueStatus -@ stdcall GetRawInputBuffer(ptr ptr long) +@ stdcall GetRawInputBuffer(ptr ptr long) NtUserGetRawInputBuffer @ stdcall GetRawInputData(ptr long ptr ptr long) NtUserGetRawInputData @ stdcall GetRawInputDeviceInfoA(ptr long ptr ptr) @ stdcall GetRawInputDeviceInfoW(ptr long ptr ptr) diff --git a/dlls/user32/user_private.h b/dlls/user32/user_private.h index 11f8b6389ac..a9ba17a769f 100644 --- a/dlls/user32/user_private.h +++ b/dlls/user32/user_private.h @@ -47,10 +47,6 @@ struct wm_char_mapping_data MSG get_msg; };
-/* on windows the buffer capacity is quite large as well, enough to */ -/* hold up to 10s of 1kHz mouse rawinput events */ -#define RAWINPUT_BUFFER_SIZE (512*1024) - extern BOOL (WINAPI *imm_register_window)(HWND) DECLSPEC_HIDDEN; extern void (WINAPI *imm_unregister_window)(HWND) DECLSPEC_HIDDEN;
diff --git a/dlls/win32u/gdiobj.c b/dlls/win32u/gdiobj.c index a988b1a0c4a..ebc7ccaeb5f 100644 --- a/dlls/win32u/gdiobj.c +++ b/dlls/win32u/gdiobj.c @@ -1181,6 +1181,7 @@ static struct unix_funcs unix_funcs = NtUserGetMessage, NtUserGetPriorityClipboardFormat, NtUserGetQueueStatus, + NtUserGetRawInputBuffer, NtUserGetRawInputData, NtUserGetSystemMenu, NtUserGetUpdateRect, diff --git a/dlls/win32u/ntuser_private.h b/dlls/win32u/ntuser_private.h index 717538c1adc..0470b094952 100644 --- a/dlls/win32u/ntuser_private.h +++ b/dlls/win32u/ntuser_private.h @@ -67,6 +67,10 @@ struct rawinput_thread_data RAWINPUT buffer[1]; /* rawinput message data buffer */ };
+/* on windows the buffer capacity is quite large as well, enough to */ +/* hold up to 10s of 1kHz mouse rawinput events */ +#define RAWINPUT_BUFFER_SIZE (512 * 1024) + struct user_object { HANDLE handle; diff --git a/dlls/win32u/rawinput.c b/dlls/win32u/rawinput.c index 0d2c585c36e..1440b1ebe54 100644 --- a/dlls/win32u/rawinput.c +++ b/dlls/win32u/rawinput.c @@ -23,6 +23,7 @@ #pragma makedep unix #endif
+#include <stdbool.h> #include "win32u_private.h" #include "ntuser_private.h" #include "wine/server.h" @@ -30,6 +31,249 @@
WINE_DEFAULT_DEBUG_CHANNEL(rawinput);
+#define WINE_MOUSE_HANDLE ((HANDLE)1) +#define WINE_KEYBOARD_HANDLE ((HANDLE)2) + +#ifdef _WIN64 +typedef RAWINPUTHEADER RAWINPUTHEADER64; +typedef RAWINPUT RAWINPUT64; +#else +typedef struct +{ + DWORD dwType; + DWORD dwSize; + ULONGLONG hDevice; + ULONGLONG wParam; +} RAWINPUTHEADER64; + +typedef struct +{ + RAWINPUTHEADER64 header; + union + { + RAWMOUSE mouse; + RAWKEYBOARD keyboard; + RAWHID hid; + } data; +} RAWINPUT64; +#endif + +static bool rawinput_from_hardware_message( RAWINPUT *rawinput, const struct hardware_msg_data *msg_data ) +{ + SIZE_T size; + + rawinput->header.dwType = msg_data->rawinput.type; + if (msg_data->rawinput.type == RIM_TYPEMOUSE) + { + static const unsigned int button_flags[] = + { + 0, /* MOUSEEVENTF_MOVE */ + RI_MOUSE_LEFT_BUTTON_DOWN, /* MOUSEEVENTF_LEFTDOWN */ + RI_MOUSE_LEFT_BUTTON_UP, /* MOUSEEVENTF_LEFTUP */ + RI_MOUSE_RIGHT_BUTTON_DOWN, /* MOUSEEVENTF_RIGHTDOWN */ + RI_MOUSE_RIGHT_BUTTON_UP, /* MOUSEEVENTF_RIGHTUP */ + RI_MOUSE_MIDDLE_BUTTON_DOWN, /* MOUSEEVENTF_MIDDLEDOWN */ + RI_MOUSE_MIDDLE_BUTTON_UP, /* MOUSEEVENTF_MIDDLEUP */ + }; + unsigned int i; + + rawinput->header.dwSize = FIELD_OFFSET(RAWINPUT, data) + sizeof(RAWMOUSE); + rawinput->header.hDevice = WINE_MOUSE_HANDLE; + rawinput->header.wParam = 0; + + rawinput->data.mouse.usFlags = MOUSE_MOVE_RELATIVE; + rawinput->data.mouse.usButtonFlags = 0; + rawinput->data.mouse.usButtonData = 0; + for (i = 1; i < ARRAY_SIZE(button_flags); ++i) + { + if (msg_data->flags & (1 << i)) + rawinput->data.mouse.usButtonFlags |= button_flags[i]; + } + if (msg_data->flags & MOUSEEVENTF_WHEEL) + { + rawinput->data.mouse.usButtonFlags |= RI_MOUSE_WHEEL; + rawinput->data.mouse.usButtonData = msg_data->rawinput.mouse.data; + } + if (msg_data->flags & MOUSEEVENTF_HWHEEL) + { + rawinput->data.mouse.usButtonFlags |= RI_MOUSE_HORIZONTAL_WHEEL; + rawinput->data.mouse.usButtonData = msg_data->rawinput.mouse.data; + } + if (msg_data->flags & MOUSEEVENTF_XDOWN) + { + if (msg_data->rawinput.mouse.data == XBUTTON1) + rawinput->data.mouse.usButtonFlags |= RI_MOUSE_BUTTON_4_DOWN; + else if (msg_data->rawinput.mouse.data == XBUTTON2) + rawinput->data.mouse.usButtonFlags |= RI_MOUSE_BUTTON_5_DOWN; + } + if (msg_data->flags & MOUSEEVENTF_XUP) + { + if (msg_data->rawinput.mouse.data == XBUTTON1) + rawinput->data.mouse.usButtonFlags |= RI_MOUSE_BUTTON_4_UP; + else if (msg_data->rawinput.mouse.data == XBUTTON2) + rawinput->data.mouse.usButtonFlags |= RI_MOUSE_BUTTON_5_UP; + } + + rawinput->data.mouse.ulRawButtons = 0; + rawinput->data.mouse.lLastX = msg_data->rawinput.mouse.x; + rawinput->data.mouse.lLastY = msg_data->rawinput.mouse.y; + rawinput->data.mouse.ulExtraInformation = msg_data->info; + } + else if (msg_data->rawinput.type == RIM_TYPEKEYBOARD) + { + rawinput->header.dwSize = FIELD_OFFSET(RAWINPUT, data) + sizeof(RAWKEYBOARD); + rawinput->header.hDevice = WINE_KEYBOARD_HANDLE; + rawinput->header.wParam = 0; + + rawinput->data.keyboard.MakeCode = msg_data->rawinput.kbd.scan; + rawinput->data.keyboard.Flags = (msg_data->flags & KEYEVENTF_KEYUP) ? RI_KEY_BREAK : RI_KEY_MAKE; + if (msg_data->flags & KEYEVENTF_EXTENDEDKEY) + rawinput->data.keyboard.Flags |= RI_KEY_E0; + rawinput->data.keyboard.Reserved = 0; + + switch (msg_data->rawinput.kbd.vkey) + { + case VK_LSHIFT: + case VK_RSHIFT: + rawinput->data.keyboard.VKey = VK_SHIFT; + rawinput->data.keyboard.Flags &= ~RI_KEY_E0; + break; + + case VK_LCONTROL: + case VK_RCONTROL: + rawinput->data.keyboard.VKey = VK_CONTROL; + break; + + case VK_LMENU: + case VK_RMENU: + rawinput->data.keyboard.VKey = VK_MENU; + break; + + default: + rawinput->data.keyboard.VKey = msg_data->rawinput.kbd.vkey; + break; + } + + rawinput->data.keyboard.Message = msg_data->rawinput.kbd.message; + rawinput->data.keyboard.ExtraInformation = msg_data->info; + } + else if (msg_data->rawinput.type == RIM_TYPEHID) + { + size = msg_data->size - sizeof(*msg_data); + if (size > rawinput->header.dwSize - sizeof(*rawinput)) return false; + + rawinput->header.dwSize = FIELD_OFFSET( RAWINPUT, data.hid.bRawData ) + size; + rawinput->header.hDevice = ULongToHandle( msg_data->rawinput.hid.device ); + rawinput->header.wParam = 0; + + rawinput->data.hid.dwCount = msg_data->rawinput.hid.count; + rawinput->data.hid.dwSizeHid = msg_data->rawinput.hid.length; + memcpy( rawinput->data.hid.bRawData, msg_data + 1, size ); + } + else + { + FIXME( "Unhandled rawinput type %#x.\n", msg_data->rawinput.type ); + return false; + } + + return true; +} + +/********************************************************************** + * NtUserGetRawInputBuffer (win32u.@) + */ +UINT WINAPI NtUserGetRawInputBuffer( RAWINPUT *data, UINT *data_size, UINT header_size ) +{ + unsigned int count = 0, remaining, rawinput_size, next_size, overhead; + struct rawinput_thread_data *thread_data; + struct hardware_msg_data *msg_data; + RAWINPUT *rawinput; + int i; + + if (NtCurrentTeb()->WowTebOffset) + rawinput_size = sizeof(RAWINPUT64); + else + rawinput_size = sizeof(RAWINPUT); + overhead = rawinput_size - sizeof(RAWINPUT); + + if (header_size != sizeof(RAWINPUTHEADER)) + { + WARN( "Invalid structure size %u.\n", header_size ); + SetLastError( ERROR_INVALID_PARAMETER ); + return ~0u; + } + + if (!data_size) + { + SetLastError( ERROR_INVALID_PARAMETER ); + return ~0u; + } + + if (!data) + { + TRACE( "data %p, data_size %p (%u), header_size %u\n", data, data_size, *data_size, header_size ); + SERVER_START_REQ( get_rawinput_buffer ) + { + req->rawinput_size = rawinput_size; + req->buffer_size = 0; + if (wine_server_call( req )) return ~0u; + *data_size = reply->next_size; + } + SERVER_END_REQ; + return 0; + } + + if (!user_callbacks || !(thread_data = user_callbacks->get_rawinput_thread_data())) return ~0u; + rawinput = thread_data->buffer; + + /* first RAWINPUT block in the buffer is used for WM_INPUT message data */ + msg_data = (struct hardware_msg_data *)NEXTRAWINPUTBLOCK(rawinput); + SERVER_START_REQ( get_rawinput_buffer ) + { + req->rawinput_size = rawinput_size; + req->buffer_size = *data_size; + wine_server_set_reply( req, msg_data, RAWINPUT_BUFFER_SIZE - rawinput->header.dwSize ); + if (wine_server_call( req )) return ~0u; + next_size = reply->next_size; + count = reply->count; + } + SERVER_END_REQ; + + remaining = *data_size; + for (i = 0; i < count; ++i) + { + data->header.dwSize = remaining; + if (!rawinput_from_hardware_message( data, msg_data )) break; + if (overhead) + memmove( (char *)&data->data + overhead, &data->data, + data->header.dwSize - sizeof(RAWINPUTHEADER) ); + data->header.dwSize += overhead; + remaining -= data->header.dwSize; + data = NEXTRAWINPUTBLOCK(data); + msg_data = (struct hardware_msg_data *)((char *)msg_data + msg_data->size); + } + + if (!next_size) + { + if (!count) + *data_size = 0; + else + next_size = rawinput_size; + } + + if (next_size && *data_size <= next_size) + { + SetLastError( ERROR_INSUFFICIENT_BUFFER ); + *data_size = next_size; + count = ~0u; + } + + if (count) + TRACE( "data %p, data_size %p (%u), header_size %u, count %u\n", + data, data_size, *data_size, header_size, count ); + return count; +} + /********************************************************************** * NtUserGetRawInputData (win32u.@) */ diff --git a/dlls/win32u/win32u.spec b/dlls/win32u/win32u.spec index 8b71504f374..6ad0d80333c 100644 --- a/dlls/win32u/win32u.spec +++ b/dlls/win32u/win32u.spec @@ -983,7 +983,7 @@ @ stdcall -syscall NtUserGetProp(long wstr) @ stdcall NtUserGetQueueStatus(long) @ stub NtUserGetQueueStatusReadonly -@ stub NtUserGetRawInputBuffer +@ stdcall NtUserGetRawInputBuffer(ptr ptr long) @ stdcall NtUserGetRawInputData(ptr long ptr ptr long) @ stub NtUserGetRawInputDeviceInfo @ stub NtUserGetRawInputDeviceList diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index 87901d1313e..4e386c16436 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -243,6 +243,7 @@ struct unix_funcs BOOL (WINAPI *pNtUserGetMessage)( MSG *msg, HWND hwnd, UINT first, UINT last ); INT (WINAPI *pNtUserGetPriorityClipboardFormat)( UINT *list, INT count ); DWORD (WINAPI *pNtUserGetQueueStatus)( UINT flags ); + UINT (WINAPI *pNtUserGetRawInputBuffer)( RAWINPUT *data, UINT *data_size, UINT header_size ); UINT (WINAPI *pNtUserGetRawInputData)( HRAWINPUT rawinput, UINT command, void *data, UINT *data_size, UINT header_size ); HMENU (WINAPI *pNtUserGetSystemMenu)( HWND hwnd, BOOL revert ); diff --git a/dlls/win32u/wrappers.c b/dlls/win32u/wrappers.c index 17354abc73e..59b9401751f 100644 --- a/dlls/win32u/wrappers.c +++ b/dlls/win32u/wrappers.c @@ -1023,6 +1023,12 @@ DWORD WINAPI NtUserGetQueueStatus( UINT flags ) return unix_funcs->pNtUserGetQueueStatus( flags ); }
+UINT WINAPI DECLSPEC_HOTPATCH NtUserGetRawInputBuffer( RAWINPUT *data, UINT *data_size, UINT header_size ) +{ + if (!unix_funcs) return ~0u; + return unix_funcs->pNtUserGetRawInputBuffer( data, data_size, header_size ); +} + UINT WINAPI NtUserGetRawInputData( HRAWINPUT rawinput, UINT command, void *data, UINT *data_size, UINT header_size ) { if (!unix_funcs) return ~0u; diff --git a/include/ntuser.h b/include/ntuser.h index 85b7a87247f..164ce763155 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -589,6 +589,7 @@ HWINSTA WINAPI NtUserGetProcessWindowStation(void); HANDLE WINAPI NtUserGetProp( HWND hwnd, const WCHAR *str ); ULONG WINAPI NtUserGetProcessDpiAwarenessContext( HANDLE process ); DWORD WINAPI NtUserGetQueueStatus( UINT flags ); +UINT WINAPI NtUserGetRawInputBuffer( RAWINPUT *data, UINT *data_size, UINT header_size ); UINT WINAPI NtUserGetRawInputData( HRAWINPUT rawinput, UINT command, void *data, UINT *data_size, UINT header_size ); ULONG WINAPI NtUserGetSystemDpiForProcess( HANDLE process ); HMENU WINAPI NtUserGetSystemMenu( HWND hwnd, BOOL revert );
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=116822
Your paranoid android.
=== debian11 (32 bit report) ===
user32: input.c:2349: Test failed: GetRawInputBuffer succeeded input.c:2350: Test failed: GetRawInputBuffer returned unexpected size: 0 input.c:2351: Test failed: GetRawInputBuffer returned deadbeef input.c:2356: Test failed: GetRawInputBuffer returned unexpected size: 0 input.c:2384: Test failed: GetRawInputBuffer returned 0 input.c:2385: Test failed: GetRawInputBuffer returned unexpected size: 0 input.c:2386: Test failed: Unexpected rawinput data: 0 input.c:2397: Test failed: GetRawInputBuffer succeeded input.c:2398: Test failed: GetRawInputBuffer returned deadbeef input.c:2399: Test failed: Unexpected rawinput data: 0 input.c:2412: Test failed: Spurious WM_INPUT messages
=== debian11 (32 bit Chinese:China report) ===
user32: input.c:2349: Test failed: GetRawInputBuffer succeeded input.c:2350: Test failed: GetRawInputBuffer returned unexpected size: 0 input.c:2351: Test failed: GetRawInputBuffer returned deadbeef input.c:2356: Test failed: GetRawInputBuffer returned unexpected size: 0 input.c:2384: Test failed: GetRawInputBuffer returned 0 input.c:2385: Test failed: GetRawInputBuffer returned unexpected size: 0 input.c:2386: Test failed: Unexpected rawinput data: 0 input.c:2397: Test failed: GetRawInputBuffer succeeded input.c:2398: Test failed: GetRawInputBuffer returned deadbeef input.c:2399: Test failed: Unexpected rawinput data: 0 input.c:2412: Test failed: Spurious WM_INPUT messages
=== debian11 (32 bit WoW report) ===
user32: input.c:2349: Test failed: GetRawInputBuffer succeeded input.c:2350: Test failed: GetRawInputBuffer returned unexpected size: 0 input.c:2351: Test failed: GetRawInputBuffer returned deadbeef input.c:2356: Test failed: GetRawInputBuffer returned unexpected size: 0 input.c:2384: Test failed: GetRawInputBuffer returned 0 input.c:2385: Test failed: GetRawInputBuffer returned unexpected size: 0 input.c:2386: Test failed: Unexpected rawinput data: 0 input.c:2397: Test failed: GetRawInputBuffer succeeded input.c:2398: Test failed: GetRawInputBuffer returned deadbeef input.c:2399: Test failed: Unexpected rawinput data: 0 input.c:2412: Test failed: Spurious WM_INPUT messages
=== debian11 (64 bit WoW report) ===
user32: input.c:2349: Test failed: GetRawInputBuffer succeeded input.c:2350: Test failed: GetRawInputBuffer returned unexpected size: 0 input.c:2351: Test failed: GetRawInputBuffer returned deadbeef input.c:2356: Test failed: GetRawInputBuffer returned unexpected size: 0 input.c:2384: Test failed: GetRawInputBuffer returned 0 input.c:2385: Test failed: GetRawInputBuffer returned unexpected size: 0 input.c:2386: Test failed: Unexpected rawinput data: 0 input.c:2397: Test failed: GetRawInputBuffer succeeded input.c:2398: Test failed: GetRawInputBuffer returned deadbeef input.c:2399: Test failed: Unexpected rawinput data: 0 input.c:2412: Test failed: Spurious WM_INPUT messages
Rémi Bernon (@rbernon) commented about dlls/user32/tests/input.c:
{
if (is_wow64)
{
const RAWINPUT64 *data = (RAWINPUT64 *)buffer;
ok(data->header.dwType == RIM_TYPEMOUSE, "Unexpected rawinput type: %lu\n", data->header.dwType);
ok(data->header.dwSize == sizeof(*data), "Unexpected rawinput size: %lu\n", data->header.dwSize);
todo_wine ok(data->header.wParam == wparam, "Unexpected wparam: %#I64x\n", data->header.wParam);
}
else
{
const RAWINPUT *data = (RAWINPUT *)buffer;
ok(data->header.dwType == RIM_TYPEMOUSE, "Unexpected rawinput type: %lu\n", data->header.dwType);
ok(data->header.dwSize == sizeof(*data), "Unexpected rawinput size: %lu\n", data->header.dwSize);
todo_wine ok(data->header.wParam == wparam, "Unexpected wparam: %#Ix\n", data->header.wParam);
}
}
The i variable isn't used here, I guess you wanted to iterate the buffer?
Rémi Bernon (@rbernon) commented about dlls/user32/tests/input.c:
GetCursorPos(&pt); ok(pt.x == 300 && pt.y == 300, "Unexpected cursor position pos %ldx%ld\n", pt.x, pt.y);
- hwnd = CreateWindowA("static", "static", WS_VISIBLE | WS_POPUP,
- hwnd = CreateWindowA("static", "static", WS_POPUP, 100, 100, 100, 100, 0, NULL, NULL, NULL); SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONG_PTR)rawinputbuffer_wndproc); ok(hwnd != 0, "CreateWindow failed\n");
Wine currently doesn't listen to X11 mouse events in the background, it needs a visible window to receive them and only when the cursor moves over it.
If you want to test `RIDEV_INPUTSINK` I think the best way is to use a second window (possibly invisible), and use it as the `hwndTarget`, while still moving the cursor over the first, visible, window.
On 6/13/22 03:27, Rémi Bernon (@rbernon) wrote:
Rémi Bernon (@rbernon) commented about dlls/user32/tests/input.c:
GetCursorPos(&pt); ok(pt.x == 300 && pt.y == 300, "Unexpected cursor position pos %ldx%ld\n", pt.x, pt.y);
- hwnd = CreateWindowA("static", "static", WS_VISIBLE | WS_POPUP,
- hwnd = CreateWindowA("static", "static", WS_POPUP, 100, 100, 100, 100, 0, NULL, NULL, NULL); SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONG_PTR)rawinputbuffer_wndproc); ok(hwnd != 0, "CreateWindow failed\n");
Wine currently doesn't listen to X11 mouse events in the background, it needs a visible window to receive them and only when the cursor moves over it.
If you want to test `RIDEV_INPUTSINK` I think the best way is to use a second window (possibly invisible), and use it as the `hwndTarget`, while still moving the cursor over the first, visible, window.
I think that doesn't work, because they're still part of the same process. It probably is best to just drop that part of the tests for now.
Rémi Bernon (@rbernon) commented about dlls/user32/tests/input.c:
ok(count == ~0u, "GetRawInputData returned %d\n", count);
ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetRawInputData returned %08lx\n", GetLastError());
}
else if (is_wow64)
{
count = GetRawInputData((HRAWINPUT)lparam, RID_INPUT, &ri, &size, sizeof(RAWINPUTHEADER64));
todo_wine ok(count == sizeof(ri), "GetRawInputData returned %d\n", count);
ok(ri.data.mouse.lLastX == 6, "Unexpected rawinput data: %ld\n", ri.data.mouse.lLastX);
todo_wine ok(GetLastError() == 0xdeadbeef, "GetRawInputData returned %08lx\n", GetLastError());
}
else
{
count = GetRawInputData((HRAWINPUT)lparam, RID_INPUT, &ri, &size, sizeof(RAWINPUTHEADER64));
ok(count == ~0u, "GetRawInputData returned %d\n", count);
ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetRawInputData returned %08lx\n", GetLastError());
}
It feels a bit unbalanced to test invalid cases at the same time as a valid case depending on the arch. Could we have instead a test for the invalid sizes, and the another one with valid size?
IMHO using a ternary operator and a variable for the header size instead of two different `GetRawInputData` calls would make it simpler too.
On 6/13/22 03:27, Rémi Bernon (@rbernon) wrote:
Rémi Bernon (@rbernon) commented about dlls/user32/tests/input.c:
ok(count == ~0u, "GetRawInputData returned %d\n", count);
ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetRawInputData returned %08lx\n", GetLastError());
}
else if (is_wow64)
{
count = GetRawInputData((HRAWINPUT)lparam, RID_INPUT, &ri, &size, sizeof(RAWINPUTHEADER64));
todo_wine ok(count == sizeof(ri), "GetRawInputData returned %d\n", count);
ok(ri.data.mouse.lLastX == 6, "Unexpected rawinput data: %ld\n", ri.data.mouse.lLastX);
todo_wine ok(GetLastError() == 0xdeadbeef, "GetRawInputData returned %08lx\n", GetLastError());
}
else
{
count = GetRawInputData((HRAWINPUT)lparam, RID_INPUT, &ri, &size, sizeof(RAWINPUTHEADER64));
ok(count == ~0u, "GetRawInputData returned %d\n", count);
ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetRawInputData returned %08lx\n", GetLastError());
}
It feels a bit unbalanced to test invalid cases at the same time as a valid case depending on the arch. Could we have instead a test for the invalid sizes, and the another one with valid size?
I don't understand what you mean by this. Only one of these three tests makes sense, and on mutually exclusive architectures.
I could separate the if/elif/else into three separate if blocks, but I doubt that's what you mean.
Rémi Bernon (@rbernon) commented about dlls/user32/tests/input.c:
ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetRawInputBuffer returned %08lx\n", GetLastError());
- SetLastError(0xdeadbeef);
- size = sizeof(buffer);
- count = GetRawInputBuffer((RAWINPUT*)buffer, &size, sizeof(RAWINPUTHEADER) + 1);
- ok(count == ~0U, "GetRawInputBuffer succeeded\n");
- ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetRawInputBuffer returned %08lx\n", GetLastError());
- /* the function returns 64-bit RAWINPUT structures on WoW64, but still
* forbids sizeof(RAWINPUTHEADER) from the wrong architecture */
- SetLastError(0xdeadbeef);
- size = sizeof(buffer);
- if (sizeof(void *) == 8)
count = GetRawInputBuffer((RAWINPUT*)buffer, &size, sizeof(RAWINPUTHEADER32));
- else
count = GetRawInputBuffer((RAWINPUT*)buffer, &size, sizeof(RAWINPUTHEADER64));
Same here, I think adding a conditionally initialized `header_size` variable would make it simpler to read.
Rémi Bernon (@rbernon) commented about dlls/user32/tests/input.c:
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: %lu\n", raw.header.dwType);
ok(raw.header.dwSize == raw_size, "Expected size %u, got %lu\n", raw_size, raw.header.dwSize);
todo_wine_if (wparam)
ok(raw.header.wParam == wparam, "Expected wparam %Iu, got %Iu\n", wparam, raw.header.wParam);
We don't usually indent `todo_wine_(if)`, do we?
On 6/13/22 03:27, Rémi Bernon (@rbernon) wrote:
Rémi Bernon (@rbernon) commented about dlls/user32/tests/input.c:
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: %lu\n", raw.header.dwType);
ok(raw.header.dwSize == raw_size, "Expected size %u, got %lu\n", raw_size, raw.header.dwSize);
todo_wine_if (wparam)
ok(raw.header.wParam == wparam, "Expected wparam %Iu, got %Iu\n", wparam, raw.header.wParam);
We don't usually indent `todo_wine_(if)`, do we?
Some people do. Semantically "todo_wine" is similar to "if (x)" [and "todo_wine_if" is similar to "if"] so I indent it accordingly. This also has the advantage that the line will be touched again when the todo_wine is removed, which can make it easy to spot what commit fixed a test in `git blame` (where applicable).
Rémi Bernon (@rbernon) commented about dlls/win32u/rawinput.c:
wine_server_set_reply( req, msg_data, RAWINPUT_BUFFER_SIZE - rawinput->header.dwSize );
if (wine_server_call( req )) return ~0u;
next_size = reply->next_size;
count = reply->count;
- }
- SERVER_END_REQ;
- remaining = *data_size;
- for (i = 0; i < count; ++i)
- {
data->header.dwSize = remaining;
if (!rawinput_from_hardware_message( data, msg_data )) break;
if (overhead)
memmove( (char *)&data->data + overhead, &data->data,
data->header.dwSize - sizeof(RAWINPUTHEADER) );
data->header.dwSize += overhead;
I'd prefer either the original single hanging style, or ```C if (overhead) { memmove( (char *)&data->data + overhead, &data->data, data->header.dwSize - sizeof(RAWINPUTHEADER) ); data->header.dwSize += overhead; } ``` rather than a double hanging line like this.
Rémi Bernon (@rbernon) commented about dlls/win32u/rawinput.c:
if (!count)
*data_size = 0;
else
next_size = rawinput_size;
- }
- if (next_size && *data_size <= next_size)
- {
SetLastError( ERROR_INSUFFICIENT_BUFFER );
*data_size = next_size;
count = ~0u;
- }
- if (count)
TRACE( "data %p, data_size %p (%u), header_size %u, count %u\n",
data, data_size, *data_size, header_size, count );
Same here, it triggers me somehow. Maybe we could just remove the if.
Rémi Bernon (@rbernon) commented about dlls/win32u/rawinput.c:
if (!rawinput_from_hardware_message( data, msg_data )) break;
if (overhead)
memmove( (char *)&data->data + overhead, &data->data,
data->header.dwSize - sizeof(RAWINPUTHEADER) );
data->header.dwSize += overhead;
remaining -= data->header.dwSize;
data = NEXTRAWINPUTBLOCK(data);
msg_data = (struct hardware_msg_data *)((char *)msg_data + msg_data->size);
- }
- if (!next_size)
- {
if (!count)
*data_size = 0;
else
next_size = rawinput_size;
NP: The new nested if is fine but single line ifs inside could be nicer imho.
Rémi Bernon (@rbernon) commented about dlls/user32/rawinput.c:
}
#ifdef _WIN64 +typedef RAWINPUTHEADER RAWINPUTHEADER64;
I'm not sure about the typedef, it's not used anywhere (yet?). I understand it makes things consistent on both sides of the `#ifdef` though. I guess I'm fine keeping it, just saying.
FWIW you also didn't sign off the patches. I don't know where we are regarding this requirement.
On Tue Jun 14 04:05:11 2022 +0000, **** wrote:
Zebediah Figura replied on the mailing list:
On 6/13/22 03:27, Rémi Bernon (@rbernon) wrote: > Rémi Bernon (@rbernon) commented about dlls/user32/tests/input.c: >> + ok(count == ~0u, "GetRawInputData returned %d\n", count); >> + ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetRawInputData returned %08lx\n", GetLastError()); >> + } >> + else if (is_wow64) >> + { >> + count = GetRawInputData((HRAWINPUT)lparam, RID_INPUT, &ri, &size, sizeof(RAWINPUTHEADER64)); >> + todo_wine ok(count == sizeof(ri), "GetRawInputData returned %d\n", count); >> + ok(ri.data.mouse.lLastX == 6, "Unexpected rawinput data: %ld\n", ri.data.mouse.lLastX); >> + todo_wine ok(GetLastError() == 0xdeadbeef, "GetRawInputData returned %08lx\n", GetLastError()); >> + } >> + else >> + { >> + count = GetRawInputData((HRAWINPUT)lparam, RID_INPUT, &ri, &size, sizeof(RAWINPUTHEADER64)); >> + ok(count == ~0u, "GetRawInputData returned %d\n", count); >> + ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetRawInputData returned %08lx\n", GetLastError()); >> + } > It feels a bit unbalanced to test invalid cases at the same time as a valid case depending on the arch. Could we have instead a test for the invalid sizes, and the another one with valid size? I don't understand what you mean by this. Only one of these three tests makes sense, and on mutually exclusive architectures. I could separate the if/elif/else into three separate if blocks, but I doubt that's what you mean.
I mean that, like the `GetRawInputBuffer` tests below you check an invalid size and ERROR_INVALID_PARAMETER error case, but on wow64, you don't and instead you check a valid size and the returned data.
I think you should check the same cases on all arch if possible, so invalid size and error on all arch (similarly to `GetRawInputBuffer`), then the valid case and data on all arch as well.
On 6/14/22 00:02, Rémi Bernon (@rbernon) wrote:
On Tue Jun 14 04:05:11 2022 +0000, **** wrote:
Zebediah Figura replied on the mailing list:
On 6/13/22 03:27, Rémi Bernon (@rbernon) wrote: > Rémi Bernon (@rbernon) commented about dlls/user32/tests/input.c: >> + ok(count == ~0u, "GetRawInputData returned %d\n", count); >> + ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetRawInputData returned %08lx\n", GetLastError()); >> + } >> + else if (is_wow64) >> + { >> + count = GetRawInputData((HRAWINPUT)lparam, RID_INPUT, &ri, &size, sizeof(RAWINPUTHEADER64)); >> + todo_wine ok(count == sizeof(ri), "GetRawInputData returned %d\n", count); >> + ok(ri.data.mouse.lLastX == 6, "Unexpected rawinput data: %ld\n", ri.data.mouse.lLastX); >> + todo_wine ok(GetLastError() == 0xdeadbeef, "GetRawInputData returned %08lx\n", GetLastError()); >> + } >> + else >> + { >> + count = GetRawInputData((HRAWINPUT)lparam, RID_INPUT, &ri, &size, sizeof(RAWINPUTHEADER64)); >> + ok(count == ~0u, "GetRawInputData returned %d\n", count); >> + ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetRawInputData returned %08lx\n", GetLastError()); >> + } > It feels a bit unbalanced to test invalid cases at the same time as a valid case depending on the arch. Could we have instead a test for the invalid sizes, and the another one with valid size? I don't understand what you mean by this. Only one of these three tests makes sense, and on mutually exclusive architectures. I could separate the if/elif/else into three separate if blocks, but I doubt that's what you mean.
I mean that, like the `GetRawInputBuffer` tests below you check an invalid size and ERROR_INVALID_PARAMETER error case, but on wow64, you don't and instead you check a valid size and the returned data.
I think you should check the same cases on all arch if possible, so invalid size and error on all arch (similarly to `GetRawInputBuffer`), then the valid case and data on all arch as well.
The point is to check the "wrong" architecture's size in all three cases. In the wow64 case, this succeeds; otherwise, it fails. This quirk is specific to GetRawInputData(); GetRawInputBuffer() always rejects the "wrong" architecture's size.
Perhaps this structure would make it clearer:
if (sizeof(void *) == 8) { count = GetRawInputData(..., sizeof(RAWINPUTHEADER32)); ok(count == ~0u, ...); } else { count = GetRawInputData(..., sizeof(RAWINPUTHEADER64)); if (is_wow64) { ok(count == sizeof(ri), ...); } else { ok(count == ~0u, ...); } }
On Tue Jun 14 04:03:29 2022 +0000, **** wrote:
Zebediah Figura replied on the mailing list:
On 6/13/22 03:27, Rémi Bernon (@rbernon) wrote: > Rémi Bernon (@rbernon) commented about dlls/user32/tests/input.c: >> 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: %lu\n", raw.header.dwType); >> + ok(raw.header.dwSize == raw_size, "Expected size %u, got %lu\n", raw_size, raw.header.dwSize); >> + todo_wine_if (wparam) >> + ok(raw.header.wParam == wparam, "Expected wparam %Iu, got %Iu\n", wparam, raw.header.wParam); > We don't usually indent `todo_wine_(if)`, do we? > Some people do. Semantically "todo_wine" is similar to "if (x)" [and "todo_wine_if" is similar to "if"] so I indent it accordingly. This also has the advantage that the line will be touched again when the todo_wine is removed, which can make it easy to spot what commit fixed a test in `git blame` (where applicable).
Sure, it's a matter of taste, but it didn't seem to me that we _usually_ indent it. So that for instance, removing the todo doesn't need to touch the test line itself.
On Tue Jun 14 05:04:59 2022 +0000, Rémi Bernon wrote:
Sure, it's a matter of taste, but it didn't seem to me that we _usually_ indent it. So that for instance, removing the todo doesn't need to touch the test line itself.
Re-reading, you say it's touching the line on purpose. I don't mind any way.
On Wed Jun 15 23:43:22 2022 +0000, **** wrote:
Zebediah Figura replied on the mailing list:
On 6/14/22 00:02, Rémi Bernon (@rbernon) wrote: > On Tue Jun 14 04:05:11 2022 +0000, **** wrote: >> Zebediah Figura replied on the mailing list: >> \`\`\` >> On 6/13/22 03:27, Rémi Bernon (@rbernon) wrote: >>> Rémi Bernon (@rbernon) commented about dlls/user32/tests/input.c: >>>> + ok(count == ~0u, "GetRawInputData returned %d\n", count); >>>> + ok(GetLastError() == ERROR_INVALID_PARAMETER, >> "GetRawInputData returned %08lx\n", GetLastError()); >>>> + } >>>> + else if (is_wow64) >>>> + { >>>> + count = GetRawInputData((HRAWINPUT)lparam, >> RID_INPUT, &ri, &size, sizeof(RAWINPUTHEADER64)); >>>> + todo_wine ok(count == sizeof(ri), "GetRawInputData >> returned %d\n", count); >>>> + ok(ri.data.mouse.lLastX == 6, "Unexpected rawinput >> data: %ld\n", ri.data.mouse.lLastX); >>>> + todo_wine ok(GetLastError() == 0xdeadbeef, >> "GetRawInputData returned %08lx\n", GetLastError()); >>>> + } >>>> + else >>>> + { >>>> + count = GetRawInputData((HRAWINPUT)lparam, >> RID_INPUT, &ri, &size, sizeof(RAWINPUTHEADER64)); >>>> + ok(count == ~0u, "GetRawInputData returned %d\n", count); >>>> + ok(GetLastError() == ERROR_INVALID_PARAMETER, >> "GetRawInputData returned %08lx\n", GetLastError()); >>>> + } >>> It feels a bit unbalanced to test invalid cases at the same time as a >> valid case depending on the arch. Could we have instead a test for the >> invalid sizes, and the another one with valid size? >> I don't understand what you mean by this. Only one of these three tests >> makes sense, and on mutually exclusive architectures. >> I could separate the if/elif/else into three separate if blocks, but I >> doubt that's what you mean. >> \`\`\` > I mean that, like the `GetRawInputBuffer` tests below you check an invalid size and ERROR_INVALID_PARAMETER error case, but on wow64, you don't and instead you check a valid size and the returned data. > > I think you should check the same cases on all arch if possible, so invalid size and error on all arch (similarly to `GetRawInputBuffer`), then the valid case and data on all arch as well. > The point is to check the "wrong" architecture's size in all three cases. In the wow64 case, this succeeds; otherwise, it fails. This quirk is specific to GetRawInputData(); GetRawInputBuffer() always rejects the "wrong" architecture's size. Perhaps this structure would make it clearer: if (sizeof(void *) == 8) { count = GetRawInputData(..., sizeof(RAWINPUTHEADER32)); ok(count == ~0u, ...); } else { count = GetRawInputData(..., sizeof(RAWINPUTHEADER64)); if (is_wow64) { ok(count == sizeof(ri), ...); } else { ok(count == ~0u, ...); } }
Yeah looks clearer.