Adding method to get the device name.
2 using System.Windows.Forms;
3 using System.Runtime.InteropServices;
4 using System.Diagnostics;
8 namespace Devices.RemoteControl
11 public enum InputDevice
19 public enum RemoteControlButton
76 #region RemoteControlEventArgs
78 public class RemoteControlEventArgs : EventArgs
80 RemoteControlButton _rcb;
83 ConsumerControl iConsumerControl;
85 public RemoteControlEventArgs(RemoteControlButton rcb, InputDevice device)
93 public RemoteControlEventArgs(ConsumerControl aConsumerControl, InputDevice device)
97 iConsumerControl = aConsumerControl;
102 public RemoteControlEventArgs(MceButton mce, InputDevice device)
110 private void SetNullButtons()
112 iConsumerControl = ConsumerControl.Null;
113 iMceButton = MceButton.Null;
114 _rcb = RemoteControlButton.Unknown;
117 public RemoteControlEventArgs()
119 iMceButton = MceButton.Null;
120 _rcb = RemoteControlButton.Unknown;
121 _device = InputDevice.Key;
124 public RemoteControlButton Button
127 set { _rcb = value; }
130 public MceButton MceButton
132 get { return iMceButton; }
133 set { iMceButton = value; }
136 public ConsumerControl ConsumerControl
138 get { return iConsumerControl; }
139 set { iConsumerControl = value; }
142 public InputDevice Device
144 get { return _device; }
145 set { _device = value; }
149 #endregion RemoteControlEventArgs
152 public sealed class RemoteControlDevice
154 public delegate bool RemoteControlDeviceEventHandler(object sender, RemoteControlEventArgs e);
155 public event RemoteControlDeviceEventHandler ButtonPressed;
158 /// Return true if the usage was processed.
160 /// <param name="aUsage"></param>
161 /// <returns></returns>
162 public delegate bool HidUsageHandler(ushort aUsage);
165 //-------------------------------------------------------------
167 //-------------------------------------------------------------
169 public RemoteControlDevice(IntPtr aHWND)
171 // Register the input device to receive the commands from the
172 // remote device. See http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnwmt/html/remote_control.asp
173 // for the vendor defined usage page.
175 RAWINPUTDEVICE[] rid = new RAWINPUTDEVICE[5];
178 rid[i].usUsagePage = (ushort)Hid.UsagePage.MceRemote;
179 rid[i].usUsage = (ushort)Hid.UsageIdMce.MceRemote;
180 rid[i].dwFlags = Const.RIDEV_EXINPUTSINK;
181 rid[i].hwndTarget = aHWND;
184 rid[i].usUsagePage = (ushort)Hid.UsagePage.Consumer;
185 rid[i].usUsage = (ushort)Hid.UsageIdConsumer.ConsumerControl;
186 rid[i].dwFlags = Const.RIDEV_EXINPUTSINK;
187 rid[i].hwndTarget = aHWND;
190 rid[i].usUsagePage = (ushort)Hid.UsagePage.Consumer;
191 rid[i].usUsage = (ushort)Hid.UsageIdConsumer.Selection;
192 rid[i].dwFlags = Const.RIDEV_EXINPUTSINK;
193 rid[i].hwndTarget = aHWND;
196 rid[i].usUsagePage = (ushort)Hid.UsagePage.GenericDesktopControl;
197 rid[i].usUsage = (ushort)Hid.UsageIdGenericDesktop.SystemControl;
198 rid[i].dwFlags = Const.RIDEV_EXINPUTSINK;
199 rid[i].hwndTarget = aHWND;
202 rid[i].usUsagePage = (ushort)Hid.UsagePage.GenericDesktopControl;
203 rid[i].usUsage = (ushort)Hid.UsageIdGenericDesktop.Keyboard;
204 rid[i].dwFlags = Const.RIDEV_EXINPUTSINK;
205 rid[i].hwndTarget = aHWND;
208 //rid[i].usUsagePage = (ushort)Hid.UsagePage.GenericDesktopControl;
209 //rid[i].usUsage = (ushort)Hid.UsageIdGenericDesktop.Mouse;
210 //rid[i].dwFlags = Const.RIDEV_EXINPUTSINK;
211 //rid[i].hwndTarget = aHWND;
214 if (!Function.RegisterRawInputDevices(rid,(uint) rid.Length,(uint) Marshal.SizeOf(rid[0])))
216 throw new ApplicationException("Failed to register raw input devices: " + Marshal.GetLastWin32Error().ToString());
221 //-------------------------------------------------------------
223 //-------------------------------------------------------------
225 public void ProcessMessage(Message message)
229 case Const.WM_KEYDOWN:
230 ProcessKeyDown(message.WParam);
233 //Returning zero means we processed that message.
234 message.Result = new IntPtr(0);
235 ProcessInputCommand(ref message);
242 //-------------------------------------------------------------
244 //-------------------------------------------------------------
246 private void ProcessKeyDown(IntPtr wParam)
248 RemoteControlButton rcb = RemoteControlButton.Unknown;
250 switch (wParam.ToInt32())
252 case (int) Keys.Escape:
253 rcb = RemoteControlButton.Clear;
256 rcb = RemoteControlButton.Up;
258 case (int) Keys.Down:
259 rcb = RemoteControlButton.Down;
261 case (int) Keys.Left:
262 rcb = RemoteControlButton.Left;
264 case (int)Keys.Right:
265 rcb = RemoteControlButton.Right;
267 case (int)Keys.Enter:
268 rcb = RemoteControlButton.Enter;
271 rcb = RemoteControlButton.Digit0;
274 rcb = RemoteControlButton.Digit1;
277 rcb = RemoteControlButton.Digit2;
280 rcb = RemoteControlButton.Digit3;
283 rcb = RemoteControlButton.Digit4;
286 rcb = RemoteControlButton.Digit5;
289 rcb = RemoteControlButton.Digit6;
292 rcb = RemoteControlButton.Digit7;
295 rcb = RemoteControlButton.Digit8;
298 rcb = RemoteControlButton.Digit9;
302 if (this.ButtonPressed != null && rcb != RemoteControlButton.Unknown)
304 Debug.WriteLine("KeyDown: " + rcb.ToString());
305 this.ButtonPressed(this, new RemoteControlEventArgs(rcb, InputDevice.Key));
313 /// <param name="aUsage"></param>
314 private bool HidConsumerDeviceHandler(ushort aUsage)
322 if (Enum.IsDefined(typeof(ConsumerControl), aUsage) && aUsage != 0) //Our button is a known consumer control
324 if (this.ButtonPressed != null)
326 return this.ButtonPressed(this, new RemoteControlEventArgs((ConsumerControl)aUsage, InputDevice.OEM));
332 Debug.WriteLine("Unknown Consumer Control!");
340 /// <param name="aUsage"></param>
341 private bool HidMceRemoteHandler(ushort aUsage)
350 if (Enum.IsDefined(typeof(MceButton), aUsage) && aUsage != 0) //Our button is a known MCE button
352 if (this.ButtonPressed != null)
354 return this.ButtonPressed(this, new RemoteControlEventArgs((MceButton)aUsage, InputDevice.OEM));
360 Debug.WriteLine("Unknown MCE button!");
366 private void ProcessInputCommand(ref Message message)
368 //We received a WM_INPUT message
369 Debug.WriteLine("================WM_INPUT================");
371 //Check if we received this message while in background or foreground
372 if (Macro.GET_RAWINPUT_CODE_WPARAM(message.WParam) == Const.RIM_INPUT)
374 Debug.WriteLine("================FOREGROUND");
376 else if (Macro.GET_RAWINPUT_CODE_WPARAM(message.WParam) == Const.RIM_INPUTSINK)
378 Debug.WriteLine("================BACKGROUND");
381 //Declare some pointers
382 IntPtr rawInputBuffer = IntPtr.Zero;
383 //My understanding is that this is basically our HID descriptor
384 IntPtr preParsedData = IntPtr.Zero;
389 RAWINPUT rawInput = new RAWINPUT();
390 if (!RawInput.GetRawInputData(message.LParam, ref rawInput, ref rawInputBuffer))
396 RID_DEVICE_INFO deviceInfo = new RID_DEVICE_INFO();
397 if (!RawInput.GetDeviceInfo(rawInput.header.hDevice, ref deviceInfo))
403 Debug.WriteLine(RawInput.GetDeviceName(rawInput.header.hDevice));
406 if (rawInput.header.dwType == Const.RIM_TYPEHID) //Check that our raw input is HID
408 Debug.WriteLine("WM_INPUT source device is HID.");
409 //Get Usage Page and Usage
410 Debug.WriteLine("Usage Page: 0x" + deviceInfo.hid.usUsagePage.ToString("X4") + " Usage ID: 0x" + deviceInfo.hid.usUsage.ToString("X4"));
413 preParsedData = RawInput.GetPreParsedData(rawInput.header.hDevice);
416 HidUsageHandler usagePageHandler=null;
418 //Check if this an MCE remote HID message
419 if (deviceInfo.hid.usUsagePage == (ushort)Hid.UsagePage.MceRemote && deviceInfo.hid.usUsage == (ushort)Hid.UsageIdMce.MceRemote)
421 usagePageHandler = HidMceRemoteHandler;
423 //Check if this is a consumer control HID message
424 else if (deviceInfo.hid.usUsagePage == (ushort)Hid.UsagePage.Consumer && deviceInfo.hid.usUsage == (ushort)Hid.UsageIdConsumer.ConsumerControl)
426 usagePageHandler = HidConsumerDeviceHandler;
428 //Unknown HID message
431 Debug.WriteLine("Unknown HID message.");
435 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
436 && rawInput.hid.dwCount > 0)) //Check that we have at least one HID msg
442 //Allocate a buffer for one HID input
443 byte[] hidInputReport = new byte[rawInput.hid.dwSizeHid];
445 Debug.WriteLine("Raw input contains " + rawInput.hid.dwCount + " HID input report(s)");
447 //For each HID input report in our raw input
448 for (int i = 0; i < rawInput.hid.dwCount; i++)
450 //Compute the address from which to copy our HID input
451 int hidInputOffset = 0;
454 byte* source = (byte*)rawInputBuffer;
455 source += sizeof(RAWINPUTHEADER) + sizeof(RAWHID) + (rawInput.hid.dwSizeHid * i);
456 hidInputOffset = (int)source;
459 //Copy HID input into our buffer
460 Marshal.Copy(new IntPtr(hidInputOffset), hidInputReport, 0, (int)rawInput.hid.dwSizeHid);
462 //Print HID input report in our debug output
463 string hidDump = "HID input report: ";
464 foreach (byte b in hidInputReport)
466 hidDump += b.ToString("X2");
468 Debug.WriteLine(hidDump);
471 uint usageCount = 1; //Assuming a single usage per input report. Is that correct?
472 Win32.USAGE_AND_PAGE[] usages = new Win32.USAGE_AND_PAGE[usageCount];
473 Win32.HidStatus status = Win32.Function.HidP_GetUsagesEx(Win32.HIDP_REPORT_TYPE.HidP_Input, 0, usages, ref usageCount, preParsedData, hidInputReport, (uint)hidInputReport.Length);
474 if (status != Win32.HidStatus.HIDP_STATUS_SUCCESS)
476 Debug.WriteLine("Could not parse HID data!");
480 Debug.WriteLine("UsagePage: 0x" + usages[0].UsagePage.ToString("X4"));
481 Debug.WriteLine("Usage: 0x" + usages[0].Usage.ToString("X4"));
482 //Call on our Usage Page handler
483 usagePageHandler(usages[0].Usage);
488 else if (rawInput.header.dwType == Const.RIM_TYPEMOUSE)
490 Debug.WriteLine("WM_INPUT source device is Mouse.");
491 // do mouse handling...
493 else if (rawInput.header.dwType == Const.RIM_TYPEKEYBOARD)
495 Debug.WriteLine("WM_INPUT source device is Keyboard.");
496 // do keyboard handling...
497 Debug.WriteLine("Type: " + deviceInfo.keyboard.dwType.ToString());
498 Debug.WriteLine("SubType: " + deviceInfo.keyboard.dwSubType.ToString());
499 Debug.WriteLine("Mode: " + deviceInfo.keyboard.dwKeyboardMode.ToString());
500 Debug.WriteLine("Number of function keys: " + deviceInfo.keyboard.dwNumberOfFunctionKeys.ToString());
501 Debug.WriteLine("Number of indicators: " + deviceInfo.keyboard.dwNumberOfIndicators.ToString());
502 Debug.WriteLine("Number of keys total: " + deviceInfo.keyboard.dwNumberOfKeysTotal.ToString());
507 //Always executed when leaving our try block
508 Marshal.FreeHGlobal(rawInputBuffer);
509 Marshal.FreeHGlobal(preParsedData);