From 65b09537b34fc5b153057a37996c40b8b4f5d8ee Mon Sep 17 00:00:00 2001 From: Piotr Caban Date: Tue, 14 Oct 2014 13:28:12 +0200 Subject: [PATCH] user32/tests: Add mouse SendInput tests. --- dlls/user32/tests/input.c | 253 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 253 insertions(+) diff --git a/dlls/user32/tests/input.c b/dlls/user32/tests/input.c index 8f24a4c6f43..e60ee275596 100644 --- a/dlls/user32/tests/input.c +++ b/dlls/user32/tests/input.c @@ -1643,6 +1643,258 @@ static void test_key_names(void) ok( bufferW[0] == 0xcccc, "wrong string %s\n", wine_dbgstr_w(bufferW) ); } +static void simulate_click(BOOL left, int x, int y) +{ + INPUT input[2]; + UINT events_no; + + SetCursorPos(x, y); + memset(input, 0, sizeof(input)); + input[0].type = INPUT_MOUSE; + U(input[0]).mi.dx = x; + U(input[0]).mi.dy = y; + U(input[0]).mi.dwFlags = left ? MOUSEEVENTF_LEFTDOWN : MOUSEEVENTF_RIGHTDOWN; + input[1].type = INPUT_MOUSE; + U(input[1]).mi.dx = x; + U(input[1]).mi.dy = y; + U(input[1]).mi.dwFlags = left ? MOUSEEVENTF_LEFTUP : MOUSEEVENTF_RIGHTUP; + events_no = SendInput(2, input, sizeof(input[0])); + ok(events_no == 2, "SendInput returned %d\n", events_no); +} + +static BOOL wait_for_message( MSG *msg ) +{ + BOOL ret; + + for (;;) + { + ret = PeekMessageA(msg, 0, 0, 0, PM_REMOVE); + if (ret) + { + if (msg->message == WM_PAINT) DispatchMessageA(msg); + else break; + } + else if (MsgWaitForMultipleObjects(0, NULL, FALSE, 100, QS_ALLINPUT) == WAIT_TIMEOUT) break; + } + if (!ret) msg->message = 0; + return ret; +} + +static BOOL wait_for_event(HANDLE event, int timeout) +{ + DWORD end_time = GetTickCount() + timeout; + MSG msg; + + do { + if(MsgWaitForMultipleObjects(1, &event, FALSE, timeout, QS_ALLINPUT) == WAIT_OBJECT_0) + return TRUE; + while(PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) + DispatchMessageA(&msg); + timeout = end_time - GetTickCount(); + }while(timeout > 0); + + return FALSE; +} + +static WNDPROC def_static_proc; +static DWORD hittest_no; +static LRESULT WINAPI static_hook_proc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) +{ + if (msg == WM_NCHITTEST) + { + /* break infinite hittest loop */ + if(hittest_no > 50) return HTCLIENT; + hittest_no++; + } + + return def_static_proc(hwnd, msg, wp, lp); +} + +struct thread_data +{ + HANDLE start_event; + HANDLE end_event; + HWND win; +}; + +static DWORD WINAPI create_static_win(void *arg) +{ + struct thread_data *thread_data = arg; + HWND win; + + win = CreateWindowA("static", "static", WS_VISIBLE | WS_POPUP, + 100, 100, 100, 100, 0, NULL, NULL, NULL); + ok(win != 0, "CreateWindow failed\n"); + def_static_proc = (void*)SetWindowLongPtrA(win, + GWLP_WNDPROC, (LONG_PTR)static_hook_proc); + thread_data->win = win; + + SetEvent(thread_data->start_event); + wait_for_event(thread_data->end_event, 5000); + return 0; +} + +static void test_Input_mouse(void) +{ + BOOL got_button_down, got_button_up; + HWND hwnd, button_win, static_win; + struct thread_data thread_data; + HANDLE thread; + DWORD thread_id; + POINT pt; + MSG msg; + + button_win = CreateWindowA("button", "button", WS_VISIBLE | WS_POPUP, + 100, 100, 100, 100, 0, NULL, NULL, NULL); + ok(button_win != 0, "CreateWindow failed\n"); + + pt.x = pt.y = 150; + hwnd = WindowFromPoint(pt); + if (hwnd != button_win) + { + skip("there's another window covering test window\n"); + DestroyWindow(button_win); + return; + } + + /* simple button click test */ + simulate_click(TRUE, 150, 150); + got_button_down = got_button_up = FALSE; + while (wait_for_message(&msg)) + { + DispatchMessageA(&msg); + + if (msg.message == WM_LBUTTONDOWN) + { + got_button_down = TRUE; + } + else if (msg.message == WM_LBUTTONUP) + { + got_button_up = TRUE; + break; + } + } + ok(got_button_down, "expected WM_LBUTTONDOWN message\n"); + ok(got_button_up, "expected WM_LBUTTONUP message\n"); + + /* click through HTTRANSPARENT child window */ + static_win = CreateWindowA("static", "static", WS_VISIBLE | WS_CHILD, + 0, 0, 100, 100, button_win, NULL, NULL, NULL); + ok(static_win != 0, "CreateWindow failed\n"); + def_static_proc = (void*)SetWindowLongPtrA(static_win, + GWLP_WNDPROC, (LONG_PTR)static_hook_proc); + simulate_click(FALSE, 150, 150); + hittest_no = 0; + got_button_down = got_button_up = FALSE; + while (wait_for_message(&msg)) + { + DispatchMessageA(&msg); + + if (msg.message == WM_RBUTTONDOWN) + { + ok(msg.hwnd == button_win, "msg.hwnd = %p\n", msg.hwnd); + got_button_down = TRUE; + } + else if (msg.message == WM_RBUTTONUP) + { + ok(msg.hwnd == button_win, "msg.hwnd = %p\n", msg.hwnd); + got_button_up = TRUE; + break; + } + } + ok(hittest_no && hittest_no<50, "expected WM_NCHITTEST message\n"); + todo_wine ok(got_button_down, "expected WM_RBUTTONDOWN message\n"); + todo_wine ok(got_button_up, "expected WM_RBUTTONUP message\n"); + DestroyWindow(static_win); + + /* click through HTTRANSPARENT top-level window */ + static_win = CreateWindowA("static", "static", WS_VISIBLE | WS_POPUP, + 100, 100, 100, 100, 0, NULL, NULL, NULL); + ok(static_win != 0, "CreateWindow failed\n"); + def_static_proc = (void*)SetWindowLongPtrA(static_win, + GWLP_WNDPROC, (LONG_PTR)static_hook_proc); + simulate_click(TRUE, 150, 150); + hittest_no = 0; + got_button_down = got_button_up = FALSE; + while (wait_for_message(&msg)) + { + DispatchMessageA(&msg); + + if (msg.message == WM_LBUTTONDOWN) + { + ok(msg.hwnd == button_win, "msg.hwnd = %p\n", msg.hwnd); + got_button_down = TRUE; + } + else if (msg.message == WM_LBUTTONUP) + { + ok(msg.hwnd == button_win, "msg.hwnd = %p\n", msg.hwnd); + got_button_up = TRUE; + break; + } + } + ok(hittest_no && hittest_no<50, "expected WM_NCHITTEST message\n"); + todo_wine ok(got_button_down, "expected WM_LBUTTONDOWN message\n"); + todo_wine ok(got_button_up, "expected WM_LBUTTONUP message\n"); + DestroyWindow(static_win); + + /* click on HTTRANSPARENT top-level window that belongs to other thread */ + thread_data.start_event = CreateEventA(NULL, FALSE, FALSE, NULL); + ok(thread_data.start_event != NULL, "CreateEvent failed\n"); + thread_data.end_event = CreateEventA(NULL, FALSE, FALSE, NULL); + ok(thread_data.end_event != NULL, "CreateEvent failed\n"); + thread = CreateThread(NULL, 0, create_static_win, &thread_data, 0, NULL); + ok(thread != NULL, "CreateThread failed\n"); + hittest_no = 0; + got_button_down = got_button_up = FALSE; + WaitForSingleObject(thread_data.start_event, INFINITE); + simulate_click(FALSE, 150, 150); + while (wait_for_message(&msg)) + { + DispatchMessageA(&msg); + + if (msg.message == WM_RBUTTONDOWN) + got_button_down = TRUE; + else if (msg.message == WM_RBUTTONUP) + got_button_up = TRUE; + } + SetEvent(thread_data.end_event); + WaitForSingleObject(thread, INFINITE); + ok(hittest_no && hittest_no<50, "expected WM_NCHITTEST message\n"); + ok(!got_button_down, "unexpected WM_RBUTTONDOWN message\n"); + ok(!got_button_up, "unexpected WM_RBUTTONUP message\n"); + + /* click on HTTRANSPARENT top-level window that belongs to ther thread, + * threads input queues are attached */ + thread = CreateThread(NULL, 0, create_static_win, &thread_data, 0, &thread_id); + ok(thread != NULL, "CreateThread failed\n"); + hittest_no = 0; + got_button_down = got_button_up = FALSE; + WaitForSingleObject(thread_data.start_event, INFINITE); + ok(AttachThreadInput(thread_id, GetCurrentThreadId(), TRUE), + "AttachThreadInput failed\n"); + while (wait_for_message(&msg)) DispatchMessageA(&msg); + SetWindowPos(thread_data.win, button_win, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE); + simulate_click(TRUE, 150, 150); + while (wait_for_message(&msg)) + { + DispatchMessageA(&msg); + + if (msg.message == WM_LBUTTONDOWN) + got_button_down = TRUE; + else if (msg.message == WM_LBUTTONUP) + got_button_up = TRUE; + } + SetEvent(thread_data.end_event); + WaitForSingleObject(thread, INFINITE); + todo_wine ok(hittest_no > 50, "expected loop with WM_NCHITTEST messages\n"); + ok(!got_button_down, "unexpected WM_LBUTTONDOWN message\n"); + ok(!got_button_up, "unexpected WM_LBUTTONUP message\n"); + + CloseHandle(thread_data.start_event); + CloseHandle(thread_data.end_event); + DestroyWindow(button_win); +} + START_TEST(input) { init_function_pointers(); @@ -1652,6 +1904,7 @@ START_TEST(input) test_Input_blackbox(); test_Input_whitebox(); test_Input_unicode(); + test_Input_mouse(); } else win_skip("SendInput is not available\n"); -- 2.11.4.GIT