Adding button count property to HID device.
Adding device list refresh button.
Better reporting of input value capabilities description.
     1.1 --- a/HidDevice.cs	Thu Mar 05 10:12:37 2015 +0100
     1.2 +++ b/HidDevice.cs	Sun Mar 15 09:53:37 2015 +0100
     1.3 @@ -47,6 +47,9 @@
     1.4          public HIDP_VALUE_CAPS[] InputValueCapabilities { get { return iInputValueCapabilities; } }
     1.5          private HIDP_VALUE_CAPS[] iInputValueCapabilities;
     1.6  
     1.7 +        //
     1.8 +        public int ButtonCount { get; private set; }
     1.9 +
    1.10          /// <summary>
    1.11          /// Class constructor will fetch this object properties from HID sub system.
    1.12          /// </summary>
    1.13 @@ -167,6 +170,8 @@
    1.14                  {
    1.15                      throw new Exception("HidDevice: HidP_GetButtonCaps failed: " + status.ToString());
    1.16                  }
    1.17 +
    1.18 +                ComputeButtonCount();
    1.19              }
    1.20  
    1.21              //Get input value caps if needed
    1.22 @@ -182,6 +187,23 @@
    1.23              }
    1.24          }
    1.25  
    1.26 +
    1.27 +        /// <summary>
    1.28 +        /// Useful for gamepads.
    1.29 +        /// </summary>
    1.30 +        void ComputeButtonCount()
    1.31 +        {
    1.32 +            ButtonCount = 0;
    1.33 +            foreach (HIDP_BUTTON_CAPS bc in iInputButtonCapabilities)
    1.34 +            {
    1.35 +                if (bc.IsRange)
    1.36 +                {
    1.37 +                    ButtonCount += (bc.Range.UsageMax - bc.Range.UsageMin + 1);
    1.38 +                }
    1.39 +            }            
    1.40 +        }
    1.41 +
    1.42 +
    1.43          /// <summary>
    1.44          /// 
    1.45          /// </summary>
    1.46 @@ -273,7 +295,8 @@
    1.47          }
    1.48  
    1.49          /// <summary>
    1.50 -        /// 
    1.51 +        /// Provide a description for the given capabilities.
    1.52 +        /// Notably describes axis on a gamepad/joystick.
    1.53          /// </summary>
    1.54          /// <param name="aCaps"></param>
    1.55          /// <returns></returns>
    1.56 @@ -281,7 +304,20 @@
    1.57          {
    1.58              if (!aCaps.IsRange && Enum.IsDefined(typeof(UsagePage), Capabilities.UsagePage))
    1.59              {
    1.60 -                return "Input Value: " + Enum.GetName(Utils.UsageType((UsagePage)Capabilities.UsagePage), aCaps.NotRange.Usage);
    1.61 +                Type usageType=Utils.UsageType((UsagePage)Capabilities.UsagePage);
    1.62 +                string name = Enum.GetName(usageType, aCaps.NotRange.Usage);
    1.63 +                if (name == null)
    1.64 +                {
    1.65 +                    //Could not find that usage in our enum.
    1.66 +                    //Provide a relevant warning instead.
    1.67 +                    name = "Usage 0x" + aCaps.NotRange.Usage.ToString("X2") + " not defined in " + usageType.Name;
    1.68 +                }
    1.69 +                else
    1.70 +                {
    1.71 +                    //Prepend our usage type name
    1.72 +                    name = usageType.Name + "." + name;
    1.73 +                }
    1.74 +                return "Input Value: " + name;
    1.75              }
    1.76  
    1.77              return null;
     2.1 --- a/HidEvent.cs	Thu Mar 05 10:12:37 2015 +0100
     2.2 +++ b/HidEvent.cs	Sun Mar 15 09:53:37 2015 +0100
     2.3 @@ -22,6 +22,9 @@
     2.4          public bool IsBackground { get { return !IsForeground; } }
     2.5          public bool IsMouse { get; private set; }
     2.6          public bool IsKeyboard { get; private set; }
     2.7 +        /// <summary>
     2.8 +        /// If this not a mouse or keyboard event then it's a generic HID event.
     2.9 +        /// </summary>
    2.10          public bool IsGeneric { get; private set; }
    2.11          public bool IsButtonDown { get { return Usages.Count == 1 && Usages[0] != 0; } }
    2.12          public bool IsButtonUp { get { return Usages.Count == 0; } }
    2.13 @@ -29,6 +32,8 @@
    2.14          public uint RepeatCount { get; private set; }
    2.15  
    2.16          public HidDevice Device { get; private set; }
    2.17 +        public RAWINPUT RawInput { get {return iRawInput;} } 
    2.18 +        private RAWINPUT iRawInput;
    2.19  
    2.20          public ushort UsagePage { get; private set; }
    2.21          public ushort UsageCollection { get; private set; }
    2.22 @@ -76,7 +81,6 @@
    2.23              IsKeyboard = false;
    2.24              IsGeneric = false;
    2.25  
    2.26 -
    2.27              Time = DateTime.Now;
    2.28              OriginalTime = DateTime.Now;
    2.29              Timer = new System.Timers.Timer();
    2.30 @@ -105,8 +109,8 @@
    2.31              try
    2.32              {
    2.33                  //Fetch raw input
    2.34 -                RAWINPUT rawInput = new RAWINPUT();
    2.35 -                if (!Win32.RawInput.GetRawInputData(aMessage.LParam, ref rawInput, ref rawInputBuffer))
    2.36 +                iRawInput = new RAWINPUT();
    2.37 +                if (!Win32.RawInput.GetRawInputData(aMessage.LParam, ref iRawInput, ref rawInputBuffer))
    2.38                  {
    2.39                      Debug.WriteLine("GetRawInputData failed!");
    2.40                      return;
    2.41 @@ -114,13 +118,13 @@
    2.42  
    2.43                  //Our device can actually be null.
    2.44                  //This is notably happening for some keyboard events
    2.45 -                if (rawInput.header.hDevice != IntPtr.Zero)
    2.46 +                if (RawInput.header.hDevice != IntPtr.Zero)
    2.47                  {
    2.48                      //Get various information about this HID device
    2.49 -                    Device = new Hid.HidDevice(rawInput.header.hDevice);
    2.50 +                    Device = new Hid.HidDevice(RawInput.header.hDevice);
    2.51                  }
    2.52  
    2.53 -                if (rawInput.header.dwType == Win32.RawInputDeviceType.RIM_TYPEHID)  //Check that our raw input is HID                        
    2.54 +                if (RawInput.header.dwType == Win32.RawInputDeviceType.RIM_TYPEHID)  //Check that our raw input is HID                        
    2.55                  {
    2.56                      IsGeneric = true;
    2.57  
    2.58 @@ -130,31 +134,31 @@
    2.59                      UsagePage = Device.Info.hid.usUsagePage;
    2.60                      UsageCollection = Device.Info.hid.usUsage;
    2.61  
    2.62 -                    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
    2.63 -                        && rawInput.hid.dwCount > 0))    //Check that we have at least one HID msg
    2.64 +                    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
    2.65 +                        && RawInput.hid.dwCount > 0))    //Check that we have at least one HID msg
    2.66                      {
    2.67                          return;
    2.68                      }
    2.69  
    2.70                      //Allocate a buffer for one HID input
    2.71 -                    InputReport = new byte[rawInput.hid.dwSizeHid];
    2.72 +                    InputReport = new byte[RawInput.hid.dwSizeHid];
    2.73  
    2.74 -                    Debug.WriteLine("Raw input contains " + rawInput.hid.dwCount + " HID input report(s)");
    2.75 +                    Debug.WriteLine("Raw input contains " + RawInput.hid.dwCount + " HID input report(s)");
    2.76  
    2.77                      //For each HID input report in our raw input
    2.78 -                    for (int i = 0; i < rawInput.hid.dwCount; i++)
    2.79 +                    for (int i = 0; i < RawInput.hid.dwCount; i++)
    2.80                      {
    2.81                          //Compute the address from which to copy our HID input
    2.82                          int hidInputOffset = 0;
    2.83                          unsafe
    2.84                          {
    2.85                              byte* source = (byte*)rawInputBuffer;
    2.86 -                            source += sizeof(RAWINPUTHEADER) + sizeof(RAWHID) + (rawInput.hid.dwSizeHid * i);
    2.87 +                            source += sizeof(RAWINPUTHEADER) + sizeof(RAWHID) + (RawInput.hid.dwSizeHid * i);
    2.88                              hidInputOffset = (int)source;
    2.89                          }
    2.90  
    2.91                          //Copy HID input into our buffer
    2.92 -                        Marshal.Copy(new IntPtr(hidInputOffset), InputReport, 0, (int)rawInput.hid.dwSizeHid);
    2.93 +                        Marshal.Copy(new IntPtr(hidInputOffset), InputReport, 0, (int)RawInput.hid.dwSizeHid);
    2.94  
    2.95                          //Print HID input report in our debug output
    2.96                          //string hidDump = "HID input report: " + InputReportString();
    2.97 @@ -196,14 +200,14 @@
    2.98                          }
    2.99                      }
   2.100                  }
   2.101 -                else if (rawInput.header.dwType == RawInputDeviceType.RIM_TYPEMOUSE)
   2.102 +                else if (RawInput.header.dwType == RawInputDeviceType.RIM_TYPEMOUSE)
   2.103                  {
   2.104                      IsMouse = true;
   2.105  
   2.106                      Debug.WriteLine("WM_INPUT source device is Mouse.");
   2.107                      // do mouse handling...
   2.108                  }
   2.109 -                else if (rawInput.header.dwType == RawInputDeviceType.RIM_TYPEKEYBOARD)
   2.110 +                else if (RawInput.header.dwType == RawInputDeviceType.RIM_TYPEKEYBOARD)
   2.111                  {
   2.112                      IsKeyboard = true;
   2.113  
     3.1 --- a/MainForm.Designer.cs	Thu Mar 05 10:12:37 2015 +0100
     3.2 +++ b/MainForm.Designer.cs	Sun Mar 15 09:53:37 2015 +0100
     3.3 @@ -29,15 +29,16 @@
     3.4              this.buttonTreeViewExpandAll = new System.Windows.Forms.Button();
     3.5              this.buttonTreeViewCollapseAll = new System.Windows.Forms.Button();
     3.6              this.treeViewDevices = new System.Windows.Forms.TreeView();
     3.7 +            this.tabPageTests = new System.Windows.Forms.TabPage();
     3.8 +            this.textBoxTests = new System.Windows.Forms.TextBox();
     3.9              this.statusStrip = new System.Windows.Forms.StatusStrip();
    3.10              this.toolStripStatusLabelDevice = new System.Windows.Forms.ToolStripStatusLabel();
    3.11 -            this.tabPageTests = new System.Windows.Forms.TabPage();
    3.12 -            this.textBoxTests = new System.Windows.Forms.TextBox();
    3.13 +            this.buttonRefresh = new System.Windows.Forms.Button();
    3.14              this.tabControl.SuspendLayout();
    3.15              this.tabPageMessages.SuspendLayout();
    3.16              this.tabPageDevices.SuspendLayout();
    3.17 +            this.tabPageTests.SuspendLayout();
    3.18              this.statusStrip.SuspendLayout();
    3.19 -            this.tabPageTests.SuspendLayout();
    3.20              this.SuspendLayout();
    3.21              // 
    3.22              // labelButtonName
    3.23 @@ -150,6 +151,7 @@
    3.24              // 
    3.25              // tabPageDevices
    3.26              // 
    3.27 +            this.tabPageDevices.Controls.Add(this.buttonRefresh);
    3.28              this.tabPageDevices.Controls.Add(this.buttonTreeViewExpandAll);
    3.29              this.tabPageDevices.Controls.Add(this.buttonTreeViewCollapseAll);
    3.30              this.tabPageDevices.Controls.Add(this.treeViewDevices);
    3.31 @@ -190,22 +192,6 @@
    3.32              this.treeViewDevices.Size = new System.Drawing.Size(713, 492);
    3.33              this.treeViewDevices.TabIndex = 0;
    3.34              // 
    3.35 -            // statusStrip
    3.36 -            // 
    3.37 -            this.statusStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
    3.38 -            this.toolStripStatusLabelDevice});
    3.39 -            this.statusStrip.Location = new System.Drawing.Point(0, 547);
    3.40 -            this.statusStrip.Name = "statusStrip";
    3.41 -            this.statusStrip.Size = new System.Drawing.Size(935, 22);
    3.42 -            this.statusStrip.TabIndex = 5;
    3.43 -            this.statusStrip.Text = "statusStrip1";
    3.44 -            // 
    3.45 -            // toolStripStatusLabelDevice
    3.46 -            // 
    3.47 -            this.toolStripStatusLabelDevice.Name = "toolStripStatusLabelDevice";
    3.48 -            this.toolStripStatusLabelDevice.Size = new System.Drawing.Size(61, 17);
    3.49 -            this.toolStripStatusLabelDevice.Text = "No Device";
    3.50 -            // 
    3.51              // tabPageTests
    3.52              // 
    3.53              this.tabPageTests.Controls.Add(this.textBoxTests);
    3.54 @@ -224,6 +210,32 @@
    3.55              this.textBoxTests.Size = new System.Drawing.Size(887, 499);
    3.56              this.textBoxTests.TabIndex = 0;
    3.57              // 
    3.58 +            // statusStrip
    3.59 +            // 
    3.60 +            this.statusStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
    3.61 +            this.toolStripStatusLabelDevice});
    3.62 +            this.statusStrip.Location = new System.Drawing.Point(0, 547);
    3.63 +            this.statusStrip.Name = "statusStrip";
    3.64 +            this.statusStrip.Size = new System.Drawing.Size(935, 22);
    3.65 +            this.statusStrip.TabIndex = 5;
    3.66 +            this.statusStrip.Text = "statusStrip1";
    3.67 +            // 
    3.68 +            // toolStripStatusLabelDevice
    3.69 +            // 
    3.70 +            this.toolStripStatusLabelDevice.Name = "toolStripStatusLabelDevice";
    3.71 +            this.toolStripStatusLabelDevice.Size = new System.Drawing.Size(61, 17);
    3.72 +            this.toolStripStatusLabelDevice.Text = "No Device";
    3.73 +            // 
    3.74 +            // buttonRefresh
    3.75 +            // 
    3.76 +            this.buttonRefresh.Location = new System.Drawing.Point(813, 64);
    3.77 +            this.buttonRefresh.Name = "buttonRefresh";
    3.78 +            this.buttonRefresh.Size = new System.Drawing.Size(75, 23);
    3.79 +            this.buttonRefresh.TabIndex = 3;
    3.80 +            this.buttonRefresh.Text = "Refresh";
    3.81 +            this.buttonRefresh.UseVisualStyleBackColor = true;
    3.82 +            this.buttonRefresh.Click += new System.EventHandler(this.buttonRefresh_Click);
    3.83 +            // 
    3.84              // MainForm
    3.85              // 
    3.86              this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
    3.87 @@ -238,10 +250,10 @@
    3.88              this.tabPageMessages.ResumeLayout(false);
    3.89              this.tabPageMessages.PerformLayout();
    3.90              this.tabPageDevices.ResumeLayout(false);
    3.91 +            this.tabPageTests.ResumeLayout(false);
    3.92 +            this.tabPageTests.PerformLayout();
    3.93              this.statusStrip.ResumeLayout(false);
    3.94              this.statusStrip.PerformLayout();
    3.95 -            this.tabPageTests.ResumeLayout(false);
    3.96 -            this.tabPageTests.PerformLayout();
    3.97              this.ResumeLayout(false);
    3.98              this.PerformLayout();
    3.99  
   3.100 @@ -254,6 +266,7 @@
   3.101          private System.Windows.Forms.ToolStripStatusLabel toolStripStatusLabelDevice;
   3.102          private System.Windows.Forms.TabPage tabPageTests;
   3.103          private System.Windows.Forms.TextBox textBoxTests;
   3.104 +        private System.Windows.Forms.Button buttonRefresh;
   3.105  
   3.106      }
   3.107  }
     4.1 --- a/MainForm.cs	Thu Mar 05 10:12:37 2015 +0100
     4.2 +++ b/MainForm.cs	Sun Mar 15 09:53:37 2015 +0100
     4.3 @@ -177,5 +177,11 @@
     4.4              treeViewDevices.ExpandAll();
     4.5          }
     4.6  
     4.7 +        private void buttonRefresh_Click(object sender, EventArgs e)
     4.8 +        {
     4.9 +            treeViewDevices.Nodes.Clear();
    4.10 +            Win32.RawInput.PopulateDeviceList(treeViewDevices);
    4.11 +        }
    4.12 +
    4.13  	}
    4.14  }
     5.1 --- a/RawInput.cs	Thu Mar 05 10:12:37 2015 +0100
     5.2 +++ b/RawInput.cs	Sun Mar 15 09:53:37 2015 +0100
     5.3 @@ -207,6 +207,10 @@
     5.4                      node.Nodes.Add(hidDevice.InputCapabilitiesDescription);
     5.5                  }
     5.6  
     5.7 +                //Add button count
     5.8 +                node.Nodes.Add("Button Count: " + hidDevice.ButtonCount);
     5.9 +
    5.10 +                //Those can be joystick/gamepad axis
    5.11                  if (hidDevice.InputValueCapabilities != null)
    5.12                  {
    5.13                      foreach (HIDP_VALUE_CAPS caps in hidDevice.InputValueCapabilities)
     6.1 --- a/Win32Hid.cs	Thu Mar 05 10:12:37 2015 +0100
     6.2 +++ b/Win32Hid.cs	Sun Mar 15 09:53:37 2015 +0100
     6.3 @@ -302,10 +302,10 @@
     6.4  
     6.5          /// Union Range/NotRange
     6.6          [FieldOffset(56)]
     6.7 -        HIDP_BUTTON_CAPS_RANGE Range;
     6.8 +        public HIDP_BUTTON_CAPS_RANGE Range;
     6.9  
    6.10          [FieldOffset(56)]
    6.11 -        HIDP_BUTTON_CAPS_NOT_RANGE NotRange;       
    6.12 +        public HIDP_BUTTON_CAPS_NOT_RANGE NotRange;       
    6.13      }
    6.14  
    6.15      /// <summary>