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 ---
Supersedes: 201324-201326
In this series we use __wine_send_input to send HID device notifications by adding a RAWINPUT structure parameter to it.
The RAWINPUT structure is used in an unorthodox way here, to send the notification data, as it's not supposed to carry WM_INPUT_DEVICE_CHANGE message data in general but we would have to introduce custom structure instead otherwise.
After this series the INPUT data from the notification is already sent up to wineserver, but it is then dropped as winedevice.exe is not associated with any desktop. In later patches I intend to send the RAWINPUT data too, and implement specific processing to translate this message to the proper message sequence.
In further patches, we will use the same mechanism to send HID reports, this time properly using the RAWINPUT data to carry them, and dispatch WM_INPUT messages accordingly.
Ultimately, this RAWINPUT parameter and INPUT_HARDWARE type can also be used to send mouse and keyboard rawinput messages, replacing the custom flags that are used in the implementation currently in wine-staging.
dlls/user32/input.c | 18 ++++++ dlls/user32/tests/input.c | 122 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 140 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..f48807a27a0 100644 --- a/dlls/user32/tests/input.c +++ b/dlls/user32/tests/input.c @@ -4212,6 +4212,127 @@ 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) ); +#ifdef _WIN64 + todo_wine + ok( res == 0 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "SendInput returned %u, error %#x\n", res, GetLastError() ); +#else + ok( res == 16 && GetLastError() == 0xdeadbeef, "SendInput returned %u, error %#x\n", res, GetLastError() ); +#endif + 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) ); +#ifdef _WIN64 + todo_wine ok( res == 0 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "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(); +#else + 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); + ok( !!res, "SendInput did not trigger any message\n" ); + todo_wine ok( msg.message == WM_KEYDOWN, "SendInput triggered unexpected message %#x\n", msg.message ); + while ((res = wait_for_message(&msg)) && msg.message == WM_TIMER) DispatchMessageA(&msg); + ok( !!res, "SendInput did not trigger any message\n" ); + todo_wine ok( msg.message == WM_KEYUP, "SendInput triggered unexpected message %#x\n", msg.message ); + empty_message_queue(); +#endif + + 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 +4355,7 @@ START_TEST(input) return; }
+ test_SendInput(); test_Input_blackbox(); test_Input_whitebox(); test_Input_unicode();