Now checking HID usage page and usage.
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