RawInput.cs
author StephaneLenclud
Sun, 15 Mar 2015 14:45:40 +0100
changeset 77 fb9ea5ad8c2d
parent 76 831ebeeecfdf
permissions -rw-r--r--
Now using SharpLib.Hid and SharpLib.Win32 as namespaces.
StephaneLenclud@76
     1
//
StephaneLenclud@76
     2
// Copyright (C) 2014-2015 Stéphane Lenclud.
StephaneLenclud@76
     3
//
StephaneLenclud@76
     4
// This file is part of SharpLibHid.
StephaneLenclud@76
     5
//
StephaneLenclud@76
     6
// SharpDisplayManager is free software: you can redistribute it and/or modify
StephaneLenclud@76
     7
// it under the terms of the GNU General Public License as published by
StephaneLenclud@76
     8
// the Free Software Foundation, either version 3 of the License, or
StephaneLenclud@76
     9
// (at your option) any later version.
StephaneLenclud@76
    10
//
StephaneLenclud@76
    11
// SharpDisplayManager is distributed in the hope that it will be useful,
StephaneLenclud@76
    12
// but WITHOUT ANY WARRANTY; without even the implied warranty of
StephaneLenclud@76
    13
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
StephaneLenclud@76
    14
// GNU General Public License for more details.
StephaneLenclud@76
    15
//
StephaneLenclud@76
    16
// You should have received a copy of the GNU General Public License
StephaneLenclud@76
    17
// along with SharpDisplayManager.  If not, see <http://www.gnu.org/licenses/>.
StephaneLenclud@76
    18
//
StephaneLenclud@76
    19
sl@10
    20
using System;
sl@10
    21
using System.Runtime.InteropServices;
sl@10
    22
using System.Diagnostics;
StephaneLenclud@60
    23
using System.Windows.Forms;
sl@10
    24
StephaneLenclud@77
    25
