HidEvent.cs
changeset 27 305d2ecd3b1a
child 29 7679a5ab194b
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/HidEvent.cs	Sat Dec 06 21:52:45 2014 +0100
     1.3 @@ -0,0 +1,206 @@
     1.4 +using System;
     1.5 +using System.Windows.Forms;
     1.6 +using System.Runtime.InteropServices;
     1.7 +using System.Diagnostics;
     1.8 +using System.Text;
     1.9 +using Microsoft.Win32.SafeHandles;
    1.10 +using Win32;
    1.11 +using System.Collections.Generic;
    1.12 +
    1.13 +
    1.14 +namespace Hid
    1.15 +{
    1.16 +    /// <summary>
    1.17 +    /// Represent a HID event.
    1.18 +    /// </summary>
    1.19 +    class HidEvent
    1.20 +    {
    1.21 +        public bool IsValid { get; private set; }
    1.22 +        public bool IsForeground { get; private set; }
    1.23 +        public bool IsBackground { get{return !IsForeground;} }
    1.24 +        public bool IsMouse { get; private set; }
    1.25 +        public bool IsKeyboard { get; private set; }
    1.26 +        public bool IsGeneric { get; private set; }
    1.27 +
    1.28 +        public HidDevice Device { get; private set; }
    1.29 +
    1.30 +        public ushort UsagePage { get; private set; }
    1.31 +        public ushort UsageCollection { get; private set; }
    1.32 +        public List<ushort> Usages { get; private set; }
    1.33 +
    1.34 +
    1.35 +        /// <summary>
    1.36 +        /// Initialize an HidEvent from a WM_INPUT message
    1.37 +        /// </summary>
    1.38 +        /// <param name="hRawInputDevice">Device Handle as provided by RAWINPUTHEADER.hDevice, typically accessed as rawinput.header.hDevice</param>
    1.39 +        public HidEvent(Message aMessage)
    1.40 +        {
    1.41 +            IsValid = false;
    1.42 +            IsKeyboard = false;
    1.43 +            IsGeneric = false;
    1.44 +
    1.45 +            Usages = new List<ushort>();
    1.46 +
    1.47 +            if (aMessage.Msg != Const.WM_INPUT)
    1.48 +            {
    1.49 +                //Has to be a WM_INPUT message
    1.50 +                return;
    1.51 +            }
    1.52 +
    1.53 +            if (Macro.GET_RAWINPUT_CODE_WPARAM(aMessage.WParam) == Const.RIM_INPUT)
    1.54 +            {
    1.55 +                IsForeground = true;
    1.56 +            }
    1.57 +            else if (Macro.GET_RAWINPUT_CODE_WPARAM(aMessage.WParam) == Const.RIM_INPUTSINK)
    1.58 +            {
    1.59 +                IsForeground = false;
    1.60 +            }
    1.61 +
    1.62 +            //Declare some pointers
    1.63 +            IntPtr rawInputBuffer = IntPtr.Zero;
    1.64 +            //My understanding is that this is basically our HID descriptor 
    1.65 +            IntPtr preParsedData = IntPtr.Zero;
    1.66 +
    1.67 +            try
    1.68 +            {
    1.69 +                //Fetch raw input
    1.70 +                RAWINPUT rawInput = new RAWINPUT();
    1.71 +                if (!RawInput.GetRawInputData(aMessage.LParam, ref rawInput, ref rawInputBuffer))
    1.72 +                {
    1.73 +                    return;
    1.74 +                }
    1.75 +
    1.76 +                //Fetch device info
    1.77 +                RID_DEVICE_INFO deviceInfo = new RID_DEVICE_INFO();
    1.78 +                if (!RawInput.GetDeviceInfo(rawInput.header.hDevice, ref deviceInfo))
    1.79 +                {
    1.80 +                    return;
    1.81 +                }
    1.82 +
    1.83 +                //Get various information about this HID device
    1.84 +                Device = new Hid.HidDevice(rawInput.header.hDevice);                
    1.85 +
    1.86 +                if (rawInput.header.dwType == Const.RIM_TYPEHID)  //Check that our raw input is HID                        
    1.87 +                {
    1.88 +                    IsGeneric = true;
    1.89 +
    1.90 +                    Debug.WriteLine("WM_INPUT source device is HID.");
    1.91 +                    //Get Usage Page and Usage
    1.92 +                    //Debug.WriteLine("Usage Page: 0x" + deviceInfo.hid.usUsagePage.ToString("X4") + " Usage ID: 0x" + deviceInfo.hid.usUsage.ToString("X4"));
    1.93 +                    UsagePage = deviceInfo.hid.usUsagePage;
    1.94 +                    UsageCollection = deviceInfo.hid.usUsage;
    1.95 +
    1.96 +                    preParsedData = RawInput.GetPreParsedData(rawInput.header.hDevice);
    1.97 +
    1.98 +                    if (!(rawInput.hid.dwSizeHid > 1     //Make sure our HID msg size more than 1. In fact the first ushort is irrelevant to us for now
    1.99 +                        && rawInput.hid.dwCount > 0))    //Check that we have at least one HID msg
   1.100 +                    {
   1.101 +                        return;
   1.102 +                    }
   1.103 +
   1.104 +                    //Allocate a buffer for one HID input
   1.105 +                    byte[] hidInputReport = new byte[rawInput.hid.dwSizeHid];
   1.106 +
   1.107 +                    Debug.WriteLine("Raw input contains " + rawInput.hid.dwCount + " HID input report(s)");
   1.108 +
   1.109 +                    //For each HID input report in our raw input
   1.110 +                    for (int i = 0; i < rawInput.hid.dwCount; i++)
   1.111 +                    {
   1.112 +                        //Compute the address from which to copy our HID input
   1.113 +                        int hidInputOffset = 0;
   1.114 +                        unsafe
   1.115 +                        {
   1.116 +                            byte* source = (byte*)rawInputBuffer;
   1.117 +                            source += sizeof(RAWINPUTHEADER) + sizeof(RAWHID) + (rawInput.hid.dwSizeHid * i);
   1.118 +                            hidInputOffset = (int)source;
   1.119 +                        }
   1.120 +
   1.121 +                        //Copy HID input into our buffer
   1.122 +                        Marshal.Copy(new IntPtr(hidInputOffset), hidInputReport, 0, (int)rawInput.hid.dwSizeHid);
   1.123 +
   1.124 +                        //Print HID input report in our debug output
   1.125 +                        string hidDump = "HID input report: ";
   1.126 +                        foreach (byte b in hidInputReport)
   1.127 +                        {
   1.128 +                            hidDump += b.ToString("X2");
   1.129 +                        }
   1.130 +                        Debug.WriteLine(hidDump);
   1.131 +
   1.132 +                        //Proper parsing now
   1.133 +                        uint usageCount = 1; //Assuming a single usage per input report. Is that correct?
   1.134 +                        Win32.USAGE_AND_PAGE[] usages = new Win32.USAGE_AND_PAGE[usageCount];
   1.135 +                        Win32.HidStatus status = Win32.Function.HidP_GetUsagesEx(Win32.HIDP_REPORT_TYPE.HidP_Input, 0, usages, ref usageCount, preParsedData, hidInputReport, (uint)hidInputReport.Length);
   1.136 +                        if (status != Win32.HidStatus.HIDP_STATUS_SUCCESS)
   1.137 +                        {
   1.138 +                            Debug.WriteLine("Could not parse HID data!");
   1.139 +                        }
   1.140 +                        else
   1.141 +                        {
   1.142 +                            //Debug.WriteLine("UsagePage: 0x" + usages[0].UsagePage.ToString("X4"));
   1.143 +                            //Debug.WriteLine("Usage: 0x" + usages[0].Usage.ToString("X4"));
   1.144 +                            //Add this usage to our list
   1.145 +                            Usages.Add(usages[0].Usage);
   1.146 +                        }
   1.147 +                    }
   1.148 +
   1.149 +                }
   1.150 +                else if (rawInput.header.dwType == Const.RIM_TYPEMOUSE)
   1.151 +                {
   1.152 +                    IsMouse = true;
   1.153 +
   1.154 +                    Debug.WriteLine("WM_INPUT source device is Mouse.");                    
   1.155 +                    // do mouse handling...
   1.156 +                }
   1.157 +                else if (rawInput.header.dwType == Const.RIM_TYPEKEYBOARD)
   1.158 +                {
   1.159 +                    IsKeyboard = true;
   1.160 +
   1.161 +                    Debug.WriteLine("WM_INPUT source device is Keyboard.");
   1.162 +                    // do keyboard handling...
   1.163 +                    Debug.WriteLine("Type: " + deviceInfo.keyboard.dwType.ToString());
   1.164 +                    Debug.WriteLine("SubType: " + deviceInfo.keyboard.dwSubType.ToString());
   1.165 +                    Debug.WriteLine("Mode: " + deviceInfo.keyboard.dwKeyboardMode.ToString());
   1.166 +                    Debug.WriteLine("Number of function keys: " + deviceInfo.keyboard.dwNumberOfFunctionKeys.ToString());
   1.167 +                    Debug.WriteLine("Number of indicators: " + deviceInfo.keyboard.dwNumberOfIndicators.ToString());
   1.168 +                    Debug.WriteLine("Number of keys total: " + deviceInfo.keyboard.dwNumberOfKeysTotal.ToString());
   1.169 +                }
   1.170 +            }
   1.171 +            finally
   1.172 +            {
   1.173 +                //Always executed when leaving our try block
   1.174 +                Marshal.FreeHGlobal(rawInputBuffer);
   1.175 +                Marshal.FreeHGlobal(preParsedData);
   1.176 +            }
   1.177 +
   1.178 +            IsValid = true;
   1.179 +        }
   1.180 +
   1.181 +        /// <summary>
   1.182 +        /// Print information about this device to our debug output.
   1.183 +        /// </summary>
   1.184 +        public void DebugWrite()
   1.185 +        {
   1.186 +            if (!IsValid)
   1.187 +            {
   1.188 +                Debug.WriteLine("==== Invalid HidEvent");
   1.189 +                return;
   1.190 +            }
   1.191 +            Device.DebugWrite();
   1.192 +            if (IsGeneric) Debug.WriteLine("==== Generic");
   1.193 +            if (IsKeyboard) Debug.WriteLine("==== Keyboard");
   1.194 +            if (IsMouse) Debug.WriteLine("==== Mouse");
   1.195 +            Debug.WriteLine("==== Foreground: " + IsForeground.ToString());
   1.196 +            Debug.WriteLine("==== UsagePage: 0x" + UsagePage.ToString("X4"));
   1.197 +            Debug.WriteLine("==== UsageCollection: 0x" + UsageCollection.ToString("X4"));
   1.198 +            foreach (ushort usage in Usages)
   1.199 +            {
   1.200 +                Debug.WriteLine("==== Usage: 0x" + usage.ToString("X4"));
   1.201 +            }
   1.202 +        }
   1.203 +
   1.204 +
   1.205 +
   1.206 +
   1.207 +    }
   1.208 +
   1.209 +}
   1.210 \ No newline at end of file