Manage more mice using VB.net

skipper guerrini 1 Reputation point
2021-01-03T09:25:49.52+00:00

Hi All,

i have a lot of mice connected to the pc, i would like to create a program that recognizes which of these mice did the "click" action. I've been trying for days, but without success...

Can someone help me?

thanks

Skipper

VB
VB
An object-oriented programming language developed by Microsoft that is implemented on the .NET Framework. Previously known as Visual Basic .NET.
2,642 questions
{count} votes

2 answers

Sort by: Most helpful
  1. Castorix31 82,751 Reputation points
    2021-01-03T17:03:09.32+00:00

    This test identifies the device (VID/PID) on my OS (Windows 10, test with 2 mice) with RIDI_DEVICENAME (I commented the call with RIDI_DEVICEINFO because it reports always the same values for my 2 mice but you can uncomment it to check...)

    Imports System.Runtime.InteropServices
    
    Public Class Form1
    
        <DllImport("User32.dll", CharSet:=CharSet.Unicode, SetLastError:=True)>
        Public Shared Function RegisterRawInputDevices(ByRef pRawInputDevices As RAWINPUTDEVICE, uiNumDevices As UInteger, cbSize As UInteger) As Boolean
        End Function
    
        <DllImport("User32.dll", CharSet:=CharSet.Unicode, SetLastError:=True)>
        Public Shared Function GetRawInputData(ByVal hRawInput As IntPtr, ByVal uiCommand As UInteger, <Out> ByRef pData As RAWINPUT, <[In], Out> ByRef pcbSize As UInteger, ByVal cbSizeHeader As UInteger) As Integer
        End Function
    
        <DllImport("User32.dll", CharSet:=CharSet.Unicode, SetLastError:=True)>
        Public Shared Function GetRawInputDeviceInfo(ByVal hDevice As IntPtr, ByVal uiCommand As UInteger, ByVal pData As IntPtr, <[In], Out> ByRef pcbSize As UInteger) As Integer
        End Function
    
        Public Const RIDI_PREPARSEDDATA = &H20000005
        Public Const RIDI_DEVICENAME = &H20000007 ' the Return valus Is the character length, Not the Byte size
        Public Const RIDI_DEVICEINFO = &H2000000B
    
        Public Const RID_INPUT = &H10000003
        Public Const RID_HEADER = &H10000005
    
        Public Const RIM_TYPEMOUSE = 0
        Public Const RIM_TYPEKEYBOARD = 1
        Public Const RIM_TYPEHID = 2
        Public Const RIM_TYPEMAX = 2
    
        Public Structure RAWINPUTHEADER
            Public dwType As UInteger
            Public dwSize As UInteger
            Public hDevice As IntPtr
            Public wParam As Short
        End Structure
    
        <StructLayout(LayoutKind.Explicit, Pack:=1)>
        Public Structure RAWINPUT
            <FieldOffset(0)>
            Public Header As RAWINPUTHEADER
            <FieldOffset(16)>
            Public Mouse As RAWMOUSE
            <FieldOffset(16)>
            Public Keyboard As RAWKEYBOARD
            <FieldOffset(16)>
            Public HID As RAWHID
        End Structure
    
        <StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Unicode, Pack:=1)>
        Public Structure RAWHID
            Public dwSizeHid As UInteger
            Public dwCount As UInteger
            Public bRawData As IntPtr
        End Structure
    
        <StructLayout(LayoutKind.Sequential)>
        Public Structure RAWMOUSE
            Public usFlags As UShort
            <StructLayout(LayoutKind.Explicit)>
            Public Structure Union
                <FieldOffset(0)>
                Public ulButtons As UInteger
                <FieldOffset(2)>
                Public usButtonData As UShort
                <FieldOffset(0)>
                Public usButtonFlags As UShort
            End Structure
            Public Data As Union
            Public ulRawButtons As UInteger
            Public lLastX As Integer
            Public lLastY As Integer
            Public ulExtraInformation As UInteger
        End Structure
    
        <StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Unicode, Pack:=1)>
        Public Structure RAWKEYBOARD
            Public MakeCode As UShort
            Public Flags As UShort
            Public Reserved As UShort
            Public VKey As UShort
            Public Message As UInteger
            Public ExtraInformation As UInteger
        End Structure
    
        Public Const WM_INPUT = &HFF
    
        <StructLayout(LayoutKind.Sequential)>
        Public Structure RAWINPUTDEVICE
            Public usUsagePage As UShort
            Public usUsage As UShort
            Public dwFlags As UInteger
            Public hwndTarget As IntPtr
        End Structure
    
        Public Const RIDEV_REMOVE = &H1
        Public Const RIDEV_EXCLUDE = &H10
        Public Const RIDEV_PAGEONLY = &H20
        Public Const RIDEV_NOLEGACY = &H30
        Public Const RIDEV_INPUTSINK = &H100
        Public Const RIDEV_CAPTUREMOUSE = &H200  'effective when mouse nolegacy is specified, otherwise it would be an error
        Public Const RIDEV_NOHOTKEYS = &H200  'effective for keyboard.
        Public Const RIDEV_APPKEYS = &H400  'effective for keyboard.
        Public Const RIDEV_EXINPUTSINK = &H1000
        Public Const RIDEV_DEVNOTIFY = &H2000
        Public Const RIDEV_EXMODEMASK = &HF0
        Public Shared Function RIDEV_EXMODE(mode As Integer) As Integer
            Return mode And RIDEV_EXMODEMASK
        End Function
    
        <StructLayout(LayoutKind.Sequential)>
        Public Structure RID_DEVICE_INFO_MOUSE
            Public dwId As UInteger
            Public dwNumberOfButtons As UInteger
            Public dwSampleRate As UInteger
        End Structure
    
        <StructLayout(LayoutKind.Sequential)>
        Public Structure RID_DEVICE_INFO_KEYBOARD
            Public dwType As UInteger
            Public dwSubType As UInteger
            Public dwKeyboardMode As UInteger
            Public dwNumberOfFunctionKeys As UInteger
            Public dwNumberOfIndicators As UInteger
            Public dwNumberOfKeysTotal As UInteger
        End Structure
    
        <StructLayout(LayoutKind.Sequential)>
        Public Structure RID_DEVICE_INFO_HID
            Public dwVendorId As UInteger
            Public dwProductId As UInteger
            Public dwVersionNumber As UInteger
            Public usUsagePage As UShort
            Public usUsage As UShort
        End Structure
    
        <StructLayout(LayoutKind.Explicit)>
        Public Structure RID_DEVICE_INFO
            <FieldOffset(0)>
            Public cbSize As UInteger
            <FieldOffset(4)>
            Public dwType As UInteger
            <FieldOffset(8)>
            Public mouse As RID_DEVICE_INFO_MOUSE
            <FieldOffset(8)>
            Public keyboard As RID_DEVICE_INFO_KEYBOARD
            <FieldOffset(8)>
            Public hid As RID_DEVICE_INFO_HID
        End Structure
    
        ' "C:\WINDOWS\System32\rundll32.exe" C:\WINDOWS\System32\shell32.dll,Control_RunDLL C:\WINDOWS\System32\main.cpl
    
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            Dim rid As RAWINPUTDEVICE = New RAWINPUTDEVICE()
            rid.usUsagePage = &H1 ' HID_USAGE_PAGE_GENERIC 
            rid.usUsage = &H2 ' HID_USAGE_GENERIC_MOUSE 
            rid.dwFlags = RIDEV_INPUTSINK
            rid.hwndTarget = Me.Handle
            Dim bRet As Boolean = RegisterRawInputDevices(rid, 1, Marshal.SizeOf(rid))
        End Sub
    
        Protected Overrides Sub WndProc(ByRef m As Message)
            If m.Msg = WM_INPUT Then
                Dim ri As RAWINPUT = New RAWINPUT()
                Dim nRiSize As UInteger = Marshal.SizeOf(GetType(RAWINPUT)) ' 40
                Dim inputData As Integer = GetRawInputData(m.LParam, RID_INPUT, ri, nRiSize, Marshal.SizeOf(GetType(RAWINPUTHEADER)))
                If (inputData <> -1) Then
                    If (ri.Header.dwType = RIM_TYPEMOUSE) Then
                        Console.WriteLine("hDevice : {0}, Button Flags : {1}", ri.Header.hDevice, ri.Mouse.Data.usButtonFlags)
                        Dim nStringLength As Integer = 512
                        Dim pStringBuffer As IntPtr = Marshal.AllocHGlobal(nStringLength)
                        Dim nRetSize As Integer = GetRawInputDeviceInfo(ri.Header.hDevice, RIDI_DEVICENAME, pStringBuffer, nStringLength)
                        If (nRetSize <> -1) Then
                            Dim sDeviceName As String = Marshal.PtrToStringUni(pStringBuffer)
                            Console.WriteLine("Device Name : {0}", sDeviceName)
                            'Dim nLength As Integer = Marshal.SizeOf(GetType(RID_DEVICE_INFO))
                            'Dim pBuffer As IntPtr = Marshal.AllocHGlobal(nLength)
                            'nRetSize = GetRawInputDeviceInfo(ri.Header.hDevice, RIDI_DEVICEINFO, pBuffer, nLength)
                            'If (nRetSize <> -1) Then
                            '    Dim rdi As RID_DEVICE_INFO = CType(Marshal.PtrToStructure(pBuffer, GetType(RID_DEVICE_INFO)), RID_DEVICE_INFO)
                            '    Console.WriteLine("Mouse ID : {0}, Number of Buttons: {1}", rdi.mouse.dwId, rdi.mouse.dwNumberOfButtons)
                            'End If
                        End If
                        Marshal.FreeHGlobal(pStringBuffer)
                    End If
                End If
            Else
                    MyBase.WndProc(m)
            End If
        End Sub
    End Class
    
    1 person found this answer helpful.
    0 comments No comments

  2. skipper guerrini 1 Reputation point
    2021-01-04T13:30:51.937+00:00

    Thanks Castorix, i already have the mouse ID, but how could know when i use the first one or the second one?