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