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