Signed-off-by: Rémi Bernon rbernon@codeweavers.com ---
v2: Fix WoW64 and 32bit test results, a bit or rewrite of PATCH 3 to use of the INPUT_WINE flag as implicit way to inform of injected messages.
Supersedes: 201308-201310
dlls/user32/input.c | 18 +++++++++++ dlls/user32/tests/input.c | 63 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+)
diff --git a/dlls/user32/input.c b/dlls/user32/input.c index e06f8b4413e..e9a74f177b9 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 9d75daa0bd5..7e8829ce375 100644 --- a/dlls/user32/tests/input.c +++ b/dlls/user32/tests/input.c @@ -4118,6 +4118,68 @@ 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; + + 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(); + + trace("done\n"); + DestroyWindow(hwnd); +} + START_TEST(input) { char **argv; @@ -4140,6 +4202,7 @@ START_TEST(input) return; }
+ test_SendInput(); test_Input_blackbox(); test_Input_whitebox(); test_Input_unicode();
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/user32/input.c | 22 ++++++++++++++++------ dlls/user32/tests/input.c | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 6 deletions(-)
diff --git a/dlls/user32/input.c b/dlls/user32/input.c index e9a74f177b9..03d853d2f48 100644 --- a/dlls/user32/input.c +++ b/dlls/user32/input.c @@ -179,8 +179,9 @@ static void update_mouse_coords( INPUT *input ) */ UINT WINAPI SendInput( UINT count, LPINPUT inputs, int size ) { + NTSTATUS status = STATUS_SUCCESS; + INPUT tmp; UINT i; - NTSTATUS status;
if (size != sizeof(INPUT)) { @@ -202,14 +203,23 @@ UINT WINAPI SendInput( UINT count, LPINPUT inputs, int size )
for (i = 0; i < count; i++) { - if (inputs[i].type == INPUT_MOUSE) + memcpy( &tmp, (char *)inputs + i * size, size ); + + switch (tmp.type) { + case INPUT_MOUSE: /* we need to update the coordinates to what the server expects */ - INPUT input = inputs[i]; - update_mouse_coords( &input ); - status = send_hardware_message( 0, &input, SEND_HWMSG_INJECTED ); + update_mouse_coords( &tmp ); + /* fallthrough */ + case INPUT_KEYBOARD: + status = send_hardware_message( 0, &tmp, SEND_HWMSG_INJECTED ); + break; +#ifdef _WIN64 + case INPUT_HARDWARE: + SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); + return 0; +#endif } - 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 7e8829ce375..f4193c66653 100644 --- a/dlls/user32/tests/input.c +++ b/dlls/user32/tests/input.c @@ -4123,6 +4123,7 @@ 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"); @@ -4176,6 +4177,38 @@ static void test_SendInput(void) 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()); + SetLastError(0xdeadbeef); + res = SendInput(16, input, sizeof(*input)); +#ifdef _WIN64 + 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 (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE)) ok(0, "SendInput triggered unexpected message %#x\n", msg.message); + + memset(input, 0, sizeof(input)); + input[0].type = INPUT_HARDWARE; + input[1].type = INPUT_KEYBOARD; + SetLastError(0xdeadbeef); + res = SendInput(16, input, sizeof(*input)); +#ifdef _WIN64 + ok(res == 0 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "SendInput returned %u, error %#x\n", res, GetLastError()); + while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE)) ok(0, "SendInput triggered unexpected message %#x\n", msg.message); +#else + ok(res == 16 && GetLastError() == 0xdeadbeef, "SendInput returned %u, error %#x\n", res, GetLastError()); + while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE)) ok(msg.message == WM_KEYDOWN, "SendInput triggered unexpected message %#x\n", msg.message); +#endif + + for (i = 0; i < ARRAY_SIZE(input); ++i) input[i].type = INPUT_HARDWARE + 1; + SetLastError(0xdeadbeef); + res = SendInput(16, input, sizeof(*input)); + ok(res == 16 && GetLastError() == 0xdeadbeef, "SendInput returned %u, error %#x\n", res, GetLastError()); + while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE)) ok(0, "SendInput triggered unexpected message %#x\n", msg.message); + trace("done\n"); DestroyWindow(hwnd); }
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=86721
Your paranoid android.
=== w7u_2qxl (32 bit report) ===
user32: input.c:756: Test failed: 0 (a4/0): 00 from 00 -> 80 unexpected
=== 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
=== debiant2 (32 bit report) ===
user32: win.c:3079: Test succeeded inside todo block: Focus should be on child 000800FE, not 000800FE
=== debiant2 (32 bit Chinese:China report) ===
user32: win.c:3079: Test succeeded inside todo block: Focus should be on child 000800FE, not 000800FE
=== debiant2 (32 bit WoW report) ===
user32: win.c:3079: Test succeeded inside todo block: Focus should be on child 000800FE, not 000800FE
=== debiant2 (64 bit WoW report) ===
user32: clipboard.c:833: Test failed: 1: gle 5 clipboard.c:838: Test failed: 1.0: got 0000 instead of 0007 clipboard.c:868: Test failed: 1: gle 1418 clipboard.c:717: Test failed: 2: gle 5 clipboard.c:719: Test failed: 2: gle 1418 clipboard.c:746: Test failed: 2: count 4 clipboard.c:749: Test failed: 2: gle 1418 clipboard.c:760: Test failed: 2: gle 5 clipboard.c:765: Test failed: 2.0: got 0000 instead of 000d clipboard.c:805: Test failed: 2: gle 1418 clipboard.c:815: Test failed: 2: count 4 clipboard.c:818: Test failed: 2: gle 1418 clipboard.c:833: Test failed: 2: gle 5 clipboard.c:838: Test failed: 2.0: got 0000 instead of 000d clipboard.c:868: Test failed: 2: gle 1418 clipboard.c:717: Test failed: 3: gle 5 clipboard.c:719: Test failed: 3: gle 1418 clipboard.c:746: Test failed: 3: count 5 clipboard.c:749: Test failed: 3: gle 1418 clipboard.c:755: Test failed: 3: 0003 not available clipboard.c:757: Test failed: 3: count 5 instead of 2 clipboard.c:760: Test failed: 3: gle 5 clipboard.c:765: Test failed: 3.0: got 0000 instead of 000e clipboard.c:805: Test failed: 3: gle 1418 clipboard.c:815: Test failed: 3: count 5 clipboard.c:818: Test failed: 3: gle 1418 clipboard.c:826: Test failed: 3: 0003 not available clipboard.c:828: Test failed: 3: count 5 instead of 2 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 clipboard.c:717: Test failed: 4: gle 5 clipboard.c:719: Test failed: 4: gle 1418 clipboard.c:746: Test failed: 4: count 6 clipboard.c:749: Test failed: 4: gle 1418 clipboard.c:757: Test failed: 4: count 6 instead of 2 clipboard.c:760: Test failed: 4: gle 5 clipboard.c:765: Test failed: 4.0: got 0000 instead of 0003 clipboard.c:805: Test failed: 4: gle 1418 clipboard.c:815: Test failed: 4: count 6 clipboard.c:818: Test failed: 4: gle 1418 clipboard.c:828: Test failed: 4: count 6 instead of 2 clipboard.c:833: Test failed: 4: gle 5 clipboard.c:838: Test failed: 4.0: got 0000 instead of 0003 clipboard.c:868: Test failed: 4: gle 1418 clipboard.c:717: Test failed: 5: gle 5 clipboard.c:719: Test failed: 5: gle 1418 clipboard.c:746: Test failed: 5: count 7 clipboard.c:749: Test failed: 5: gle 1418 clipboard.c:755: Test failed: 5: 0008 not available clipboard.c:755: Test failed: 5: 0011 not available clipboard.c:757: Test failed: 5: count 7 instead of 3 clipboard.c:760: Test failed: 5: gle 5 clipboard.c:765: Test failed: 5.0: got 0000 instead of 0002 clipboard.c:805: Test failed: 5: gle 1418 clipboard.c:815: Test failed: 5: count 7 clipboard.c:818: Test failed: 5: gle 1418 clipboard.c:826: Test failed: 5: 0008 not available clipboard.c:826: Test failed: 5: 0011 not available clipboard.c:828: Test failed: 5: count 7 instead of 3 clipboard.c:833: Test failed: 5: gle 5 clipboard.c:838: Test failed: 5.0: got 0000 instead of 0002 clipboard.c:868: Test failed: 5: gle 1418 clipboard.c:717: Test failed: 6: gle 5 clipboard.c:719: Test failed: 6: gle 1418 clipboard.c:746: Test failed: 6: count 8 clipboard.c:749: Test failed: 6: gle 1418 clipboard.c:755: Test failed: 6: 0011 not available clipboard.c:757: Test failed: 6: count 8 instead of 3 clipboard.c:760: Test failed: 6: gle 5 clipboard.c:765: Test failed: 6.0: got 0000 instead of 0008 clipboard.c:805: Test failed: 6: gle 1418 clipboard.c:815: Test failed: 6: count 8 clipboard.c:818: Test failed: 6: gle 1418 clipboard.c:826: Test failed: 6: 0011 not available clipboard.c:828: Test failed: 6: count 8 instead of 3 clipboard.c:833: Test failed: 6: gle 5 clipboard.c:838: Test failed: 6.0: got 0000 instead of 0008 clipboard.c:868: Test failed: 6: gle 1418 clipboard.c:717: Test failed: 7: gle 5 clipboard.c:719: Test failed: 7: gle 1418 clipboard.c:746: Test failed: 7: count 9 clipboard.c:749: Test failed: 7: gle 1418 clipboard.c:757: Test failed: 7: count 9 instead of 3 clipboard.c:760: Test failed: 7: gle 5 clipboard.c:765: Test failed: 7.0: got 0000 instead of 0011 clipboard.c:805: Test failed: 7: gle 1418 clipboard.c:815: Test failed: 7: count 9 clipboard.c:818: Test failed: 7: gle 1418 clipboard.c:828: Test failed: 7: count 9 instead of 3 clipboard.c:833: Test failed: 7: gle 5 clipboard.c:838: Test failed: 7.0: got 0000 instead of 0011 clipboard.c:868: Test failed: 7: gle 1418 clipboard.c:874: Test failed: gle 5 clipboard.c:876: Test failed: gle 1418 clipboard.c:878: Test failed: gle 1418 clipboard.c:1383: Test failed: gle 5 clipboard.c:1385: Test failed: gle 1418 clipboard.c:1388: Test failed: got 00000000 clipboard.c:1389: Test failed: expected moveable mem 00000000 clipboard.c:1391: Test failed: got 00000000 clipboard.c:1392: Test failed: expected moveable mem 00000000 clipboard.c:1395: Test failed: got 00000000 clipboard.c:1396: Test failed: expected bitmap 00000000 clipboard.c:1398: Test failed: got 00000000 clipboard.c:1399: Test failed: expected bitmap 00000000 clipboard.c:1401: Test failed: got 00000000 clipboard.c:1402: Test failed: expected bitmap 00000000 clipboard.c:1404: Test failed: got 00000000 clipboard.c:1405: Test failed: expected palette 00000000 clipboard.c:1407: Test failed: got 00000000 clipboard.c:1408: Test failed: expected moveable mem 00000000 clipboard.c:1410: Test failed: got 00000000 clipboard.c:1411: Test failed: expected moveable mem 00000000 clipboard.c:1425: Test failed: got 00000000 clipboard.c:1426: Test failed: expected fixed mem 00000000 clipboard.c:1428: Test failed: got 00000000 clipboard.c:1429: Test failed: expected fixed mem 00000000 clipboard.c:1431: Test failed: got 00000000 clipboard.c:1432: Test failed: expected moveable mem 00000000 clipboard.c:1444: Test failed: wrong data 00000000 clipboard.c:1445: Test failed: expected moveable mem 00000000 clipboard.c:1448: Test failed: wrong data 00000000, cf 0000c040 clipboard.c:1449: Test failed: expected moveable mem 00000000 clipboard.c:1452: Test failed: wrong data 00000000 clipboard.c:1453: Test failed: expected moveable mem 00000000 clipboard.c:1456: Test failed: wrong data 00000000 clipboard.c:1457: Test failed: expected moveable mem 00000000 clipboard.c:1460: Test failed: wrong data 00000000 clipboard.c:1461: Test failed: expected fixed mem 00000000 clipboard.c:1464: Test failed: wrong data 00000000 clipboard.c:1465: Test failed: expected fixed mem 00000000 clipboard.c:1468: Test failed: wrong data 00000000 clipboard.c:1469: Test failed: expected moveable mem 00000000 clipboard.c:1475: Test failed: got 00000000 clipboard.c:1476: Test failed: expected moveable mem 00000000 clipboard.c:1477: Test failed: expected freed mem 00BB2452 clipboard.c:1480: Test failed: got 00000000 clipboard.c:1481: Test failed: expected fixed mem 00000000 clipboard.c:1486: Test failed: gle 1418 clipboard.c:1549: Test failed: wrong data 00000000 clipboard.c:1552: Test failed: wrong data 00000000, cf 0000c040 clipboard.c:1555: Test failed: wrong data 00000000 clipboard.c:1558: Test failed: wrong data 00000000 clipboard.c:1561: Test failed: wrong data 00000000 clipboard.c:1564: Test failed: wrong data 00000000 clipboard.c:1567: Test failed: wrong data 00000000 clipboard.c:1574: Test failed: expected fixed mem 00000000 clipboard.c:1576: Test failed: expected fixed mem 00000000 clipboard.c:1578: Test failed: expected fixed mem 00000000 clipboard.c:1580: Test failed: expected bitmap 00000000 clipboard.c:1582: Test failed: expected bitmap 00000000 clipboard.c:1584: Test failed: expected palette 00000000 clipboard.c:1586: Test failed: expected fixed mem 00000000 clipboard.c:1588: Test failed: expected fixed mem 00000000 clipboard.c:1600: Test failed: expected freed mem 00BB884A clipboard.c:1601: Test failed: expected freed mem 00BB86A2 clipboard.c:1602: Test failed: expected freed mem 00BB8642 clipboard.c:1603: Test failed: expected freed mem 00BB241A clipboard.c:1604: Test failed: expected freed mem 00BB35A2 win.c:3079: Test succeeded inside todo block: Focus should be on child 000800FE, not 000800FE win.c:10113: Test failed: Expected foreground window 000E013E, got 00000000 win.c:10120: Test failed: Expected foreground window 000E013E, got 00E10102 win.c:10122: Test failed: GetActiveWindow() = 00000000 win.c:10122: Test failed: GetFocus() = 00000000 win.c:10123: Test failed: Received WM_ACTIVATEAPP(1), did not expect it. win.c:10124: Test failed: Received WM_ACTIVATEAPP(0), did not expect it. win.c:10132: Test failed: Expected foreground window 000E013E, got 00000000 win.c:10134: Test failed: GetActiveWindow() = 00000000 win.c:10134: Test failed: GetFocus() = 00000000 win.c:10142: Test failed: Received WM_ACTIVATEAPP(1), did not expect it.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/user32/input.c | 21 +++++++++++++++------ dlls/user32/message.c | 15 ++++++++++++--- dlls/user32/user_private.h | 2 +- include/winuser.h | 10 ++++++++++ 4 files changed, 38 insertions(+), 10 deletions(-)
diff --git a/dlls/user32/input.c b/dlls/user32/input.c index 03d853d2f48..ac276ec1462 100644 --- a/dlls/user32/input.c +++ b/dlls/user32/input.c @@ -121,7 +121,10 @@ BOOL set_capture_window( HWND hwnd, UINT gui_flags, HWND *prev_ret ) */ BOOL CDECL __wine_send_input( HWND hwnd, const INPUT *input ) { - NTSTATUS status = send_hardware_message( hwnd, input, 0 ); + NTSTATUS status; + INPUT tmp = *input; + tmp.type |= INPUT_WINE; + status = send_hardware_message( hwnd, &tmp ); if (status) SetLastError( RtlNtStatusToDosError(status) ); return !status; } @@ -179,11 +182,13 @@ static void update_mouse_coords( INPUT *input ) */ UINT WINAPI SendInput( UINT count, LPINPUT inputs, int size ) { + WINEINPUT tmp; NTSTATUS status = STATUS_SUCCESS; - INPUT tmp; + BOOL internal; UINT i;
- if (size != sizeof(INPUT)) + internal = count && inputs && inputs[0].type & INPUT_WINE; + if (size != (internal ? sizeof(WINEINPUT) : sizeof(INPUT))) { SetLastError( ERROR_INVALID_PARAMETER ); return 0; @@ -204,15 +209,19 @@ UINT WINAPI SendInput( UINT count, LPINPUT inputs, int size ) for (i = 0; i < count; i++) { memcpy( &tmp, (char *)inputs + i * size, size ); + if (!(tmp.input.type & INPUT_WINE)) tmp.hwnd = 0;
- switch (tmp.type) + switch (tmp.input.type) { case INPUT_MOUSE: + case INPUT_MOUSE|INPUT_WINE: /* we need to update the coordinates to what the server expects */ - update_mouse_coords( &tmp ); + update_mouse_coords( &tmp.input ); /* fallthrough */ case INPUT_KEYBOARD: - status = send_hardware_message( 0, &tmp, SEND_HWMSG_INJECTED ); + case INPUT_KEYBOARD|INPUT_WINE: + case INPUT_HARDWARE|INPUT_WINE: + status = send_hardware_message( tmp.hwnd, &tmp.input ); break; #ifdef _WIN64 case INPUT_HARDWARE: diff --git a/dlls/user32/message.c b/dlls/user32/message.c index def59998a52..ec8513a1903 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 ) { struct user_key_state_info *key_state_info = get_user_thread_info()->key_state; struct send_message_info info; @@ -3245,11 +3245,14 @@ NTSTATUS send_hardware_message( HWND hwnd, const INPUT *input, UINT flags ) SERVER_START_REQ( send_hardware_message ) { req->win = wine_server_user_handle( hwnd ); - req->flags = flags; + req->flags = 0; req->input.type = input->type; switch (input->type) { case INPUT_MOUSE: + req->flags = SEND_HWMSG_INJECTED; + /* fallthrough */ + case INPUT_MOUSE|INPUT_WINE: req->input.mouse.x = input->u.mi.dx; req->input.mouse.y = input->u.mi.dy; req->input.mouse.data = input->u.mi.mouseData; @@ -3258,6 +3261,9 @@ NTSTATUS send_hardware_message( HWND hwnd, const INPUT *input, UINT flags ) req->input.mouse.info = input->u.mi.dwExtraInfo; break; case INPUT_KEYBOARD: + req->flags = SEND_HWMSG_INJECTED; + /* fallthrough */ + case INPUT_KEYBOARD|INPUT_WINE: req->input.kbd.vkey = input->u.ki.wVk; req->input.kbd.scan = input->u.ki.wScan; req->input.kbd.flags = input->u.ki.dwFlags; @@ -3265,6 +3271,9 @@ NTSTATUS send_hardware_message( HWND hwnd, const INPUT *input, UINT flags ) req->input.kbd.info = input->u.ki.dwExtraInfo; break; case INPUT_HARDWARE: + req->flags = SEND_HWMSG_INJECTED; + /* fallthrough */ + case INPUT_HARDWARE|INPUT_WINE: req->input.hw.msg = input->u.hi.uMsg; req->input.hw.lparam = MAKELONG( input->u.hi.wParamL, input->u.hi.wParamH ); break; @@ -3287,7 +3296,7 @@ NTSTATUS send_hardware_message( HWND hwnd, const INPUT *input, UINT flags ) key_state_info->time = GetTickCount(); key_state_info->counter = counter; } - if ((flags & SEND_HWMSG_INJECTED) && (prev_x != new_x || prev_y != new_y)) + if (!(input->type & INPUT_WINE) && (prev_x != new_x || prev_y != new_y)) USER_Driver->pSetCursorPos( new_x, new_y ); }
diff --git a/dlls/user32/user_private.h b/dlls/user32/user_private.h index 7761a1ceb4f..2425d14e43b 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 ) 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/include/winuser.h b/include/winuser.h index 53661f6c788..2072f047165 100644 --- a/include/winuser.h +++ b/include/winuser.h @@ -477,6 +477,16 @@ typedef struct tagINPUT } DUMMYUNIONNAME; } INPUT, *PINPUT, *LPINPUT;
+#ifdef __WINESRC__ +/* extension to send hardware input from drivers */ +#define INPUT_WINE 0x80000000 +typedef struct +{ + INPUT input; + HWND hwnd; +} WINEINPUT; +#endif /* __WINESRC__ */ + DECLARE_HANDLE(HRAWINPUT);
typedef struct tagRAWINPUTDEVICELIST
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=86722
Your paranoid android.
=== debiant2 (32 bit report) ===
user32: win.c:3079: Test succeeded inside todo block: Focus should be on child 000800FE, not 000800FE
=== debiant2 (32 bit Chinese:China report) ===
user32: clipboard.c:833: Test failed: 1: gle 5 clipboard.c:838: Test failed: 1.0: got 0000 instead of 0007 clipboard.c:868: Test failed: 1: gle 1418 clipboard.c:717: Test failed: 2: gle 5 clipboard.c:719: Test failed: 2: gle 1418 clipboard.c:746: Test failed: 2: count 4 clipboard.c:749: Test failed: 2: gle 1418 clipboard.c:760: Test failed: 2: gle 5 clipboard.c:765: Test failed: 2.0: got 0000 instead of 000d clipboard.c:805: Test failed: 2: gle 1418 clipboard.c:815: Test failed: 2: count 4 clipboard.c:818: Test failed: 2: gle 1418 clipboard.c:833: Test failed: 2: gle 5 clipboard.c:838: Test failed: 2.0: got 0000 instead of 000d clipboard.c:868: Test failed: 2: gle 1418 clipboard.c:717: Test failed: 3: gle 5 clipboard.c:719: Test failed: 3: gle 1418 clipboard.c:746: Test failed: 3: count 5 clipboard.c:749: Test failed: 3: gle 1418 clipboard.c:755: Test failed: 3: 0003 not available clipboard.c:757: Test failed: 3: count 5 instead of 2 clipboard.c:760: Test failed: 3: gle 5 clipboard.c:765: Test failed: 3.0: got 0000 instead of 000e clipboard.c:805: Test failed: 3: gle 1418 clipboard.c:815: Test failed: 3: count 5 clipboard.c:818: Test failed: 3: gle 1418 clipboard.c:826: Test failed: 3: 0003 not available clipboard.c:828: Test failed: 3: count 5 instead of 2 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 clipboard.c:717: Test failed: 4: gle 5 clipboard.c:719: Test failed: 4: gle 1418 clipboard.c:746: Test failed: 4: count 6 clipboard.c:749: Test failed: 4: gle 1418 clipboard.c:757: Test failed: 4: count 6 instead of 2 clipboard.c:760: Test failed: 4: gle 5 clipboard.c:765: Test failed: 4.0: got 0000 instead of 0003 clipboard.c:805: Test failed: 4: gle 1418 clipboard.c:815: Test failed: 4: count 6 clipboard.c:818: Test failed: 4: gle 1418 clipboard.c:828: Test failed: 4: count 6 instead of 2 clipboard.c:833: Test failed: 4: gle 5 clipboard.c:838: Test failed: 4.0: got 0000 instead of 0003 clipboard.c:868: Test failed: 4: gle 1418 clipboard.c:717: Test failed: 5: gle 5 clipboard.c:719: Test failed: 5: gle 1418 clipboard.c:746: Test failed: 5: count 7 clipboard.c:749: Test failed: 5: gle 1418 clipboard.c:755: Test failed: 5: 0008 not available clipboard.c:755: Test failed: 5: 0011 not available clipboard.c:757: Test failed: 5: count 7 instead of 3 clipboard.c:760: Test failed: 5: gle 5 clipboard.c:765: Test failed: 5.0: got 0000 instead of 0002 clipboard.c:805: Test failed: 5: gle 1418 clipboard.c:815: Test failed: 5: count 7 clipboard.c:818: Test failed: 5: gle 1418 clipboard.c:826: Test failed: 5: 0008 not available clipboard.c:826: Test failed: 5: 0011 not available clipboard.c:828: Test failed: 5: count 7 instead of 3 clipboard.c:833: Test failed: 5: gle 5 clipboard.c:838: Test failed: 5.0: got 0000 instead of 0002 clipboard.c:868: Test failed: 5: gle 1418 clipboard.c:717: Test failed: 6: gle 5 clipboard.c:719: Test failed: 6: gle 1418 clipboard.c:746: Test failed: 6: count 8 clipboard.c:749: Test failed: 6: gle 1418 clipboard.c:755: Test failed: 6: 0011 not available clipboard.c:757: Test failed: 6: count 8 instead of 3 clipboard.c:760: Test failed: 6: gle 5 clipboard.c:765: Test failed: 6.0: got 0000 instead of 0008 clipboard.c:805: Test failed: 6: gle 1418 clipboard.c:815: Test failed: 6: count 8 clipboard.c:818: Test failed: 6: gle 1418 clipboard.c:826: Test failed: 6: 0011 not available clipboard.c:828: Test failed: 6: count 8 instead of 3 clipboard.c:833: Test failed: 6: gle 5 clipboard.c:838: Test failed: 6.0: got 0000 instead of 0008 clipboard.c:868: Test failed: 6: gle 1418 clipboard.c:717: Test failed: 7: gle 5 clipboard.c:719: Test failed: 7: gle 1418 clipboard.c:746: Test failed: 7: count 9 clipboard.c:749: Test failed: 7: gle 1418 clipboard.c:757: Test failed: 7: count 9 instead of 3 clipboard.c:760: Test failed: 7: gle 5 clipboard.c:765: Test failed: 7.0: got 0000 instead of 0011 clipboard.c:805: Test failed: 7: gle 1418 clipboard.c:815: Test failed: 7: count 9 clipboard.c:818: Test failed: 7: gle 1418 clipboard.c:828: Test failed: 7: count 9 instead of 3 clipboard.c:833: Test failed: 7: gle 5 clipboard.c:838: Test failed: 7.0: got 0000 instead of 0011 clipboard.c:868: Test failed: 7: gle 1418 clipboard.c:874: Test failed: gle 5 clipboard.c:876: Test failed: gle 1418 clipboard.c:878: Test failed: gle 1418 clipboard.c:1383: Test failed: gle 5 clipboard.c:1385: Test failed: gle 1418 clipboard.c:1388: Test failed: got 00000000 clipboard.c:1389: Test failed: expected moveable mem 00000000 clipboard.c:1391: Test failed: got 00000000 clipboard.c:1392: Test failed: expected moveable mem 00000000 clipboard.c:1395: Test failed: got 00000000 clipboard.c:1396: Test failed: expected bitmap 00000000 clipboard.c:1398: Test failed: got 00000000 clipboard.c:1399: Test failed: expected bitmap 00000000 clipboard.c:1401: Test failed: got 00000000 clipboard.c:1402: Test failed: expected bitmap 00000000 clipboard.c:1404: Test failed: got 00000000 clipboard.c:1405: Test failed: expected palette 00000000 clipboard.c:1407: Test failed: got 00000000 clipboard.c:1408: Test failed: expected moveable mem 00000000 clipboard.c:1410: Test failed: got 00000000 clipboard.c:1411: Test failed: expected moveable mem 00000000 clipboard.c:1425: Test failed: got 00000000 clipboard.c:1426: Test failed: expected fixed mem 00000000 clipboard.c:1428: Test failed: got 00000000 clipboard.c:1429: Test failed: expected fixed mem 00000000 clipboard.c:1431: Test failed: got 00000000 clipboard.c:1432: Test failed: expected moveable mem 00000000 clipboard.c:1444: Test failed: wrong data 00000000 clipboard.c:1445: Test failed: expected moveable mem 00000000 clipboard.c:1448: Test failed: wrong data 00000000, cf 0000c040 clipboard.c:1449: Test failed: expected moveable mem 00000000 clipboard.c:1452: Test failed: wrong data 00000000 clipboard.c:1453: Test failed: expected moveable mem 00000000 clipboard.c:1456: Test failed: wrong data 00000000 clipboard.c:1457: Test failed: expected moveable mem 00000000 clipboard.c:1460: Test failed: wrong data 00000000 clipboard.c:1461: Test failed: expected fixed mem 00000000 clipboard.c:1464: Test failed: wrong data 00000000 clipboard.c:1465: Test failed: expected fixed mem 00000000 clipboard.c:1468: Test failed: wrong data 00000000 clipboard.c:1469: Test failed: expected moveable mem 00000000 clipboard.c:1475: Test failed: got 00000000 clipboard.c:1476: Test failed: expected moveable mem 00000000 clipboard.c:1477: Test failed: expected freed mem 00BD875A clipboard.c:1480: Test failed: got 00000000 clipboard.c:1481: Test failed: expected fixed mem 00000000 clipboard.c:1486: Test failed: gle 1418 clipboard.c:1549: Test failed: wrong data 00000000 clipboard.c:1552: Test failed: wrong data 00000000, cf 0000c040 clipboard.c:1555: Test failed: wrong data 00000000 clipboard.c:1558: Test failed: wrong data 00000000 clipboard.c:1561: Test failed: wrong data 00000000 clipboard.c:1564: Test failed: wrong data 00000000 clipboard.c:1567: Test failed: wrong data 00000000 clipboard.c:1574: Test failed: expected fixed mem 00000000 clipboard.c:1576: Test failed: expected fixed mem 00000000 clipboard.c:1578: Test failed: expected fixed mem 00000000 clipboard.c:1580: Test failed: expected bitmap 00000000 clipboard.c:1582: Test failed: expected bitmap 00000000 clipboard.c:1584: Test failed: expected palette 00000000 clipboard.c:1586: Test failed: expected fixed mem 00000000 clipboard.c:1588: Test failed: expected fixed mem 00000000 clipboard.c:1600: Test failed: expected freed mem 00BCFE22 clipboard.c:1601: Test failed: expected freed mem 00BD0272 clipboard.c:1602: Test failed: expected freed mem 00BD02AA clipboard.c:1603: Test failed: expected freed mem 00BCFF62 clipboard.c:1604: Test failed: expected freed mem 00BD88D2 win.c:3079: Test succeeded inside todo block: Focus should be on child 000800FE, not 000800FE
=== debiant2 (32 bit WoW report) ===
user32: win.c:3079: Test succeeded inside todo block: Focus should be on child 000800FE, not 000800FE
=== debiant2 (64 bit WoW report) ===
user32: win.c:3079: Test succeeded inside todo block: Focus should be on child 000800FE, not 000800FE
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=86720
Your paranoid android.
=== w7u_2qxl (32 bit report) ===
user32: input.c:756: Test failed: 0 (a4/0): 00 from 00 -> 80 unexpected
=== 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
=== debiant2 (32 bit report) ===
user32: win.c:3079: Test succeeded inside todo block: Focus should be on child 000800FE, not 000800FE
=== debiant2 (32 bit Chinese:China report) ===
user32: win.c:3079: Test succeeded inside todo block: Focus should be on child 000800FE, not 000800FE
=== debiant2 (32 bit WoW report) ===
user32: win.c:3079: Test succeeded inside todo block: Focus should be on child 000800FE, not 000800FE
=== debiant2 (64 bit WoW report) ===
user32: win.c:3079: Test succeeded inside todo block: Focus should be on child 000800FE, not 000800FE
On 3/9/21 7:39 PM, Rémi Bernon wrote:
Signed-off-by: Rémi Bernon rbernon@codeweavers.com
v2: Fix WoW64 and 32bit test results, a bit or rewrite of PATCH 3 to use of the INPUT_WINE flag as implicit way to inform of injected messages.
Supersedes: 201308-201310
dlls/user32/input.c | 18 +++++++++++ dlls/user32/tests/input.c | 63 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+)
diff --git a/dlls/user32/input.c b/dlls/user32/input.c index e06f8b4413e..e9a74f177b9 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 9d75daa0bd5..7e8829ce375 100644 --- a/dlls/user32/tests/input.c +++ b/dlls/user32/tests/input.c @@ -4118,6 +4118,68 @@ 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;
- 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();
- trace("done\n");
- DestroyWindow(hwnd);
+}
- START_TEST(input) { char **argv;
@@ -4140,6 +4202,7 @@ START_TEST(input) return; }
- test_SendInput(); test_Input_blackbox(); test_Input_whitebox(); test_Input_unicode();
So, should I keep the custom __wine_send_input entry point and extend it to accept a dynamically sized structure instead?
On 3/15/21 7:26 PM, Rémi Bernon wrote:
On 3/9/21 7:39 PM, Rémi Bernon wrote:
Signed-off-by: Rémi Bernon rbernon@codeweavers.com
v2: Fix WoW64 and 32bit test results, a bit or rewrite of PATCH 3 to use of the INPUT_WINE flag as implicit way to inform of injected messages.
Supersedes: 201308-201310
dlls/user32/input.c | 18 +++++++++++ dlls/user32/tests/input.c | 63 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+)
diff --git a/dlls/user32/input.c b/dlls/user32/input.c index e06f8b4413e..e9a74f177b9 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 9d75daa0bd5..7e8829ce375 100644 --- a/dlls/user32/tests/input.c +++ b/dlls/user32/tests/input.c @@ -4118,6 +4118,68 @@ 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;
+ 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();
+ trace("done\n"); + DestroyWindow(hwnd); +}
START_TEST(input) { char **argv; @@ -4140,6 +4202,7 @@ START_TEST(input) return; } + test_SendInput(); test_Input_blackbox(); test_Input_whitebox(); test_Input_unicode();
So, should I keep the custom __wine_send_input entry point and extend it to accept a dynamically sized structure instead?
I'm not completely sure what is wrong here, but it I understand it's not liked very much. I can see that patch 3 has an issue where we probably shouldn't call update_mouse_coords for internal messages.
Anyway it should be possible to send HID reports without this and, I think, only using the current and public Win32 structures. My current plan is the following, and although I haven't implemented it fully yet I think it could work:
- Use __wine_send_input to send all HID input, using an INPUT structure, with INPUT_HARDWARE type and WM_INPUT / WM_INPUT_DEVICE_CHANGE uMsg.
- For WM_INPUT message, it'd be difficult to pass a HRAWINPUT handle as wParamL/H as afaics there's no way to convert a RAWINPUT struct or pointer to a 32bit handle.
- For WM_INPUT_DEVICE_CHANGE, we could use the lparam as the device index, as it's supposed to be, but we would then still miss the usage page / usage field.
- So, in both cases, this INPUT will instead be implicitly followed in memory with a RAWINPUT structure, that send_hardware_message will expect for these internal / INPUT_HARDWARE / uMsg combination, and the INPUT wParamL/H would be used as a size information (for instance).
- The RAWINPUT structure will be dynamically sized and hold the HID report as well. In the WM_INPUT_DEVICE_CHANGE case, when a device is added, the report will be the device descriptor report, which will provide the device usage (page) bytes.
- Because other WM_INPUT reports won't have the device usage (page) bytes anymore, we will instead have to keep the list of known rawinput devices on the wineserver side, with their associated rawinput device index, and match the hDevice field of the RAWINPUT structures to figure their usage (page) and find interested processes.
Is that a better plan?
In all cases, I think the first two patches here are still useful to check that we can use INPUT_HARDWARE type for internal use (and disallow it for external use).
Cheers,