# HG changeset patch
# User StephaneLenclud
# Date 1426409617 -3600
# Node ID 471b1d45c46a0d752967cadfc8d3901a92a09bfe
# Parent  c28dd93b94c5be1ce8144e9871f59042650abc09
Adding button count property to HID device.
Adding device list refresh button.
Better reporting of input value capabilities description.
diff -r c28dd93b94c5 -r 471b1d45c46a HidDevice.cs
--- a/HidDevice.cs	Thu Mar 05 10:12:37 2015 +0100
+++ b/HidDevice.cs	Sun Mar 15 09:53:37 2015 +0100
@@ -47,6 +47,9 @@
         public HIDP_VALUE_CAPS[] InputValueCapabilities { get { return iInputValueCapabilities; } }
         private HIDP_VALUE_CAPS[] iInputValueCapabilities;
 
+        //
+        public int ButtonCount { get; private set; }
+
         /// 
         /// Class constructor will fetch this object properties from HID sub system.
         /// 
@@ -167,6 +170,8 @@
                 {
                     throw new Exception("HidDevice: HidP_GetButtonCaps failed: " + status.ToString());
                 }
+
+                ComputeButtonCount();
             }
 
             //Get input value caps if needed
@@ -182,6 +187,23 @@
             }
         }
 
+
+        /// 
+        /// Useful for gamepads.
+        /// 
+        void ComputeButtonCount()
+        {
+            ButtonCount = 0;
+            foreach (HIDP_BUTTON_CAPS bc in iInputButtonCapabilities)
+            {
+                if (bc.IsRange)
+                {
+                    ButtonCount += (bc.Range.UsageMax - bc.Range.UsageMin + 1);
+                }
+            }            
+        }
+
+
         /// 
         /// 
         /// 
@@ -273,7 +295,8 @@
         }
 
         /// 
-        /// 
+        /// Provide a description for the given capabilities.
+        /// Notably describes axis on a gamepad/joystick.
         /// 
         /// 
         /// 
