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 HWND hWnd1, hWnd2, hWnd3; 11 HHOOK hMouseHookLL, hMouseHook; 12 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 MSG_ENTRY mousemove2_chain[]={{0, WH_MOUSE_LL, HOOK, WM_MOUSEMOVE}, 168 {2, WM_NCHITTEST}, 169 {2, WH_MOUSE,HOOK, WM_MOUSEMOVE, HTCLIENT}, 170 {2, WM_SETCURSOR}, 171 {1, WM_SETCURSOR}, 172 {2, WM_MOUSEMOVE, POST}, 173 {0,0}}; 174 175 /* the mouse hovers hwnd2 */ 176 MSG_ENTRY mousehover2_chain[]={{0, WH_MOUSE_LL, HOOK, WM_MOUSEMOVE}, 177 {2, WM_NCHITTEST}, 178 {2, WH_MOUSE,HOOK, WM_MOUSEMOVE, HTCLIENT}, 179 {2, WM_SETCURSOR}, 180 {1, WM_SETCURSOR}, 181 {2, WM_MOUSEMOVE, POST}, 182 {2, WM_SYSTIMER, POST, ID_TME_TIMER}, 183 {2, WM_MOUSEHOVER, POST}, 184 {0,0}}; 185 186 /* the mouse leaves hwnd2 and moves to hwnd1 */ 187 MSG_ENTRY mouseleave2to1_chain[]={{0, WH_MOUSE_LL, HOOK, WM_MOUSEMOVE}, 188 {1, WM_NCHITTEST}, 189 {1, WH_MOUSE,HOOK, WM_MOUSEMOVE, HTCLIENT}, 190 {1, WM_SETCURSOR}, 191 {1, WM_MOUSEMOVE, POST}, 192 {2, WM_MOUSELEAVE, POST}, 193 {0,0}}; 194 195 /* the mouse leaves hwnd2 and moves to hwnd3 */ 196 MSG_ENTRY mouseleave2to3_chain[]={{0, WH_MOUSE_LL, HOOK, WM_MOUSEMOVE}, 197 {3, WM_NCHITTEST}, 198 {3, WH_MOUSE,HOOK, WM_MOUSEMOVE, HTCLIENT}, 199 {3, WM_SETCURSOR}, 200 {1, WM_SETCURSOR}, 201 {3, WM_MOUSEMOVE, POST}, 202 {2, WM_MOUSELEAVE, POST}, 203 {0,0}}; 204 205 /* the mouse hovers hwnd3 */ 206 MSG_ENTRY mousehover3_chain[]={{0, WH_MOUSE_LL, HOOK, WM_MOUSEMOVE}, 207 {3, WM_NCHITTEST}, 208 {3, WH_MOUSE,HOOK, WM_MOUSEMOVE, HTCLIENT}, 209 {3, WM_SETCURSOR}, 210 {1, WM_SETCURSOR}, 211 {3, WM_MOUSEMOVE, POST}, 212 {3, WM_SYSTIMER, POST, ID_TME_TIMER}, 213 {3, WM_MOUSEHOVER, POST}, 214 {0,0}}; 215 216 /* the mouse hovers hwnd3 without moving */ 217 MSG_ENTRY mousehover3_nomove_chain[]={{3, WM_SYSTIMER, POST, ID_TME_TIMER}, 218 {3, WM_MOUSEHOVER, POST}, 219 {0,0}}; 220 221 /* the mouse hovers hwnd3 and the timer is not dispatched */ 222 MSG_ENTRY mousehover3_droptimer_chain[]={{0, WH_MOUSE_LL, HOOK, WM_MOUSEMOVE}, 223 {3, WM_NCHITTEST}, 224 {3, WH_MOUSE,HOOK, WM_MOUSEMOVE, HTCLIENT}, 225 {3, WM_SETCURSOR}, 226 {1, WM_SETCURSOR}, 227 {3, WM_MOUSEMOVE, POST}, 228 {3, WM_SYSTIMER, POST, ID_TME_TIMER}, 229 {0,0}}; 230 231 /* the mouse hovers hwnd3 and mouse message is dropped by WH_MOUSE */ 232 MSG_ENTRY mousehover3_dropmouse_chain[]={{0, WH_MOUSE_LL, HOOK, WM_MOUSEMOVE}, 233 {3, WM_NCHITTEST}, 234 {3, WH_MOUSE,HOOK, WM_MOUSEMOVE, HTCLIENT}, 235 {3, WM_SYSTIMER, POST, ID_TME_TIMER}, 236 {3, WM_MOUSEHOVER, POST}, 237 {0,0}}; 238 239 /* the mouse hovers hwnd3 and mouse message is dropped by WH_MOUSE_LL */ 240 MSG_ENTRY mousehover3_dropmousell_chain[]={{0, WH_MOUSE_LL, HOOK, WM_MOUSEMOVE}, 241 {3, WM_SYSTIMER, POST, ID_TME_TIMER}, 242 {3, WM_MOUSEHOVER, POST}, 243 {0,0}}; 244 245 /* the mouse leaves hwnd3 and moves to hwnd2 and mouse message is dropped by WH_MOUSE */ 246 MSG_ENTRY mouseleave3to2_dropmouse_chain[]={{0, WH_MOUSE_LL, HOOK, WM_MOUSEMOVE}, 247 {2, WM_NCHITTEST}, 248 {2, WH_MOUSE,HOOK, WM_MOUSEMOVE, HTCLIENT}, 249 {0,0}}; 250 251 /* the mouse leaves hwnd3 and moves to hwnd2 and mouse message is dropped by WH_MOUSE_LL */ 252 MSG_ENTRY mouseleave3to2_dropmousell_chain[]={{0, WH_MOUSE_LL, HOOK, WM_MOUSEMOVE}, 253 {0,0}}; 254 255 /* after WH_MOUSE drops WM_MOUSEMOVE, WM_MOUSELEAVE is still in the queue */ 256 MSG_ENTRY mouseleave3_remainging_chain[]={{3, WM_MOUSELEAVE, POST}, 257 {0,0}}; 258 259 void Test_TrackMouseEvent() 260 { 261 MOVE_CURSOR(0,0); 262 create_test_windows(); 263 FlushMessages(); 264 EMPTY_CACHE(); 265 266 /* the mouse moves over hwnd2 */ 267 MOVE_CURSOR(220,220); 268 FlushMessages(); 269 COMPARE_CACHE(mousemove2_chain); 270 EXPECT_TME_FLAGS(hWnd2, 0); 271 272 /* Begin tracking mouse events for hWnd2 */ 273 TmeStartTracking(hWnd2, TME_HOVER|TME_LEAVE); 274 EXPECT_TME_FLAGS(hWnd2, TME_HOVER|TME_LEAVE); 275 FlushMessages(); 276 COMPARE_CACHE(empty_chain); 277 278 /* the mouse hovers hwnd2 */ 279 MOVE_CURSOR(221, 221); 280 Sleep(100); 281 EXPECT_TME_FLAGS(hWnd2, TME_HOVER|TME_LEAVE); 282 FLUSH_MESSAGES(QS_TIMER|QS_MOUSEMOVE, 0); 283 EXPECT_TME_FLAGS(hWnd2, TME_LEAVE); 284 COMPARE_CACHE(mousehover2_chain); 285 286 /* the mouse leaves hwnd2 and moves to hwnd1 */ 287 MOVE_CURSOR(150, 150); 288 EXPECT_TME_FLAGS(hWnd2, TME_LEAVE); 289 FLUSH_MESSAGES(QS_MOUSEMOVE,QS_TIMER ); 290 EXPECT_TME_FLAGS(hWnd2, 0); 291 COMPARE_CACHE(mouseleave2to1_chain); 292 293 FlushMessages(); 294 COMPARE_CACHE(empty_chain); 295 296 /* the mouse moves over hwnd2 */ 297 MOVE_CURSOR(220,220); 298 FLUSH_MESSAGES(QS_MOUSEMOVE, QS_TIMER); 299 COMPARE_CACHE(mousemove2_chain); 300 EXPECT_TME_FLAGS(hWnd2, 0); 301 302 FlushMessages(); 303 COMPARE_CACHE(empty_chain); 304 305 /* Begin tracking mouse events for hWnd2 */ 306 TmeStartTracking(hWnd2, TME_HOVER|TME_LEAVE); 307 TmeStartTracking(hWnd2, TME_HOVER|TME_LEAVE); 308 TmeStartTracking(hWnd2, TME_HOVER|TME_LEAVE); 309 TmeStartTracking(hWnd2, TME_HOVER|TME_LEAVE); 310 FLUSH_MESSAGES(0, QS_TIMER|QS_MOUSEMOVE); 311 COMPARE_CACHE(empty_chain); 312 EXPECT_TME_FLAGS(hWnd2, TME_HOVER|TME_LEAVE); 313 314 /* the mouse moves from hwnd2 to the intersection of hwnd2 and hwnd3 */ 315 MOVE_CURSOR(300,300); 316 FLUSH_MESSAGES(QS_MOUSEMOVE, QS_TIMER); 317 EXPECT_TME_FLAGS(hWnd2, TME_HOVER|TME_LEAVE); 318 COMPARE_CACHE(mousemove2_chain); 319 320 FlushMessages(); 321 COMPARE_CACHE(empty_chain); 322 323 /* the mouse moves from hwnd2 to hwnd3 */ 324 MOVE_CURSOR(400,400); 325 FLUSH_MESSAGES(QS_MOUSEMOVE, QS_TIMER); 326 EXPECT_TME_FLAGS(hWnd2, 0); 327 COMPARE_CACHE(mouseleave2to3_chain); 328 329 FlushMessages(); 330 COMPARE_CACHE(empty_chain); 331 332 /* Begin tracking mouse events for hWnd3 */ 333 TmeStartTracking(hWnd3, TME_HOVER|TME_LEAVE); 334 FLUSH_MESSAGES(0, QS_TIMER|QS_MOUSEMOVE); 335 COMPARE_CACHE(empty_chain); 336 EXPECT_TME_FLAGS(hWnd2, TME_HOVER|TME_LEAVE); 337 338 /* the mouse hovers hwnd3 */ 339 MOVE_CURSOR(401,401); 340 Sleep(100); 341 EXPECT_TME_FLAGS(hWnd3, TME_HOVER|TME_LEAVE); 342 FLUSH_MESSAGES(QS_TIMER|QS_MOUSEMOVE, 0); 343 EXPECT_TME_FLAGS(hWnd3, TME_LEAVE); 344 COMPARE_CACHE(mousehover3_chain); 345 346 FlushMessages(); 347 COMPARE_CACHE(empty_chain); 348 349 /* Begin tracking mouse events for hWnd3 */ 350 TmeStartTracking(hWnd3, TME_HOVER ); 351 FLUSH_MESSAGES(0, QS_TIMER|QS_MOUSEMOVE); 352 COMPARE_CACHE(empty_chain); 353 EXPECT_TME_FLAGS(hWnd3, TME_HOVER|TME_LEAVE); 354 355 /* make sure that the timer will fire before the mouse moves */ 356 Sleep(100); 357 FlushMessages(); 358 COMPARE_CACHE(mousehover3_nomove_chain); 359 EXPECT_TME_FLAGS(hWnd3, TME_LEAVE); 360 361 Sleep(100); 362 FlushMessages(); 363 COMPARE_CACHE(empty_chain); 364 365 /* the mouse hovers hwnd3 and the timer is not dispatched*/ 366 TmeStartTracking(hWnd3, TME_HOVER ); 367 ignore_timer = TRUE; 368 MOVE_CURSOR(400,400); 369 Sleep(100); 370 EXPECT_TME_FLAGS(hWnd3, TME_HOVER|TME_LEAVE); 371 FLUSH_MESSAGES(QS_TIMER|QS_MOUSEMOVE, 0); /* the loop drops WM_SYSTIMER */ 372 EXPECT_TME_FLAGS(hWnd3, TME_HOVER|TME_LEAVE); /* TME_HOVER is still active */ 373 COMPARE_CACHE(mousehover3_droptimer_chain); /* we get no WM_MOUSEHOVER */ 374 ignore_timer = FALSE; 375 376 /* the mouse hovers hwnd3 and mouse message is dropped by WH_MOUSE_LL */ 377 ignore_mousell = TRUE; 378 MOVE_CURSOR(402,402); 379 Sleep(100); 380 EXPECT_TME_FLAGS(hWnd3, TME_HOVER|TME_LEAVE); 381 FLUSH_MESSAGES(QS_TIMER, QS_MOUSEMOVE); /* WH_MOUSE_LL drops WM_MOUSEMOVE */ 382 EXPECT_TME_FLAGS(hWnd3, TME_LEAVE); 383 COMPARE_CACHE(mousehover3_dropmousell_chain); /* we get WM_MOUSEHOVER normaly */ 384 ignore_mousell = FALSE; 385 386 FlushMessages(); 387 COMPARE_CACHE(empty_chain); 388 389 /* the mouse hovers hwnd3 and mouse message is dropped by WH_MOUSE */ 390 ignore_mouse = TRUE; 391 TmeStartTracking(hWnd3, TME_HOVER ); 392 MOVE_CURSOR(401,401); 393 Sleep(100); 394 EXPECT_TME_FLAGS(hWnd3, TME_HOVER|TME_LEAVE); 395 FLUSH_MESSAGES(QS_TIMER|QS_MOUSEMOVE, 0); /* WH_MOUSE drops WM_MOUSEMOVE */ 396 EXPECT_TME_FLAGS(hWnd3, TME_LEAVE); 397 COMPARE_CACHE(mousehover3_dropmouse_chain); /* we get WM_MOUSEHOVER normaly */ 398 ignore_mouse = FALSE; 399 400 FlushMessages(); 401 COMPARE_CACHE(empty_chain); 402 403 /* the mouse leaves hwnd3 and moves to hwnd2 and mouse message is dropped by WH_MOUSE_LL */ 404 ignore_mousell = TRUE; 405 TmeStartTracking(hWnd3, TME_LEAVE ); 406 MOVE_CURSOR(220,220); 407 FLUSH_MESSAGES(0, QS_MOUSEMOVE|QS_TIMER); /* WH_MOUSE drops WM_MOUSEMOVE */ 408 EXPECT_TME_FLAGS(hWnd3, TME_LEAVE); /* all flags are removed */ 409 COMPARE_CACHE(mouseleave3to2_dropmousell_chain); /* we get no WM_MOUSELEAVE */ 410 ignore_mousell = 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 */ 416 ignore_mouse = TRUE; 417 MOVE_CURSOR(220,220); 418 FLUSH_MESSAGES(QS_MOUSEMOVE, QS_TIMER); /* WH_MOUSE drops WM_MOUSEMOVE */ 419 EXPECT_TME_FLAGS(hWnd3, 0); /* all flags are removed */ 420 COMPARE_CACHE(mouseleave3to2_dropmouse_chain); /* we get no WM_MOUSELEAVE */ 421 ignore_mouse = FALSE; 422 423 /* after WH_MOUSE drops WM_MOUSEMOVE, WM_MOUSELEAVE is still in the queue */ 424 FLUSH_MESSAGES(QS_POSTMESSAGE, QS_TIMER|QS_MOUSEMOVE); 425 COMPARE_CACHE(mouseleave3_remainging_chain); 426 427 FlushMessages(); 428 COMPARE_CACHE(empty_chain); 429 430 destroy_test_window(); 431 } 432 433 START_TEST(TrackMouseEvent) 434 { 435 Test_TrackMouseEvent(); 436 } 437