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