1 /* 2 * PROJECT: ReactOS api tests 3 * LICENSE: GPL - See COPYING in the top level directory 4 * PURPOSE: Test for TrackMouseEvent 5 * PROGRAMMERS: Giannis Adamopoulos 6 */ 7 8 #include <apitest.h> 9 #include <wingdi.h> 10 #include <winuser.h> 11 #include <undocuser.h> 12 13 #include <msgtrace.h> 14 #include <user32testhelpers.h> 15 16 HWND hWnd1, hWnd2, hWnd3; 17 HHOOK hMouseHookLL, hMouseHook; 18 int ignore_timer = 0, ignore_mouse = 0, ignore_mousell = 0; 19 20 static int get_iwnd(HWND hWnd) 21 { 22 if(hWnd == hWnd1) return 1; 23 else if(hWnd == hWnd2) return 2; 24 else if(hWnd == hWnd3) return 3; 25 else return 0; 26 } 27 28 LRESULT CALLBACK TmeTestProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 29 { 30 int iwnd = get_iwnd(hWnd); 31 32 if(message == WM_PAINT) 33 { 34 PAINTSTRUCT ps; 35 BeginPaint(hWnd, &ps); 36 Rectangle(ps.hdc, ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right, ps.rcPaint.bottom); 37 EndPaint(hWnd, &ps); 38 } 39 40 if(message > WM_USER || !iwnd || IsDWmMsg(message) || IseKeyMsg(message)) 41 return DefWindowProc(hWnd, message, wParam, lParam); 42 43 switch(message) 44 { 45 case WM_IME_SETCONTEXT: 46 case WM_IME_NOTIFY : 47 case WM_GETICON : 48 case WM_GETTEXT: 49 break; 50 case WM_SYSTIMER: 51 ok(0, "Got unexpected WM_SYSTIMER in the winproc. wParam=%d\n", wParam); 52 break; 53 default: 54 RECORD_MESSAGE(iwnd, message, SENT, 0,0); 55 } 56 return DefWindowProc(hWnd, message, wParam, lParam); 57 } 58 59 static LRESULT CALLBACK MouseLLHookProc(int nCode, WPARAM wParam, LPARAM lParam) 60 { 61 LRESULT ret; 62 RECORD_MESSAGE(0, WH_MOUSE_LL, HOOK, wParam, 0); 63 ret = CallNextHookEx(hMouseHookLL, nCode, wParam, lParam); 64 if(ignore_mousell) 65 return TRUE; 66 return ret; 67 } 68 69 static LRESULT CALLBACK MouseHookProc(int nCode, WPARAM wParam, LPARAM lParam) 70 { 71 MOUSEHOOKSTRUCT *hs = (MOUSEHOOKSTRUCT*) lParam; 72 LRESULT ret; 73 RECORD_MESSAGE(get_iwnd(hs->hwnd), WH_MOUSE, HOOK, wParam, hs->wHitTestCode); 74 ret = CallNextHookEx(hMouseHook, nCode, wParam, lParam); 75 if(ignore_mouse) 76 return TRUE; 77 return ret; 78 } 79 80 static void FlushMessages() 81 { 82 MSG msg; 83 84 while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) 85 { 86 int iwnd = get_iwnd(msg.hwnd); 87 if(iwnd) 88 { 89 if(msg.message == WM_SYSTIMER) 90 { 91 RECORD_MESSAGE(iwnd, msg.message, POST,msg.wParam,0); 92 if(ignore_timer) 93 continue; 94 } 95 else if(!(msg.message > WM_USER || !iwnd || IsDWmMsg(msg.message) || IseKeyMsg(msg.message))) 96 RECORD_MESSAGE(iwnd, msg.message, POST,0,0); 97 } 98 DispatchMessageA( &msg ); 99 } 100 } 101 102 #define FLUSH_MESSAGES(expected, notexpected) \ 103 { EXPECT_QUEUE_STATUS(expected, notexpected);\ 104 FlushMessages();\ 105 } 106 107 static void create_test_windows() 108 { 109 hMouseHookLL = SetWindowsHookExW(WH_MOUSE_LL, MouseLLHookProc, GetModuleHandleW( NULL ), 0); 110 hMouseHook = SetWindowsHookExW(WH_MOUSE, MouseHookProc, GetModuleHandleW( NULL ), GetCurrentThreadId()); 111 ok(hMouseHook!=NULL,"failed to set hook\n"); 112 ok(hMouseHookLL!=NULL,"failed to set hook\n"); 113 114 RegisterSimpleClass(TmeTestProc, L"testClass"); 115 116 hWnd1 = CreateWindowW(L"testClass", L"test", WS_OVERLAPPEDWINDOW, 117 100, 100, 500, 500, NULL, NULL, 0, NULL); 118 hWnd2 = CreateWindowW(L"testClass", L"test", WS_CHILD, 119 50, 50, 200, 200, hWnd1, NULL, 0, NULL); 120 hWnd3 = CreateWindowW(L"testClass", L"test", WS_CHILD, 121 150, 150, 200, 200, hWnd1, NULL, 0, NULL); 122 123 ShowWindow(hWnd1, SW_SHOW); 124 UpdateWindow(hWnd1); 125 ShowWindow(hWnd2, SW_SHOW); 126 UpdateWindow(hWnd2); 127 ShowWindow(hWnd3, SW_SHOWNORMAL); 128 UpdateWindow(hWnd3); 129 //SetWindowPos (hWnd3, HWND_TOP, 0,0,0,0, SWP_NOMOVE|SWP_NOREDRAW); 130 } 131 132 static void destroy_test_window() 133 { 134 DestroyWindow(hWnd1); 135 UnregisterClassW(L"testClass", 0); 136 UnhookWindowsHookEx(hMouseHookLL); 137 UnhookWindowsHookEx(hMouseHook); 138 } 139 140 static void TmeStartTracking(HWND hwnd, DWORD Flags) 141 { 142 TRACKMOUSEEVENT tme; 143 tme.cbSize = sizeof(tme); 144 tme.dwFlags = Flags; 145 tme.hwndTrack = hwnd; 146 tme.dwHoverTime = 1; 147 if(!TrackMouseEvent(&tme)) 148 { 149 trace("failed!\n"); 150 } 151 } 152 153 DWORD TmeQuery(HWND hwnd) 154 { 155 TRACKMOUSEEVENT tme; 156 tme.cbSize = sizeof(tme); 157 tme.dwFlags = TME_QUERY|TME_HOVER|TME_LEAVE; 158 tme.hwndTrack = hwnd; 159 TrackMouseEvent(&tme); 160 return tme.dwFlags; 161 } 162 163 #define EXPECT_TME_FLAGS(hWnd, expected) \ 164 { DWORD flags = TmeQuery(hWnd); \ 165 ok(flags == (expected),"wrong tme flags. expected %li, and got %li\n", (DWORD)(expected), flags); \ 166 } 167 168 #define MOVE_CURSOR(x,y) mouse_event(MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE , \ 169 x*(65535/GetSystemMetrics(SM_CXVIRTUALSCREEN)), \ 170 y*(65535/GetSystemMetrics(SM_CYVIRTUALSCREEN)) , 0,0); 171 172 /* the mouse moves over hwnd2 */ 173 MSG_ENTRY mousemove2_chain[]={{0, WH_MOUSE_LL, HOOK, WM_MOUSEMOVE}, 174 {2, WM_NCHITTEST}, 175 {2, WH_MOUSE,HOOK, WM_MOUSEMOVE, HTCLIENT}, 176 {2, WM_SETCURSOR}, 177 {1, WM_SETCURSOR}, 178 {2, WM_MOUSEMOVE, POST}, 179 {0,0}}; 180 181 /* the mouse hovers hwnd2 */ 182 MSG_ENTRY mousehover2_chain[]={{0, WH_MOUSE_LL, HOOK, WM_MOUSEMOVE}, 183 {2, WM_NCHITTEST}, 184 {2, WH_MOUSE,HOOK, WM_MOUSEMOVE, HTCLIENT}, 185 {2, WM_SETCURSOR}, 186 {1, WM_SETCURSOR}, 187 {2, WM_MOUSEMOVE, POST}, 188 {2, WM_SYSTIMER, POST, ID_TME_TIMER}, 189 {2, WM_MOUSEHOVER, POST}, 190 {0,0}}; 191 192 /* the mouse leaves hwnd2 and moves to hwnd1 */ 193 MSG_ENTRY mouseleave2to1_chain[]={{0, WH_MOUSE_LL, HOOK, WM_MOUSEMOVE}, 194 {1, WM_NCHITTEST}, 195 {1, WH_MOUSE,HOOK, WM_MOUSEMOVE, HTCLIENT}, 196 {1, WM_SETCURSOR}, 197 {1, WM_MOUSEMOVE, POST}, 198 {2, WM_MOUSELEAVE, POST}, 199 {0,0}}; 200 201 /* the mouse leaves hwnd2 and moves to hwnd3 */ 202 MSG_ENTRY mouseleave2to3_chain[]={{0, WH_MOUSE_LL, HOOK, WM_MOUSEMOVE}, 203 {3, WM_NCHITTEST}, 204 {3, WH_MOUSE,HOOK, WM_MOUSEMOVE, HTCLIENT}, 205 {3, WM_SETCURSOR}, 206 {1, WM_SETCURSOR}, 207 {3, WM_MOUSEMOVE, POST}, 208 {2, WM_MOUSELEAVE, POST}, 209 {0,0}}; 210 211 /* the mouse hovers hwnd3 */ 212 MSG_ENTRY mousehover3_chain[]={{0, WH_MOUSE_LL, HOOK, WM_MOUSEMOVE}, 213 {3, WM_NCHITTEST}, 214 {3, WH_MOUSE,HOOK, WM_MOUSEMOVE, HTCLIENT}, 215 {3, WM_SETCURSOR}, 216 {1, WM_SETCURSOR}, 217 {3, WM_MOUSEMOVE, POST}, 218 {3, WM_SYSTIMER, POST, ID_TME_TIMER}, 219 {3, WM_MOUSEHOVER, POST}, 220 {0,0}}; 221 222 /* the mouse hovers hwnd3 without moving */ 223 MSG_ENTRY mousehover3_nomove_chain[]={{3, WM_SYSTIMER, POST, ID_TME_TIMER}, 224 {3, WM_MOUSEHOVER, POST}, 225 {0,0}}; 226 227 /* the mouse hovers hwnd3 and the timer is not dispatched */ 228 MSG_ENTRY mousehover3_droptimer_chain[]={{0, WH_MOUSE_LL, HOOK, WM_MOUSEMOVE}, 229 {3, WM_NCHITTEST}, 230 {3, WH_MOUSE,HOOK, WM_MOUSEMOVE, HTCLIENT}, 231 {3, WM_SETCURSOR}, 232 {1, WM_SETCURSOR}, 233 {3, WM_MOUSEMOVE, POST}, 234 {3, WM_SYSTIMER, POST, ID_TME_TIMER}, 235 {0,0}}; 236 237 /* the mouse hovers hwnd3 and mouse message is dropped by WH_MOUSE */ 238 MSG_ENTRY mousehover3_dropmouse_chain[]={{0, WH_MOUSE_LL, HOOK, WM_MOUSEMOVE}, 239 {3, WM_NCHITTEST}, 240 {3, WH_MOUSE,HOOK, WM_MOUSEMOVE, HTCLIENT}, 241 {3, WM_SYSTIMER, POST, ID_TME_TIMER}, 242 {3, WM_MOUSEHOVER, POST}, 243 {0,0}}; 244 245 /* the mouse hovers hwnd3 and mouse message is dropped by WH_MOUSE_LL */ 246 MSG_ENTRY mousehover3_dropmousell_chain[]={{0, WH_MOUSE_LL, HOOK, WM_MOUSEMOVE}, 247 {3, WM_SYSTIMER, POST, ID_TME_TIMER}, 248 {3, WM_MOUSEHOVER, POST}, 249 {0,0}}; 250 251 /* the mouse leaves hwnd3 and moves to hwnd2 and mouse message is dropped by WH_MOUSE */ 252 MSG_ENTRY mouseleave3to2_dropmouse_chain[]={{0, WH_MOUSE_LL, HOOK, WM_MOUSEMOVE}, 253 {2, WM_NCHITTEST}, 254 {2, WH_MOUSE,HOOK, WM_MOUSEMOVE, HTCLIENT}, 255 {0,0}}; 256 257 /* the mouse leaves hwnd3 and moves to hwnd2 and mouse message is dropped by WH_MOUSE_LL */ 258 MSG_ENTRY mouseleave3to2_dropmousell_chain[]={{0, WH_MOUSE_LL, HOOK, WM_MOUSEMOVE}, 259 {0,0}}; 260 261 /* after WH_MOUSE drops WM_MOUSEMOVE, WM_MOUSELEAVE is still in the queue */ 262 MSG_ENTRY mouseleave3_remainging_chain[]={{3, WM_MOUSELEAVE, POST}, 263 {0,0}}; 264 265 void Test_TrackMouseEvent() 266 { 267 MOVE_CURSOR(0,0); 268 create_test_windows(); 269 FlushMessages(); 270 EMPTY_CACHE(); 271 272 /* the mouse moves over hwnd2 */ 273 MOVE_CURSOR(220,220); 274 FlushMessages(); 275 COMPARE_CACHE(mousemove2_chain); 276 EXPECT_TME_FLAGS(hWnd2, 0); 277 278 /* Begin tracking mouse events for hWnd2 */ 279 TmeStartTracking(hWnd2, TME_HOVER|TME_LEAVE); 280 EXPECT_TME_FLAGS(hWnd2, TME_HOVER|TME_LEAVE); 281 FlushMessages(); 282 COMPARE_CACHE(empty_chain); 283 284 /* the mouse hovers hwnd2 */ 285 MOVE_CURSOR(221, 221); 286 Sleep(100); 287 EXPECT_TME_FLAGS(hWnd2, TME_HOVER|TME_LEAVE); 288 FLUSH_MESSAGES(QS_TIMER|QS_MOUSEMOVE, 0); 289 EXPECT_TME_FLAGS(hWnd2, TME_LEAVE); 290 COMPARE_CACHE(mousehover2_chain); 291 292 /* the mouse leaves hwnd2 and moves to hwnd1 */ 293 MOVE_CURSOR(150, 150); 294 EXPECT_TME_FLAGS(hWnd2, TME_LEAVE); 295 FLUSH_MESSAGES(QS_MOUSEMOVE,QS_TIMER ); 296 EXPECT_TME_FLAGS(hWnd2, 0); 297 COMPARE_CACHE(mouseleave2to1_chain); 298 299 FlushMessages(); 300 COMPARE_CACHE(empty_chain); 301 302 /* the mouse moves over hwnd2 */ 303 MOVE_CURSOR(220,220); 304 FLUSH_MESSAGES(QS_MOUSEMOVE, QS_TIMER); 305 COMPARE_CACHE(mousemove2_chain); 306 EXPECT_TME_FLAGS(hWnd2, 0); 307 308 FlushMessages(); 309 COMPARE_CACHE(empty_chain); 310 311 /* Begin tracking mouse events for hWnd2 */ 312 TmeStartTracking(hWnd2, TME_HOVER|TME_LEAVE); 313 TmeStartTracking(hWnd2, TME_HOVER|TME_LEAVE); 314 TmeStartTracking(hWnd2, TME_HOVER|TME_LEAVE); 315 TmeStartTracking(hWnd2, TME_HOVER|TME_LEAVE); 316 FLUSH_MESSAGES(0, QS_TIMER|QS_MOUSEMOVE); 317 COMPARE_CACHE(empty_chain); 318 EXPECT_TME_FLAGS(hWnd2, TME_HOVER|TME_LEAVE); 319 320 /* the mouse moves from hwnd2 to the intersection of hwnd2 and hwnd3 */ 321 MOVE_CURSOR(300,300); 322 FLUSH_MESSAGES(QS_MOUSEMOVE, QS_TIMER); 323 EXPECT_TME_FLAGS(hWnd2, TME_HOVER|TME_LEAVE); 324 COMPARE_CACHE(mousemove2_chain); 325 326 FlushMessages(); 327 COMPARE_CACHE(empty_chain); 328 329 /* the mouse moves from hwnd2 to hwnd3 */ 330 MOVE_CURSOR(400,400); 331 FLUSH_MESSAGES(QS_MOUSEMOVE, QS_TIMER); 332 EXPECT_TME_FLAGS(hWnd2, 0); 333 COMPARE_CACHE(mouseleave2to3_chain); 334 335 FlushMessages(); 336 COMPARE_CACHE(empty_chain); 337 338 /* Begin tracking mouse events for hWnd3 */ 339 TmeStartTracking(hWnd3, TME_HOVER|TME_LEAVE); 340 FLUSH_MESSAGES(0, QS_TIMER|QS_MOUSEMOVE); 341 COMPARE_CACHE(empty_chain); 342 EXPECT_TME_FLAGS(hWnd2, TME_HOVER|TME_LEAVE); 343 344 /* the mouse hovers hwnd3 */ 345 MOVE_CURSOR(401,401); 346 Sleep(100); 347 EXPECT_TME_FLAGS(hWnd3, TME_HOVER|TME_LEAVE); 348 FLUSH_MESSAGES(QS_TIMER|QS_MOUSEMOVE, 0); 349 EXPECT_TME_FLAGS(hWnd3, TME_LEAVE); 350 COMPARE_CACHE(mousehover3_chain); 351 352 FlushMessages(); 353 COMPARE_CACHE(empty_chain); 354 355 /* Begin tracking mouse events for hWnd3 */ 356 TmeStartTracking(hWnd3, TME_HOVER ); 357 FLUSH_MESSAGES(0, QS_TIMER|QS_MOUSEMOVE); 358 COMPARE_CACHE(empty_chain); 359 EXPECT_TME_FLAGS(hWnd3, TME_HOVER|TME_LEAVE); 360 361 /* make sure that the timer will fire before the mouse moves */ 362 Sleep(100); 363 FlushMessages(); 364 COMPARE_CACHE(mousehover3_nomove_chain); 365 EXPECT_TME_FLAGS(hWnd3, TME_LEAVE); 366 367 Sleep(100); 368 FlushMessages(); 369 COMPARE_CACHE(empty_chain); 370 371 /* the mouse hovers hwnd3 and the timer is not dispatched*/ 372 TmeStartTracking(hWnd3, TME_HOVER ); 373 ignore_timer = TRUE; 374 MOVE_CURSOR(400,400); 375 Sleep(100); 376 EXPECT_TME_FLAGS(hWnd3, TME_HOVER|TME_LEAVE); 377 FLUSH_MESSAGES(QS_TIMER|QS_MOUSEMOVE, 0); /* the loop drops WM_SYSTIMER */ 378 EXPECT_TME_FLAGS(hWnd3, TME_HOVER|TME_LEAVE); /* TME_HOVER is still active */ 379 COMPARE_CACHE(mousehover3_droptimer_chain); /* we get no WM_MOUSEHOVER */ 380 ignore_timer = FALSE; 381 382 /* the mouse hovers hwnd3 and mouse message is dropped by WH_MOUSE_LL */ 383 ignore_mousell = TRUE; 384 MOVE_CURSOR(402,402); 385 Sleep(100); 386 EXPECT_TME_FLAGS(hWnd3, TME_HOVER|TME_LEAVE); 387 FLUSH_MESSAGES(QS_TIMER, QS_MOUSEMOVE); /* WH_MOUSE_LL drops WM_MOUSEMOVE */ 388 EXPECT_TME_FLAGS(hWnd3, TME_LEAVE); 389 COMPARE_CACHE(mousehover3_dropmousell_chain); /* we get WM_MOUSEHOVER normaly */ 390 ignore_mousell = FALSE; 391 392 FlushMessages(); 393 COMPARE_CACHE(empty_chain); 394 395 /* the mouse hovers hwnd3 and mouse message is dropped by WH_MOUSE */ 396 ignore_mouse = TRUE; 397 TmeStartTracking(hWnd3, TME_HOVER ); 398 MOVE_CURSOR(401,401); 399 Sleep(100); 400 EXPECT_TME_FLAGS(hWnd3, TME_HOVER|TME_LEAVE); 401 FLUSH_MESSAGES(QS_TIMER|QS_MOUSEMOVE, 0); /* WH_MOUSE drops WM_MOUSEMOVE */ 402 EXPECT_TME_FLAGS(hWnd3, TME_LEAVE); 403 COMPARE_CACHE(mousehover3_dropmouse_chain); /* we get WM_MOUSEHOVER normaly */ 404 ignore_mouse = FALSE; 405 406 FlushMessages(); 407 COMPARE_CACHE(empty_chain); 408 409 /* the mouse leaves hwnd3 and moves to hwnd2 and mouse message is dropped by WH_MOUSE_LL */ 410 ignore_mousell = TRUE; 411 TmeStartTracking(hWnd3, TME_LEAVE ); 412 MOVE_CURSOR(220,220); 413 FLUSH_MESSAGES(0, QS_MOUSEMOVE|QS_TIMER); /* WH_MOUSE drops WM_MOUSEMOVE */ 414 EXPECT_TME_FLAGS(hWnd3, TME_LEAVE); /* all flags are removed */ 415 COMPARE_CACHE(mouseleave3to2_dropmousell_chain); /* we get no WM_MOUSELEAVE */ 416 ignore_mousell = FALSE; 417 418 FlushMessages(); 419 COMPARE_CACHE(empty_chain); 420 421 /* the mouse leaves hwnd3 and moves to hwnd2 and mouse message is dropped by WH_MOUSE */ 422 ignore_mouse = TRUE; 423 MOVE_CURSOR(220,220); 424 FLUSH_MESSAGES(QS_MOUSEMOVE, QS_TIMER); /* WH_MOUSE drops WM_MOUSEMOVE */ 425 EXPECT_TME_FLAGS(hWnd3, 0); /* all flags are removed */ 426 COMPARE_CACHE(mouseleave3to2_dropmouse_chain); /* we get no WM_MOUSELEAVE */ 427 ignore_mouse = FALSE; 428 429 /* after WH_MOUSE drops WM_MOUSEMOVE, WM_MOUSELEAVE is still in the queue */ 430 FLUSH_MESSAGES(QS_POSTMESSAGE, QS_TIMER|QS_MOUSEMOVE); 431 COMPARE_CACHE(mouseleave3_remainging_chain); 432 433 FlushMessages(); 434 COMPARE_CACHE(empty_chain); 435 436 destroy_test_window(); 437 } 438 439 START_TEST(TrackMouseEvent) 440 { 441 Test_TrackMouseEvent(); 442 } 443