RawInput.cs
author StephaneLenclud
Sun, 15 Mar 2015 09:53:37 +0100
changeset 72 471b1d45c46a
parent 71 c28dd93b94c5
child 73 5262f4b7c4ad
permissions -rw-r--r--
Adding button count property to HID device.
Adding device list refresh button.
Better reporting of input value capabilities description.
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
            {
StephaneLenclud@71
   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
            {
StephaneLenclud@71
   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@70
   154
        /// Populate the given tree-view control with our Raw Input Devices.
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
                TreeNode node = null;
StephaneLenclud@61
   184
                if (hidDevice.Product != null && hidDevice.Product.Length > 1)
StephaneLenclud@61
   185
                {
StephaneLenclud@61
   186
                    //Add the devices with a proper name at the top
StephaneLenclud@63
   187
                    node = aTreeView.Nodes.Insert(0, hidDevice.Name, hidDevice.FriendlyName);
StephaneLenclud@61
   188
                }
StephaneLenclud@61
   189
                else
StephaneLenclud@61
   190
                {
StephaneLenclud@61
   191
                    //Add other once at the bottom
StephaneLenclud@69
   192
                    node = aTreeView.Nodes.Add(hidDevice.Name, hidDevice.FriendlyName);
StephaneLenclud@61
   193
                }
StephaneLenclud@61
   194
StephaneLenclud@61
   195
                node.Nodes.Add("Manufacturer: " + hidDevice.Manufacturer);
StephaneLenclud@61
   196
                node.Nodes.Add("Product ID: 0x" + hidDevice.ProductId.ToString("X4"));
StephaneLenclud@61
   197
                node.Nodes.Add("Vendor ID: 0x" + hidDevice.VendorId.ToString("X4"));
StephaneLenclud@61
   198
                node.Nodes.Add("Version: " + hidDevice.Version);
StephaneLenclud@61
   199
                node.Nodes.Add(hidDevice.Info.dwType.ToString());
StephaneLenclud@61
   200
                if (hidDevice.Info.dwType == RawInputDeviceType.RIM_TYPEHID)
StephaneLenclud@61
   201
                {
StephaneLenclud@61
   202
                    node.Nodes.Add("UsagePage / UsageCollection: 0x" + hidDevice.Info.hid.usUsagePage.ToString("X4") + " / 0x" + hidDevice.Info.hid.usUsage.ToString("X4"));
StephaneLenclud@61
   203
                }
StephaneLenclud@61
   204
StephaneLenclud@64
   205
                if (hidDevice.InputCapabilitiesDescription != null)
StephaneLenclud@64
   206
                {
StephaneLenclud@64
   207
                    node.Nodes.Add(hidDevice.InputCapabilitiesDescription);
StephaneLenclud@64
   208
                }
StephaneLenclud@65
   209
StephaneLenclud@72
   210
                //Add button count
StephaneLenclud@72
   211
                node.Nodes.Add("Button Count: " + hidDevice.ButtonCount);
StephaneLenclud@72
   212
StephaneLenclud@72
   213
                //Those can be joystick/gamepad axis
StephaneLenclud@65
   214
                if (hidDevice.InputValueCapabilities != null)
StephaneLenclud@65
   215
                {
StephaneLenclud@65
   216
                    foreach (HIDP_VALUE_CAPS caps in hidDevice.InputValueCapabilities)
StephaneLenclud@65
   217
                    {
StephaneLenclud@65
   218
                        string des = hidDevice.InputValueCapabilityDescription(caps);
StephaneLenclud@65
   219
                        if (des != null)
StephaneLenclud@65
   220
                        {
StephaneLenclud@65
   221
                            node.Nodes.Add(des);
StephaneLenclud@65
   222
                        }
StephaneLenclud@65
   223
                    }
StephaneLenclud@65
   224
StephaneLenclud@65
   225
                }
StephaneLenclud@65
   226
StephaneLenclud@61
   227
                node.Nodes.Add(hidDevice.Name);
StephaneLenclud@60
   228
            }
StephaneLenclud@60
   229
        }
StephaneLenclud@60
   230
sl@10
   231
    }
sl@10
   232
}