2 * PROJECT: ReactOS api tests
3 * LICENSE: GPL - See COPYING in the top level directory
4 * PURPOSE: Test for TrackMouseEvent
5 * PROGRAMMERS: Giannis Adamopoulos
11 #include <undocuser.h>
14 #include <user32testhelpers.h>
16 HWND hWnd1
, hWnd2
, hWnd3
;
17 HHOOK hMouseHookLL
, hMouseHook
;
18 int ignore_timer
= 0, ignore_mouse
= 0, ignore_mousell
= 0;
20 static int get_iwnd(HWND hWnd
)
22 if(hWnd
== hWnd1
) return 1;
23 else if(hWnd
== hWnd2
) return 2;
24 else if(hWnd
== hWnd3
) return 3;
28 LRESULT CALLBACK
TmeTestProc(HWND hWnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
30 int iwnd
= get_iwnd(hWnd
);
32 if(message
== WM_PAINT
)
35 BeginPaint(hWnd
, &ps
);
36 Rectangle(ps
.hdc
, ps
.rcPaint
.left
, ps
.rcPaint
.top
, ps
.rcPaint
.right
, ps
.rcPaint
.bottom
);
40 if(message
> WM_USER
|| !iwnd
|| IsDWmMsg(message
) || IseKeyMsg(message
))
41 return DefWindowProc(hWnd
, message
, wParam
, lParam
);
45 case WM_IME_SETCONTEXT
:
51 ok(0, "Got unexpected WM_SYSTIMER in the winproc. wParam=%d\n", wParam
);
54 RECORD_MESSAGE(iwnd
, message
, SENT
, 0,0);
56 return DefWindowProc(hWnd
, message
, wParam
, lParam
);
59 static LRESULT CALLBACK
MouseLLHookProc(int nCode
, WPARAM wParam
, LPARAM lParam
)
62 RECORD_MESSAGE(0, WH_MOUSE_LL
, HOOK
, wParam
, 0);
63 ret
= CallNextHookEx(hMouseHookLL
, nCode
, wParam
, lParam
);
69 static LRESULT CALLBACK
MouseHookProc(int nCode
, WPARAM wParam
, LPARAM lParam
)
71 MOUSEHOOKSTRUCT
*hs
= (MOUSEHOOKSTRUCT
*) lParam
;
73 RECORD_MESSAGE(get_iwnd(hs
->hwnd
), WH_MOUSE
, HOOK
, wParam
, hs
->wHitTestCode
);
74 ret
= CallNextHookEx(hMouseHook
, nCode
, wParam
, lParam
);
80 static void FlushMessages()
84 while (PeekMessage( &msg
, 0, 0, 0, PM_REMOVE
))
86 int iwnd
= get_iwnd(msg
.hwnd
);
89 if(msg
.message
== WM_SYSTIMER
)
91 RECORD_MESSAGE(iwnd
, msg
.message
, POST
,msg
.wParam
,0);
95 else if(!(msg
.message
> WM_USER
|| !iwnd
|| IsDWmMsg(msg
.message
) || IseKeyMsg(msg
.message
)))
96 RECORD_MESSAGE(iwnd
, msg
.message
, POST
,0,0);
98 DispatchMessageA( &msg
);
102 #define FLUSH_MESSAGES(expected, notexpected) \
103 { EXPECT_QUEUE_STATUS(expected, notexpected);\
107 static void create_test_windows()
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");
114 RegisterSimpleClass(TmeTestProc
, L
"testClass");
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
);
123 ShowWindow(hWnd1
, SW_SHOW
);
125 ShowWindow(hWnd2
, SW_SHOW
);
127 ShowWindow(hWnd3
, SW_SHOWNORMAL
);
129 //SetWindowPos (hWnd3, HWND_TOP, 0,0,0,0, SWP_NOMOVE|SWP_NOREDRAW);
132 static void destroy_test_window()
134 DestroyWindow(hWnd1
);
135 UnregisterClassW(L
"testClass", 0);
136 UnhookWindowsHookEx(hMouseHookLL
);
137 UnhookWindowsHookEx(hMouseHook
);
140 static void TmeStartTracking(HWND hwnd
, DWORD Flags
)
143 tme
.cbSize
= sizeof(tme
);
145 tme
.hwndTrack
= hwnd
;
147 if(!TrackMouseEvent(&tme
))
153 DWORD
TmeQuery(HWND hwnd
)
156 tme
.cbSize
= sizeof(tme
);
157 tme
.dwFlags
= TME_QUERY
|TME_HOVER
|TME_LEAVE
;
158 tme
.hwndTrack
= hwnd
;
159 TrackMouseEvent(&tme
);
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); \
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);
172 /* the mouse moves over hwnd2 */
173 MSG_ENTRY mousemove2_chain
[]={{0, WH_MOUSE_LL
, HOOK
, WM_MOUSEMOVE
},
175 {2, WH_MOUSE
,HOOK
, WM_MOUSEMOVE
, HTCLIENT
},
178 {2, WM_MOUSEMOVE
, POST
},
181 /* the mouse hovers hwnd2 */
182 MSG_ENTRY mousehover2_chain
[]={{0, WH_MOUSE_LL
, HOOK
, WM_MOUSEMOVE
},
184 {2, WH_MOUSE
,HOOK
, WM_MOUSEMOVE
, HTCLIENT
},
187 {2, WM_MOUSEMOVE
, POST
},
188 {2, WM_SYSTIMER
, POST
, ID_TME_TIMER
},
189 {2, WM_MOUSEHOVER
, POST
},
192 /* the mouse leaves hwnd2 and moves to hwnd1 */
193 MSG_ENTRY mouseleave2to1_chain
[]={{0, WH_MOUSE_LL
, HOOK
, WM_MOUSEMOVE
},
195 {1, WH_MOUSE
,HOOK
, WM_MOUSEMOVE
, HTCLIENT
},
197 {1, WM_MOUSEMOVE
, POST
},
198 {2, WM_MOUSELEAVE
, POST
},
201 /* the mouse leaves hwnd2 and moves to hwnd3 */
202 MSG_ENTRY mouseleave2to3_chain
[]={{0, WH_MOUSE_LL
, HOOK
, WM_MOUSEMOVE
},
204 {3, WH_MOUSE
,HOOK
, WM_MOUSEMOVE
, HTCLIENT
},
207 {3, WM_MOUSEMOVE
, POST
},
208 {2, WM_MOUSELEAVE
, POST
},
211 /* the mouse hovers hwnd3 */
212 MSG_ENTRY mousehover3_chain
[]={{0, WH_MOUSE_LL
, HOOK
, WM_MOUSEMOVE
},
214 {3, WH_MOUSE
,HOOK
, WM_MOUSEMOVE
, HTCLIENT
},
217 {3, WM_MOUSEMOVE
, POST
},
218 {3, WM_SYSTIMER
, POST
, ID_TME_TIMER
},
219 {3, WM_MOUSEHOVER
, POST
},
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
},
227 /* the mouse hovers hwnd3 and the timer is not dispatched */
228 MSG_ENTRY mousehover3_droptimer_chain
[]={{0, WH_MOUSE_LL
, HOOK
, WM_MOUSEMOVE
},
230 {3, WH_MOUSE
,HOOK
, WM_MOUSEMOVE
, HTCLIENT
},
233 {3, WM_MOUSEMOVE
, POST
},
234 {3, WM_SYSTIMER
, POST
, ID_TME_TIMER
},
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
},
240 {3, WH_MOUSE
,HOOK
, WM_MOUSEMOVE
, HTCLIENT
},
241 {3, WM_SYSTIMER
, POST
, ID_TME_TIMER
},
242 {3, WM_MOUSEHOVER
, POST
},
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
},
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
},
254 {2, WH_MOUSE
,HOOK
, WM_MOUSEMOVE
, HTCLIENT
},
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
},
261 /* after WH_MOUSE drops WM_MOUSEMOVE, WM_MOUSELEAVE is still in the queue */
262 MSG_ENTRY mouseleave3_remainging_chain
[]={{3, WM_MOUSELEAVE
, POST
},
265 void Test_TrackMouseEvent()
268 create_test_windows();
272 /* the mouse moves over hwnd2 */
273 MOVE_CURSOR(220,220);
275 COMPARE_CACHE(mousemove2_chain
);
276 EXPECT_TME_FLAGS(hWnd2
, 0);
278 /* Begin tracking mouse events for hWnd2 */
279 TmeStartTracking(hWnd2
, TME_HOVER
|TME_LEAVE
);
280 EXPECT_TME_FLAGS(hWnd2
, TME_HOVER
|TME_LEAVE
);
282 COMPARE_CACHE(empty_chain
);
284 /* the mouse hovers hwnd2 */
285 MOVE_CURSOR(221, 221);
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
);
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
);
300 COMPARE_CACHE(empty_chain
);
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);
309 COMPARE_CACHE(empty_chain
);
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
);
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
);
327 COMPARE_CACHE(empty_chain
);
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
);
336 COMPARE_CACHE(empty_chain
);
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
);
344 /* the mouse hovers hwnd3 */
345 MOVE_CURSOR(401,401);
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
);
353 COMPARE_CACHE(empty_chain
);
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
);
361 /* make sure that the timer will fire before the mouse moves */
364 COMPARE_CACHE(mousehover3_nomove_chain
);
365 EXPECT_TME_FLAGS(hWnd3
, TME_LEAVE
);
369 COMPARE_CACHE(empty_chain
);
371 /* the mouse hovers hwnd3 and the timer is not dispatched*/
372 TmeStartTracking(hWnd3
, TME_HOVER
);
374 MOVE_CURSOR(400,400);
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
;
382 /* the mouse hovers hwnd3 and mouse message is dropped by WH_MOUSE_LL */
383 ignore_mousell
= TRUE
;
384 MOVE_CURSOR(402,402);
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
;
393 COMPARE_CACHE(empty_chain
);
395 /* the mouse hovers hwnd3 and mouse message is dropped by WH_MOUSE */
397 TmeStartTracking(hWnd3
, TME_HOVER
);
398 MOVE_CURSOR(401,401);
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
;
407 COMPARE_CACHE(empty_chain
);
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
;
419 COMPARE_CACHE(empty_chain
);
421 /* the mouse leaves hwnd3 and moves to hwnd2 and mouse message is dropped by WH_MOUSE */
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
;
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
);
434 COMPARE_CACHE(empty_chain
);
436 destroy_test_window();
439 START_TEST(TrackMouseEvent
)
441 Test_TrackMouseEvent();