来自 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;
}
问题
但是logMouseX
和logMouseY
有问题。那些字符串只是在每次调用时附加 x 和 y 轴的鼠标增量。不幸的是,logMouseX
仅记录值 0 或 65535,而 logMouseY
仅记录 0。我还尝试记录鼠标左键 up/down 等消息。实际上似乎没有任何效果。对我来说,数字可能是随机的或类似的东西似乎有点。
问题
这就是我(认为我)所做的:
APIWrapper.GetRawInputData(...)
需要一个指向字节数组的指针。因此,我只是通过编组在非托管内存中分配了 space,结果得到了一个指针。
- 我正在调用填充指针指向的数组的函数。
- 我正在使用指向填充数组的指针并将其内容复制到实际的字节数组中。
- 要访问结构
RAWINPUT
的字段,我需要将字节数组转换为 RAWINPUT
结构。
- 我使用使用 GCHandle 的三行来执行此操作。我实际上在某处找到了该片段,但之前从未使用过 class。
可能是我搞砸了什么?也许像 Big-Endian 和 Little-Endian 混淆了?
编辑
我发现使用 rawData.mouse.lLastX
& rawData.mouse.lLastY
时得到的值是这样的:
- 向下移动鼠标X为0,向上移动鼠标X为65535
- 无论我向左或向右移动鼠标,Y 始终为零
我发现使用 rawDataL.hid.pbRawData
包含更多关于机芯的信息。在那里我得到的值取决于我移动鼠标的速度。不幸的是,没有 X 或 Y 分量,因此这仅适用于一个轴 (downwards/upwards)。
- 我发现了一种更简单的转换方式。不幸的是,我仍然得到如上所述的奇怪值。现在看起来像这样:
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
鼠标移动得越快,值越大(向下或向右移动时)或越小(向上或向左移动时)。
关于
我正在尝试将系统的原始鼠标输入输入到 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;
}
问题
但是logMouseX
和logMouseY
有问题。那些字符串只是在每次调用时附加 x 和 y 轴的鼠标增量。不幸的是,logMouseX
仅记录值 0 或 65535,而 logMouseY
仅记录 0。我还尝试记录鼠标左键 up/down 等消息。实际上似乎没有任何效果。对我来说,数字可能是随机的或类似的东西似乎有点。
问题
这就是我(认为我)所做的:
APIWrapper.GetRawInputData(...)
需要一个指向字节数组的指针。因此,我只是通过编组在非托管内存中分配了 space,结果得到了一个指针。- 我正在调用填充指针指向的数组的函数。
- 我正在使用指向填充数组的指针并将其内容复制到实际的字节数组中。
- 要访问结构
RAWINPUT
的字段,我需要将字节数组转换为RAWINPUT
结构。 - 我使用使用 GCHandle 的三行来执行此操作。我实际上在某处找到了该片段,但之前从未使用过 class。
可能是我搞砸了什么?也许像 Big-Endian 和 Little-Endian 混淆了?
编辑
我发现使用
rawData.mouse.lLastX
&rawData.mouse.lLastY
时得到的值是这样的:- 向下移动鼠标X为0,向上移动鼠标X为65535
- 无论我向左或向右移动鼠标,Y 始终为零
我发现使用
rawDataL.hid.pbRawData
包含更多关于机芯的信息。在那里我得到的值取决于我移动鼠标的速度。不幸的是,没有 X 或 Y 分量,因此这仅适用于一个轴 (downwards/upwards)。- 我发现了一种更简单的转换方式。不幸的是,我仍然得到如上所述的奇怪值。现在看起来像这样:
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
鼠标移动得越快,值越大(向下或向右移动时)或越小(向上或向左移动时)。