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@0: namespace BruceThomas.Devices.RemoteControl sl@0: { 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@0: sl@0: #region RemoteControlEventArgs sl@0: sl@0: public class RemoteControlEventArgs : EventArgs sl@0: { sl@0: RemoteControlButton _rcb; sl@0: InputDevice _device; sl@0: sl@0: public RemoteControlEventArgs(RemoteControlButton rcb, InputDevice device) sl@0: { sl@0: _rcb = rcb; sl@0: _device = device; sl@0: } sl@0: sl@0: sl@0: public RemoteControlEventArgs() sl@0: { sl@0: _rcb = RemoteControlButton.Unknown; sl@0: _device = InputDevice.Key; sl@0: } 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@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@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@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 RAWINPUT_DETAILS = 0x209; sl@0: private const int RAWINPUT_GUIDE = 0x8D; sl@0: private const int RAWINPUT_TVJUMP = 0x25; sl@0: private const int RAWINPUT_STANDBY = 0x82; sl@0: private const int RAWINPUT_OEM1 = 0x80; sl@0: private const int RAWINPUT_OEM2 = 0x81; sl@0: private const int RAWINPUT_MYTV = 0x46; sl@0: private const int RAWINPUT_MYVIDEOS = 0x4A; sl@0: private const int RAWINPUT_MYPICTURES = 0x49; sl@0: private const int RAWINPUT_MYMUSIC = 0x47; sl@0: private const int RAWINPUT_RECORDEDTV = 0x48; sl@0: private const int RAWINPUT_DVDANGLE = 0x4B; sl@0: private const int RAWINPUT_DVDAUDIO = 0x4C; sl@0: private const int RAWINPUT_DVDMENU = 0x24; sl@0: private const int RAWINPUT_DVDSUBTITLE = 0x4D; sl@0: sl@0: private const int RIM_TYPEMOUSE = 0; sl@0: private const int RIM_TYPEKEYBOARD = 1; sl@0: private const int RIM_TYPEHID = 2; 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@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@0: RemoteControlButton rcb = RemoteControlButton.Unknown; 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@0: IntPtr buffer = Marshal.AllocHGlobal((int) dwSize); sl@0: try sl@0: { sl@0: if(buffer == IntPtr.Zero) sl@0: return; sl@0: sl@0: //Now read our RAWINPUT data sl@0: if (GetRawInputData(message.LParam, RID_INPUT, buffer, ref dwSize, (uint) Marshal.SizeOf(typeof(RAWINPUTHEADER))) != dwSize) sl@0: { sl@0: return; sl@0: } sl@0: sl@0: //Cast our buffer sl@0: RAWINPUT raw = (RAWINPUT)Marshal.PtrToStructure(buffer, typeof(RAWINPUT)); 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@0: byte* source = (byte*)buffer; sl@0: source += sizeof(RAWINPUTHEADER) + sizeof(RAWHID); sl@0: //source += 1; sl@0: pRawData = (int)source; sl@0: } sl@0: //int pRawData = buffer.ToUint32() + Marshal.SizeOf(typeof(RAWINPUT)) + 1; sl@0: sl@0: //Marshal.Copy(new IntPtr(pRawData), bRawData, 0, raw.hid.dwSizeHid - 1); sl@0: Marshal.Copy(new IntPtr(pRawData), bRawData, 0, raw.hid.dwSizeHid); sl@0: //int rawData = bRawData[0] | bRawData[1] << 8; sl@0: int rawData = bRawData[1]; //Get button code sl@2: Debug.WriteLine("HID " + raw.hid.dwCount + "/" + raw.hid.dwSizeHid + ":" + bRawData[0].ToString("X2") + bRawData[1].ToString("X2")); sl@0: sl@0: switch (rawData) sl@0: { sl@0: case RAWINPUT_DETAILS: sl@0: rcb = RemoteControlButton.Details; sl@0: break; sl@0: case RAWINPUT_GUIDE: sl@0: rcb = RemoteControlButton.Guide; sl@0: break; sl@0: case RAWINPUT_TVJUMP: sl@0: rcb = RemoteControlButton.TVJump; sl@0: break; sl@0: case RAWINPUT_STANDBY: sl@0: rcb = RemoteControlButton.StandBy; sl@0: break; sl@0: case RAWINPUT_OEM1: sl@0: rcb = RemoteControlButton.OEM1; sl@0: break; sl@0: case RAWINPUT_OEM2: sl@0: rcb = RemoteControlButton.OEM2; sl@0: break; sl@0: case RAWINPUT_MYTV: sl@0: rcb = RemoteControlButton.MyTV; sl@0: break; sl@0: case RAWINPUT_MYVIDEOS: sl@0: rcb = RemoteControlButton.MyVideos; sl@0: break; sl@0: case RAWINPUT_MYPICTURES: sl@0: rcb = RemoteControlButton.MyPictures; sl@0: break; sl@0: case RAWINPUT_MYMUSIC: sl@0: rcb = RemoteControlButton.MyMusic; sl@0: break; sl@0: case RAWINPUT_RECORDEDTV: sl@0: rcb = RemoteControlButton.RecordedTV; sl@0: break; sl@0: case RAWINPUT_DVDANGLE: sl@0: rcb = RemoteControlButton.DVDAngle; sl@0: break; sl@0: case RAWINPUT_DVDAUDIO: sl@0: rcb = RemoteControlButton.DVDAudio; sl@0: break; sl@0: case RAWINPUT_DVDMENU: sl@0: rcb = RemoteControlButton.DVDMenu; sl@0: break; sl@0: case RAWINPUT_DVDSUBTITLE: sl@0: rcb = RemoteControlButton.DVDSubtitle; sl@0: break; sl@0: } sl@0: sl@0: if (rcb != RemoteControlButton.Unknown && this.ButtonPressed != null) sl@0: this.ButtonPressed(this, new RemoteControlEventArgs(rcb, GetDevice(message.LParam.ToInt32()))); 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@0: Marshal.FreeHGlobal(buffer); 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: }