namespace SharpLib.Win32
sl@10
    26
{
sl@17
    27
    /// <summary>
sl@17
    28
    /// Provide some utility functions for raw input handling.
sl@17
    29
    /// </summary>
StephaneLenclud@74
    30
    static public class RawInput
sl@10
    31
    {
sl@10
    32
        /// <summary>
sl@10
    33
        /// 
sl@10
    34
        /// </summary>
sl@10
    35
        /// <param name="aRawInputHandle"></param>
sl@10
    36
        /// <param name="aRawInput"></param>
sl@10
    37
        /// <param name="rawInputBuffer">Caller must free up memory on the pointer using Marshal.FreeHGlobal</param>
sl@10
    38
        /// <returns></returns>
sl@10
    39
        public static bool GetRawInputData(IntPtr aRawInputHandle, ref RAWINPUT aRawInput, ref IntPtr rawInputBuffer)
sl@10
    40
        {
sl@10
    41
            bool success = true;
sl@10
    42
            rawInputBuffer = IntPtr.Zero;
sl@10
    43
sl@10
    44
            try
sl@10
    45
            {
sl@10
    46
                uint dwSize = 0;
sl@10
    47
                uint sizeOfHeader = (uint)Marshal.SizeOf(typeof(RAWINPUTHEADER));
sl@10
    48
sl@10
    49
                //Get the size of our raw input data.
sl@10
    50
                Win32.Function.GetRawInputData(aRawInputHandle, Const.RID_INPUT, IntPtr.Zero, ref dwSize, sizeOfHeader);
sl@10
    51
sl@10
    52
                //Allocate a large enough buffer
sl@10
    53
                 rawInputBuffer = Marshal.AllocHGlobal((int)dwSize);
sl@10
    54
sl@10
    55
                //Now read our RAWINPUT data
sl@10
    56
                if (Win32.Function.GetRawInputData(aRawInputHandle, Const.RID_INPUT, rawInputBuffer, ref dwSize, (uint)Marshal.SizeOf(typeof(RAWINPUTHEADER))) != dwSize)
sl@10
    57
                {
sl@10
    58
                    return false;
sl@10
    59
                }
sl@10
    60
sl@10
    61
                //Cast our buffer
sl@10
    62
                aRawInput = (RAWINPUT)Marshal.PtrToStructure(rawInputBuffer, typeof(RAWINPUT));
sl@10
    63
            }
sl@10
    64
            catch
sl@10
    65
            {
sl@10
    66
                Debug.WriteLine("GetRawInputData failed!");
sl@10
    67
                success = false;
sl@10
    68
            }
sl@10
    69
sl@10
    70
            return success;
sl@10
    71
        }
sl@10
    72
sl@10
    73
        /// <summary>
sl@10
    74
        /// 
sl@10
    75
        /// </summary>
sl@47
    76
        /// <param name="hDevice"></param>
sl@47
    77
        /// <param name="deviceInfo"></param>
sl@10
    78
        /// <returns></returns>
sl@10
    79
        public static bool GetDeviceInfo(IntPtr hDevice, ref RID_DEVICE_INFO deviceInfo)
sl@10
    80
        {
sl@10
    81
            bool success = true;
sl@10
    82
            IntPtr deviceInfoBuffer = IntPtr.Zero;
sl@10
    83
            try
sl@10
    84
            {
sl@10
    85
                //Get Device Info
sl@10
    86
                uint deviceInfoSize = (uint)Marshal.SizeOf(typeof(RID_DEVICE_INFO));
sl@10
    87
                deviceInfoBuffer = Marshal.AllocHGlobal((int)deviceInfoSize);
sl@10
    88
StephaneLenclud@60
    89
                int res = Win32.Function.GetRawInputDeviceInfo(hDevice, Win32.RawInputDeviceInfoType.RIDI_DEVICEINFO, deviceInfoBuffer, ref deviceInfoSize);
sl@10
    90
                if (res <= 0)
sl@10
    91
                {
sl@10
    92
                    Debug.WriteLine("WM_INPUT could not read device info: " + Marshal.GetLastWin32Error().ToString());
sl@10
    93
                    return false;
sl@10
    94
                }
sl@10
    95
sl@10
    96
                //Cast our buffer
sl@10
    97
                deviceInfo = (RID_DEVICE_INFO)Marshal.PtrToStructure(deviceInfoBuffer, typeof(RID_DEVICE_INFO));
sl@10
    98
            }
sl@10
    99
            catch
sl@10
   100
            {
sl@10
   101
                Debug.WriteLine("GetRawInputData failed!");
sl@10
   102
                success = false;
sl@10
   103
            }
sl@10
   104
            finally
sl@10
   105
            {
sl@10
   106
                //Always executes, prevents memory leak
sl@10
   107
                Marshal.FreeHGlobal(deviceInfoBuffer);
sl@10
   108
            }
sl@10
   109
sl@10
   110
            
sl@10
   111
            return success;
sl@10
   112
        }
sl@10
   113
sl@17
   114
        /// <summary>
sl@19
   115
        /// Fetch pre-parsed data corresponding to HID descriptor for the given HID device.
sl@17
   116
        /// </summary>
sl@17
   117
        /// <param name="device"></param>
sl@17
   118
        /// <returns></returns>
sl@17
   119
        public static IntPtr GetPreParsedData(IntPtr hDevice)
sl@17
   120
        {
StephaneLenclud@60
   121
            uint ppDataSize = 0;
StephaneLenclud@60
   122
            int result = Win32.Function.GetRawInputDeviceInfo(hDevice, RawInputDeviceInfoType.RIDI_PREPARSEDDATA, IntPtr.Zero, ref ppDataSize);
sl@17
   123
            if (result != 0)
sl@17
   124
            {
StephaneLenclud@71
   125
                Debug.WriteLine("Failed to get raw input pre-parsed data size: " + result + " : " + Marshal.GetLastWin32Error());
sl@17
   126
                return IntPtr.Zero;
sl@17
   127
            }
sl@17
   128
sl@17
   129
            IntPtr ppData = Marshal.AllocHGlobal((int)ppDataSize);
StephaneLenclud@60
   130
            result = Win32.Function.GetRawInputDeviceInfo(hDevice, RawInputDeviceInfoType.RIDI_PREPARSEDDATA, ppData, ref ppDataSize);
sl@17
   131
            if (result <= 0)
sl@17
   132
            {
StephaneLenclud@71
   133
                Debug.WriteLine("Failed to get raw input pre-parsed data: " + result + " : " + Marshal.GetLastWin32Error());
sl@17
   134
                return IntPtr.Zero;
sl@17
   135
            }
sl@17
   136
            return ppData;
sl@17
   137
        }
sl@17
   138
sl@22
   139
        /// <summary>
sl@22
   140
        /// 
sl@22
   141
        /// </summary>
sl@22
   142
        /// <param name="device"></param>
sl@22
   143
        /// <returns></returns>
sl@22
   144
        public static string GetDeviceName(IntPtr device)
sl@22
   145
        {
sl@22
   146
            uint deviceNameSize = 256;
StephaneLenclud@60
   147
            int result = Win32.Function.GetRawInputDeviceInfo(device, RawInputDeviceInfoType.RIDI_DEVICENAME, IntPtr.Zero, ref deviceNameSize);
sl@22
   148
            if (result != 0)
sl@22
   149
            {
sl@22
   150
                return string.Empty;
sl@22
   151
            }
sl@22
   152
sl@22
   153
            IntPtr deviceName = Marshal.AllocHGlobal((int)deviceNameSize * 2);  // size is the character count not byte count
sl@22
   154
            try
sl@22
   155
            {
StephaneLenclud@60
   156
                result = Win32.Function.GetRawInputDeviceInfo(device, RawInputDeviceInfoType.RIDI_DEVICENAME, deviceName, ref deviceNameSize);
sl@22
   157
                if (result > 0)
sl@22
   158
                {
sl@23
   159
                    return Marshal.PtrToStringAnsi(deviceName, result - 1); // -1 for NULL termination
sl@22
   160
                }
sl@22
   161
sl@22
   162
                return string.Empty;
sl@22
   163
            }
sl@22
   164
            finally
sl@22
   165
            {
sl@22
   166
                Marshal.FreeHGlobal(deviceName);
sl@22
   167
            }
sl@22
   168
        }
sl@22
   169
sl@17
   170
StephaneLenclud@60
   171
        /// <summary>
StephaneLenclud@70
   172
        /// Populate the given tree-view control with our Raw Input Devices.
StephaneLenclud@60
   173
        /// </summary>
StephaneLenclud@60
   174
        /// <param name="aTreeView"></param>
StephaneLenclud@60
   175
        public static void PopulateDeviceList(TreeView aTreeView)
StephaneLenclud@60
   176
        {
StephaneLenclud@60
   177
StephaneLenclud@60
   178
            //Get our list of devices
StephaneLenclud@60
   179
            RAWINPUTDEVICELIST[] ridList = null;
StephaneLenclud@60
   180
            uint deviceCount = 0;
StephaneLenclud@60
   181
            int res = Win32.Function.GetRawInputDeviceList(ridList, ref deviceCount,(uint)Marshal.SizeOf(typeof(RAWINPUTDEVICELIST)));
StephaneLenclud@60
   182
            if (res == -1)
StephaneLenclud@60
   183
            {
StephaneLenclud@60
   184
                //Just give up then
StephaneLenclud@60
   185
                return;
StephaneLenclud@60
   186
            }
StephaneLenclud@60
   187
StephaneLenclud@60
   188
            ridList = new RAWINPUTDEVICELIST[deviceCount];
StephaneLenclud@60
   189
            res = Win32.Function.GetRawInputDeviceList(ridList, ref deviceCount, (uint)Marshal.SizeOf(typeof(RAWINPUTDEVICELIST)));
StephaneLenclud@60
   190
            if (res != deviceCount)
StephaneLenclud@60
   191
            {
StephaneLenclud@60
   192
                //Just give up then
StephaneLenclud@60
   193
                return;
StephaneLenclud@60
   194
            }
StephaneLenclud@60
   195
StephaneLenclud@61
   196
            //For each our device add a node to our treeview
StephaneLenclud@60
   197
            foreach (RAWINPUTDEVICELIST device in ridList)
StephaneLenclud@60
   198
            {
StephaneLenclud@77
   199
                SharpLib.Hid.HidDevice hidDevice=new SharpLib.Hid.HidDevice(device.hDevice);
StephaneLenclud@61
   200
StephaneLenclud@61
   201
                TreeNode node = null;
StephaneLenclud@61
   202
                if (hidDevice.Product != null && hidDevice.Product.Length > 1)
StephaneLenclud@61
   203
                {
StephaneLenclud@61
   204
                    //Add the devices with a proper name at the top
StephaneLenclud@63
   205
                    node = aTreeView.Nodes.Insert(0, hidDevice.Name, hidDevice.FriendlyName);
StephaneLenclud@61
   206
                }
StephaneLenclud@61
   207
                else
StephaneLenclud@61
   208
                {
StephaneLenclud@61
   209
                    //Add other once at the bottom
StephaneLenclud@69
   210
                    node = aTreeView.Nodes.Add(hidDevice.Name, hidDevice.FriendlyName);
StephaneLenclud@61
   211
                }
StephaneLenclud@61
   212
StephaneLenclud@61
   213
                node.Nodes.Add("Manufacturer: " + hidDevice.Manufacturer);
StephaneLenclud@61
   214
                node.Nodes.Add("Product ID: 0x" + hidDevice.ProductId.ToString("X4"));
StephaneLenclud@61
   215
                node.Nodes.Add("Vendor ID: 0x" + hidDevice.VendorId.ToString("X4"));
StephaneLenclud@61
   216
                node.Nodes.Add("Version: " + hidDevice.Version);
StephaneLenclud@61
   217
                node.Nodes.Add(hidDevice.Info.dwType.ToString());
StephaneLenclud@61
   218
                if (hidDevice.Info.dwType == RawInputDeviceType.RIM_TYPEHID)
StephaneLenclud@61
   219
                {
StephaneLenclud@61
   220
                    node.Nodes.Add("UsagePage / UsageCollection: 0x" + hidDevice.Info.hid.usUsagePage.ToString("X4") + " / 0x" + hidDevice.Info.hid.usUsage.ToString("X4"));
StephaneLenclud@61
   221
                }
StephaneLenclud@61
   222
StephaneLenclud@64
   223
                if (hidDevice.InputCapabilitiesDescription != null)
StephaneLenclud@64
   224
                {
StephaneLenclud@64
   225
                    node.Nodes.Add(hidDevice.InputCapabilitiesDescription);
StephaneLenclud@64
   226
                }
StephaneLenclud@65
   227
StephaneLenclud@72
   228
                //Add button count
StephaneLenclud@72
   229
                node.Nodes.Add("Button Count: " + hidDevice.ButtonCount);
StephaneLenclud@72
   230
StephaneLenclud@72
   231
                //Those can be joystick/gamepad axis
StephaneLenclud@65
   232
                if (hidDevice.InputValueCapabilities != null)
StephaneLenclud@65
   233
                {
StephaneLenclud@65
   234
                    foreach (HIDP_VALUE_CAPS caps in hidDevice.InputValueCapabilities)
StephaneLenclud@65
   235
                    {
StephaneLenclud@77
   236
                        string des = SharpLib.Hid.HidDevice.InputValueCapabilityDescription(caps);
StephaneLenclud@65
   237
                        if (des != null)
StephaneLenclud@65
   238
                        {
StephaneLenclud@65
   239
                            node.Nodes.Add(des);
StephaneLenclud@65
   240
                        }
StephaneLenclud@65
   241
                    }
StephaneLenclud@65
   242
StephaneLenclud@65
   243
                }
StephaneLenclud@65
   244
StephaneLenclud@61
   245
                node.Nodes.Add(hidDevice.Name);
StephaneLenclud@60
   246
            }
StephaneLenclud@60
   247
        }
StephaneLenclud@60
   248
sl@10
   249
    }
sl@10
   250
}