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
get_iwnd(HWND hWnd)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
TmeTestProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)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
MouseLLHookProc(int nCode,WPARAM wParam,LPARAM lParam)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
MouseHookProc(int nCode,WPARAM wParam,LPARAM lParam)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
FlushMessages()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
create_test_windows()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
destroy_test_window()126 static void destroy_test_window()
127 {
128 DestroyWindow(hWnd1);
129 UnregisterClassW(L"testClass", 0);
130 UnhookWindowsHookEx(hMouseHookLL);
131 UnhookWindowsHookEx(hMouseHook);
132 }
133
TmeStartTracking(HWND hwnd,DWORD Flags)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
TmeQuery(HWND hwnd)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
Test_TrackMouseEvent()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
START_TEST(TrackMouseEvent)445 START_TEST(TrackMouseEvent)
446 {
447 Test_TrackMouseEvent();
448 }
449