@@ -281,7 +304,20 @@
         {
             if (!aCaps.IsRange && Enum.IsDefined(typeof(UsagePage), Capabilities.UsagePage))
             {
-                return "Input Value: " + Enum.GetName(Utils.UsageType((UsagePage)Capabilities.UsagePage), aCaps.NotRange.Usage);
+                Type usageType=Utils.UsageType((UsagePage)Capabilities.UsagePage);
+                string name = Enum.GetName(usageType, aCaps.NotRange.Usage);
+                if (name == null)
+                {
+                    //Could not find that usage in our enum.
+                    //Provide a relevant warning instead.
+                    name = "Usage 0x" + aCaps.NotRange.Usage.ToString("X2") + " not defined in " + usageType.Name;
+                }
+                else
+                {
+                    //Prepend our usage type name
+                    name = usageType.Name + "." + name;
+                }
+                return "Input Value: " + name;
             }
 
             return null;
diff -r c28dd93b94c5 -r 471b1d45c46a HidEvent.cs
--- a/HidEvent.cs	Thu Mar 05 10:12:37 2015 +0100
+++ b/HidEvent.cs	Sun Mar 15 09:53:37 2015 +0100
@@ -22,6 +22,9 @@
         public bool IsBackground { get { return !IsForeground; } }
         public bool IsMouse { get; private set; }
         public bool IsKeyboard { get; private set; }
+        /// 
+        /// If this not a mouse or keyboard event then it's a generic HID event.
+        /// 
         public bool IsGeneric { get; private set; }
         public bool IsButtonDown { get { return Usages.Count == 1 && Usages[0] != 0; } }
         public bool IsButtonUp { get { return Usages.Count == 0; } }
@@ -29,6 +32,8 @@
         public uint RepeatCount { get; private set; }
 
         public HidDevice Device { get; private set; }
+        public RAWINPUT RawInput { get {return iRawInput;} } 
+        private RAWINPUT iRawInput;
 
         public ushort UsagePage { get; private set; }
         public ushort UsageCollection { get; private set; }
@@ -76,7 +81,6 @@
             IsKeyboard = false;
             IsGeneric = false;
 
-
             Time = DateTime.Now;
             OriginalTime = DateTime.Now;
             Timer = new System.Timers.Timer();
@@ -105,8 +109,8 @@
             try
             {
                 //Fetch raw input
-                RAWINPUT rawInput = new RAWINPUT();
-                if (!Win32.RawInput.GetRawInputData(aMessage.LParam, ref rawInput, ref rawInputBuffer))
+                iRawInput = new RAWINPUT();
+                if (!Win32.RawInput.GetRawInputData(aMessage.LParam, ref iRawInput, ref rawInputBuffer))
                 {
                     Debug.WriteLine("GetRawInputData failed!");
                     return;
@@ -114,13 +118,13 @@
 
                 //Our device can actually be null.
                 //This is notably happening for some keyboard events
-                if (rawInput.header.hDevice != IntPtr.Zero)
+                if (RawInput.header.hDevice != IntPtr.Zero)
                 {
                     //Get various information about this HID device
-                    Device = new Hid.HidDevice(rawInput.header.hDevice);
+                    Device = new Hid.HidDevice(RawInput.header.hDevice);
                 }
 
-                if (rawInput.header.dwType == Win32.RawInputDeviceType.RIM_TYPEHID)  //Check that our raw input is HID                        
+                if (RawInput.header.dwType == Win32.RawInputDeviceType.RIM_TYPEHID)  //Check that our raw input is HID                        
                 {
                     IsGeneric = true;
 
@@ -130,31 +134,31 @@
                     UsagePage = Device.Info.hid.usUsagePage;
                     UsageCollection = Device.Info.hid.usUsage;
 
-                    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
+                    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
-                    InputReport = new byte[rawInput.hid.dwSizeHid];
+                    InputReport = new byte[RawInput.hid.dwSizeHid];
 
-                    Debug.WriteLine("Raw input contains " + rawInput.hid.dwCount + " HID input report(s)");
+                    Debug.WriteLine("Raw input contains " + RawInput.hid.dwCount + " HID input report(s)");
 
                     //For each HID input report in our raw input
-                    for (int i = 0; i < rawInput.hid.dwCount; i++)
+                    for (int i = 0; i < RawInput.hid.dwCount; i++)
                     {
                         //Compute the address from which to copy our HID input
                         int hidInputOffset = 0;
                         unsafe
                         {
                             byte* source = (byte*)rawInputBuffer;
-                            source += sizeof(RAWINPUTHEADER) + sizeof(RAWHID) + (rawInput.hid.dwSizeHid * i);
+                            source += sizeof(RAWINPUTHEADER) + sizeof(RAWHID) + (RawInput.hid.dwSizeHid * i);
                             hidInputOffset = (int)source;
                         }
 
                         //Copy HID input into our buffer
-                        Marshal.Copy(new IntPtr(hidInputOffset), InputReport, 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: " + InputReportString();
@@ -196,14 +200,14 @@
                         }
                     }
                 }
-                else if (rawInput.header.dwType == RawInputDeviceType.RIM_TYPEMOUSE)
+                else if (RawInput.header.dwType == RawInputDeviceType.RIM_TYPEMOUSE)
                 {
                     IsMouse = true;
 
                     Debug.WriteLine("WM_INPUT source device is Mouse.");
                     // do mouse handling...
                 }
-                else if (rawInput.header.dwType == RawInputDeviceType.RIM_TYPEKEYBOARD)
+                else if (RawInput.header.dwType == RawInputDeviceType.RIM_TYPEKEYBOARD)
                 {
                     IsKeyboard = true;
 
diff -r c28dd93b94c5 -r 471b1d45c46a MainForm.Designer.cs
--- a/MainForm.Designer.cs	Thu Mar 05 10:12:37 2015 +0100
+++ b/MainForm.Designer.cs	Sun Mar 15 09:53:37 2015 +0100
@@ -29,15 +29,16 @@
             this.buttonTreeViewExpandAll = new System.Windows.Forms.Button();
             this.buttonTreeViewCollapseAll = new System.Windows.Forms.Button();
             this.treeViewDevices = new System.Windows.Forms.TreeView();
+            this.tabPageTests = new System.Windows.Forms.TabPage();
+            this.textBoxTests = new System.Windows.Forms.TextBox();
             this.statusStrip = new System.Windows.Forms.StatusStrip();
             this.toolStripStatusLabelDevice = new System.Windows.Forms.ToolStripStatusLabel();
-            this.tabPageTests = new System.Windows.Forms.TabPage();
-            this.textBoxTests = new System.Windows.Forms.TextBox();
+            this.buttonRefresh = new System.Windows.Forms.Button();
             this.tabControl.SuspendLayout();
             this.tabPageMessages.SuspendLayout();
             this.tabPageDevices.SuspendLayout();
+            this.tabPageTests.SuspendLayout();
             this.statusStrip.SuspendLayout();
-            this.tabPageTests.SuspendLayout();
             this.SuspendLayout();
             // 
             // labelButtonName
@@ -150,6 +151,7 @@
             // 
             // tabPageDevices
             // 
+            this.tabPageDevices.Controls.Add(this.buttonRefresh);
             this.tabPageDevices.Controls.Add(this.buttonTreeViewExpandAll);
             this.tabPageDevices.Controls.Add(this.buttonTreeViewCollapseAll);
             this.tabPageDevices.Controls.Add(this.treeViewDevices);
@@ -190,22 +192,6 @@
             this.treeViewDevices.Size = new System.Drawing.Size(713, 492);
             this.treeViewDevices.TabIndex = 0;
             // 
-            // statusStrip
-            // 
-            this.statusStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
-            this.toolStripStatusLabelDevice});
-            this.statusStrip.Location = new System.Drawing.Point(0, 547);
-            this.statusStrip.Name = "statusStrip";
-            this.statusStrip.Size = new System.Drawing.Size(935, 22);
-            this.statusStrip.TabIndex = 5;
-            this.statusStrip.Text = "statusStrip1";
-            // 
-            // toolStripStatusLabelDevice
-            // 
-            this.toolStripStatusLabelDevice.Name = "toolStripStatusLabelDevice";
-            this.toolStripStatusLabelDevice.Size = new System.Drawing.Size(61, 17);
-            this.toolStripStatusLabelDevice.Text = "No Device";
-            // 
             // tabPageTests
             // 
             this.tabPageTests.Controls.Add(this.textBoxTests);
@@ -224,6 +210,32 @@
             this.textBoxTests.Size = new System.Drawing.Size(887, 499);
             this.textBoxTests.TabIndex = 0;
             // 
+            // statusStrip
+            // 
+            this.statusStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
+            this.toolStripStatusLabelDevice});
+            this.statusStrip.Location = new System.Drawing.Point(0, 547);
+            this.statusStrip.Name = "statusStrip";
+            this.statusStrip.Size = new System.Drawing.Size(935, 22);
+            this.statusStrip.TabIndex = 5;
+            this.statusStrip.Text = "statusStrip1";
+            // 
+            // toolStripStatusLabelDevice
+            // 
+            this.toolStripStatusLabelDevice.Name = "toolStripStatusLabelDevice";
+            this.toolStripStatusLabelDevice.Size = new System.Drawing.Size(61, 17);
+            this.toolStripStatusLabelDevice.Text = "No Device";
+            // 
+            // buttonRefresh
+            // 
+            this.buttonRefresh.Location = new System.Drawing.Point(813, 64);
+            this.buttonRefresh.Name = "buttonRefresh";
+            this.buttonRefresh.Size = new System.Drawing.Size(75, 23);
+            this.buttonRefresh.TabIndex = 3;
+            this.buttonRefresh.Text = "Refresh";
+            this.buttonRefresh.UseVisualStyleBackColor = true;
+            this.buttonRefresh.Click += new System.EventHandler(this.buttonRefresh_Click);
+            // 
             // MainForm
             // 
             this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
