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