in Src/Mouse.cpp [646:860]
void Mouse::ProcessMessage(UINT message, WPARAM wParam, LPARAM lParam)
{
auto pImpl = Impl::s_mouse;
if (!pImpl)
return;
HANDLE events[3] = { pImpl->mScrollWheelValue.get(), pImpl->mAbsoluteMode.get(), pImpl->mRelativeMode.get() };
switch (WaitForMultipleObjectsEx(static_cast<DWORD>(std::size(events)), events, FALSE, 0, FALSE))
{
default:
case WAIT_TIMEOUT:
break;
case WAIT_OBJECT_0:
pImpl->mState.scrollWheelValue = 0;
ResetEvent(events[0]);
break;
case (WAIT_OBJECT_0 + 1):
{
pImpl->mMode = MODE_ABSOLUTE;
ClipCursor(nullptr);
POINT point;
point.x = pImpl->mLastX;
point.y = pImpl->mLastY;
// We show the cursor before moving it to support Remote Desktop
ShowCursor(TRUE);
if (MapWindowPoints(pImpl->mWindow, nullptr, &point, 1))
{
SetCursorPos(point.x, point.y);
}
pImpl->mState.x = pImpl->mLastX;
pImpl->mState.y = pImpl->mLastY;
}
break;
case (WAIT_OBJECT_0 + 2):
{
ResetEvent(pImpl->mRelativeRead.get());
pImpl->mMode = MODE_RELATIVE;
pImpl->mState.x = pImpl->mState.y = 0;
pImpl->mRelativeX = INT32_MAX;
pImpl->mRelativeY = INT32_MAX;
ShowCursor(FALSE);
pImpl->ClipToWindow();
}
break;
case WAIT_FAILED:
throw std::system_error(std::error_code(static_cast<int>(GetLastError()), std::system_category()), "WaitForMultipleObjectsEx");
}
switch (message)
{
case WM_ACTIVATE:
case WM_ACTIVATEAPP:
if (wParam)
{
pImpl->mInFocus = true;
if (pImpl->mMode == MODE_RELATIVE)
{
pImpl->mState.x = pImpl->mState.y = 0;
ShowCursor(FALSE);
pImpl->ClipToWindow();
}
}
else
{
int scrollWheel = pImpl->mState.scrollWheelValue;
memset(&pImpl->mState, 0, sizeof(State));
pImpl->mState.scrollWheelValue = scrollWheel;
if (pImpl->mMode == MODE_RELATIVE)
{
ClipCursor(nullptr);
}
pImpl->mInFocus = false;
}
return;
case WM_INPUT:
if (pImpl->mInFocus && pImpl->mMode == MODE_RELATIVE)
{
RAWINPUT raw;
UINT rawSize = sizeof(raw);
UINT resultData = GetRawInputData(reinterpret_cast<HRAWINPUT>(lParam), RID_INPUT, &raw, &rawSize, sizeof(RAWINPUTHEADER));
if (resultData == UINT(-1))
{
throw std::runtime_error("GetRawInputData");
}
if (raw.header.dwType == RIM_TYPEMOUSE)
{
if (!(raw.data.mouse.usFlags & MOUSE_MOVE_ABSOLUTE))
{
pImpl->mState.x = raw.data.mouse.lLastX;
pImpl->mState.y = raw.data.mouse.lLastY;
ResetEvent(pImpl->mRelativeRead.get());
}
else if (raw.data.mouse.usFlags & MOUSE_VIRTUAL_DESKTOP)
{
// This is used to make Remote Desktop sessons work
const int width = GetSystemMetrics(SM_CXVIRTUALSCREEN);
const int height = GetSystemMetrics(SM_CYVIRTUALSCREEN);
int x = static_cast<int>((float(raw.data.mouse.lLastX) / 65535.0f) * float(width));
int y = static_cast<int>((float(raw.data.mouse.lLastY) / 65535.0f) * float(height));
if (pImpl->mRelativeX == INT32_MAX)
{
pImpl->mState.x = pImpl->mState.y = 0;
}
else
{
pImpl->mState.x = x - pImpl->mRelativeX;
pImpl->mState.y = y - pImpl->mRelativeY;
}
pImpl->mRelativeX = x;
pImpl->mRelativeY = y;
ResetEvent(pImpl->mRelativeRead.get());
}
}
}
return;
case WM_MOUSEMOVE:
break;
case WM_LBUTTONDOWN:
pImpl->mState.leftButton = true;
break;
case WM_LBUTTONUP:
pImpl->mState.leftButton = false;
break;
case WM_RBUTTONDOWN:
pImpl->mState.rightButton = true;
break;
case WM_RBUTTONUP:
pImpl->mState.rightButton = false;
break;
case WM_MBUTTONDOWN:
pImpl->mState.middleButton = true;
break;
case WM_MBUTTONUP:
pImpl->mState.middleButton = false;
break;
case WM_MOUSEWHEEL:
pImpl->mState.scrollWheelValue += GET_WHEEL_DELTA_WPARAM(wParam);
return;
case WM_XBUTTONDOWN:
switch (GET_XBUTTON_WPARAM(wParam))
{
case XBUTTON1:
pImpl->mState.xButton1 = true;
break;
case XBUTTON2:
pImpl->mState.xButton2 = true;
break;
}
break;
case WM_XBUTTONUP:
switch (GET_XBUTTON_WPARAM(wParam))
{
case XBUTTON1:
pImpl->mState.xButton1 = false;
break;
case XBUTTON2:
pImpl->mState.xButton2 = false;
break;
}
break;
case WM_MOUSEHOVER:
break;
default:
// Not a mouse message, so exit
return;
}
if (pImpl->mMode == MODE_ABSOLUTE)
{
// All mouse messages provide a new pointer position
int xPos = static_cast<short>(LOWORD(lParam)); // GET_X_LPARAM(lParam);
int yPos = static_cast<short>(HIWORD(lParam)); // GET_Y_LPARAM(lParam);
pImpl->mState.x = pImpl->mLastX = xPos;
pImpl->mState.y = pImpl->mLastY = yPos;
}
}