@@ -238,10 +250,10 @@
             this.tabPageMessages.ResumeLayout(false);
             this.tabPageMessages.PerformLayout();
             this.tabPageDevices.ResumeLayout(false);
+            this.tabPageTests.ResumeLayout(false);
+            this.tabPageTests.PerformLayout();
             this.statusStrip.ResumeLayout(false);
             this.statusStrip.PerformLayout();
-            this.tabPageTests.ResumeLayout(false);
-            this.tabPageTests.PerformLayout();
             this.ResumeLayout(false);
             this.PerformLayout();
 
@@ -254,6 +266,7 @@
         private System.Windows.Forms.ToolStripStatusLabel toolStripStatusLabelDevice;
         private System.Windows.Forms.TabPage tabPageTests;
         private System.Windows.Forms.TextBox textBoxTests;
+        private System.Windows.Forms.Button buttonRefresh;
 
     }
 }
diff -r c28dd93b94c5 -r 471b1d45c46a MainForm.cs
--- a/MainForm.cs	Thu Mar 05 10:12:37 2015 +0100
+++ b/MainForm.cs	Sun Mar 15 09:53:37 2015 +0100
@@ -177,5 +177,11 @@
             treeViewDevices.ExpandAll();
         }
 
+        private void buttonRefresh_Click(object sender, EventArgs e)
+        {
+            treeViewDevices.Nodes.Clear();
+            Win32.RawInput.PopulateDeviceList(treeViewDevices);
+        }
+
 	}
 }
diff -r c28dd93b94c5 -r 471b1d45c46a RawInput.cs
--- a/RawInput.cs	Thu Mar 05 10:12:37 2015 +0100
+++ b/RawInput.cs	Sun Mar 15 09:53:37 2015 +0100
@@ -207,6 +207,10 @@
                     node.Nodes.Add(hidDevice.InputCapabilitiesDescription);
                 }
 
+                //Add button count
+                node.Nodes.Add("Button Count: " + hidDevice.ButtonCount);
+
+                //Those can be joystick/gamepad axis
                 if (hidDevice.InputValueCapabilities != null)
                 {
                     foreach (HIDP_VALUE_CAPS caps in hidDevice.InputValueCapabilities)
diff -r c28dd93b94c5 -r 471b1d45c46a Win32Hid.cs
--- a/Win32Hid.cs	Thu Mar 05 10:12:37 2015 +0100
+++ b/Win32Hid.cs	Sun Mar 15 09:53:37 2015 +0100
@@ -302,10 +302,10 @@
 
         /// Union Range/NotRange
         [FieldOffset(56)]
-        HIDP_BUTTON_CAPS_RANGE Range;
+        public HIDP_BUTTON_CAPS_RANGE Range;
 
         [FieldOffset(56)]
-        HIDP_BUTTON_CAPS_NOT_RANGE NotRange;       
+        public HIDP_BUTTON_CAPS_NOT_RANGE NotRange;       
     }
 
     ///