# HG changeset patch # User sl # Date 1415212799 -3600 # Node ID fa97ff5ceb7b3b5594f1ced15d6dea3b4374c2a8 # Parent b2ed6fc37d950678551f0fe19c5d4b9bd44fdba4 Now checking HID usage page and usage. diff -r b2ed6fc37d95 -r fa97ff5ceb7b Form1.cs --- a/Form1.cs Wed Nov 05 10:19:02 2014 +0100 +++ b/Form1.cs Wed Nov 05 19:39:59 2014 +0100 @@ -4,7 +4,7 @@ using System.ComponentModel; using System.Windows.Forms; using System.Data; -using BruceThomas.Devices.RemoteControl; +using Devices.RemoteControl; namespace RemoteControlSample { @@ -34,7 +34,7 @@ _timer.Enabled = false; _timer.Tick +=new EventHandler(_timer_Tick); _remote = new RemoteControlDevice(); - _remote.ButtonPressed +=new BruceThomas.Devices.RemoteControl.RemoteControlDevice.RemoteControlDeviceEventHandler(_remote_ButtonPressed); + _remote.ButtonPressed +=new Devices.RemoteControl.RemoteControlDevice.RemoteControlDeviceEventHandler(_remote_ButtonPressed); } /// @@ -44,7 +44,7 @@ { if( disposing ) { - if (components != null) + if (components != null) { components.Dispose(); } @@ -62,9 +62,9 @@ this.label1 = new System.Windows.Forms.Label(); this.label2 = new System.Windows.Forms.Label(); this.SuspendLayout(); - // + // // label1 - // + // this.label1.Dock = System.Windows.Forms.DockStyle.Fill; this.label1.Font = new System.Drawing.Font("Microsoft Sans Serif", 36F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(0))); this.label1.ForeColor = System.Drawing.Color.White; @@ -74,18 +74,18 @@ this.label1.TabIndex = 0; this.label1.Text = "Ready..."; this.label1.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; - // + // // label2 - // + // this.label2.Font = new System.Drawing.Font("Microsoft Sans Serif", 16F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(0))); this.label2.Location = new System.Drawing.Point(72, 32); this.label2.Name = "label2"; this.label2.Size = new System.Drawing.Size(576, 23); this.label2.TabIndex = 1; this.label2.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; - // + // // Form1 - // + // this.AutoScaleBaseSize = new System.Drawing.Size(5, 13); this.BackColor = System.Drawing.Color.LightSteelBlue; this.ClientSize = new System.Drawing.Size(736, 266); @@ -97,26 +97,26 @@ this.ResumeLayout(false); } - #endregion + #endregion Windows Form Designer generated code /// /// The main entry point for the application. /// [STAThread] - static void Main() + static void Main() { Application.Run(new Form1()); } private void Form1_Load(object sender, System.EventArgs e) { - + } protected override void WndProc(ref Message message) { - _remote.ProcessMessage(message); + _remote.ProcessMessage(message); base.WndProc(ref message); } @@ -136,13 +136,13 @@ { //Also display HP button name label1.Text += " / HP:" + ((HpMceButton)e.MceButton).ToString(); - } + } } else { label1.Text = "Unknown"; } - label2.Text = e.Device.ToString(); + label2.Text = e.Device.ToString(); _timer.Enabled = true; } diff -r b2ed6fc37d95 -r fa97ff5ceb7b RemoteControlDevice.cs --- a/RemoteControlDevice.cs Wed Nov 05 10:19:02 2014 +0100 +++ b/RemoteControlDevice.cs Wed Nov 05 19:39:59 2014 +0100 @@ -4,8 +4,59 @@ using System.Diagnostics; -namespace BruceThomas.Devices.RemoteControl +namespace Devices.RemoteControl { + + public static class Hid + { + /// + /// From USB HID usage tables. + /// http://www.usb.org/developers/hidpage#HID_Usage + /// http://www.usb.org/developers/devclass_docs/Hut1_12v2.pdf + /// + public enum UsagePage : ushort + { + Undefined = 0, + GenericDesktopControl, + SimulationControl, + VirtualRealityControl, + SportControl, + GameControl, + GenericDeviceControl, + Keyboard, + LightEmittingDiode, + Button, + Ordinal, + Telephony, + Consumer, + Digitiser, + PhysicalInterfaceDevice = 0x0f, + Unicode = 0x10, + AlphaNumericDisplay = 0x14, + MedicalInstruments = 0x40, + MonitorPage0 = 0x80, + MonitorPage1, + MonitorPage2, + MonitorPage3, + PowerPage0, + PowerPage1, + PowerPage2, + PowerPage3, + BarCodeScanner = 0x8c, + Scale, + MagneticStripeReader, + ReservedPointOfSale, + CameraControl, + Arcade, + // http://msdn.microsoft.com/en-us/library/windows/desktop/bb417079.aspx + MceRemote = 0xffbc, + TerraTecRemote = 0xffcc + } + + public const ushort MceRemoteUsage = 0x88; + } + + public enum InputDevice { Key, @@ -70,14 +121,14 @@ } /// - /// + /// /// public enum MceButton { /// /// Not defined by the Microsoft specs. /// - Null = 0x00, + Null = 0x00, GreenStart = 0x0D, ClosedCaptioning = 0x2B, Teletext = 0x5A, @@ -193,7 +244,7 @@ NetworkSelection = 0x2C, BlueRayTool = 0x78, ChannelInfo = 0x41, - VideoSelection = 0x61 + VideoSelection = 0x61 } public enum HpMceButton @@ -395,14 +446,62 @@ } + [StructLayout(LayoutKind.Sequential, Pack=1)] + internal struct RID_DEVICE_INFO_MOUSE + { + public uint dwId; + public uint dwNumberOfButtons; + public uint dwSampleRate; + public bool fHasHorizontalWheel; + } + + + [StructLayout(LayoutKind.Sequential, Pack=1)] + internal struct RID_DEVICE_INFO_KEYBOARD + { + public uint dwType; + public uint dwSubType; + public uint dwKeyboardMode; + public uint dwNumberOfFunctionKeys; + public uint dwNumberOfIndicators; + public uint dwNumberOfKeysTotal; + } + + [StructLayout(LayoutKind.Sequential, Pack=1)] + internal struct RID_DEVICE_INFO_HID + { + public uint dwVendorId; + public uint dwProductId; + public uint dwVersionNumber; + public ushort usUsagePage; + public ushort usUsage; + } + + [StructLayout(LayoutKind.Explicit, Pack=1)] + internal struct RID_DEVICE_INFO + { + [FieldOffset(0)] + public uint cbSize; + [FieldOffset(4)] + public uint dwType; + [FieldOffset(8)] + public RID_DEVICE_INFO_MOUSE mouse; + [FieldOffset(8)] + public RID_DEVICE_INFO_KEYBOARD keyboard; + [FieldOffset(8)] + public RID_DEVICE_INFO_HID hid; + } + + + [DllImport("User32.dll")] extern static bool RegisterRawInputDevices(RAWINPUTDEVICE[] pRawInputDevice, uint uiNumDevices, uint cbSize); [DllImport("User32.dll")] extern static uint GetRawInputData(IntPtr hRawInput, uint uiCommand, IntPtr pData, ref uint pcbSize, uint cbSizeHeader); - [DllImport("User32.dll")] - extern static uint GetRawInputDeviceInfo(IntPtr hDevice, uint uiCommand, IntPtr pData, ref uint pcbSize); + [DllImport("User32.dll", SetLastError=true)] + extern static int GetRawInputDeviceInfo(IntPtr hDevice, uint uiCommand, IntPtr pData, ref uint pcbSize); private const int WM_KEYDOWN = 0x0100; @@ -425,10 +524,6 @@ private const int APPCOMMAND_MEDIA_CHANNEL_UP = 51; private const int APPCOMMAND_MEDIA_CHANNEL_DOWN = 52; - private const int RIM_TYPEMOUSE = 0; - private const int RIM_TYPEKEYBOARD = 1; - private const int RIM_TYPEHID = 2; - private const int RID_INPUT = 0x10000003; private const int RID_HEADER = 0x10000005; @@ -437,6 +532,37 @@ private const int FAPPCOMMAND_KEY = 0; private const int FAPPCOMMAND_OEM = 0x1000; + /// + /// GetRawInputDeviceInfo pData points to a string that contains the device name. + /// + public const uint RIDI_DEVICENAME = 0x20000007; + /// + /// GetRawInputDeviceInfo For this uiCommand only, the value in pcbSize is the character count (not the byte count). + /// + public const uint RIDI_DEVICEINFO = 0x2000000b; + /// + /// GetRawInputDeviceInfo pData points to an RID_DEVICE_INFO structure. + /// + public const uint RIDI_PREPARSEDDATA = 0x20000005; + + + /// + /// Data comes from a mouse. + /// + public const uint RIM_TYPEMOUSE = 0; + /// + /// Data comes from a keyboard. + /// + public const uint RIM_TYPEKEYBOARD = 1; + /// + /// Data comes from an HID that is not a keyboard or a mouse. + /// + public const uint RIM_TYPEHID = 2; + + + + + public delegate void RemoteControlDeviceEventHandler(object sender, RemoteControlEventArgs e); public event RemoteControlDeviceEventHandler ButtonPressed; @@ -629,7 +755,9 @@ private void ProcessInputCommand(ref Message message) { - RemoteControlButton rcb = RemoteControlButton.Unknown; + + + uint dwSize = 0; uint sizeOfHeader=(uint)Marshal.SizeOf(typeof(RAWINPUTHEADER)); @@ -638,20 +766,54 @@ GetRawInputData(message.LParam, RID_INPUT, IntPtr.Zero, ref dwSize, sizeOfHeader); //Allocate a large enough buffer - IntPtr buffer = Marshal.AllocHGlobal((int) dwSize); + IntPtr rawInputBuffer = Marshal.AllocHGlobal((int) dwSize); try { - if(buffer == IntPtr.Zero) + if(rawInputBuffer == IntPtr.Zero) return; //Now read our RAWINPUT data - if (GetRawInputData(message.LParam, RID_INPUT, buffer, ref dwSize, (uint) Marshal.SizeOf(typeof(RAWINPUTHEADER))) != dwSize) + if (GetRawInputData(message.LParam, RID_INPUT, rawInputBuffer, ref dwSize, (uint) Marshal.SizeOf(typeof(RAWINPUTHEADER))) != dwSize) { return; } //Cast our buffer - RAWINPUT raw = (RAWINPUT)Marshal.PtrToStructure(buffer, typeof(RAWINPUT)); + RAWINPUT raw = (RAWINPUT)Marshal.PtrToStructure(rawInputBuffer, typeof(RAWINPUT)); + + //Get Device Info + uint deviceInfoSize = (uint)Marshal.SizeOf(typeof(RID_DEVICE_INFO)); + IntPtr deviceInfoBuffer = Marshal.AllocHGlobal((int)deviceInfoSize); + + int res = GetRawInputDeviceInfo(raw.header.hDevice, RIDI_DEVICEINFO, deviceInfoBuffer, ref deviceInfoSize); + if (res <= 0) + { + Debug.WriteLine("WM_INPUT could not read device info: " + Marshal.GetLastWin32Error().ToString()); + return; + } + + //Cast our buffer + RID_DEVICE_INFO deviceInfo = (RID_DEVICE_INFO)Marshal.PtrToStructure(deviceInfoBuffer, typeof(RID_DEVICE_INFO)); + + //Check type of input device and quite if we don't like it + switch (deviceInfo.dwType) + { + case RIM_TYPEHID: + Debug.WriteLine("WM_INPUT source device is HID."); + break; + case RIM_TYPEMOUSE: + Debug.WriteLine("WM_INPUT source device is Mouse."); + return; + case RIM_TYPEKEYBOARD: + Debug.WriteLine("WM_INPUT source device is Keyboard."); + return; + default: + Debug.WriteLine("WM_INPUT source device is Unknown."); + return; + } + + //Get Usage Page and Usage + Debug.WriteLine("Usage Page: 0x" + deviceInfo.hid.usUsagePage.ToString("X4") + " Usage: 0x" + deviceInfo.hid.usUsage.ToString("X4")); //Check that our raw input is HID if (raw.header.dwType == RIM_TYPEHID && raw.hid.dwSizeHid>0) @@ -663,7 +825,7 @@ int pRawData = 0; unsafe { - byte* source = (byte*)buffer; + byte* source = (byte*)rawInputBuffer; source += sizeof(RAWINPUTHEADER) + sizeof(RAWHID); pRawData = (int)source; } @@ -674,7 +836,19 @@ //TODO: check size before access int rawData = bRawData[1]; //Get button code //Print HID codes in our debug output - Debug.WriteLine("HID " + raw.hid.dwCount + "/" + raw.hid.dwSizeHid + ":" + bRawData[0].ToString("X2") + bRawData[1].ToString("X2")); + string hidDump = "HID " + raw.hid.dwCount + "/" + raw.hid.dwSizeHid + ":"; + foreach (byte b in bRawData) + { + hidDump += b.ToString("X2"); + } + Debug.WriteLine(hidDump); + + //Make sure both usage page and usage are matching MCE remote + if (deviceInfo.hid.usUsagePage != (ushort)Hid.UsagePage.MceRemote || deviceInfo.hid.usUsage != (ushort)Hid.MceRemoteUsage) + { + Debug.WriteLine("Not MCE remote page and usage."); + return; + } if (Enum.IsDefined(typeof(MceButton), rawData) && rawData!=0) //Our button is a known MCE button { @@ -695,7 +869,7 @@ } finally { - Marshal.FreeHGlobal(buffer); + Marshal.FreeHGlobal(rawInputBuffer); } }