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: }