RemoteControlDevice.cs
author sl
Fri, 19 Dec 2014 21:07:15 +0100
changeset 35 928c966fcf42
parent 29 7679a5ab194b
child 40 b3e177062849
permissions -rw-r--r--
Adding missing entries in consumer usage table.
Adding magic MyTv code in MCE usage table as handled by MP.
     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         WindowsMediaCenterRemoteControl 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(WindowsMediaCenterRemoteControl 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 = WindowsMediaCenterRemoteControl.Null;
   119             _rcb = RemoteControlButton.Unknown;
   120         }
   121 
   122         public RemoteControlEventArgs()
   123         {
   124             iMceButton = WindowsMediaCenterRemoteControl.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 WindowsMediaCenterRemoteControl 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         Hid.HidHandler iHidHandler;
   170 
   171 
   172         //-------------------------------------------------------------
   173         // constructors
   174         //-------------------------------------------------------------
   175 
   176         public RemoteControlDevice(IntPtr aHWND)
   177         {
   178             // Register the input device to receive the commands from the
   179             // remote device. See http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnwmt/html/remote_control.asp
   180             // for the vendor defined usage page.
   181 
   182             RAWINPUTDEVICE[] rid = new RAWINPUTDEVICE[4];
   183 
   184             int i = 0;
   185             rid[i].usUsagePage = (ushort)Hid.UsagePage.WindowsMediaCenterRemoteControl;
   186             rid[i].usUsage = (ushort)Hid.UsageCollectionWindowsMediaCenter.WindowsMediaCenterRemoteControl;
   187             rid[i].dwFlags = Const.RIDEV_EXINPUTSINK;
   188             rid[i].hwndTarget = aHWND;
   189 
   190             i++;
   191             rid[i].usUsagePage = (ushort)Hid.UsagePage.Consumer;
   192             rid[i].usUsage = (ushort)Hid.UsageCollectionConsumer.ConsumerControl;
   193             rid[i].dwFlags = Const.RIDEV_EXINPUTSINK;
   194             rid[i].hwndTarget = aHWND;
   195 
   196             i++;
   197             rid[i].usUsagePage = (ushort)Hid.UsagePage.Consumer;
   198             rid[i].usUsage = (ushort)Hid.UsageCollectionConsumer.Selection;
   199             rid[i].dwFlags = Const.RIDEV_EXINPUTSINK;
   200             rid[i].hwndTarget = aHWND;
   201 
   202             i++;
   203             rid[i].usUsagePage = (ushort)Hid.UsagePage.GenericDesktopControls;
   204             rid[i].usUsage = (ushort)Hid.UsageCollectionGenericDesktop.SystemControl;
   205             rid[i].dwFlags = Const.RIDEV_EXINPUTSINK;
   206             rid[i].hwndTarget = aHWND;
   207 
   208             //i++;
   209             //rid[i].usUsagePage = (ushort)Hid.UsagePage.GenericDesktopControls;
   210             //rid[i].usUsage = (ushort)Hid.UsageCollectionGenericDesktop.Keyboard;
   211             //rid[i].dwFlags = Const.RIDEV_EXINPUTSINK;
   212             //rid[i].hwndTarget = aHWND;
   213 
   214             //i++;
   215             //rid[i].usUsagePage = (ushort)Hid.UsagePage.GenericDesktopControls;
   216             //rid[i].usUsage = (ushort)Hid.UsageCollectionGenericDesktop.Mouse;
   217             //rid[i].dwFlags = Const.RIDEV_EXINPUTSINK;
   218             //rid[i].hwndTarget = aHWND;
   219 
   220 
   221             iHidHandler = new Hid.HidHandler(rid);
   222             if (!iHidHandler.IsRegistered)
   223             {
   224                 Debug.WriteLine("Failed to register raw input devices: " + Marshal.GetLastWin32Error().ToString());
   225             }
   226             iHidHandler.OnHidEvent += HandleHidEvent;
   227         }
   228 
   229 
   230         //-------------------------------------------------------------
   231         // methods
   232         //-------------------------------------------------------------
   233 
   234         public void ProcessMessage(Message message)
   235         {
   236             switch (message.Msg)
   237             {
   238                 case Const.WM_KEYDOWN:
   239                     ProcessKeyDown(message.WParam);
   240                     break;
   241                 case Const.WM_INPUT:
   242                     //Returning zero means we processed that message.
   243                     message.Result = new IntPtr(0);
   244                     ProcessInputCommand(ref message);
   245                     break;
   246             }
   247 
   248         }
   249 
   250 
   251         //-------------------------------------------------------------
   252         // methods (helpers)
   253         //-------------------------------------------------------------
   254 
   255         private void ProcessKeyDown(IntPtr wParam)
   256         {
   257             RemoteControlButton rcb = RemoteControlButton.Unknown;
   258 
   259             switch (wParam.ToInt32())
   260             {
   261                 case (int)Keys.Escape:
   262                     rcb = RemoteControlButton.Clear;
   263                     break;
   264                 case (int)Keys.Up:
   265                     rcb = RemoteControlButton.Up;
   266                     break;
   267                 case (int)Keys.Down:
   268                     rcb = RemoteControlButton.Down;
   269                     break;
   270                 case (int)Keys.Left:
   271                     rcb = RemoteControlButton.Left;
   272                     break;
   273                 case (int)Keys.Right:
   274                     rcb = RemoteControlButton.Right;
   275                     break;
   276                 case (int)Keys.Enter:
   277                     rcb = RemoteControlButton.Enter;
   278                     break;
   279                 case (int)Keys.D0:
   280                     rcb = RemoteControlButton.Digit0;
   281                     break;
   282                 case (int)Keys.D1:
   283                     rcb = RemoteControlButton.Digit1;
   284                     break;
   285                 case (int)Keys.D2:
   286                     rcb = RemoteControlButton.Digit2;
   287                     break;
   288                 case (int)Keys.D3:
   289                     rcb = RemoteControlButton.Digit3;
   290                     break;
   291                 case (int)Keys.D4:
   292                     rcb = RemoteControlButton.Digit4;
   293                     break;
   294                 case (int)Keys.D5:
   295                     rcb = RemoteControlButton.Digit5;
   296                     break;
   297                 case (int)Keys.D6:
   298                     rcb = RemoteControlButton.Digit6;
   299                     break;
   300                 case (int)Keys.D7:
   301                     rcb = RemoteControlButton.Digit7;
   302                     break;
   303                 case (int)Keys.D8:
   304                     rcb = RemoteControlButton.Digit8;
   305                     break;
   306                 case (int)Keys.D9:
   307                     rcb = RemoteControlButton.Digit9;
   308                     break;
   309             }
   310 
   311             if (this.ButtonPressed != null && rcb != RemoteControlButton.Unknown)
   312             {
   313                 Debug.WriteLine("KeyDown: " + rcb.ToString());
   314                 this.ButtonPressed(this, new RemoteControlEventArgs(rcb, InputDevice.Key));
   315             }
   316         }
   317 
   318 
   319         /// <summary>
   320         /// 
   321         /// </summary>
   322         /// <param name="aUsage"></param>
   323         private bool HidConsumerDeviceHandler(ushort aUsage)
   324         {
   325             if (aUsage == 0)
   326             {
   327                 //Just skip those
   328                 return false;
   329             }
   330 
   331             if (Enum.IsDefined(typeof(ConsumerControl), aUsage) && aUsage != 0) //Our button is a known consumer control
   332             {
   333                 if (this.ButtonPressed != null)
   334                 {
   335                     return this.ButtonPressed(this, new RemoteControlEventArgs((ConsumerControl)aUsage, InputDevice.OEM));
   336                 }
   337                 return false;
   338             }
   339             else
   340             {
   341                 Debug.WriteLine("Unknown Consumer Control!");
   342                 return false;
   343             }
   344         }
   345 
   346         /// <summary>
   347         /// 
   348         /// </summary>
   349         /// <param name="aUsage"></param>
   350         private bool HidMceRemoteHandler(ushort aUsage)
   351         {
   352             if (aUsage == 0)
   353             {
   354                 //Just skip those
   355                 return false;
   356             }
   357 
   358 
   359             if (Enum.IsDefined(typeof(WindowsMediaCenterRemoteControl), aUsage) && aUsage != 0) //Our button is a known MCE button
   360             {
   361                 if (this.ButtonPressed != null)
   362                 {
   363                     return this.ButtonPressed(this, new RemoteControlEventArgs((WindowsMediaCenterRemoteControl)aUsage, InputDevice.OEM));
   364                 }
   365                 return false;
   366             }
   367             else
   368             {
   369                 Debug.WriteLine("Unknown MCE button!");
   370                 return false;
   371             }
   372         }
   373 
   374         /// <summary>
   375         /// 
   376         /// </summary>
   377         /// <param name="message"></param>
   378         private void ProcessInputCommand(ref Message message)
   379         {
   380             //We received a WM_INPUT message
   381             Debug.WriteLine("================WM_INPUT================");
   382 
   383             iHidHandler.ProcessInput(message);
   384 
   385         }
   386 
   387         /// <summary>
   388         /// 
   389         /// </summary>
   390         /// <param name="aSender"></param>
   391         /// <param name="aHidEvent"></param>
   392         void HandleHidEvent(object aSender, Hid.HidEvent aHidEvent)
   393         {
   394             HidUsageHandler usagePageHandler = null;
   395 
   396             //Check if this an MCE remote HID message
   397             if (aHidEvent.UsagePage == (ushort)Hid.UsagePage.WindowsMediaCenterRemoteControl && aHidEvent.UsageCollection == (ushort)Hid.UsageCollectionWindowsMediaCenter.WindowsMediaCenterRemoteControl)
   398             {
   399                 usagePageHandler = HidMceRemoteHandler;
   400             }
   401             //Check if this is a consumer control HID message
   402             else if (aHidEvent.UsagePage == (ushort)Hid.UsagePage.Consumer && aHidEvent.UsageCollection == (ushort)Hid.UsageCollectionConsumer.ConsumerControl)
   403             {
   404                 usagePageHandler = HidConsumerDeviceHandler;
   405             }
   406             //Unknown HID message
   407             else
   408             {
   409                 Debug.WriteLine("Unknown HID message.");
   410                 return;
   411             }
   412 
   413             foreach (ushort usage in aHidEvent.Usages)
   414             {
   415                 usagePageHandler(usage);
   416             }
   417         }
   418     }
   419 }
   420