Fixing unsafe compile error.
2 using System.Windows.Forms;
3 using System.Runtime.InteropServices;
4 using System.Diagnostics;
7 namespace BruceThomas.Devices.RemoteControl
9 public enum InputDevice
17 public enum RemoteControlButton
73 #region RemoteControlEventArgs
75 public class RemoteControlEventArgs : EventArgs
77 RemoteControlButton _rcb;
80 public RemoteControlEventArgs(RemoteControlButton rcb, InputDevice device)
87 public RemoteControlEventArgs()
89 _rcb = RemoteControlButton.Unknown;
90 _device = InputDevice.Key;
94 public RemoteControlButton Button
100 public InputDevice Device
102 get { return _device; }
103 set { _device = value; }
107 #endregion RemoteControlEventArgs
110 public sealed class RemoteControlDevice
113 [StructLayout(LayoutKind.Sequential, Pack = 1)]
114 internal struct RAWINPUTDEVICE
116 [MarshalAs(UnmanagedType.U2)]
117 public ushort usUsagePage;
118 [MarshalAs(UnmanagedType.U2)]
119 public ushort usUsage;
120 [MarshalAs(UnmanagedType.U4)]
122 public IntPtr hwndTarget;
126 [StructLayout(LayoutKind.Sequential, Pack = 1)]
127 internal struct RAWINPUTHEADER
129 [MarshalAs(UnmanagedType.U4)]
131 [MarshalAs(UnmanagedType.U4)]
133 public IntPtr hDevice;
134 [MarshalAs(UnmanagedType.U4)]
139 [StructLayout(LayoutKind.Sequential, Pack = 1)]
140 internal struct RAWHID
142 [MarshalAs(UnmanagedType.U4)]
143 public int dwSizeHid;
144 [MarshalAs(UnmanagedType.U4)]
151 [StructLayout(LayoutKind.Sequential, Pack = 1)]
152 internal struct BUTTONSSTR
154 [MarshalAs(UnmanagedType.U2)]
155 public ushort usButtonFlags;
156 [MarshalAs(UnmanagedType.U2)]
157 public ushort usButtonData;
161 [StructLayout(LayoutKind.Explicit, Pack = 1)]
162 internal struct RAWMOUSE
164 [MarshalAs(UnmanagedType.U2)]
165 [FieldOffset (0)] public ushort usFlags;
166 [MarshalAs(UnmanagedType.U4)]
167 [FieldOffset (4)] public uint ulButtons;
168 [FieldOffset (4)] public BUTTONSSTR buttonsStr;
169 [MarshalAs(UnmanagedType.U4)]
170 [FieldOffset (8)] public uint ulRawButtons;
171 [MarshalAs(UnmanagedType.U4)]
172 [FieldOffset (12)] public int lLastX;
173 [MarshalAs(UnmanagedType.U4)]
174 [FieldOffset (16)] public int lLastY;
175 [MarshalAs(UnmanagedType.U4)]
176 [FieldOffset (20)] public uint ulExtraInformation;
179 [StructLayout(LayoutKind.Sequential, Pack = 1)]
180 internal struct RAWKEYBOARD
182 [MarshalAs(UnmanagedType.U2)]
183 public ushort MakeCode;
184 [MarshalAs(UnmanagedType.U2)]
186 [MarshalAs(UnmanagedType.U2)]
187 public ushort Reserved;
188 [MarshalAs(UnmanagedType.U2)]
190 [MarshalAs(UnmanagedType.U4)]
192 [MarshalAs(UnmanagedType.U4)]
193 public uint ExtraInformation;
197 [StructLayout(LayoutKind.Explicit, Pack=1)]
198 internal struct RAWINPUT
200 [FieldOffset (0)] public RAWINPUTHEADER header;
201 [FieldOffset (16)] public RAWMOUSE mouse;
202 [FieldOffset (16)] public RAWKEYBOARD keyboard;
203 [FieldOffset (16)] public RAWHID hid;
207 [DllImport("User32.dll")]
208 extern static bool RegisterRawInputDevices(RAWINPUTDEVICE[] pRawInputDevice, uint uiNumDevices, uint cbSize);
210 [DllImport("User32.dll")]
211 extern static uint GetRawInputData(IntPtr hRawInput, uint uiCommand, IntPtr pData, ref uint pcbSize, uint cbSizeHeader);
214 private const int WM_KEYDOWN = 0x0100;
215 private const int WM_APPCOMMAND = 0x0319;
216 private const int WM_INPUT = 0x00FF;
218 private const int APPCOMMAND_BROWSER_BACKWARD = 1;
219 private const int APPCOMMAND_VOLUME_MUTE = 8;
220 private const int APPCOMMAND_VOLUME_DOWN = 9;
221 private const int APPCOMMAND_VOLUME_UP = 10;
222 private const int APPCOMMAND_MEDIA_NEXTTRACK = 11;
223 private const int APPCOMMAND_MEDIA_PREVIOUSTRACK = 12;
224 private const int APPCOMMAND_MEDIA_STOP = 13;
225 private const int APPCOMMAND_MEDIA_PLAY_PAUSE = 14;
226 private const int APPCOMMAND_MEDIA_PLAY = 46;
227 private const int APPCOMMAND_MEDIA_PAUSE = 47;
228 private const int APPCOMMAND_MEDIA_RECORD = 48;
229 private const int APPCOMMAND_MEDIA_FAST_FORWARD = 49;
230 private const int APPCOMMAND_MEDIA_REWIND = 50;
231 private const int APPCOMMAND_MEDIA_CHANNEL_UP = 51;
232 private const int APPCOMMAND_MEDIA_CHANNEL_DOWN = 52;
234 private const int RAWINPUT_DETAILS = 0x209;
235 private const int RAWINPUT_GUIDE = 0x8D;
236 private const int RAWINPUT_TVJUMP = 0x25;
237 private const int RAWINPUT_STANDBY = 0x82;
238 private const int RAWINPUT_OEM1 = 0x80;
239 private const int RAWINPUT_OEM2 = 0x81;
240 private const int RAWINPUT_MYTV = 0x46;
241 private const int RAWINPUT_MYVIDEOS = 0x4A;
242 private const int RAWINPUT_MYPICTURES = 0x49;
243 private const int RAWINPUT_MYMUSIC = 0x47;
244 private const int RAWINPUT_RECORDEDTV = 0x48;
245 private const int RAWINPUT_DVDANGLE = 0x4B;
246 private const int RAWINPUT_DVDAUDIO = 0x4C;
247 private const int RAWINPUT_DVDMENU = 0x24;
248 private const int RAWINPUT_DVDSUBTITLE = 0x4D;
250 private const int RIM_TYPEMOUSE = 0;
251 private const int RIM_TYPEKEYBOARD = 1;
252 private const int RIM_TYPEHID = 2;
254 private const int RID_INPUT = 0x10000003;
255 private const int RID_HEADER = 0x10000005;
257 private const int FAPPCOMMAND_MASK = 0xF000;
258 private const int FAPPCOMMAND_MOUSE = 0x8000;
259 private const int FAPPCOMMAND_KEY = 0;
260 private const int FAPPCOMMAND_OEM = 0x1000;
262 public delegate void RemoteControlDeviceEventHandler(object sender, RemoteControlEventArgs e);
263 public event RemoteControlDeviceEventHandler ButtonPressed;
266 //-------------------------------------------------------------
268 //-------------------------------------------------------------
270 public RemoteControlDevice()
272 // Register the input device to receive the commands from the
273 // remote device. See http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnwmt/html/remote_control.asp
274 // for the vendor defined usage page.
276 RAWINPUTDEVICE[] rid = new RAWINPUTDEVICE[3];
278 rid[0].usUsagePage = 0xFFBC;
279 rid[0].usUsage = 0x88;
282 rid[1].usUsagePage = 0x0C;
283 rid[1].usUsage = 0x01;
286 rid[2].usUsagePage = 0x0C;
287 rid[2].usUsage = 0x80;
290 if (!RegisterRawInputDevices(rid,
292 (uint) Marshal.SizeOf(rid[0]))
295 throw new ApplicationException("Failed to register raw input devices.");
300 //-------------------------------------------------------------
302 //-------------------------------------------------------------
304 public void ProcessMessage(Message message)
311 param = message.WParam.ToInt32();
312 ProcessKeyDown(param);
315 param = message.LParam.ToInt32();
316 ProcessAppCommand(param);
319 ProcessInputCommand(ref message);
320 message.Result = new IntPtr(0);
327 //-------------------------------------------------------------
329 //-------------------------------------------------------------
331 private void ProcessKeyDown(int param)
333 RemoteControlButton rcb = RemoteControlButton.Unknown;
337 case (int) Keys.Escape:
338 rcb = RemoteControlButton.Clear;
340 case (int) Keys.Down:
341 rcb = RemoteControlButton.Down;
343 case (int) Keys.Left:
344 rcb = RemoteControlButton.Left;
347 rcb = RemoteControlButton.Digit0;
350 rcb = RemoteControlButton.Digit1;
353 rcb = RemoteControlButton.Digit2;
356 rcb = RemoteControlButton.Digit3;
359 rcb = RemoteControlButton.Digit4;
362 rcb = RemoteControlButton.Digit5;
365 rcb = RemoteControlButton.Digit6;
368 rcb = RemoteControlButton.Digit7;
371 rcb = RemoteControlButton.Digit8;
374 rcb = RemoteControlButton.Digit9;
376 case (int) Keys.Enter:
377 rcb = RemoteControlButton.Enter;
379 case (int) Keys.Right:
380 rcb = RemoteControlButton.Right;
383 rcb = RemoteControlButton.Up;
387 if (this.ButtonPressed != null && rcb != RemoteControlButton.Unknown)
388 this.ButtonPressed(this, new RemoteControlEventArgs(rcb, GetDevice(param)));
392 private void ProcessAppCommand(int param)
394 RemoteControlButton rcb = RemoteControlButton.Unknown;
396 int cmd = (int) (((ushort) (param >> 16)) & ~FAPPCOMMAND_MASK);
400 case APPCOMMAND_BROWSER_BACKWARD:
401 rcb = RemoteControlButton.Back;
403 case APPCOMMAND_MEDIA_CHANNEL_DOWN:
404 rcb = RemoteControlButton.ChannelDown;
406 case APPCOMMAND_MEDIA_CHANNEL_UP:
407 rcb = RemoteControlButton.ChannelUp;
409 case APPCOMMAND_MEDIA_FAST_FORWARD:
410 rcb = RemoteControlButton.FastForward;
412 case APPCOMMAND_VOLUME_MUTE:
413 rcb = RemoteControlButton.VolumeMute;
415 case APPCOMMAND_MEDIA_PAUSE:
416 rcb = RemoteControlButton.Pause;
418 case APPCOMMAND_MEDIA_PLAY:
419 rcb = RemoteControlButton.Play;
421 case APPCOMMAND_MEDIA_PLAY_PAUSE:
422 rcb = RemoteControlButton.PlayPause;
424 case APPCOMMAND_MEDIA_RECORD:
425 rcb = RemoteControlButton.Record;
427 case APPCOMMAND_MEDIA_PREVIOUSTRACK:
428 rcb = RemoteControlButton.PreviousTrack;
430 case APPCOMMAND_MEDIA_REWIND:
431 rcb = RemoteControlButton.Rewind;
433 case APPCOMMAND_MEDIA_NEXTTRACK:
434 rcb = RemoteControlButton.NextTrack;
436 case APPCOMMAND_MEDIA_STOP:
437 rcb = RemoteControlButton.Stop;
439 case APPCOMMAND_VOLUME_DOWN:
440 rcb = RemoteControlButton.VolumeDown;
442 case APPCOMMAND_VOLUME_UP:
443 rcb = RemoteControlButton.VolumeUp;
447 if (this.ButtonPressed != null && rcb != RemoteControlButton.Unknown)
448 this.ButtonPressed(this, new RemoteControlEventArgs(rcb, GetDevice(param)));
452 private void ProcessInputCommand(ref Message message)
454 RemoteControlButton rcb = RemoteControlButton.Unknown;
457 uint sizeOfHeader=(uint)Marshal.SizeOf(typeof(RAWINPUTHEADER));
459 //Get the size of our raw input data.
460 GetRawInputData(message.LParam, RID_INPUT, IntPtr.Zero, ref dwSize, sizeOfHeader);
462 //Allocate a large enough buffer
463 IntPtr buffer = Marshal.AllocHGlobal((int) dwSize);
466 if(buffer == IntPtr.Zero)
469 //Now read our RAWINPUT data
470 if (GetRawInputData(message.LParam, RID_INPUT, buffer, ref dwSize, (uint) Marshal.SizeOf(typeof(RAWINPUTHEADER))) != dwSize)
476 RAWINPUT raw = (RAWINPUT)Marshal.PtrToStructure(buffer, typeof(RAWINPUT));
478 //Check that our raw input is HID
479 if (raw.header.dwType == RIM_TYPEHID && raw.hid.dwSizeHid>0)
481 //Allocate a buffer for one HID message
482 byte[] bRawData = new byte[raw.hid.dwSizeHid];
484 //Compute the address from which to copy our HID message
488 byte* source = (byte*)buffer;
489 source += sizeof(RAWINPUTHEADER) + sizeof(RAWHID);
491 pRawData = (int)source;
493 //int pRawData = buffer.ToUint32() + Marshal.SizeOf(typeof(RAWINPUT)) + 1;
495 //Marshal.Copy(new IntPtr(pRawData), bRawData, 0, raw.hid.dwSizeHid - 1);
496 Marshal.Copy(new IntPtr(pRawData), bRawData, 0, raw.hid.dwSizeHid);
497 //int rawData = bRawData[0] | bRawData[1] << 8;
498 int rawData = bRawData[1]; //Get button code
499 Debug.WriteLine("HID " + raw.hid.dwCount + "/" + raw.hid.dwSizeHid + ":" + bRawData[0].ToString("X") + bRawData[1].ToString("X"));
503 case RAWINPUT_DETAILS:
504 rcb = RemoteControlButton.Details;
507 rcb = RemoteControlButton.Guide;
509 case RAWINPUT_TVJUMP:
510 rcb = RemoteControlButton.TVJump;
512 case RAWINPUT_STANDBY:
513 rcb = RemoteControlButton.StandBy;
516 rcb = RemoteControlButton.OEM1;
519 rcb = RemoteControlButton.OEM2;
522 rcb = RemoteControlButton.MyTV;
524 case RAWINPUT_MYVIDEOS:
525 rcb = RemoteControlButton.MyVideos;
527 case RAWINPUT_MYPICTURES:
528 rcb = RemoteControlButton.MyPictures;
530 case RAWINPUT_MYMUSIC:
531 rcb = RemoteControlButton.MyMusic;
533 case RAWINPUT_RECORDEDTV:
534 rcb = RemoteControlButton.RecordedTV;
536 case RAWINPUT_DVDANGLE:
537 rcb = RemoteControlButton.DVDAngle;
539 case RAWINPUT_DVDAUDIO:
540 rcb = RemoteControlButton.DVDAudio;
542 case RAWINPUT_DVDMENU:
543 rcb = RemoteControlButton.DVDMenu;
545 case RAWINPUT_DVDSUBTITLE:
546 rcb = RemoteControlButton.DVDSubtitle;
550 if (rcb != RemoteControlButton.Unknown && this.ButtonPressed != null)
551 this.ButtonPressed(this, new RemoteControlEventArgs(rcb, GetDevice(message.LParam.ToInt32())));
553 else if(raw.header.dwType == RIM_TYPEMOUSE)
555 // do mouse handling...
557 else if(raw.header.dwType == RIM_TYPEKEYBOARD)
559 // do keyboard handling...
564 Marshal.FreeHGlobal(buffer);
569 private InputDevice GetDevice(int param)
571 InputDevice inputDevice;
573 switch ((int) (((ushort) (param >> 16)) & FAPPCOMMAND_MASK))
575 case FAPPCOMMAND_OEM:
576 inputDevice = InputDevice.OEM;
578 case FAPPCOMMAND_MOUSE:
579 inputDevice = InputDevice.Mouse;
582 inputDevice = InputDevice.Key;