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