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