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 VOID 346 FASTCALL 347 IntRemoveTrackMouseEvent( 348 PDESKTOP pDesk) 349 { 350 /* Generate a leave message */ 351 if (pDesk->dwDTFlags & DF_TME_LEAVE) 352 { 353 UINT uMsg = (pDesk->htEx != HTCLIENT) ? WM_NCMOUSELEAVE : WM_MOUSELEAVE; 354 UserPostMessage(UserHMGetHandle(pDesk->spwndTrack), uMsg, 0, 0); 355 } 356 /* Kill the timer */ 357 if (pDesk->dwDTFlags & DF_TME_HOVER) 358 IntKillTimer(pDesk->spwndTrack, ID_EVENT_SYSTIMER_MOUSEHOVER, TRUE); 359 360 /* Reset state */ 361 pDesk->dwDTFlags &= ~(DF_TME_LEAVE|DF_TME_HOVER); 362 pDesk->spwndTrack = NULL; 363 } 364 365 BOOL 366 FASTCALL 367 IntQueryTrackMouseEvent( 368 LPTRACKMOUSEEVENT lpEventTrack) 369 { 370 PDESKTOP pDesk; 371 PTHREADINFO pti; 372 373 pti = PsGetCurrentThreadWin32Thread(); 374 pDesk = pti->rpdesk; 375 376 /* Always cleared with size set and return true. */ 377 RtlZeroMemory(lpEventTrack , sizeof(TRACKMOUSEEVENT)); 378 lpEventTrack->cbSize = sizeof(TRACKMOUSEEVENT); 379 380 if (pDesk->dwDTFlags & (DF_TME_LEAVE | DF_TME_HOVER) && 381 pDesk->spwndTrack && 382 pti->MessageQueue == pDesk->spwndTrack->head.pti->MessageQueue) 383 { 384 if (pDesk->htEx != HTCLIENT) 385 lpEventTrack->dwFlags |= TME_NONCLIENT; 386 387 if (pDesk->dwDTFlags & DF_TME_LEAVE) 388 lpEventTrack->dwFlags |= TME_LEAVE; 389 390 if (pDesk->dwDTFlags & DF_TME_HOVER) 391 { 392 lpEventTrack->dwFlags |= TME_HOVER; 393 lpEventTrack->dwHoverTime = pDesk->dwMouseHoverTime; 394 } 395 lpEventTrack->hwndTrack = UserHMGetHandle(pDesk->spwndTrack); 396 } 397 return TRUE; 398 } 399 400 BOOL 401 FASTCALL 402 IntTrackMouseEvent( 403 LPTRACKMOUSEEVENT lpEventTrack) 404 { 405 PDESKTOP pDesk; 406 PTHREADINFO pti; 407 PWND pWnd; 408 POINT point; 409 410 pti = PsGetCurrentThreadWin32Thread(); 411 pDesk = pti->rpdesk; 412 413 if (!(pWnd = UserGetWindowObject(lpEventTrack->hwndTrack))) 414 return FALSE; 415 416 if ( pDesk->spwndTrack != pWnd || 417 (pDesk->htEx != HTCLIENT) ^ !!(lpEventTrack->dwFlags & TME_NONCLIENT) ) 418 { 419 if ( lpEventTrack->dwFlags & TME_LEAVE && !(lpEventTrack->dwFlags & TME_CANCEL) ) 420 { 421 UserPostMessage( lpEventTrack->hwndTrack, 422 lpEventTrack->dwFlags & TME_NONCLIENT ? WM_NCMOUSELEAVE : WM_MOUSELEAVE, 423 0, 0); 424 } 425 TRACE("IntTrackMouseEvent spwndTrack %p pwnd %p\n", pDesk->spwndTrack, pWnd); 426 return TRUE; 427 } 428 429 /* Tracking spwndTrack same as pWnd */ 430 if (lpEventTrack->dwFlags & TME_CANCEL) // Canceled mode. 431 { 432 if (lpEventTrack->dwFlags & TME_LEAVE) 433 pDesk->dwDTFlags &= ~DF_TME_LEAVE; 434 435 if (lpEventTrack->dwFlags & TME_HOVER) 436 { 437 if (pDesk->dwDTFlags & DF_TME_HOVER) 438 { // Kill hover timer. 439 IntKillTimer(pWnd, ID_EVENT_SYSTIMER_MOUSEHOVER, TRUE); 440 pDesk->dwDTFlags &= ~DF_TME_HOVER; 441 } 442 } 443 } 444 else // Not Canceled. 445 { 446 if (lpEventTrack->dwFlags & TME_LEAVE) 447 pDesk->dwDTFlags |= DF_TME_LEAVE; 448 449 if (lpEventTrack->dwFlags & TME_HOVER) 450 { 451 pDesk->dwDTFlags |= DF_TME_HOVER; 452 453 if (!lpEventTrack->dwHoverTime || lpEventTrack->dwHoverTime == HOVER_DEFAULT) 454 pDesk->dwMouseHoverTime = gspv.iMouseHoverTime; // use the system default hover time-out. 455 else 456 pDesk->dwMouseHoverTime = lpEventTrack->dwHoverTime; 457 // Start timer for the hover period. 458 IntSetTimer(pWnd, ID_EVENT_SYSTIMER_MOUSEHOVER, pDesk->dwMouseHoverTime, SystemTimerProc, TMRF_SYSTEM); 459 // Get windows thread message points. 460 point = pWnd->head.pti->ptLast; 461 // Set desktop mouse hover from the system default hover rectangle. 462 RECTL_vSetRect(&pDesk->rcMouseHover, 463 point.x - gspv.iMouseHoverWidth / 2, 464 point.y - gspv.iMouseHoverHeight / 2, 465 point.x + gspv.iMouseHoverWidth / 2, 466 point.y + gspv.iMouseHoverHeight / 2); 467 } 468 } 469 return TRUE; 470 } 471 472 BOOL 473 APIENTRY 474 NtUserTrackMouseEvent( 475 LPTRACKMOUSEEVENT lpEventTrack) 476 { 477 TRACKMOUSEEVENT SafeTME; 478 BOOL bRet = FALSE; 479 480 TRACE("Enter NtUserTrackMouseEvent\n"); 481 482 _SEH2_TRY 483 { 484 ProbeForRead(lpEventTrack, sizeof(TRACKMOUSEEVENT), 1); 485 RtlCopyMemory(&SafeTME, lpEventTrack, sizeof(TRACKMOUSEEVENT)); 486 } 487 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 488 { 489 SetLastNtError(_SEH2_GetExceptionCode()); 490 _SEH2_YIELD(return FALSE); 491 } 492 _SEH2_END; 493 494 if (SafeTME.cbSize != sizeof(TRACKMOUSEEVENT)) 495 { 496 EngSetLastError(ERROR_INVALID_PARAMETER); 497 return FALSE; 498 } 499 500 if (SafeTME.dwFlags & ~(TME_CANCEL | TME_QUERY | TME_NONCLIENT | TME_LEAVE | TME_HOVER) ) 501 { 502 EngSetLastError(ERROR_INVALID_FLAGS); 503 return FALSE; 504 } 505 506 UserEnterExclusive(); 507 508 if (SafeTME.dwFlags & TME_QUERY) 509 { 510 bRet = IntQueryTrackMouseEvent(&SafeTME); 511 _SEH2_TRY 512 { 513 ProbeForWrite(lpEventTrack, sizeof(TRACKMOUSEEVENT), 1); 514 RtlCopyMemory(lpEventTrack, &SafeTME, sizeof(TRACKMOUSEEVENT)); 515 } 516 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 517 { 518 SetLastNtError(_SEH2_GetExceptionCode()); 519 bRet = FALSE; 520 } 521 _SEH2_END; 522 } 523 else 524 { 525 bRet = IntTrackMouseEvent(&SafeTME); 526 } 527 528 TRACE("Leave NtUserTrackMouseEvent, ret=%i\n", bRet); 529 UserLeave(); 530 return bRet; 531 } 532 533 DWORD 534 APIENTRY 535 NtUserGetMouseMovePointsEx( 536 UINT cbSize, 537 LPMOUSEMOVEPOINT lpptIn, 538 LPMOUSEMOVEPOINT lpptOut, 539 int nBufPoints, 540 DWORD resolution) 541 { 542 MOUSEMOVEPOINT Safeppt; 543 //BOOL Hit; 544 INT iRet = -1; 545 546 TRACE("Enter NtUserGetMouseMovePointsEx\n"); 547 548 if ((cbSize != sizeof(MOUSEMOVEPOINT)) || (nBufPoints < 0) || (nBufPoints > 64)) 549 { 550 EngSetLastError(ERROR_INVALID_PARAMETER); 551 return (DWORD)-1; 552 } 553 554 if (!lpptIn || (!lpptOut && nBufPoints)) 555 { 556 EngSetLastError(ERROR_NOACCESS); 557 return (DWORD)-1; 558 } 559 560 _SEH2_TRY 561 { 562 ProbeForRead(lpptIn, cbSize, 1); 563 RtlCopyMemory(&Safeppt, lpptIn, cbSize); 564 } 565 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 566 { 567 SetLastNtError(_SEH2_GetExceptionCode()); 568 _SEH2_YIELD(return (DWORD)-1); 569 } 570 _SEH2_END; 571 572 UserEnterShared(); 573 574 // http://msdn.microsoft.com/en-us/library/ms646259(v=vs.85).aspx 575 // This explains the math issues in transforming points. 576 iRet = gcMouseHistoryOfMoves; // FIFO is forward so retrieve backward. 577 //Hit = FALSE; 578 do 579 { 580 if (Safeppt.x == 0 && Safeppt.y == 0) 581 break; // No test. 582 // Finds the point, it returns the last nBufPoints prior to and including the supplied point. 583 if (gMouseHistoryOfMoves[iRet].x == Safeppt.x && gMouseHistoryOfMoves[iRet].y == Safeppt.y) 584 { 585 if (Safeppt.time) // Now test time and it seems to be absolute. 586 { 587 if (Safeppt.time == gMouseHistoryOfMoves[iRet].time) 588 { 589 //Hit = TRUE; 590 break; 591 } 592 else 593 { 594 if (--iRet < 0) iRet = 63; 595 continue; 596 } 597 } 598 //Hit = TRUE; 599 break; 600 } 601 if (--iRet < 0) iRet = 63; 602 } 603 while (iRet != gcMouseHistoryOfMoves); 604 605 switch(resolution) 606 { 607 case GMMP_USE_DISPLAY_POINTS: 608 if (nBufPoints) 609 { 610 _SEH2_TRY 611 { 612 ProbeForWrite(lpptOut, cbSize, 1); 613 } 614 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 615 { 616 SetLastNtError(_SEH2_GetExceptionCode()); 617 iRet = -1; 618 _SEH2_YIELD(goto cleanup); 619 } 620 _SEH2_END; 621 } 622 iRet = nBufPoints; 623 break; 624 case GMMP_USE_HIGH_RESOLUTION_POINTS: 625 break; 626 default: 627 EngSetLastError(ERROR_POINT_NOT_FOUND); 628 iRet = -1; 629 } 630 631 cleanup: 632 TRACE("Leave NtUserGetMouseMovePointsEx, ret=%i\n", iRet); 633 UserLeave(); 634 return (DWORD)iRet; 635 } 636