# HG changeset patch
# User sl
# Date 1417816239 -3600
# Node ID 8f7e35c3bfd162b9bd9f93a637c831ba6d535cec
# Parent 9a3e776550313356891c73f1493a26a246ee9dc9
Draft implementation of proper HID input report parsing based on HID descriptor.
diff -r 9a3e77655031 -r 8f7e35c3bfd1 RawInput.cs
--- a/RawInput.cs Wed Dec 03 21:54:45 2014 +0100
+++ b/RawInput.cs Fri Dec 05 22:50:39 2014 +0100
@@ -5,6 +5,9 @@
namespace Win32
{
+ ///
+ /// Provide some utility functions for raw input handling.
+ ///
static class RawInput
{
///
@@ -90,5 +93,145 @@
return success;
}
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static IntPtr GetPreParsedData(IntPtr hDevice)
+ {
+ uint ppDataSize = 256;
+ int result = Win32.Function.GetRawInputDeviceInfo(hDevice, Win32.Const.RIDI_PREPARSEDDATA, IntPtr.Zero, ref ppDataSize);
+ if (result != 0)
+ {
+ Debug.WriteLine("Failed to get raw input pre-parsed data size" + result + Marshal.GetLastWin32Error());
+ return IntPtr.Zero;
+ }
+
+ IntPtr ppData = Marshal.AllocHGlobal((int)ppDataSize);
+ result = Win32.Function.GetRawInputDeviceInfo(hDevice, Win32.Const.RIDI_PREPARSEDDATA, ppData, ref ppDataSize);
+ if (result <= 0)
+ {
+ Debug.WriteLine("Failed to get raw input pre-parsed data" + result + Marshal.GetLastWin32Error());
+ return IntPtr.Zero;
+ }
+ return ppData;
+ }
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ /*
+ private bool GetUsageFromRawInput(TwinhanHidDriver driver, TwinhanHid device, NativeMethods.RAWINPUT input, IntPtr rawInput, out UsageType usageType, out int usage, out string usageName)
+ {
+ usageType = 0;
+ usage = 0;
+ usageName = string.Empty;
+ if (input.header.dwType == NativeMethods.RawInputDeviceType.RIM_TYPEKEYBOARD)
+ {
+ if (input.data.keyboard.Flags == NativeMethods.RawInputKeyboardFlag.RI_KEY_BREAK)
+ {
+ _modifiers = 0;
+ // Key up event. We don't handle repeats, so ignore this.
+ return false;
+ }
+ NativeMethods.VirtualKey vk = input.data.keyboard.VKey;
+ if (vk == NativeMethods.VirtualKey.VK_CONTROL)
+ {
+ _modifiers |= VirtualKeyModifier.Control;
+ return false;
+ }
+ if (vk == NativeMethods.VirtualKey.VK_SHIFT)
+ {
+ _modifiers |= VirtualKeyModifier.Shift;
+ return false;
+ }
+ if (vk == NativeMethods.VirtualKey.VK_MENU)
+ {
+ _modifiers |= VirtualKeyModifier.Alt;
+ return false;
+ }
+ usageType = UsageType.Keyboard;
+ usage = (int)vk | (int)_modifiers;
+ usageName = vk.ToString();
+ if (_modifiers != 0)
+ {
+ usageName += string.Format(", modifiers = {0}", _modifiers);
+ }
+ }
+ else if (input.header.dwType == NativeMethods.RawInputDeviceType.RIM_TYPEHID)
+ {
+ if ((!driver.IsTerraTec && device.Name.Contains("Col03")) || (driver.IsTerraTec && device.Name.Contains("Col02")))
+ {
+ usageType = UsageType.Raw;
+ usage = Marshal.ReadByte(rawInput, HID_INPUT_DATA_OFFSET + 1);
+ usageName = string.Format("0x{0:x2}", usage);
+ }
+ else if (device.Name.Contains("Col05"))
+ {
+ usageType = UsageType.Ascii;
+ usage = Marshal.ReadByte(rawInput, HID_INPUT_DATA_OFFSET + 1);
+ usageName = string.Format("0x{0:x2}", usage);
+ }
+ else
+ {
+ byte[] report = new byte[input.data.hid.dwSizeHid];
+ Marshal.Copy(IntPtr.Add(rawInput, HID_INPUT_DATA_OFFSET), report, 0, report.Length);
+ uint usageCount = input.data.hid.dwCount;
+ NativeMethods.USAGE_AND_PAGE[] usages = new NativeMethods.USAGE_AND_PAGE[usageCount];
+ NativeMethods.HidStatus status = NativeMethods.HidP_GetUsagesEx(NativeMethods.HIDP_REPORT_TYPE.HidP_Input, 0, usages, ref usageCount, device.PreParsedData, report, (uint)report.Length);
+ if (status != NativeMethods.HidStatus.HIDP_STATUS_SUCCESS)
+ {
+ this.LogError("Twinhan HID remote: failed to get raw input HID usages, device = {0}, status = {1}", device.Name, status);
+ Dump.DumpBinary(rawInput, (int)input.header.dwSize);
+ return false;
+ }
+ if (usageCount > 1)
+ {
+ this.LogWarn("Twinhan HID remote: multiple simultaneous HID usages not supported");
+ }
+ NativeMethods.USAGE_AND_PAGE up = usages[0];
+ HidUsagePage page = (HidUsagePage)up.UsagePage;
+ usage = up.Usage;
+ if (page != HidUsagePage.MceRemote && usage == 0)
+ {
+ // Key up event. We don't handle repeats, so ignore this.
+ return false;
+ }
+ if (page == HidUsagePage.Consumer)
+ {
+ usageType = UsageType.Consumer;
+ usageName = Enum.GetName(typeof(HidConsumerUsage), up.Usage);
+ }
+ else if (page == HidUsagePage.MceRemote)
+ {
+ usageType = UsageType.Mce;
+ usageName = Enum.GetName(typeof(MceRemoteUsage), up.Usage);
+ }
+ else
+ {
+ this.LogError("Twinhan HID remote: unexpected usage page, device = {0}, page = {1}, usage = {2}", device.Name, page, up.Usage);
+ return false;
+ }
+ }
+ }
+ else
+ {
+ this.LogError("Twinhan HID remote: received input from unsupported input device type, device = {0}, type = {1}", device.Name, input.header.dwType);
+ return false;
+ }
+ return true;
+ }
+ * */
+
}
}
\ No newline at end of file
diff -r 9a3e77655031 -r 8f7e35c3bfd1 RemoteControlDevice.cs
--- a/RemoteControlDevice.cs Wed Dec 03 21:54:45 2014 +0100
+++ b/RemoteControlDevice.cs Fri Dec 05 22:50:39 2014 +0100
@@ -395,8 +395,10 @@
Debug.WriteLine("================BACKGROUND");
}
- //Declare a pointer
+ //Declare some pointers
IntPtr rawInputBuffer = IntPtr.Zero;
+ //My understanding is that this is basically our HID descriptor
+ IntPtr preParsedData = IntPtr.Zero;
try
{
@@ -421,6 +423,9 @@
//Get Usage Page and Usage
Debug.WriteLine("Usage Page: 0x" + deviceInfo.hid.usUsagePage.ToString("X4") + " Usage ID: 0x" + deviceInfo.hid.usUsage.ToString("X4"));
+
+ preParsedData = RawInput.GetPreParsedData(rawInput.header.hDevice);
+
//
HidUsageHandler usagePageHandler=null;
@@ -449,7 +454,7 @@
//Allocate a buffer for one HID input
- byte[] hidInput = new byte[rawInput.hid.dwSizeHid];
+ byte[] hidInputReport = new byte[rawInput.hid.dwSizeHid];
//For each HID input in our raw input
for (int i = 0; i < rawInput.hid.dwCount; i++)
@@ -464,11 +469,11 @@
}
//Copy HID input into our buffer
- Marshal.Copy(new IntPtr(hidInputOffset), hidInput, 0, rawInput.hid.dwSizeHid);
+ Marshal.Copy(new IntPtr(hidInputOffset), hidInputReport, 0, (int)rawInput.hid.dwSizeHid);
//Print HID raw input in our debug output
string hidDump = "HID " + rawInput.hid.dwCount + "/" + rawInput.hid.dwSizeHid + ":";
- foreach (byte b in hidInput)
+ foreach (byte b in hidInputReport)
{
hidDump += b.ToString("X2");
}
@@ -476,19 +481,40 @@
ushort usage = 0;
//hidInput[0] //Not sure what's the meaning of the code at offset 0
- if (hidInput.Length == 2)
+ if (hidInputReport.Length == 2)
{
//Single byte code
- usage = hidInput[1]; //Get button code
+ usage = hidInputReport[1]; //Get button code
}
- else if (hidInput.Length > 2) //Defensive
+ else if (hidInputReport.Length > 2) //Defensive
{
//Assuming double bytes code
- usage = (ushort)((hidInput[2] << 8) + hidInput[1]);
+ usage = (ushort)((hidInputReport[2] << 8) + hidInputReport[1]);
}
Debug.WriteLine("Usage: 0x" + usage.ToString("X4"));
+ //Proper parsing now
+ //byte[] report = new byte[input.data.hid.dwSizeHid];
+ //Marshal.Copy(IntPtr.Add(rawInput, HID_INPUT_DATA_OFFSET), report, 0, report.Length);
+ uint usageCount = rawInput.hid.dwCount;
+ Win32.USAGE_AND_PAGE[] usages = new Win32.USAGE_AND_PAGE[usageCount];
+ Win32.HidStatus status = Win32.Function.HidP_GetUsagesEx(Win32.HIDP_REPORT_TYPE.HidP_Input, 0, usages, ref usageCount, preParsedData, hidInputReport, (uint)hidInputReport.Length);
+ if (status != Win32.HidStatus.HIDP_STATUS_SUCCESS)
+ {
+ Debug.WriteLine("Could not parse HID data!");
+ //this.LogError("Twinhan HID remote: failed to get raw input HID usages, device = {0}, status = {1}", device.Name, status);
+ //Dump.DumpBinary(rawInput, (int)input.header.dwSize);
+ //return false;
+ }
+ else
+ {
+ Debug.WriteLine("UsagePage: 0x" + usages[0].UsagePage.ToString("X4"));
+ Debug.WriteLine("Usage: 0x" + usages[0].Usage.ToString("X4"));
+ }
+
+
+
//Call on our Usage Page handler
usagePageHandler(usage);
}
@@ -510,6 +536,7 @@
{
//Always executed when leaving our try block
Marshal.FreeHGlobal(rawInputBuffer);
+ Marshal.FreeHGlobal(preParsedData);
}
}
diff -r 9a3e77655031 -r 8f7e35c3bfd1 RemoteControlSample.csproj
--- a/RemoteControlSample.csproj Wed Dec 03 21:54:45 2014 +0100
+++ b/RemoteControlSample.csproj Fri Dec 05 22:50:39 2014 +0100
@@ -132,6 +132,7 @@
Code
+
diff -r 9a3e77655031 -r 8f7e35c3bfd1 Win32Hid.cs
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Win32Hid.cs Fri Dec 05 22:50:39 2014 +0100
@@ -0,0 +1,69 @@
+using System;
+using System.Runtime.InteropServices;
+
+namespace Win32
+{
+
+ static partial class Function
+ {
+ [DllImport("hid.dll", CharSet = CharSet.Unicode)]
+ public static extern HidStatus HidP_GetUsagesEx(HIDP_REPORT_TYPE ReportType, ushort LinkCollection, [Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] USAGE_AND_PAGE[] ButtonList, ref uint UsageLength, IntPtr PreparsedData, [MarshalAs(UnmanagedType.LPArray)] byte[] Report, uint ReportLength);
+ }
+
+
+ static partial class Macro
+ {
+
+
+ }
+
+
+ static partial class Const
+ {
+
+
+ }
+
+
+ public enum HIDP_REPORT_TYPE : ushort
+ {
+ HidP_Input = 0,
+ HidP_Output,
+ HidP_Feature
+ }
+
+
+ public enum HidStatus : uint
+ {
+ HIDP_STATUS_SUCCESS = 0x110000,
+ HIDP_STATUS_NULL = 0x80110001,
+ HIDP_STATUS_INVALID_PREPARSED_DATA = 0xc0110001,
+ HIDP_STATUS_INVALID_REPORT_TYPE = 0xc0110002,
+ HIDP_STATUS_INVALID_REPORT_LENGTH = 0xc0110003,
+ HIDP_STATUS_USAGE_NOT_FOUND = 0xc0110004,
+ HIDP_STATUS_VALUE_OUT_OF_RANGE = 0xc0110005,
+ HIDP_STATUS_BAD_LOG_PHY_VALUES = 0xc0110006,
+ HIDP_STATUS_BUFFER_TOO_SMALL = 0xc0110007,
+ HIDP_STATUS_INTERNAL_ERROR = 0xc0110008,
+ HIDP_STATUS_I8042_TRANS_UNKNOWN = 0xc0110009,
+ HIDP_STATUS_INCOMPATIBLE_REPORT_ID = 0xc011000a,
+ HIDP_STATUS_NOT_VALUE_ARRAY = 0xc011000b,
+ HIDP_STATUS_IS_VALUE_ARRAY = 0xc011000c,
+ HIDP_STATUS_DATA_INDEX_NOT_FOUND = 0xc011000d,
+ HIDP_STATUS_DATA_INDEX_OUT_OF_RANGE = 0xc011000e,
+ HIDP_STATUS_BUTTON_NOT_PRESSED = 0xc011000f,
+ HIDP_STATUS_REPORT_DOES_NOT_EXIST = 0xc0110010,
+ HIDP_STATUS_NOT_IMPLEMENTED = 0xc0110020,
+ HIDP_STATUS_I8242_TRANS_UNKNOWN = 0xc0110009
+ }
+
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct USAGE_AND_PAGE
+ {
+ public ushort Usage;
+ public ushort UsagePage;
+ };
+
+
+}
\ No newline at end of file
diff -r 9a3e77655031 -r 8f7e35c3bfd1 Win32RawInput.cs
--- a/Win32RawInput.cs Wed Dec 03 21:54:45 2014 +0100
+++ b/Win32RawInput.cs Fri Dec 05 22:50:39 2014 +0100
@@ -219,9 +219,9 @@
internal struct RAWHID
{
[MarshalAs(UnmanagedType.U4)]
- public int dwSizeHid;
+ public uint dwSizeHid;
[MarshalAs(UnmanagedType.U4)]
- public int dwCount;
+ public uint dwCount;
//
//BYTE bRawData[1];
}