* Sync up to trunk head (r65394).
[reactos.git] / win32ss / user / ntuser / mouse.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: Mouse functions
5 * FILE: subsystems/win32/win32k/ntuser/input.c
6 * PROGRAMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 * Rafal Harabien (rafalh@reactos.org)
8 */
9
10 #include <win32k.h>
11 DBG_DEFAULT_CHANNEL(UserInput);
12
13 MOUSEMOVEPOINT gMouseHistoryOfMoves[64];
14 INT gcMouseHistoryOfMoves = 0;
15
16 /*
17 * UserGetMouseButtonsState
18 *
19 * Returns bitfield of MK_* flags used in mouse messages
20 */
21 WORD FASTCALL
22 UserGetMouseButtonsState(VOID)
23 {
24 WORD wRet = 0;
25
26 wRet = IntGetSysCursorInfo()->ButtonsDown;
27
28 if (IS_KEY_DOWN(gafAsyncKeyState, VK_SHIFT)) wRet |= MK_SHIFT;
29 if (IS_KEY_DOWN(gafAsyncKeyState, VK_CONTROL)) wRet |= MK_CONTROL;
30
31 return wRet;
32 }
33
34 /*
35 * UserProcessMouseInput
36 *
37 * Process raw mouse input data
38 */
39 VOID NTAPI
40 UserProcessMouseInput(PMOUSE_INPUT_DATA mid)
41 {
42 MOUSEINPUT mi;
43
44 /* Convert MOUSE_INPUT_DATA to MOUSEINPUT. First init all fields. */
45 mi.dx = mid->LastX;
46 mi.dy = mid->LastY;
47 mi.mouseData = 0;
48 mi.dwFlags = 0;
49 mi.time = 0;
50 mi.dwExtraInfo = mid->ExtraInformation;
51
52 /* Mouse position */
53 if (mi.dx != 0 || mi.dy != 0)
54 mi.dwFlags |= MOUSEEVENTF_MOVE;
55
56 /* Flags for absolute move */
57 if (mid->Flags & MOUSE_MOVE_ABSOLUTE)
58 mi.dwFlags |= MOUSEEVENTF_ABSOLUTE;
59 if (mid->Flags & MOUSE_VIRTUAL_DESKTOP)
60 mi.dwFlags |= MOUSEEVENTF_VIRTUALDESK;
61
62 /* Left button */
63 if (mid->ButtonFlags & MOUSE_LEFT_BUTTON_DOWN)
64 mi.dwFlags |= MOUSEEVENTF_LEFTDOWN;
65 if (mid->ButtonFlags & MOUSE_LEFT_BUTTON_UP)
66 mi.dwFlags |= MOUSEEVENTF_LEFTUP;
67
68 /* Middle button */
69 if (mid->ButtonFlags & MOUSE_MIDDLE_BUTTON_DOWN)
70 mi.dwFlags |= MOUSEEVENTF_MIDDLEDOWN;
71 if (mid->ButtonFlags & MOUSE_MIDDLE_BUTTON_UP)
72 mi.dwFlags |= MOUSEEVENTF_MIDDLEUP;
73
74 /* Right button */
75 if (mid->ButtonFlags & MOUSE_RIGHT_BUTTON_DOWN)
76 mi.dwFlags |= MOUSEEVENTF_RIGHTDOWN;
77 if (mid->ButtonFlags & MOUSE_RIGHT_BUTTON_UP)
78 mi.dwFlags |= MOUSEEVENTF_RIGHTUP;
79
80 /* Note: Next buttons use mouseData field so they cannot be sent in one call */
81
82 /* Button 4 */
83 if (mid->ButtonFlags & MOUSE_BUTTON_4_DOWN)
84 {
85 mi.dwFlags |= MOUSEEVENTF_XDOWN;
86 mi.mouseData |= XBUTTON1;
87 }
88 if (mid->ButtonFlags & MOUSE_BUTTON_4_UP)
89 {
90 mi.dwFlags |= MOUSEEVENTF_XUP;
91 mi.mouseData |= XBUTTON1;
92 }
93
94 /* If mouseData is used by button 4, send input and clear mi */
95 if (mi.dwFlags & (MOUSE_BUTTON_4_DOWN | MOUSE_BUTTON_4_UP))
96 {
97 UserSendMouseInput(&mi, FALSE);
98 RtlZeroMemory(&mi, sizeof(mi));
99 }
100
101 /* Button 5 */
102 if (mid->ButtonFlags & MOUSE_BUTTON_5_DOWN)
103 {
104 mi.mouseData |= XBUTTON2;
105 mi.dwFlags |= MOUSEEVENTF_XDOWN;
106 }
107 if (mid->ButtonFlags & MOUSE_BUTTON_5_UP)
108 {
109 mi.mouseData |= XBUTTON2;
110 mi.dwFlags |= MOUSEEVENTF_XUP;
111 }
112
113 /* If mouseData is used by button 5, send input and clear mi */
114 if (mi.dwFlags & (MOUSE_BUTTON_5_DOWN | MOUSE_BUTTON_5_UP))
115 {
116 UserSendMouseInput(&mi, FALSE);
117 RtlZeroMemory(&mi, sizeof(mi));
118 }
119
120 /* Mouse wheel */
121 if (mid->ButtonFlags & MOUSE_WHEEL)
122 {
123 mi.mouseData = mid->ButtonData;
124 mi.dwFlags |= MOUSEEVENTF_WHEEL;
125 }
126
127 /* If something has changed, send input to user */
128 if (mi.dwFlags)
129 UserSendMouseInput(&mi, FALSE);
130 }
131
132 /*
133 * IntFixMouseInputButtons
134 *
135 * Helper function for supporting mouse button swap function
136 */
137 DWORD
138 IntFixMouseInputButtons(DWORD dwFlags)
139 {
140 DWORD dwNewFlags;
141
142 if (!gspv.bMouseBtnSwap)
143 return dwFlags;
144
145 /* Buttons other than left and right are not affected */
146 dwNewFlags = dwFlags & ~(MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP |
147 MOUSEEVENTF_RIGHTDOWN | MOUSEEVENTF_RIGHTUP);
148
149 /* Swap buttons */
150 if (dwFlags & MOUSEEVENTF_LEFTDOWN)
151 dwNewFlags |= MOUSEEVENTF_RIGHTDOWN;
152 if (dwFlags & MOUSEEVENTF_LEFTUP)
153 dwNewFlags |= MOUSEEVENTF_RIGHTUP;
154 if (dwFlags & MOUSEEVENTF_RIGHTDOWN)
155 dwNewFlags |= MOUSEEVENTF_LEFTDOWN;
156 if (dwFlags & MOUSEEVENTF_RIGHTUP)
157 dwNewFlags |= MOUSEEVENTF_LEFTUP;
158
159 return dwNewFlags;
160 }
161
162 /*
163 * UserSendMouseInput
164 *
165 * Process mouse input from input devices and SendInput API
166 */
167 BOOL NTAPI
168 UserSendMouseInput(MOUSEINPUT *pmi, BOOL bInjected)
169 {
170 POINT ptCursor;
171 PSYSTEM_CURSORINFO pCurInfo;
172 MSG Msg;
173 DWORD dwFlags;
174
175 ASSERT(pmi);
176
177 pCurInfo = IntGetSysCursorInfo();
178 ptCursor = gpsi->ptCursor;
179 dwFlags = IntFixMouseInputButtons(pmi->dwFlags);
180
181 gppiInputProvider = ((PTHREADINFO)PsGetCurrentThreadWin32Thread())->ppi;
182
183 if (pmi->dwFlags & MOUSEEVENTF_MOVE)
184 {
185 /* Mouse has changes position */
186 if (!(pmi->dwFlags & MOUSEEVENTF_ABSOLUTE))
187 {
188 /* Relative move */
189 ptCursor.x += pmi->dx;
190 ptCursor.y += pmi->dy;
191 }
192 else if (pmi->dwFlags & MOUSEEVENTF_VIRTUALDESK)
193 {
194 /* Absolute move in virtual screen units */
195 ptCursor.x = pmi->dx * UserGetSystemMetrics(SM_CXVIRTUALSCREEN) >> 16;
196 ptCursor.y = pmi->dy * UserGetSystemMetrics(SM_CYVIRTUALSCREEN) >> 16;
197 }
198 else
199 {
200 /* Absolute move in primary monitor units */
201 ptCursor.x = pmi->dx * UserGetSystemMetrics(SM_CXSCREEN) >> 16;
202 ptCursor.y = pmi->dy * UserGetSystemMetrics(SM_CYSCREEN) >> 16;
203 }
204 }
205
206 /* Init message fields */
207 Msg.wParam = UserGetMouseButtonsState();
208 Msg.lParam = MAKELPARAM(ptCursor.x, ptCursor.y);
209 Msg.pt = ptCursor;
210 Msg.time = pmi->time;
211 if (!Msg.time)
212 {
213 LARGE_INTEGER LargeTickCount;
214 KeQueryTickCount(&LargeTickCount);
215 Msg.time = MsqCalculateMessageTime(&LargeTickCount);
216 }
217
218 /* Do GetMouseMovePointsEx FIFO. */
219 gMouseHistoryOfMoves[gcMouseHistoryOfMoves].x = ptCursor.x;
220 gMouseHistoryOfMoves[gcMouseHistoryOfMoves].y = ptCursor.y;
221 gMouseHistoryOfMoves[gcMouseHistoryOfMoves].time = Msg.time;
222 gMouseHistoryOfMoves[gcMouseHistoryOfMoves].dwExtraInfo = pmi->dwExtraInfo;
223 if (++gcMouseHistoryOfMoves == ARRAYSIZE(gMouseHistoryOfMoves))
224 gcMouseHistoryOfMoves = 0; // 0 - 63 is 64, FIFO forwards.
225
226 /* Update cursor position */
227 if (dwFlags & MOUSEEVENTF_MOVE)
228 {
229 UserSetCursorPos(ptCursor.x, ptCursor.y, bInjected, pmi->dwExtraInfo, TRUE);
230 }
231
232 /* Left button */
233 if (dwFlags & MOUSEEVENTF_LEFTDOWN)
234 {
235 SET_KEY_DOWN(gafAsyncKeyState, VK_LBUTTON, TRUE);
236 Msg.message = WM_LBUTTONDOWN;
237 pCurInfo->ButtonsDown |= MK_LBUTTON;
238 Msg.wParam |= MK_LBUTTON;
239 co_MsqInsertMouseMessage(&Msg, bInjected, pmi->dwExtraInfo, TRUE);
240 }
241 else if (dwFlags & MOUSEEVENTF_LEFTUP)
242 {
243 SET_KEY_DOWN(gafAsyncKeyState, VK_LBUTTON, FALSE);
244 Msg.message = WM_LBUTTONUP;
245 pCurInfo->ButtonsDown &= ~MK_LBUTTON;
246 Msg.wParam &= ~MK_LBUTTON;
247 co_MsqInsertMouseMessage(&Msg, bInjected, pmi->dwExtraInfo, TRUE);
248 }
249
250 /* Middle button */
251 if (dwFlags & MOUSEEVENTF_MIDDLEDOWN)
252 {
253 SET_KEY_DOWN(gafAsyncKeyState, VK_MBUTTON, TRUE);
254 Msg.message = WM_MBUTTONDOWN;
255 pCurInfo->ButtonsDown |= MK_MBUTTON;
256 Msg.wParam |= MK_MBUTTON;
257 co_MsqInsertMouseMessage(&Msg, bInjected, pmi->dwExtraInfo, TRUE);
258 }
259 else if (dwFlags & MOUSEEVENTF_MIDDLEUP)
260 {
261 SET_KEY_DOWN(gafAsyncKeyState, VK_MBUTTON, FALSE);
262 Msg.message = WM_MBUTTONUP;
263 pCurInfo->ButtonsDown &= ~MK_MBUTTON;
264 Msg.wParam &= ~MK_MBUTTON;
265 co_MsqInsertMouseMessage(&Msg, bInjected, pmi->dwExtraInfo, TRUE);
266 }
267
268 /* Right button */
269 if (dwFlags & MOUSEEVENTF_RIGHTDOWN)
270 {
271 SET_KEY_DOWN(gafAsyncKeyState, VK_RBUTTON, TRUE);
272 Msg.message = WM_RBUTTONDOWN;
273 pCurInfo->ButtonsDown |= MK_RBUTTON;
274 Msg.wParam |= MK_RBUTTON;
275 co_MsqInsertMouseMessage(&Msg, bInjected, pmi->dwExtraInfo, TRUE);
276 }
277 else if (dwFlags & MOUSEEVENTF_RIGHTUP)
278 {
279 SET_KEY_DOWN(gafAsyncKeyState, VK_RBUTTON, FALSE);
280 Msg.message = WM_RBUTTONUP;
281 pCurInfo->ButtonsDown &= ~MK_RBUTTON;
282 Msg.wParam &= ~MK_RBUTTON;
283 co_MsqInsertMouseMessage(&Msg, bInjected, pmi->dwExtraInfo, TRUE);
284 }
285
286 if((dwFlags & (MOUSEEVENTF_XDOWN | MOUSEEVENTF_XUP)) &&
287 (dwFlags & MOUSEEVENTF_WHEEL))
288 {
289 /* Fail because both types of events use the mouseData field */
290 WARN("Invalid flags!\n");
291 return FALSE;
292 }
293
294 /* X-Button (4 or 5) */
295 if (dwFlags & MOUSEEVENTF_XDOWN)
296 {
297 Msg.message = WM_XBUTTONDOWN;
298 if (pmi->mouseData & XBUTTON1)
299 {
300 SET_KEY_DOWN(gafAsyncKeyState, VK_XBUTTON1, TRUE);
301 pCurInfo->ButtonsDown |= MK_XBUTTON1;
302 Msg.wParam |= MAKEWPARAM(MK_XBUTTON1, XBUTTON1);
303 co_MsqInsertMouseMessage(&Msg, bInjected, pmi->dwExtraInfo, TRUE);
304 }
305 if (pmi->mouseData & XBUTTON2)
306 {
307 SET_KEY_DOWN(gafAsyncKeyState, VK_XBUTTON2, TRUE);
308 pCurInfo->ButtonsDown |= MK_XBUTTON2;
309 Msg.wParam |= MAKEWPARAM(MK_XBUTTON2, XBUTTON2);
310 co_MsqInsertMouseMessage(&Msg, bInjected, pmi->dwExtraInfo, TRUE);
311 }
312 }
313 else if (dwFlags & MOUSEEVENTF_XUP)
314 {
315 Msg.message = WM_XBUTTONUP;
316 if(pmi->mouseData & XBUTTON1)
317 {
318 SET_KEY_DOWN(gafAsyncKeyState, VK_XBUTTON1, FALSE);
319 pCurInfo->ButtonsDown &= ~MK_XBUTTON1;
320 Msg.wParam &= ~MK_XBUTTON1;
321 Msg.wParam |= MAKEWPARAM(0, XBUTTON2);
322 co_MsqInsertMouseMessage(&Msg, bInjected, pmi->dwExtraInfo, TRUE);
323 }
324 if (pmi->mouseData & XBUTTON2)
325 {
326 SET_KEY_DOWN(gafAsyncKeyState, VK_XBUTTON2, FALSE);
327 pCurInfo->ButtonsDown &= ~MK_XBUTTON2;
328 Msg.wParam &= ~MK_XBUTTON2;
329 Msg.wParam |= MAKEWPARAM(0, XBUTTON2);
330 co_MsqInsertMouseMessage(&Msg, bInjected, pmi->dwExtraInfo, TRUE);
331 }
332 }
333
334 /* Mouse wheel */
335 if (dwFlags & MOUSEEVENTF_WHEEL)
336 {
337 Msg.message = WM_MOUSEWHEEL;
338 Msg.wParam = MAKEWPARAM(pCurInfo->ButtonsDown, pmi->mouseData);
339 co_MsqInsertMouseMessage(&Msg, bInjected, pmi->dwExtraInfo, TRUE);
340 }
341
342 return TRUE;
343 }
344
345 BOOL
346 FASTCALL
347 IntQueryTrackMouseEvent(
348 LPTRACKMOUSEEVENT lpEventTrack)
349 {
350 PDESKTOP pDesk;
351 PTHREADINFO pti;
352
353 pti = PsGetCurrentThreadWin32Thread();
354 pDesk = pti->rpdesk;
355
356 /* Always cleared with size set and return true. */
357 RtlZeroMemory(lpEventTrack , sizeof(TRACKMOUSEEVENT));
358 lpEventTrack->cbSize = sizeof(TRACKMOUSEEVENT);
359
360 if (pDesk->dwDTFlags & (DF_TME_LEAVE | DF_TME_HOVER) &&
361 pDesk->spwndTrack &&
362 pti->MessageQueue == pDesk->spwndTrack->head.pti->MessageQueue)
363 {
364 if (pDesk->htEx != HTCLIENT)
365 lpEventTrack->dwFlags |= TME_NONCLIENT;
366
367 if (pDesk->dwDTFlags & DF_TME_LEAVE)
368 lpEventTrack->dwFlags |= TME_LEAVE;
369
370 if (pDesk->dwDTFlags & DF_TME_HOVER)
371 {
372 lpEventTrack->dwFlags |= TME_HOVER;
373 lpEventTrack->dwHoverTime = pDesk->dwMouseHoverTime;
374 }
375 lpEventTrack->hwndTrack = UserHMGetHandle(pDesk->spwndTrack);
376 }
377 return TRUE;
378 }
379
380 BOOL
381 FASTCALL
382 IntTrackMouseEvent(
383 LPTRACKMOUSEEVENT lpEventTrack)
384 {
385 PDESKTOP pDesk;
386 PTHREADINFO pti;
387 PWND pWnd;
388 POINT point;
389
390 pti = PsGetCurrentThreadWin32Thread();
391 pDesk = pti->rpdesk;
392
393 if (!(pWnd = UserGetWindowObject(lpEventTrack->hwndTrack)))
394 return FALSE;
395
396 if ( pDesk->spwndTrack != pWnd ||
397 (pDesk->htEx != HTCLIENT) ^ !!(lpEventTrack->dwFlags & TME_NONCLIENT) )
398 {
399 if ( lpEventTrack->dwFlags & TME_LEAVE && !(lpEventTrack->dwFlags & TME_CANCEL) )
400 {
401 UserPostMessage( lpEventTrack->hwndTrack,
402 lpEventTrack->dwFlags & TME_NONCLIENT ? WM_NCMOUSELEAVE : WM_MOUSELEAVE,
403 0, 0);
404 }
405 TRACE("IntTrackMouseEvent spwndTrack %p pwnd %p\n", pDesk->spwndTrack, pWnd);
406 return TRUE;
407 }
408
409 /* Tracking spwndTrack same as pWnd */
410 if (lpEventTrack->dwFlags & TME_CANCEL) // Canceled mode.
411 {
412 if (lpEventTrack->dwFlags & TME_LEAVE)
413 pDesk->dwDTFlags &= ~DF_TME_LEAVE;
414
415 if (lpEventTrack->dwFlags & TME_HOVER)
416 {
417 if (pDesk->dwDTFlags & DF_TME_HOVER)
418 { // Kill hover timer.
419 IntKillTimer(pWnd, ID_EVENT_SYSTIMER_MOUSEHOVER, TRUE);
420 pDesk->dwDTFlags &= ~DF_TME_HOVER;
421 }
422 }
423 }
424 else // Not Canceled.
425 {
426 if (lpEventTrack->dwFlags & TME_LEAVE)
427 pDesk->dwDTFlags |= DF_TME_LEAVE;
428
429 if (lpEventTrack->dwFlags & TME_HOVER)
430 {
431 pDesk->dwDTFlags |= DF_TME_HOVER;
432
433 if (!lpEventTrack->dwHoverTime || lpEventTrack->dwHoverTime == HOVER_DEFAULT)
434 pDesk->dwMouseHoverTime = gspv.iMouseHoverTime; // use the system default hover time-out.
435 else
436 pDesk->dwMouseHoverTime = lpEventTrack->dwHoverTime;
437 // Start timer for the hover period.
438 IntSetTimer(pWnd, ID_EVENT_SYSTIMER_MOUSEHOVER, pDesk->dwMouseHoverTime, SystemTimerProc, TMRF_SYSTEM);
439 // Get windows thread message points.
440 point = pWnd->head.pti->ptLast;
441 // Set desktop mouse hover from the system default hover rectangle.
442 RECTL_vSetRect(&pDesk->rcMouseHover,
443 point.x - gspv.iMouseHoverWidth / 2,
444 point.y - gspv.iMouseHoverHeight / 2,
445 point.x + gspv.iMouseHoverWidth / 2,
446 point.y + gspv.iMouseHoverHeight / 2);
447 }
448 }
449 return TRUE;
450 }
451
452 BOOL
453 APIENTRY
454 NtUserTrackMouseEvent(
455 LPTRACKMOUSEEVENT lpEventTrack)
456 {
457 TRACKMOUSEEVENT SafeTME;
458 BOOL bRet = FALSE;
459
460 TRACE("Enter NtUserTrackMouseEvent\n");
461
462 _SEH2_TRY
463 {
464 ProbeForRead(lpEventTrack, sizeof(TRACKMOUSEEVENT), 1);
465 RtlCopyMemory(&SafeTME, lpEventTrack, sizeof(TRACKMOUSEEVENT));
466 }
467 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
468 {
469 SetLastNtError(_SEH2_GetExceptionCode());
470 _SEH2_YIELD(return FALSE);
471 }
472 _SEH2_END;
473
474 if (SafeTME.cbSize != sizeof(TRACKMOUSEEVENT))
475 {
476 EngSetLastError(ERROR_INVALID_PARAMETER);
477 return FALSE;
478 }
479
480 if (SafeTME.dwFlags & ~(TME_CANCEL | TME_QUERY | TME_NONCLIENT | TME_LEAVE | TME_HOVER) )
481 {
482 EngSetLastError(ERROR_INVALID_FLAGS);
483 return FALSE;
484 }
485
486 UserEnterExclusive();
487
488 if (SafeTME.dwFlags & TME_QUERY)
489 {
490 bRet = IntQueryTrackMouseEvent(&SafeTME);
491 _SEH2_TRY
492 {
493 ProbeForWrite(lpEventTrack, sizeof(TRACKMOUSEEVENT), 1);
494 RtlCopyMemory(lpEventTrack, &SafeTME, sizeof(TRACKMOUSEEVENT));
495 }
496 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
497 {
498 SetLastNtError(_SEH2_GetExceptionCode());
499 bRet = FALSE;
500 }
501 _SEH2_END;
502 }
503 else
504 {
505 bRet = IntTrackMouseEvent(&SafeTME);
506 }
507
508 TRACE("Leave NtUserTrackMouseEvent, ret=%i\n", bRet);
509 UserLeave();
510 return bRet;
511 }
512
513 DWORD
514 APIENTRY
515 NtUserGetMouseMovePointsEx(
516 UINT cbSize,
517 LPMOUSEMOVEPOINT lpptIn,
518 LPMOUSEMOVEPOINT lpptOut,
519 int nBufPoints,
520 DWORD resolution)
521 {
522 MOUSEMOVEPOINT Safeppt;
523 //BOOL Hit;
524 INT iRet = -1;
525
526 TRACE("Enter NtUserGetMouseMovePointsEx\n");
527
528 if ((cbSize != sizeof(MOUSEMOVEPOINT)) || (nBufPoints < 0) || (nBufPoints > 64))
529 {
530 EngSetLastError(ERROR_INVALID_PARAMETER);
531 return (DWORD)-1;
532 }
533
534 if (!lpptIn || (!lpptOut && nBufPoints))
535 {
536 EngSetLastError(ERROR_NOACCESS);
537 return (DWORD)-1;
538 }
539
540 _SEH2_TRY
541 {
542 ProbeForRead(lpptIn, cbSize, 1);
543 RtlCopyMemory(&Safeppt, lpptIn, cbSize);
544 }
545 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
546 {
547 SetLastNtError(_SEH2_GetExceptionCode());
548 _SEH2_YIELD(return (DWORD)-1);
549 }
550 _SEH2_END;
551
552 UserEnterShared();
553
554 // http://msdn.microsoft.com/en-us/library/ms646259(v=vs.85).aspx
555 // This explains the math issues in transforming points.
556 iRet = gcMouseHistoryOfMoves; // FIFO is forward so retrieve backward.
557 //Hit = FALSE;
558 do
559 {
560 if (Safeppt.x == 0 && Safeppt.y == 0)
561 break; // No test.
562 // Finds the point, it returns the last nBufPoints prior to and including the supplied point.
563 if (gMouseHistoryOfMoves[iRet].x == Safeppt.x && gMouseHistoryOfMoves[iRet].y == Safeppt.y)
564 {
565 if (Safeppt.time) // Now test time and it seems to be absolute.
566 {
567 if (Safeppt.time == gMouseHistoryOfMoves[iRet].time)
568 {
569 //Hit = TRUE;
570 break;
571 }
572 else
573 {
574 if (--iRet < 0) iRet = 63;
575 continue;
576 }
577 }
578 //Hit = TRUE;
579 break;
580 }
581 if (--iRet < 0) iRet = 63;
582 }
583 while (iRet != gcMouseHistoryOfMoves);
584
585 switch(resolution)
586 {
587 case GMMP_USE_DISPLAY_POINTS:
588 if (nBufPoints)
589 {
590 _SEH2_TRY
591 {
592 ProbeForWrite(lpptOut, cbSize, 1);
593 }
594 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
595 {
596 SetLastNtError(_SEH2_GetExceptionCode());
597 iRet = -1;
598 _SEH2_YIELD(goto cleanup);
599 }
600 _SEH2_END;
601 }
602 iRet = nBufPoints;
603 break;
604 case GMMP_USE_HIGH_RESOLUTION_POINTS:
605 break;
606 default:
607 EngSetLastError(ERROR_POINT_NOT_FOUND);
608 iRet = -1;
609 }
610
611 cleanup:
612 TRACE("Leave NtUserGetMouseMovePointsEx, ret=%i\n", iRet);
613 UserLeave();
614 return (DWORD)iRet;
615 }