RawInput.cs
author StephaneLenclud
Sun, 15 Feb 2015 20:28:46 +0100
changeset 62 bc92e2648220
parent 61 60bfe5083721
child 63 4b8b058de215
permissions -rw-r--r--
Device list now showing usage collection string.
sl@10
     1
using System;
sl@10
     2
using System.Runtime.InteropServices;
sl@10
     3
using System.Diagnostics;
StephaneLenclud@60
     4
using System.Windows.Forms;
sl@10
     5
sl@10
     6
StephaneLenclud@60
     7
namespace Win32
sl@10
     8
{
sl@17
     9
    /// <summary>
sl@17
    10
    /// Provide some utility functions for raw input handling.
sl@17
    11
    /// </summary>
sl@10
    12
    static class RawInput
sl@10
    13
    {
sl@10
    14
        /// <summary>
sl@10
    15
        /// 
sl@10
    16
        /// </summary>
sl@10
    17
        /// <param name="aRawInputHandle"></param>
sl@10
    18
        /// <param name="aRawInput"></param>
sl@10
    19
        /// <param name="rawInputBuffer">Caller must free up memory on the pointer using Marshal.FreeHGlobal</param>
sl@10
    20
        /// <returns></returns>
sl@10
    21
        public static bool GetRawInputData(IntPtr aRawInputHandle, ref RAWINPUT aRawInput, ref IntPtr rawInputBuffer)
sl@10
    22
        {
sl@10
    23
            bool success = true;
sl@10
    24
            rawInputBuffer = IntPtr.Zero;
sl@10
    25
sl@10
    26
            try
sl@10
    27
            {
sl@10
    28
                uint dwSize = 0;
sl@10
    29
                uint sizeOfHeader = (uint)Marshal.SizeOf(typeof(RAWINPUTHEADER));
sl@10
    30
sl@10
    31
                //Get the size of our raw input data.
sl@10
    32
                Win32.Function.GetRawInputData(aRawInputHandle, Const.RID_INPUT, IntPtr.Zero, ref dwSize, sizeOfHeader);
sl@10
    33
sl@10
    34
                //Allocate a large enough buffer
sl@10
    35
                 rawInputBuffer = Marshal.AllocHGlobal((int)dwSize);
sl@10
    36
sl@10
    37
                //Now read our RAWINPUT data
sl@10
    38
                if (Win32.Function.GetRawInputData(aRawInputHandle, Const.RID_INPUT, rawInputBuffer, ref dwSize, (uint)Marshal.SizeOf(typeof(RAWINPUTHEADER))) != dwSize)
sl@10
    39
                {
sl@10
    40
                    return false;
sl@10
    41
                }
sl@10
    42
sl@10
    43
                //Cast our buffer
sl@10
    44
                aRawInput = (RAWINPUT)Marshal.PtrToStructure(rawInputBuffer, typeof(RAWINPUT));
sl@10
    45
            }
sl@10
    46
            catch
sl@10
    47
            {
sl@10
    48
                Debug.WriteLine("GetRawInputData failed!");
sl@10
    49
                success = false;
sl@10
    50
            }
sl@10
    51
sl@10
    52
            return success;
sl@10
    53
        }
sl@10
    54
sl@10
    55
        /// <summary>
sl@10
    56
        /// 
sl@10
    57
        /// </summary>
sl@47
    58
        /// <param name="hDevice"></param>
sl@47
    59
        /// <param name="deviceInfo"></param>
sl@10
    60
        /// <returns></returns>
sl@10
    61
        public static bool GetDeviceInfo(IntPtr hDevice, ref RID_DEVICE_INFO deviceInfo)
sl@10
    62
        {
sl@10
    63
            bool success = true;
sl@10
    64
            IntPtr deviceInfoBuffer = IntPtr.Zero;
sl@10
    65
            try
sl@10
    66
            {
sl@10
    67
                //Get Device Info
sl@10
    68
                uint deviceInfoSize = (uint)Marshal.SizeOf(typeof(RID_DEVICE_INFO));
sl@10
    69
                deviceInfoBuffer = Marshal.AllocHGlobal((int)deviceInfoSize);
sl@10
    70
StephaneLenclud@60
    71
                int res = Win32.Function.GetRawInputDeviceInfo(hDevice, Win32.RawInputDeviceInfoType.RIDI_DEVICEINFO, deviceInfoBuffer, ref deviceInfoSize);
sl@10
    72
                if (res <= 0)
sl@10
    73
                {
sl@10
    74
                    Debug.WriteLine("WM_INPUT could not read device info: " + Marshal.GetLastWin32Error().ToString());
sl@10
    75
                    return false;
sl@10
    76
                }
sl@10
    77
sl@10
    78
                //Cast our buffer
sl@10
    79
                deviceInfo = (RID_DEVICE_INFO)Marshal.PtrToStructure(deviceInfoBuffer, typeof(RID_DEVICE_INFO));
sl@10
    80
            }
sl@10
    81
            catch
sl@10
    82
            {
sl@10
    83
                Debug.WriteLine("GetRawInputData failed!");
sl@10
    84
                success = false;
sl@10
    85
            }
sl@10
    86
            finally
sl@10
    87
            {
sl@10
    88
                //Always executes, prevents memory leak
sl@10
    89
                Marshal.FreeHGlobal(deviceInfoBuffer);
sl@10
    90
            }
sl@10
    91
sl@10
    92
            
sl@10
    93
            return success;
sl@10
    94
        }
sl@10
    95
sl@17
    96
        /// <summary>
sl@19
    97
        /// Fetch pre-parsed data corresponding to HID descriptor for the given HID device.
sl@17
    98
        /// </summary>
sl@17
    99
        /// <param name="device"></param>
sl@17
   100
        /// <returns></returns>
sl@17
   101
        public static IntPtr GetPreParsedData(IntPtr hDevice)
sl@17
   102
        {
StephaneLenclud@60
   103
            uint ppDataSize = 0;
StephaneLenclud@60
   104
            int result = Win32.Function.GetRawInputDeviceInfo(hDevice, RawInputDeviceInfoType.RIDI_PREPARSEDDATA, IntPtr.Zero, ref ppDataSize);
sl@17
   105
            if (result != 0)
sl@17
   106
            {
sl@17
   107
                Debug.WriteLine("Failed to get raw input pre-parsed data size" + result + Marshal.GetLastWin32Error());
sl@17
   108
                return IntPtr.Zero;
sl@17
   109
            }
sl@17
   110
sl@17
   111
            IntPtr ppData = Marshal.AllocHGlobal((int)ppDataSize);
StephaneLenclud@60
   112
            result = Win32.Function.GetRawInputDeviceInfo(hDevice, RawInputDeviceInfoType.RIDI_PREPARSEDDATA, ppData, ref ppDataSize);
sl@17
   113
            if (result <= 0)
sl@17
   114
            {
sl@17
   115
                Debug.WriteLine("Failed to get raw input pre-parsed data" + result + Marshal.GetLastWin32Error());
sl@17
   116
                return IntPtr.Zero;
sl@17
   117
            }
sl@17
   118
            return ppData;
sl@17
   119
        }
sl@17
   120
sl@22
   121
        /// <summary>
sl@22
   122
        /// 
sl@22
   123
        /// </summary>
sl@22
   124
        /// <param name="device"></param>
sl@22
   125
        /// <returns></returns>
sl@22
   126
        public static string GetDeviceName(IntPtr device)
sl@22
   127
        {
sl@22
   128
            uint deviceNameSize = 256;
StephaneLenclud@60
   129
            int result = Win32.Function.GetRawInputDeviceInfo(device, RawInputDeviceInfoType.RIDI_DEVICENAME, IntPtr.Zero, ref deviceNameSize);
sl@22
   130
            if (result != 0)
sl@22
   131
            {
sl@22
   132
                return string.Empty;
sl@22
   133
            }
sl@22
   134
sl@22
   135
            IntPtr deviceName = Marshal.AllocHGlobal((int)deviceNameSize * 2);  // size is the character count not byte count
sl@22
   136
            try
sl@22
   137
            {
StephaneLenclud@60
   138
                result = Win32.Function.GetRawInputDeviceInfo(device, RawInputDeviceInfoType.RIDI_DEVICENAME, deviceName, ref deviceNameSize);
sl@22
   139
                if (result > 0)
sl@22
   140
                {
sl@23
   141
                    return Marshal.PtrToStringAnsi(deviceName, result - 1); // -1 for NULL termination
sl@22
   142
                }
sl@22
   143
sl@22
   144
                return string.Empty;
sl@22
   145
            }
sl@22
   146
            finally
sl@22
   147
            {
sl@22
   148
                Marshal.FreeHGlobal(deviceName);
sl@22
   149
            }
sl@22
   150
        }
sl@22
   151
sl@17
   152
StephaneLenclud@60
   153
        /// <summary>
StephaneLenclud@60
   154
        /// 
StephaneLenclud@60
   155
        /// </summary>
StephaneLenclud@60
   156
        /// <param name="aTreeView"></param>
StephaneLenclud@60
   157
        public static void PopulateDeviceList(TreeView aTreeView)
StephaneLenclud@60
   158
        {
StephaneLenclud@60
   159
StephaneLenclud@60
   160
            //Get our list of devices
StephaneLenclud@60
   161
            RAWINPUTDEVICELIST[] ridList = null;
StephaneLenclud@60
   162
            uint deviceCount = 0;
StephaneLenclud@60
   163
            int res = Win32.Function.GetRawInputDeviceList(ridList, ref deviceCount,(uint)Marshal.SizeOf(typeof(RAWINPUTDEVICELIST)));
StephaneLenclud@60
   164
            if (res == -1)
StephaneLenclud@60
   165
            {
StephaneLenclud@60
   166
                //Just give up then
StephaneLenclud@60
   167
                return;
StephaneLenclud@60
   168
            }
StephaneLenclud@60
   169
StephaneLenclud@60
   170
            ridList = new RAWINPUTDEVICELIST[deviceCount];
StephaneLenclud@60
   171
            res = Win32.Function.GetRawInputDeviceList(ridList, ref deviceCount, (uint)Marshal.SizeOf(typeof(RAWINPUTDEVICELIST)));
StephaneLenclud@60
   172
            if (res != deviceCount)
StephaneLenclud@60
   173
            {
StephaneLenclud@60
   174
                //Just give up then
StephaneLenclud@60
   175
                return;
StephaneLenclud@60
   176
            }
StephaneLenclud@60
   177
StephaneLenclud@61
   178
            //For each our device add a node to our treeview
StephaneLenclud@60
   179
            foreach (RAWINPUTDEVICELIST device in ridList)
StephaneLenclud@60
   180
            {
StephaneLenclud@61
   181
                Hid.HidDevice hidDevice=new Hid.HidDevice(device.hDevice);
StephaneLenclud@61
   182
StephaneLenclud@61
   183
                //Work out proper suffix for our device root node.
StephaneLenclud@61
   184
                //That allows users to see in a glance what kind of device this is.
StephaneLenclud@61
   185
                string suffix = "";
StephaneLenclud@62
   186
                Type usageCollectionType=null; 
StephaneLenclud@61
   187
                if (hidDevice.Info.dwType == RawInputDeviceType.RIM_TYPEHID)
StephaneLenclud@61
   188
                {
StephaneLenclud@61
   189
                    //Process usage page
StephaneLenclud@61
   190
                    if (Enum.IsDefined(typeof(Hid.UsagePage), hidDevice.Info.hid.usUsagePage))
StephaneLenclud@61
   191
                    {
StephaneLenclud@61
   192
                        //We know this usage page, add its name
StephaneLenclud@61
   193
                        Hid.UsagePage usagePage = (Hid.UsagePage)hidDevice.Info.hid.usUsagePage;
StephaneLenclud@61
   194
                        suffix += " ( " + usagePage.ToString() + ", ";
StephaneLenclud@62
   195
                        usageCollectionType = Hid.Utils.UsageCollectionType(usagePage);
StephaneLenclud@61
   196
                    }
StephaneLenclud@61
   197
                    else
StephaneLenclud@61
   198
                    {
StephaneLenclud@61
   199
                        //We don't know this usage page, add its value
StephaneLenclud@61
   200
                        suffix += " ( 0x" + hidDevice.Info.hid.usUsagePage.ToString("X4") + ", ";
StephaneLenclud@61
   201
                    }
StephaneLenclud@61
   202
StephaneLenclud@62
   203
                    //Process usage collection
StephaneLenclud@61
   204
                    //We don't know this usage page, add its value
StephaneLenclud@62
   205
                    if (usageCollectionType == null || !Enum.IsDefined(usageCollectionType, hidDevice.Info.hid.usUsage))
StephaneLenclud@62
   206
                    {
StephaneLenclud@62
   207
                        //Show Hexa
StephaneLenclud@62
   208
                        suffix += "0x" + hidDevice.Info.hid.usUsage.ToString("X4") + " )";
StephaneLenclud@62
   209
                    }
StephaneLenclud@62
   210
                    else
StephaneLenclud@62
   211
                    {
StephaneLenclud@62
   212
                        //We know this usage page, add its name
StephaneLenclud@62
   213
                        suffix += Enum.GetName(usageCollectionType, hidDevice.Info.hid.usUsage) + " )";                        
StephaneLenclud@62
   214
                    }
StephaneLenclud@61
   215
                }
StephaneLenclud@61
   216
                else if (hidDevice.Info.dwType == RawInputDeviceType.RIM_TYPEKEYBOARD)
StephaneLenclud@61
   217
                {
StephaneLenclud@61
   218
                    suffix = " - Keyboard";
StephaneLenclud@61
   219
                }
StephaneLenclud@61
   220
                else if (hidDevice.Info.dwType == RawInputDeviceType.RIM_TYPEMOUSE)
StephaneLenclud@61
   221
                {
StephaneLenclud@61
   222
                    suffix = " - Mouse";
StephaneLenclud@61
   223
                }
StephaneLenclud@61
   224
StephaneLenclud@61
   225
                TreeNode node = null;
StephaneLenclud@61
   226
                if (hidDevice.Product != null && hidDevice.Product.Length > 1)
StephaneLenclud@61
   227
                {
StephaneLenclud@61
   228
                    //Add the devices with a proper name at the top
StephaneLenclud@61
   229
                    node = aTreeView.Nodes.Insert(0, hidDevice.Name, hidDevice.Product + suffix);
StephaneLenclud@61
   230
                }
StephaneLenclud@61
   231
                else
StephaneLenclud@61
   232
                {
StephaneLenclud@61
   233
                    //Add other once at the bottom
StephaneLenclud@61
   234
                    node = aTreeView.Nodes.Add(hidDevice.Name, "0x" + hidDevice.ProductId.ToString("X4") + suffix);
StephaneLenclud@61
   235
                }
StephaneLenclud@61
   236
StephaneLenclud@61
   237
                node.Nodes.Add("Manufacturer: " + hidDevice.Manufacturer);
StephaneLenclud@61
   238
                node.Nodes.Add("Product ID: 0x" + hidDevice.ProductId.ToString("X4"));
StephaneLenclud@61
   239
                node.Nodes.Add("Vendor ID: 0x" + hidDevice.VendorId.ToString("X4"));
StephaneLenclud@61
   240
                node.Nodes.Add("Version: " + hidDevice.Version);
StephaneLenclud@61
   241
                node.Nodes.Add(hidDevice.Info.dwType.ToString());
StephaneLenclud@61
   242
                if (hidDevice.Info.dwType == RawInputDeviceType.RIM_TYPEHID)
StephaneLenclud@61
   243
                {
StephaneLenclud@61
   244
                    node.Nodes.Add("UsagePage / UsageCollection: 0x" + hidDevice.Info.hid.usUsagePage.ToString("X4") + " / 0x" + hidDevice.Info.hid.usUsage.ToString("X4"));
StephaneLenclud@61
   245
                }
StephaneLenclud@61
   246
StephaneLenclud@61
   247
                node.Nodes.Add(hidDevice.Name);
StephaneLenclud@60
   248
            }
StephaneLenclud@60
   249
        }
StephaneLenclud@60
   250
sl@10
   251
    }
sl@10
   252
}