سؤال

Background:

I have been using WM_MOUSEMOVE and WM_KEYDOWN/WM_KEYUP messages for mouse and keyboard input respectively throughout most of my time developing using the Windows API. However I have recently begun to implement an input class that handles input using RAWINPUT and the WM_INPUT message instead.

The keyboard implementation is working flawlessly thanks to this site

However I have now turned my attention to implementing mouse movement. From my understanding, WM_INPUT generates mouse movement deltas, rather than client space coordinates when dealing with the mouse.

The problem is I would also like to store both the client and screen space coordinates of the mouse pointer within the class, and ideally I would like to do this without needing to also trap the WM_MOUSEMOVE message or use GetCursorPos()/ScreenToClient() functions if possible, due to my (probably unwarranted) fear of performance issues.

My reasearch into RAWINPUT led me here whereby it states about mouse details:

Note that the values returned are not screen space values like you get from the WM_MOUSEMOVE message. This is raw data we are getting so the values need interpreting.

This led me to believe that it was possible to interpret the data by calculating the initial position of the mouse cursor using an initial call GetCursorPos() then for every mouse move event detected by the WM_INPUT message, add the deltas retrieved from the WM_INPUT message to the initial cursor position, taking steps to ensure that the position remains within the screen boundaries. For example something like this (note this wont compile as it contains extracts from my class, but it should be sufficient to give an overview of what I am doing currently)

// Somewhere in class header

RECT m_screenMouseBounds;
POINT m_mouseDelta;
POINT m_mouseScreenPosition;
POINT m_mouseScreenPositionGETCURSOR;
RAWMOUSE m_rawMouse;

// ... 

// Somewhere during class initialisation

GetCursorPos(&m_mouseScreenPosition); // Get initial mouse cursor position

// Determine maximum and minimum boundaires of current display
m_screenMouseBounds.right = GetSystemMetrics(SM_CXSCREEN);
m_screenMouseBounds.bottom = GetSystemMetrics(SM_CYSCREEN);
m_screenMouseBounds.top = 0;
m_screenMouseBounds.left = 0;

// Prepare the devices for registering
RAWINPUTDEVICE theInputDevices[2]; 

// 0 = keyboard
theInputDevices[0].usUsagePage = 0x01;
theInputDevices[0].usUsage = 0x06;
theInputDevices[0].dwFlags = RIDEV_NOLEGACY; 
theInputDevices[0].hwndTarget = theWindowToHandle;

// 1 = mouse
theInputDevices[1].usUsagePage = 0x01;
theInputDevices[1].usUsage = 0x02;
theInputDevices[1].dwFlags = 0; // RIDEV_NOLEGACY 
theInputDevices[1].hwndTarget = theWindowToHandle;

// Register each device with raw input
if(RegisterRawInputDevices(theInputDevices,2,sizeof(RAWINPUTDEVICE))==FALSE)
{
    // throw exception
    return false;
}

// ... 

// In the WM_INPUT processing function with parameters : (WPARAM wParam, LPARAM lParam)

char inputBuffer[sizeof(RAWINPUT)] = {};
UINT inputBufferSize = sizeof(RAWINPUT);
GetRawInputData(reinterpret_cast<HRAWINPUT>(lParam), RID_INPUT, inputBuffer, &inputBufferSize, sizeof(RAWINPUTHEADER));
RAWINPUT* rawData = reinterpret_cast<RAWINPUT*>(inputBuffer);

if(rawData->header.dwType == RIM_TYPEMOUSE)
{
    m_rawMouse = rawData->data.mouse;

    // Add the movement deltas acquired from the WM_INPUT message
    m_mouseDelta.x = m_rawMouse.lLastX;
    m_mouseDelta.y = m_rawMouse.lLastY;

    // Update the screen position using the delta values (Does not work as expected!)
    m_mouseScreenPosition.x += m_mouseDelta.x;
    m_mouseScreenPosition.y += m_mouseDelta.y;

    // Ensure mouse coords are within the screens boundaries
    if (m_mouseScreenPosition.x < m_screenMouseBounds.left)
    {
        m_mouseScreenPosition.x = m_screenMouseBounds.left;
    }
    if (m_mouseScreenPosition.x > m_screenMouseBounds.right)
    {
        m_mouseScreenPosition.x = m_screenMouseBounds.right;
    }
    if (m_mouseScreenPosition.y < m_screenMouseBounds.top)
    {
        m_mouseScreenPosition.y = m_screenMouseBounds.top;
    }
    if (m_mouseScreenPosition.y > m_screenMouseBounds.bottom)
    {
        m_mouseScreenPosition.y = m_screenMouseBounds.bottom;
    }        

    // Double check to make sure that the screen position coordinates calculated 
    // above match the screen coordinates as determined by Windows 
    // using GetCursorPos() (Hint: They don't! :( )
    GetCursorPos(&m_mouseScreenPositionGETCURSOR);

    TCHAR s[256];
    swprintf(s, L"MouseDX: %ld MouseDY: %ld\n", m_mouseDelta.x, m_mouseDelta.y);
    OutputDebugString(s);

    swprintf(s, L"MouseX(Screen(WM_INPUT)): %ld MouseY(Screen(WM_INPUT)): %ld\n", m_mouseScreenPosition.x, m_mouseScreenPosition.y);
    OutputDebugString(s);

    swprintf(s, L"MouseX(Screen(GetCursorPos)): %ld MouseY(Screen(GetCursorPos)): %ld\n", m_mouseScreenPositionGETCURSOR.x, m_mouseScreenPositionGETCURSOR.y);
    OutputDebugString(s);
}

The problem is the values acquired for m_mouseScreenPosition through this method are different than those of the m_mouseScreenPositionGETCURSOR which are acquired via the WINAPI function GetCursorPos().

In summary

I suppose my overall set of questions are:

  1. What are the values lLastX and lLastY of the RAWMOUSE structure related to? are they related to screen coordinates/client coordinates i.e. the values returned are a 1:1 relation to pixels on the screen or are they not related to the display at all and are rather related to mouse's details (sensitivity etc) and therefore not a 1:1 relation to pixels?

  2. If the answer to 1 is related to mouse rather than display coordinates: is it possible to determine the actual screen coordinates of the mouse pointer solely using WM_INPUT? or will I have to either trap WM_MOUSEMOVE messages and/or use GetCursorPos() in order to determine the cursors coordinates in client space and screen space?

  3. If the answer to 2 is I will need to use WM_MOUSEMOVE/GetCursorPos(): Are there any performance issues I should be aware of if I end up using RAWINPUT as well as WM_MOUSEMOVE/GetCursorPos()? Or are my concerns about performance unfounded?

If you've managed this far, you have my thanks and I appreciate any help or information you can give me. Thank you!

هل كانت مفيدة؟

المحلول

  1. "Note that the values returned are not screen space values like you get from the WM_MOUSEMOVE message. This is raw data we are getting so the values need interpreting. The values are normally relative to the last position and hence indicate motion. To be sure you can check the usFlags in the RAWMOUSE structure." Got this from Toymaker which I always find awesome. Here

  2. RAWINPUT is only made for getting relative input. Thats why its raw. If you really don't want to use GetCursorPos, just use WM_MOUSEMOVE and check the l/w params.

  3. I've never actually done performance tests for GetCursorPos() but I have done a bit of reading on it for my own projects and I've never seen any objection against it. Calling GetCursorPos, whether or not you use RAWINPUT, once per frame or every update is surely going to be negligible. I've used it for rotating cameras and it has always worked fine.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top