[PATCH 1/5] user32/tests: Add more SendInput tests.

Rémi Bernon rbernon at codeweavers.com
Wed Apr 7 08:13:32 CDT 2021


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 at 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();
-- 
2.31.0




More information about the wine-devel mailing list