void Mouse::ProcessMessage()

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;
    }
}