Now checking HID usage page and usage.
authorsl
Wed, 05 Nov 2014 19:39:59 +0100
changeset 6fa97ff5ceb7b
parent 5 b2ed6fc37d95
child 7 5ecebf1bd397
Now checking HID usage page and usage.
Form1.cs
RemoteControlDevice.cs
     1.1 --- a/Form1.cs	Wed Nov 05 10:19:02 2014 +0100
     1.2 +++ b/Form1.cs	Wed Nov 05 19:39:59 2014 +0100
     1.3 @@ -4,7 +4,7 @@
     1.4  using System.ComponentModel;
     1.5  using System.Windows.Forms;
     1.6  using System.Data;
     1.7 -using BruceThomas.Devices.RemoteControl;
     1.8 +using Devices.RemoteControl;
     1.9  
    1.10  namespace RemoteControlSample
    1.11  {
    1.12 @@ -34,7 +34,7 @@
    1.13  			_timer.Enabled = false;
    1.14  			_timer.Tick +=new EventHandler(_timer_Tick);
    1.15  			_remote = new RemoteControlDevice();
    1.16 -			_remote.ButtonPressed +=new BruceThomas.Devices.RemoteControl.RemoteControlDevice.RemoteControlDeviceEventHandler(_remote_ButtonPressed);			
    1.17 +			_remote.ButtonPressed +=new Devices.RemoteControl.RemoteControlDevice.RemoteControlDeviceEventHandler(_remote_ButtonPressed);
    1.18  		}
    1.19  
    1.20  		/// <summary>
    1.21 @@ -44,7 +44,7 @@
    1.22  		{
    1.23  			if( disposing )
    1.24  			{
    1.25 -				if (components != null) 
    1.26 +				if (components != null)
    1.27  				{
    1.28  					components.Dispose();
    1.29  				}
    1.30 @@ -62,9 +62,9 @@
    1.31  			this.label1 = new System.Windows.Forms.Label();
    1.32  			this.label2 = new System.Windows.Forms.Label();
    1.33  			this.SuspendLayout();
    1.34 -			// 
    1.35 +			//
    1.36  			// label1
    1.37 -			// 
    1.38 +			//
    1.39  			this.label1.Dock = System.Windows.Forms.DockStyle.Fill;
    1.40  			this.label1.Font = new System.Drawing.Font("Microsoft Sans Serif", 36F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(0)));
    1.41  			this.label1.ForeColor = System.Drawing.Color.White;
    1.42 @@ -74,18 +74,18 @@
    1.43  			this.label1.TabIndex = 0;
    1.44  			this.label1.Text = "Ready...";
    1.45  			this.label1.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
    1.46 -			// 
    1.47 +			//
    1.48  			// label2
    1.49 -			// 
    1.50 +			//
    1.51  			this.label2.Font = new System.Drawing.Font("Microsoft Sans Serif", 16F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(0)));
    1.52  			this.label2.Location = new System.Drawing.Point(72, 32);
    1.53  			this.label2.Name = "label2";
    1.54  			this.label2.Size = new System.Drawing.Size(576, 23);
    1.55  			this.label2.TabIndex = 1;
    1.56  			this.label2.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
    1.57 -			// 
    1.58 +			//
    1.59  			// Form1
    1.60 -			// 
    1.61 +			//
    1.62  			this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
    1.63  			this.BackColor = System.Drawing.Color.LightSteelBlue;
    1.64  			this.ClientSize = new System.Drawing.Size(736, 266);
    1.65 @@ -97,26 +97,26 @@
    1.66  			this.ResumeLayout(false);
    1.67  
    1.68  		}
    1.69 -		#endregion
    1.70 +		#endregion Windows Form Designer generated code
    1.71  
    1.72  		/// <summary>
    1.73  		/// The main entry point for the application.
    1.74  		/// </summary>
    1.75  		[STAThread]
    1.76 -		static void Main() 
    1.77 +		static void Main()
    1.78  		{
    1.79  			Application.Run(new Form1());
    1.80  		}
    1.81  
    1.82  		private void Form1_Load(object sender, System.EventArgs e)
    1.83  		{
    1.84 -		
    1.85 +
    1.86  		}
    1.87  
    1.88  
    1.89  		protected override void WndProc(ref Message message)
    1.90  		{
    1.91 -			_remote.ProcessMessage(message);			
    1.92 +			_remote.ProcessMessage(message);
    1.93  			base.WndProc(ref message);
    1.94  		}
    1.95  
    1.96 @@ -136,13 +136,13 @@
    1.97                  {
    1.98                      //Also display HP button name
    1.99                      label1.Text += " / HP:" + ((HpMceButton)e.MceButton).ToString();
   1.100 -                }                
   1.101 +                }
   1.102              }
   1.103              else
   1.104              {
   1.105                  label1.Text = "Unknown";
   1.106              }
   1.107 -			label2.Text = e.Device.ToString();			
   1.108 +			label2.Text = e.Device.ToString();
   1.109  			_timer.Enabled = true;
   1.110  		}
   1.111  
     2.1 --- a/RemoteControlDevice.cs	Wed Nov 05 10:19:02 2014 +0100
     2.2 +++ b/RemoteControlDevice.cs	Wed Nov 05 19:39:59 2014 +0100
     2.3 @@ -4,8 +4,59 @@
     2.4  using System.Diagnostics;
     2.5  
     2.6  
     2.7 -namespace BruceThomas.Devices.RemoteControl
     2.8 +namespace Devices.RemoteControl
     2.9  {
    2.10 +
    2.11 +    public static class Hid
    2.12 +    {
    2.13 +        /// <summary>
    2.14 +        /// From USB HID usage tables.
    2.15 +        /// http://www.usb.org/developers/hidpage#HID_Usage
    2.16 +        /// http://www.usb.org/developers/devclass_docs/Hut1_12v2.pdf
    2.17 +        /// </summary>
    2.18 +        public enum UsagePage : ushort
    2.19 +        {
    2.20 +            Undefined = 0,
    2.21 +            GenericDesktopControl,
    2.22 +            SimulationControl,
    2.23 +            VirtualRealityControl,
    2.24 +            SportControl,
    2.25 +            GameControl,
    2.26 +            GenericDeviceControl,
    2.27 +            Keyboard,
    2.28 +            LightEmittingDiode,
    2.29 +            Button,
    2.30 +            Ordinal,
    2.31 +            Telephony,
    2.32 +            Consumer,
    2.33 +            Digitiser,
    2.34 +            PhysicalInterfaceDevice = 0x0f,
    2.35 +            Unicode = 0x10,
    2.36 +            AlphaNumericDisplay = 0x14,
    2.37 +            MedicalInstruments = 0x40,
    2.38 +            MonitorPage0 = 0x80,
    2.39 +            MonitorPage1,
    2.40 +            MonitorPage2,
    2.41 +            MonitorPage3,
    2.42 +            PowerPage0,
    2.43 +            PowerPage1,
    2.44 +            PowerPage2,
    2.45 +            PowerPage3,
    2.46 +            BarCodeScanner = 0x8c,
    2.47 +            Scale,
    2.48 +            MagneticStripeReader,
    2.49 +            ReservedPointOfSale,
    2.50 +            CameraControl,
    2.51 +            Arcade,
    2.52 +            // http://msdn.microsoft.com/en-us/library/windows/desktop/bb417079.aspx
    2.53 +            MceRemote = 0xffbc,
    2.54 +            TerraTecRemote = 0xffcc
    2.55 +        }
    2.56 +
    2.57 +        public const ushort MceRemoteUsage = 0x88;
    2.58 +    }
    2.59 +
    2.60 +
    2.61  	public enum InputDevice
    2.62  	{
    2.63  		Key,
    2.64 @@ -70,14 +121,14 @@
    2.65  	}
    2.66  
    2.67      /// <summary>
    2.68 -    /// 
    2.69 +    ///
    2.70      /// </summary>
    2.71      public enum MceButton
    2.72      {
    2.73          /// <summary>
    2.74          /// Not defined by the Microsoft specs.
    2.75          /// </summary>
    2.76 -        Null                    =   0x00, 
    2.77 +        Null                    =   0x00,
    2.78          GreenStart              =   0x0D,
    2.79          ClosedCaptioning        =   0x2B,
    2.80          Teletext                =   0x5A,
    2.81 @@ -193,7 +244,7 @@
    2.82          NetworkSelection        =   0x2C,
    2.83          BlueRayTool             =   0x78,
    2.84          ChannelInfo             =   0x41,
    2.85 -        VideoSelection          =   0x61                
    2.86 +        VideoSelection          =   0x61
    2.87      }
    2.88  
    2.89      public enum HpMceButton
    2.90 @@ -395,14 +446,62 @@
    2.91  		}
    2.92  
    2.93  
    2.94 +        [StructLayout(LayoutKind.Sequential, Pack=1)]
    2.95 +        internal struct RID_DEVICE_INFO_MOUSE
    2.96 +		{
    2.97 +            public uint dwId;
    2.98 +            public uint dwNumberOfButtons;
    2.99 +            public uint dwSampleRate;
   2.100 +            public bool fHasHorizontalWheel;
   2.101 +		}
   2.102 +
   2.103 +
   2.104 +        [StructLayout(LayoutKind.Sequential, Pack=1)]
   2.105 +        internal struct RID_DEVICE_INFO_KEYBOARD
   2.106 +		{
   2.107 +            public uint dwType;
   2.108 +            public uint dwSubType;
   2.109 +            public uint dwKeyboardMode;
   2.110 +            public uint dwNumberOfFunctionKeys;
   2.111 +            public uint dwNumberOfIndicators;
   2.112 +            public uint dwNumberOfKeysTotal;
   2.113 +        }
   2.114 +
   2.115 +        [StructLayout(LayoutKind.Sequential, Pack=1)]
   2.116 +        internal struct RID_DEVICE_INFO_HID
   2.117 +		{
   2.118 +            public uint dwVendorId;
   2.119 +            public uint dwProductId;
   2.120 +            public uint dwVersionNumber;
   2.121 +            public ushort usUsagePage;
   2.122 +            public ushort usUsage;
   2.123 +        }
   2.124 +
   2.125 +        [StructLayout(LayoutKind.Explicit, Pack=1)]
   2.126 +        internal struct RID_DEVICE_INFO
   2.127 +		{
   2.128 +            [FieldOffset(0)]
   2.129 +            public uint cbSize;
   2.130 +            [FieldOffset(4)]
   2.131 +            public uint dwType;
   2.132 +            [FieldOffset(8)]
   2.133 +            public RID_DEVICE_INFO_MOUSE mouse;
   2.134 +            [FieldOffset(8)]
   2.135 +            public RID_DEVICE_INFO_KEYBOARD keyboard;
   2.136 +            [FieldOffset(8)]
   2.137 +            public RID_DEVICE_INFO_HID hid;
   2.138 +		}
   2.139 +
   2.140 +
   2.141 +
   2.142  		[DllImport("User32.dll")]
   2.143  		extern static bool RegisterRawInputDevices(RAWINPUTDEVICE[] pRawInputDevice, uint uiNumDevices, uint cbSize);
   2.144  
   2.145  		[DllImport("User32.dll")]
   2.146  		extern static uint GetRawInputData(IntPtr hRawInput, uint uiCommand, IntPtr pData, ref uint pcbSize, uint cbSizeHeader);
   2.147  
   2.148 -   		[DllImport("User32.dll")]
   2.149 -		extern static uint GetRawInputDeviceInfo(IntPtr hDevice, uint uiCommand, IntPtr pData, ref uint pcbSize);
   2.150 +   		[DllImport("User32.dll", SetLastError=true)]
   2.151 +		extern static int GetRawInputDeviceInfo(IntPtr hDevice, uint uiCommand, IntPtr pData, ref uint pcbSize);
   2.152  
   2.153  
   2.154  		private const int WM_KEYDOWN	= 0x0100;
   2.155 @@ -425,10 +524,6 @@
   2.156  		private const int APPCOMMAND_MEDIA_CHANNEL_UP   = 51;
   2.157  		private const int APPCOMMAND_MEDIA_CHANNEL_DOWN = 52;
   2.158  
   2.159 -		private const int RIM_TYPEMOUSE					= 0;
   2.160 -		private const int RIM_TYPEKEYBOARD				= 1;
   2.161 -		private const int RIM_TYPEHID					= 2;
   2.162 -
   2.163  		private const int RID_INPUT						= 0x10000003;
   2.164  		private const int RID_HEADER					= 0x10000005;
   2.165  
   2.166 @@ -437,6 +532,37 @@
   2.167  		private const int FAPPCOMMAND_KEY				= 0;
   2.168  		private const int FAPPCOMMAND_OEM				= 0x1000;
   2.169  
   2.170 +        /// <summary>
   2.171 +        /// GetRawInputDeviceInfo pData points to a string that contains the device name.
   2.172 +        /// </summary>
   2.173 +        public const uint RIDI_DEVICENAME = 0x20000007;
   2.174 +        /// <summary>
   2.175 +        /// GetRawInputDeviceInfo For this uiCommand only, the value in pcbSize is the character count (not the byte count).
   2.176 +        /// </summary>
   2.177 +        public const uint RIDI_DEVICEINFO = 0x2000000b;
   2.178 +        /// <summary>
   2.179 +        /// GetRawInputDeviceInfo pData points to an RID_DEVICE_INFO structure.
   2.180 +        /// </summary>
   2.181 +        public const uint RIDI_PREPARSEDDATA = 0x20000005;
   2.182 +
   2.183 +
   2.184 +        /// <summary>
   2.185 +        /// Data comes from a mouse.
   2.186 +        /// </summary>
   2.187 +        public const uint RIM_TYPEMOUSE = 0;
   2.188 +        /// <summary>
   2.189 +        /// Data comes from a keyboard.
   2.190 +        /// </summary>
   2.191 +        public const uint RIM_TYPEKEYBOARD = 1;
   2.192 +        /// <summary>
   2.193 +        /// Data comes from an HID that is not a keyboard or a mouse.
   2.194 +        /// </summary>
   2.195 +        public const uint RIM_TYPEHID = 2;
   2.196 +
   2.197 +
   2.198 +
   2.199 +
   2.200 +
   2.201  		public delegate void RemoteControlDeviceEventHandler(object sender, RemoteControlEventArgs e);
   2.202  		public event RemoteControlDeviceEventHandler ButtonPressed;
   2.203  
   2.204 @@ -629,7 +755,9 @@
   2.205  
   2.206  		private void ProcessInputCommand(ref Message message)
   2.207  		{
   2.208 -			RemoteControlButton rcb = RemoteControlButton.Unknown;
   2.209 +
   2.210 +
   2.211 +
   2.212  			uint dwSize = 0;
   2.213  
   2.214              uint sizeOfHeader=(uint)Marshal.SizeOf(typeof(RAWINPUTHEADER));
   2.215 @@ -638,20 +766,54 @@
   2.216  			GetRawInputData(message.LParam,	RID_INPUT, IntPtr.Zero,	ref dwSize,	sizeOfHeader);
   2.217  
   2.218              //Allocate a large enough buffer
   2.219 -			IntPtr buffer = Marshal.AllocHGlobal((int) dwSize);
   2.220 +			IntPtr rawInputBuffer = Marshal.AllocHGlobal((int) dwSize);
   2.221  			try
   2.222  			{
   2.223 -				if(buffer == IntPtr.Zero)
   2.224 +				if(rawInputBuffer == IntPtr.Zero)
   2.225  					return;
   2.226  
   2.227                  //Now read our RAWINPUT data
   2.228 -				if (GetRawInputData(message.LParam,	RID_INPUT, buffer, ref dwSize, (uint) Marshal.SizeOf(typeof(RAWINPUTHEADER))) != dwSize)
   2.229 +				if (GetRawInputData(message.LParam,	RID_INPUT, rawInputBuffer, ref dwSize, (uint) Marshal.SizeOf(typeof(RAWINPUTHEADER))) != dwSize)
   2.230  				{
   2.231  					return;
   2.232  				}
   2.233  
   2.234                  //Cast our buffer
   2.235 -                RAWINPUT raw = (RAWINPUT)Marshal.PtrToStructure(buffer, typeof(RAWINPUT));
   2.236 +                RAWINPUT raw = (RAWINPUT)Marshal.PtrToStructure(rawInputBuffer, typeof(RAWINPUT));
   2.237 +
   2.238 +                //Get Device Info
   2.239 +                uint deviceInfoSize = (uint)Marshal.SizeOf(typeof(RID_DEVICE_INFO));
   2.240 +                IntPtr deviceInfoBuffer = Marshal.AllocHGlobal((int)deviceInfoSize);
   2.241 +
   2.242 +                int res = GetRawInputDeviceInfo(raw.header.hDevice, RIDI_DEVICEINFO, deviceInfoBuffer, ref deviceInfoSize);
   2.243 +                if (res <= 0)
   2.244 +                {
   2.245 +                    Debug.WriteLine("WM_INPUT could not read device info: " + Marshal.GetLastWin32Error().ToString());
   2.246 +                    return;
   2.247 +                }
   2.248 +
   2.249 +                //Cast our buffer
   2.250 +                RID_DEVICE_INFO deviceInfo = (RID_DEVICE_INFO)Marshal.PtrToStructure(deviceInfoBuffer, typeof(RID_DEVICE_INFO));
   2.251 +
   2.252 +                //Check type of input device and quite if we don't like it
   2.253 +                switch (deviceInfo.dwType)
   2.254 +                {
   2.255 +                    case RIM_TYPEHID:
   2.256 +                        Debug.WriteLine("WM_INPUT source device is HID.");
   2.257 +                        break;
   2.258 +                    case RIM_TYPEMOUSE:
   2.259 +                        Debug.WriteLine("WM_INPUT source device is Mouse.");
   2.260 +                        return;
   2.261 +                    case RIM_TYPEKEYBOARD:
   2.262 +                        Debug.WriteLine("WM_INPUT source device is Keyboard.");
   2.263 +                        return;
   2.264 +                    default:
   2.265 +                        Debug.WriteLine("WM_INPUT source device is Unknown.");
   2.266 +                        return;
   2.267 +                }
   2.268 +
   2.269 +                //Get Usage Page and Usage
   2.270 +                Debug.WriteLine("Usage Page: 0x" + deviceInfo.hid.usUsagePage.ToString("X4") + " Usage: 0x" + deviceInfo.hid.usUsage.ToString("X4"));
   2.271  
   2.272                  //Check that our raw input is HID
   2.273                  if (raw.header.dwType == RIM_TYPEHID && raw.hid.dwSizeHid>0)
   2.274 @@ -663,7 +825,7 @@
   2.275                      int pRawData = 0;
   2.276                      unsafe
   2.277                      {
   2.278 -                        byte* source = (byte*)buffer;
   2.279 +                        byte* source = (byte*)rawInputBuffer;
   2.280                          source += sizeof(RAWINPUTHEADER) + sizeof(RAWHID);
   2.281                          pRawData = (int)source;
   2.282                      }
   2.283 @@ -674,7 +836,19 @@
   2.284                      //TODO: check size before access
   2.285                      int rawData = bRawData[1]; //Get button code
   2.286                      //Print HID codes in our debug output
   2.287 -                    Debug.WriteLine("HID " + raw.hid.dwCount + "/" + raw.hid.dwSizeHid + ":" + bRawData[0].ToString("X2") + bRawData[1].ToString("X2"));
   2.288 +                    string hidDump = "HID " + raw.hid.dwCount + "/" + raw.hid.dwSizeHid + ":";
   2.289 +                    foreach (byte b in bRawData)
   2.290 +                    {
   2.291 +                        hidDump += b.ToString("X2");
   2.292 +                    }
   2.293 +                    Debug.WriteLine(hidDump);
   2.294 +
   2.295 +                    //Make sure both usage page and usage are matching MCE remote
   2.296 +                    if (deviceInfo.hid.usUsagePage != (ushort)Hid.UsagePage.MceRemote || deviceInfo.hid.usUsage != (ushort)Hid.MceRemoteUsage)
   2.297 +                    {
   2.298 +                        Debug.WriteLine("Not MCE remote page and usage.");
   2.299 +                        return;
   2.300 +                    }
   2.301  
   2.302                      if (Enum.IsDefined(typeof(MceButton), rawData) && rawData!=0) //Our button is a known MCE button
   2.303                      {
   2.304 @@ -695,7 +869,7 @@
   2.305  			}
   2.306  			finally
   2.307  			{
   2.308 -				Marshal.FreeHGlobal(buffer);
   2.309 +				Marshal.FreeHGlobal(rawInputBuffer);
   2.310  			}
   2.311  		}
   2.312