来自 WM_INPUT 的奇怪值,转换错误?

Weird values from WM_INPUT, casting mistake?

关于

我正在尝试将系统的原始鼠标输入输入到 C# 应用程序中。我正在使用 WM_INPUT (MSDN link) to get access to the data. To do so I am using the user32.dll. This (Whosebug link) 帮助我编写 API Wrapper。

当前方法

以下代码段显示了 WndProc 方法。 rimTypeMouseCount 已经显示 windows 消息似乎已正确获取。当我调高或调低鼠标的轮询率时,我也可以通过检查计数看到这一点——较低的轮询率意味着较低的计数,较高的轮询率意味着较高的计数,同时记录相同的时间间隔。到目前为止还不错。

WndProc回调方法:

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 结构:

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

问题

但是logMouseXlogMouseY有问题。那些字符串只是在每次调用时附加 x 和 y 轴的鼠标增量。不幸的是,logMouseX 仅记录值 0 或 65535,而 logMouseY 仅记录 0。我还尝试记录鼠标左键 up/down 等消息。实际上似乎没有任何效果。对我来说,数字可能是随机的或类似的东西似乎有点。

问题

这就是我(认为我)所做的:

  1. APIWrapper.GetRawInputData(...) 需要一个指向字节数组的指针。因此,我只是通过编组在非托管内存中分配了 space,结果得到了一个指针。
  2. 我正在调用填充指针指向的数组的函数。
  3. 我正在使用指向填充数组的指针并将其内容复制到实际的字节数组中。
  4. 要访问结构 RAWINPUT 的字段,我需要将字节数组转换为 RAWINPUT 结构。
  5. 我使用使用 GCHandle 的三行来执行此操作。我实际上在某处找到了该片段,但之前从未使用过 class。

可能是我搞砸了什么?也许像 Big-Endian 和 Little-Endian 混淆了?

编辑

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();

我在这里发布了我的问题 (MSDN link),我被告知 RAWMOUSE 结构的偏移量不正确。

所以我简单地记录了原始数据数组的所有字节,最终可以看到我需要的所有数据以及正确的偏移量。我想使用 32 位或 64 位机器时偏移量会有所不同。以下是相关代码更改:

WndProc 更改:

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

RawMouseData 结构:

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

这是每个鼠标移动方向的原始字节数组数据日志的样子:

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 

鼠标移动得越快,值越大(向下或向右移动时)或越小(向上或向左移动时)。