Adding button count property to HID device.
authorStephaneLenclud
Sun, 15 Mar 2015 09:53:37 +0100
changeset 72471b1d45c46a
parent 71 c28dd93b94c5
child 73 5262f4b7c4ad
Adding button count property to HID device.
Adding device list refresh button.
Better reporting of input value capabilities description.
HidDevice.cs
HidEvent.cs
MainForm.Designer.cs
MainForm.cs
RawInput.cs
Win32Hid.cs
     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>