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