RemoteControlDevice.cs
author sl
Sat, 06 Dec 2014 00:59:59 +0100
changeset 19 d066e3999973
parent 18 24ac84ab9620
child 20 f2b65a8318e9
permissions -rw-r--r--
Starting to remove special case for app commands.
Adding a whole bunch of consumer controls.
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@8
     5
using Hid.UsageTables;
sl@9
     6
using Win32;
sl@0
     7
sl@6
     8
namespace Devices.RemoteControl
sl@0
     9
{
sl@6
    10
sl@0
    11
	public enum InputDevice
sl@0
    12
	{
sl@0
    13
		Key,
sl@0
    14
		Mouse,
sl@0
    15
		OEM
sl@0
    16
	}
sl@0
    17
sl@0
    18
sl@0
    19
	public enum RemoteControlButton
sl@0
    20
	{
sl@0
    21
		Clear,
sl@0
    22
		Down,
sl@0
    23
		Left,
sl@0
    24
		Digit0,
sl@0
    25
		Digit1,
sl@0
    26
		Digit2,
sl@0
    27
		Digit3,
sl@0
    28
		Digit4,
sl@0
    29
		Digit5,
sl@0
    30
		Digit6,
sl@0
    31
		Digit7,
sl@0
    32
		Digit8,
sl@0
    33
		Digit9,
sl@0
    34
		Enter,
sl@0
    35
		Right,
sl@0
    36
		Up,
sl@0
    37
sl@0
    38
		Back,
sl@0
    39
		ChannelDown,
sl@0
    40
		ChannelUp,
sl@0
    41
		FastForward,
sl@0
    42
		VolumeMute,
sl@0
    43
		Pause,
sl@0
    44
		Play,
sl@0
    45
        PlayPause,
sl@0
    46
		Record,
sl@0
    47
		PreviousTrack,
sl@0
    48
		Rewind,
sl@0
    49
		NextTrack,
sl@0
    50
		Stop,
sl@0
    51
		VolumeDown,
sl@0
    52
		VolumeUp,
sl@0
    53
sl@0
    54
		RecordedTV,
sl@0
    55
		Guide,
sl@0
    56
		LiveTV,
sl@12
    57
		MoreInfo,
sl@12
    58
        Print,
sl@0
    59
		DVDMenu,
sl@0
    60
		DVDAngle,
sl@0
    61
		DVDAudio,
sl@0
    62
		DVDSubtitle,
sl@0
    63
		MyMusic,
sl@0
    64
		MyPictures,
sl@0
    65
		MyVideos,
sl@0
    66
		MyTV,
sl@0
    67
		OEM1,
sl@0
    68
		OEM2,
sl@0
    69
		StandBy,
sl@0
    70
		TVJump,
sl@0
    71
sl@0
    72
		Unknown
sl@0
    73
	}
sl@0
    74
sl@0
    75
sl@0
    76
	#region RemoteControlEventArgs
sl@0
    77
sl@0
    78
	public class RemoteControlEventArgs : EventArgs
sl@0
    79
	{
sl@3
    80
        RemoteControlButton _rcb;
sl@0
    81
		InputDevice _device;
sl@3
    82
        MceButton iMceButton;
sl@19
    83
        ConsumerControl iConsumerControl;
sl@0
    84
sl@3
    85
        public RemoteControlEventArgs(RemoteControlButton rcb, InputDevice device)
sl@0
    86
		{
sl@19
    87
            SetNullButtons();
sl@19
    88
            //
sl@0
    89
			_rcb = rcb;
sl@19
    90
			_device = device;            
sl@0
    91
		}
sl@0
    92
sl@19
    93
        public RemoteControlEventArgs(ConsumerControl aConsumerControl, InputDevice device)
sl@19
    94
        {
sl@19
    95
            SetNullButtons();
sl@19
    96
            //
sl@19
    97
            iConsumerControl = aConsumerControl;            
sl@19
    98
            _device = device;
sl@19
    99
        }
sl@19
   100
sl@19
   101
sl@3
   102
        public RemoteControlEventArgs(MceButton mce, InputDevice device)
sl@3
   103
        {
sl@19
   104
            SetNullButtons();
sl@19
   105
            //
sl@19
   106
            iMceButton = mce;            
sl@19
   107
            _device = device;
sl@19
   108
        }
sl@19
   109
sl@19
   110
        private void SetNullButtons()
sl@19
   111
        {
sl@19
   112
            iConsumerControl = ConsumerControl.Null;
sl@19
   113
            iMceButton = MceButton.Null;
sl@3
   114
            _rcb = RemoteControlButton.Unknown;
sl@3
   115
        }
sl@0
   116
sl@0
   117
		public RemoteControlEventArgs()
sl@0
   118
		{
sl@3
   119
            iMceButton = MceButton.Null;
sl@0
   120
			_rcb = RemoteControlButton.Unknown;
sl@0
   121
			_device = InputDevice.Key;
sl@0
   122
		}
sl@0
   123
sl@0
   124
		public RemoteControlButton Button
sl@0
   125
		{
sl@0
   126
			get { return _rcb;  }
sl@0
   127
			set { _rcb = value; }
sl@0
   128
		}
sl@0
   129
sl@3
   130
        public MceButton MceButton
sl@3
   131
        {
sl@3
   132
            get { return iMceButton; }
sl@3
   133
            set { iMceButton = value; }
sl@3
   134
        }
sl@3
   135
sl@19
   136
        public ConsumerControl ConsumerControl
sl@19
   137
        {
sl@19
   138
            get { return iConsumerControl; }
sl@19
   139
            set { iConsumerControl = value; }
sl@19
   140
        }
sl@19
   141
sl@0
   142
		public InputDevice Device
sl@0
   143
		{
sl@0
   144
			get { return _device;  }
sl@0
   145
			set { _device = value; }
sl@0
   146
		}
sl@0
   147
	}
sl@0
   148
sl@0
   149
	#endregion RemoteControlEventArgs
sl@0
   150
sl@0
   151
sl@0
   152
	public sealed class RemoteControlDevice
sl@0
   153
	{
sl@19
   154
		public delegate bool RemoteControlDeviceEventHandler(object sender, RemoteControlEventArgs e);
sl@0
   155
		public event RemoteControlDeviceEventHandler ButtonPressed;
sl@0
   156
sl@19
   157
        /// <summary>
sl@19
   158
        /// Return true if the usage was processed.
sl@19
   159
        /// </summary>
sl@19
   160
        /// <param name="aUsage"></param>
sl@19
   161
        /// <returns></returns>
sl@19
   162
        public delegate bool HidUsageHandler(ushort aUsage);
sl@12
   163
        
sl@12
   164
sl@0
   165
		//-------------------------------------------------------------
sl@0
   166
		// constructors
sl@0
   167
		//-------------------------------------------------------------
sl@0
   168
sl@15
   169
		public RemoteControlDevice(IntPtr aHWND)
sl@0
   170
		{
sl@0
   171
			// Register the input device to receive the commands from the
sl@0
   172
			// remote device. See http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnwmt/html/remote_control.asp
sl@0
   173
			// for the vendor defined usage page.
sl@0
   174
sl@0
   175
			RAWINPUTDEVICE[] rid = new RAWINPUTDEVICE[3];
sl@0
   176
sl@0
   177
			rid[0].usUsagePage = 0xFFBC;
sl@0
   178
			rid[0].usUsage = 0x88;
sl@15
   179
            rid[0].dwFlags = Const.RIDEV_EXINPUTSINK;
sl@15
   180
            rid[0].hwndTarget = aHWND;
sl@0
   181
sl@0
   182
			rid[1].usUsagePage = 0x0C;
sl@0
   183
			rid[1].usUsage = 0x01;
sl@15
   184
            rid[1].dwFlags = Const.RIDEV_EXINPUTSINK;
sl@15
   185
            rid[1].hwndTarget = aHWND;
sl@0
   186
sl@0
   187
			rid[2].usUsagePage = 0x0C;
sl@0
   188
			rid[2].usUsage = 0x80;
sl@15
   189
            rid[2].dwFlags = Const.RIDEV_EXINPUTSINK;
sl@15
   190
            rid[2].hwndTarget = aHWND;
sl@0
   191
sl@15
   192
			if (!Function.RegisterRawInputDevices(rid,(uint) rid.Length,(uint) Marshal.SizeOf(rid[0])))
sl@0
   193
			{
sl@15
   194
                throw new ApplicationException("Failed to register raw input devices: " + Marshal.GetLastWin32Error().ToString());
sl@0
   195
			}
sl@0
   196
		}
sl@0
   197
sl@0
   198
sl@0
   199
		//-------------------------------------------------------------
sl@0
   200
		// methods
sl@0
   201
		//-------------------------------------------------------------
sl@0
   202
sl@0
   203
		public void ProcessMessage(Message message)
sl@0
   204
		{
sl@0
   205
			switch (message.Msg)
sl@0
   206
			{
sl@15
   207
				case Const.WM_KEYDOWN:
sl@15
   208
                    ProcessKeyDown(message.WParam);
sl@0
   209
					break;
sl@15
   210
                case Const.WM_APPCOMMAND:
sl@19
   211
					//ProcessAppCommand(message.LParam);
sl@0
   212
					break;
sl@15
   213
                case Const.WM_INPUT:
sl@19
   214
                    //Returning zero means we processed that message.
sl@19
   215
                    message.Result = new IntPtr(0);
sl@0
   216
					ProcessInputCommand(ref message);
sl@0
   217
					break;
sl@0
   218
			}
sl@0
   219
sl@0
   220
		}
sl@0
   221
sl@0
   222
sl@0
   223
		//-------------------------------------------------------------
sl@0
   224
		// methods (helpers)
sl@0
   225
		//-------------------------------------------------------------
sl@0
   226
sl@15
   227
		private void ProcessKeyDown(IntPtr wParam)
sl@0
   228
		{
sl@0
   229
			RemoteControlButton rcb = RemoteControlButton.Unknown;
sl@0
   230
sl@15
   231
            switch (wParam.ToInt32())
sl@0
   232
			{
sl@0
   233
				case (int) Keys.Escape:
sl@0
   234
					rcb = RemoteControlButton.Clear;
sl@0
   235
					break;
sl@0
   236
				case (int) Keys.Down:
sl@0
   237
					rcb = RemoteControlButton.Down;
sl@0
   238
					break;
sl@0
   239
				case (int) Keys.Left:
sl@0
   240
					rcb = RemoteControlButton.Left;
sl@0
   241
					break;
sl@0
   242
				case (int) Keys.D0:
sl@0
   243
					rcb = RemoteControlButton.Digit0;
sl@0
   244
					break;
sl@0
   245
				case (int) Keys.D1:
sl@0
   246
					rcb = RemoteControlButton.Digit1;
sl@0
   247
					break;
sl@0
   248
				case (int) Keys.D2:
sl@0
   249
					rcb = RemoteControlButton.Digit2;
sl@0
   250
					break;
sl@0
   251
				case (int) Keys.D3:
sl@0
   252
					rcb = RemoteControlButton.Digit3;
sl@0
   253
					break;
sl@0
   254
				case (int) Keys.D4:
sl@0
   255
					rcb = RemoteControlButton.Digit4;
sl@0
   256
					break;
sl@0
   257
				case (int) Keys.D5:
sl@0
   258
					rcb = RemoteControlButton.Digit5;
sl@0
   259
					break;
sl@0
   260
				case (int) Keys.D6:
sl@0
   261
					rcb = RemoteControlButton.Digit6;
sl@0
   262
					break;
sl@0
   263
				case (int) Keys.D7:
sl@0
   264
					rcb = RemoteControlButton.Digit7;
sl@0
   265
					break;
sl@0
   266
				case (int) Keys.D8:
sl@0
   267
					rcb = RemoteControlButton.Digit8;
sl@0
   268
					break;
sl@0
   269
				case (int) Keys.D9:
sl@0
   270
					rcb = RemoteControlButton.Digit9;
sl@0
   271
					break;
sl@0
   272
				case (int) Keys.Enter:
sl@0
   273
					rcb = RemoteControlButton.Enter;
sl@0
   274
					break;
sl@0
   275
				case (int) Keys.Right:
sl@0
   276
					rcb = RemoteControlButton.Right;
sl@0
   277
					break;
sl@0
   278
				case (int) Keys.Up:
sl@0
   279
					rcb = RemoteControlButton.Up;
sl@0
   280
					break;
sl@0
   281
			}
sl@0
   282
sl@0
   283
			if (this.ButtonPressed != null && rcb != RemoteControlButton.Unknown)
sl@15
   284
				this.ButtonPressed(this, new RemoteControlEventArgs(rcb, GetDevice(wParam)));
sl@0
   285
		}
sl@0
   286
sl@0
   287
sl@15
   288
		private void ProcessAppCommand(IntPtr lParam)
sl@0
   289
		{
sl@0
   290
			RemoteControlButton rcb = RemoteControlButton.Unknown;
sl@0
   291
sl@15
   292
            int cmd = Macro.GET_APPCOMMAND_LPARAM(lParam);
sl@15
   293
                //(int) (((ushort) (param >> 16)) & ~Const.FAPPCOMMAND_MASK);
sl@0
   294
sl@0
   295
			switch (cmd)
sl@0
   296
			{
sl@15
   297
                case Const.APPCOMMAND_BROWSER_BACKWARD:
sl@0
   298
					rcb = RemoteControlButton.Back;
sl@0
   299
					break;
sl@15
   300
                case Const.APPCOMMAND_MEDIA_CHANNEL_DOWN:
sl@0
   301
					rcb = RemoteControlButton.ChannelDown;
sl@0
   302
					break;
sl@15
   303
                case Const.APPCOMMAND_MEDIA_CHANNEL_UP:
sl@0
   304
					rcb = RemoteControlButton.ChannelUp;
sl@0
   305
					break;
sl@15
   306
                case Const.APPCOMMAND_MEDIA_FAST_FORWARD:
sl@0
   307
					rcb = RemoteControlButton.FastForward;
sl@0
   308
					break;
sl@15
   309
                case Const.APPCOMMAND_VOLUME_MUTE:
sl@0
   310
					rcb = RemoteControlButton.VolumeMute;
sl@0
   311
					break;
sl@15
   312
                case Const.APPCOMMAND_MEDIA_PAUSE:
sl@0
   313
					rcb = RemoteControlButton.Pause;
sl@0
   314
					break;
sl@15
   315
                case Const.APPCOMMAND_MEDIA_PLAY:
sl@0
   316
					rcb = RemoteControlButton.Play;
sl@0
   317
					break;
sl@15
   318
                case Const.APPCOMMAND_MEDIA_PLAY_PAUSE:
sl@0
   319
                    rcb = RemoteControlButton.PlayPause;
sl@0
   320
                    break;
sl@15
   321
                case Const.APPCOMMAND_MEDIA_RECORD:
sl@0
   322
					rcb = RemoteControlButton.Record;
sl@0
   323
					break;
sl@15
   324
                case Const.APPCOMMAND_MEDIA_PREVIOUSTRACK:
sl@0
   325
					rcb = RemoteControlButton.PreviousTrack;
sl@0
   326
					break;
sl@15
   327
                case Const.APPCOMMAND_MEDIA_REWIND:
sl@0
   328
					rcb = RemoteControlButton.Rewind;
sl@0
   329
					break;
sl@15
   330
                case Const.APPCOMMAND_MEDIA_NEXTTRACK:
sl@0
   331
					rcb = RemoteControlButton.NextTrack;
sl@0
   332
					break;
sl@15
   333
                case Const.APPCOMMAND_MEDIA_STOP:
sl@0
   334
					rcb = RemoteControlButton.Stop;
sl@0
   335
					break;
sl@15
   336
                case Const.APPCOMMAND_VOLUME_DOWN:
sl@0
   337
					rcb = RemoteControlButton.VolumeDown;
sl@0
   338
					break;
sl@15
   339
                case Const.APPCOMMAND_VOLUME_UP:
sl@0
   340
					rcb = RemoteControlButton.VolumeUp;
sl@0
   341
					break;
sl@0
   342
			}
sl@0
   343
sl@0
   344
			if (this.ButtonPressed != null && rcb != RemoteControlButton.Unknown)
sl@15
   345
                this.ButtonPressed(this, new RemoteControlEventArgs(rcb, GetDevice(lParam)));
sl@0
   346
		}
sl@0
   347
sl@12
   348
        /// <summary>
sl@12
   349
        /// 
sl@12
   350
        /// </summary>
sl@12
   351
        /// <param name="aUsage"></param>
sl@19
   352
        private bool HidConsumerDeviceHandler(ushort aUsage)
sl@12
   353
        {
sl@12
   354
            if (aUsage == 0)
sl@12
   355
            {
sl@12
   356
                //Just skip those
sl@19
   357
                return false;
sl@12
   358
            }
sl@12
   359
sl@12
   360
            if (Enum.IsDefined(typeof(ConsumerControl), aUsage) && aUsage != 0) //Our button is a known consumer control
sl@12
   361
            {
sl@12
   362
                if (this.ButtonPressed != null)
sl@12
   363
                {
sl@19
   364
                    return this.ButtonPressed(this, new RemoteControlEventArgs((ConsumerControl)aUsage, InputDevice.OEM));
sl@12
   365
                }
sl@19
   366
                return false;
sl@12
   367
            }
sl@12
   368
            else
sl@12
   369
            {
sl@12
   370
                Debug.WriteLine("Unknown Consumer Control!");
sl@19
   371
                return false;
sl@12
   372
            }
sl@12
   373
        }
sl@12
   374
sl@12
   375
        /// <summary>
sl@12
   376
        /// 
sl@12
   377
        /// </summary>
sl@12
   378
        /// <param name="aUsage"></param>
sl@19
   379
        private bool HidMceRemoteHandler(ushort aUsage)
sl@12
   380
        {
sl@12
   381
            if (aUsage == 0)
sl@12
   382
            {
sl@12
   383
                //Just skip those
sl@19
   384
                return false;
sl@12
   385
            }
sl@12
   386
sl@12
   387
sl@12
   388
            if (Enum.IsDefined(typeof(MceButton), aUsage) && aUsage != 0) //Our button is a known MCE button
sl@12
   389
            {
sl@12
   390
                if (this.ButtonPressed != null)
sl@12
   391
                {
sl@19
   392
                    return this.ButtonPressed(this, new RemoteControlEventArgs((MceButton)aUsage, InputDevice.OEM));                    
sl@12
   393
                }
sl@19
   394
                return false;
sl@12
   395
            }
sl@12
   396
            else
sl@12
   397
            {
sl@12
   398
                Debug.WriteLine("Unknown MCE button!");
sl@19
   399
                return false;
sl@12
   400
            }
sl@12
   401
        }
sl@12
   402
sl@0
   403
sl@0
   404
		private void ProcessInputCommand(ref Message message)
sl@0
   405
		{
sl@15
   406
            //We received a WM_INPUT message
sl@7
   407
            Debug.WriteLine("================WM_INPUT================");
sl@6
   408
sl@15
   409
            //Check if we received this message while in background or foreground
sl@15
   410
            if (Macro.GET_RAWINPUT_CODE_WPARAM(message.WParam) == Const.RIM_INPUT)
sl@15
   411
            {
sl@15
   412
                Debug.WriteLine("================FOREGROUND");
sl@15
   413
            }
sl@15
   414
            else if (Macro.GET_RAWINPUT_CODE_WPARAM(message.WParam) == Const.RIM_INPUTSINK)
sl@15
   415
            {
sl@15
   416
                Debug.WriteLine("================BACKGROUND");
sl@15
   417
            }
sl@0
   418
sl@17
   419
            //Declare some pointers
sl@10
   420
            IntPtr rawInputBuffer = IntPtr.Zero;
sl@17
   421
            //My understanding is that this is basically our HID descriptor
sl@17
   422
            IntPtr preParsedData = IntPtr.Zero;
sl@0
   423
sl@10
   424
            try
sl@10
   425
            {
sl@10
   426
                //Fetch raw input
sl@11
   427
                RAWINPUT rawInput = new RAWINPUT();
sl@11
   428
                if (!RawInput.GetRawInputData(message.LParam, ref rawInput, ref rawInputBuffer))
sl@6
   429
                {
sl@6
   430
                    return;
sl@6
   431
                }
sl@6
   432
sl@10
   433
                //Fetch device info
sl@10
   434
                RID_DEVICE_INFO deviceInfo = new RID_DEVICE_INFO();
sl@11
   435
                if (!RawInput.GetDeviceInfo(rawInput.header.hDevice, ref deviceInfo))
sl@10
   436
                {
sl@10
   437
                    return;
sl@10
   438
                }
sl@11
   439
               
sl@6
   440
sl@11
   441
                if (rawInput.header.dwType == Const.RIM_TYPEHID)  //Check that our raw input is HID                        
sl@6
   442
                {
sl@11
   443
                    Debug.WriteLine("WM_INPUT source device is HID.");
sl@11
   444
                    //Get Usage Page and Usage
sl@13
   445
                    Debug.WriteLine("Usage Page: 0x" + deviceInfo.hid.usUsagePage.ToString("X4") + " Usage ID: 0x" + deviceInfo.hid.usUsage.ToString("X4"));
sl@10
   446
sl@17
   447
sl@17
   448
                    preParsedData = RawInput.GetPreParsedData(rawInput.header.hDevice);
sl@17
   449
sl@12
   450
                    //
sl@13
   451
                    HidUsageHandler usagePageHandler=null;
sl@12
   452
sl@14
   453
                    //Check if this an MCE remote HID message
sl@14
   454
                    if (deviceInfo.hid.usUsagePage == (ushort)Hid.UsagePage.MceRemote && deviceInfo.hid.usUsage == (ushort)Hid.UsageId.MceRemoteUsage)
sl@12
   455
                    {                        
sl@13
   456
                        usagePageHandler = HidMceRemoteHandler;
sl@12
   457
                    }
sl@14
   458
                    //Check if this is a consumer control HID message
sl@14
   459
                    else if (deviceInfo.hid.usUsagePage == (ushort)Hid.UsagePage.Consumer && deviceInfo.hid.usUsage == (ushort)Hid.UsageId.ConsumerControl)
sl@12
   460
                    {
sl@13
   461
                        usagePageHandler = HidConsumerDeviceHandler;
sl@12
   462
                    }
sl@14
   463
                    //Unknown HID message
sl@12
   464
                    else
sl@6
   465
                    {
sl@14
   466
                        Debug.WriteLine("Unknown HID message.");
sl@6
   467
                        return;
sl@6
   468
                    }
sl@0
   469
sl@11
   470
                    if (!(rawInput.hid.dwSizeHid > 1     //Make sure our HID msg size more than 1. In fact the first ushort is irrelevant to us for now
sl@11
   471
                        && rawInput.hid.dwCount > 0))    //Check that we have at least one HID msg
sl@3
   472
                    {
sl@11
   473
                        return;
sl@11
   474
                    }
sl@11
   475
sl@11
   476
sl@11
   477
                    //Allocate a buffer for one HID input
sl@17
   478
                    byte[] hidInputReport = new byte[rawInput.hid.dwSizeHid];
sl@11
   479
sl@18
   480
                    Debug.WriteLine("Raw input contains " + rawInput.hid.dwCount + " HID input report(s)");
sl@18
   481
sl@18
   482
                    //For each HID input report in our raw input
sl@11
   483
                    for (int i = 0; i < rawInput.hid.dwCount; i++)
sl@11
   484
                    {
sl@11
   485
                        //Compute the address from which to copy our HID input
sl@11
   486
                        int hidInputOffset = 0;
sl@11
   487
                        unsafe
sl@3
   488
                        {
sl@11
   489
                            byte* source = (byte*)rawInputBuffer;
sl@11
   490
                            source += sizeof(RAWINPUTHEADER) + sizeof(RAWHID) + (rawInput.hid.dwSizeHid * i);
sl@11
   491
                            hidInputOffset = (int)source;
sl@11
   492
                        }
sl@11
   493
sl@11
   494
                        //Copy HID input into our buffer
sl@17
   495
                        Marshal.Copy(new IntPtr(hidInputOffset), hidInputReport, 0, (int)rawInput.hid.dwSizeHid);
sl@11
   496
sl@18
   497
                        //Print HID input report in our debug output
sl@18
   498
                        string hidDump = "HID input report: ";
sl@17
   499
                        foreach (byte b in hidInputReport)
sl@11
   500
                        {
sl@11
   501
                            hidDump += b.ToString("X2");
sl@11
   502
                        }
sl@11
   503
                        Debug.WriteLine(hidDump);
sl@11
   504
                        
sl@17
   505
                        //Proper parsing now
sl@18
   506
                        uint usageCount = 1; //Assuming a single usage per input report. Is that correct?
sl@17
   507
                        Win32.USAGE_AND_PAGE[] usages = new Win32.USAGE_AND_PAGE[usageCount];
sl@17
   508
                        Win32.HidStatus status = Win32.Function.HidP_GetUsagesEx(Win32.HIDP_REPORT_TYPE.HidP_Input, 0, usages, ref usageCount, preParsedData, hidInputReport, (uint)hidInputReport.Length);
sl@17
   509
                        if (status != Win32.HidStatus.HIDP_STATUS_SUCCESS)
sl@17
   510
                        {
sl@17
   511
                            Debug.WriteLine("Could not parse HID data!");
sl@17
   512
                        }
sl@17
   513
                        else
sl@17
   514
                        {
sl@17
   515
                            Debug.WriteLine("UsagePage: 0x" + usages[0].UsagePage.ToString("X4"));
sl@17
   516
                            Debug.WriteLine("Usage: 0x" + usages[0].Usage.ToString("X4"));
sl@18
   517
                            //Call on our Usage Page handler
sl@18
   518
                            usagePageHandler(usages[0].Usage);
sl@17
   519
                        }
sl@3
   520
                    }
sl@11
   521
sl@10
   522
                }
sl@11
   523
                else if (rawInput.header.dwType == Const.RIM_TYPEMOUSE)
sl@10
   524
                {
sl@11
   525
                    Debug.WriteLine("WM_INPUT source device is Mouse.");
sl@10
   526
                    // do mouse handling...
sl@10
   527
                }
sl@11
   528
                else if (rawInput.header.dwType == Const.RIM_TYPEKEYBOARD)
sl@10
   529
                {
sl@11
   530
                    Debug.WriteLine("WM_INPUT source device is Keyboard.");
sl@10
   531
                    // do keyboard handling...
sl@11
   532
sl@10
   533
                }
sl@10
   534
            }
sl@10
   535
            finally
sl@10
   536
            {
sl@10
   537
                //Always executed when leaving our try block
sl@10
   538
                Marshal.FreeHGlobal(rawInputBuffer);
sl@17
   539
                Marshal.FreeHGlobal(preParsedData);
sl@10
   540
            }
sl@0
   541
		}
sl@0
   542
sl@0
   543
sl@15
   544
		private InputDevice GetDevice(IntPtr lParam)
sl@0
   545
		{
sl@0
   546
			InputDevice inputDevice;
sl@0
   547
sl@15
   548
            switch (Macro.GET_DEVICE_LPARAM(lParam))
sl@0
   549
			{
sl@15
   550
				case Const.FAPPCOMMAND_OEM:
sl@0
   551
					inputDevice = InputDevice.OEM;
sl@0
   552
					break;
sl@15
   553
				case Const.FAPPCOMMAND_MOUSE:
sl@0
   554
					inputDevice = InputDevice.Mouse;
sl@0
   555
					break;
sl@0
   556
				default:
sl@0
   557
					inputDevice = InputDevice.Key;
sl@0
   558
					break;
sl@0
   559
			}
sl@0
   560
sl@0
   561
			return inputDevice;
sl@0
   562
		}
sl@0
   563
	}
sl@0
   564
}