David Michael Huber David Michael Huber - 3 months ago 7
C# Question

Weird values from WM_INPUT, casting mistake?

About



I am trying to get the raw mouse input of the system into a C# application. I am using
WM_INPUT
(MSDN link) to get access to the data. To do so I am using the user32.dll. This (stackoverflow link) helped me alot with writing the API Wrapper.

Current approach



The following snippet shows the
WndProc
method.
rimTypeMouseCount
already shows that the windows messages seem to get fetched correctly. When I turn the polling rate of my mouse up or down I can see this also by checking the count - Lower polling rate means a lower count, higher polling rate means a higher count while logging for equal time intervals. That's good so far.

WndProc callback method:



protected override void WndProc(ref Message m)
{
if (m.Msg == 0x00ff) {
uint dwSize = 40;

byte[] raw = new byte[40];
IntPtr rawPtr = Marshal.AllocHGlobal(raw.Length);

APIWrapper.GetRawInputData((IntPtr)m.LParam, 0x10000003, rawPtr, ref dwSize, Marshal.SizeOf(new APIWrapper.RAWINPUTHEADER()));

Marshal.Copy(rawPtr, raw, 0, 40);

GCHandle handle = GCHandle.Alloc(raw, GCHandleType.Pinned);
APIWrapper.RAWINPUT rawData = (APIWrapper.RAWINPUT)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(APIWrapper.RAWINPUT));
handle.Free();

if (rawData.header.dwType == 0)
{
rimTypeMouseCount++;
logMouseX = logMouseX + rawData.mouse.lLastX.ToString() + Environment.NewLine;
logMouseY = logMouseY + rawData.mouse.lLastY.ToString() + Environment.NewLine;
}
}

base.WndProc(ref m);
}


RAWINPUT struct:



[StructLayout(LayoutKind.Explicit)]
internal struct RAWINPUT
{
[FieldOffset(0)]
public RAWINPUTHEADER header;

[FieldOffset(16 + 8)]
public RAWMOUSE mouse;

[FieldOffset(16 + 8)]
public RAWKEYBOARD keyboard;

[FieldOffset(16 + 8)]
public RAWHID hid;
}


Problem



But there is a problem with
logMouseX
and
logMouseY
. Those to strings simply append the mouse deltas of the x and y axis with every call. Unfortunately
logMouseX
only logs the values 0 or 65535 while
logMouseY
logs 0 only. I also tried to log messages like left mouse button up/down and so on. Nothing seems to work actually. For me it seems a little that the numbers might be random or something like that.

Question



This is what I (think I) do:


  1. APIWrapper.GetRawInputData(...)
    needs a pointer to a byte array. So I simply allocated space in unmanaged memory with marshalling and got a pointer as a result.

  2. I am calling the function that fills the array the pointer is pointing at.

  3. I am taking the pointer that points to the filled array and copy its content into an actual byte array.

  4. To access the fields of the struct
    RAWINPUT
    I need to cast the byte array to a
    RAWINPUT
    struct.

  5. I do this with the three lines that use a GCHandle. I actually found that snippet somewhere but never worked with that class before.



Might it be that I am messing up something there? Maybe something like a Big-Endian and Little-Endian mix up?

Edits




  • I found out that the values I get when using
    rawData.mouse.lLastX
    &
    rawData.mouse.lLastY
    behave like this:


    • X is zero when moving the mouse downwards and 65535 when moving upwards

    • Y is zero always no matter if I move the mouse left or right


  • I found out that using
    rawDataL.hid.pbRawData
    includes more information about the movement. There I get values in dependency of how fast I am moving the mouse. Unfortunately there is no X or Y component so this only works for one axis (downwards/upwards).

  • I found a simpler way of casts. Unfortunately I still get the stranges values as described above. It looks like this now:



Casting part of WndProc:



uint dwSize = 40;

byte[] raw = new byte[40];
GCHandle handle = GCHandle.Alloc(raw, GCHandleType.Pinned);

APIWrapper.GetRawInputData((IntPtr)m.LParam, 0x10000003, handle.AddrOfPinnedObject(), ref dwSize, Marshal.SizeOf(new APIWrapper.RAWINPUTHEADER()));

APIWrapper.RAWINPUT rawData = (APIWrapper.RAWINPUT)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(APIWrapper.RAWINPUT));

if (rawData.header.dwType == 0)
{
// accessing data
}

handle.Free();

Answer

I posted my question here (MSDN link) and I was told that the offsets of the RAWMOUSE struct are not correct.

So I simply logged all bytes of the raw data array and finally could see all the data I need and therefore the correct offsets. I guess the offsets differ when using 32 bit or 64 bit machines. Here are the relevant code changes:

WndProc changes:

RawMouseData rawData = (RawMouseData) Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(RawMouseData));

RawMouseData struct:

[StructLayout(LayoutKind.Explicit)]
internal struct RawMouseData
{
    [FieldOffset(20)]
    public ButtonFlags buttonFlags;
    [FieldOffset(22)]
    public ushort buttonData;
    [FieldOffset(28)]
    public int lastX;
    [FieldOffset(32)]
    public int lastY;
}

This is how the data log of the raw byte array looks like for each mouse movement direction:

Downwards:      Upwards:
Byte 29: 0      Byte 29: 0 
Byte 30: 0      Byte 30: 0 
Byte 31: 0      Byte 31: 0 
Byte 32: 0      Byte 32: 0 
Byte 33: 1      Byte 33: 255 
Byte 34: 0      Byte 34: 255 
Byte 35: 0      Byte 35: 255 
Byte 36: 0      Byte 36: 255

Left:           Right:
Byte 29: 255    Byte 29: 1 
Byte 30: 255    Byte 30: 0 
Byte 31: 255    Byte 31: 0 
Byte 32: 255    Byte 32: 0 
Byte 33: 0      Byte 33: 0 
Byte 34: 0      Byte 34: 0 
Byte 35: 0      Byte 35: 0 
Byte 36: 0      Byte 36: 0 

The faster I move the mouse the bigger (when moving downwards or right) or smaller (when moving upwards or left) the values get.

Comments