C# 获取鼠标句柄 (GetRawInputDeviceInfo)
本文关键字:GetRawInputDeviceInfo 句柄 获取 鼠标 | 更新日期: 2023-09-27 17:56:34
我的目标应该很简单...抓住在我的窗体上触发单击事件的鼠标的设备句柄(我有多个鼠标)。
在我的表格上,我已经修补成
public bool PreFilterMessage(ref Message message) {
。以确保没有子控件被遗漏(这工作正常)。
在此例程中,我调用了一个处理所有必要 API 以获取设备句柄的类:
public bool PreFilterMessage(ref Message message) {
switch (message.Msg) {
case 0x0201: //LButtonDown
int HardwareID = new clsGetInputID().GetDeviceID(message);
break;
case 0x204: //RButtonDown
int HardwareID2 = new clsGetInputID().GetDeviceID(message);
break;
}
硬件 ID 总是显示不同的数字,即使我用同一个鼠标单击也是如此。
我怀疑我设置了一些常量不正确,或者我错误地编组了它们。
class clsGetInputID {
[DllImport("User32.dll")]
extern static uint GetRawInputDeviceInfo(IntPtr hDevice, uint uiCommand, IntPtr pData, ref uint pcbSize);
[DllImport("User32.dll")]
extern static uint GetRawInputData(IntPtr hRawInput, uint uiCommand, IntPtr pData, ref uint pcbSize, uint cbSizeHeader);
private const int RID_INPUT = 0x10000003;
[StructLayout(LayoutKind.Sequential)]
internal struct BUTTONSSTR {
[MarshalAs(UnmanagedType.U2)]
public ushort usButtonFlags;
[MarshalAs(UnmanagedType.U2)]
public ushort usButtonData;
}
[StructLayout(LayoutKind.Sequential)]
internal struct RAWHID {
[MarshalAs(UnmanagedType.U4)]
public int dwSizHid;
[MarshalAs(UnmanagedType.U4)]
public int dwCount;
}
[StructLayout(LayoutKind.Explicit)]
internal struct RAWMOUSE {
[MarshalAs(UnmanagedType.U2)]
[FieldOffset(0)]
public ushort usFlags;
[MarshalAs(UnmanagedType.U4)]
[FieldOffset(4)]
public uint ulButtons;
[FieldOffset(4)]
public BUTTONSSTR buttonsStr;
[MarshalAs(UnmanagedType.U4)]
[FieldOffset(8)]
public uint ulRawButtons;
[FieldOffset(12)]
public int lLastX;
[FieldOffset(16)]
public int lLastY;
[MarshalAs(UnmanagedType.U4)]
[FieldOffset(20)]
public uint ulExtraInformation;
}
[StructLayout(LayoutKind.Sequential)]
internal struct RAWKEYBOARD {
[MarshalAs(UnmanagedType.U2)]
public ushort MakeCode;
[MarshalAs(UnmanagedType.U2)]
public ushort Flags;
[MarshalAs(UnmanagedType.U2)]
public ushort Reserved;
[MarshalAs(UnmanagedType.U2)]
public ushort VKey;
[MarshalAs(UnmanagedType.U4)]
public uint Message;
[MarshalAs(UnmanagedType.U4)]
public uint ExtraInformation;
}
[StructLayout(LayoutKind.Explicit)]
internal struct RAWINPUT {
[FieldOffset(0)]
public RAWINPUTHEADER header;
[FieldOffset(16)]
public RAWMOUSE mouse;
[FieldOffset(16)]
public RAWKEYBOARD keyboard;
[FieldOffset(16)]
public RAWHID hid;
}
[StructLayout(LayoutKind.Sequential)]
internal struct RAWINPUTHEADER {
[MarshalAs(UnmanagedType.U4)]
public int dwType;
[MarshalAs(UnmanagedType.U4)]
public int dwSize;
public IntPtr hDevice;
[MarshalAs(UnmanagedType.U4)]
public int wParam;
}
[StructLayout(LayoutKind.Sequential)]
internal struct RID_DEVICE_INFO_HID {
[MarshalAs(UnmanagedType.U4)]
public int dwVendorId;
[MarshalAs(UnmanagedType.U4)]
public int dwProductId;
[MarshalAs(UnmanagedType.U4)]
public int dwVersionNumber;
[MarshalAs(UnmanagedType.U2)]
public ushort usUsagePage;
[MarshalAs(UnmanagedType.U2)]
public ushort usUsage;
}
[StructLayout(LayoutKind.Sequential)]
internal struct RID_DEVICE_INFO_KEYBOARD {
[MarshalAs(UnmanagedType.U4)]
public int dwType;
[MarshalAs(UnmanagedType.U4)]
public int dwSubType;
[MarshalAs(UnmanagedType.U4)]
public int dwKeyboardMode;
[MarshalAs(UnmanagedType.U4)]
public int dwNumberOfFunctionKeys;
[MarshalAs(UnmanagedType.U4)]
public int dwNumberOfIndicators;
[MarshalAs(UnmanagedType.U4)]
public int dwNumberOfKeysTotal;
}
[StructLayout(LayoutKind.Sequential)]
internal struct RID_DEVICE_INFO_MOUSE {
[MarshalAs(UnmanagedType.U4)]
public int dwId;
[MarshalAs(UnmanagedType.U4)]
public int dwNumberOfButtons;
[MarshalAs(UnmanagedType.U4)]
public int dwSampleRate;
[MarshalAs(UnmanagedType.U4)]
public int fHasHorizontalWheel;
}
[StructLayout(LayoutKind.Explicit)]
internal struct RID_DEVICE_INFO {
[FieldOffset(0)]
public int cbSize;
[FieldOffset(4)]
public int dwType;
[FieldOffset(8)]
public RID_DEVICE_INFO_MOUSE mouse;
[FieldOffset(8)]
public RID_DEVICE_INFO_KEYBOARD keyboard;
[FieldOffset(8)]
public RID_DEVICE_INFO_HID hid;
}
public int GetDeviceID(Message message) {
uint dwSize = 0;
GetRawInputData(
message.LParam,
RID_INPUT,
IntPtr.Zero,
ref dwSize,
(uint)Marshal.SizeOf(typeof(RAWINPUTHEADER))
);
IntPtr buffer = Marshal.AllocHGlobal((int)dwSize);
GetRawInputData(
message.LParam,
RID_INPUT,
buffer,
ref dwSize,
(uint)Marshal.SizeOf(typeof(RAWINPUTHEADER))
);
RAWINPUT raw = (RAWINPUT)Marshal.PtrToStructure(buffer, typeof(RAWINPUT));
uint size = (uint)System.Runtime.InteropServices.Marshal.SizeOf(typeof(RID_DEVICE_INFO));
GetRawInputDeviceInfo(raw.header.hDevice, 0x2000000b, IntPtr.Zero, ref size);
IntPtr HardwareRawInfoPTR = Marshal.AllocHGlobal((int)size);
GetRawInputDeviceInfo(raw.header.hDevice, 0x2000000b, HardwareRawInfoPTR, ref size);
RID_DEVICE_INFO RawDevInfo = (RID_DEVICE_INFO)Marshal.PtrToStructure(HardwareRawInfoPTR, typeof(RID_DEVICE_INFO));
Marshal.FreeHGlobal(buffer);
System.Diagnostics.Debug.WriteLine(String.Format("hDevice: {0} HdHandle: {1}", raw.header.hDevice, RawDevInfo.mouse.dwId));
return RawDevInfo.mouse.dwId;
}
}
raw.header.hDevice 和 RawDevInfo.mouse.dwId 总是不同的值。
有人能发现我做错了什么吗?
经过一番试验和错误,我最终解决了这个问题。
我不完全明白为什么,但由于某种原因,PreFilterMessage()(可能还有 wndProc)覆盖中的"鼠标按下"消息没有向 API 提供足够的信息来正确确定设备/硬件 ID。
相反,我将鼠标按钮检测移到类中,并对通过此过滤器的所有消息执行 API。
我还确定您必须首先针对表单句柄调用 RegisterRawInputDevices(),以便它侦听设备信息。
完整的工作代码...
形式:
public partial class frmQuizMaster : Form, IMessageFilter {
clsGetInputID MouseHandler;
// Initialization
public frmQuizMaster() {
InitializeComponent();
Application.AddMessageFilter(this);
}
private void frmQuizMaster_Load(object sender, EventArgs e) {
MouseHandler = new clsGetInputID(this.Handle);
}
private void frmQuizMaster_FormClosing(object sender, FormClosingEventArgs e) {
Application.RemoveMessageFilter(this);
}
public bool PreFilterMessage(ref Message message) {
int HardID = MouseHandler.GetDeviceID(message);
if (HardID > 0) {
System.Diagnostics.Debug.WriteLine("Device ID : " + HardID.ToString());
//Return true here if you want to supress the mouse click
//bear in mind that mouse down and up messages will still pass through, so you will need to filter these out and return true also.
}
return false;
}
clsGetInputID:
class clsGetInputID {
private const int RID_INPUT = 0x10000003;
private const int RIDEV_INPUTSINK = 0x00000100;
[DllImport("user32.dll", SetLastError = true)]
extern static uint GetRawInputDeviceInfo(IntPtr hDevice, uint uiCommand, IntPtr pData, ref uint pcbSize);
[DllImport("User32.dll")]
extern static uint GetRawInputData(IntPtr hRawInput, uint uiCommand, IntPtr pData, ref uint pcbSize, uint cbSizeHeader);
[DllImport("User32.dll")]
extern static bool RegisterRawInputDevices(RAWINPUTDEVICE[] pRawInputDevice, uint uiNumDevices, uint cbSize);
[Flags()]
public enum RawMouseFlags : ushort {
/// <summary>Relative to the last position.</summary>
MoveRelative = 0,
/// <summary>Absolute positioning.</summary>
MoveAbsolute = 1,
/// <summary>Coordinate data is mapped to a virtual desktop.</summary>
VirtualDesktop = 2,
/// <summary>Attributes for the mouse have changed.</summary>
AttributesChanged = 4
}
[Flags()]
public enum RawMouseButtons : ushort {
/// <summary>No button.</summary>
None = 0,
/// <summary>Left (button 1) down.</summary>
LeftDown = 0x0001,
/// <summary>Left (button 1) up.</summary>
LeftUp = 0x0002,
/// <summary>Right (button 2) down.</summary>
RightDown = 0x0004,
/// <summary>Right (button 2) up.</summary>
RightUp = 0x0008,
/// <summary>Middle (button 3) down.</summary>
MiddleDown = 0x0010,
/// <summary>Middle (button 3) up.</summary>
MiddleUp = 0x0020,
/// <summary>Button 4 down.</summary>
Button4Down = 0x0040,
/// <summary>Button 4 up.</summary>
Button4Up = 0x0080,
/// <summary>Button 5 down.</summary>
Button5Down = 0x0100,
/// <summary>Button 5 up.</summary>
Button5Up = 0x0200,
/// <summary>Mouse wheel moved.</summary>
MouseWheel = 0x0400
}
[StructLayout(LayoutKind.Sequential)]
internal struct RAWINPUTDEVICE {
[MarshalAs(UnmanagedType.U2)]
public ushort usUsagePage;
[MarshalAs(UnmanagedType.U2)]
public ushort usUsage;
[MarshalAs(UnmanagedType.U4)]
public int dwFlags;
public IntPtr hwndTarget;
}
[StructLayout(LayoutKind.Sequential)]
internal struct RAWHID {
[MarshalAs(UnmanagedType.U4)]
public int dwSizHid;
[MarshalAs(UnmanagedType.U4)]
public int dwCount;
}
[StructLayout(LayoutKind.Explicit)]
public struct RawMouse {
/// <summary>
/// The mouse state.
/// </summary>
[FieldOffset(0)]
public RawMouseFlags Flags;
/// <summary>
/// Flags for the event.
/// </summary>
[FieldOffset(4)]
public RawMouseButtons ButtonFlags;
/// <summary>
/// If the mouse wheel is moved, this will contain the delta amount.
/// </summary>
[FieldOffset(6)]
public ushort ButtonData;
/// <summary>
/// Raw button data.
/// </summary>
[FieldOffset(8)]
public uint RawButtons;
/// <summary>
/// The motion in the X direction. This is signed relative motion or
/// absolute motion, depending on the value of usFlags.
/// </summary>
[FieldOffset(12)]
public int LastX;
/// <summary>
/// The motion in the Y direction. This is signed relative motion or absolute motion,
/// depending on the value of usFlags.
/// </summary>
[FieldOffset(16)]
public int LastY;
/// <summary>
/// The device-specific additional information for the event.
/// </summary>
[FieldOffset(20)]
public uint ExtraInformation;
}
[StructLayout(LayoutKind.Sequential)]
internal struct RAWKEYBOARD {
[MarshalAs(UnmanagedType.U2)]
public ushort MakeCode;
[MarshalAs(UnmanagedType.U2)]
public ushort Flags;
[MarshalAs(UnmanagedType.U2)]
public ushort Reserved;
[MarshalAs(UnmanagedType.U2)]
public ushort VKey;
[MarshalAs(UnmanagedType.U4)]
public uint Message;
[MarshalAs(UnmanagedType.U4)]
public uint ExtraInformation;
}
public enum RawInputType {
/// <summary>
/// Mouse input.
/// </summary>
Mouse = 0,
/// <summary>
/// Keyboard input.
/// </summary>
Keyboard = 1,
/// <summary>
/// Another device that is not the keyboard or the mouse.
/// </summary>
HID = 2
}
[StructLayout(LayoutKind.Explicit)]
internal struct RawInput {
/// <summary>Header for the data.</summary>
[FieldOffset(0)]
public RawInputHeader Header;
/// <summary>Mouse raw input data.</summary>
[FieldOffset(16)]
public RawMouse Mouse;
/// <summary>Keyboard raw input data.</summary>
[FieldOffset(16)]
public RAWKEYBOARD Keyboard;
/// <summary>HID raw input data.</summary>
[FieldOffset(16)]
public RAWHID Hid;
}
[StructLayout(LayoutKind.Sequential)]
internal struct RawInputHeader {
/// <summary>Type of device the input is coming from.</summary>
public RawInputType Type;
/// <summary>Size of the packet of data.</summary>
public int Size;
/// <summary>Handle to the device sending the data.</summary>
public IntPtr Device;
/// <summary>wParam from the window message.</summary>
public IntPtr wParam;
}
public bool LockForBuzzersOnly = true;
public List<int> BuzzerDevices = new List<int>();
public int GetDeviceID(Message message) {
uint dwSize = 0;
GetRawInputData(
message.LParam,
RID_INPUT,
IntPtr.Zero,
ref dwSize,
(uint)Marshal.SizeOf(typeof(RawInputHeader))
);
IntPtr buffer = Marshal.AllocHGlobal((int)dwSize);
GetRawInputData(
message.LParam,
RID_INPUT,
buffer,
ref dwSize,
(uint)Marshal.SizeOf(typeof(RawInputHeader))
);
RawInput raw = (RawInput)Marshal.PtrToStructure(buffer, typeof(RawInput));
Marshal.FreeHGlobal(buffer);
if (raw.Mouse.ButtonFlags == RawMouseButtons.LeftDown || raw.Mouse.ButtonFlags == RawMouseButtons.RightDown) {
return (int)raw.Header.Device;
} else {
return 0;
}
}
public clsGetInputID(IntPtr hwnd) {
RAWINPUTDEVICE[] rid = new RAWINPUTDEVICE[1];
rid[0].usUsagePage = 0x01;
rid[0].usUsage = 0x02;
rid[0].dwFlags = RIDEV_INPUTSINK;
rid[0].hwndTarget = hwnd;
if (!RegisterRawInputDevices(rid, (uint)rid.Length, (uint)Marshal.SizeOf(rid[0]))) {
throw new ApplicationException("Failed to register raw input device(s).");
}
}
}