/* * UserProcessMouseInput * * Process raw mouse input data */ VOID NTAPI UserProcessMouseInput(PMOUSE_INPUT_DATA mid) { MOUSEINPUT mi; /* Convert MOUSE_INPUT_DATA to MOUSEINPUT. First init all fields. */ mi.dx = mid->LastX; mi.dy = mid->LastY; mi.mouseData = 0; mi.dwFlags = 0; mi.time = 0; mi.dwExtraInfo = mid->ExtraInformation; /* Mouse position */ if (mi.dx != 0 || mi.dy != 0) mi.dwFlags |= MOUSEEVENTF_MOVE; /* Flags for absolute move */ if (mid->Flags & MOUSE_MOVE_ABSOLUTE) mi.dwFlags |= MOUSEEVENTF_ABSOLUTE; if (mid->Flags & MOUSE_VIRTUAL_DESKTOP) mi.dwFlags |= MOUSEEVENTF_VIRTUALDESK; /* Left button */ if (mid->ButtonFlags & MOUSE_LEFT_BUTTON_DOWN) mi.dwFlags |= MOUSEEVENTF_LEFTDOWN; if (mid->ButtonFlags & MOUSE_LEFT_BUTTON_UP) mi.dwFlags |= MOUSEEVENTF_LEFTUP; /* Middle button */ if (mid->ButtonFlags & MOUSE_MIDDLE_BUTTON_DOWN) mi.dwFlags |= MOUSEEVENTF_MIDDLEDOWN; if (mid->ButtonFlags & MOUSE_MIDDLE_BUTTON_UP) mi.dwFlags |= MOUSEEVENTF_MIDDLEUP; /* Right button */ if (mid->ButtonFlags & MOUSE_RIGHT_BUTTON_DOWN) mi.dwFlags |= MOUSEEVENTF_RIGHTDOWN; if (mid->ButtonFlags & MOUSE_RIGHT_BUTTON_UP) mi.dwFlags |= MOUSEEVENTF_RIGHTUP; /* Note: Next buttons use mouseData field so they cannot be sent in one call */ /* Button 4 */ if (mid->ButtonFlags & MOUSE_BUTTON_4_DOWN) { mi.dwFlags |= MOUSEEVENTF_XDOWN; mi.mouseData |= XBUTTON1; } if (mid->ButtonFlags & MOUSE_BUTTON_4_UP) { mi.dwFlags |= MOUSEEVENTF_XUP; mi.mouseData |= XBUTTON1; } /* If mouseData is used by button 4, send input and clear mi */ if (mi.dwFlags & (MOUSE_BUTTON_4_DOWN | MOUSE_BUTTON_4_UP)) { UserSendMouseInput(&mi, FALSE); RtlZeroMemory(&mi, sizeof(mi)); } /* Button 5 */ if (mid->ButtonFlags & MOUSE_BUTTON_5_DOWN) { mi.mouseData |= XBUTTON2; mi.dwFlags |= MOUSEEVENTF_XDOWN; } if (mid->ButtonFlags & MOUSE_BUTTON_5_UP) { mi.mouseData |= XBUTTON2; mi.dwFlags |= MOUSEEVENTF_XUP; } /* If mouseData is used by button 5, send input and clear mi */ if (mi.dwFlags & (MOUSE_BUTTON_5_DOWN | MOUSE_BUTTON_5_UP)) { UserSendMouseInput(&mi, FALSE); RtlZeroMemory(&mi, sizeof(mi)); } /* Mouse wheel */ if (mid->ButtonFlags & MOUSE_WHEEL) { mi.mouseData = mid->ButtonData; mi.dwFlags |= MOUSEEVENTF_WHEEL; } /* If something has changed, send input to user */ if (mi.dwFlags) UserSendMouseInput(&mi, FALSE); }
HWND FASTCALL co_UserSetCapture(HWND hWnd) { PTHREADINFO pti; PUSER_MESSAGE_QUEUE ThreadQueue; PWND pWnd, Window = NULL; HWND hWndPrev; pti = PsGetCurrentThreadWin32Thread(); ThreadQueue = pti->MessageQueue; if (ThreadQueue->QF_flags & QF_CAPTURELOCKED) return NULL; if (hWnd && (Window = UserGetWindowObject(hWnd))) { if (Window->head.pti->MessageQueue != ThreadQueue) { return NULL; } } hWndPrev = MsqSetStateWindow(pti, MSQ_STATE_CAPTURE, hWnd); if (hWndPrev) { pWnd = UserGetWindowObject(hWndPrev); if (pWnd) IntNotifyWinEvent(EVENT_SYSTEM_CAPTUREEND, pWnd, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI); } if (Window) IntNotifyWinEvent(EVENT_SYSTEM_CAPTURESTART, Window, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI); if (hWndPrev && hWndPrev != hWnd) { if (ThreadQueue->MenuOwner && Window) ThreadQueue->QF_flags |= QF_CAPTURELOCKED; //co_IntPostOrSendMessage(hWndPrev, WM_CAPTURECHANGED, 0, (LPARAM)hWnd); co_IntSendMessage(hWndPrev, WM_CAPTURECHANGED, 0, (LPARAM)hWnd); ThreadQueue->QF_flags &= ~QF_CAPTURELOCKED; } ThreadQueue->spwndCapture = Window; if (hWnd == NULL) // Release mode. { MOUSEINPUT mi; /// These are HACKS! /* Also remove other windows if not capturing anymore */ MsqSetStateWindow(pti, MSQ_STATE_MENUOWNER, NULL); MsqSetStateWindow(pti, MSQ_STATE_MOVESIZE, NULL); /// /* Somebody may have missed some mouse movements */ mi.dx = 0; mi.dy = 0; mi.mouseData = 0; mi.dwFlags = MOUSEEVENTF_MOVE; mi.time = 0; mi.dwExtraInfo = 0; UserSendMouseInput(&mi, FALSE); } return hWndPrev; }
/* * NtUserSendInput * * Generates input events from software */ UINT APIENTRY NtUserSendInput( UINT nInputs, LPINPUT pInput, INT cbSize) { PTHREADINFO pti; UINT uRet = 0; TRACE("Enter NtUserSendInput\n"); UserEnterExclusive(); pti = PsGetCurrentThreadWin32Thread(); ASSERT(pti); if (!pti->rpdesk) { goto cleanup; } if (!nInputs || !pInput || cbSize != sizeof(INPUT)) { EngSetLastError(ERROR_INVALID_PARAMETER); goto cleanup; } /* * FIXME: Check access rights of the window station * e.g. services running in the service window station cannot block input */ if (!ThreadHasInputAccess(pti) || !IntIsActiveDesktop(pti->rpdesk)) { EngSetLastError(ERROR_ACCESS_DENIED); goto cleanup; } while (nInputs--) { INPUT SafeInput; NTSTATUS Status; Status = MmCopyFromCaller(&SafeInput, pInput++, sizeof(INPUT)); if (!NT_SUCCESS(Status)) { SetLastNtError(Status); goto cleanup; } switch (SafeInput.type) { case INPUT_MOUSE: if (UserSendMouseInput(&SafeInput.mi, TRUE)) uRet++; break; case INPUT_KEYBOARD: if (UserSendKeyboardInput(&SafeInput.ki, TRUE)) uRet++; break; case INPUT_HARDWARE: FIXME("INPUT_HARDWARE not supported!"); break; default: ERR("SendInput(): Invalid input type: 0x%x\n", SafeInput.type); break; } } cleanup: TRACE("Leave NtUserSendInput, ret=%u\n", uRet); UserLeave(); return uRet; }