1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS kernel 4 * PURPOSE: Mouse functions 5 * FILE: win32ss/user/ntuser/mouse.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 } 616