[USER32_APITEST] -Move the helper functions in the common include directory
[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 #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 }