RemoteControlDevice.cs
author sl
Wed, 05 Nov 2014 19:39:59 +0100
changeset 6 fa97ff5ceb7b
parent 5 b2ed6fc37d95
child 7 5ecebf1bd397
permissions -rw-r--r--
Now checking HID usage page and usage.
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@0
     5
sl@0
     6
sl@6
     7
namespace Devices.RemoteControl
sl@0
     8
{
sl@6
     9
sl@6
    10
    public static class Hid
sl@6
    11
    {
sl@6
    12
        /// <summary>
sl@6
    13
        /// From USB HID usage tables.
sl@6
    14
        /// http://www.usb.org/developers/hidpage#HID_Usage
sl@6
    15
        /// http://www.usb.org/developers/devclass_docs/Hut1_12v2.pdf
sl@6
    16
        /// </summary>
sl@6
    17
        public enum UsagePage : ushort
sl@6
    18
        {
sl@6
    19
            Undefined = 0,
sl@6
    20
            GenericDesktopControl,
sl@6
    21
            SimulationControl,
sl@6
    22
            VirtualRealityControl,
sl@6
    23
            SportControl,
sl@6
    24
            GameControl,
sl@6
    25
            GenericDeviceControl,
sl@6
    26
            Keyboard,
sl@6
    27
            LightEmittingDiode,
sl@6
    28
            Button,
sl@6
    29
            Ordinal,
sl@6
    30
            Telephony,
sl@6
    31
            Consumer,
sl@6
    32
            Digitiser,
sl@6
    33
            PhysicalInterfaceDevice = 0x0f,
sl@6
    34
            Unicode = 0x10,
sl@6
    35
            AlphaNumericDisplay = 0x14,
sl@6
    36
            MedicalInstruments = 0x40,
sl@6
    37
            MonitorPage0 = 0x80,
sl@6
    38
            MonitorPage1,
sl@6
    39
            MonitorPage2,
sl@6
    40
            MonitorPage3,
sl@6
    41
            PowerPage0,
sl@6
    42
            PowerPage1,
sl@6
    43
            PowerPage2,
sl@6
    44
            PowerPage3,
sl@6
    45
            BarCodeScanner = 0x8c,
sl@6
    46
            Scale,
sl@6
    47
            MagneticStripeReader,
sl@6
    48
            ReservedPointOfSale,
sl@6
    49
            CameraControl,
sl@6
    50
            Arcade,
sl@6
    51
            // http://msdn.microsoft.com/en-us/library/windows/desktop/bb417079.aspx
sl@6
    52
            MceRemote = 0xffbc,
sl@6
    53
            TerraTecRemote = 0xffcc
sl@6
    54
        }
sl@6
    55
sl@6
    56
        public const ushort MceRemoteUsage = 0x88;
sl@6
    57
    }
sl@6
    58
sl@6
    59
sl@0
    60
	public enum InputDevice
sl@0
    61
	{
sl@0
    62
		Key,
sl@0
    63
		Mouse,
sl@0
    64
		OEM
sl@0
    65
	}
sl@0
    66
sl@0
    67
sl@0
    68
	public enum RemoteControlButton
sl@0
    69
	{
sl@0
    70
		Clear,
sl@0
    71
		Down,
sl@0
    72
		Left,
sl@0
    73
		Digit0,
sl@0
    74
		Digit1,
sl@0
    75
		Digit2,
sl@0
    76
		Digit3,
sl@0
    77
		Digit4,
sl@0
    78
		Digit5,
sl@0
    79
		Digit6,
sl@0
    80
		Digit7,
sl@0
    81
		Digit8,
sl@0
    82
		Digit9,
sl@0
    83
		Enter,
sl@0
    84
		Right,
sl@0
    85
		Up,
sl@0
    86
sl@0
    87
		Back,
sl@0
    88
		ChannelDown,
sl@0
    89
		ChannelUp,
sl@0
    90
		FastForward,
sl@0
    91
		VolumeMute,
sl@0
    92
		Pause,
sl@0
    93
		Play,
sl@0
    94
        PlayPause,
sl@0
    95
		Record,
sl@0
    96
		PreviousTrack,
sl@0
    97
		Rewind,
sl@0
    98
		NextTrack,
sl@0
    99
		Stop,
sl@0
   100
		VolumeDown,
sl@0
   101
		VolumeUp,
sl@0
   102
sl@0
   103
		RecordedTV,
sl@0
   104
		Guide,
sl@0
   105
		LiveTV,
sl@0
   106
		Details,
sl@0
   107
		DVDMenu,
sl@0
   108
		DVDAngle,
sl@0
   109
		DVDAudio,
sl@0
   110
		DVDSubtitle,
sl@0
   111
		MyMusic,
sl@0
   112
		MyPictures,
sl@0
   113
		MyVideos,
sl@0
   114
		MyTV,
sl@0
   115
		OEM1,
sl@0
   116
		OEM2,
sl@0
   117
		StandBy,
sl@0
   118
		TVJump,
sl@0
   119
sl@0
   120
		Unknown
sl@0
   121
	}
sl@0
   122
sl@3
   123
    /// <summary>
sl@6
   124
    ///
sl@3
   125
    /// </summary>
sl@3
   126
    public enum MceButton
sl@3
   127
    {
sl@5
   128
        /// <summary>
sl@5
   129
        /// Not defined by the Microsoft specs.
sl@5
   130
        /// </summary>
sl@6
   131
        Null                    =   0x00,
sl@3
   132
        GreenStart              =   0x0D,
sl@3
   133
        ClosedCaptioning        =   0x2B,
sl@3
   134
        Teletext                =   0x5A,
sl@3
   135
        TeletextRed             =   0x5B,
sl@3
   136
        TeletextGreen           =   0x5C,
sl@3
   137
        TeletextYellow          =   0x5D,
sl@3
   138
        TeletextBlue            =   0x5E,
sl@3
   139
        LiveTv                  =   0x25,
sl@3
   140
        Music                   =   0x47,
sl@3
   141
        RecordedTv              =   0x48,
sl@3
   142
        Pictures                =   0x49,
sl@3
   143
        Videos                  =   0x4A,
sl@3
   144
        FmRadio                 =   0x50,
sl@3
   145
        Extras                  =   0x3C,
sl@3
   146
        ExtrasApp               =   0x3D,
sl@3
   147
        DvdMenu                 =   0x24,
sl@3
   148
        DvdAngle                =   0x4B,
sl@3
   149
        DvdAudio                =   0x4C,
sl@3
   150
        DvdSubtitle             =   0x4D,
sl@5
   151
        /// <summary>
sl@5
   152
        /// First press action: Ejects a DVD drive.
sl@5
   153
        /// <para />
sl@5
   154
        /// Second press action: Repeats first press action.
sl@5
   155
        /// <para />
sl@5
   156
        /// Notably issued by XBOX360 remote as defined in irplus - Remote Control - Android application.
sl@5
   157
        /// </summary>
sl@3
   158
        Eject                   =   0x28,
sl@3
   159
        DvdTopMenu              =   0x43,
sl@5
   160
        /// <summary>
sl@5
   161
        /// First press action: Generates EXTn HID message in the Media Center Vendor Specific
sl@5
   162
        /// Collection (page 0xFFBC, usage 0x88).
sl@5
   163
        /// <para />
sl@5
   164
        /// Second press action: Repeats message.
sl@5
   165
        /// <para />
sl@5
   166
        /// Auto-repeat: No
sl@5
   167
        /// <para />
sl@5
   168
        /// Notably sent by the 'Visualization' button of HP Windows Media Center Remote (TSGH-IR08).
sl@5
   169
        /// <para />
sl@5
   170
        /// According to HP specs it displays visual imagery that is synchronized to the sound of your music tracks.
sl@5
   171
        /// </summary>
sl@3
   172
        Ext0                    =   0x32,
sl@5
   173
        /// <summary>
sl@5
   174
        /// First press action: Generates EXTn HID message in the Media Center Vendor Specific
sl@5
   175
        /// Collection (page 0xFFBC, usage 0x88).
sl@5
   176
        /// <para />
sl@5
   177
        /// Second press action: Repeats message.
sl@5
   178
        /// <para />
sl@5
   179
        /// Auto-repeat: No
sl@5
   180
        /// <para />
sl@5
   181
        /// Notably sent by the 'Slide Show' button of HP Windows Media Center Remote (TSGH-IR08).
sl@5
   182
        /// <para />
sl@5
   183
        /// According to HP specs it plays a slide show of all the pictures on your hard disk drive.
sl@5
   184
        /// </summary>
sl@3
   185
        Ext1                    =   0x33,
sl@5
   186
        /// <summary>
sl@5
   187
        /// First press action: Generates EXTn HID message in the Media Center Vendor Specific
sl@5
   188
        /// Collection (page 0xFFBC, usage 0x88).
sl@5
   189
        /// <para />
sl@5
   190
        /// Second press action: Repeats message.
sl@5
   191
        /// <para />
sl@5
   192
        /// Auto-repeat: No
sl@5
   193
        /// <para />
sl@5
   194
        /// Notably sent by the 'Eject' button of HP Windows Media Center Remote (TSGH-IR08).
sl@5
   195
        /// Also interpreted as 'Eject' action by SoundGraph iMON Manager in MCE mode (OrigenAE VF310).
sl@5
   196
        /// </summary>
sl@3
   197
        Ext2                    =   0x34,
sl@5
   198
        /// <summary>
sl@5
   199
        /// First press action: Generates EXTn HID message in the Media Center Vendor Specific
sl@5
   200
        /// Collection (page 0xFFBC, usage 0x88).
sl@5
   201
        /// <para />
sl@5
   202
        /// Second press action: Repeats message.
sl@5
   203
        /// <para />
sl@5
   204
        /// Auto-repeat: No
sl@5
   205
        /// <para />
sl@5
   206
        /// Notably sent by the 'Input selection' button of HP Windows Media Center Remote (TSGH-IR08).
sl@5
   207
        /// </summary>
sl@3
   208
        Ext3                    =   0x35,
sl@3
   209
        Ext4                    =   0x36,
sl@3
   210
        Ext5                    =   0x37,
sl@3
   211
        Ext6                    =   0x38,
sl@3
   212
        Ext7                    =   0x39,
sl@3
   213
        Ext8                    =   0x3A,
sl@3
   214
        Ext9                    =   0x80,
sl@3
   215
        Ext10                   =   0x81,
sl@3
   216
        Ext11                   =   0x6F,
sl@3
   217
        Zoom                    =   0x27,
sl@3
   218
        ChannelInput            =   0x42,
sl@3
   219
        SubAudio                =   0x2D,
sl@3
   220
        Channel10               =   0x3E,
sl@3
   221
        Channel11               =   0x3F,
sl@3
   222
        Channel12               =   0x40,
sl@5
   223
        /// <summary>
sl@5
   224
        /// First press action: Generates OEM2 HID message in the Media Center Vendor Specific
sl@5
   225
        /// Collection. This button is intended to control the front panel display of home entertainment
sl@5
   226
        /// computers. When this button is pressed, the display could be turned on or off, or the display
sl@5
   227
        /// mode could change.
sl@5
   228
        /// <para />
sl@5
   229
        /// Second press action: Repeats message.
sl@5
   230
        /// <para />
sl@5
   231
        /// Auto-repeat: No
sl@5
   232
        /// <para />
sl@5
   233
        /// Notably issued by XBOX360 remote as defined in irplus - Remote Control - Android application.
sl@5
   234
        /// </summary>
sl@3
   235
        Display                 =   0x4F,
sl@5
   236
        /// <summary>
sl@5
   237
        /// First press action: To be determined.
sl@5
   238
        /// <para />
sl@5
   239
        /// Second press action: Repeats message.
sl@5
   240
        /// <para />
sl@5
   241
        /// Auto-repeat: No
sl@5
   242
        /// </summary>
sl@3
   243
        Kiosk                   =   0x6A,
sl@3
   244
        NetworkSelection        =   0x2C,
sl@3
   245
        BlueRayTool             =   0x78,
sl@3
   246
        ChannelInfo             =   0x41,
sl@6
   247
        VideoSelection          =   0x61
sl@3
   248
    }
sl@3
   249
sl@5
   250
    public enum HpMceButton
sl@5
   251
    {
sl@5
   252
        /// <summary>
sl@5
   253
        /// Displays visual imagery that is synchronized to the sound of your music tracks.
sl@5
   254
        /// <para />
sl@5
   255
        /// Second press action: Repeats message.
sl@5
   256
        /// <para />
sl@5
   257
        /// Auto-repeat: No
sl@5
   258
        /// <para />
sl@5
   259
        /// Notably sent by the 'Visualization' button of HP Windows Media Center Remote (TSGH-IR08).
sl@5
   260
        /// <para />
sl@5
   261
        /// According to HP specs it displays visual imagery that is synchronized to the sound of your music tracks.
sl@5
   262
        /// </summary>
sl@5
   263
        Visualization = MceButton.Ext0,
sl@5
   264
        /// <summary>
sl@5
   265
        /// Plays a slide show of all the pictures on your hard disk drive.
sl@5
   266
        /// <para />
sl@5
   267
        /// Second press action: Repeats message.
sl@5
   268
        /// <para />
sl@5
   269
        /// Auto-repeat: No
sl@5
   270
        /// <para />
sl@5
   271
        /// Notably sent by the 'Slide Show' button of HP Windows Media Center Remote (TSGH-IR08).
sl@5
   272
        /// <para />
sl@5
   273
        /// According to HP specs it plays a slide show of all the pictures on your hard disk drive.
sl@5
   274
        /// </summary>
sl@5
   275
        SlideShow = MceButton.Ext1,
sl@5
   276
        /// <summary>
sl@5
   277
        /// Eject optical drive.
sl@5
   278
        /// <para />
sl@5
   279
        /// Second press action: Repeats message.
sl@5
   280
        /// <para />
sl@5
   281
        /// Auto-repeat: No
sl@5
   282
        /// <para />
sl@5
   283
        /// Notably sent by the 'Eject' button of HP Windows Media Center Remote (TSGH-IR08).
sl@5
   284
        /// Also interpreted as 'Eject' action by SoundGraph iMON Manager in MCE mode (OrigenAE VF310).
sl@5
   285
        /// </summary>
sl@5
   286
        Eject = MceButton.Ext2,
sl@5
   287
        /// <summary>
sl@5
   288
        /// Not sure what this should do.
sl@5
   289
        /// <para />
sl@5
   290
        /// Second press action: Repeats message.
sl@5
   291
        /// <para />
sl@5
   292
        /// Auto-repeat: No
sl@5
   293
        /// <para />
sl@5
   294
        /// Notably sent by the 'Input selection' button of HP Windows Media Center Remote (TSGH-IR08).
sl@5
   295
        /// </summary>
sl@5
   296
        InputSelection = MceButton.Ext3,
sl@5
   297
    }
sl@5
   298
sl@5
   299
sl@0
   300
sl@0
   301
	#region RemoteControlEventArgs
sl@0
   302
sl@0
   303
	public class RemoteControlEventArgs : EventArgs
sl@0
   304
	{
sl@3
   305
        RemoteControlButton _rcb;
sl@0
   306
		InputDevice _device;
sl@3
   307
        MceButton iMceButton;
sl@0
   308
sl@3
   309
        public RemoteControlEventArgs(RemoteControlButton rcb, InputDevice device)
sl@0
   310
		{
sl@3
   311
            iMceButton = MceButton.Null;
sl@0
   312
			_rcb = rcb;
sl@0
   313
			_device = device;
sl@0
   314
		}
sl@0
   315
sl@3
   316
        public RemoteControlEventArgs(MceButton mce, InputDevice device)
sl@3
   317
        {
sl@3
   318
            iMceButton = mce;
sl@3
   319
            _rcb = RemoteControlButton.Unknown;
sl@3
   320
            _device = device;
sl@3
   321
        }
sl@0
   322
sl@0
   323
		public RemoteControlEventArgs()
sl@0
   324
		{
sl@3
   325
            iMceButton = MceButton.Null;
sl@0
   326
			_rcb = RemoteControlButton.Unknown;
sl@0
   327
			_device = InputDevice.Key;
sl@0
   328
		}
sl@0
   329
sl@0
   330
		public RemoteControlButton Button
sl@0
   331
		{
sl@0
   332
			get { return _rcb;  }
sl@0
   333
			set { _rcb = value; }
sl@0
   334
		}
sl@0
   335
sl@3
   336
        public MceButton MceButton
sl@3
   337
        {
sl@3
   338
            get { return iMceButton; }
sl@3
   339
            set { iMceButton = value; }
sl@3
   340
        }
sl@3
   341
sl@0
   342
		public InputDevice Device
sl@0
   343
		{
sl@0
   344
			get { return _device;  }
sl@0
   345
			set { _device = value; }
sl@0
   346
		}
sl@0
   347
	}
sl@0
   348
sl@0
   349
	#endregion RemoteControlEventArgs
sl@0
   350
sl@0
   351
sl@0
   352
	public sealed class RemoteControlDevice
sl@0
   353
	{
sl@0
   354
sl@0
   355
        [StructLayout(LayoutKind.Sequential, Pack = 1)]
sl@0
   356
		internal struct RAWINPUTDEVICE
sl@0
   357
		{
sl@0
   358
			[MarshalAs(UnmanagedType.U2)]
sl@0
   359
			public ushort usUsagePage;
sl@0
   360
			[MarshalAs(UnmanagedType.U2)]
sl@0
   361
			public ushort usUsage;
sl@0
   362
			[MarshalAs(UnmanagedType.U4)]
sl@0
   363
			public int	 dwFlags;
sl@0
   364
			public IntPtr hwndTarget;
sl@0
   365
		}
sl@0
   366
sl@0
   367
sl@0
   368
        [StructLayout(LayoutKind.Sequential, Pack = 1)]
sl@0
   369
		internal struct RAWINPUTHEADER
sl@0
   370
		{
sl@0
   371
			[MarshalAs(UnmanagedType.U4)]
sl@0
   372
			public int dwType;
sl@0
   373
			[MarshalAs(UnmanagedType.U4)]
sl@0
   374
			public int dwSize;
sl@0
   375
            public IntPtr hDevice;
sl@0
   376
			[MarshalAs(UnmanagedType.U4)]
sl@0
   377
			public int wParam;
sl@0
   378
		}
sl@0
   379
sl@0
   380
sl@0
   381
        [StructLayout(LayoutKind.Sequential, Pack = 1)]
sl@0
   382
		internal struct RAWHID
sl@0
   383
		{
sl@0
   384
			[MarshalAs(UnmanagedType.U4)]
sl@0
   385
			public int dwSizeHid;
sl@0
   386
			[MarshalAs(UnmanagedType.U4)]
sl@0
   387
			public int dwCount;
sl@0
   388
            //
sl@0
   389
            //BYTE  bRawData[1];
sl@0
   390
		}
sl@0
   391
sl@0
   392
sl@0
   393
        [StructLayout(LayoutKind.Sequential, Pack = 1)]
sl@0
   394
		internal struct BUTTONSSTR
sl@0
   395
		{
sl@0
   396
			[MarshalAs(UnmanagedType.U2)]
sl@0
   397
			public ushort usButtonFlags;
sl@0
   398
			[MarshalAs(UnmanagedType.U2)]
sl@0
   399
			public ushort usButtonData;
sl@0
   400
		}
sl@0
   401
sl@0
   402
sl@0
   403
        [StructLayout(LayoutKind.Explicit, Pack = 1)]
sl@0
   404
		internal struct RAWMOUSE
sl@0
   405
		{
sl@0
   406
			[MarshalAs(UnmanagedType.U2)]
sl@0
   407
			[FieldOffset (0)] public ushort usFlags;
sl@0
   408
			[MarshalAs(UnmanagedType.U4)]
sl@0
   409
			[FieldOffset (4)] public uint ulButtons;
sl@0
   410
			[FieldOffset (4)] public BUTTONSSTR buttonsStr;
sl@0
   411
			[MarshalAs(UnmanagedType.U4)]
sl@0
   412
			[FieldOffset (8)] public uint ulRawButtons;
sl@0
   413
            [MarshalAs(UnmanagedType.U4)]
sl@0
   414
            [FieldOffset (12)] public int lLastX;
sl@0
   415
            [MarshalAs(UnmanagedType.U4)]
sl@0
   416
            [FieldOffset (16)] public int lLastY;
sl@0
   417
			[MarshalAs(UnmanagedType.U4)]
sl@0
   418
			[FieldOffset (20)] public uint ulExtraInformation;
sl@0
   419
		}
sl@0
   420
sl@0
   421
        [StructLayout(LayoutKind.Sequential, Pack = 1)]
sl@0
   422
		internal struct RAWKEYBOARD
sl@0
   423
		{
sl@0
   424
			[MarshalAs(UnmanagedType.U2)]
sl@0
   425
			public ushort MakeCode;
sl@0
   426
			[MarshalAs(UnmanagedType.U2)]
sl@0
   427
			public ushort Flags;
sl@0
   428
			[MarshalAs(UnmanagedType.U2)]
sl@0
   429
			public ushort Reserved;
sl@0
   430
			[MarshalAs(UnmanagedType.U2)]
sl@0
   431
			public ushort VKey;
sl@0
   432
			[MarshalAs(UnmanagedType.U4)]
sl@0
   433
			public uint Message;
sl@0
   434
			[MarshalAs(UnmanagedType.U4)]
sl@0
   435
			public uint ExtraInformation;
sl@0
   436
		}
sl@0
   437
sl@0
   438
sl@0
   439
		[StructLayout(LayoutKind.Explicit, Pack=1)]
sl@0
   440
		internal struct RAWINPUT
sl@0
   441
		{
sl@0
   442
			[FieldOffset  (0)] public RAWINPUTHEADER header;
sl@0
   443
			[FieldOffset (16)] public RAWMOUSE mouse;
sl@0
   444
			[FieldOffset (16)] public RAWKEYBOARD keyboard;
sl@0
   445
			[FieldOffset (16)] public RAWHID hid;
sl@0
   446
		}
sl@0
   447
sl@0
   448
sl@6
   449
        [StructLayout(LayoutKind.Sequential, Pack=1)]
sl@6
   450
        internal struct RID_DEVICE_INFO_MOUSE
sl@6
   451
		{
sl@6
   452
            public uint dwId;
sl@6
   453
            public uint dwNumberOfButtons;
sl@6
   454
            public uint dwSampleRate;
sl@6
   455
            public bool fHasHorizontalWheel;
sl@6
   456
		}
sl@6
   457
sl@6
   458
sl@6
   459
        [StructLayout(LayoutKind.Sequential, Pack=1)]
sl@6
   460
        internal struct RID_DEVICE_INFO_KEYBOARD
sl@6
   461
		{
sl@6
   462
            public uint dwType;
sl@6
   463
            public uint dwSubType;
sl@6
   464
            public uint dwKeyboardMode;
sl@6
   465
            public uint dwNumberOfFunctionKeys;
sl@6
   466
            public uint dwNumberOfIndicators;
sl@6
   467
            public uint dwNumberOfKeysTotal;
sl@6
   468
        }
sl@6
   469
sl@6
   470
        [StructLayout(LayoutKind.Sequential, Pack=1)]
sl@6
   471
        internal struct RID_DEVICE_INFO_HID
sl@6
   472
		{
sl@6
   473
            public uint dwVendorId;
sl@6
   474
            public uint dwProductId;
sl@6
   475
            public uint dwVersionNumber;
sl@6
   476
            public ushort usUsagePage;
sl@6
   477
            public ushort usUsage;
sl@6
   478
        }
sl@6
   479
sl@6
   480
        [StructLayout(LayoutKind.Explicit, Pack=1)]
sl@6
   481
        internal struct RID_DEVICE_INFO
sl@6
   482
		{
sl@6
   483
            [FieldOffset(0)]
sl@6
   484
            public uint cbSize;
sl@6
   485
            [FieldOffset(4)]
sl@6
   486
            public uint dwType;
sl@6
   487
            [FieldOffset(8)]
sl@6
   488
            public RID_DEVICE_INFO_MOUSE mouse;
sl@6
   489
            [FieldOffset(8)]
sl@6
   490
            public RID_DEVICE_INFO_KEYBOARD keyboard;
sl@6
   491
            [FieldOffset(8)]
sl@6
   492
            public RID_DEVICE_INFO_HID hid;
sl@6
   493
		}
sl@6
   494
sl@6
   495
sl@6
   496
sl@0
   497
		[DllImport("User32.dll")]
sl@0
   498
		extern static bool RegisterRawInputDevices(RAWINPUTDEVICE[] pRawInputDevice, uint uiNumDevices, uint cbSize);
sl@0
   499
sl@0
   500
		[DllImport("User32.dll")]
sl@0
   501
		extern static uint GetRawInputData(IntPtr hRawInput, uint uiCommand, IntPtr pData, ref uint pcbSize, uint cbSizeHeader);
sl@0
   502
sl@6
   503
   		[DllImport("User32.dll", SetLastError=true)]
sl@6
   504
		extern static int GetRawInputDeviceInfo(IntPtr hDevice, uint uiCommand, IntPtr pData, ref uint pcbSize);
sl@4
   505
sl@0
   506
sl@0
   507
		private const int WM_KEYDOWN	= 0x0100;
sl@0
   508
		private const int WM_APPCOMMAND	= 0x0319;
sl@0
   509
		private const int WM_INPUT		= 0x00FF;
sl@0
   510
sl@0
   511
		private const int APPCOMMAND_BROWSER_BACKWARD   = 1;
sl@0
   512
		private const int APPCOMMAND_VOLUME_MUTE        = 8;
sl@0
   513
		private const int APPCOMMAND_VOLUME_DOWN        = 9;
sl@0
   514
		private const int APPCOMMAND_VOLUME_UP          = 10;
sl@0
   515
		private const int APPCOMMAND_MEDIA_NEXTTRACK    = 11;
sl@0
   516
		private const int APPCOMMAND_MEDIA_PREVIOUSTRACK = 12;
sl@0
   517
		private const int APPCOMMAND_MEDIA_STOP         = 13;
sl@0
   518
		private const int APPCOMMAND_MEDIA_PLAY_PAUSE   = 14;
sl@0
   519
		private const int APPCOMMAND_MEDIA_PLAY         = 46;
sl@0
   520
		private const int APPCOMMAND_MEDIA_PAUSE        = 47;
sl@0
   521
		private const int APPCOMMAND_MEDIA_RECORD       = 48;
sl@0
   522
		private const int APPCOMMAND_MEDIA_FAST_FORWARD = 49;
sl@0
   523
		private const int APPCOMMAND_MEDIA_REWIND       = 50;
sl@0
   524
		private const int APPCOMMAND_MEDIA_CHANNEL_UP   = 51;
sl@0
   525
		private const int APPCOMMAND_MEDIA_CHANNEL_DOWN = 52;
sl@0
   526
sl@0
   527
		private const int RID_INPUT						= 0x10000003;
sl@0
   528
		private const int RID_HEADER					= 0x10000005;
sl@0
   529
sl@0
   530
		private const int FAPPCOMMAND_MASK				= 0xF000;
sl@0
   531
		private const int FAPPCOMMAND_MOUSE				= 0x8000;
sl@0
   532
		private const int FAPPCOMMAND_KEY				= 0;
sl@0
   533
		private const int FAPPCOMMAND_OEM				= 0x1000;
sl@0
   534
sl@6
   535
        /// <summary>
sl@6
   536
        /// GetRawInputDeviceInfo pData points to a string that contains the device name.
sl@6
   537
        /// </summary>
sl@6
   538
        public const uint RIDI_DEVICENAME = 0x20000007;
sl@6
   539
        /// <summary>
sl@6
   540
        /// GetRawInputDeviceInfo For this uiCommand only, the value in pcbSize is the character count (not the byte count).
sl@6
   541
        /// </summary>
sl@6
   542
        public const uint RIDI_DEVICEINFO = 0x2000000b;
sl@6
   543
        /// <summary>
sl@6
   544
        /// GetRawInputDeviceInfo pData points to an RID_DEVICE_INFO structure.
sl@6
   545
        /// </summary>
sl@6
   546
        public const uint RIDI_PREPARSEDDATA = 0x20000005;
sl@6
   547
sl@6
   548
sl@6
   549
        /// <summary>
sl@6
   550
        /// Data comes from a mouse.
sl@6
   551
        /// </summary>
sl@6
   552
        public const uint RIM_TYPEMOUSE = 0;
sl@6
   553
        /// <summary>
sl@6
   554
        /// Data comes from a keyboard.
sl@6
   555
        /// </summary>
sl@6
   556
        public const uint RIM_TYPEKEYBOARD = 1;
sl@6
   557
        /// <summary>
sl@6
   558
        /// Data comes from an HID that is not a keyboard or a mouse.
sl@6
   559
        /// </summary>
sl@6
   560
        public const uint RIM_TYPEHID = 2;
sl@6
   561
sl@6
   562
sl@6
   563
sl@6
   564
sl@6
   565
sl@0
   566
		public delegate void RemoteControlDeviceEventHandler(object sender, RemoteControlEventArgs e);
sl@0
   567
		public event RemoteControlDeviceEventHandler ButtonPressed;
sl@0
   568
sl@0
   569
sl@0
   570
		//-------------------------------------------------------------
sl@0
   571
		// constructors
sl@0
   572
		//-------------------------------------------------------------
sl@0
   573
sl@0
   574
		public RemoteControlDevice()
sl@0
   575
		{
sl@0
   576
			// Register the input device to receive the commands from the
sl@0
   577
			// remote device. See http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnwmt/html/remote_control.asp
sl@0
   578
			// for the vendor defined usage page.
sl@0
   579
sl@0
   580
			RAWINPUTDEVICE[] rid = new RAWINPUTDEVICE[3];
sl@0
   581
sl@0
   582
			rid[0].usUsagePage = 0xFFBC;
sl@0
   583
			rid[0].usUsage = 0x88;
sl@0
   584
			rid[0].dwFlags = 0;
sl@0
   585
sl@0
   586
			rid[1].usUsagePage = 0x0C;
sl@0
   587
			rid[1].usUsage = 0x01;
sl@0
   588
			rid[1].dwFlags = 0;
sl@0
   589
sl@0
   590
			rid[2].usUsagePage = 0x0C;
sl@0
   591
			rid[2].usUsage = 0x80;
sl@0
   592
			rid[2].dwFlags = 0;
sl@0
   593
sl@0
   594
			if (!RegisterRawInputDevices(rid,
sl@0
   595
				(uint) rid.Length,
sl@0
   596
				(uint) Marshal.SizeOf(rid[0]))
sl@0
   597
				)
sl@0
   598
			{
sl@0
   599
				throw new ApplicationException("Failed to register raw input devices.");
sl@0
   600
			}
sl@0
   601
		}
sl@0
   602
sl@0
   603
sl@0
   604
		//-------------------------------------------------------------
sl@0
   605
		// methods
sl@0
   606
		//-------------------------------------------------------------
sl@0
   607
sl@0
   608
		public void ProcessMessage(Message message)
sl@0
   609
		{
sl@0
   610
			int param;
sl@0
   611
sl@0
   612
			switch (message.Msg)
sl@0
   613
			{
sl@0
   614
				case WM_KEYDOWN:
sl@0
   615
					param = message.WParam.ToInt32();
sl@0
   616
					ProcessKeyDown(param);
sl@0
   617
					break;
sl@0
   618
				case WM_APPCOMMAND:
sl@0
   619
					param = message.LParam.ToInt32();
sl@0
   620
					ProcessAppCommand(param);
sl@0
   621
					break;
sl@0
   622
				case WM_INPUT:
sl@0
   623
					ProcessInputCommand(ref message);
sl@0
   624
                    message.Result = new IntPtr(0);
sl@0
   625
					break;
sl@0
   626
			}
sl@0
   627
sl@0
   628
		}
sl@0
   629
sl@0
   630
sl@0
   631
		//-------------------------------------------------------------
sl@0
   632
		// methods (helpers)
sl@0
   633
		//-------------------------------------------------------------
sl@0
   634
sl@0
   635
		private void ProcessKeyDown(int param)
sl@0
   636
		{
sl@0
   637
			RemoteControlButton rcb = RemoteControlButton.Unknown;
sl@0
   638
sl@0
   639
			switch (param)
sl@0
   640
			{
sl@0
   641
				case (int) Keys.Escape:
sl@0
   642
					rcb = RemoteControlButton.Clear;
sl@0
   643
					break;
sl@0
   644
				case (int) Keys.Down:
sl@0
   645
					rcb = RemoteControlButton.Down;
sl@0
   646
					break;
sl@0
   647
				case (int) Keys.Left:
sl@0
   648
					rcb = RemoteControlButton.Left;
sl@0
   649
					break;
sl@0
   650
				case (int) Keys.D0:
sl@0
   651
					rcb = RemoteControlButton.Digit0;
sl@0
   652
					break;
sl@0
   653
				case (int) Keys.D1:
sl@0
   654
					rcb = RemoteControlButton.Digit1;
sl@0
   655
					break;
sl@0
   656
				case (int) Keys.D2:
sl@0
   657
					rcb = RemoteControlButton.Digit2;
sl@0
   658
					break;
sl@0
   659
				case (int) Keys.D3:
sl@0
   660
					rcb = RemoteControlButton.Digit3;
sl@0
   661
					break;
sl@0
   662
				case (int) Keys.D4:
sl@0
   663
					rcb = RemoteControlButton.Digit4;
sl@0
   664
					break;
sl@0
   665
				case (int) Keys.D5:
sl@0
   666
					rcb = RemoteControlButton.Digit5;
sl@0
   667
					break;
sl@0
   668
				case (int) Keys.D6:
sl@0
   669
					rcb = RemoteControlButton.Digit6;
sl@0
   670
					break;
sl@0
   671
				case (int) Keys.D7:
sl@0
   672
					rcb = RemoteControlButton.Digit7;
sl@0
   673
					break;
sl@0
   674
				case (int) Keys.D8:
sl@0
   675
					rcb = RemoteControlButton.Digit8;
sl@0
   676
					break;
sl@0
   677
				case (int) Keys.D9:
sl@0
   678
					rcb = RemoteControlButton.Digit9;
sl@0
   679
					break;
sl@0
   680
				case (int) Keys.Enter:
sl@0
   681
					rcb = RemoteControlButton.Enter;
sl@0
   682
					break;
sl@0
   683
				case (int) Keys.Right:
sl@0
   684
					rcb = RemoteControlButton.Right;
sl@0
   685
					break;
sl@0
   686
				case (int) Keys.Up:
sl@0
   687
					rcb = RemoteControlButton.Up;
sl@0
   688
					break;
sl@0
   689
			}
sl@0
   690
sl@0
   691
			if (this.ButtonPressed != null && rcb != RemoteControlButton.Unknown)
sl@0
   692
				this.ButtonPressed(this, new RemoteControlEventArgs(rcb, GetDevice(param)));
sl@0
   693
		}
sl@0
   694
sl@0
   695
sl@0
   696
		private void ProcessAppCommand(int param)
sl@0
   697
		{
sl@0
   698
			RemoteControlButton rcb = RemoteControlButton.Unknown;
sl@0
   699
sl@0
   700
			int cmd	= (int) (((ushort) (param >> 16)) & ~FAPPCOMMAND_MASK);
sl@0
   701
sl@0
   702
			switch (cmd)
sl@0
   703
			{
sl@0
   704
				case APPCOMMAND_BROWSER_BACKWARD:
sl@0
   705
					rcb = RemoteControlButton.Back;
sl@0
   706
					break;
sl@0
   707
				case APPCOMMAND_MEDIA_CHANNEL_DOWN:
sl@0
   708
					rcb = RemoteControlButton.ChannelDown;
sl@0
   709
					break;
sl@0
   710
				case APPCOMMAND_MEDIA_CHANNEL_UP:
sl@0
   711
					rcb = RemoteControlButton.ChannelUp;
sl@0
   712
					break;
sl@0
   713
				case APPCOMMAND_MEDIA_FAST_FORWARD:
sl@0
   714
					rcb = RemoteControlButton.FastForward;
sl@0
   715
					break;
sl@0
   716
				case APPCOMMAND_VOLUME_MUTE:
sl@0
   717
					rcb = RemoteControlButton.VolumeMute;
sl@0
   718
					break;
sl@0
   719
				case APPCOMMAND_MEDIA_PAUSE:
sl@0
   720
					rcb = RemoteControlButton.Pause;
sl@0
   721
					break;
sl@0
   722
				case APPCOMMAND_MEDIA_PLAY:
sl@0
   723
					rcb = RemoteControlButton.Play;
sl@0
   724
					break;
sl@0
   725
                case APPCOMMAND_MEDIA_PLAY_PAUSE:
sl@0
   726
                    rcb = RemoteControlButton.PlayPause;
sl@0
   727
                    break;
sl@0
   728
				case APPCOMMAND_MEDIA_RECORD:
sl@0
   729
					rcb = RemoteControlButton.Record;
sl@0
   730
					break;
sl@0
   731
				case APPCOMMAND_MEDIA_PREVIOUSTRACK:
sl@0
   732
					rcb = RemoteControlButton.PreviousTrack;
sl@0
   733
					break;
sl@0
   734
				case APPCOMMAND_MEDIA_REWIND:
sl@0
   735
					rcb = RemoteControlButton.Rewind;
sl@0
   736
					break;
sl@0
   737
				case APPCOMMAND_MEDIA_NEXTTRACK:
sl@0
   738
					rcb = RemoteControlButton.NextTrack;
sl@0
   739
					break;
sl@0
   740
				case APPCOMMAND_MEDIA_STOP:
sl@0
   741
					rcb = RemoteControlButton.Stop;
sl@0
   742
					break;
sl@0
   743
				case APPCOMMAND_VOLUME_DOWN:
sl@0
   744
					rcb = RemoteControlButton.VolumeDown;
sl@0
   745
					break;
sl@0
   746
				case APPCOMMAND_VOLUME_UP:
sl@0
   747
					rcb = RemoteControlButton.VolumeUp;
sl@0
   748
					break;
sl@0
   749
			}
sl@0
   750
sl@0
   751
			if (this.ButtonPressed != null && rcb != RemoteControlButton.Unknown)
sl@0
   752
				this.ButtonPressed(this, new RemoteControlEventArgs(rcb, GetDevice(param)));
sl@0
   753
		}
sl@0
   754
sl@0
   755
sl@0
   756
		private void ProcessInputCommand(ref Message message)
sl@0
   757
		{
sl@6
   758
sl@6
   759
sl@6
   760
sl@0
   761
			uint dwSize = 0;
sl@0
   762
sl@0
   763
            uint sizeOfHeader=(uint)Marshal.SizeOf(typeof(RAWINPUTHEADER));
sl@0
   764
sl@0
   765
            //Get the size of our raw input data.
sl@0
   766
			GetRawInputData(message.LParam,	RID_INPUT, IntPtr.Zero,	ref dwSize,	sizeOfHeader);
sl@0
   767
sl@0
   768
            //Allocate a large enough buffer
sl@6
   769
			IntPtr rawInputBuffer = Marshal.AllocHGlobal((int) dwSize);
sl@0
   770
			try
sl@0
   771
			{
sl@6
   772
				if(rawInputBuffer == IntPtr.Zero)
sl@0
   773
					return;
sl@0
   774
sl@0
   775
                //Now read our RAWINPUT data
sl@6
   776
				if (GetRawInputData(message.LParam,	RID_INPUT, rawInputBuffer, ref dwSize, (uint) Marshal.SizeOf(typeof(RAWINPUTHEADER))) != dwSize)
sl@0
   777
				{
sl@0
   778
					return;
sl@0
   779
				}
sl@0
   780
sl@0
   781
                //Cast our buffer
sl@6
   782
                RAWINPUT raw = (RAWINPUT)Marshal.PtrToStructure(rawInputBuffer, typeof(RAWINPUT));
sl@6
   783
sl@6
   784
                //Get Device Info
sl@6
   785
                uint deviceInfoSize = (uint)Marshal.SizeOf(typeof(RID_DEVICE_INFO));
sl@6
   786
                IntPtr deviceInfoBuffer = Marshal.AllocHGlobal((int)deviceInfoSize);
sl@6
   787
sl@6
   788
                int res = GetRawInputDeviceInfo(raw.header.hDevice, RIDI_DEVICEINFO, deviceInfoBuffer, ref deviceInfoSize);
sl@6
   789
                if (res <= 0)
sl@6
   790
                {
sl@6
   791
                    Debug.WriteLine("WM_INPUT could not read device info: " + Marshal.GetLastWin32Error().ToString());
sl@6
   792
                    return;
sl@6
   793
                }
sl@6
   794
sl@6
   795
                //Cast our buffer
sl@6
   796
                RID_DEVICE_INFO deviceInfo = (RID_DEVICE_INFO)Marshal.PtrToStructure(deviceInfoBuffer, typeof(RID_DEVICE_INFO));
sl@6
   797
sl@6
   798
                //Check type of input device and quite if we don't like it
sl@6
   799
                switch (deviceInfo.dwType)
sl@6
   800
                {
sl@6
   801
                    case RIM_TYPEHID:
sl@6
   802
                        Debug.WriteLine("WM_INPUT source device is HID.");
sl@6
   803
                        break;
sl@6
   804
                    case RIM_TYPEMOUSE:
sl@6
   805
                        Debug.WriteLine("WM_INPUT source device is Mouse.");
sl@6
   806
                        return;
sl@6
   807
                    case RIM_TYPEKEYBOARD:
sl@6
   808
                        Debug.WriteLine("WM_INPUT source device is Keyboard.");
sl@6
   809
                        return;
sl@6
   810
                    default:
sl@6
   811
                        Debug.WriteLine("WM_INPUT source device is Unknown.");
sl@6
   812
                        return;
sl@6
   813
                }
sl@6
   814
sl@6
   815
                //Get Usage Page and Usage
sl@6
   816
                Debug.WriteLine("Usage Page: 0x" + deviceInfo.hid.usUsagePage.ToString("X4") + " Usage: 0x" + deviceInfo.hid.usUsage.ToString("X4"));
sl@0
   817
sl@0
   818
                //Check that our raw input is HID
sl@0
   819
                if (raw.header.dwType == RIM_TYPEHID && raw.hid.dwSizeHid>0)
sl@0
   820
				{
sl@0
   821
                    //Allocate a buffer for one HID message
sl@0
   822
					byte[] bRawData = new byte[raw.hid.dwSizeHid];
sl@0
   823
sl@0
   824
                    //Compute the address from which to copy our HID message
sl@0
   825
                    int pRawData = 0;
sl@0
   826
                    unsafe
sl@0
   827
                    {
sl@6
   828
                        byte* source = (byte*)rawInputBuffer;
sl@0
   829
                        source += sizeof(RAWINPUTHEADER) + sizeof(RAWHID);
sl@0
   830
                        pRawData = (int)source;
sl@0
   831
                    }
sl@0
   832
sl@4
   833
                    //Copy HID message into our buffer
sl@0
   834
                    Marshal.Copy(new IntPtr(pRawData), bRawData, 0, raw.hid.dwSizeHid);
sl@4
   835
                    //bRawData[0] //Not sure what's the meaning of the code at offset 0
sl@4
   836
                    //TODO: check size before access
sl@0
   837
                    int rawData = bRawData[1]; //Get button code
sl@4
   838
                    //Print HID codes in our debug output
sl@6
   839
                    string hidDump = "HID " + raw.hid.dwCount + "/" + raw.hid.dwSizeHid + ":";
sl@6
   840
                    foreach (byte b in bRawData)
sl@6
   841
                    {
sl@6
   842
                        hidDump += b.ToString("X2");
sl@6
   843
                    }
sl@6
   844
                    Debug.WriteLine(hidDump);
sl@6
   845
sl@6
   846
                    //Make sure both usage page and usage are matching MCE remote
sl@6
   847
                    if (deviceInfo.hid.usUsagePage != (ushort)Hid.UsagePage.MceRemote || deviceInfo.hid.usUsage != (ushort)Hid.MceRemoteUsage)
sl@6
   848
                    {
sl@6
   849
                        Debug.WriteLine("Not MCE remote page and usage.");
sl@6
   850
                        return;
sl@6
   851
                    }
sl@0
   852
sl@3
   853
                    if (Enum.IsDefined(typeof(MceButton), rawData) && rawData!=0) //Our button is a known MCE button
sl@3
   854
                    {
sl@3
   855
                        if (this.ButtonPressed != null) //What's that?
sl@3
   856
                        {
sl@3
   857
                            this.ButtonPressed(this, new RemoteControlEventArgs((MceButton)rawData, GetDevice(message.LParam.ToInt32())));
sl@3
   858
                        }
sl@3
   859
                    }
sl@0
   860
				}
sl@0
   861
				else if(raw.header.dwType == RIM_TYPEMOUSE)
sl@0
   862
				{
sl@0
   863
					// do mouse handling...
sl@0
   864
				}
sl@0
   865
				else if(raw.header.dwType == RIM_TYPEKEYBOARD)
sl@0
   866
				{
sl@0
   867
					// do keyboard handling...
sl@0
   868
				}
sl@0
   869
			}
sl@0
   870
			finally
sl@0
   871
			{
sl@6
   872
				Marshal.FreeHGlobal(rawInputBuffer);
sl@0
   873
			}
sl@0
   874
		}
sl@0
   875
sl@0
   876
sl@0
   877
		private InputDevice GetDevice(int param)
sl@0
   878
		{
sl@0
   879
			InputDevice inputDevice;
sl@0
   880
sl@0
   881
			switch ((int) (((ushort) (param >> 16)) & FAPPCOMMAND_MASK))
sl@0
   882
			{
sl@0
   883
				case FAPPCOMMAND_OEM:
sl@0
   884
					inputDevice = InputDevice.OEM;
sl@0
   885
					break;
sl@0
   886
				case FAPPCOMMAND_MOUSE:
sl@0
   887
					inputDevice = InputDevice.Mouse;
sl@0
   888
					break;
sl@0
   889
				default:
sl@0
   890
					inputDevice = InputDevice.Key;
sl@0
   891
					break;
sl@0
   892
			}
sl@0
   893
sl@0
   894
			return inputDevice;
sl@0
   895
		}
sl@0
   896
	}
sl@0
   897
}