/// <summary> /// Get all our usages, those are typically the buttons currently pushed on a gamepad. /// For a remote control it's usually just the one button that was pushed. /// </summary> private void GetUsages(byte[] inputReport) { /// Do proper parsing of our HID report /// First query our usage count uint usageCount = 0; USAGE_AND_PAGE[] usages = null; HidStatus status = Win32.Win32Hid.NativeMethods.HidP_GetUsagesEx(HIDP_REPORT_TYPE.HidP_Input, 0, usages, ref usageCount, this.Device.PreParsedData, inputReport, (uint)inputReport.Length); if (status == HidStatus.HIDP_STATUS_BUFFER_TOO_SMALL) { // Allocate a large enough buffer usages = new USAGE_AND_PAGE[usageCount]; // ...and fetch our usages status = Win32.Win32Hid.NativeMethods.HidP_GetUsagesEx(HIDP_REPORT_TYPE.HidP_Input, 0, usages, ref usageCount, this.Device.PreParsedData, inputReport, (uint)inputReport.Length); if (status != HidStatus.HIDP_STATUS_SUCCESS) { Debug.WriteLine("Second pass could not parse HID data: " + status.ToString()); } } else if (status != HidStatus.HIDP_STATUS_SUCCESS) { Debug.WriteLine("First pass could not parse HID data: " + status.ToString()); } Debug.WriteLine("Usage count: " + usageCount.ToString()); // Copy usages into this event if (usages != null) { foreach (var bc in this.Device.InputButtonCapabilities) { var b = false; foreach (USAGE_AND_PAGE up in usages) { if (up.UsagePage == bc.UsagePage && up.Usage == bc.NotRange.Usage) { b = true; break; } } this.Buttons[bc] = b; } } else { foreach (var bc in this.Device.InputButtonCapabilities) { this.Buttons[bc] = false; } } }
/// <summary> /// Typically fetches values of a joystick/gamepad axis and dpad directions. /// </summary> /// <param name="inputReport"></param> private void GetUsageValues(byte[] inputReport) { if (this.Device.InputValueCapabilities == null) { return; } foreach (HIDP_VALUE_CAPS caps in this.Device.InputValueCapabilities) { if (caps.IsRange) { // What should we do with those guys? continue; } // Now fetch and add our usage value uint usageValue = 0; HidStatus status = Win32.Win32Hid.NativeMethods.HidP_GetUsageValue(HIDP_REPORT_TYPE.HidP_Input, caps.UsagePage, caps.LinkCollection, caps.NotRange.Usage, ref usageValue, this.Device.PreParsedData, inputReport, (uint)inputReport.Length); if (status == HidStatus.HIDP_STATUS_SUCCESS) { this.UsageValues[caps] = usageValue; } } }
/// <summary> /// Private constructor. /// </summary> /// <param name="hRawInputDevice"></param> private void Construct(IntPtr hRawInputDevice) { PreParsedData = IntPtr.Zero; iInputButtonCapabilities = null; iInputValueCapabilities = null; //Fetch various information defining the given HID device Name = Win32.RawInput.GetDeviceName(hRawInputDevice); //Fetch device info iInfo = new RID_DEVICE_INFO(); if (!Win32.RawInput.GetDeviceInfo(hRawInputDevice, ref iInfo)) { throw new Exception("HidDevice: GetDeviceInfo failed: " + Marshal.GetLastWin32Error().ToString()); } //Open our device from the device name/path SafeFileHandle handle = Win32.Function.CreateFile(Name, Win32.FileAccess.NONE, Win32.FileShare.FILE_SHARE_READ | Win32.FileShare.FILE_SHARE_WRITE, IntPtr.Zero, Win32.CreationDisposition.OPEN_EXISTING, Win32.FileFlagsAttributes.FILE_FLAG_OVERLAPPED, IntPtr.Zero ); //Check if CreateFile worked if (handle.IsInvalid) { throw new Exception("HidDevice: CreateFile failed: " + Marshal.GetLastWin32Error().ToString()); } //Get manufacturer string StringBuilder manufacturerString = new StringBuilder(256); if (Win32.Function.HidD_GetManufacturerString(handle, manufacturerString, manufacturerString.Capacity)) { Manufacturer = manufacturerString.ToString(); } //Get product string StringBuilder productString = new StringBuilder(256); if (Win32.Function.HidD_GetProductString(handle, productString, productString.Capacity)) { Product = productString.ToString(); } //Get attributes Win32.HIDD_ATTRIBUTES attributes = new Win32.HIDD_ATTRIBUTES(); if (Win32.Function.HidD_GetAttributes(handle, ref attributes)) { VendorId = attributes.VendorID; ProductId = attributes.ProductID; Version = attributes.VersionNumber; } handle.Close(); SetFriendlyName(); //Get our HID descriptor pre-parsed data PreParsedData = Win32.RawInput.GetPreParsedData(hRawInputDevice); if (PreParsedData == IntPtr.Zero) { //We are done then. //Some devices don't have pre-parsed data. return; } //Get capabilities HidStatus status = Win32.Function.HidP_GetCaps(PreParsedData, ref iCapabilities); if (status != HidStatus.HIDP_STATUS_SUCCESS) { throw new Exception("HidDevice: HidP_GetCaps failed: " + status.ToString()); } SetInputCapabilitiesDescription(); //Get input button caps if needed if (Capabilities.NumberInputButtonCaps > 0) { iInputButtonCapabilities = new HIDP_BUTTON_CAPS[Capabilities.NumberInputButtonCaps]; ushort buttonCapabilitiesLength = Capabilities.NumberInputButtonCaps; status = Win32.Function.HidP_GetButtonCaps(HIDP_REPORT_TYPE.HidP_Input, iInputButtonCapabilities, ref buttonCapabilitiesLength, PreParsedData); if (status != HidStatus.HIDP_STATUS_SUCCESS || buttonCapabilitiesLength != Capabilities.NumberInputButtonCaps) { throw new Exception("HidDevice: HidP_GetButtonCaps failed: " + status.ToString()); } ComputeButtonCount(); } //Get input value caps if needed if (Capabilities.NumberInputValueCaps > 0) { iInputValueCapabilities = new HIDP_VALUE_CAPS[Capabilities.NumberInputValueCaps]; ushort valueCapabilitiesLength = Capabilities.NumberInputValueCaps; status = Win32.Function.HidP_GetValueCaps(HIDP_REPORT_TYPE.HidP_Input, iInputValueCapabilities, ref valueCapabilitiesLength, PreParsedData); if (status != HidStatus.HIDP_STATUS_SUCCESS || valueCapabilitiesLength != Capabilities.NumberInputValueCaps) { throw new Exception("HidDevice: HidP_GetValueCaps failed: " + status.ToString()); } } }