RemoteControlDevice.cs
author sl
Sat, 06 Dec 2014 22:59:55 +0100
changeset 28 6af1cbb3beb4
parent 27 305d2ecd3b1a
child 29 7679a5ab194b
permissions -rw-r--r--
HID Usage Tables fixes.
     1 using System;
     2 using System.Windows.Forms;
     3 using System.Runtime.InteropServices;
     4 using System.Diagnostics;
     5 using System.Text;
     6 using Microsoft.Win32.SafeHandles;
     7 
     8 using Hid.UsageTables;
     9 using Win32;
    10 
    11 
    12 
    13 namespace Devices.RemoteControl
    14 {
    15 
    16     public enum InputDevice
    17     {
    18         Key,
    19         Mouse,
    20         OEM
    21     }
    22 
    23 
    24     public enum RemoteControlButton
    25     {
    26         Clear,
    27         Down,
    28         Left,
    29         Digit0,
    30         Digit1,
    31         Digit2,
    32         Digit3,
    33         Digit4,
    34         Digit5,
    35         Digit6,
    36         Digit7,
    37         Digit8,
    38         Digit9,
    39         Enter,
    40         Right,
    41         Up,
    42 
    43         Back,
    44         ChannelDown,
    45         ChannelUp,
    46         FastForward,
    47         VolumeMute,
    48         Pause,
    49         Play,
    50         PlayPause,
    51         Record,
    52         PreviousTrack,
    53         Rewind,
    54         NextTrack,
    55         Stop,
    56         VolumeDown,
    57         VolumeUp,
    58 
    59         RecordedTV,
    60         Guide,
    61         LiveTV,
    62         MoreInfo,
    63         Print,
    64         DVDMenu,
    65         DVDAngle,
    66         DVDAudio,
    67         DVDSubtitle,
    68         MyMusic,
    69         MyPictures,
    70         MyVideos,
    71         MyTV,
    72         OEM1,
    73         OEM2,
    74         StandBy,
    75         TVJump,
    76 
    77         Unknown
    78     }
    79 
    80 
    81     #region RemoteControlEventArgs
    82 
    83     public class RemoteControlEventArgs : EventArgs
    84     {
    85         RemoteControlButton _rcb;
    86         InputDevice _device;
    87         MceButton iMceButton;
    88         ConsumerControl iConsumerControl;
    89 
    90         public RemoteControlEventArgs(RemoteControlButton rcb, InputDevice device)
    91         {
    92             SetNullButtons();
    93             //
    94             _rcb = rcb;
    95             _device = device;
    96         }
    97 
    98         public RemoteControlEventArgs(ConsumerControl aConsumerControl, InputDevice device)
    99         {
   100             SetNullButtons();
   101             //
   102             iConsumerControl = aConsumerControl;
   103             _device = device;
   104         }
   105 
   106 
   107         public RemoteControlEventArgs(MceButton mce, InputDevice device)
   108         {
   109             SetNullButtons();
   110             //
   111             iMceButton = mce;
   112             _device = device;
   113         }
   114 
   115         private void SetNullButtons()
   116         {
   117             iConsumerControl = ConsumerControl.Null;
   118             iMceButton = MceButton.Null;
   119             _rcb = RemoteControlButton.Unknown;
   120         }
   121 
   122         public RemoteControlEventArgs()
   123         {
   124             iMceButton = MceButton.Null;
   125             _rcb = RemoteControlButton.Unknown;
   126             _device = InputDevice.Key;
   127         }
   128 
   129         public RemoteControlButton Button
   130         {
   131             get { return _rcb; }
   132             set { _rcb = value; }
   133         }
   134 
   135         public MceButton MceButton
   136         {
   137             get { return iMceButton; }
   138             set { iMceButton = value; }
   139         }
   140 
   141         public ConsumerControl ConsumerControl
   142         {
   143             get { return iConsumerControl; }
   144             set { iConsumerControl = value; }
   145         }
   146 
   147         public InputDevice Device
   148         {
   149             get { return _device; }
   150             set { _device = value; }
   151         }
   152     }
   153 
   154     #endregion RemoteControlEventArgs
   155 
   156 
   157     public sealed class RemoteControlDevice
   158     {
   159         public delegate bool RemoteControlDeviceEventHandler(object sender, RemoteControlEventArgs e);
   160         public event RemoteControlDeviceEventHandler ButtonPressed;
   161 
   162         /// <summary>
   163         /// Return true if the usage was processed.
   164         /// </summary>
   165         /// <param name="aUsage"></param>
   166         /// <returns></returns>
   167         public delegate bool HidUsageHandler(ushort aUsage);
   168 
   169 
   170         //-------------------------------------------------------------
   171         // constructors
   172         //-------------------------------------------------------------
   173 
   174         public RemoteControlDevice(IntPtr aHWND)
   175         {
   176             // Register the input device to receive the commands from the
   177             // remote device. See http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnwmt/html/remote_control.asp
   178             // for the vendor defined usage page.
   179 
   180             RAWINPUTDEVICE[] rid = new RAWINPUTDEVICE[4];
   181 
   182             int i = 0;
   183             rid[i].usUsagePage = (ushort)Hid.UsagePage.MceRemote;
   184             rid[i].usUsage = (ushort)Hid.UsageIdMce.MceRemote;
   185             rid[i].dwFlags = Const.RIDEV_EXINPUTSINK;
   186             rid[i].hwndTarget = aHWND;
   187 
   188             i++;
   189             rid[i].usUsagePage = (ushort)Hid.UsagePage.Consumer;
   190             rid[i].usUsage = (ushort)Hid.UsageCollectionConsumer.ConsumerControl;
   191             rid[i].dwFlags = Const.RIDEV_EXINPUTSINK;
   192             rid[i].hwndTarget = aHWND;
   193 
   194             i++;
   195             rid[i].usUsagePage = (ushort)Hid.UsagePage.Consumer;
   196             rid[i].usUsage = (ushort)Hid.UsageCollectionConsumer.Selection;
   197             rid[i].dwFlags = Const.RIDEV_EXINPUTSINK;
   198             rid[i].hwndTarget = aHWND;
   199 
   200             i++;
   201             rid[i].usUsagePage = (ushort)Hid.UsagePage.GenericDesktopControls;
   202             rid[i].usUsage = (ushort)Hid.UsageCollectionGenericDesktop.SystemControl;
   203             rid[i].dwFlags = Const.RIDEV_EXINPUTSINK;
   204             rid[i].hwndTarget = aHWND;
   205 
   206             //i++;
   207             //rid[i].usUsagePage = (ushort)Hid.UsagePage.GenericDesktopControls;
   208             //rid[i].usUsage = (ushort)Hid.UsageCollectionGenericDesktop.Keyboard;
   209             //rid[i].dwFlags = Const.RIDEV_EXINPUTSINK;
   210             //rid[i].hwndTarget = aHWND;
   211 
   212             //i++;
   213             //rid[i].usUsagePage = (ushort)Hid.UsagePage.GenericDesktopControls;
   214             //rid[i].usUsage = (ushort)Hid.UsageCollectionGenericDesktop.Mouse;
   215             //rid[i].dwFlags = Const.RIDEV_EXINPUTSINK;
   216             //rid[i].hwndTarget = aHWND;
   217 
   218 
   219             if (!Function.RegisterRawInputDevices(rid, (uint)rid.Length, (uint)Marshal.SizeOf(rid[0])))
   220             {
   221                 throw new ApplicationException("Failed to register raw input devices: " + Marshal.GetLastWin32Error().ToString());
   222             }
   223         }
   224 
   225 
   226         //-------------------------------------------------------------
   227         // methods
   228         //-------------------------------------------------------------
   229 
   230         public void ProcessMessage(Message message)
   231         {
   232             switch (message.Msg)
   233             {
   234                 case Const.WM_KEYDOWN:
   235                     ProcessKeyDown(message.WParam);
   236                     break;
   237                 case Const.WM_INPUT:
   238                     //Returning zero means we processed that message.
   239                     message.Result = new IntPtr(0);
   240                     ProcessInputCommand(ref message);
   241                     break;
   242             }
   243 
   244         }
   245 
   246 
   247         //-------------------------------------------------------------
   248         // methods (helpers)
   249         //-------------------------------------------------------------
   250 
   251         private void ProcessKeyDown(IntPtr wParam)
   252         {
   253             RemoteControlButton rcb = RemoteControlButton.Unknown;
   254 
   255             switch (wParam.ToInt32())
   256             {
   257                 case (int)Keys.Escape:
   258                     rcb = RemoteControlButton.Clear;
   259                     break;
   260                 case (int)Keys.Up:
   261                     rcb = RemoteControlButton.Up;
   262                     break;
   263                 case (int)Keys.Down:
   264                     rcb = RemoteControlButton.Down;
   265                     break;
   266                 case (int)Keys.Left:
   267                     rcb = RemoteControlButton.Left;
   268                     break;
   269                 case (int)Keys.Right:
   270                     rcb = RemoteControlButton.Right;
   271                     break;
   272                 case (int)Keys.Enter:
   273                     rcb = RemoteControlButton.Enter;
   274                     break;
   275                 case (int)Keys.D0:
   276                     rcb = RemoteControlButton.Digit0;
   277                     break;
   278                 case (int)Keys.D1:
   279                     rcb = RemoteControlButton.Digit1;
   280                     break;
   281                 case (int)Keys.D2:
   282                     rcb = RemoteControlButton.Digit2;
   283                     break;
   284                 case (int)Keys.D3:
   285                     rcb = RemoteControlButton.Digit3;
   286                     break;
   287                 case (int)Keys.D4:
   288                     rcb = RemoteControlButton.Digit4;
   289                     break;
   290                 case (int)Keys.D5:
   291                     rcb = RemoteControlButton.Digit5;
   292                     break;
   293                 case (int)Keys.D6:
   294                     rcb = RemoteControlButton.Digit6;
   295                     break;
   296                 case (int)Keys.D7:
   297                     rcb = RemoteControlButton.Digit7;
   298                     break;
   299                 case (int)Keys.D8:
   300                     rcb = RemoteControlButton.Digit8;
   301                     break;
   302                 case (int)Keys.D9:
   303                     rcb = RemoteControlButton.Digit9;
   304                     break;
   305             }
   306 
   307             if (this.ButtonPressed != null && rcb != RemoteControlButton.Unknown)
   308             {
   309                 Debug.WriteLine("KeyDown: " + rcb.ToString());
   310                 this.ButtonPressed(this, new RemoteControlEventArgs(rcb, InputDevice.Key));
   311             }
   312         }
   313 
   314 
   315         /// <summary>
   316         /// 
   317         /// </summary>
   318         /// <param name="aUsage"></param>
   319         private bool HidConsumerDeviceHandler(ushort aUsage)
   320         {
   321             if (aUsage == 0)
   322             {
   323                 //Just skip those
   324                 return false;
   325             }
   326 
   327             if (Enum.IsDefined(typeof(ConsumerControl), aUsage) && aUsage != 0) //Our button is a known consumer control
   328             {
   329                 if (this.ButtonPressed != null)
   330                 {
   331                     return this.ButtonPressed(this, new RemoteControlEventArgs((ConsumerControl)aUsage, InputDevice.OEM));
   332                 }
   333                 return false;
   334             }
   335             else
   336             {
   337                 Debug.WriteLine("Unknown Consumer Control!");
   338                 return false;
   339             }
   340         }
   341 
   342         /// <summary>
   343         /// 
   344         /// </summary>
   345         /// <param name="aUsage"></param>
   346         private bool HidMceRemoteHandler(ushort aUsage)
   347         {
   348             if (aUsage == 0)
   349             {
   350                 //Just skip those
   351                 return false;
   352             }
   353 
   354 
   355             if (Enum.IsDefined(typeof(MceButton), aUsage) && aUsage != 0) //Our button is a known MCE button
   356             {
   357                 if (this.ButtonPressed != null)
   358                 {
   359                     return this.ButtonPressed(this, new RemoteControlEventArgs((MceButton)aUsage, InputDevice.OEM));
   360                 }
   361                 return false;
   362             }
   363             else
   364             {
   365                 Debug.WriteLine("Unknown MCE button!");
   366                 return false;
   367             }
   368         }
   369 
   370 
   371         private void ProcessInputCommand(ref Message message)
   372         {
   373             //We received a WM_INPUT message
   374             Debug.WriteLine("================WM_INPUT================");
   375 
   376             Hid.HidEvent hidEvent = new Hid.HidEvent(message);
   377             hidEvent.DebugWrite();
   378 
   379             if (!hidEvent.IsValid || !hidEvent.IsGeneric)
   380             {
   381                 Debug.WriteLine("Skipping HID message.");
   382                 return;
   383             }
   384 
   385 
   386             HidUsageHandler usagePageHandler = null;
   387 
   388             //Check if this an MCE remote HID message
   389             if (hidEvent.UsagePage == (ushort)Hid.UsagePage.MceRemote && hidEvent.UsageCollection == (ushort)Hid.UsageIdMce.MceRemote)
   390             {
   391                 usagePageHandler = HidMceRemoteHandler;
   392             }
   393             //Check if this is a consumer control HID message
   394             else if (hidEvent.UsagePage == (ushort)Hid.UsagePage.Consumer && hidEvent.UsageCollection == (ushort)Hid.UsageCollectionConsumer.ConsumerControl)
   395             {
   396                 usagePageHandler = HidConsumerDeviceHandler;
   397             }
   398             //Unknown HID message
   399             else
   400             {
   401                 Debug.WriteLine("Unknown HID message.");
   402                 return;
   403             }
   404 
   405             foreach (ushort usage in hidEvent.Usages)
   406             {
   407                 usagePageHandler(usage);
   408             }
   409         }
   410     }
   411 }
   412