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