Search Unity

Resolved New Input System: Get Raw Mouse Delta from WM_INPUT?

Discussion in 'Input System' started by Arycama, Oct 2, 2021.

  1. Arycama

    Arycama

    Joined:
    May 25, 2014
    Posts:
    184
    The existing mouse delta only returns pixel coordinates, so you have to move your mouse at least 1 pixel to get any delta.

    This is problematic for FPS/Third person shooters where you want to track very small movements, especially for high DPI mice.

    According to this thread, it uses WM_INPUT internally, however the values reported in the Input Debugger are always integer window coordinates. (Eg they go from (0, 0) to (WindowWidth, WindowHeight)

    https://forum.unity.com/threads/input-system-raw-input-from-mouse.949914/

    Is there any way to access the raw information, possibly by coding a custom input device within the new input system?
     
  2. dmytro_at_unity

    dmytro_at_unity

    Unity Technologies

    Joined:
    Feb 12, 2021
    Posts:
    212
    AFAIK we're propagating values as is without rounding.

    We use this API https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-rawmouse and it gives us
    lLastX
    ,
    lLastY
    as
    LONG
    , so values already coming integer, and
    MOUSE_MOVE_ABSOLUTE
    is only applicable to remote connections over RDP from my understanding, could be wrong though.

    From what I know it seems the only way would be to call
    GetMouseMovePointsEx
    directly with
    GMMP_USE_HIGH_RESOLUTION_POINTS
    flag, you should be able to do it by PInvoking to it directly from C#.
     
  3. Arycama

    Arycama

    Joined:
    May 25, 2014
    Posts:
    184
    The values from the input debugger are showing DeltaX/Y as float values, normalized to the screen resolution, and rounded to the nearest integer.

    When setting my high precision mouse to a low dpi setting, the input values remain at zero until the cursor is moved enough for it to move by 1 pixel onscreen. (This is influenced by windows mouse settings such as mouse acceleration and speed in control panel)

    These both suggest that lLastX and lLastY are not being passed through as-is, as they should be signed integers in the range of 0-65535.

    Below is a screenshot of DeltaX/Y from input debugger, showing (25, -1) with no decimal places.
    vlc_2021-10-07_00-38-17.png

    It would be useful if there's a way to access this info without having to do PInvokes etc ourselves, as that's what the input system should be taking care of.

    It's important for games such as first and third person shooters to take advantage of high definition mouse input, and not relying on the screen resolution, and mouse acceleration/speeds set in control panel. Without this control, it's not possible to reach the same responsiveness that other engines and games have.
     
  4. dmytro_at_unity

    dmytro_at_unity

    Unity Technologies

    Joined:
    Feb 12, 2021
    Posts:
    212
    > These both suggest that lLastX and lLastY are not being passed through as-is, as they should be signed integers in the range of 0-65535.

    How do you get float mouse deltas on Windows?

    This is our code for rawinput mouse handling:

    Code (CSharp):
    1.         if (data.usFlags == MOUSE_MOVE_RELATIVE)
    2.         {
    3.             m_Mouse.state.stateData.deltaX = data.lLastX;
    4.             m_Mouse.state.stateData.deltaY = -data.lLastY;
    5.         }
    And from there it goes directly to input system where you can read it. The thing of us presenting it as a float in input debugger is just an implementation detail left to support macOS which does sends float deltas.

    There is also another code branch for
    MOUSE_MOVE_ABSOLUTE
    which does some transformation and might be loosing some precision, but it only should be triggered for RDP/other remote connections from my understanding.
     
  5. Arycama

    Arycama

    Joined:
    May 25, 2014
    Posts:
    184
    After looking into RAWMOUSE documentation, it seems to match the results I'm getting from Unity. It's description matches the issue/limitation I am having too:

    The primary disadvantage to data from WM_MOUSEMOVE is that it is limited to the screen resolution. This means that if you move the mouse slightly — but not enough to cause the pointer to move to the next pixel — then no WM_MOUSEMOVE message is generated. So, using this method to read mouse movement negates the benefits of high-definition input.

    It seems like using WM_INPUT is definitely required to get sub-pixel mouse movement. Is this possible in any way using the current input system? If not, is it the kind of thing Unity is looking to add in the near future?

    Without it, I can't really see the input system being useful to any serious Third or First person shooter, as it's going to feel less precise compared to other engines with proper high resolution mouse support.

    https://docs.microsoft.com/en-us/wi...s/taking-advantage-of-high-dpi-mouse-movement
     
    graphicsayy97 likes this.
  6. dmytro_at_unity

    dmytro_at_unity

    Unity Technologies

    Joined:
    Feb 12, 2021
    Posts:
    212
    WM_INPUT is the only way to get raw input. Our code is almost exact one to one with what they have on MSDN:

    Code (CSharp):
    1. case WM_INPUT:
    2. {
    3.     UINT dwSize = sizeof(RAWINPUT);
    4.     static BYTE lpb[sizeof(RAWINPUT)];
    5.  
    6.     GetRawInputData((HRAWINPUT)lParam, RID_INPUT, lpb, &dwSize, sizeof(RAWINPUTHEADER));
    7.  
    8.     RAWINPUT* raw = (RAWINPUT*)lpb;
    9.  
    10.     if (raw->header.dwType == RIM_TYPEMOUSE)
    11.     {
    12.         int xPosRelative = raw->data.mouse.lLastX;
    13.         int yPosRelative = raw->data.mouse.lLastY;
    14.     }
    15.     break;
    16. }
    Though we flush the raw input queue differently, but we're not processing data any other way AFAIK.

    Are you sure that delta values that you have are incorrect?
    Do you have any other application/test/etc that give you more precise delta values?
     
  7. graphicsayy97

    graphicsayy97

    Joined:
    Dec 24, 2020
    Posts:
    50
    this is insane unity, i am not sure why you change it all, but for even the basic demo scene "SimpleDemo_UsingPlayerInput" you can see major regression for mouse use

    I am lost for words

    i.. i will return to SDL and open GL

    good bye my love Unity (maybe 2019 i will keep as memento)
     
  8. dmytro_at_unity

    dmytro_at_unity

    Unity Technologies

    Joined:
    Feb 12, 2021
    Posts:
    212
  9. Arycama

    Arycama

    Joined:
    May 25, 2014
    Posts:
    184
    I slightly misinterpreted your previous messages, I got RAWINPUT confused with WM_MOUSEMOVE, so thought you were using WM_MOUSEMOVE instead of WM_INPUT, sorry about that.

    As for more info,
    Here's Debug.Logs of action.ReadValue<Vector2> for both mousePosition and mouseDelta input types. Both give rounded values in pixel coordinates, which only update when the cursor has moved a full pixel.

    This is where I'd expect to see fractional values when the mouse is being moved slowly between pixels.

    This also indicates that the mouse events are linked to the cursor, meaning it will be affected by mouse speed and mouse acceleration shared by all windows programs. (However, WM_INPUT specifically says it is not affected by those settings)

    The main symptom is jittery movement when moving the mouse slowly, especially when used for a camera at high mouse sensitivity values.

    Relevant code:

    upload_2021-10-14_1-47-39.png

    (Called from MonoBehaviour.Update)
    upload_2021-10-14_1-47-25.png


    Input setup:
    upload_2021-10-14_1-49-7.png

    Debug logs:
    mousePosition:
    upload_2021-10-14_1-40-50.png

    Mouse delta
    upload_2021-10-14_1-42-3.png
     
  10. dmytro_at_unity

    dmytro_at_unity

    Unity Technologies

    Joined:
    Feb 12, 2021
    Posts:
    212
    I understand your complaint, do you have any other application that uses WM_INPUT and returns you fractional deltas or more smooth deltas for your mouse?
     
  11. Arycama

    Arycama

    Joined:
    May 25, 2014
    Posts:
    184
    After some more research, and implementing my own WM_MOUSE callback into Unity, it seems the values are correct after all.

    I was a bit confused by the microsoft documentation, I thought that a high DPI mouse should be giving me values inbetween pixels. However I had mouse acceleration in windows disabled, and mouse speed set to full in control panel. I believe this creates a 1:1 mapping from mouse DPI to pixels. So I was already getting max precision.

    I compared it to the legacy input system, and the legacy values seem to be exactly 20 times smaller, not sure where this value comes from, or if it differs amongst PCs etc.

    I was also a bit confused by the other posts here about the new input system's mouse input being incorrect.

    I've now turned up the DPI on my mouse, combined with a lower ingame sensitivity and the values are much more smooth.

    I think I was also misled as there are a lot of posts about people not being happy with the new Input system's mouse.. but from what I can understand, it should be exactly the same as the old input, but multiplied by some magic number. (Which appeared to be 20 in this case)

    Perhaps better documentation, or example projects might help with this issue.

    Either way, thanks for taking the time to double check the code and tell me how things are set up on Unity's end, seems like everything is being done correctly, but Unity users aren't necessarily aware of best practices etc.
     
  12. dmytro_at_unity

    dmytro_at_unity

    Unity Technologies

    Joined:
    Feb 12, 2021
    Posts:
    212
    I've checked the code, Windows code for old input system multiplies delta by 0.5f, no idea why, that constant is 12+ years old. And then mouse axis delta gets multiplied by sensitivity, which is 0.1f by default. So it's 20x difference on Windows and likely 10x on other platforms.