Validating that SendInput with INPUT_HARDWARE type should be no-op.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=50506 Signed-off-by: Rémi Bernon rbernon@codeweavers.com ---
v2: Remove the #ifdef _WIN64 and mark 32bit test results as broken.
dlls/user32/input.c | 18 ++++++ dlls/user32/tests/input.c | 113 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 131 insertions(+)
diff --git a/dlls/user32/input.c b/dlls/user32/input.c index 8992c463c48..22e53585f00 100644 --- a/dlls/user32/input.c +++ b/dlls/user32/input.c @@ -182,6 +182,24 @@ UINT WINAPI SendInput( UINT count, LPINPUT inputs, int size ) UINT i; NTSTATUS status;
+ if (size != sizeof(INPUT)) + { + SetLastError( ERROR_INVALID_PARAMETER ); + return 0; + } + + if (!count) + { + SetLastError( ERROR_INVALID_PARAMETER ); + return 0; + } + + if (!inputs) + { + SetLastError( ERROR_NOACCESS ); + return 0; + } + for (i = 0; i < count; i++) { if (inputs[i].type == INPUT_MOUSE) diff --git a/dlls/user32/tests/input.c b/dlls/user32/tests/input.c index 646a9a66eb5..0bbd03c615e 100644 --- a/dlls/user32/tests/input.c +++ b/dlls/user32/tests/input.c @@ -4212,6 +4212,118 @@ static void test_UnregisterDeviceNotification(void) ok(ret == FALSE, "Unregistering NULL Device Notification returned: %d\n", ret); }
+static void test_SendInput(void) +{ + INPUT input[16]; + UINT res, i; + HWND hwnd; + MSG msg; + + hwnd = CreateWindowW( L"static", L"test", WS_OVERLAPPED, 0, 0, 100, 100, 0, 0, 0, 0 ); + ok( hwnd != 0, "CreateWindowW failed\n" ); + + ShowWindow( hwnd, SW_SHOWNORMAL ); + UpdateWindow( hwnd ); + SetForegroundWindow( hwnd ); + SetFocus( hwnd ); + empty_message_queue(); + + SetLastError( 0xdeadbeef ); + res = SendInput( 0, NULL, 0 ); + ok( res == 0 && GetLastError() == ERROR_INVALID_PARAMETER, "SendInput returned %u, error %#x\n", res, GetLastError() ); + SetLastError( 0xdeadbeef ); + res = SendInput( 1, NULL, 0 ); + ok( res == 0 && GetLastError() == ERROR_INVALID_PARAMETER, "SendInput returned %u, error %#x\n", res, GetLastError() ); + SetLastError( 0xdeadbeef ); + res = SendInput( 1, NULL, sizeof(*input) ); + ok( res == 0 && (GetLastError() == ERROR_NOACCESS || GetLastError() == ERROR_INVALID_PARAMETER), + "SendInput returned %u, error %#x\n", res, GetLastError() ); + SetLastError( 0xdeadbeef ); + res = SendInput( 0, input, sizeof(*input) ); + ok( res == 0 && GetLastError() == ERROR_INVALID_PARAMETER, "SendInput returned %u, error %#x\n", res, GetLastError() ); + SetLastError( 0xdeadbeef ); + res = SendInput( 0, NULL, sizeof(*input) ); + ok( res == 0 && GetLastError() == ERROR_INVALID_PARAMETER, "SendInput returned %u, error %#x\n", res, GetLastError() ); + + memset( input, 0, sizeof(input) ); + SetLastError( 0xdeadbeef ); + res = SendInput( 1, input, sizeof(*input) ); + ok( res == 1 && GetLastError() == 0xdeadbeef, "SendInput returned %u, error %#x\n", res, GetLastError() ); + SetLastError( 0xdeadbeef ); + res = SendInput( 16, input, sizeof(*input) ); + ok( res == 16 && GetLastError() == 0xdeadbeef, "SendInput returned %u, error %#x\n", res, GetLastError() ); + + SetLastError( 0xdeadbeef ); + res = SendInput( 1, input, 0 ); + ok( res == 0 && GetLastError() == ERROR_INVALID_PARAMETER, "SendInput returned %u, error %#x\n", res, GetLastError() ); + SetLastError( 0xdeadbeef ); + res = SendInput( 1, input, sizeof(*input) + 1 ); + ok( res == 0 && GetLastError() == ERROR_INVALID_PARAMETER, "SendInput returned %u, error %#x\n", res, GetLastError() ); + SetLastError( 0xdeadbeef ); + res = SendInput( 1, input, sizeof(*input) - 1 ); + ok( res == 0 && GetLastError() == ERROR_INVALID_PARAMETER, "SendInput returned %u, error %#x\n", res, GetLastError() ); + + for (i = 0; i < ARRAY_SIZE(input); ++i) input[i].type = INPUT_KEYBOARD; + SetLastError( 0xdeadbeef ); + res = SendInput( 16, input, offsetof( INPUT, ki ) + sizeof(KEYBDINPUT) ); + ok( res == 0 && GetLastError() == ERROR_INVALID_PARAMETER, "SendInput returned %u, error %#x\n", res, GetLastError() ); + SetLastError( 0xdeadbeef ); + res = SendInput( 16, input, sizeof(*input) ); + ok( res == 16 && GetLastError() == 0xdeadbeef, "SendInput returned %u, error %#x\n", res, GetLastError() ); + empty_message_queue(); + + for (i = 0; i < ARRAY_SIZE(input); ++i) input[i].type = INPUT_HARDWARE; + SetLastError( 0xdeadbeef ); + res = SendInput( 16, input, offsetof( INPUT, hi ) + sizeof(HARDWAREINPUT) ); + ok( res == 0 && GetLastError() == ERROR_INVALID_PARAMETER, "SendInput returned %u, error %#x\n", res, GetLastError() ); + + input[0].hi.uMsg = WM_KEYDOWN; + input[0].hi.wParamL = 0; + input[0].hi.wParamH = 'A'; + input[1].hi.uMsg = WM_KEYUP; + input[1].hi.wParamL = 0; + input[1].hi.wParamH = 'A' | 0xc000; + SetLastError( 0xdeadbeef ); + res = SendInput( 16, input, sizeof(*input) ); + todo_wine + ok( (res == 0 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) || + broken(res == 16 && GetLastError() == 0xdeadbeef) /* 32bit */, + "SendInput returned %u, error %#x\n", res, GetLastError() ); + while ((res = wait_for_message(&msg)) && msg.message == WM_TIMER) DispatchMessageA(&msg); + todo_wine ok( !res, "SendInput triggered unexpected message %#x\n", msg.message ); + empty_message_queue(); + + memset( input, 0, sizeof(input) ); + input[0].type = INPUT_HARDWARE; + input[1].type = INPUT_KEYBOARD; + input[1].ki.wVk = 'A'; + input[1].ki.dwFlags = 0; + input[2].type = INPUT_KEYBOARD; + input[2].ki.wVk = 'A'; + input[2].ki.dwFlags = KEYEVENTF_KEYUP; + SetLastError( 0xdeadbeef ); + res = SendInput( 16, input, sizeof(*input) ); + todo_wine + ok( (res == 0 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) || + broken(res == 16 && GetLastError() == 0xdeadbeef), + "SendInput returned %u, error %#x\n", res, GetLastError() ); + while ((res = wait_for_message(&msg)) && (msg.message == WM_TIMER || broken(msg.message == WM_KEYDOWN || msg.message == WM_KEYUP))) + DispatchMessageA(&msg); + todo_wine ok( !res, "SendInput triggered unexpected message %#x\n", msg.message ); + empty_message_queue(); + + for (i = 0; i < ARRAY_SIZE(input); ++i) input[i].type = INPUT_HARDWARE + 1; + SetLastError( 0xdeadbeef ); + res = SendInput( 16, input, sizeof(*input) ); + todo_wine ok( res == 16 && GetLastError() == 0xdeadbeef, "SendInput returned %u, error %#x\n", res, GetLastError() ); + while ((res = wait_for_message(&msg)) && msg.message == WM_TIMER) DispatchMessageA(&msg); + todo_wine ok( !res, "SendInput triggered unexpected message %#x\n", msg.message ); + empty_message_queue(); + + trace( "done\n" ); + DestroyWindow( hwnd ); +} + START_TEST(input) { char **argv; @@ -4234,6 +4346,7 @@ START_TEST(input) return; }
+ test_SendInput(); test_Input_blackbox(); test_Input_whitebox(); test_Input_unicode();
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=50506 Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/user32/input.c | 14 ++++++++++---- dlls/user32/tests/input.c | 10 ++++------ 2 files changed, 14 insertions(+), 10 deletions(-)
diff --git a/dlls/user32/input.c b/dlls/user32/input.c index 22e53585f00..7cf7e53a6c8 100644 --- a/dlls/user32/input.c +++ b/dlls/user32/input.c @@ -180,7 +180,7 @@ static void update_mouse_coords( INPUT *input ) UINT WINAPI SendInput( UINT count, LPINPUT inputs, int size ) { UINT i; - NTSTATUS status; + NTSTATUS status = STATUS_SUCCESS;
if (size != sizeof(INPUT)) { @@ -202,14 +202,20 @@ UINT WINAPI SendInput( UINT count, LPINPUT inputs, int size )
for (i = 0; i < count; i++) { - if (inputs[i].type == INPUT_MOUSE) + INPUT input = inputs[i]; + switch (input.type) { + case INPUT_MOUSE: /* we need to update the coordinates to what the server expects */ - INPUT input = inputs[i]; update_mouse_coords( &input ); + /* fallthrough */ + case INPUT_KEYBOARD: status = send_hardware_message( 0, &input, SEND_HWMSG_INJECTED ); + break; + case INPUT_HARDWARE: + SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); + return 0; } - else status = send_hardware_message( 0, &inputs[i], SEND_HWMSG_INJECTED );
if (status) { diff --git a/dlls/user32/tests/input.c b/dlls/user32/tests/input.c index 0bbd03c615e..2397b4104e4 100644 --- a/dlls/user32/tests/input.c +++ b/dlls/user32/tests/input.c @@ -4285,12 +4285,11 @@ static void test_SendInput(void) input[1].hi.wParamH = 'A' | 0xc000; SetLastError( 0xdeadbeef ); res = SendInput( 16, input, sizeof(*input) ); - todo_wine ok( (res == 0 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) || broken(res == 16 && GetLastError() == 0xdeadbeef) /* 32bit */, "SendInput returned %u, error %#x\n", res, GetLastError() ); while ((res = wait_for_message(&msg)) && msg.message == WM_TIMER) DispatchMessageA(&msg); - todo_wine ok( !res, "SendInput triggered unexpected message %#x\n", msg.message ); + ok( !res, "SendInput triggered unexpected message %#x\n", msg.message ); empty_message_queue();
memset( input, 0, sizeof(input) ); @@ -4303,21 +4302,20 @@ static void test_SendInput(void) input[2].ki.dwFlags = KEYEVENTF_KEYUP; SetLastError( 0xdeadbeef ); res = SendInput( 16, input, sizeof(*input) ); - todo_wine ok( (res == 0 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) || broken(res == 16 && GetLastError() == 0xdeadbeef), "SendInput returned %u, error %#x\n", res, GetLastError() ); while ((res = wait_for_message(&msg)) && (msg.message == WM_TIMER || broken(msg.message == WM_KEYDOWN || msg.message == WM_KEYUP))) DispatchMessageA(&msg); - todo_wine ok( !res, "SendInput triggered unexpected message %#x\n", msg.message ); + ok( !res, "SendInput triggered unexpected message %#x\n", msg.message ); empty_message_queue();
for (i = 0; i < ARRAY_SIZE(input); ++i) input[i].type = INPUT_HARDWARE + 1; SetLastError( 0xdeadbeef ); res = SendInput( 16, input, sizeof(*input) ); - todo_wine ok( res == 16 && GetLastError() == 0xdeadbeef, "SendInput returned %u, error %#x\n", res, GetLastError() ); + ok( res == 16 && GetLastError() == 0xdeadbeef, "SendInput returned %u, error %#x\n", res, GetLastError() ); while ((res = wait_for_message(&msg)) && msg.message == WM_TIMER) DispatchMessageA(&msg); - todo_wine ok( !res, "SendInput triggered unexpected message %#x\n", msg.message ); + ok( !res, "SendInput triggered unexpected message %#x\n", msg.message ); empty_message_queue();
trace( "done\n" );
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=88510
Your paranoid android.
=== w7u_2qxl (32 bit report) ===
user32: input.c:756: Test failed: 0 (a4/0): 00 from 00 -> 80 unexpected input.c:756: Test failed: 0 (a4/0): 41 from 01 -> 00 unexpected
=== w7u_el (32 bit report) ===
user32: input.c:4292: Test failed: SendInput triggered unexpected message 0xc042
=== w1064 (32 bit report) ===
user32: input.c:3258: Test failed: expected WM_LBUTTONDOWN message input.c:3259: Test failed: expected WM_LBUTTONUP message input.c:3286: Test failed: expected WM_NCHITTEST message input.c:3287: Test failed: expected WM_RBUTTONDOWN message input.c:3288: Test failed: expected WM_RBUTTONUP message input.c:3317: Test failed: expected WM_LBUTTONDOWN message input.c:3318: Test failed: expected WM_LBUTTONUP message input.c:3371: Test failed: expected loop with WM_NCHITTEST messages input.c:3424: Test failed: expected WM_LBUTTONDOWN message input.c:3425: Test failed: expected WM_LBUTTONUP message
=== wvistau64 (64 bit report) ===
user32: input.c:756: Test failed: 0 (a4/0): 00 from 00 -> 80 unexpected input.c:756: Test failed: 0 (a4/0): 01 from 01 -> 00 unexpected input.c:756: Test failed: 0 (a4/0): 11 from 01 -> 00 unexpected input.c:756: Test failed: 0 (a4/0): a2 from 01 -> 00 unexpected
=== w10pro64_ar (64 bit report) ===
user32: input.c:3286: Test failed: expected WM_NCHITTEST message input.c:3287: Test failed: expected WM_RBUTTONDOWN message input.c:3288: Test failed: expected WM_RBUTTONUP message input.c:3317: Test failed: expected WM_LBUTTONDOWN message input.c:3318: Test failed: expected WM_LBUTTONUP message input.c:3371: Test failed: expected loop with WM_NCHITTEST messages input.c:3424: Test failed: expected WM_LBUTTONDOWN message input.c:3425: Test failed: expected WM_LBUTTONUP message
=== debiant2 (32 bit Chinese:China report) ===
user32: clipboard.c:833: Test failed: 3: gle 5 clipboard.c:838: Test failed: 3.0: got 0000 instead of 000e clipboard.c:868: Test failed: 3: gle 1418
And send_hardware_message.
This makes it possible to use __wine_send_input to send extended input data, such as HID device notifications and WM_INPUT messages carrying HID reports.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=50506 Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/user32/input.c | 6 +++--- dlls/user32/message.c | 2 +- dlls/user32/user32.spec | 2 +- dlls/user32/user_private.h | 2 +- dlls/wineandroid.drv/keyboard.c | 2 +- dlls/wineandroid.drv/window.c | 4 ++-- dlls/winemac.drv/ime.c | 4 ++-- dlls/winemac.drv/keyboard.c | 2 +- dlls/winemac.drv/mouse.c | 2 +- dlls/winex11.drv/keyboard.c | 2 +- dlls/winex11.drv/mouse.c | 8 ++++---- include/winuser.h | 2 +- 12 files changed, 19 insertions(+), 19 deletions(-)
diff --git a/dlls/user32/input.c b/dlls/user32/input.c index 7cf7e53a6c8..805bfe3e9de 100644 --- a/dlls/user32/input.c +++ b/dlls/user32/input.c @@ -119,9 +119,9 @@ BOOL set_capture_window( HWND hwnd, UINT gui_flags, HWND *prev_ret ) * * Internal SendInput function to allow the graphics driver to inject real events. */ -BOOL CDECL __wine_send_input( HWND hwnd, const INPUT *input ) +BOOL CDECL __wine_send_input( HWND hwnd, const INPUT *input, const RAWINPUT *rawinput ) { - NTSTATUS status = send_hardware_message( hwnd, input, 0 ); + NTSTATUS status = send_hardware_message( hwnd, input, rawinput, 0 ); if (status) SetLastError( RtlNtStatusToDosError(status) ); return !status; } @@ -210,7 +210,7 @@ UINT WINAPI SendInput( UINT count, LPINPUT inputs, int size ) update_mouse_coords( &input ); /* fallthrough */ case INPUT_KEYBOARD: - status = send_hardware_message( 0, &input, SEND_HWMSG_INJECTED ); + status = send_hardware_message( 0, &input, NULL, SEND_HWMSG_INJECTED ); break; case INPUT_HARDWARE: SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); diff --git a/dlls/user32/message.c b/dlls/user32/message.c index def59998a52..f87ef9fb3af 100644 --- a/dlls/user32/message.c +++ b/dlls/user32/message.c @@ -3227,7 +3227,7 @@ static BOOL send_message( struct send_message_info *info, DWORD_PTR *res_ptr, BO /*********************************************************************** * send_hardware_message */ -NTSTATUS send_hardware_message( HWND hwnd, const INPUT *input, UINT flags ) +NTSTATUS send_hardware_message( HWND hwnd, const INPUT *input, const RAWINPUT *rawinput, UINT flags ) { struct user_key_state_info *key_state_info = get_user_thread_info()->key_state; struct send_message_info info; diff --git a/dlls/user32/user32.spec b/dlls/user32/user32.spec index 4ef75247d71..190ee74fd6c 100644 --- a/dlls/user32/user32.spec +++ b/dlls/user32/user32.spec @@ -834,5 +834,5 @@ # All functions must be prefixed with '__wine_' (for internal functions) # or 'wine_' (for user-visible functions) to avoid namespace conflicts. # -@ cdecl __wine_send_input(long ptr) +@ cdecl __wine_send_input(long ptr ptr) @ cdecl __wine_set_pixel_format(long long) diff --git a/dlls/user32/user_private.h b/dlls/user32/user_private.h index 7761a1ceb4f..dfd52421e66 100644 --- a/dlls/user32/user_private.h +++ b/dlls/user32/user_private.h @@ -263,7 +263,7 @@ extern RECT get_virtual_screen_rect(void) DECLSPEC_HIDDEN; extern LRESULT call_current_hook( HHOOK hhook, INT code, WPARAM wparam, LPARAM lparam ) DECLSPEC_HIDDEN; extern DWORD get_input_codepage( void ) DECLSPEC_HIDDEN; extern BOOL map_wparam_AtoW( UINT message, WPARAM *wparam, enum wm_char_mapping mapping ) DECLSPEC_HIDDEN; -extern NTSTATUS send_hardware_message( HWND hwnd, const INPUT *input, UINT flags ) DECLSPEC_HIDDEN; +extern NTSTATUS send_hardware_message( HWND hwnd, const INPUT *input, const RAWINPUT *rawinput, UINT flags ) DECLSPEC_HIDDEN; extern LRESULT MSG_SendInternalMessageTimeout( DWORD dest_pid, DWORD dest_tid, UINT msg, WPARAM wparam, LPARAM lparam, UINT flags, UINT timeout, PDWORD_PTR res_ptr ) DECLSPEC_HIDDEN; diff --git a/dlls/wineandroid.drv/keyboard.c b/dlls/wineandroid.drv/keyboard.c index 1c8a1e4f68f..0a6ede0ec5f 100644 --- a/dlls/wineandroid.drv/keyboard.c +++ b/dlls/wineandroid.drv/keyboard.c @@ -680,7 +680,7 @@ static void send_keyboard_input( HWND hwnd, WORD vkey, WORD scan, DWORD flags ) input.u.ki.time = 0; input.u.ki.dwExtraInfo = 0;
- __wine_send_input( hwnd, &input ); + __wine_send_input( hwnd, &input, NULL ); }
/*********************************************************************** diff --git a/dlls/wineandroid.drv/window.c b/dlls/wineandroid.drv/window.c index 79bc471a984..1cb1bbbadc9 100644 --- a/dlls/wineandroid.drv/window.c +++ b/dlls/wineandroid.drv/window.c @@ -521,7 +521,7 @@ static int process_events( DWORD mask ) } SERVER_END_REQ; } - __wine_send_input( capture ? capture : event->data.motion.hwnd, &event->data.motion.input ); + __wine_send_input( capture ? capture : event->data.motion.hwnd, &event->data.motion.input, NULL ); } break;
@@ -535,7 +535,7 @@ static int process_events( DWORD mask ) event->data.kbd.input.u.ki.wVk, event->data.kbd.input.u.ki.wVk, event->data.kbd.input.u.ki.wScan ); update_keyboard_lock_state( event->data.kbd.input.u.ki.wVk, event->data.kbd.lock_state ); - __wine_send_input( 0, &event->data.kbd.input ); + __wine_send_input( 0, &event->data.kbd.input, NULL ); break;
default: diff --git a/dlls/winemac.drv/ime.c b/dlls/winemac.drv/ime.c index dabe6654f98..f2368c10743 100644 --- a/dlls/winemac.drv/ime.c +++ b/dlls/winemac.drv/ime.c @@ -1427,10 +1427,10 @@ void macdrv_im_set_text(const macdrv_event *event) { input.ki.wScan = chars[i]; input.ki.dwFlags = KEYEVENTF_UNICODE; - __wine_send_input(hwnd, &input); + __wine_send_input(hwnd, &input, NULL);
input.ki.dwFlags = KEYEVENTF_UNICODE | KEYEVENTF_KEYUP; - __wine_send_input(hwnd, &input); + __wine_send_input(hwnd, &input, NULL); } }
diff --git a/dlls/winemac.drv/keyboard.c b/dlls/winemac.drv/keyboard.c index 1b74300e93a..1ea15f59341 100644 --- a/dlls/winemac.drv/keyboard.c +++ b/dlls/winemac.drv/keyboard.c @@ -929,7 +929,7 @@ static void macdrv_send_keyboard_input(HWND hwnd, WORD vkey, WORD scan, DWORD fl input.ki.time = time; input.ki.dwExtraInfo = 0;
- __wine_send_input(hwnd, &input); + __wine_send_input(hwnd, &input, NULL); }
diff --git a/dlls/winemac.drv/mouse.c b/dlls/winemac.drv/mouse.c index dd6443fe1ba..d2278ae0e4c 100644 --- a/dlls/winemac.drv/mouse.c +++ b/dlls/winemac.drv/mouse.c @@ -165,7 +165,7 @@ static void send_mouse_input(HWND hwnd, macdrv_window cocoa_window, UINT flags, input.mi.time = time; input.mi.dwExtraInfo = 0;
- __wine_send_input(top_level_hwnd, &input); + __wine_send_input(top_level_hwnd, &input, NULL); }
diff --git a/dlls/winex11.drv/keyboard.c b/dlls/winex11.drv/keyboard.c index 35a801fc895..01620c5e4a4 100644 --- a/dlls/winex11.drv/keyboard.c +++ b/dlls/winex11.drv/keyboard.c @@ -1148,7 +1148,7 @@ static void X11DRV_send_keyboard_input( HWND hwnd, WORD vkey, WORD scan, DWORD f input.u.ki.time = time; input.u.ki.dwExtraInfo = 0;
- __wine_send_input( hwnd, &input ); + __wine_send_input( hwnd, &input, NULL ); }
diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index 94dece652b6..42bac332664 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -659,7 +659,7 @@ static void send_mouse_input( HWND hwnd, Window window, unsigned int state, INPU sync_window_cursor( window ); last_cursor_change = input->u.mi.time; } - __wine_send_input( hwnd, input ); + __wine_send_input( hwnd, input, NULL ); return; }
@@ -699,7 +699,7 @@ static void send_mouse_input( HWND hwnd, Window window, unsigned int state, INPU SERVER_END_REQ; }
- __wine_send_input( hwnd, input ); + __wine_send_input( hwnd, input, NULL ); }
#ifdef SONAME_LIBXCURSOR @@ -1669,7 +1669,7 @@ void move_resize_window( HWND hwnd, int dir ) input.u.mi.dwFlags = button_up_flags[button - 1] | MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE; input.u.mi.time = GetTickCount(); input.u.mi.dwExtraInfo = 0; - __wine_send_input( hwnd, &input ); + __wine_send_input( hwnd, &input, NULL ); }
while (PeekMessageW( &msg, 0, 0, 0, PM_REMOVE )) @@ -1900,7 +1900,7 @@ static BOOL X11DRV_RawMotion( XGenericEventCookie *xev ) TRACE( "pos %d,%d (event %f,%f)\n", input.u.mi.dx, input.u.mi.dy, dx, dy );
input.type = INPUT_MOUSE; - __wine_send_input( 0, &input ); + __wine_send_input( 0, &input, NULL ); return TRUE; }
diff --git a/include/winuser.h b/include/winuser.h index 53661f6c788..0b1571c0a95 100644 --- a/include/winuser.h +++ b/include/winuser.h @@ -4406,7 +4406,7 @@ static inline BOOL WINAPI SetRectEmpty(LPRECT rect) WORD WINAPI SYSTEM_KillSystemTimer( WORD );
#ifdef __WINESRC__ -WINUSERAPI BOOL CDECL __wine_send_input( HWND hwnd, const INPUT *input ); +WINUSERAPI BOOL CDECL __wine_send_input( HWND hwnd, const INPUT *input, const RAWINPUT *rawinput ); #endif
#ifdef __cplusplus
On 4/9/21 1:11 PM, Rémi Bernon wrote:
And send_hardware_message.
This makes it possible to use __wine_send_input to send extended input data, such as HID device notifications and WM_INPUT messages carrying HID reports.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=50506 Signed-off-by: Rémi Bernon rbernon@codeweavers.com
dlls/user32/input.c | 6 +++--- dlls/user32/message.c | 2 +- dlls/user32/user32.spec | 2 +- dlls/user32/user_private.h | 2 +- dlls/wineandroid.drv/keyboard.c | 2 +- dlls/wineandroid.drv/window.c | 4 ++-- dlls/winemac.drv/ime.c | 4 ++-- dlls/winemac.drv/keyboard.c | 2 +- dlls/winemac.drv/mouse.c | 2 +- dlls/winex11.drv/keyboard.c | 2 +- dlls/winex11.drv/mouse.c | 8 ++++---- include/winuser.h | 2 +- 12 files changed, 19 insertions(+), 19 deletions(-)
diff --git a/dlls/user32/input.c b/dlls/user32/input.c index 7cf7e53a6c8..805bfe3e9de 100644 --- a/dlls/user32/input.c +++ b/dlls/user32/input.c @@ -119,9 +119,9 @@ BOOL set_capture_window( HWND hwnd, UINT gui_flags, HWND *prev_ret )
- Internal SendInput function to allow the graphics driver to inject real events.
*/ -BOOL CDECL __wine_send_input( HWND hwnd, const INPUT *input ) +BOOL CDECL __wine_send_input( HWND hwnd, const INPUT *input, const RAWINPUT *rawinput ) {
- NTSTATUS status = send_hardware_message( hwnd, input, 0 );
- NTSTATUS status = send_hardware_message( hwnd, input, rawinput, 0 ); if (status) SetLastError( RtlNtStatusToDosError(status) ); return !status; }
@@ -210,7 +210,7 @@ UINT WINAPI SendInput( UINT count, LPINPUT inputs, int size ) update_mouse_coords( &input ); /* fallthrough */ case INPUT_KEYBOARD:
status = send_hardware_message( 0, &input, SEND_HWMSG_INJECTED );
status = send_hardware_message( 0, &input, NULL, SEND_HWMSG_INJECTED ); break; case INPUT_HARDWARE: SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
diff --git a/dlls/user32/message.c b/dlls/user32/message.c index def59998a52..f87ef9fb3af 100644 --- a/dlls/user32/message.c +++ b/dlls/user32/message.c @@ -3227,7 +3227,7 @@ static BOOL send_message( struct send_message_info *info, DWORD_PTR *res_ptr, BO /***********************************************************************
send_hardware_message
*/ -NTSTATUS send_hardware_message( HWND hwnd, const INPUT *input, UINT flags ) +NTSTATUS send_hardware_message( HWND hwnd, const INPUT *input, const RAWINPUT *rawinput, UINT flags ) { struct user_key_state_info *key_state_info = get_user_thread_info()->key_state; struct send_message_info info; diff --git a/dlls/user32/user32.spec b/dlls/user32/user32.spec index 4ef75247d71..190ee74fd6c 100644 --- a/dlls/user32/user32.spec +++ b/dlls/user32/user32.spec @@ -834,5 +834,5 @@ # All functions must be prefixed with '__wine_' (for internal functions) # or 'wine_' (for user-visible functions) to avoid namespace conflicts. # -@ cdecl __wine_send_input(long ptr) +@ cdecl __wine_send_input(long ptr ptr) @ cdecl __wine_set_pixel_format(long long) diff --git a/dlls/user32/user_private.h b/dlls/user32/user_private.h index 7761a1ceb4f..dfd52421e66 100644 --- a/dlls/user32/user_private.h +++ b/dlls/user32/user_private.h @@ -263,7 +263,7 @@ extern RECT get_virtual_screen_rect(void) DECLSPEC_HIDDEN; extern LRESULT call_current_hook( HHOOK hhook, INT code, WPARAM wparam, LPARAM lparam ) DECLSPEC_HIDDEN; extern DWORD get_input_codepage( void ) DECLSPEC_HIDDEN; extern BOOL map_wparam_AtoW( UINT message, WPARAM *wparam, enum wm_char_mapping mapping ) DECLSPEC_HIDDEN; -extern NTSTATUS send_hardware_message( HWND hwnd, const INPUT *input, UINT flags ) DECLSPEC_HIDDEN; +extern NTSTATUS send_hardware_message( HWND hwnd, const INPUT *input, const RAWINPUT *rawinput, UINT flags ) DECLSPEC_HIDDEN; extern LRESULT MSG_SendInternalMessageTimeout( DWORD dest_pid, DWORD dest_tid, UINT msg, WPARAM wparam, LPARAM lparam, UINT flags, UINT timeout, PDWORD_PTR res_ptr ) DECLSPEC_HIDDEN; diff --git a/dlls/wineandroid.drv/keyboard.c b/dlls/wineandroid.drv/keyboard.c index 1c8a1e4f68f..0a6ede0ec5f 100644 --- a/dlls/wineandroid.drv/keyboard.c +++ b/dlls/wineandroid.drv/keyboard.c @@ -680,7 +680,7 @@ static void send_keyboard_input( HWND hwnd, WORD vkey, WORD scan, DWORD flags ) input.u.ki.time = 0; input.u.ki.dwExtraInfo = 0;
- __wine_send_input( hwnd, &input );
__wine_send_input( hwnd, &input, NULL ); }
/***********************************************************************
diff --git a/dlls/wineandroid.drv/window.c b/dlls/wineandroid.drv/window.c index 79bc471a984..1cb1bbbadc9 100644 --- a/dlls/wineandroid.drv/window.c +++ b/dlls/wineandroid.drv/window.c @@ -521,7 +521,7 @@ static int process_events( DWORD mask ) } SERVER_END_REQ; }
__wine_send_input( capture ? capture : event->data.motion.hwnd, &event->data.motion.input );
__wine_send_input( capture ? capture : event->data.motion.hwnd, &event->data.motion.input, NULL ); } break;
@@ -535,7 +535,7 @@ static int process_events( DWORD mask ) event->data.kbd.input.u.ki.wVk, event->data.kbd.input.u.ki.wVk, event->data.kbd.input.u.ki.wScan ); update_keyboard_lock_state( event->data.kbd.input.u.ki.wVk, event->data.kbd.lock_state );
__wine_send_input( 0, &event->data.kbd.input );
__wine_send_input( 0, &event->data.kbd.input, NULL ); break; default:
diff --git a/dlls/winemac.drv/ime.c b/dlls/winemac.drv/ime.c index dabe6654f98..f2368c10743 100644 --- a/dlls/winemac.drv/ime.c +++ b/dlls/winemac.drv/ime.c @@ -1427,10 +1427,10 @@ void macdrv_im_set_text(const macdrv_event *event) { input.ki.wScan = chars[i]; input.ki.dwFlags = KEYEVENTF_UNICODE;
__wine_send_input(hwnd, &input);
__wine_send_input(hwnd, &input, NULL); input.ki.dwFlags = KEYEVENTF_UNICODE | KEYEVENTF_KEYUP;
__wine_send_input(hwnd, &input);
__wine_send_input(hwnd, &input, NULL); } }
diff --git a/dlls/winemac.drv/keyboard.c b/dlls/winemac.drv/keyboard.c index 1b74300e93a..1ea15f59341 100644 --- a/dlls/winemac.drv/keyboard.c +++ b/dlls/winemac.drv/keyboard.c @@ -929,7 +929,7 @@ static void macdrv_send_keyboard_input(HWND hwnd, WORD vkey, WORD scan, DWORD fl input.ki.time = time; input.ki.dwExtraInfo = 0;
- __wine_send_input(hwnd, &input);
- __wine_send_input(hwnd, &input, NULL); }
diff --git a/dlls/winemac.drv/mouse.c b/dlls/winemac.drv/mouse.c index dd6443fe1ba..d2278ae0e4c 100644 --- a/dlls/winemac.drv/mouse.c +++ b/dlls/winemac.drv/mouse.c @@ -165,7 +165,7 @@ static void send_mouse_input(HWND hwnd, macdrv_window cocoa_window, UINT flags, input.mi.time = time; input.mi.dwExtraInfo = 0;
- __wine_send_input(top_level_hwnd, &input);
- __wine_send_input(top_level_hwnd, &input, NULL); }
diff --git a/dlls/winex11.drv/keyboard.c b/dlls/winex11.drv/keyboard.c index 35a801fc895..01620c5e4a4 100644 --- a/dlls/winex11.drv/keyboard.c +++ b/dlls/winex11.drv/keyboard.c @@ -1148,7 +1148,7 @@ static void X11DRV_send_keyboard_input( HWND hwnd, WORD vkey, WORD scan, DWORD f input.u.ki.time = time; input.u.ki.dwExtraInfo = 0;
- __wine_send_input( hwnd, &input );
- __wine_send_input( hwnd, &input, NULL ); }
diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index 94dece652b6..42bac332664 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -659,7 +659,7 @@ static void send_mouse_input( HWND hwnd, Window window, unsigned int state, INPU sync_window_cursor( window ); last_cursor_change = input->u.mi.time; }
__wine_send_input( hwnd, input );
__wine_send_input( hwnd, input, NULL ); return; }
@@ -699,7 +699,7 @@ static void send_mouse_input( HWND hwnd, Window window, unsigned int state, INPU SERVER_END_REQ; }
- __wine_send_input( hwnd, input );
__wine_send_input( hwnd, input, NULL ); }
#ifdef SONAME_LIBXCURSOR
@@ -1669,7 +1669,7 @@ void move_resize_window( HWND hwnd, int dir ) input.u.mi.dwFlags = button_up_flags[button - 1] | MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE; input.u.mi.time = GetTickCount(); input.u.mi.dwExtraInfo = 0;
__wine_send_input( hwnd, &input );
__wine_send_input( hwnd, &input, NULL ); } while (PeekMessageW( &msg, 0, 0, 0, PM_REMOVE ))
@@ -1900,7 +1900,7 @@ static BOOL X11DRV_RawMotion( XGenericEventCookie *xev ) TRACE( "pos %d,%d (event %f,%f)\n", input.u.mi.dx, input.u.mi.dy, dx, dy );
input.type = INPUT_MOUSE;
- __wine_send_input( 0, &input );
- __wine_send_input( 0, &input, NULL ); return TRUE; }
diff --git a/include/winuser.h b/include/winuser.h index 53661f6c788..0b1571c0a95 100644 --- a/include/winuser.h +++ b/include/winuser.h @@ -4406,7 +4406,7 @@ static inline BOOL WINAPI SetRectEmpty(LPRECT rect) WORD WINAPI SYSTEM_KillSystemTimer( WORD );
#ifdef __WINESRC__ -WINUSERAPI BOOL CDECL __wine_send_input( HWND hwnd, const INPUT *input ); +WINUSERAPI BOOL CDECL __wine_send_input( HWND hwnd, const INPUT *input, const RAWINPUT *rawinput ); #endif
#ifdef __cplusplus
Hi,
I'm a bit confused about this, as the first two patches have been accepted but not this one.
I think the changes here are pretty straightforward, so does this mean that this should be done some other way? Maybe I should start implementing the handling of the rawinput data first? I did it by sending the data first to avoid adding dead code, but I don't really mind.
The winuser.h changes forces a rebuild of a lot of things, so this patch takes a long time on the testbot, as well as any patches sent with it, so I would love a few hints before resending it.
Cheers,
Rémi Bernon rbernon@codeweavers.com writes:
The winuser.h changes forces a rebuild of a lot of things, so this patch takes a long time on the testbot, as well as any patches sent with it, so I would love a few hints before resending it.
I didn't want to rebuild everything either last night ;-) It should go in with today's round.
On 4/15/21 10:39 AM, Alexandre Julliard wrote:
Rémi Bernon rbernon@codeweavers.com writes:
The winuser.h changes forces a rebuild of a lot of things, so this patch takes a long time on the testbot, as well as any patches sent with it, so I would love a few hints before resending it.
I didn't want to rebuild everything either last night ;-) It should go in with today's round.
Awesome (and I understand), thanks!
The handles are just numeric values and not real object handles, they are used in the hDevice field of the RAWINPUTHEADER struct.
They will also be used as an HID rawinput device array index on the server side.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=50506 Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/hidclass.sys/device.c | 17 +++++++++++++++++ dlls/hidclass.sys/hid.h | 1 + 2 files changed, 18 insertions(+)
diff --git a/dlls/hidclass.sys/device.c b/dlls/hidclass.sys/device.c index fc1dfd07db1..9a3c92b3576 100644 --- a/dlls/hidclass.sys/device.c +++ b/dlls/hidclass.sys/device.c @@ -71,6 +71,17 @@ NTSTATUS HID_CreateDevice(DEVICE_OBJECT *native_device, HID_MINIDRIVER_REGISTRAT return STATUS_SUCCESS; }
+/* user32 reserves 1 & 2 for winemouse and winekeyboard, + * keep this in sync with user_private.h */ +#define WINE_MOUSE_HANDLE 1 +#define WINE_KEYBOARD_HANDLE 2 + +static UINT32 alloc_rawinput_handle(void) +{ + static LONG counter = WINE_KEYBOARD_HANDLE + 1; + return InterlockedIncrement(&counter); +} + NTSTATUS HID_LinkDevice(DEVICE_OBJECT *device) { WCHAR device_instance_id[MAX_DEVICE_ID_LEN]; @@ -125,7 +136,13 @@ NTSTATUS HID_LinkDevice(DEVICE_OBJECT *device) { if (!IoRegisterDeviceInterface(device, &GUID_DEVINTERFACE_MOUSE, NULL, &ext->mouse_link_name)) ext->is_mouse = TRUE; + ext->rawinput_handle = WINE_MOUSE_HANDLE; } + else if (ext->preparseData->caps.UsagePage == HID_USAGE_PAGE_GENERIC + && ext->preparseData->caps.Usage == HID_USAGE_GENERIC_KEYBOARD) + ext->rawinput_handle = WINE_KEYBOARD_HANDLE; + else + ext->rawinput_handle = alloc_rawinput_handle();
return STATUS_SUCCESS;
diff --git a/dlls/hidclass.sys/hid.h b/dlls/hidclass.sys/hid.h index 889b8c625c0..41f3766a535 100644 --- a/dlls/hidclass.sys/hid.h +++ b/dlls/hidclass.sys/hid.h @@ -51,6 +51,7 @@ typedef struct _BASE_DEVICE_EXTENSION { struct ReportRingBuffer *ring_buffer; HANDLE halt_event; HANDLE thread; + UINT32 rawinput_handle;
KSPIN_LOCK irp_queue_lock; LIST_ENTRY irp_queue;
On Fri, Apr 09, 2021 at 01:11:34PM +0200, Rémi Bernon wrote:
The handles are just numeric values and not real object handles, they are used in the hDevice field of the RAWINPUTHEADER struct.
They will also be used as an HID rawinput device array index on the server side.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=50506 Signed-off-by: Rémi Bernon rbernon@codeweavers.com
Signed-off-by: Arkadiusz Hiler ahiler@codeweavers.com
hDevice is an opaque value that's consistent across processes, so it's probably a global identifier assigned by the system. This looks like a correct thing to do.
This currently does nothing, because winedevice.exe isn't associated with any desktop, and the INPUT_HARDWARE messages are dropped.
In this specific case, when INPUT type is INPUT_HARDWARE and hi.uMsg is WM_INPUT_DEVICE_CHANGE, the RAWINPUT structure usage is a non-standard extension for Wine internal usage:
* header.wParam contains the message GIDC_ARRIVAL / GIDC_REMOVAL wparam,
* hid.bRawData contains two bytes, which are the HID device UsagePage and Usage bytes, instead of a real HID report.
This will let us use the same entry point and structures to send device notifications as for the HID reports in the future (which will be sent with INPUT_HARDWARE type / WM_INPUT uMsg instead).
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=50506 Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/hidclass.sys/Makefile.in | 2 +- dlls/hidclass.sys/pnp.c | 36 +++++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-)
diff --git a/dlls/hidclass.sys/Makefile.in b/dlls/hidclass.sys/Makefile.in index be4af747853..2f9f30f8bef 100644 --- a/dlls/hidclass.sys/Makefile.in +++ b/dlls/hidclass.sys/Makefile.in @@ -1,6 +1,6 @@ MODULE = hidclass.sys IMPORTLIB = hidclass -IMPORTS = hal ntoskrnl +IMPORTS = hal ntoskrnl user32 DELAYIMPORTS = setupapi hid
EXTRADLLFLAGS = -mno-cygwin diff --git a/dlls/hidclass.sys/pnp.c b/dlls/hidclass.sys/pnp.c index a499aec93bb..8e539dfe6b7 100644 --- a/dlls/hidclass.sys/pnp.c +++ b/dlls/hidclass.sys/pnp.c @@ -25,6 +25,7 @@ #include "ddk/hidtypes.h" #include "ddk/wdm.h" #include "regstr.h" +#include "winuser.h" #include "wine/debug.h" #include "wine/list.h"
@@ -69,6 +70,9 @@ static NTSTATUS get_device_id(DEVICE_OBJECT *device, BUS_QUERY_ID_TYPE type, WCH return status; }
+/* make sure bRawData can hold two bytes without requiring additional allocation */ +C_ASSERT(offsetof(RAWINPUT, data.hid.bRawData[2]) < sizeof(RAWINPUT)); + NTSTATUS WINAPI PNP_AddDevice(DRIVER_OBJECT *driver, DEVICE_OBJECT *PDO) { WCHAR device_id[MAX_DEVICE_ID_LEN], instance_id[MAX_DEVICE_ID_LEN]; @@ -79,6 +83,8 @@ NTSTATUS WINAPI PNP_AddDevice(DRIVER_OBJECT *driver, DEVICE_OBJECT *PDO) BASE_DEVICE_EXTENSION *ext = NULL; HID_DESCRIPTOR descriptor; BYTE *reportDescriptor; + RAWINPUT rawinput; + INPUT input; INT i;
if ((status = get_device_id(PDO, BusQueryDeviceID, device_id))) @@ -187,6 +193,21 @@ NTSTATUS WINAPI PNP_AddDevice(DRIVER_OBJECT *driver, DEVICE_OBJECT *PDO)
HID_StartDeviceThread(device);
+ rawinput.header.dwType = RIM_TYPEHID; + rawinput.header.dwSize = offsetof(RAWINPUT, data.hid.bRawData[2]); + rawinput.header.hDevice = ULongToHandle(ext->rawinput_handle); + rawinput.header.wParam = GIDC_ARRIVAL; + rawinput.data.hid.dwCount = 1; + rawinput.data.hid.dwSizeHid = 2; + rawinput.data.hid.bRawData[0] = ext->preparseData->caps.UsagePage; + rawinput.data.hid.bRawData[1] = ext->preparseData->caps.Usage; + + input.type = INPUT_HARDWARE; + input.u.hi.uMsg = WM_INPUT_DEVICE_CHANGE; + input.u.hi.wParamH = (WORD)(rawinput.header.dwSize >> 16); + input.u.hi.wParamL = (WORD)(rawinput.header.dwSize >> 0); + __wine_send_input(0, &input, &rawinput); + return STATUS_SUCCESS; }
@@ -194,6 +215,21 @@ static NTSTATUS remove_device(minidriver *minidriver, DEVICE_OBJECT *device, IRP { BASE_DEVICE_EXTENSION *ext = device->DeviceExtension; NTSTATUS rc = STATUS_NOT_SUPPORTED; + RAWINPUT rawinput; + INPUT input; + + rawinput.header.dwType = RIM_TYPEHID; + rawinput.header.dwSize = offsetof(RAWINPUT, data.hid.bRawData[0]); + rawinput.header.hDevice = ULongToHandle(ext->rawinput_handle); + rawinput.header.wParam = GIDC_REMOVAL; + rawinput.data.hid.dwCount = 0; + rawinput.data.hid.dwSizeHid = 0; + + input.type = INPUT_HARDWARE; + input.u.hi.uMsg = WM_INPUT_DEVICE_CHANGE; + input.u.hi.wParamH = (WORD)(rawinput.header.dwSize >> 16); + input.u.hi.wParamL = (WORD)(rawinput.header.dwSize >> 0); + __wine_send_input(0, &input, &rawinput);
rc = IoSetDeviceInterfaceState(&ext->link_name, FALSE); if (rc)
On 4/9/21 1:11 PM, Rémi Bernon wrote:
This currently does nothing, because winedevice.exe isn't associated with any desktop, and the INPUT_HARDWARE messages are dropped.
In this specific case, when INPUT type is INPUT_HARDWARE and hi.uMsg is WM_INPUT_DEVICE_CHANGE, the RAWINPUT structure usage is a non-standard extension for Wine internal usage:
header.wParam contains the message GIDC_ARRIVAL / GIDC_REMOVAL wparam,
hid.bRawData contains two bytes, which are the HID device UsagePage and Usage bytes, instead of a real HID report.
This will let us use the same entry point and structures to send device notifications as for the HID reports in the future (which will be sent with INPUT_HARDWARE type / WM_INPUT uMsg instead).
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=50506 Signed-off-by: Rémi Bernon rbernon@codeweavers.com
dlls/hidclass.sys/Makefile.in | 2 +- dlls/hidclass.sys/pnp.c | 36 +++++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-)
diff --git a/dlls/hidclass.sys/Makefile.in b/dlls/hidclass.sys/Makefile.in index be4af747853..2f9f30f8bef 100644 --- a/dlls/hidclass.sys/Makefile.in +++ b/dlls/hidclass.sys/Makefile.in @@ -1,6 +1,6 @@ MODULE = hidclass.sys IMPORTLIB = hidclass -IMPORTS = hal ntoskrnl +IMPORTS = hal ntoskrnl user32 DELAYIMPORTS = setupapi hid
EXTRADLLFLAGS = -mno-cygwin diff --git a/dlls/hidclass.sys/pnp.c b/dlls/hidclass.sys/pnp.c index a499aec93bb..8e539dfe6b7 100644 --- a/dlls/hidclass.sys/pnp.c +++ b/dlls/hidclass.sys/pnp.c @@ -25,6 +25,7 @@ #include "ddk/hidtypes.h" #include "ddk/wdm.h" #include "regstr.h" +#include "winuser.h" #include "wine/debug.h" #include "wine/list.h"
@@ -69,6 +70,9 @@ static NTSTATUS get_device_id(DEVICE_OBJECT *device, BUS_QUERY_ID_TYPE type, WCH return status; }
+/* make sure bRawData can hold two bytes without requiring additional allocation */ +C_ASSERT(offsetof(RAWINPUT, data.hid.bRawData[2]) < sizeof(RAWINPUT));
- NTSTATUS WINAPI PNP_AddDevice(DRIVER_OBJECT *driver, DEVICE_OBJECT *PDO) { WCHAR device_id[MAX_DEVICE_ID_LEN], instance_id[MAX_DEVICE_ID_LEN];
@@ -79,6 +83,8 @@ NTSTATUS WINAPI PNP_AddDevice(DRIVER_OBJECT *driver, DEVICE_OBJECT *PDO) BASE_DEVICE_EXTENSION *ext = NULL; HID_DESCRIPTOR descriptor; BYTE *reportDescriptor;
RAWINPUT rawinput;
INPUT input; INT i;
if ((status = get_device_id(PDO, BusQueryDeviceID, device_id)))
@@ -187,6 +193,21 @@ NTSTATUS WINAPI PNP_AddDevice(DRIVER_OBJECT *driver, DEVICE_OBJECT *PDO)
HID_StartDeviceThread(device);
- rawinput.header.dwType = RIM_TYPEHID;
- rawinput.header.dwSize = offsetof(RAWINPUT, data.hid.bRawData[2]);
- rawinput.header.hDevice = ULongToHandle(ext->rawinput_handle);
- rawinput.header.wParam = GIDC_ARRIVAL;
- rawinput.data.hid.dwCount = 1;
- rawinput.data.hid.dwSizeHid = 2;
- rawinput.data.hid.bRawData[0] = ext->preparseData->caps.UsagePage;
- rawinput.data.hid.bRawData[1] = ext->preparseData->caps.Usage;
- input.type = INPUT_HARDWARE;
- input.u.hi.uMsg = WM_INPUT_DEVICE_CHANGE;
- input.u.hi.wParamH = (WORD)(rawinput.header.dwSize >> 16);
- input.u.hi.wParamL = (WORD)(rawinput.header.dwSize >> 0);
- __wine_send_input(0, &input, &rawinput);
}return STATUS_SUCCESS;
@@ -194,6 +215,21 @@ static NTSTATUS remove_device(minidriver *minidriver, DEVICE_OBJECT *device, IRP { BASE_DEVICE_EXTENSION *ext = device->DeviceExtension; NTSTATUS rc = STATUS_NOT_SUPPORTED;
RAWINPUT rawinput;
INPUT input;
rawinput.header.dwType = RIM_TYPEHID;
rawinput.header.dwSize = offsetof(RAWINPUT, data.hid.bRawData[0]);
rawinput.header.hDevice = ULongToHandle(ext->rawinput_handle);
rawinput.header.wParam = GIDC_REMOVAL;
rawinput.data.hid.dwCount = 0;
rawinput.data.hid.dwSizeHid = 0;
input.type = INPUT_HARDWARE;
input.u.hi.uMsg = WM_INPUT_DEVICE_CHANGE;
input.u.hi.wParamH = (WORD)(rawinput.header.dwSize >> 16);
input.u.hi.wParamL = (WORD)(rawinput.header.dwSize >> 0);
__wine_send_input(0, &input, &rawinput);
rc = IoSetDeviceInterfaceState(&ext->link_name, FALSE); if (rc)
This last patch is wrong in the sense that UsagePage and Usage are actually words.
However, if the first patches are fine I would rather avoid re-sending the whole thing as PATCH 3 causes a very long Wine rebuild. Or is there anything else to change there too?
On Fri, Apr 09, 2021 at 01:11:35PM +0200, Rémi Bernon wrote:
diff --git a/dlls/hidclass.sys/Makefile.in b/dlls/hidclass.sys/Makefile.in index be4af747853..2f9f30f8bef 100644 --- a/dlls/hidclass.sys/Makefile.in +++ b/dlls/hidclass.sys/Makefile.in @@ -187,6 +193,21 @@ NTSTATUS WINAPI PNP_AddDevice(DRIVER_OBJECT *driver, DEVICE_OBJECT *PDO)
HID_StartDeviceThread(device);
- rawinput.header.dwType = RIM_TYPEHID;
- rawinput.header.dwSize = offsetof(RAWINPUT, data.hid.bRawData[2]);
- rawinput.header.hDevice = ULongToHandle(ext->rawinput_handle);
- rawinput.header.wParam = GIDC_ARRIVAL;
- rawinput.data.hid.dwCount = 1;
- rawinput.data.hid.dwSizeHid = 2;
- rawinput.data.hid.bRawData[0] = ext->preparseData->caps.UsagePage;
- rawinput.data.hid.bRawData[1] = ext->preparseData->caps.Usage;
UsagePage and Usage are 16 bits each. See USB Device Class Definition for Human Interface Devices section 5.5 on page 17.
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=88509
Your paranoid android.
=== w7u_2qxl (32 bit report) ===
user32: input.c:756: Test failed: 0 (a4/0): 00 from 00 -> 80 unexpected input.c:756: Test failed: 0 (a4/0): 41 from 01 -> 00 unexpected
=== w7u_el (32 bit report) ===
user32: input.c:4293: Test failed: SendInput triggered unexpected message 0xc042
=== wvistau64 (64 bit report) ===
user32: input.c:756: Test failed: 0 (a4/0): 00 from 00 -> 80 unexpected input.c:756: Test failed: 0 (a4/0): 01 from 01 -> 00 unexpected input.c:756: Test failed: 0 (a4/0): 11 from 01 -> 00 unexpected input.c:756: Test failed: 0 (a4/0): a2 from 01 -> 00 unexpected
=== w10pro64_he (64 bit report) ===
user32: input.c:1362: Test failed: Wrong new pos: (103,103) input.c:1292: Test failed: GetCursorPos: (99,100)
=== w10pro64_zh_CN (64 bit report) ===
user32: input.c:3286: Test failed: expected WM_NCHITTEST message input.c:3287: Test failed: expected WM_RBUTTONDOWN message input.c:3288: Test failed: expected WM_RBUTTONUP message input.c:3317: Test failed: expected WM_LBUTTONDOWN message input.c:3318: Test failed: expected WM_LBUTTONUP message input.c:3371: Test failed: expected loop with WM_NCHITTEST messages input.c:3424: Test failed: expected WM_LBUTTONDOWN message input.c:3425: Test failed: expected WM_LBUTTONUP message input.c:1302: Test failed: Wrong set pos: (99,100) input.c:1322: Test failed: GetCursorPos: (99,100)
=== debiant2 (32 bit WoW report) ===
user32: win.c:10096: Test failed: Expected foreground window 0, got 00E10102 win.c:10102: Test failed: Expected foreground window 000E013E, got 00E10102