C # Get Mouse handle (GetRawInputDeviceInfo)

My goal should be simple ... Take the device handle for the mouse that triggered the click event on my form (I have multiple mice).

In my form, I have encrypted in

    public bool PreFilterMessage(ref Message message) {

      

... to make sure no child controls are skipped (this works fine).

As part of this procedure, I call a class that handles all the required API to capture a device descriptor:

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

      

The hardware ID always shows a different number, even if I click the same mouse.

I suspect that some constants are misconfigured or I am sorting them wrong.

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 and RawDevInfo.mouse.dwId are always different values.

Can anyone identify what I am doing wrong?

+3


source to share


1 answer


After some trial and error, I ended up solving the problem.

I don't quite understand why, but somehow the "mouse button down" messages in the PreFilterMessage () override (and probably wndProc) do not provide enough API information to correctly determine the device / hardware ID.

Instead, I moved the mouse button detection to a class and executed the API for all messages coming through this filter.

I also figured that you should call RegisterRawInputDevices () on your forms first. Refer to it to listen to information about the device.

Complete working code ...



the form:

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).");
        }
    }
}

      

+4


source







All Articles