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 Msg.time = EngGetTickCount32(); 214 } 215 216 /* Do GetMouseMovePointsEx FIFO. */ 217 gMouseHistoryOfMoves[gcMouseHistoryOfMoves].x = ptCursor.x; 218 gMouseHistoryOfMoves[gcMouseHistoryOfMoves].y = ptCursor.y; 219 gMouseHistoryOfMoves[gcMouseHistoryOfMoves].time = Msg.time; 220 gMouseHistoryOfMoves[gcMouseHistoryOfMoves].dwExtraInfo = pmi->dwExtraInfo; 221 if (++gcMouseHistoryOfMoves == ARRAYSIZE(gMouseHistoryOfMoves)) 222 gcMouseHistoryOfMoves = 0; // 0 - 63 is 64, FIFO forwards. 223 224 /* Update cursor position */ 225 if (dwFlags & MOUSEEVENTF_MOVE) 226 { 227 UserSetCursorPos(ptCursor.x, ptCursor.y, bInjected, pmi->dwExtraInfo, TRUE); 228 } 229 230 if (IS_KEY_DOWN(gafAsyncKeyState, VK_SHIFT)) 231 pCurInfo->ButtonsDown |= MK_SHIFT; 232 else 233 pCurInfo->ButtonsDown &= ~MK_SHIFT; 234 235 if (IS_KEY_DOWN(gafAsyncKeyState, VK_CONTROL)) 236 pCurInfo->ButtonsDown |= MK_CONTROL; 237 else 238 pCurInfo->ButtonsDown &= ~MK_CONTROL; 239 240 /* Left button */ 241 if (dwFlags & MOUSEEVENTF_LEFTDOWN) 242 { 243 SET_KEY_DOWN(gafAsyncKeyState, VK_LBUTTON, TRUE); 244 Msg.message = WM_LBUTTONDOWN; 245 pCurInfo->ButtonsDown |= MK_LBUTTON; 246 Msg.wParam |= MK_LBUTTON; 247 co_MsqInsertMouseMessage(&Msg, bInjected, pmi->dwExtraInfo, TRUE); 248 } 249 else if (dwFlags & MOUSEEVENTF_LEFTUP) 250 { 251 SET_KEY_DOWN(gafAsyncKeyState, VK_LBUTTON, FALSE); 252 Msg.message = WM_LBUTTONUP; 253 pCurInfo->ButtonsDown &= ~MK_LBUTTON; 254 Msg.wParam &= ~MK_LBUTTON; 255 co_MsqInsertMouseMessage(&Msg, bInjected, pmi->dwExtraInfo, TRUE); 256 } 257 258 /* Middle button */ 259 if (dwFlags & MOUSEEVENTF_MIDDLEDOWN) 260 { 261 SET_KEY_DOWN(gafAsyncKeyState, VK_MBUTTON, TRUE); 262 Msg.message = WM_MBUTTONDOWN; 263 pCurInfo->ButtonsDown |= MK_MBUTTON; 264 Msg.wParam |= MK_MBUTTON; 265 co_MsqInsertMouseMessage(&Msg, bInjected, pmi->dwExtraInfo, TRUE); 266 } 267 else if (dwFlags & MOUSEEVENTF_MIDDLEUP) 268 { 269 SET_KEY_DOWN(gafAsyncKeyState, VK_MBUTTON, FALSE); 270 Msg.message = WM_MBUTTONUP; 271 pCurInfo->ButtonsDown &= ~MK_MBUTTON; 272 Msg.wParam &= ~MK_MBUTTON; 273 co_MsqInsertMouseMessage(&Msg, bInjected, pmi->dwExtraInfo, TRUE); 274 } 275 276 /* Right button */ 277 if (dwFlags & MOUSEEVENTF_RIGHTDOWN) 278 { 279 SET_KEY_DOWN(gafAsyncKeyState, VK_RBUTTON, TRUE); 280 Msg.message = WM_RBUTTONDOWN; 281 pCurInfo->ButtonsDown |= MK_RBUTTON; 282 Msg.wParam |= MK_RBUTTON; 283 co_MsqInsertMouseMessage(&Msg, bInjected, pmi->dwExtraInfo, TRUE); 284 } 285 else if (dwFlags & MOUSEEVENTF_RIGHTUP) 286 { 287 SET_KEY_DOWN(gafAsyncKeyState, VK_RBUTTON, FALSE); 288 Msg.message = WM_RBUTTONUP; 289 pCurInfo->ButtonsDown &= ~MK_RBUTTON; 290 Msg.wParam &= ~MK_RBUTTON; 291 co_MsqInsertMouseMessage(&Msg, bInjected, pmi->dwExtraInfo, TRUE); 292 } 293 294 if((dwFlags & (MOUSEEVENTF_XDOWN | MOUSEEVENTF_XUP)) && 295 (dwFlags & MOUSEEVENTF_WHEEL)) 296 { 297 /* Fail because both types of events use the mouseData field */ 298 WARN("Invalid flags!\n"); 299 return FALSE; 300 } 301 302 /* X-Button (4 or 5) */ 303 if (dwFlags & MOUSEEVENTF_XDOWN) 304 { 305 Msg.message = WM_XBUTTONDOWN; 306 if (pmi->mouseData & XBUTTON1) 307 { 308 SET_KEY_DOWN(gafAsyncKeyState, VK_XBUTTON1, TRUE); 309 pCurInfo->ButtonsDown |= MK_XBUTTON1; 310 Msg.wParam |= MAKEWPARAM(MK_XBUTTON1, XBUTTON1); 311 co_MsqInsertMouseMessage(&Msg, bInjected, pmi->dwExtraInfo, TRUE); 312 } 313 if (pmi->mouseData & XBUTTON2) 314 { 315 SET_KEY_DOWN(gafAsyncKeyState, VK_XBUTTON2, TRUE); 316 pCurInfo->ButtonsDown |= MK_XBUTTON2; 317 Msg.wParam |= MAKEWPARAM(MK_XBUTTON2, XBUTTON2); 318 co_MsqInsertMouseMessage(&Msg, bInjected, pmi->dwExtraInfo, TRUE); 319 } 320 } 321 else if (dwFlags & MOUSEEVENTF_XUP) 322 { 323 Msg.message = WM_XBUTTONUP; 324 if(pmi->mouseData & XBUTTON1) 325 { 326 SET_KEY_DOWN(gafAsyncKeyState, VK_XBUTTON1, FALSE); 327 pCurInfo->ButtonsDown &= ~MK_XBUTTON1; 328 Msg.wParam &= ~MK_XBUTTON1; 329 Msg.wParam |= MAKEWPARAM(0, XBUTTON2); 330 co_MsqInsertMouseMessage(&Msg, bInjected, pmi->dwExtraInfo, TRUE); 331 } 332 if (pmi->mouseData & XBUTTON2) 333 { 334 SET_KEY_DOWN(gafAsyncKeyState, VK_XBUTTON2, FALSE); 335 pCurInfo->ButtonsDown &= ~MK_XBUTTON2; 336 Msg.wParam &= ~MK_XBUTTON2; 337 Msg.wParam |= MAKEWPARAM(0, XBUTTON2); 338 co_MsqInsertMouseMessage(&Msg, bInjected, pmi->dwExtraInfo, TRUE); 339 } 340 } 341 342 /* Mouse wheel */ 343 if (dwFlags & MOUSEEVENTF_WHEEL) 344 { 345 Msg.message = WM_MOUSEWHEEL; 346 Msg.wParam = MAKEWPARAM(pCurInfo->ButtonsDown, pmi->mouseData); 347 co_MsqInsertMouseMessage(&Msg, bInjected, pmi->dwExtraInfo, TRUE); 348 } 349 350 return TRUE; 351 } 352 353 VOID 354 FASTCALL 355 IntRemoveTrackMouseEvent( 356 PDESKTOP pDesk) 357 { 358 /* Generate a leave message */ 359 if (pDesk->dwDTFlags & DF_TME_LEAVE) 360 { 361 UINT uMsg = (pDesk->htEx != HTCLIENT) ? WM_NCMOUSELEAVE : WM_MOUSELEAVE; 362 UserPostMessage(UserHMGetHandle(pDesk->spwndTrack), uMsg, 0, 0); 363 } 364 /* Kill the timer */ 365 if (pDesk->dwDTFlags & DF_TME_HOVER) 366 IntKillTimer(pDesk->spwndTrack, ID_EVENT_SYSTIMER_MOUSEHOVER, TRUE); 367 368 /* Reset state */ 369 pDesk->dwDTFlags &= ~(DF_TME_LEAVE|DF_TME_HOVER); 370 pDesk->spwndTrack = NULL; 371 } 372 373 BOOL 374 FASTCALL 375 IntQueryTrackMouseEvent( 376 LPTRACKMOUSEEVENT lpEventTrack) 377 { 378 PDESKTOP pDesk; 379 PTHREADINFO pti; 380 381 pti = PsGetCurrentThreadWin32Thread(); 382 pDesk = pti->rpdesk; 383 384 /* Always cleared with size set and return true. */ 385 RtlZeroMemory(lpEventTrack , sizeof(TRACKMOUSEEVENT)); 386 lpEventTrack->cbSize = sizeof(TRACKMOUSEEVENT); 387 388 if (pDesk->dwDTFlags & (DF_TME_LEAVE | DF_TME_HOVER) && 389 pDesk->spwndTrack && 390 pti->MessageQueue == pDesk->spwndTrack->head.pti->MessageQueue) 391 { 392 if (pDesk->htEx != HTCLIENT) 393 lpEventTrack->dwFlags |= TME_NONCLIENT; 394 395 if (pDesk->dwDTFlags & DF_TME_LEAVE) 396 lpEventTrack->dwFlags |= TME_LEAVE; 397 398 if (pDesk->dwDTFlags & DF_TME_HOVER) 399 { 400 lpEventTrack->dwFlags |= TME_HOVER; 401 lpEventTrack->dwHoverTime = pDesk->dwMouseHoverTime; 402 } 403 lpEventTrack->hwndTrack = UserHMGetHandle(pDesk->spwndTrack); 404 } 405 return TRUE; 406 } 407 408 BOOL 409 FASTCALL 410 IntTrackMouseEvent( 411 LPTRACKMOUSEEVENT lpEventTrack) 412 { 413 PDESKTOP pDesk; 414 PTHREADINFO pti; 415 PWND pWnd; 416 POINT point; 417 418 pti = PsGetCurrentThreadWin32Thread(); 419 pDesk = pti->rpdesk; 420 421 if (!(pWnd = UserGetWindowObject(lpEventTrack->hwndTrack))) 422 return FALSE; 423 424 if ( pDesk->spwndTrack != pWnd || 425 (pDesk->htEx != HTCLIENT) ^ !!(lpEventTrack->dwFlags & TME_NONCLIENT) ) 426 { 427 if ( lpEventTrack->dwFlags & TME_LEAVE && !(lpEventTrack->dwFlags & TME_CANCEL) ) 428 { 429 UserPostMessage( lpEventTrack->hwndTrack, 430 lpEventTrack->dwFlags & TME_NONCLIENT ? WM_NCMOUSELEAVE : WM_MOUSELEAVE, 431 0, 0); 432 } 433 TRACE("IntTrackMouseEvent spwndTrack %p pwnd %p\n", pDesk->spwndTrack, pWnd); 434 return TRUE; 435 } 436 437 /* Tracking spwndTrack same as pWnd */ 438 if (lpEventTrack->dwFlags & TME_CANCEL) // Canceled mode. 439 { 440 if (lpEventTrack->dwFlags & TME_LEAVE) 441 pDesk->dwDTFlags &= ~DF_TME_LEAVE; 442 443 if (lpEventTrack->dwFlags & TME_HOVER) 444 { 445 if (pDesk->dwDTFlags & DF_TME_HOVER) 446 { // Kill hover timer. 447 IntKillTimer(pWnd, ID_EVENT_SYSTIMER_MOUSEHOVER, TRUE); 448 pDesk->dwDTFlags &= ~DF_TME_HOVER; 449 } 450 } 451 } 452 else // Not Canceled. 453 { 454 if (lpEventTrack->dwFlags & TME_LEAVE) 455 pDesk->dwDTFlags |= DF_TME_LEAVE; 456 457 if (lpEventTrack->dwFlags & TME_HOVER) 458 { 459 pDesk->dwDTFlags |= DF_TME_HOVER; 460 461 if (!lpEventTrack->dwHoverTime || lpEventTrack->dwHoverTime == HOVER_DEFAULT) 462 pDesk->dwMouseHoverTime = gspv.iMouseHoverTime; // use the system default hover time-out. 463 else 464 pDesk->dwMouseHoverTime = lpEventTrack->dwHoverTime; 465 // Start timer for the hover period. 466 IntSetTimer(pWnd, ID_EVENT_SYSTIMER_MOUSEHOVER, pDesk->dwMouseHoverTime, SystemTimerProc, TMRF_SYSTEM); 467 // Get windows thread message points. 468 point = pWnd->head.pti->ptLast; 469 // Set desktop mouse hover from the system default hover rectangle. 470 RECTL_vSetRect(&pDesk->rcMouseHover, 471 point.x - gspv.iMouseHoverWidth / 2, 472 point.y - gspv.iMouseHoverHeight / 2, 473 point.x + gspv.iMouseHoverWidth / 2, 474 point.y + gspv.iMouseHoverHeight / 2); 475 } 476 } 477 return TRUE; 478 } 479 480 BOOL 481 APIENTRY 482 NtUserTrackMouseEvent( 483 LPTRACKMOUSEEVENT lpEventTrack) 484 { 485 TRACKMOUSEEVENT SafeTME; 486 BOOL bRet = FALSE; 487 488 TRACE("Enter NtUserTrackMouseEvent\n"); 489 490 _SEH2_TRY 491 { 492 ProbeForRead(lpEventTrack, sizeof(TRACKMOUSEEVENT), 1); 493 RtlCopyMemory(&SafeTME, lpEventTrack, sizeof(TRACKMOUSEEVENT)); 494 } 495 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 496 { 497 SetLastNtError(_SEH2_GetExceptionCode()); 498 _SEH2_YIELD(return FALSE); 499 } 500 _SEH2_END; 501 502 if (SafeTME.cbSize != sizeof(TRACKMOUSEEVENT)) 503 { 504 EngSetLastError(ERROR_INVALID_PARAMETER); 505 return FALSE; 506 } 507 508 if (SafeTME.dwFlags & ~(TME_CANCEL | TME_QUERY | TME_NONCLIENT | TME_LEAVE | TME_HOVER) ) 509 { 510 EngSetLastError(ERROR_INVALID_FLAGS); 511 return FALSE; 512 } 513 514 UserEnterExclusive(); 515 516 if (SafeTME.dwFlags & TME_QUERY) 517 { 518 bRet = IntQueryTrackMouseEvent(&SafeTME); 519 _SEH2_TRY 520 { 521 ProbeForWrite(lpEventTrack, sizeof(TRACKMOUSEEVENT), 1); 522 RtlCopyMemory(lpEventTrack, &SafeTME, sizeof(TRACKMOUSEEVENT)); 523 } 524 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 525 { 526 SetLastNtError(_SEH2_GetExceptionCode()); 527 bRet = FALSE; 528 } 529 _SEH2_END; 530 } 531 else 532 { 533 bRet = IntTrackMouseEvent(&SafeTME); 534 } 535 536 TRACE("Leave NtUserTrackMouseEvent, ret=%i\n", bRet); 537 UserLeave(); 538 return bRet; 539 } 540 541 DWORD 542 APIENTRY 543 NtUserGetMouseMovePointsEx( 544 UINT cbSize, 545 LPMOUSEMOVEPOINT lpptIn, 546 LPMOUSEMOVEPOINT lpptOut, 547 int nBufPoints, 548 DWORD resolution) 549 { 550 MOUSEMOVEPOINT Safeppt; 551 //BOOL Hit; 552 INT iRet = -1; 553 554 TRACE("Enter NtUserGetMouseMovePointsEx\n"); 555 556 if ((cbSize != sizeof(MOUSEMOVEPOINT)) || (nBufPoints < 0) || (nBufPoints > 64)) 557 { 558 EngSetLastError(ERROR_INVALID_PARAMETER); 559 return (DWORD)-1; 560 } 561 562 if (!lpptIn || (!lpptOut && nBufPoints)) 563 { 564 EngSetLastError(ERROR_NOACCESS); 565 return (DWORD)-1; 566 } 567 568 _SEH2_TRY 569 { 570 ProbeForRead(lpptIn, cbSize, 1); 571 RtlCopyMemory(&Safeppt, lpptIn, cbSize); 572 } 573 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 574 { 575 SetLastNtError(_SEH2_GetExceptionCode()); 576 _SEH2_YIELD(return (DWORD)-1); 577 } 578 _SEH2_END; 579 580 UserEnterShared(); 581 582 // http://msdn.microsoft.com/en-us/library/ms646259(v=vs.85).aspx 583 // This explains the math issues in transforming points. 584 iRet = gcMouseHistoryOfMoves; // FIFO is forward so retrieve backward. 585 //Hit = FALSE; 586 do 587 { 588 if (Safeppt.x == 0 && Safeppt.y == 0) 589 break; // No test. 590 // Finds the point, it returns the last nBufPoints prior to and including the supplied point. 591 if (gMouseHistoryOfMoves[iRet].x == Safeppt.x && gMouseHistoryOfMoves[iRet].y == Safeppt.y) 592 { 593 if (Safeppt.time) // Now test time and it seems to be absolute. 594 { 595 if (Safeppt.time == gMouseHistoryOfMoves[iRet].time) 596 { 597 //Hit = TRUE; 598 break; 599 } 600 else 601 { 602 if (--iRet < 0) iRet = 63; 603 continue; 604 } 605 } 606 //Hit = TRUE; 607 break; 608 } 609 if (--iRet < 0) iRet = 63; 610 } 611 while (iRet != gcMouseHistoryOfMoves); 612 613 switch(resolution) 614 { 615 case GMMP_USE_DISPLAY_POINTS: 616 if (nBufPoints) 617 { 618 _SEH2_TRY 619 { 620 ProbeForWrite(lpptOut, cbSize, 1); 621 } 622 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 623 { 624 SetLastNtError(_SEH2_GetExceptionCode()); 625 iRet = -1; 626 _SEH2_YIELD(goto cleanup); 627 } 628 _SEH2_END; 629 } 630 iRet = nBufPoints; 631 break; 632 case GMMP_USE_HIGH_RESOLUTION_POINTS: 633 break; 634 default: 635 EngSetLastError(ERROR_POINT_NOT_FOUND); 636 iRet = -1; 637 } 638 639 cleanup: 640 TRACE("Leave NtUserGetMouseMovePointsEx, ret=%i\n", iRet); 641 UserLeave(); 642 return (DWORD)iRet; 643 } 644