# HG changeset patch # User sl # Date 1417899165 -3600 # Node ID 305d2ecd3b1ad865795d859eb826bc44b32c7de1 # Parent 0166dfab3349a80a4220a3e895a0ef7e18faebfc HidEvent implementation. diff -r 0166dfab3349 -r 305d2ecd3b1a HidEvent.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/HidEvent.cs Sat Dec 06 21:52:45 2014 +0100 @@ -0,0 +1,206 @@ +using System; +using System.Windows.Forms; +using System.Runtime.InteropServices; +using System.Diagnostics; +using System.Text; +using Microsoft.Win32.SafeHandles; +using Win32; +using System.Collections.Generic; + + +namespace Hid +{ + /// + /// Represent a HID event. + /// + class HidEvent + { + public bool IsValid { get; private set; } + public bool IsForeground { get; private set; } + public bool IsBackground { get{return !IsForeground;} } + public bool IsMouse { get; private set; } + public bool IsKeyboard { get; private set; } + public bool IsGeneric { get; private set; } + + public HidDevice Device { get; private set; } + + public ushort UsagePage { get; private set; } + public ushort UsageCollection { get; private set; } + public List Usages { get; private set; } + + + /// + /// Initialize an HidEvent from a WM_INPUT message + /// + /// Device Handle as provided by RAWINPUTHEADER.hDevice, typically accessed as rawinput.header.hDevice + public HidEvent(Message aMessage) + { + IsValid = false; + IsKeyboard = false; + IsGeneric = false; + + Usages = new List(); + + if (aMessage.Msg != Const.WM_INPUT) + { + //Has to be a WM_INPUT message + return; + } + + if (Macro.GET_RAWINPUT_CODE_WPARAM(aMessage.WParam) == Const.RIM_INPUT) + { + IsForeground = true; + } + else if (Macro.GET_RAWINPUT_CODE_WPARAM(aMessage.WParam) == Const.RIM_INPUTSINK) + { + IsForeground = false; + } + + //Declare some pointers + IntPtr rawInputBuffer = IntPtr.Zero; + //My understanding is that this is basically our HID descriptor + IntPtr preParsedData = IntPtr.Zero; + + try + { + //Fetch raw input + RAWINPUT rawInput = new RAWINPUT(); + if (!RawInput.GetRawInputData(aMessage.LParam, ref rawInput, ref rawInputBuffer)) + { + return; + } + + //Fetch device info + RID_DEVICE_INFO deviceInfo = new RID_DEVICE_INFO(); + if (!RawInput.GetDeviceInfo(rawInput.header.hDevice, ref deviceInfo)) + { + return; + } + + //Get various information about this HID device + Device = new Hid.HidDevice(rawInput.header.hDevice); + + if (rawInput.header.dwType == Const.RIM_TYPEHID) //Check that our raw input is HID + { + IsGeneric = true; + + Debug.WriteLine("WM_INPUT source device is HID."); + //Get Usage Page and Usage + //Debug.WriteLine("Usage Page: 0x" + deviceInfo.hid.usUsagePage.ToString("X4") + " Usage ID: 0x" + deviceInfo.hid.usUsage.ToString("X4")); + UsagePage = deviceInfo.hid.usUsagePage; + UsageCollection = deviceInfo.hid.usUsage; + + preParsedData = RawInput.GetPreParsedData(rawInput.header.hDevice); + + if (!(rawInput.hid.dwSizeHid > 1 //Make sure our HID msg size more than 1. In fact the first ushort is irrelevant to us for now + && rawInput.hid.dwCount > 0)) //Check that we have at least one HID msg + { + return; + } + + //Allocate a buffer for one HID input + byte[] hidInputReport = new byte[rawInput.hid.dwSizeHid]; + + Debug.WriteLine("Raw input contains " + rawInput.hid.dwCount + " HID input report(s)"); + + //For each HID input report in our raw input + for (int i = 0; i < rawInput.hid.dwCount; i++) + { + //Compute the address from which to copy our HID input + int hidInputOffset = 0; + unsafe + { + byte* source = (byte*)rawInputBuffer; + source += sizeof(RAWINPUTHEADER) + sizeof(RAWHID) + (rawInput.hid.dwSizeHid * i); + hidInputOffset = (int)source; + } + + //Copy HID input into our buffer + Marshal.Copy(new IntPtr(hidInputOffset), hidInputReport, 0, (int)rawInput.hid.dwSizeHid); + + //Print HID input report in our debug output + string hidDump = "HID input report: "; + foreach (byte b in hidInputReport) + { + hidDump += b.ToString("X2"); + } + Debug.WriteLine(hidDump); + + //Proper parsing now + uint usageCount = 1; //Assuming a single usage per input report. Is that correct? + Win32.USAGE_AND_PAGE[] usages = new Win32.USAGE_AND_PAGE[usageCount]; + Win32.HidStatus status = Win32.Function.HidP_GetUsagesEx(Win32.HIDP_REPORT_TYPE.HidP_Input, 0, usages, ref usageCount, preParsedData, hidInputReport, (uint)hidInputReport.Length); + if (status != Win32.HidStatus.HIDP_STATUS_SUCCESS) + { + Debug.WriteLine("Could not parse HID data!"); + } + else + { + //Debug.WriteLine("UsagePage: 0x" + usages[0].UsagePage.ToString("X4")); + //Debug.WriteLine("Usage: 0x" + usages[0].Usage.ToString("X4")); + //Add this usage to our list + Usages.Add(usages[0].Usage); + } + } + + } + else if (rawInput.header.dwType == Const.RIM_TYPEMOUSE) + { + IsMouse = true; + + Debug.WriteLine("WM_INPUT source device is Mouse."); + // do mouse handling... + } + else if (rawInput.header.dwType == Const.RIM_TYPEKEYBOARD) + { + IsKeyboard = true; + + Debug.WriteLine("WM_INPUT source device is Keyboard."); + // do keyboard handling... + Debug.WriteLine("Type: " + deviceInfo.keyboard.dwType.ToString()); + Debug.WriteLine("SubType: " + deviceInfo.keyboard.dwSubType.ToString()); + Debug.WriteLine("Mode: " + deviceInfo.keyboard.dwKeyboardMode.ToString()); + Debug.WriteLine("Number of function keys: " + deviceInfo.keyboard.dwNumberOfFunctionKeys.ToString()); + Debug.WriteLine("Number of indicators: " + deviceInfo.keyboard.dwNumberOfIndicators.ToString()); + Debug.WriteLine("Number of keys total: " + deviceInfo.keyboard.dwNumberOfKeysTotal.ToString()); + } + } + finally + { + //Always executed when leaving our try block + Marshal.FreeHGlobal(rawInputBuffer); + Marshal.FreeHGlobal(preParsedData); + } + + IsValid = true; + } + + /// + /// Print information about this device to our debug output. + /// + public void DebugWrite() + { + if (!IsValid) + { + Debug.WriteLine("==== Invalid HidEvent"); + return; + } + Device.DebugWrite(); + if (IsGeneric) Debug.WriteLine("==== Generic"); + if (IsKeyboard) Debug.WriteLine("==== Keyboard"); + if (IsMouse) Debug.WriteLine("==== Mouse"); + Debug.WriteLine("==== Foreground: " + IsForeground.ToString()); + Debug.WriteLine("==== UsagePage: 0x" + UsagePage.ToString("X4")); + Debug.WriteLine("==== UsageCollection: 0x" + UsageCollection.ToString("X4")); + foreach (ushort usage in Usages) + { + Debug.WriteLine("==== Usage: 0x" + usage.ToString("X4")); + } + } + + + + + } + +} \ No newline at end of file diff -r 0166dfab3349 -r 305d2ecd3b1a HidUsageTables.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/HidUsageTables.cs Sat Dec 06 21:52:45 2014 +0100 @@ -0,0 +1,394 @@ +// +// +// + +namespace Hid +{ + /// + /// From USB HID usage tables. + /// http://www.usb.org/developers/hidpage#HID_Usage + /// http://www.usb.org/developers/devclass_docs/Hut1_12v2.pdf + /// + public enum UsagePage : ushort + { + Undefined = 0, + GenericDesktopControl, + SimulationControl, + VirtualRealityControl, + SportControl, + GameControl, + GenericDeviceControl, + Keyboard, + LightEmittingDiode, + Button, + Ordinal, + Telephony, + Consumer, + Digitiser, + PhysicalInterfaceDevice = 0x0f, + Unicode = 0x10, + AlphaNumericDisplay = 0x14, + MedicalInstruments = 0x40, + MonitorPage0 = 0x80, + MonitorPage1, + MonitorPage2, + MonitorPage3, + PowerPage0, + PowerPage1, + PowerPage2, + PowerPage3, + BarCodeScanner = 0x8c, + Scale, + MagneticStripeReader, + ReservedPointOfSale, + CameraControl, + Arcade, + // http://msdn.microsoft.com/en-us/library/windows/desktop/bb417079.aspx + MceRemote = 0xffbc, + TerraTecRemote = 0xffcc + } + + public enum UsageIdGenericDesktop : ushort + { + Pointer = 0x01, + Mouse = 0x02, + Joystick = 0x04, + GamePad = 0x05, + Keyboard = 0x06, + KeyPad = 0x07, + MultiAxisController = 0x08, + TabletPCSystemControls = 0x09, + SystemControl = 0x80 + } + + public enum UsageIdConsumer : ushort + { + ConsumerControl = 0x01, + NumericKeyPad = 0x02, + ProgrammableButtons = 0x03, + Microphone = 0x04, + Headphone = 0x05, + GraphicEqualizer = 0x06, + Selection = 0x80, + } + + + public enum UsageIdMce: ushort + { + MceRemote = 0x88 + } + + + + namespace UsageTables + { + /// + /// + /// + public enum MceButton: ushort + { + /// + /// Not defined by the Microsoft specs. + /// + Null = 0x00, + GreenStart = 0x0D, + ClosedCaptioning = 0x2B, + Teletext = 0x5A, + TeletextRed = 0x5B, + TeletextGreen = 0x5C, + TeletextYellow = 0x5D, + TeletextBlue = 0x5E, + LiveTv = 0x25, + Music = 0x47, + RecordedTv = 0x48, + Pictures = 0x49, + Videos = 0x4A, + FmRadio = 0x50, + Extras = 0x3C, + ExtrasApp = 0x3D, + DvdMenu = 0x24, + DvdAngle = 0x4B, + DvdAudio = 0x4C, + DvdSubtitle = 0x4D, + /// + /// First press action: Ejects a DVD drive. + /// + /// Second press action: Repeats first press action. + /// + /// Notably issued by XBOX360 remote as defined in irplus - Remote Control - Android application. + /// + Eject = 0x28, + DvdTopMenu = 0x43, + /// + /// First press action: Generates EXTn HID message in the Media Center Vendor Specific + /// Collection (page 0xFFBC, usage 0x88). + /// + /// Second press action: Repeats message. + /// + /// Auto-repeat: No + /// + /// Notably sent by the 'Visualization' button of HP Windows Media Center Remote (TSGH-IR08). + /// + /// According to HP specs it displays visual imagery that is synchronized to the sound of your music tracks. + /// + Ext0 = 0x32, + /// + /// First press action: Generates EXTn HID message in the Media Center Vendor Specific + /// Collection (page 0xFFBC, usage 0x88). + /// + /// Second press action: Repeats message. + /// + /// Auto-repeat: No + /// + /// Notably sent by the 'Slide Show' button of HP Windows Media Center Remote (TSGH-IR08). + /// + /// According to HP specs it plays a slide show of all the pictures on your hard disk drive. + /// + Ext1 = 0x33, + /// + /// First press action: Generates EXTn HID message in the Media Center Vendor Specific + /// Collection (page 0xFFBC, usage 0x88). + /// + /// Second press action: Repeats message. + /// + /// Auto-repeat: No + /// + /// Notably sent by the 'Eject' button of HP Windows Media Center Remote (TSGH-IR08). + /// Also interpreted as 'Eject' action by SoundGraph iMON Manager in MCE mode (OrigenAE VF310). + /// + Ext2 = 0x34, + /// + /// First press action: Generates EXTn HID message in the Media Center Vendor Specific + /// Collection (page 0xFFBC, usage 0x88). + /// + /// Second press action: Repeats message. + /// + /// Auto-repeat: No + /// + /// Notably sent by the 'Input selection' button of HP Windows Media Center Remote (TSGH-IR08). + /// + Ext3 = 0x35, + Ext4 = 0x36, + Ext5 = 0x37, + Ext6 = 0x38, + Ext7 = 0x39, + Ext8 = 0x3A, + Ext9 = 0x80, + Ext10 = 0x81, + Ext11 = 0x6F, + Zoom = 0x27, + ChannelInput = 0x42, + SubAudio = 0x2D, + Channel10 = 0x3E, + Channel11 = 0x3F, + Channel12 = 0x40, + /// + /// First press action: Generates OEM2 HID message in the Media Center Vendor Specific + /// Collection. This button is intended to control the front panel display of home entertainment + /// computers. When this button is pressed, the display could be turned on or off, or the display + /// mode could change. + /// + /// Second press action: Repeats message. + /// + /// Auto-repeat: No + /// + /// Notably issued by XBOX360 remote as defined in irplus - Remote Control - Android application. + /// + Display = 0x4F, + /// + /// First press action: To be determined. + /// + /// Second press action: Repeats message. + /// + /// Auto-repeat: No + /// + Kiosk = 0x6A, + NetworkSelection = 0x2C, + BlueRayTool = 0x78, + ChannelInfo = 0x41, + VideoSelection = 0x61 + } + + /// + /// Those codes come from experimenting with HP remotes. + /// + public enum HpMceButton: ushort + { + /// + /// Displays visual imagery that is synchronized to the sound of your music tracks. + /// + /// Second press action: Repeats message. + /// + /// Auto-repeat: No + /// + /// Notably sent by the 'Visualization' button of HP Windows Media Center Remote (TSGH-IR08). + /// + /// According to HP specs it displays visual imagery that is synchronized to the sound of your music tracks. + /// + Visualization = MceButton.Ext0, + /// + /// Plays a slide show of all the pictures on your hard disk drive. + /// + /// Second press action: Repeats message. + /// + /// Auto-repeat: No + /// + /// Notably sent by the 'Slide Show' button of HP Windows Media Center Remote (TSGH-IR08). + /// + /// According to HP specs it plays a slide show of all the pictures on your hard disk drive. + /// + SlideShow = MceButton.Ext1, + /// + /// Eject optical drive. + /// + /// Second press action: Repeats message. + /// + /// Auto-repeat: No + /// + /// Notably sent by the 'Eject' button of HP Windows Media Center Remote (TSGH-IR08). + /// Also interpreted as 'Eject' action by SoundGraph iMON Manager in MCE mode (OrigenAE VF310). + /// + Eject = MceButton.Ext2, + /// + /// Not sure what this should do. + /// + /// Second press action: Repeats message. + /// + /// Auto-repeat: No + /// + /// Notably sent by the 'Input selection' button of HP Windows Media Center Remote (TSGH-IR08). + /// + InputSelection = MceButton.Ext3, + } + + /// + /// Usage Table for Consumer Controls + /// 0x0C 0X01 + /// + public enum ConsumerControl: ushort + { + Null = 0x0000, + // + Channel = 0x0086, + MediaSelection = 0x0087, + MediaSelectComputer = 0x0088, + MediaSelectTV = 0x0089, + MediaSelectWWW = 0x008A, + MediaSelectDVD = 0x008B, + MediaSelectTelephone = 0x008C, + MediaSelectProgramGuide = 0x008D, + MediaSelectVideoPhone = 0x008E, + MediaSelectGames = 0x008F, + MediaSelectMessages = 0x0090, + MediaSelectCD = 0x0091, + MediaSelectVCR = 0x0092, + MediaSelectTuner = 0x0093, + Quit = 0x0094, + Help = 0x0095, + MediaSelectTape = 0x0096, + MediaSelectCable = 0x0097, + MediaSelectSatellite = 0x0098, + MediaSelectSecurity = 0x0099, + MediaSelectHome = 0x009A, + MediaSelectCall = 0x009B, + ChannelIncrement = 0x009C, + ChannelDecrement = 0x009D, + MediaSelectSAP = 0x009E, + // + Play = 0x00B0, + Pause = 0x00B1, + Record = 0x00B2, + FastForward = 0x00B3, + Rewind = 0x00B4, + ScanNextTrack = 0x00B5, + ScanPreviousTrack = 0x00B6, + Stop = 0x00B7, + Eject = 0x00B8, + RandomPlay = 0x00B9, + SelectDisc = 0x00BA, + EnterDisc = 0x00BB, + Repeat = 0x00BC, + Tracking = 0x00BD, + TrackNormal = 0x00BE, + SlowTracking = 0x00BF, + FrameForward = 0x00C0, + FrameBack = 0x00C1, + Mark = 0x00C2, + ClearMark = 0x00C3, + RepeatFromMark = 0x00C4, + ReturnToMark = 0x00C5, + SearchMarkForward = 0x00C6, + SearchMarkBackwards = 0x00C7, + CounterReset = 0x00C8, + ShowCounter = 0x00C9, + TrackingIncrement = 0x00CA, + TrackingDecrement = 0x00CB, + StopEject = 0x00CC, + PlayPause = 0x00CD, + PlaySkip = 0x00CE, + + /// + /// Audio controls + /// + Volume = 0x00E0, + Balance = 0x00E1, + Mute = 0x00E2, + Bass = 0x00E3, + Treble = 0x00E4, + BassBoost = 0x00E5, + SurroundMode = 0x00E6, + Loudness = 0x00E7, + MPX = 0x00E8, + VolumeIncrement = 0x00E9, + VolumeDecrement = 0x00EA, + + //Generic GUI Application Controls + GenericGUIApplicationControls = 0x0200, + AppCtrlNew = 0x0201, + AppCtrlOpen = 0x0202, + AppCtrlClose = 0x0203, + AppCtrlExit = 0x0204, + AppCtrlMaximize = 0x0205, + AppCtrlMinimize = 0x0206, + AppCtrlSave = 0x0207, + AppCtrlPrint = 0x0208, + AppCtrlProperties = 0x0209, + AppCtrlUndo = 0x021A, + AppCtrlCopy = 0x021B, + AppCtrlCut = 0x021C, + AppCtrlPaste = 0x021D, + AppCtrlSelectAll = 0x021E, + AppCtrlFind = 0x021F, + AppCtrlFindAndReplace = 0x0220, + AppCtrlSearch = 0x0221, + AppCtrlGoTo = 0x0222, + AppCtrlHome = 0x0223, + AppCtrlBack = 0x0224, + AppCtrlForward = 0x0225, + AppCtrlStop = 0x0226, + AppCtrlRefresh = 0x0227, + AppCtrlPreviousLink = 0x0228, + AppCtrlNextLink = 0x0229, + AppCtrlBookmarks = 0x022A, + AppCtrlHistory = 0x022B, + AppCtrlSubscriptions = 0x022C, + AppCtrlZoomIn = 0x022D, + AppCtrlZoomOut = 0x022E, + AppCtrlZoom = 0x022F, + AppCtrlFullScreenView = 0x0230, + AppCtrlNormalView = 0x0231, + AppCtrlViewToggle = 0x0232, + AppCtrlScrollUp = 0x0233, + AppCtrlScrollDown = 0x0234, + AppCtrlScroll = 0x0235, + AppCtrlPanLeft = 0x0236, + AppCtrlPanRight = 0x0237, + AppCtrlPan = 0x0238, + AppCtrlNewWindow = 0x0239, + AppCtrlTileHorizontally = 0x023A, + AppCtrlTileVertically = 0x023B, + AppCtrlFormat = 0x023C, + AppCtrlEdit = 0x023D, + } + } +} \ No newline at end of file diff -r 0166dfab3349 -r 305d2ecd3b1a HumanInterfaceDevice.cs --- a/HumanInterfaceDevice.cs Sat Dec 06 13:14:16 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,394 +0,0 @@ -// -// -// - -namespace Hid -{ - /// - /// From USB HID usage tables. - /// http://www.usb.org/developers/hidpage#HID_Usage - /// http://www.usb.org/developers/devclass_docs/Hut1_12v2.pdf - /// - public enum UsagePage : ushort - { - Undefined = 0, - GenericDesktopControl, - SimulationControl, - VirtualRealityControl, - SportControl, - GameControl, - GenericDeviceControl, - Keyboard, - LightEmittingDiode, - Button, - Ordinal, - Telephony, - Consumer, - Digitiser, - PhysicalInterfaceDevice = 0x0f, - Unicode = 0x10, - AlphaNumericDisplay = 0x14, - MedicalInstruments = 0x40, - MonitorPage0 = 0x80, - MonitorPage1, - MonitorPage2, - MonitorPage3, - PowerPage0, - PowerPage1, - PowerPage2, - PowerPage3, - BarCodeScanner = 0x8c, - Scale, - MagneticStripeReader, - ReservedPointOfSale, - CameraControl, - Arcade, - // http://msdn.microsoft.com/en-us/library/windows/desktop/bb417079.aspx - MceRemote = 0xffbc, - TerraTecRemote = 0xffcc - } - - public enum UsageIdGenericDesktop : ushort - { - Pointer = 0x01, - Mouse = 0x02, - Joystick = 0x04, - GamePad = 0x05, - Keyboard = 0x06, - KeyPad = 0x07, - MultiAxisController = 0x08, - TabletPCSystemControls = 0x09, - SystemControl = 0x80 - } - - public enum UsageIdConsumer : ushort - { - ConsumerControl = 0x01, - NumericKeyPad = 0x02, - ProgrammableButtons = 0x03, - Microphone = 0x04, - Headphone = 0x05, - GraphicEqualizer = 0x06, - Selection = 0x80, - } - - - public enum UsageIdMce: ushort - { - MceRemote = 0x88 - } - - - - namespace UsageTables - { - /// - /// - /// - public enum MceButton: ushort - { - /// - /// Not defined by the Microsoft specs. - /// - Null = 0x00, - GreenStart = 0x0D, - ClosedCaptioning = 0x2B, - Teletext = 0x5A, - TeletextRed = 0x5B, - TeletextGreen = 0x5C, - TeletextYellow = 0x5D, - TeletextBlue = 0x5E, - LiveTv = 0x25, - Music = 0x47, - RecordedTv = 0x48, - Pictures = 0x49, - Videos = 0x4A, - FmRadio = 0x50, - Extras = 0x3C, - ExtrasApp = 0x3D, - DvdMenu = 0x24, - DvdAngle = 0x4B, - DvdAudio = 0x4C, - DvdSubtitle = 0x4D, - /// - /// First press action: Ejects a DVD drive. - /// - /// Second press action: Repeats first press action. - /// - /// Notably issued by XBOX360 remote as defined in irplus - Remote Control - Android application. - /// - Eject = 0x28, - DvdTopMenu = 0x43, - /// - /// First press action: Generates EXTn HID message in the Media Center Vendor Specific - /// Collection (page 0xFFBC, usage 0x88). - /// - /// Second press action: Repeats message. - /// - /// Auto-repeat: No - /// - /// Notably sent by the 'Visualization' button of HP Windows Media Center Remote (TSGH-IR08). - /// - /// According to HP specs it displays visual imagery that is synchronized to the sound of your music tracks. - /// - Ext0 = 0x32, - /// - /// First press action: Generates EXTn HID message in the Media Center Vendor Specific - /// Collection (page 0xFFBC, usage 0x88). - /// - /// Second press action: Repeats message. - /// - /// Auto-repeat: No - /// - /// Notably sent by the 'Slide Show' button of HP Windows Media Center Remote (TSGH-IR08). - /// - /// According to HP specs it plays a slide show of all the pictures on your hard disk drive. - /// - Ext1 = 0x33, - /// - /// First press action: Generates EXTn HID message in the Media Center Vendor Specific - /// Collection (page 0xFFBC, usage 0x88). - /// - /// Second press action: Repeats message. - /// - /// Auto-repeat: No - /// - /// Notably sent by the 'Eject' button of HP Windows Media Center Remote (TSGH-IR08). - /// Also interpreted as 'Eject' action by SoundGraph iMON Manager in MCE mode (OrigenAE VF310). - /// - Ext2 = 0x34, - /// - /// First press action: Generates EXTn HID message in the Media Center Vendor Specific - /// Collection (page 0xFFBC, usage 0x88). - /// - /// Second press action: Repeats message. - /// - /// Auto-repeat: No - /// - /// Notably sent by the 'Input selection' button of HP Windows Media Center Remote (TSGH-IR08). - /// - Ext3 = 0x35, - Ext4 = 0x36, - Ext5 = 0x37, - Ext6 = 0x38, - Ext7 = 0x39, - Ext8 = 0x3A, - Ext9 = 0x80, - Ext10 = 0x81, - Ext11 = 0x6F, - Zoom = 0x27, - ChannelInput = 0x42, - SubAudio = 0x2D, - Channel10 = 0x3E, - Channel11 = 0x3F, - Channel12 = 0x40, - /// - /// First press action: Generates OEM2 HID message in the Media Center Vendor Specific - /// Collection. This button is intended to control the front panel display of home entertainment - /// computers. When this button is pressed, the display could be turned on or off, or the display - /// mode could change. - /// - /// Second press action: Repeats message. - /// - /// Auto-repeat: No - /// - /// Notably issued by XBOX360 remote as defined in irplus - Remote Control - Android application. - /// - Display = 0x4F, - /// - /// First press action: To be determined. - /// - /// Second press action: Repeats message. - /// - /// Auto-repeat: No - /// - Kiosk = 0x6A, - NetworkSelection = 0x2C, - BlueRayTool = 0x78, - ChannelInfo = 0x41, - VideoSelection = 0x61 - } - - /// - /// Those codes come from experimenting with HP remotes. - /// - public enum HpMceButton: ushort - { - /// - /// Displays visual imagery that is synchronized to the sound of your music tracks. - /// - /// Second press action: Repeats message. - /// - /// Auto-repeat: No - /// - /// Notably sent by the 'Visualization' button of HP Windows Media Center Remote (TSGH-IR08). - /// - /// According to HP specs it displays visual imagery that is synchronized to the sound of your music tracks. - /// - Visualization = MceButton.Ext0, - /// - /// Plays a slide show of all the pictures on your hard disk drive. - /// - /// Second press action: Repeats message. - /// - /// Auto-repeat: No - /// - /// Notably sent by the 'Slide Show' button of HP Windows Media Center Remote (TSGH-IR08). - /// - /// According to HP specs it plays a slide show of all the pictures on your hard disk drive. - /// - SlideShow = MceButton.Ext1, - /// - /// Eject optical drive. - /// - /// Second press action: Repeats message. - /// - /// Auto-repeat: No - /// - /// Notably sent by the 'Eject' button of HP Windows Media Center Remote (TSGH-IR08). - /// Also interpreted as 'Eject' action by SoundGraph iMON Manager in MCE mode (OrigenAE VF310). - /// - Eject = MceButton.Ext2, - /// - /// Not sure what this should do. - /// - /// Second press action: Repeats message. - /// - /// Auto-repeat: No - /// - /// Notably sent by the 'Input selection' button of HP Windows Media Center Remote (TSGH-IR08). - /// - InputSelection = MceButton.Ext3, - } - - /// - /// Usage Table for Consumer Controls - /// 0x0C 0X01 - /// - public enum ConsumerControl: ushort - { - Null = 0x0000, - // - Channel = 0x0086, - MediaSelection = 0x0087, - MediaSelectComputer = 0x0088, - MediaSelectTV = 0x0089, - MediaSelectWWW = 0x008A, - MediaSelectDVD = 0x008B, - MediaSelectTelephone = 0x008C, - MediaSelectProgramGuide = 0x008D, - MediaSelectVideoPhone = 0x008E, - MediaSelectGames = 0x008F, - MediaSelectMessages = 0x0090, - MediaSelectCD = 0x0091, - MediaSelectVCR = 0x0092, - MediaSelectTuner = 0x0093, - Quit = 0x0094, - Help = 0x0095, - MediaSelectTape = 0x0096, - MediaSelectCable = 0x0097, - MediaSelectSatellite = 0x0098, - MediaSelectSecurity = 0x0099, - MediaSelectHome = 0x009A, - MediaSelectCall = 0x009B, - ChannelIncrement = 0x009C, - ChannelDecrement = 0x009D, - MediaSelectSAP = 0x009E, - // - Play = 0x00B0, - Pause = 0x00B1, - Record = 0x00B2, - FastForward = 0x00B3, - Rewind = 0x00B4, - ScanNextTrack = 0x00B5, - ScanPreviousTrack = 0x00B6, - Stop = 0x00B7, - Eject = 0x00B8, - RandomPlay = 0x00B9, - SelectDisc = 0x00BA, - EnterDisc = 0x00BB, - Repeat = 0x00BC, - Tracking = 0x00BD, - TrackNormal = 0x00BE, - SlowTracking = 0x00BF, - FrameForward = 0x00C0, - FrameBack = 0x00C1, - Mark = 0x00C2, - ClearMark = 0x00C3, - RepeatFromMark = 0x00C4, - ReturnToMark = 0x00C5, - SearchMarkForward = 0x00C6, - SearchMarkBackwards = 0x00C7, - CounterReset = 0x00C8, - ShowCounter = 0x00C9, - TrackingIncrement = 0x00CA, - TrackingDecrement = 0x00CB, - StopEject = 0x00CC, - PlayPause = 0x00CD, - PlaySkip = 0x00CE, - - /// - /// Audio controls - /// - Volume = 0x00E0, - Balance = 0x00E1, - Mute = 0x00E2, - Bass = 0x00E3, - Treble = 0x00E4, - BassBoost = 0x00E5, - SurroundMode = 0x00E6, - Loudness = 0x00E7, - MPX = 0x00E8, - VolumeIncrement = 0x00E9, - VolumeDecrement = 0x00EA, - - //Generic GUI Application Controls - GenericGUIApplicationControls = 0x0200, - AppCtrlNew = 0x0201, - AppCtrlOpen = 0x0202, - AppCtrlClose = 0x0203, - AppCtrlExit = 0x0204, - AppCtrlMaximize = 0x0205, - AppCtrlMinimize = 0x0206, - AppCtrlSave = 0x0207, - AppCtrlPrint = 0x0208, - AppCtrlProperties = 0x0209, - AppCtrlUndo = 0x021A, - AppCtrlCopy = 0x021B, - AppCtrlCut = 0x021C, - AppCtrlPaste = 0x021D, - AppCtrlSelectAll = 0x021E, - AppCtrlFind = 0x021F, - AppCtrlFindAndReplace = 0x0220, - AppCtrlSearch = 0x0221, - AppCtrlGoTo = 0x0222, - AppCtrlHome = 0x0223, - AppCtrlBack = 0x0224, - AppCtrlForward = 0x0225, - AppCtrlStop = 0x0226, - AppCtrlRefresh = 0x0227, - AppCtrlPreviousLink = 0x0228, - AppCtrlNextLink = 0x0229, - AppCtrlBookmarks = 0x022A, - AppCtrlHistory = 0x022B, - AppCtrlSubscriptions = 0x022C, - AppCtrlZoomIn = 0x022D, - AppCtrlZoomOut = 0x022E, - AppCtrlZoom = 0x022F, - AppCtrlFullScreenView = 0x0230, - AppCtrlNormalView = 0x0231, - AppCtrlViewToggle = 0x0232, - AppCtrlScrollUp = 0x0233, - AppCtrlScrollDown = 0x0234, - AppCtrlScroll = 0x0235, - AppCtrlPanLeft = 0x0236, - AppCtrlPanRight = 0x0237, - AppCtrlPan = 0x0238, - AppCtrlNewWindow = 0x0239, - AppCtrlTileHorizontally = 0x023A, - AppCtrlTileVertically = 0x023B, - AppCtrlFormat = 0x023C, - AppCtrlEdit = 0x023D, - } - } -} \ No newline at end of file diff -r 0166dfab3349 -r 305d2ecd3b1a RemoteControlDevice.cs --- a/RemoteControlDevice.cs Sat Dec 06 13:14:16 2014 +0100 +++ b/RemoteControlDevice.cs Sat Dec 06 21:52:45 2014 +0100 @@ -13,93 +13,93 @@ namespace Devices.RemoteControl { - public enum InputDevice - { - Key, - Mouse, - OEM - } + public enum InputDevice + { + Key, + Mouse, + OEM + } - public enum RemoteControlButton - { - Clear, - Down, - Left, - Digit0, - Digit1, - Digit2, - Digit3, - Digit4, - Digit5, - Digit6, - Digit7, - Digit8, - Digit9, - Enter, - Right, - Up, + public enum RemoteControlButton + { + Clear, + Down, + Left, + Digit0, + Digit1, + Digit2, + Digit3, + Digit4, + Digit5, + Digit6, + Digit7, + Digit8, + Digit9, + Enter, + Right, + Up, - Back, - ChannelDown, - ChannelUp, - FastForward, - VolumeMute, - Pause, - Play, + Back, + ChannelDown, + ChannelUp, + FastForward, + VolumeMute, + Pause, + Play, PlayPause, - Record, - PreviousTrack, - Rewind, - NextTrack, - Stop, - VolumeDown, - VolumeUp, + Record, + PreviousTrack, + Rewind, + NextTrack, + Stop, + VolumeDown, + VolumeUp, - RecordedTV, - Guide, - LiveTV, - MoreInfo, + RecordedTV, + Guide, + LiveTV, + MoreInfo, Print, - DVDMenu, - DVDAngle, - DVDAudio, - DVDSubtitle, - MyMusic, - MyPictures, - MyVideos, - MyTV, - OEM1, - OEM2, - StandBy, - TVJump, + DVDMenu, + DVDAngle, + DVDAudio, + DVDSubtitle, + MyMusic, + MyPictures, + MyVideos, + MyTV, + OEM1, + OEM2, + StandBy, + TVJump, - Unknown - } + Unknown + } - #region RemoteControlEventArgs + #region RemoteControlEventArgs - public class RemoteControlEventArgs : EventArgs - { + public class RemoteControlEventArgs : EventArgs + { RemoteControlButton _rcb; - InputDevice _device; + InputDevice _device; MceButton iMceButton; ConsumerControl iConsumerControl; public RemoteControlEventArgs(RemoteControlButton rcb, InputDevice device) - { + { SetNullButtons(); // - _rcb = rcb; - _device = device; - } + _rcb = rcb; + _device = device; + } public RemoteControlEventArgs(ConsumerControl aConsumerControl, InputDevice device) { SetNullButtons(); // - iConsumerControl = aConsumerControl; + iConsumerControl = aConsumerControl; _device = device; } @@ -108,7 +108,7 @@ { SetNullButtons(); // - iMceButton = mce; + iMceButton = mce; _device = device; } @@ -119,18 +119,18 @@ _rcb = RemoteControlButton.Unknown; } - public RemoteControlEventArgs() - { + public RemoteControlEventArgs() + { iMceButton = MceButton.Null; - _rcb = RemoteControlButton.Unknown; - _device = InputDevice.Key; - } + _rcb = RemoteControlButton.Unknown; + _device = InputDevice.Key; + } - public RemoteControlButton Button - { - get { return _rcb; } - set { _rcb = value; } - } + public RemoteControlButton Button + { + get { return _rcb; } + set { _rcb = value; } + } public MceButton MceButton { @@ -144,20 +144,20 @@ set { iConsumerControl = value; } } - public InputDevice Device - { - get { return _device; } - set { _device = value; } - } - } + public InputDevice Device + { + get { return _device; } + set { _device = value; } + } + } - #endregion RemoteControlEventArgs + #endregion RemoteControlEventArgs - public sealed class RemoteControlDevice - { - public delegate bool RemoteControlDeviceEventHandler(object sender, RemoteControlEventArgs e); - public event RemoteControlDeviceEventHandler ButtonPressed; + public sealed class RemoteControlDevice + { + public delegate bool RemoteControlDeviceEventHandler(object sender, RemoteControlEventArgs e); + public event RemoteControlDeviceEventHandler ButtonPressed; /// /// Return true if the usage was processed. @@ -165,22 +165,22 @@ /// /// public delegate bool HidUsageHandler(ushort aUsage); - - //------------------------------------------------------------- - // constructors - //------------------------------------------------------------- - public RemoteControlDevice(IntPtr aHWND) - { - // Register the input device to receive the commands from the - // remote device. See http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnwmt/html/remote_control.asp - // for the vendor defined usage page. + //------------------------------------------------------------- + // constructors + //------------------------------------------------------------- - RAWINPUTDEVICE[] rid = new RAWINPUTDEVICE[5]; + public RemoteControlDevice(IntPtr aHWND) + { + // Register the input device to receive the commands from the + // remote device. See http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnwmt/html/remote_control.asp + // for the vendor defined usage page. + + RAWINPUTDEVICE[] rid = new RAWINPUTDEVICE[4]; int i = 0; - rid[i].usUsagePage = (ushort)Hid.UsagePage.MceRemote; + rid[i].usUsagePage = (ushort)Hid.UsagePage.MceRemote; rid[i].usUsage = (ushort)Hid.UsageIdMce.MceRemote; rid[i].dwFlags = Const.RIDEV_EXINPUTSINK; rid[i].hwndTarget = aHWND; @@ -203,11 +203,11 @@ rid[i].dwFlags = Const.RIDEV_EXINPUTSINK; rid[i].hwndTarget = aHWND; - i++; - rid[i].usUsagePage = (ushort)Hid.UsagePage.GenericDesktopControl; - rid[i].usUsage = (ushort)Hid.UsageIdGenericDesktop.Keyboard; - rid[i].dwFlags = Const.RIDEV_EXINPUTSINK; - rid[i].hwndTarget = aHWND; + //i++; + //rid[i].usUsagePage = (ushort)Hid.UsagePage.GenericDesktopControl; + //rid[i].usUsage = (ushort)Hid.UsageIdGenericDesktop.Keyboard; + //rid[i].dwFlags = Const.RIDEV_EXINPUTSINK; + //rid[i].hwndTarget = aHWND; //i++; //rid[i].usUsagePage = (ushort)Hid.UsagePage.GenericDesktopControl; @@ -216,55 +216,55 @@ //rid[i].hwndTarget = aHWND; - if (!Function.RegisterRawInputDevices(rid,(uint) rid.Length,(uint) Marshal.SizeOf(rid[0]))) - { + if (!Function.RegisterRawInputDevices(rid, (uint)rid.Length, (uint)Marshal.SizeOf(rid[0]))) + { throw new ApplicationException("Failed to register raw input devices: " + Marshal.GetLastWin32Error().ToString()); - } - } + } + } - //------------------------------------------------------------- - // methods - //------------------------------------------------------------- + //------------------------------------------------------------- + // methods + //------------------------------------------------------------- - public void ProcessMessage(Message message) - { - switch (message.Msg) - { - case Const.WM_KEYDOWN: + public void ProcessMessage(Message message) + { + switch (message.Msg) + { + case Const.WM_KEYDOWN: ProcessKeyDown(message.WParam); - break; + break; case Const.WM_INPUT: //Returning zero means we processed that message. message.Result = new IntPtr(0); - ProcessInputCommand(ref message); - break; - } + ProcessInputCommand(ref message); + break; + } - } + } - //------------------------------------------------------------- - // methods (helpers) - //------------------------------------------------------------- + //------------------------------------------------------------- + // methods (helpers) + //------------------------------------------------------------- - private void ProcessKeyDown(IntPtr wParam) - { - RemoteControlButton rcb = RemoteControlButton.Unknown; + private void ProcessKeyDown(IntPtr wParam) + { + RemoteControlButton rcb = RemoteControlButton.Unknown; switch (wParam.ToInt32()) - { - case (int) Keys.Escape: - rcb = RemoteControlButton.Clear; + { + case (int)Keys.Escape: + rcb = RemoteControlButton.Clear; break; case (int)Keys.Up: rcb = RemoteControlButton.Up; break; - case (int) Keys.Down: - rcb = RemoteControlButton.Down; - break; - case (int) Keys.Left: - rcb = RemoteControlButton.Left; + case (int)Keys.Down: + rcb = RemoteControlButton.Down; + break; + case (int)Keys.Left: + rcb = RemoteControlButton.Left; break; case (int)Keys.Right: rcb = RemoteControlButton.Right; @@ -272,44 +272,44 @@ case (int)Keys.Enter: rcb = RemoteControlButton.Enter; break; - case (int) Keys.D0: - rcb = RemoteControlButton.Digit0; - break; - case (int) Keys.D1: - rcb = RemoteControlButton.Digit1; - break; - case (int) Keys.D2: - rcb = RemoteControlButton.Digit2; - break; - case (int) Keys.D3: - rcb = RemoteControlButton.Digit3; - break; - case (int) Keys.D4: - rcb = RemoteControlButton.Digit4; - break; - case (int) Keys.D5: - rcb = RemoteControlButton.Digit5; - break; - case (int) Keys.D6: - rcb = RemoteControlButton.Digit6; - break; - case (int) Keys.D7: - rcb = RemoteControlButton.Digit7; - break; - case (int) Keys.D8: - rcb = RemoteControlButton.Digit8; - break; - case (int) Keys.D9: - rcb = RemoteControlButton.Digit9; + case (int)Keys.D0: + rcb = RemoteControlButton.Digit0; break; - } + case (int)Keys.D1: + rcb = RemoteControlButton.Digit1; + break; + case (int)Keys.D2: + rcb = RemoteControlButton.Digit2; + break; + case (int)Keys.D3: + rcb = RemoteControlButton.Digit3; + break; + case (int)Keys.D4: + rcb = RemoteControlButton.Digit4; + break; + case (int)Keys.D5: + rcb = RemoteControlButton.Digit5; + break; + case (int)Keys.D6: + rcb = RemoteControlButton.Digit6; + break; + case (int)Keys.D7: + rcb = RemoteControlButton.Digit7; + break; + case (int)Keys.D8: + rcb = RemoteControlButton.Digit8; + break; + case (int)Keys.D9: + rcb = RemoteControlButton.Digit9; + break; + } if (this.ButtonPressed != null && rcb != RemoteControlButton.Unknown) { Debug.WriteLine("KeyDown: " + rcb.ToString()); this.ButtonPressed(this, new RemoteControlEventArgs(rcb, InputDevice.Key)); } - } + } /// @@ -356,7 +356,7 @@ { if (this.ButtonPressed != null) { - return this.ButtonPressed(this, new RemoteControlEventArgs((MceButton)aUsage, InputDevice.OEM)); + return this.ButtonPressed(this, new RemoteControlEventArgs((MceButton)aUsage, InputDevice.OEM)); } return false; } @@ -368,156 +368,45 @@ } - private void ProcessInputCommand(ref Message message) - { + private void ProcessInputCommand(ref Message message) + { //We received a WM_INPUT message Debug.WriteLine("================WM_INPUT================"); - //Check if we received this message while in background or foreground - if (Macro.GET_RAWINPUT_CODE_WPARAM(message.WParam) == Const.RIM_INPUT) + Hid.HidEvent hidEvent = new Hid.HidEvent(message); + hidEvent.DebugWrite(); + + if (!hidEvent.IsValid || !hidEvent.IsGeneric) { - Debug.WriteLine("================FOREGROUND"); - } - else if (Macro.GET_RAWINPUT_CODE_WPARAM(message.WParam) == Const.RIM_INPUTSINK) - { - Debug.WriteLine("================BACKGROUND"); + Debug.WriteLine("Skipping HID message."); + return; } - //Declare some pointers - IntPtr rawInputBuffer = IntPtr.Zero; - //My understanding is that this is basically our HID descriptor - IntPtr preParsedData = IntPtr.Zero; - try + HidUsageHandler usagePageHandler = null; + + //Check if this an MCE remote HID message + if (hidEvent.UsagePage == (ushort)Hid.UsagePage.MceRemote && hidEvent.UsageCollection == (ushort)Hid.UsageIdMce.MceRemote) { - //Fetch raw input - RAWINPUT rawInput = new RAWINPUT(); - if (!RawInput.GetRawInputData(message.LParam, ref rawInput, ref rawInputBuffer)) - { - return; - } + usagePageHandler = HidMceRemoteHandler; + } + //Check if this is a consumer control HID message + else if (hidEvent.UsagePage == (ushort)Hid.UsagePage.Consumer && hidEvent.UsageCollection == (ushort)Hid.UsageIdConsumer.ConsumerControl) + { + usagePageHandler = HidConsumerDeviceHandler; + } + //Unknown HID message + else + { + Debug.WriteLine("Unknown HID message."); + return; + } + foreach (ushort usage in hidEvent.Usages) + { + usagePageHandler(usage); + } + } + } +} - - //Fetch device info - RID_DEVICE_INFO deviceInfo = new RID_DEVICE_INFO(); - if (!RawInput.GetDeviceInfo(rawInput.header.hDevice, ref deviceInfo)) - { - return; - } - - //Get various information about this HID device - Hid.HidDevice device = new Hid.HidDevice(rawInput.header.hDevice); - device.DebugWrite(); - - - - - if (rawInput.header.dwType == Const.RIM_TYPEHID) //Check that our raw input is HID - { - Debug.WriteLine("WM_INPUT source device is HID."); - //Get Usage Page and Usage - Debug.WriteLine("Usage Page: 0x" + deviceInfo.hid.usUsagePage.ToString("X4") + " Usage ID: 0x" + deviceInfo.hid.usUsage.ToString("X4")); - - - preParsedData = RawInput.GetPreParsedData(rawInput.header.hDevice); - - // - HidUsageHandler usagePageHandler=null; - - //Check if this an MCE remote HID message - if (deviceInfo.hid.usUsagePage == (ushort)Hid.UsagePage.MceRemote && deviceInfo.hid.usUsage == (ushort)Hid.UsageIdMce.MceRemote) - { - usagePageHandler = HidMceRemoteHandler; - } - //Check if this is a consumer control HID message - else if (deviceInfo.hid.usUsagePage == (ushort)Hid.UsagePage.Consumer && deviceInfo.hid.usUsage == (ushort)Hid.UsageIdConsumer.ConsumerControl) - { - usagePageHandler = HidConsumerDeviceHandler; - } - //Unknown HID message - else - { - Debug.WriteLine("Unknown HID message."); - return; - } - - if (!(rawInput.hid.dwSizeHid > 1 //Make sure our HID msg size more than 1. In fact the first ushort is irrelevant to us for now - && rawInput.hid.dwCount > 0)) //Check that we have at least one HID msg - { - return; - } - - - //Allocate a buffer for one HID input - byte[] hidInputReport = new byte[rawInput.hid.dwSizeHid]; - - Debug.WriteLine("Raw input contains " + rawInput.hid.dwCount + " HID input report(s)"); - - //For each HID input report in our raw input - for (int i = 0; i < rawInput.hid.dwCount; i++) - { - //Compute the address from which to copy our HID input - int hidInputOffset = 0; - unsafe - { - byte* source = (byte*)rawInputBuffer; - source += sizeof(RAWINPUTHEADER) + sizeof(RAWHID) + (rawInput.hid.dwSizeHid * i); - hidInputOffset = (int)source; - } - - //Copy HID input into our buffer - Marshal.Copy(new IntPtr(hidInputOffset), hidInputReport, 0, (int)rawInput.hid.dwSizeHid); - - //Print HID input report in our debug output - string hidDump = "HID input report: "; - foreach (byte b in hidInputReport) - { - hidDump += b.ToString("X2"); - } - Debug.WriteLine(hidDump); - - //Proper parsing now - uint usageCount = 1; //Assuming a single usage per input report. Is that correct? - Win32.USAGE_AND_PAGE[] usages = new Win32.USAGE_AND_PAGE[usageCount]; - Win32.HidStatus status = Win32.Function.HidP_GetUsagesEx(Win32.HIDP_REPORT_TYPE.HidP_Input, 0, usages, ref usageCount, preParsedData, hidInputReport, (uint)hidInputReport.Length); - if (status != Win32.HidStatus.HIDP_STATUS_SUCCESS) - { - Debug.WriteLine("Could not parse HID data!"); - } - else - { - Debug.WriteLine("UsagePage: 0x" + usages[0].UsagePage.ToString("X4")); - Debug.WriteLine("Usage: 0x" + usages[0].Usage.ToString("X4")); - //Call on our Usage Page handler - usagePageHandler(usages[0].Usage); - } - } - - } - else if (rawInput.header.dwType == Const.RIM_TYPEMOUSE) - { - Debug.WriteLine("WM_INPUT source device is Mouse."); - // do mouse handling... - } - else if (rawInput.header.dwType == Const.RIM_TYPEKEYBOARD) - { - Debug.WriteLine("WM_INPUT source device is Keyboard."); - // do keyboard handling... - Debug.WriteLine("Type: " + deviceInfo.keyboard.dwType.ToString()); - Debug.WriteLine("SubType: " + deviceInfo.keyboard.dwSubType.ToString()); - Debug.WriteLine("Mode: " + deviceInfo.keyboard.dwKeyboardMode.ToString()); - Debug.WriteLine("Number of function keys: " + deviceInfo.keyboard.dwNumberOfFunctionKeys.ToString()); - Debug.WriteLine("Number of indicators: " + deviceInfo.keyboard.dwNumberOfIndicators.ToString()); - Debug.WriteLine("Number of keys total: " + deviceInfo.keyboard.dwNumberOfKeysTotal.ToString()); - } - } - finally - { - //Always executed when leaving our try block - Marshal.FreeHGlobal(rawInputBuffer); - Marshal.FreeHGlobal(preParsedData); - } - } - } -} diff -r 0166dfab3349 -r 305d2ecd3b1a RemoteControlSample.csproj --- a/RemoteControlSample.csproj Sat Dec 06 13:14:16 2014 +0100 +++ b/RemoteControlSample.csproj Sat Dec 06 21:52:45 2014 +0100 @@ -127,8 +127,9 @@ Form + + - Code