HidEvent.cs
author sl
Fri, 19 Dec 2014 21:07:15 +0100
changeset 35 928c966fcf42
parent 29 7679a5ab194b
child 40 b3e177062849
permissions -rw-r--r--
Adding missing entries in consumer usage table.
Adding magic MyTv code in MCE usage table as handled by MP.
     1 using System;
     2 using System.Windows.Forms;
     3 using System.Runtime.InteropServices;
     4 using System.Diagnostics;
     5 using System.Text;
     6 using Microsoft.Win32.SafeHandles;
     7 using Win32;
     8 using System.Collections.Generic;
     9 
    10 
    11 namespace Hid
    12 {
    13     /// <summary>
    14     /// Represent a HID event.
    15     /// </summary>
    16     class HidEvent
    17     {
    18         public bool IsValid { get; private set; }
    19         public bool IsForeground { get; private set; }
    20         public bool IsBackground { get{return !IsForeground;} }
    21         public bool IsMouse { get; private set; }
    22         public bool IsKeyboard { get; private set; }
    23         public bool IsGeneric { get; private set; }
    24         public bool IsButtonDown { get { return Usages.Count == 1 && Usages[0] != 0; } }
    25         public bool IsButtonUp { get { return Usages.Count == 1 && Usages[0] == 0; } }
    26 
    27         public HidDevice Device { get; private set; }
    28 
    29         public ushort UsagePage { get; private set; }
    30         public ushort UsageCollection { get; private set; }
    31         public uint UsageId { get { return ((uint)UsagePage << 16 | (uint)UsageCollection); } }
    32         public List<ushort> Usages { get; private set; }
    33 
    34 
    35         /// <summary>
    36         /// Initialize an HidEvent from a WM_INPUT message
    37         /// </summary>
    38         /// <param name="hRawInputDevice">Device Handle as provided by RAWINPUTHEADER.hDevice, typically accessed as rawinput.header.hDevice</param>
    39         public HidEvent(Message aMessage)
    40         {
    41             IsValid = false;
    42             IsKeyboard = false;
    43             IsGeneric = false;
    44 
    45             Usages = new List<ushort>();
    46 
    47             if (aMessage.Msg != Const.WM_INPUT)
    48             {
    49                 //Has to be a WM_INPUT message
    50                 return;
    51             }
    52 
    53             if (Macro.GET_RAWINPUT_CODE_WPARAM(aMessage.WParam) == Const.RIM_INPUT)
    54             {
    55                 IsForeground = true;
    56             }
    57             else if (Macro.GET_RAWINPUT_CODE_WPARAM(aMessage.WParam) == Const.RIM_INPUTSINK)
    58             {
    59                 IsForeground = false;
    60             }
    61 
    62             //Declare some pointers
    63             IntPtr rawInputBuffer = IntPtr.Zero;
    64             //My understanding is that this is basically our HID descriptor 
    65             IntPtr preParsedData = IntPtr.Zero;
    66 
    67             try
    68             {
    69                 //Fetch raw input
    70                 RAWINPUT rawInput = new RAWINPUT();
    71                 if (!RawInput.GetRawInputData(aMessage.LParam, ref rawInput, ref rawInputBuffer))
    72                 {
    73                     return;
    74                 }
    75 
    76                 //Fetch device info
    77                 RID_DEVICE_INFO deviceInfo = new RID_DEVICE_INFO();
    78                 if (!RawInput.GetDeviceInfo(rawInput.header.hDevice, ref deviceInfo))
    79                 {
    80                     return;
    81                 }
    82 
    83                 //Get various information about this HID device
    84                 Device = new Hid.HidDevice(rawInput.header.hDevice);                
    85 
    86                 if (rawInput.header.dwType == Const.RIM_TYPEHID)  //Check that our raw input is HID                        
    87                 {
    88                     IsGeneric = true;
    89 
    90                     Debug.WriteLine("WM_INPUT source device is HID.");
    91                     //Get Usage Page and Usage
    92                     //Debug.WriteLine("Usage Page: 0x" + deviceInfo.hid.usUsagePage.ToString("X4") + " Usage ID: 0x" + deviceInfo.hid.usUsage.ToString("X4"));
    93                     UsagePage = deviceInfo.hid.usUsagePage;
    94                     UsageCollection = deviceInfo.hid.usUsage;
    95 
    96                     preParsedData = RawInput.GetPreParsedData(rawInput.header.hDevice);
    97 
    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
    99                         && rawInput.hid.dwCount > 0))    //Check that we have at least one HID msg
   100                     {
   101                         return;
   102                     }
   103 
   104                     //Allocate a buffer for one HID input
   105                     byte[] hidInputReport = new byte[rawInput.hid.dwSizeHid];
   106 
   107                     Debug.WriteLine("Raw input contains " + rawInput.hid.dwCount + " HID input report(s)");
   108 
   109                     //For each HID input report in our raw input
   110                     for (int i = 0; i < rawInput.hid.dwCount; i++)
   111                     {
   112                         //Compute the address from which to copy our HID input
   113                         int hidInputOffset = 0;
   114                         unsafe
   115                         {
   116                             byte* source = (byte*)rawInputBuffer;
   117                             source += sizeof(RAWINPUTHEADER) + sizeof(RAWHID) + (rawInput.hid.dwSizeHid * i);
   118                             hidInputOffset = (int)source;
   119                         }
   120 
   121                         //Copy HID input into our buffer
   122                         Marshal.Copy(new IntPtr(hidInputOffset), hidInputReport, 0, (int)rawInput.hid.dwSizeHid);
   123 
   124                         //Print HID input report in our debug output
   125                         string hidDump = "HID input report: ";
   126                         foreach (byte b in hidInputReport)
   127                         {
   128                             hidDump += b.ToString("X2");
   129                         }
   130                         Debug.WriteLine(hidDump);
   131 
   132                         //Proper parsing now
   133                         uint usageCount = 1; //Assuming a single usage per input report. Is that correct?
   134                         Win32.USAGE_AND_PAGE[] usages = new Win32.USAGE_AND_PAGE[usageCount];
   135                         Win32.HidStatus status = Win32.Function.HidP_GetUsagesEx(Win32.HIDP_REPORT_TYPE.HidP_Input, 0, usages, ref usageCount, preParsedData, hidInputReport, (uint)hidInputReport.Length);
   136                         if (status != Win32.HidStatus.HIDP_STATUS_SUCCESS)
   137                         {
   138                             Debug.WriteLine("Could not parse HID data!");
   139                         }
   140                         else
   141                         {
   142                             //Debug.WriteLine("UsagePage: 0x" + usages[0].UsagePage.ToString("X4"));
   143                             //Debug.WriteLine("Usage: 0x" + usages[0].Usage.ToString("X4"));
   144                             //Add this usage to our list
   145                             Usages.Add(usages[0].Usage);
   146                         }
   147                     }
   148 
   149                 }
   150                 else if (rawInput.header.dwType == Const.RIM_TYPEMOUSE)
   151                 {
   152                     IsMouse = true;
   153 
   154                     Debug.WriteLine("WM_INPUT source device is Mouse.");                    
   155                     // do mouse handling...
   156                 }
   157                 else if (rawInput.header.dwType == Const.RIM_TYPEKEYBOARD)
   158                 {
   159                     IsKeyboard = true;
   160 
   161                     Debug.WriteLine("WM_INPUT source device is Keyboard.");
   162                     // do keyboard handling...
   163                     Debug.WriteLine("Type: " + deviceInfo.keyboard.dwType.ToString());
   164                     Debug.WriteLine("SubType: " + deviceInfo.keyboard.dwSubType.ToString());
   165                     Debug.WriteLine("Mode: " + deviceInfo.keyboard.dwKeyboardMode.ToString());
   166                     Debug.WriteLine("Number of function keys: " + deviceInfo.keyboard.dwNumberOfFunctionKeys.ToString());
   167                     Debug.WriteLine("Number of indicators: " + deviceInfo.keyboard.dwNumberOfIndicators.ToString());
   168                     Debug.WriteLine("Number of keys total: " + deviceInfo.keyboard.dwNumberOfKeysTotal.ToString());
   169                 }
   170             }
   171             finally
   172             {
   173                 //Always executed when leaving our try block
   174                 Marshal.FreeHGlobal(rawInputBuffer);
   175                 Marshal.FreeHGlobal(preParsedData);
   176             }
   177 
   178             IsValid = true;
   179         }
   180 
   181         /// <summary>
   182         /// Print information about this device to our debug output.
   183         /// </summary>
   184         public void DebugWrite()
   185         {
   186             if (!IsValid)
   187             {
   188                 Debug.WriteLine("==== Invalid HidEvent");
   189                 return;
   190             }
   191             Device.DebugWrite();
   192             if (IsGeneric) Debug.WriteLine("==== Generic");
   193             if (IsKeyboard) Debug.WriteLine("==== Keyboard");
   194             if (IsMouse) Debug.WriteLine("==== Mouse");
   195             Debug.WriteLine("==== Foreground: " + IsForeground.ToString());
   196             Debug.WriteLine("==== UsagePage: 0x" + UsagePage.ToString("X4"));
   197             Debug.WriteLine("==== UsageCollection: 0x" + UsageCollection.ToString("X4"));
   198             foreach (ushort usage in Usages)
   199             {
   200                 Debug.WriteLine("==== Usage: 0x" + usage.ToString("X4"));
   201             }
   202         }
   203 
   204 
   205 
   206 
   207     }
   208 
   209 }