# HG changeset patch # User StephaneLenclud # Date 1423680381 -3600 # Node ID 2ec781e51f3623bc09e34be96fde955b658a5da9 # Parent 1eb878505ae1e126fee6722f10ca53ad2302aaef Adding better support for multiple usage per report. Now registering for gamepad input. diff -r 1eb878505ae1 -r 2ec781e51f36 HidEvent.cs --- a/HidEvent.cs Mon Feb 02 22:12:15 2015 +0100 +++ b/HidEvent.cs Wed Feb 11 19:46:21 2015 +0100 @@ -23,7 +23,7 @@ public bool IsKeyboard { get; private set; } public bool IsGeneric { get; private set; } public bool IsButtonDown { get { return Usages.Count == 1 && Usages[0] != 0; } } - public bool IsButtonUp { get { return Usages.Count == 1 && Usages[0] == 0; } } + public bool IsButtonUp { get { return Usages.Count == 0; } } public bool IsRepeat { get { return RepeatCount != 0; } } public uint RepeatCount { get; private set; } @@ -32,8 +32,10 @@ public ushort UsagePage { get; private set; } public ushort UsageCollection { get; private set; } public uint UsageId { get { return ((uint)UsagePage << 16 | (uint)UsageCollection); } } - public List Usages { get; private set; } - public delegate void HidEventRepeatDelegate(HidEvent aHidEvent); + public List Usages { get; private set; } + public byte[] InputReport { get; private set; } + // + public delegate void HidEventRepeatDelegate(HidEvent aHidEvent); public event HidEventRepeatDelegate OnHidEventRepeat; private System.Timers.Timer Timer { get; set; } @@ -138,7 +140,7 @@ } //Allocate a buffer for one HID input - byte[] hidInputReport = new byte[rawInput.hid.dwSizeHid]; + InputReport = new byte[rawInput.hid.dwSizeHid]; Debug.WriteLine("Raw input contains " + rawInput.hid.dwCount + " HID input report(s)"); @@ -155,33 +157,46 @@ } //Copy HID input into our buffer - Marshal.Copy(new IntPtr(hidInputOffset), hidInputReport, 0, (int)rawInput.hid.dwSizeHid); + Marshal.Copy(new IntPtr(hidInputOffset), InputReport, 0, (int)rawInput.hid.dwSizeHid); //Print HID input report in our debug output - string hidDump = "HID input report: "; - foreach (byte b in hidInputReport) - { - hidDump += b.ToString("X2"); - } - Debug.WriteLine(hidDump); + //string hidDump = "HID input report: " + InputReportString(); + //Debug.WriteLine(hidDump); - //Proper parsing now - uint usageCount = 1; //Assuming a single usage per input report. Is that correct? - 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!"); - } - 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); - } + //Do proper parsing of our HID report + //First query our usage count + uint usageCount = 0; + Win32.USAGE_AND_PAGE[] usages = null; + Win32.HidStatus status = Win32.Function.HidP_GetUsagesEx(Win32.HIDP_REPORT_TYPE.HidP_Input, 0, usages, ref usageCount, preParsedData, InputReport, (uint)InputReport.Length); + if (status == Win32.HidStatus.HIDP_STATUS_BUFFER_TOO_SMALL) + { + //Allocate a large enough buffer + usages = new Win32.USAGE_AND_PAGE[usageCount]; + //...and fetch our usages + status = Win32.Function.HidP_GetUsagesEx(Win32.HIDP_REPORT_TYPE.HidP_Input, 0, usages, ref usageCount, preParsedData, InputReport, (uint)InputReport.Length); + if (status != Win32.HidStatus.HIDP_STATUS_SUCCESS) + { + Debug.WriteLine("Second pass could not parse HID data: " + status.ToString()); + } + } + else if (status != Win32.HidStatus.HIDP_STATUS_SUCCESS) + { + Debug.WriteLine("First pass could not parse HID data: " + status.ToString()); + } + + Debug.WriteLine("Usage count: " + usageCount.ToString()); + + if (usages != null) + { + foreach (USAGE_AND_PAGE up in usages) + { + //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(up.Usage); + } + } } - } else if (rawInput.header.dwType == Const.RIM_TYPEMOUSE) { @@ -214,35 +229,13 @@ // if (IsButtonDown) { + //TODO: Make this optional StartRepeatTimer(iRepeatDelay); } IsValid = true; } - /// - /// Print information about this device to our debug output. - /// - public void DebugWrite() - { - if (!IsValid) - { - Debug.WriteLine("==== Invalid HidEvent"); - return; - } - Device.DebugWrite(); - if (IsGeneric) Debug.WriteLine("==== Generic"); - if (IsKeyboard) Debug.WriteLine("==== Keyboard"); - if (IsMouse) Debug.WriteLine("==== Mouse"); - Debug.WriteLine("==== Foreground: " + IsForeground.ToString()); - Debug.WriteLine("==== UsagePage: 0x" + UsagePage.ToString("X4")); - Debug.WriteLine("==== UsageCollection: 0x" + UsageCollection.ToString("X4")); - foreach (ushort usage in Usages) - { - Debug.WriteLine("==== Usage: 0x" + usage.ToString("X4")); - } - } - public void StartRepeatTimer(double aInterval) { if (Timer == null) @@ -277,24 +270,79 @@ aHidEvent.OnHidEventRepeat(aHidEvent); } + /// + /// Print information about this device to our debug output. + /// + public void DebugWrite() + { + if (!IsValid) + { + Debug.WriteLine("==== Invalid HidEvent"); + return; + } + Device.DebugWrite(); + if (IsGeneric) Debug.WriteLine("==== Generic"); + if (IsKeyboard) Debug.WriteLine("==== Keyboard"); + if (IsMouse) Debug.WriteLine("==== Mouse"); + Debug.WriteLine("==== Foreground: " + IsForeground.ToString()); + Debug.WriteLine("==== UsagePage: 0x" + UsagePage.ToString("X4")); + Debug.WriteLine("==== UsageCollection: 0x" + UsageCollection.ToString("X4")); + Debug.WriteLine("==== InputReport: 0x" + InputReportString()); + foreach (ushort usage in Usages) + { + Debug.WriteLine("==== Usage: 0x" + usage.ToString("X4")); + } + } + + /// + /// + /// + /// + public string InputReportString() + { + string hidDump = ""; + foreach (byte b in InputReport) + { + hidDump += b.ToString("X2"); + } + return hidDump; + } + + + /// + /// Create a list view item describing this HidEvent + /// + /// public ListViewItem ToListViewItem() { - //TODO: What to do with multiple usage - string usage = ""; - UsagePage usagePage = (UsagePage)UsagePage; - switch (usagePage) - { - case Hid.UsagePage.Consumer: - usage = ((Hid.UsageTables.ConsumerControl)Usages[0]).ToString(); - break; + string usageText = ""; - case Hid.UsagePage.WindowsMediaCenterRemoteControl: - usage = ((Hid.UsageTables.WindowsMediaCenterRemoteControl)Usages[0]).ToString(); - break; + foreach (ushort usage in Usages) + { + if (usageText != "") + { + //Add a separator + usageText += ", "; + } - } + UsagePage usagePage = (UsagePage)UsagePage; + switch (usagePage) + { + case Hid.UsagePage.Consumer: + usageText += ((Hid.UsageTables.ConsumerControl)usage).ToString(); + break; - ListViewItem item = new ListViewItem(new[] { usage, UsagePage.ToString("X2"), UsageCollection.ToString("X2"), RepeatCount.ToString(), Time.ToString("HH:mm:ss:fff") }); + case Hid.UsagePage.WindowsMediaCenterRemoteControl: + usageText += ((Hid.UsageTables.WindowsMediaCenterRemoteControl)usage).ToString(); + break; + + default: + usageText += usage.ToString("X2"); + break; + } + } + + ListViewItem item = new ListViewItem(new[] { usageText, InputReportString(), UsagePage.ToString("X2"), UsageCollection.ToString("X2"), RepeatCount.ToString(), Time.ToString("HH:mm:ss:fff") }); return item; } diff -r 1eb878505ae1 -r 2ec781e51f36 HidHandler.cs --- a/HidHandler.cs Mon Feb 02 22:12:15 2015 +0100 +++ b/HidHandler.cs Wed Feb 11 19:46:21 2015 +0100 @@ -10,8 +10,6 @@ namespace Hid { - - /// /// Our HID handler manages raw input registrations, processes WM_INPUT messages and broadcasts HID events in return. /// @@ -42,7 +40,7 @@ } // - if (hidEvent.Usages[0] == 0) + if (hidEvent.IsButtonUp) { //This is a key up event //We need to discard any events belonging to the same page and collection diff -r 1eb878505ae1 -r 2ec781e51f36 MainForm.cs --- a/MainForm.cs Mon Feb 02 22:12:15 2015 +0100 +++ b/MainForm.cs Wed Feb 11 19:46:21 2015 +0100 @@ -21,11 +21,13 @@ private Label labelButtonName; private Label labelDeviceName; private ListView listViewEvents; - private ColumnHeader columnHeaderUsage; + private ColumnHeader columnHeaderUsages; private ColumnHeader columnHeaderUsagePage; private ColumnHeader columnHeaderUsageCollection; private ColumnHeader columnHeaderRepeat; private ColumnHeader columnHeaderTime; + private Button buttonClear; + private ColumnHeader columnHeaderInputReport; private Timer _timer; public delegate void OnHidEventDelegate(object aSender, Hid.HidEvent aHidEvent); @@ -65,93 +67,113 @@ /// private void InitializeComponent() { - this.labelButtonName = new System.Windows.Forms.Label(); - this.labelDeviceName = new System.Windows.Forms.Label(); - this.listViewEvents = new System.Windows.Forms.ListView(); - this.columnHeaderUsage = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); - this.columnHeaderUsagePage = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); - this.columnHeaderUsageCollection = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); - this.columnHeaderRepeat = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); - this.columnHeaderTime = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); - this.SuspendLayout(); - // - // labelButtonName - // - this.labelButtonName.AutoSize = true; - this.labelButtonName.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.labelButtonName.Location = new System.Drawing.Point(600, 32); - this.labelButtonName.Name = "labelButtonName"; - this.labelButtonName.Size = new System.Drawing.Size(103, 20); - this.labelButtonName.TabIndex = 0; - this.labelButtonName.Text = "Button Name"; - // - // labelDeviceName - // - this.labelDeviceName.AutoSize = true; - this.labelDeviceName.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.labelDeviceName.Location = new System.Drawing.Point(600, 12); - this.labelDeviceName.Name = "labelDeviceName"; - this.labelDeviceName.Size = new System.Drawing.Size(103, 20); - this.labelDeviceName.TabIndex = 1; - this.labelDeviceName.Text = "Device Name"; - // - // listViewEvents - // - this.listViewEvents.Alignment = System.Windows.Forms.ListViewAlignment.Left; - this.listViewEvents.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + this.labelButtonName = new System.Windows.Forms.Label(); + this.labelDeviceName = new System.Windows.Forms.Label(); + this.listViewEvents = new System.Windows.Forms.ListView(); + this.columnHeaderUsages = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.columnHeaderUsagePage = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.columnHeaderUsageCollection = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.columnHeaderRepeat = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.columnHeaderTime = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.buttonClear = new System.Windows.Forms.Button(); + this.columnHeaderInputReport = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.SuspendLayout(); + // + // labelButtonName + // + this.labelButtonName.AutoSize = true; + this.labelButtonName.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.labelButtonName.Location = new System.Drawing.Point(811, 55); + this.labelButtonName.Name = "labelButtonName"; + this.labelButtonName.Size = new System.Drawing.Size(103, 20); + this.labelButtonName.TabIndex = 0; + this.labelButtonName.Text = "Button Name"; + // + // labelDeviceName + // + this.labelDeviceName.AutoSize = true; + this.labelDeviceName.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.labelDeviceName.Location = new System.Drawing.Point(811, 35); + this.labelDeviceName.Name = "labelDeviceName"; + this.labelDeviceName.Size = new System.Drawing.Size(103, 20); + this.labelDeviceName.TabIndex = 1; + this.labelDeviceName.Text = "Device Name"; + // + // listViewEvents + // + this.listViewEvents.Alignment = System.Windows.Forms.ListViewAlignment.Left; + this.listViewEvents.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | System.Windows.Forms.AnchorStyles.Left))); - this.listViewEvents.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; - this.listViewEvents.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { - this.columnHeaderUsage, + this.listViewEvents.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.listViewEvents.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.columnHeaderUsages, + this.columnHeaderInputReport, this.columnHeaderUsagePage, this.columnHeaderUsageCollection, this.columnHeaderRepeat, this.columnHeaderTime}); - this.listViewEvents.GridLines = true; - this.listViewEvents.Location = new System.Drawing.Point(12, 12); - this.listViewEvents.Name = "listViewEvents"; - this.listViewEvents.Size = new System.Drawing.Size(582, 369); - this.listViewEvents.TabIndex = 2; - this.listViewEvents.UseCompatibleStateImageBehavior = false; - this.listViewEvents.View = System.Windows.Forms.View.Details; - // - // columnHeaderUsage - // - this.columnHeaderUsage.Text = "Usage"; - this.columnHeaderUsage.Width = 180; - // - // columnHeaderUsagePage - // - this.columnHeaderUsagePage.Text = "Usage Page"; - this.columnHeaderUsagePage.Width = 120; - // - // columnHeaderUsageCollection - // - this.columnHeaderUsageCollection.Text = "Usage Collection"; - this.columnHeaderUsageCollection.Width = 120; - // - // columnHeaderRepeat - // - this.columnHeaderRepeat.Text = "Repeat"; - // - // columnHeaderTime - // - this.columnHeaderTime.Text = "Time"; - this.columnHeaderTime.Width = 76; - // - // MainForm - // - this.AutoScaleBaseSize = new System.Drawing.Size(5, 13); - this.BackColor = System.Drawing.SystemColors.Control; - this.ClientSize = new System.Drawing.Size(926, 393); - this.Controls.Add(this.listViewEvents); - this.Controls.Add(this.labelDeviceName); - this.Controls.Add(this.labelButtonName); - this.Name = "MainForm"; - this.Text = "Remote Control Sample"; - this.Load += new System.EventHandler(this.Form1_Load); - this.ResumeLayout(false); - this.PerformLayout(); + this.listViewEvents.GridLines = true; + this.listViewEvents.Location = new System.Drawing.Point(12, 12); + this.listViewEvents.Name = "listViewEvents"; + this.listViewEvents.Size = new System.Drawing.Size(766, 369); + this.listViewEvents.TabIndex = 2; + this.listViewEvents.UseCompatibleStateImageBehavior = false; + this.listViewEvents.View = System.Windows.Forms.View.Details; + // + // columnHeaderUsages + // + this.columnHeaderUsages.Text = "Usages"; + this.columnHeaderUsages.Width = 180; + // + // columnHeaderUsagePage + // + this.columnHeaderUsagePage.Text = "Usage Page"; + this.columnHeaderUsagePage.Width = 87; + // + // columnHeaderUsageCollection + // + this.columnHeaderUsageCollection.Text = "Usage Collection"; + this.columnHeaderUsageCollection.Width = 134; + // + // columnHeaderRepeat + // + this.columnHeaderRepeat.Text = "Repeat"; + this.columnHeaderRepeat.Width = 68; + // + // columnHeaderTime + // + this.columnHeaderTime.Text = "Time"; + this.columnHeaderTime.Width = 76; + // + // buttonClear + // + this.buttonClear.Location = new System.Drawing.Point(839, 9); + this.buttonClear.Name = "buttonClear"; + this.buttonClear.Size = new System.Drawing.Size(75, 23); + this.buttonClear.TabIndex = 3; + this.buttonClear.Text = "Clear"; + this.buttonClear.UseVisualStyleBackColor = true; + this.buttonClear.Click += new System.EventHandler(this.buttonClear_Click); + // + // columnHeaderInputReport + // + this.columnHeaderInputReport.Text = "Input Report"; + this.columnHeaderInputReport.Width = 176; + // + // MainForm + // + this.AutoScaleBaseSize = new System.Drawing.Size(5, 13); + this.BackColor = System.Drawing.SystemColors.Control; + this.ClientSize = new System.Drawing.Size(926, 393); + this.Controls.Add(this.buttonClear); + this.Controls.Add(this.listViewEvents); + this.Controls.Add(this.labelDeviceName); + this.Controls.Add(this.labelButtonName); + this.Name = "MainForm"; + this.Text = "Remote Control Sample"; + this.Load += new System.EventHandler(this.Form1_Load); + this.ResumeLayout(false); + this.PerformLayout(); } #endregion Windows Form Designer generated code @@ -247,5 +269,10 @@ labelButtonName.Text = "Ready..."; } + private void buttonClear_Click(object sender, EventArgs e) + { + listViewEvents.Items.Clear(); + } + } } diff -r 1eb878505ae1 -r 2ec781e51f36 RemoteControlDevice.cs --- a/RemoteControlDevice.cs Mon Feb 02 22:12:15 2015 +0100 +++ b/RemoteControlDevice.cs Wed Feb 11 19:46:21 2015 +0100 @@ -205,6 +205,12 @@ rid[i].dwFlags = Const.RIDEV_EXINPUTSINK; rid[i].hwndTarget = aHWND; + //i++; + rid[i].usUsagePage = (ushort)Hid.UsagePage.GenericDesktopControls; + rid[i].usUsage = (ushort)Hid.UsageCollectionGenericDesktop.GamePad; + rid[i].dwFlags = Const.RIDEV_EXINPUTSINK; + rid[i].hwndTarget = aHWND; + //i++; //rid[i].usUsagePage = (ushort)Hid.UsagePage.GenericDesktopControls; //rid[i].usUsage = (ushort)Hid.UsageCollectionGenericDesktop.Keyboard;