sl@0: using System; sl@0: using System.Windows.Forms; sl@0: using System.Runtime.InteropServices; sl@0: using System.Diagnostics; sl@0: sl@0: sl@6: namespace Devices.RemoteControl sl@0: { sl@6: sl@6: public static class Hid sl@6: { sl@6: /// sl@6: /// From USB HID usage tables. sl@6: /// http://www.usb.org/developers/hidpage#HID_Usage sl@6: /// http://www.usb.org/developers/devclass_docs/Hut1_12v2.pdf sl@6: /// sl@6: public enum UsagePage : ushort sl@6: { sl@6: Undefined = 0, sl@6: GenericDesktopControl, sl@6: SimulationControl, sl@6: VirtualRealityControl, sl@6: SportControl, sl@6: GameControl, sl@6: GenericDeviceControl, sl@6: Keyboard, sl@6: LightEmittingDiode, sl@6: Button, sl@6: Ordinal, sl@6: Telephony, sl@6: Consumer, sl@6: Digitiser, sl@6: PhysicalInterfaceDevice = 0x0f, sl@6: Unicode = 0x10, sl@6: AlphaNumericDisplay = 0x14, sl@6: MedicalInstruments = 0x40, sl@6: MonitorPage0 = 0x80, sl@6: MonitorPage1, sl@6: MonitorPage2, sl@6: MonitorPage3, sl@6: PowerPage0, sl@6: PowerPage1, sl@6: PowerPage2, sl@6: PowerPage3, sl@6: BarCodeScanner = 0x8c, sl@6: Scale, sl@6: MagneticStripeReader, sl@6: ReservedPointOfSale, sl@6: CameraControl, sl@6: Arcade, sl@6: // http://msdn.microsoft.com/en-us/library/windows/desktop/bb417079.aspx sl@6: MceRemote = 0xffbc, sl@6: TerraTecRemote = 0xffcc sl@6: } sl@6: sl@6: public const ushort MceRemoteUsage = 0x88; sl@6: } sl@6: sl@6: sl@0: public enum InputDevice sl@0: { sl@0: Key, sl@0: Mouse, sl@0: OEM sl@0: } sl@0: sl@0: sl@0: public enum RemoteControlButton sl@0: { sl@0: Clear, sl@0: Down, sl@0: Left, sl@0: Digit0, sl@0: Digit1, sl@0: Digit2, sl@0: Digit3, sl@0: Digit4, sl@0: Digit5, sl@0: Digit6, sl@0: Digit7, sl@0: Digit8, sl@0: Digit9, sl@0: Enter, sl@0: Right, sl@0: Up, sl@0: sl@0: Back, sl@0: ChannelDown, sl@0: ChannelUp, sl@0: FastForward, sl@0: VolumeMute, sl@0: Pause, sl@0: Play, sl@0: PlayPause, sl@0: Record, sl@0: PreviousTrack, sl@0: Rewind, sl@0: NextTrack, sl@0: Stop, sl@0: VolumeDown, sl@0: VolumeUp, sl@0: sl@0: RecordedTV, sl@0: Guide, sl@0: LiveTV, sl@0: Details, sl@0: DVDMenu, sl@0: DVDAngle, sl@0: DVDAudio, sl@0: DVDSubtitle, sl@0: MyMusic, sl@0: MyPictures, sl@0: MyVideos, sl@0: MyTV, sl@0: OEM1, sl@0: OEM2, sl@0: StandBy, sl@0: TVJump, sl@0: sl@0: Unknown sl@0: } sl@0: sl@3: /// sl@6: /// sl@3: /// sl@3: public enum MceButton sl@3: { sl@5: /// sl@5: /// Not defined by the Microsoft specs. sl@5: /// sl@6: Null = 0x00, sl@3: GreenStart = 0x0D, sl@3: ClosedCaptioning = 0x2B, sl@3: Teletext = 0x5A, sl@3: TeletextRed = 0x5B, sl@3: TeletextGreen = 0x5C, sl@3: TeletextYellow = 0x5D, sl@3: TeletextBlue = 0x5E, sl@3: LiveTv = 0x25, sl@3: Music = 0x47, sl@3: RecordedTv = 0x48, sl@3: Pictures = 0x49, sl@3: Videos = 0x4A, sl@3: FmRadio = 0x50, sl@3: Extras = 0x3C, sl@3: ExtrasApp = 0x3D, sl@3: DvdMenu = 0x24, sl@3: DvdAngle = 0x4B, sl@3: DvdAudio = 0x4C, sl@3: DvdSubtitle = 0x4D, sl@5: /// sl@5: /// First press action: Ejects a DVD drive. sl@5: /// sl@5: /// Second press action: Repeats first press action. sl@5: /// sl@5: /// Notably issued by XBOX360 remote as defined in irplus - Remote Control - Android application. sl@5: /// sl@3: Eject = 0x28, sl@3: DvdTopMenu = 0x43, sl@5: /// sl@5: /// First press action: Generates EXTn HID message in the Media Center Vendor Specific sl@5: /// Collection (page 0xFFBC, usage 0x88). sl@5: /// sl@5: /// Second press action: Repeats message. sl@5: /// sl@5: /// Auto-repeat: No sl@5: /// sl@5: /// Notably sent by the 'Visualization' button of HP Windows Media Center Remote (TSGH-IR08). sl@5: /// sl@5: /// According to HP specs it displays visual imagery that is synchronized to the sound of your music tracks. sl@5: /// sl@3: Ext0 = 0x32, sl@5: /// sl@5: /// First press action: Generates EXTn HID message in the Media Center Vendor Specific sl@5: /// Collection (page 0xFFBC, usage 0x88). sl@5: /// sl@5: /// Second press action: Repeats message. sl@5: /// sl@5: /// Auto-repeat: No sl@5: /// sl@5: /// Notably sent by the 'Slide Show' button of HP Windows Media Center Remote (TSGH-IR08). sl@5: /// sl@5: /// According to HP specs it plays a slide show of all the pictures on your hard disk drive. sl@5: /// sl@3: Ext1 = 0x33, sl@5: /// sl@5: /// First press action: Generates EXTn HID message in the Media Center Vendor Specific sl@5: /// Collection (page 0xFFBC, usage 0x88). sl@5: /// sl@5: /// Second press action: Repeats message. sl@5: /// sl@5: /// Auto-repeat: No sl@5: /// sl@5: /// Notably sent by the 'Eject' button of HP Windows Media Center Remote (TSGH-IR08). sl@5: /// Also interpreted as 'Eject' action by SoundGraph iMON Manager in MCE mode (OrigenAE VF310). sl@5: /// sl@3: Ext2 = 0x34, sl@5: /// sl@5: /// First press action: Generates EXTn HID message in the Media Center Vendor Specific sl@5: /// Collection (page 0xFFBC, usage 0x88). sl@5: /// sl@5: /// Second press action: Repeats message. sl@5: /// sl@5: /// Auto-repeat: No sl@5: /// sl@5: /// Notably sent by the 'Input selection' button of HP Windows Media Center Remote (TSGH-IR08). sl@5: /// sl@3: Ext3 = 0x35, sl@3: Ext4 = 0x36, sl@3: Ext5 = 0x37, sl@3: Ext6 = 0x38, sl@3: Ext7 = 0x39, sl@3: Ext8 = 0x3A, sl@3: Ext9 = 0x80, sl@3: Ext10 = 0x81, sl@3: Ext11 = 0x6F, sl@3: Zoom = 0x27, sl@3: ChannelInput = 0x42, sl@3: SubAudio = 0x2D, sl@3: Channel10 = 0x3E, sl@3: Channel11 = 0x3F, sl@3: Channel12 = 0x40, sl@5: /// sl@5: /// First press action: Generates OEM2 HID message in the Media Center Vendor Specific sl@5: /// Collection. This button is intended to control the front panel display of home entertainment sl@5: /// computers. When this button is pressed, the display could be turned on or off, or the display sl@5: /// mode could change. sl@5: /// sl@5: /// Second press action: Repeats message. sl@5: /// sl@5: /// Auto-repeat: No sl@5: /// sl@5: /// Notably issued by XBOX360 remote as defined in irplus - Remote Control - Android application. sl@5: /// sl@3: Display = 0x4F, sl@5: /// sl@5: /// First press action: To be determined. sl@5: /// sl@5: /// Second press action: Repeats message. sl@5: /// sl@5: /// Auto-repeat: No sl@5: /// sl@3: Kiosk = 0x6A, sl@3: NetworkSelection = 0x2C, sl@3: BlueRayTool = 0x78, sl@3: ChannelInfo = 0x41, sl@6: VideoSelection = 0x61 sl@3: } sl@3: sl@5: public enum HpMceButton sl@5: { sl@5: /// sl@5: /// Displays visual imagery that is synchronized to the sound of your music tracks. sl@5: /// sl@5: /// Second press action: Repeats message. sl@5: /// sl@5: /// Auto-repeat: No sl@5: /// sl@5: /// Notably sent by the 'Visualization' button of HP Windows Media Center Remote (TSGH-IR08). sl@5: /// sl@5: /// According to HP specs it displays visual imagery that is synchronized to the sound of your music tracks. sl@5: /// sl@5: Visualization = MceButton.Ext0, sl@5: /// sl@5: /// Plays a slide show of all the pictures on your hard disk drive. sl@5: /// sl@5: /// Second press action: Repeats message. sl@5: /// sl@5: /// Auto-repeat: No sl@5: /// sl@5: /// Notably sent by the 'Slide Show' button of HP Windows Media Center Remote (TSGH-IR08). sl@5: /// sl@5: /// According to HP specs it plays a slide show of all the pictures on your hard disk drive. sl@5: /// sl@5: SlideShow = MceButton.Ext1, sl@5: /// sl@5: /// Eject optical drive. sl@5: /// sl@5: /// Second press action: Repeats message. sl@5: /// sl@5: /// Auto-repeat: No sl@5: /// sl@5: /// Notably sent by the 'Eject' button of HP Windows Media Center Remote (TSGH-IR08). sl@5: /// Also interpreted as 'Eject' action by SoundGraph iMON Manager in MCE mode (OrigenAE VF310). sl@5: /// sl@5: Eject = MceButton.Ext2, sl@5: /// sl@5: /// Not sure what this should do. sl@5: /// sl@5: /// Second press action: Repeats message. sl@5: /// sl@5: /// Auto-repeat: No sl@5: /// sl@5: /// Notably sent by the 'Input selection' button of HP Windows Media Center Remote (TSGH-IR08). sl@5: /// sl@5: InputSelection = MceButton.Ext3, sl@5: } sl@5: sl@5: sl@0: sl@0: #region RemoteControlEventArgs sl@0: sl@0: public class RemoteControlEventArgs : EventArgs sl@0: { sl@3: RemoteControlButton _rcb; sl@0: InputDevice _device; sl@3: MceButton iMceButton; sl@0: sl@3: public RemoteControlEventArgs(RemoteControlButton rcb, InputDevice device) sl@0: { sl@3: iMceButton = MceButton.Null; sl@0: _rcb = rcb; sl@0: _device = device; sl@0: } sl@0: sl@3: public RemoteControlEventArgs(MceButton mce, InputDevice device) sl@3: { sl@3: iMceButton = mce; sl@3: _rcb = RemoteControlButton.Unknown; sl@3: _device = device; sl@3: } sl@0: sl@0: public RemoteControlEventArgs() sl@0: { sl@3: iMceButton = MceButton.Null; sl@0: _rcb = RemoteControlButton.Unknown; sl@0: _device = InputDevice.Key; sl@0: } sl@0: sl@0: public RemoteControlButton Button sl@0: { sl@0: get { return _rcb; } sl@0: set { _rcb = value; } sl@0: } sl@0: sl@3: public MceButton MceButton sl@3: { sl@3: get { return iMceButton; } sl@3: set { iMceButton = value; } sl@3: } sl@3: sl@0: public InputDevice Device sl@0: { sl@0: get { return _device; } sl@0: set { _device = value; } sl@0: } sl@0: } sl@0: sl@0: #endregion RemoteControlEventArgs sl@0: sl@0: sl@0: public sealed class RemoteControlDevice sl@0: { sl@0: sl@0: [StructLayout(LayoutKind.Sequential, Pack = 1)] sl@0: internal struct RAWINPUTDEVICE sl@0: { sl@0: [MarshalAs(UnmanagedType.U2)] sl@0: public ushort usUsagePage; sl@0: [MarshalAs(UnmanagedType.U2)] sl@0: public ushort usUsage; sl@0: [MarshalAs(UnmanagedType.U4)] sl@0: public int dwFlags; sl@0: public IntPtr hwndTarget; sl@0: } sl@0: sl@0: sl@0: [StructLayout(LayoutKind.Sequential, Pack = 1)] sl@0: internal struct RAWINPUTHEADER sl@0: { sl@0: [MarshalAs(UnmanagedType.U4)] sl@0: public int dwType; sl@0: [MarshalAs(UnmanagedType.U4)] sl@0: public int dwSize; sl@0: public IntPtr hDevice; sl@0: [MarshalAs(UnmanagedType.U4)] sl@0: public int wParam; sl@0: } sl@0: sl@0: sl@0: [StructLayout(LayoutKind.Sequential, Pack = 1)] sl@0: internal struct RAWHID sl@0: { sl@0: [MarshalAs(UnmanagedType.U4)] sl@0: public int dwSizeHid; sl@0: [MarshalAs(UnmanagedType.U4)] sl@0: public int dwCount; sl@0: // sl@0: //BYTE bRawData[1]; sl@0: } sl@0: sl@0: sl@0: [StructLayout(LayoutKind.Sequential, Pack = 1)] sl@0: internal struct BUTTONSSTR sl@0: { sl@0: [MarshalAs(UnmanagedType.U2)] sl@0: public ushort usButtonFlags; sl@0: [MarshalAs(UnmanagedType.U2)] sl@0: public ushort usButtonData; sl@0: } sl@0: sl@0: sl@0: [StructLayout(LayoutKind.Explicit, Pack = 1)] sl@0: internal struct RAWMOUSE sl@0: { sl@0: [MarshalAs(UnmanagedType.U2)] sl@0: [FieldOffset (0)] public ushort usFlags; sl@0: [MarshalAs(UnmanagedType.U4)] sl@0: [FieldOffset (4)] public uint ulButtons; sl@0: [FieldOffset (4)] public BUTTONSSTR buttonsStr; sl@0: [MarshalAs(UnmanagedType.U4)] sl@0: [FieldOffset (8)] public uint ulRawButtons; sl@0: [MarshalAs(UnmanagedType.U4)] sl@0: [FieldOffset (12)] public int lLastX; sl@0: [MarshalAs(UnmanagedType.U4)] sl@0: [FieldOffset (16)] public int lLastY; sl@0: [MarshalAs(UnmanagedType.U4)] sl@0: [FieldOffset (20)] public uint ulExtraInformation; sl@0: } sl@0: sl@0: [StructLayout(LayoutKind.Sequential, Pack = 1)] sl@0: internal struct RAWKEYBOARD sl@0: { sl@0: [MarshalAs(UnmanagedType.U2)] sl@0: public ushort MakeCode; sl@0: [MarshalAs(UnmanagedType.U2)] sl@0: public ushort Flags; sl@0: [MarshalAs(UnmanagedType.U2)] sl@0: public ushort Reserved; sl@0: [MarshalAs(UnmanagedType.U2)] sl@0: public ushort VKey; sl@0: [MarshalAs(UnmanagedType.U4)] sl@0: public uint Message; sl@0: [MarshalAs(UnmanagedType.U4)] sl@0: public uint ExtraInformation; sl@0: } sl@0: sl@0: sl@0: [StructLayout(LayoutKind.Explicit, Pack=1)] sl@0: internal struct RAWINPUT sl@0: { sl@0: [FieldOffset (0)] public RAWINPUTHEADER header; sl@0: [FieldOffset (16)] public RAWMOUSE mouse; sl@0: [FieldOffset (16)] public RAWKEYBOARD keyboard; sl@0: [FieldOffset (16)] public RAWHID hid; sl@0: } sl@0: sl@0: sl@6: [StructLayout(LayoutKind.Sequential, Pack=1)] sl@6: internal struct RID_DEVICE_INFO_MOUSE sl@6: { sl@6: public uint dwId; sl@6: public uint dwNumberOfButtons; sl@6: public uint dwSampleRate; sl@6: public bool fHasHorizontalWheel; sl@6: } sl@6: sl@6: sl@6: [StructLayout(LayoutKind.Sequential, Pack=1)] sl@6: internal struct RID_DEVICE_INFO_KEYBOARD sl@6: { sl@6: public uint dwType; sl@6: public uint dwSubType; sl@6: public uint dwKeyboardMode; sl@6: public uint dwNumberOfFunctionKeys; sl@6: public uint dwNumberOfIndicators; sl@6: public uint dwNumberOfKeysTotal; sl@6: } sl@6: sl@6: [StructLayout(LayoutKind.Sequential, Pack=1)] sl@6: internal struct RID_DEVICE_INFO_HID sl@6: { sl@6: public uint dwVendorId; sl@6: public uint dwProductId; sl@6: public uint dwVersionNumber; sl@6: public ushort usUsagePage; sl@6: public ushort usUsage; sl@6: } sl@6: sl@6: [StructLayout(LayoutKind.Explicit, Pack=1)] sl@6: internal struct RID_DEVICE_INFO sl@6: { sl@6: [FieldOffset(0)] sl@6: public uint cbSize; sl@6: [FieldOffset(4)] sl@6: public uint dwType; sl@6: [FieldOffset(8)] sl@6: public RID_DEVICE_INFO_MOUSE mouse; sl@6: [FieldOffset(8)] sl@6: public RID_DEVICE_INFO_KEYBOARD keyboard; sl@6: [FieldOffset(8)] sl@6: public RID_DEVICE_INFO_HID hid; sl@6: } sl@6: sl@6: sl@6: sl@0: [DllImport("User32.dll")] sl@0: extern static bool RegisterRawInputDevices(RAWINPUTDEVICE[] pRawInputDevice, uint uiNumDevices, uint cbSize); sl@0: sl@0: [DllImport("User32.dll")] sl@0: extern static uint GetRawInputData(IntPtr hRawInput, uint uiCommand, IntPtr pData, ref uint pcbSize, uint cbSizeHeader); sl@0: sl@6: [DllImport("User32.dll", SetLastError=true)] sl@6: extern static int GetRawInputDeviceInfo(IntPtr hDevice, uint uiCommand, IntPtr pData, ref uint pcbSize); sl@4: sl@0: sl@0: private const int WM_KEYDOWN = 0x0100; sl@0: private const int WM_APPCOMMAND = 0x0319; sl@0: private const int WM_INPUT = 0x00FF; sl@0: sl@0: private const int APPCOMMAND_BROWSER_BACKWARD = 1; sl@0: private const int APPCOMMAND_VOLUME_MUTE = 8; sl@0: private const int APPCOMMAND_VOLUME_DOWN = 9; sl@0: private const int APPCOMMAND_VOLUME_UP = 10; sl@0: private const int APPCOMMAND_MEDIA_NEXTTRACK = 11; sl@0: private const int APPCOMMAND_MEDIA_PREVIOUSTRACK = 12; sl@0: private const int APPCOMMAND_MEDIA_STOP = 13; sl@0: private const int APPCOMMAND_MEDIA_PLAY_PAUSE = 14; sl@0: private const int APPCOMMAND_MEDIA_PLAY = 46; sl@0: private const int APPCOMMAND_MEDIA_PAUSE = 47; sl@0: private const int APPCOMMAND_MEDIA_RECORD = 48; sl@0: private const int APPCOMMAND_MEDIA_FAST_FORWARD = 49; sl@0: private const int APPCOMMAND_MEDIA_REWIND = 50; sl@0: private const int APPCOMMAND_MEDIA_CHANNEL_UP = 51; sl@0: private const int APPCOMMAND_MEDIA_CHANNEL_DOWN = 52; sl@0: sl@0: private const int RID_INPUT = 0x10000003; sl@0: private const int RID_HEADER = 0x10000005; sl@0: sl@0: private const int FAPPCOMMAND_MASK = 0xF000; sl@0: private const int FAPPCOMMAND_MOUSE = 0x8000; sl@0: private const int FAPPCOMMAND_KEY = 0; sl@0: private const int FAPPCOMMAND_OEM = 0x1000; sl@0: sl@6: /// sl@6: /// GetRawInputDeviceInfo pData points to a string that contains the device name. sl@6: /// sl@6: public const uint RIDI_DEVICENAME = 0x20000007; sl@6: /// sl@6: /// GetRawInputDeviceInfo For this uiCommand only, the value in pcbSize is the character count (not the byte count). sl@6: /// sl@6: public const uint RIDI_DEVICEINFO = 0x2000000b; sl@6: /// sl@6: /// GetRawInputDeviceInfo pData points to an RID_DEVICE_INFO structure. sl@6: /// sl@6: public const uint RIDI_PREPARSEDDATA = 0x20000005; sl@6: sl@6: sl@6: /// sl@6: /// Data comes from a mouse. sl@6: /// sl@6: public const uint RIM_TYPEMOUSE = 0; sl@6: /// sl@6: /// Data comes from a keyboard. sl@6: /// sl@6: public const uint RIM_TYPEKEYBOARD = 1; sl@6: /// sl@6: /// Data comes from an HID that is not a keyboard or a mouse. sl@6: /// sl@6: public const uint RIM_TYPEHID = 2; sl@6: sl@6: sl@6: sl@6: sl@6: sl@0: public delegate void RemoteControlDeviceEventHandler(object sender, RemoteControlEventArgs e); sl@0: public event RemoteControlDeviceEventHandler ButtonPressed; sl@0: sl@0: sl@0: //------------------------------------------------------------- sl@0: // constructors sl@0: //------------------------------------------------------------- sl@0: sl@0: public RemoteControlDevice() sl@0: { sl@0: // Register the input device to receive the commands from the sl@0: // remote device. See http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnwmt/html/remote_control.asp sl@0: // for the vendor defined usage page. sl@0: sl@0: RAWINPUTDEVICE[] rid = new RAWINPUTDEVICE[3]; sl@0: sl@0: rid[0].usUsagePage = 0xFFBC; sl@0: rid[0].usUsage = 0x88; sl@0: rid[0].dwFlags = 0; sl@0: sl@0: rid[1].usUsagePage = 0x0C; sl@0: rid[1].usUsage = 0x01; sl@0: rid[1].dwFlags = 0; sl@0: sl@0: rid[2].usUsagePage = 0x0C; sl@0: rid[2].usUsage = 0x80; sl@0: rid[2].dwFlags = 0; sl@0: sl@0: if (!RegisterRawInputDevices(rid, sl@0: (uint) rid.Length, sl@0: (uint) Marshal.SizeOf(rid[0])) sl@0: ) sl@0: { sl@0: throw new ApplicationException("Failed to register raw input devices."); sl@0: } sl@0: } sl@0: sl@0: sl@0: //------------------------------------------------------------- sl@0: // methods sl@0: //------------------------------------------------------------- sl@0: sl@0: public void ProcessMessage(Message message) sl@0: { sl@0: int param; sl@0: sl@0: switch (message.Msg) sl@0: { sl@0: case WM_KEYDOWN: sl@0: param = message.WParam.ToInt32(); sl@0: ProcessKeyDown(param); sl@0: break; sl@0: case WM_APPCOMMAND: sl@0: param = message.LParam.ToInt32(); sl@0: ProcessAppCommand(param); sl@0: break; sl@0: case WM_INPUT: sl@0: ProcessInputCommand(ref message); sl@0: message.Result = new IntPtr(0); sl@0: break; sl@0: } sl@0: sl@0: } sl@0: sl@0: sl@0: //------------------------------------------------------------- sl@0: // methods (helpers) sl@0: //------------------------------------------------------------- sl@0: sl@0: private void ProcessKeyDown(int param) sl@0: { sl@0: RemoteControlButton rcb = RemoteControlButton.Unknown; sl@0: sl@0: switch (param) sl@0: { sl@0: case (int) Keys.Escape: sl@0: rcb = RemoteControlButton.Clear; sl@0: break; sl@0: case (int) Keys.Down: sl@0: rcb = RemoteControlButton.Down; sl@0: break; sl@0: case (int) Keys.Left: sl@0: rcb = RemoteControlButton.Left; sl@0: break; sl@0: case (int) Keys.D0: sl@0: rcb = RemoteControlButton.Digit0; sl@0: break; sl@0: case (int) Keys.D1: sl@0: rcb = RemoteControlButton.Digit1; sl@0: break; sl@0: case (int) Keys.D2: sl@0: rcb = RemoteControlButton.Digit2; sl@0: break; sl@0: case (int) Keys.D3: sl@0: rcb = RemoteControlButton.Digit3; sl@0: break; sl@0: case (int) Keys.D4: sl@0: rcb = RemoteControlButton.Digit4; sl@0: break; sl@0: case (int) Keys.D5: sl@0: rcb = RemoteControlButton.Digit5; sl@0: break; sl@0: case (int) Keys.D6: sl@0: rcb = RemoteControlButton.Digit6; sl@0: break; sl@0: case (int) Keys.D7: sl@0: rcb = RemoteControlButton.Digit7; sl@0: break; sl@0: case (int) Keys.D8: sl@0: rcb = RemoteControlButton.Digit8; sl@0: break; sl@0: case (int) Keys.D9: sl@0: rcb = RemoteControlButton.Digit9; sl@0: break; sl@0: case (int) Keys.Enter: sl@0: rcb = RemoteControlButton.Enter; sl@0: break; sl@0: case (int) Keys.Right: sl@0: rcb = RemoteControlButton.Right; sl@0: break; sl@0: case (int) Keys.Up: sl@0: rcb = RemoteControlButton.Up; sl@0: break; sl@0: } sl@0: sl@0: if (this.ButtonPressed != null && rcb != RemoteControlButton.Unknown) sl@0: this.ButtonPressed(this, new RemoteControlEventArgs(rcb, GetDevice(param))); sl@0: } sl@0: sl@0: sl@0: private void ProcessAppCommand(int param) sl@0: { sl@0: RemoteControlButton rcb = RemoteControlButton.Unknown; sl@0: sl@0: int cmd = (int) (((ushort) (param >> 16)) & ~FAPPCOMMAND_MASK); sl@0: sl@0: switch (cmd) sl@0: { sl@0: case APPCOMMAND_BROWSER_BACKWARD: sl@0: rcb = RemoteControlButton.Back; sl@0: break; sl@0: case APPCOMMAND_MEDIA_CHANNEL_DOWN: sl@0: rcb = RemoteControlButton.ChannelDown; sl@0: break; sl@0: case APPCOMMAND_MEDIA_CHANNEL_UP: sl@0: rcb = RemoteControlButton.ChannelUp; sl@0: break; sl@0: case APPCOMMAND_MEDIA_FAST_FORWARD: sl@0: rcb = RemoteControlButton.FastForward; sl@0: break; sl@0: case APPCOMMAND_VOLUME_MUTE: sl@0: rcb = RemoteControlButton.VolumeMute; sl@0: break; sl@0: case APPCOMMAND_MEDIA_PAUSE: sl@0: rcb = RemoteControlButton.Pause; sl@0: break; sl@0: case APPCOMMAND_MEDIA_PLAY: sl@0: rcb = RemoteControlButton.Play; sl@0: break; sl@0: case APPCOMMAND_MEDIA_PLAY_PAUSE: sl@0: rcb = RemoteControlButton.PlayPause; sl@0: break; sl@0: case APPCOMMAND_MEDIA_RECORD: sl@0: rcb = RemoteControlButton.Record; sl@0: break; sl@0: case APPCOMMAND_MEDIA_PREVIOUSTRACK: sl@0: rcb = RemoteControlButton.PreviousTrack; sl@0: break; sl@0: case APPCOMMAND_MEDIA_REWIND: sl@0: rcb = RemoteControlButton.Rewind; sl@0: break; sl@0: case APPCOMMAND_MEDIA_NEXTTRACK: sl@0: rcb = RemoteControlButton.NextTrack; sl@0: break; sl@0: case APPCOMMAND_MEDIA_STOP: sl@0: rcb = RemoteControlButton.Stop; sl@0: break; sl@0: case APPCOMMAND_VOLUME_DOWN: sl@0: rcb = RemoteControlButton.VolumeDown; sl@0: break; sl@0: case APPCOMMAND_VOLUME_UP: sl@0: rcb = RemoteControlButton.VolumeUp; sl@0: break; sl@0: } sl@0: sl@0: if (this.ButtonPressed != null && rcb != RemoteControlButton.Unknown) sl@0: this.ButtonPressed(this, new RemoteControlEventArgs(rcb, GetDevice(param))); sl@0: } sl@0: sl@0: sl@0: private void ProcessInputCommand(ref Message message) sl@0: { sl@6: sl@6: sl@6: sl@0: uint dwSize = 0; sl@0: sl@0: uint sizeOfHeader=(uint)Marshal.SizeOf(typeof(RAWINPUTHEADER)); sl@0: sl@0: //Get the size of our raw input data. sl@0: GetRawInputData(message.LParam, RID_INPUT, IntPtr.Zero, ref dwSize, sizeOfHeader); sl@0: sl@0: //Allocate a large enough buffer sl@6: IntPtr rawInputBuffer = Marshal.AllocHGlobal((int) dwSize); sl@0: try sl@0: { sl@6: if(rawInputBuffer == IntPtr.Zero) sl@0: return; sl@0: sl@0: //Now read our RAWINPUT data sl@6: if (GetRawInputData(message.LParam, RID_INPUT, rawInputBuffer, ref dwSize, (uint) Marshal.SizeOf(typeof(RAWINPUTHEADER))) != dwSize) sl@0: { sl@0: return; sl@0: } sl@0: sl@0: //Cast our buffer sl@6: RAWINPUT raw = (RAWINPUT)Marshal.PtrToStructure(rawInputBuffer, typeof(RAWINPUT)); sl@6: sl@6: //Get Device Info sl@6: uint deviceInfoSize = (uint)Marshal.SizeOf(typeof(RID_DEVICE_INFO)); sl@6: IntPtr deviceInfoBuffer = Marshal.AllocHGlobal((int)deviceInfoSize); sl@6: sl@6: int res = GetRawInputDeviceInfo(raw.header.hDevice, RIDI_DEVICEINFO, deviceInfoBuffer, ref deviceInfoSize); sl@6: if (res <= 0) sl@6: { sl@6: Debug.WriteLine("WM_INPUT could not read device info: " + Marshal.GetLastWin32Error().ToString()); sl@6: return; sl@6: } sl@6: sl@6: //Cast our buffer sl@6: RID_DEVICE_INFO deviceInfo = (RID_DEVICE_INFO)Marshal.PtrToStructure(deviceInfoBuffer, typeof(RID_DEVICE_INFO)); sl@6: sl@6: //Check type of input device and quite if we don't like it sl@6: switch (deviceInfo.dwType) sl@6: { sl@6: case RIM_TYPEHID: sl@6: Debug.WriteLine("WM_INPUT source device is HID."); sl@6: break; sl@6: case RIM_TYPEMOUSE: sl@6: Debug.WriteLine("WM_INPUT source device is Mouse."); sl@6: return; sl@6: case RIM_TYPEKEYBOARD: sl@6: Debug.WriteLine("WM_INPUT source device is Keyboard."); sl@6: return; sl@6: default: sl@6: Debug.WriteLine("WM_INPUT source device is Unknown."); sl@6: return; sl@6: } sl@6: sl@6: //Get Usage Page and Usage sl@6: Debug.WriteLine("Usage Page: 0x" + deviceInfo.hid.usUsagePage.ToString("X4") + " Usage: 0x" + deviceInfo.hid.usUsage.ToString("X4")); sl@0: sl@0: //Check that our raw input is HID sl@0: if (raw.header.dwType == RIM_TYPEHID && raw.hid.dwSizeHid>0) sl@0: { sl@0: //Allocate a buffer for one HID message sl@0: byte[] bRawData = new byte[raw.hid.dwSizeHid]; sl@0: sl@0: //Compute the address from which to copy our HID message sl@0: int pRawData = 0; sl@0: unsafe sl@0: { sl@6: byte* source = (byte*)rawInputBuffer; sl@0: source += sizeof(RAWINPUTHEADER) + sizeof(RAWHID); sl@0: pRawData = (int)source; sl@0: } sl@0: sl@4: //Copy HID message into our buffer sl@0: Marshal.Copy(new IntPtr(pRawData), bRawData, 0, raw.hid.dwSizeHid); sl@4: //bRawData[0] //Not sure what's the meaning of the code at offset 0 sl@4: //TODO: check size before access sl@0: int rawData = bRawData[1]; //Get button code sl@4: //Print HID codes in our debug output sl@6: string hidDump = "HID " + raw.hid.dwCount + "/" + raw.hid.dwSizeHid + ":"; sl@6: foreach (byte b in bRawData) sl@6: { sl@6: hidDump += b.ToString("X2"); sl@6: } sl@6: Debug.WriteLine(hidDump); sl@6: sl@6: //Make sure both usage page and usage are matching MCE remote sl@6: if (deviceInfo.hid.usUsagePage != (ushort)Hid.UsagePage.MceRemote || deviceInfo.hid.usUsage != (ushort)Hid.MceRemoteUsage) sl@6: { sl@6: Debug.WriteLine("Not MCE remote page and usage."); sl@6: return; sl@6: } sl@0: sl@3: if (Enum.IsDefined(typeof(MceButton), rawData) && rawData!=0) //Our button is a known MCE button sl@3: { sl@3: if (this.ButtonPressed != null) //What's that? sl@3: { sl@3: this.ButtonPressed(this, new RemoteControlEventArgs((MceButton)rawData, GetDevice(message.LParam.ToInt32()))); sl@3: } sl@3: } sl@0: } sl@0: else if(raw.header.dwType == RIM_TYPEMOUSE) sl@0: { sl@0: // do mouse handling... sl@0: } sl@0: else if(raw.header.dwType == RIM_TYPEKEYBOARD) sl@0: { sl@0: // do keyboard handling... sl@0: } sl@0: } sl@0: finally sl@0: { sl@6: Marshal.FreeHGlobal(rawInputBuffer); sl@0: } sl@0: } sl@0: sl@0: sl@0: private InputDevice GetDevice(int param) sl@0: { sl@0: InputDevice inputDevice; sl@0: sl@0: switch ((int) (((ushort) (param >> 16)) & FAPPCOMMAND_MASK)) sl@0: { sl@0: case FAPPCOMMAND_OEM: sl@0: inputDevice = InputDevice.OEM; sl@0: break; sl@0: case FAPPCOMMAND_MOUSE: sl@0: inputDevice = InputDevice.Mouse; sl@0: break; sl@0: default: sl@0: inputDevice = InputDevice.Key; sl@0: break; sl@0: } sl@0: sl@0: return inputDevice; sl@0: } sl@0: } sl@0: }