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:
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.- I am calling the function that fills the array the pointer is pointing at.
- I am taking the pointer that points to the filled array and copy its content into an actual byte array.
- To access the fields of the struct
RAWINPUT
I need to cast the byte array to aRAWINPUT
struct. - 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();