/// <summary> /// </summary> /// <param name="aRawInputHandle"></param> /// <param name="aRawInput"></param> /// <param name="rawInputBuffer">Caller must free up memory on the pointer using Marshal.FreeHGlobal</param> /// <returns></returns> public static bool GetRawInputData(IntPtr aRawInputHandle, ref RAWINPUT aRawInput, ref IntPtr rawInputBuffer) { var success = true; rawInputBuffer = IntPtr.Zero; try { uint dwSize = 0; var sizeOfHeader = (uint) Marshal.SizeOf(typeof (RAWINPUTHEADER)); //Get the size of our raw input data. Function.GetRawInputData(aRawInputHandle, Const.RID_INPUT, IntPtr.Zero, ref dwSize, sizeOfHeader); //Allocate a large enough buffer rawInputBuffer = Marshal.AllocHGlobal((int) dwSize); //Now read our RAWINPUT data if ( Function.GetRawInputData(aRawInputHandle, Const.RID_INPUT, rawInputBuffer, ref dwSize, (uint) Marshal.SizeOf(typeof (RAWINPUTHEADER))) != dwSize) { return false; } //Cast our buffer aRawInput = (RAWINPUT) Marshal.PtrToStructure(rawInputBuffer, typeof (RAWINPUT)); } catch { Debug.WriteLine("GetRawInputData failed!"); success = false; } return success; }
/// <summary> /// </summary> /// <param name="aRawInputHandle"></param> /// <param name="aRawInput"></param> /// <param name="rawInputBuffer">Caller must free up memory on the pointer using Marshal.FreeHGlobal</param> /// <returns></returns> public static bool GetRawInputData(IntPtr aRawInputHandle, ref RAWINPUT aRawInput, ref IntPtr rawInputBuffer) { var success = true; rawInputBuffer = IntPtr.Zero; try { uint dwSize = 0; var sizeOfHeader = (uint)Marshal.SizeOf(typeof(RAWINPUTHEADER)); //Get the size of our raw input data. Function.GetRawInputData(aRawInputHandle, Const.RID_INPUT, IntPtr.Zero, ref dwSize, sizeOfHeader); //Allocate a large enough buffer rawInputBuffer = Marshal.AllocHGlobal((int)dwSize); //Now read our RAWINPUT data if ( Function.GetRawInputData(aRawInputHandle, Const.RID_INPUT, rawInputBuffer, ref dwSize, (uint)Marshal.SizeOf(typeof(RAWINPUTHEADER))) != dwSize) { return(false); } //Cast our buffer aRawInput = (RAWINPUT)Marshal.PtrToStructure(rawInputBuffer, typeof(RAWINPUT)); } catch { Debug.WriteLine("GetRawInputData failed!"); success = false; } return(success); }
/// <summary> /// Initialize an HidEvent from a WM_INPUT message /// </summary> /// <param name="hRawInputDevice"> /// Device Handle as provided by RAWINPUTHEADER.hDevice, typically accessed as /// rawinput.header.hDevice /// </param> public HidEvent(Message aMessage, HidEventRepeatDelegate aRepeatDelegate) { RepeatCount = 0; IsValid = false; IsKeyboard = false; IsGeneric = false; Time = DateTime.Now; OriginalTime = DateTime.Now; Timer = new Timer(); Timer.Elapsed += (sender, e) => OnRepeatTimerElapsed(sender, e, this); Usages = new List<ushort>(); OnHidEventRepeat += aRepeatDelegate; if (aMessage.Msg != Const.WM_INPUT) { //Has to be a WM_INPUT message return; } if (Macro.GET_RAWINPUT_CODE_WPARAM(aMessage.WParam) == Const.RIM_INPUT) { IsForeground = true; } else if (Macro.GET_RAWINPUT_CODE_WPARAM(aMessage.WParam) == Const.RIM_INPUTSINK) { IsForeground = false; } //Declare some pointers var rawInputBuffer = IntPtr.Zero; //My understanding is that this is basically our HID descriptor var preParsedData = IntPtr.Zero; try { //Fetch raw input var rawInput = new RAWINPUT(); if (!RawInput.GetRawInputData(aMessage.LParam, ref rawInput, ref rawInputBuffer)) { return; } //Fetch device info var deviceInfo = new RID_DEVICE_INFO(); if (!RawInput.GetDeviceInfo(rawInput.header.hDevice, ref deviceInfo)) { return; } //Get various information about this HID device Device = new HidDevice(rawInput.header.hDevice); if (rawInput.header.dwType == Const.RIM_TYPEHID) //Check that our raw input is HID { IsGeneric = true; Debug.WriteLine("WM_INPUT source device is HID."); //Get Usage Page and Usage //Debug.WriteLine("Usage Page: 0x" + deviceInfo.hid.usUsagePage.ToString("X4") + " Usage ID: 0x" + deviceInfo.hid.usUsage.ToString("X4")); UsagePage = deviceInfo.hid.usUsagePage; UsageCollection = deviceInfo.hid.usUsage; preParsedData = RawInput.GetPreParsedData(rawInput.header.hDevice); 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 && rawInput.hid.dwCount > 0)) //Check that we have at least one HID msg { return; } //Allocate a buffer for one HID input var hidInputReport = new byte[rawInput.hid.dwSizeHid]; Debug.WriteLine("Raw input contains " + rawInput.hid.dwCount + " HID input report(s)"); //For each HID input report in our raw input for (var i = 0; i < rawInput.hid.dwCount; i++) { //Compute the address from which to copy our HID input var hidInputOffset = 0; unsafe { var source = (byte*) rawInputBuffer; source += sizeof (RAWINPUTHEADER) + sizeof (RAWHID) + (rawInput.hid.dwSizeHid*i); hidInputOffset = (int) source; } //Copy HID input into our buffer Marshal.Copy(new IntPtr(hidInputOffset), hidInputReport, 0, (int) rawInput.hid.dwSizeHid); //Print HID input report in our debug output var hidDump = "HID input report: "; foreach (var b in hidInputReport) { hidDump += b.ToString("X2"); } Debug.WriteLine(hidDump); //Proper parsing now uint usageCount = 1; //Assuming a single usage per input report. Is that correct? var usages = new USAGE_AND_PAGE[usageCount]; var status = Function.HidP_GetUsagesEx(HIDP_REPORT_TYPE.HidP_Input, 0, usages, ref usageCount, preParsedData, hidInputReport, (uint) hidInputReport.Length); if (status != HidStatus.HIDP_STATUS_SUCCESS) { Log.Error("HID: Could not parse HID data!"); } else { //Debug.WriteLine("UsagePage: 0x" + usages[0].UsagePage.ToString("X4")); //Debug.WriteLine("Usage: 0x" + usages[0].Usage.ToString("X4")); //Add this usage to our list Usages.Add(usages[0].Usage); } } } else if (rawInput.header.dwType == Const.RIM_TYPEMOUSE) { IsMouse = true; Debug.WriteLine("WM_INPUT source device is Mouse."); // do mouse handling... } else if (rawInput.header.dwType == Const.RIM_TYPEKEYBOARD) { IsKeyboard = true; Debug.WriteLine("WM_INPUT source device is Keyboard."); // do keyboard handling... Debug.WriteLine("Type: " + deviceInfo.keyboard.dwType); Debug.WriteLine("SubType: " + deviceInfo.keyboard.dwSubType); Debug.WriteLine("Mode: " + deviceInfo.keyboard.dwKeyboardMode); Debug.WriteLine("Number of function keys: " + deviceInfo.keyboard.dwNumberOfFunctionKeys); Debug.WriteLine("Number of indicators: " + deviceInfo.keyboard.dwNumberOfIndicators); Debug.WriteLine("Number of keys total: " + deviceInfo.keyboard.dwNumberOfKeysTotal); } } finally { //Always executed when leaving our try block Marshal.FreeHGlobal(rawInputBuffer); Marshal.FreeHGlobal(preParsedData); } //Start repeat timer if needed if (IsButtonDown) { StartRepeatTimer(iRepeatDelay); } IsValid = true; }