public void Devices_HIDsWithoutProductName_AreNamedByTheirVendorAndProductID() { var hidDescriptor = new HID.HIDDeviceDescriptor { usage = (int)HID.GenericDesktop.MultiAxisController, usagePage = HID.UsagePage.GenericDesktop, vendorId = 0x1234, productId = 0x5678, inputReportSize = 4, elements = new[] { new HID.HIDElementDescriptor { usage = (int)HID.GenericDesktop.X, usagePage = HID.UsagePage.GenericDesktop, reportType = HID.HIDReportType.Input, reportId = 1, reportSizeInBits = 32 }, } }; testRuntime.ReportNewInputDevice( new InputDeviceDescription { interfaceName = HID.kHIDInterface, capabilities = hidDescriptor.ToJson() }.ToJson()); InputSystem.Update(); var device = (HID)InputSystem.devices.First(x => x is HID); Assert.That(device.name, Is.EqualTo("1234-5678")); }
public void Devices_CanGetDescriptorFromHID() { var hidDescriptor = new HID.HIDDeviceDescriptor { usage = (int)HID.GenericDesktop.MultiAxisController, usagePage = HID.UsagePage.GenericDesktop, productId = 1234, vendorId = 5678, elements = new[] { new HID.HIDElementDescriptor { usage = (int)HID.GenericDesktop.X, usagePage = HID.UsagePage.GenericDesktop, reportType = HID.HIDReportType.Input, reportId = 1, reportSizeInBits = 32 }, } }; testRuntime.ReportNewInputDevice( new InputDeviceDescription { interfaceName = HID.kHIDInterface, manufacturer = "TestVendor", product = "TestHID", capabilities = hidDescriptor.ToJson() }.ToJson()); InputSystem.Update(); var device = (HID)InputSystem.devices.First(x => x is HID); Assert.That(device.hidDescriptor.productId, Is.EqualTo(1234)); Assert.That(device.hidDescriptor.vendorId, Is.EqualTo(5678)); Assert.That(device.hidDescriptor.elements.Length, Is.EqualTo(1)); }
/// <summary> /// Parse a HID report descriptor as defined by section 6.2.2 of the /// <a href="http://www.usb.org/developers/hidpage/HID1_11.pdf">HID /// specification</a> and add the elements and collections from the /// descriptor to the given <paramref name="deviceDescriptor"/>. /// </summary> /// <param name="buffer">Buffer containing raw HID report descriptor.</param> /// <param name="deviceDescriptor">HID device descriptor to complete with the information /// from the report descriptor. Elements and collections will get added to this descriptor.</param> /// <returns>True if the report descriptor was successfully parsed.</returns> /// <remarks> /// Will also set <see cref="HID.HIDDeviceDescriptor.inputReportSize"/>, /// <see cref="HID.HIDDeviceDescriptor.outputReportSize"/>, and /// <see cref="HID.HIDDeviceDescriptor.featureReportSize"/>. /// </remarks> public static unsafe bool ParseReportDescriptor(byte[] buffer, ref HID.HIDDeviceDescriptor deviceDescriptor) { fixed(byte *bufferPtr = buffer) { return(ParseReportDescriptor(bufferPtr, buffer.Length, ref deviceDescriptor)); } }
public void Devices_HIDDescriptorSurvivesReload() { var hidDescriptor = new HID.HIDDeviceDescriptor { usage = (int)HID.GenericDesktop.MultiAxisController, usagePage = HID.UsagePage.GenericDesktop, vendorId = 0x1234, productId = 0x5678, inputReportSize = 4, elements = new[] { new HID.HIDElementDescriptor { usage = (int)HID.GenericDesktop.X, usagePage = HID.UsagePage.GenericDesktop, reportType = HID.HIDReportType.Input, reportId = 1, reportSizeInBits = 32 }, } }; testRuntime.ReportNewInputDevice( new InputDeviceDescription { interfaceName = HID.kHIDInterface, capabilities = hidDescriptor.ToJson() }.ToJson()); InputSystem.Update(); InputSystem.Save(); InputSystem.Reset(); InputSystem.Restore(); var hid = (HID)InputSystem.devices.First(x => x is HID); Assert.That(hid.hidDescriptor.vendorId, Is.EqualTo(0x1234)); Assert.That(hid.hidDescriptor.productId, Is.EqualTo(0x5678)); }
public void Devices_SupportsMultipleHIDHatSwitches() { var hidDescriptor = new HID.HIDDeviceDescriptor { usage = (int)HID.GenericDesktop.MultiAxisController, usagePage = HID.UsagePage.GenericDesktop, vendorId = 0x1234, productId = 0x5678, inputReportSize = 4, elements = new[] { new HID.HIDElementDescriptor { usage = (int)HID.GenericDesktop.HatSwitch, usagePage = HID.UsagePage.GenericDesktop, reportType = HID.HIDReportType.Input, reportId = 1, reportSizeInBits = 4, reportOffsetInBits = 0, logicalMin = 0, logicalMax = 7, physicalMin = 0, physicalMax = 315, flags = HID.HIDElementFlags.NullState }, new HID.HIDElementDescriptor { usage = (int)HID.GenericDesktop.HatSwitch, usagePage = HID.UsagePage.GenericDesktop, reportType = HID.HIDReportType.Input, reportId = 1, reportSizeInBits = 4, reportOffsetInBits = 4, logicalMin = 0, logicalMax = 7, physicalMin = 0, physicalMax = 315, flags = HID.HIDElementFlags.NullState } } }; testRuntime.ReportNewInputDevice( new InputDeviceDescription { interfaceName = HID.kHIDInterface, capabilities = hidDescriptor.ToJson() }.ToJson()); InputSystem.Update(); var hid = (HID)InputSystem.devices.First(x => x is HID); Assert.That(hid["dpad"], Is.TypeOf <DpadControl>()); Assert.That(hid["dpad1"], Is.TypeOf <DpadControl>()); Assert.That(hid["dpad"].stateBlock.byteOffset, Is.EqualTo(0)); Assert.That(hid["dpad"].stateBlock.bitOffset, Is.EqualTo(0)); Assert.That(hid["dpad1"].stateBlock.byteOffset, Is.EqualTo(0)); Assert.That(hid["dpad1"].stateBlock.bitOffset, Is.EqualTo(4)); }
public void Devices_HIDsIgnoreUnusedExcessElements() { var hidDescriptor = new HID.HIDDeviceDescriptor { usage = (int)HID.GenericDesktop.MultiAxisController, usagePage = HID.UsagePage.GenericDesktop, inputReportSize = 36, elements = new[] { new HID.HIDElementDescriptor { usage = (int)HID.GenericDesktop.X, usagePage = HID.UsagePage.GenericDesktop, reportType = HID.HIDReportType.Input, reportId = 1, reportSizeInBits = 32 }, new HID.HIDElementDescriptor { usage = 0x23435, usagePage = (HID.UsagePage) 0x544314, reportType = HID.HIDReportType.Input, reportId = 1, reportSizeInBits = 32 } } }; testRuntime.ReportNewInputDevice(new InputDeviceDescription { interfaceName = HID.kHIDInterface, manufacturer = "TestVendor", product = "TestHID", capabilities = hidDescriptor.ToJson() }.ToJson()); InputSystem.Update(); var device = InputSystem.devices.First(x => x is HID); Assert.That(device.stateBlock.sizeInBits, Is.EqualTo(32)); }
private TreeViewItem BuildDeviceItem(HID.HIDDeviceDescriptor device, ref int id) { var item = new TreeViewItem { id = id++, depth = 0, displayName = "Device" }; AddChild(item, "Vendor ID: " + device.vendorId, ref id); AddChild(item, "Product ID: " + device.productId, ref id); AddChild(item, string.Format("Usage Page: 0x{0:X} ({1})", (uint)device.usagePage, device.usagePage), ref id); AddChild(item, string.Format("Usage: 0x{0:X}", device.usage), ref id); AddChild(item, "Input Report Size: " + device.inputReportSize, ref id); AddChild(item, "Output Report Size: " + device.outputReportSize, ref id); AddChild(item, "Feature Report Size: " + device.featureReportSize, ref id); // Elements. if (device.elements != null) { var bitOffset = 0; var currentReportType = HID.HIDReportType.Unknown; var elementCount = device.elements.Length; var elements = AddChild(item, elementCount + " Elements", ref id); for (var i = 0; i < elementCount; ++i) { BuildElementItem(i, elements, device.elements[i], ref id, ref bitOffset, ref currentReportType); } } ////TODO: collections return(item); }
/// <summary> /// Parse a HID report descriptor as defined by section 6.2.2 of the /// <a href="http://www.usb.org/developers/hidpage/HID1_11.pdf">HID /// specification</a> and add the elements and collections from the /// descriptor to the given <paramref name="deviceDescriptor"/>. /// </summary> /// <param name="buffer">Buffer containing raw HID report descriptor.</param> /// <param name="deviceDescriptor">HID device descriptor to complete with the information /// from the report descriptor. Elements and collections will get added to this descriptor.</param> /// <returns>True if the report descriptor was successfully parsed.</returns> /// <remarks> /// Will also set <see cref="HID.HIDDeviceDescriptor.inputReportSize"/>, /// <see cref="HID.HIDDeviceDescriptor.outputReportSize"/>, and /// <see cref="HID.HIDDeviceDescriptor.featureReportSize"/>. /// </remarks> public static unsafe bool ParseReportDescriptor(byte[] buffer, ref HID.HIDDeviceDescriptor deviceDescriptor) { if (buffer == null) { throw new ArgumentNullException(nameof(buffer)); fixed(byte *bufferPtr = buffer) { return(ParseReportDescriptor(bufferPtr, buffer.Length, ref deviceDescriptor)); } }
public void Devices_SupportsHIDNpad() { var hidDescriptor = new HID.HIDDeviceDescriptor { vendorId = 0x57e, productId = 0x2009, }; var device = InputSystem.AddDevice( new InputDeviceDescription { interfaceName = HID.kHIDInterface, capabilities = hidDescriptor.ToJson() }); Assert.That(device, Is.TypeOf <SwitchProControllerHID>()); var controller = (SwitchProControllerHID)device; InputSystem.QueueStateEvent(controller, new SwitchProControllerHIDInputState { leftStickX = 0x10, leftStickY = 0x10, rightStickX = 0x80, rightStickY = 0xf2, }); InputSystem.Update(); var leftStickDeadzone = controller.leftStick.TryGetProcessor <StickDeadzoneProcessor>(); var rightStickDeadzone = controller.rightStick.TryGetProcessor <StickDeadzoneProcessor>(); var currentLeft = controller.leftStick.ReadValue(); var expectedLeft = leftStickDeadzone.Process(new Vector2(-1.0f, 1.0f)); var currentRight = controller.rightStick.ReadValue(); var expectedRight = rightStickDeadzone.Process(new Vector2(0.0f, -1.0f)); Assert.That(currentLeft, Is.EqualTo(expectedLeft).Using(Vector2EqualityComparer.Instance)); Assert.That(currentRight, Is.EqualTo(expectedRight).Using(new Vector2EqualityComparer(0.01f))); AssertButtonPress(controller, StateWithButton(SwitchProControllerHIDInputState.Button.A), controller.buttonEast); AssertButtonPress(controller, StateWithButton(SwitchProControllerHIDInputState.Button.B), controller.buttonSouth); AssertButtonPress(controller, StateWithButton(SwitchProControllerHIDInputState.Button.X), controller.buttonNorth); AssertButtonPress(controller, StateWithButton(SwitchProControllerHIDInputState.Button.Y), controller.buttonWest); AssertButtonPress(controller, StateWithButton(SwitchProControllerHIDInputState.Button.StickL), controller.leftStickButton); AssertButtonPress(controller, StateWithButton(SwitchProControllerHIDInputState.Button.StickR), controller.rightStickButton); AssertButtonPress(controller, StateWithButton(SwitchProControllerHIDInputState.Button.L), controller.leftShoulder); AssertButtonPress(controller, StateWithButton(SwitchProControllerHIDInputState.Button.R), controller.rightShoulder); AssertButtonPress(controller, StateWithButton(SwitchProControllerHIDInputState.Button.ZL), controller.leftTrigger); AssertButtonPress(controller, StateWithButton(SwitchProControllerHIDInputState.Button.ZR), controller.rightTrigger); AssertButtonPress(controller, StateWithButton(SwitchProControllerHIDInputState.Button.Plus), controller.startButton); AssertButtonPress(controller, StateWithButton(SwitchProControllerHIDInputState.Button.Minus), controller.selectButton); }
public void Devices_GenericHIDXAndYDrivesStickControl() { var hidDescriptor = new HID.HIDDeviceDescriptor { usage = (int)HID.GenericDesktop.Joystick, usagePage = HID.UsagePage.GenericDesktop, vendorId = 0x1234, productId = 0x5678, inputReportSize = 9, elements = new[] { // 16bit X and Y axes. new HID.HIDElementDescriptor { usage = (int)HID.GenericDesktop.X, usagePage = HID.UsagePage.GenericDesktop, reportType = HID.HIDReportType.Input, reportId = 1, reportOffsetInBits = 0, reportSizeInBits = 16 }, new HID.HIDElementDescriptor { usage = (int)HID.GenericDesktop.Y, usagePage = HID.UsagePage.GenericDesktop, reportType = HID.HIDReportType.Input, reportId = 1, reportOffsetInBits = 16, reportSizeInBits = 16 }, } }; runtime.ReportNewInputDevice( new InputDeviceDescription { interfaceName = HID.kHIDInterface, capabilities = hidDescriptor.ToJson() }.ToJson()); InputSystem.Update(); Assert.That(InputSystem.devices, Has.Count.EqualTo(1)); var device = InputSystem.devices[0]; Assert.That(device, Is.TypeOf <Joystick>()); Assert.That(device["Stick"], Is.TypeOf <StickControl>()); InputSystem.QueueStateEvent(device, new SimpleJoystickLayout { reportId = 1, x = ushort.MaxValue, y = ushort.MaxValue }); InputSystem.Update(); Vector2 stickValue = (device["Stick"] as StickControl).ReadValue(); Assert.That(stickValue.x, Is.EqualTo(1.0f).Within(0.01f)); Assert.That(stickValue.y, Is.EqualTo(1.0f).Within(0.01f)); }
public void Devices_SupportsSwitchLikeControllers(int vendorId, int productId) { var hidDescriptor = new HID.HIDDeviceDescriptor { vendorId = vendorId, productId = productId, }; var device = InputSystem.AddDevice( new InputDeviceDescription { interfaceName = HID.kHIDInterface, capabilities = hidDescriptor.ToJson() }); Assert.That(device, Is.TypeOf <SwitchProControllerHID>()); }
public void Editor_DomainReload_CanRestoreDevicesBuiltWithDynamicallyGeneratedLayouts() { var hidDescriptor = new HID.HIDDeviceDescriptor { usage = (int)HID.GenericDesktop.MultiAxisController, usagePage = HID.UsagePage.GenericDesktop, vendorId = 0x1234, productId = 0x5678, inputReportSize = 4, elements = new[] { new HID.HIDElementDescriptor { usage = (int)HID.GenericDesktop.X, usagePage = HID.UsagePage.GenericDesktop, reportType = HID.HIDReportType.Input, reportId = 1, reportSizeInBits = 32 }, } }; testRuntime.ReportNewInputDevice( new InputDeviceDescription { interfaceName = HID.kHIDInterface, capabilities = hidDescriptor.ToJson() }.ToJson()); InputSystem.Update(); Assert.That(InputSystem.devices, Has.Exactly(1).TypeOf <HID>()); InputSystem.SaveAndReset(); Assert.That(InputSystem.devices, Is.Empty); var state = InputSystem.GetSavedState(); var manager = InputSystem.s_Manager; manager.m_SavedAvailableDevices = state.managerState.availableDevices; manager.m_SavedDeviceStates = state.managerState.devices; manager.RestoreDevicesAfterDomainReload(); Assert.That(InputSystem.devices, Has.Exactly(1).TypeOf <HID>()); InputSystem.Restore(); }
public void Devices_DevicesNotAllowedByShouldCreateHIDAreSkipped() { var hidDescriptor = new HID.HIDDeviceDescriptor { usage = 1234, usagePage = (HID.UsagePage) 5678, // need at least one valid element for the device not to be ignored elements = new[] { new HID.HIDElementDescriptor { usage = (int)HID.GenericDesktop.X, usagePage = HID.UsagePage.GenericDesktop, reportType = HID.HIDReportType.Input, reportId = 1, reportOffsetInBits = 0, reportSizeInBits = 16 }, } }; var descriptionJson = new InputDeviceDescription { interfaceName = HID.kHIDInterface, manufacturer = "TestVendor", product = "TestHID", capabilities = hidDescriptor.ToJson() }.ToJson(); var deviceId = runtime.AllocateDeviceId(); runtime.ReportNewInputDevice(descriptionJson, deviceId); InputSystem.Update(); Assert.That(InputSystem.devices, Has.Count.EqualTo(0)); Assert.That(InputSystem.GetDeviceById(deviceId), Is.Null); HIDSupport.shouldCreateHID += descriptor => descriptor.usagePage == (HID.UsagePage) 5678 && descriptor.usage == 1234 ? true : (bool?)null; runtime.ReportNewInputDevice(descriptionJson, deviceId); InputSystem.Update(); Assert.That(InputSystem.devices, Has.Count.EqualTo(1)); Assert.That(InputSystem.GetDeviceById(deviceId), Is.Not.Null); }
public void Devices_HIDDevicesDifferingOnlyByUsageGetSeparateLayouts() { var hidDescriptor1 = new HID.HIDDeviceDescriptor { usage = (int)HID.GenericDesktop.MultiAxisController, usagePage = HID.UsagePage.GenericDesktop, productId = 1234, vendorId = 5678, elements = new[] { new HID.HIDElementDescriptor { usage = (int)HID.GenericDesktop.X, usagePage = HID.UsagePage.GenericDesktop, reportType = HID.HIDReportType.Input, reportId = 1, reportSizeInBits = 32 }, } }; var hidDescriptor2 = hidDescriptor1; hidDescriptor2.usage = (int)HID.GenericDesktop.Gamepad; runtime.ReportNewInputDevice( new InputDeviceDescription { interfaceName = HID.kHIDInterface, manufacturer = "TestVendor", product = "TestHID", capabilities = hidDescriptor1.ToJson() }.ToJson()); runtime.ReportNewInputDevice( new InputDeviceDescription { interfaceName = HID.kHIDInterface, manufacturer = "TestVendor", product = "TestHID", capabilities = hidDescriptor2.ToJson() }.ToJson()); InputSystem.Update(); Assert.AreEqual(InputSystem.devices.Count(), 2); Assert.AreNotEqual(InputSystem.devices[0].layout, InputSystem.devices[1].layout); }
public void Devices_GenericHIDConvertsXAndYUsagesToStickControl() { var hidDescriptor = new HID.HIDDeviceDescriptor { usage = (int)HID.GenericDesktop.Joystick, usagePage = HID.UsagePage.GenericDesktop, vendorId = 0x1234, productId = 0x5678, inputReportSize = 4, elements = new[] { // 16bit X and Y axes. new HID.HIDElementDescriptor { usage = (int)HID.GenericDesktop.X, usagePage = HID.UsagePage.GenericDesktop, reportType = HID.HIDReportType.Input, reportId = 1, reportOffsetInBits = 0, reportSizeInBits = 16 }, new HID.HIDElementDescriptor { usage = (int)HID.GenericDesktop.Y, usagePage = HID.UsagePage.GenericDesktop, reportType = HID.HIDReportType.Input, reportId = 1, reportOffsetInBits = 16, reportSizeInBits = 16 }, } }; runtime.ReportNewInputDevice( new InputDeviceDescription { interfaceName = HID.kHIDInterface, capabilities = hidDescriptor.ToJson() }.ToJson()); InputSystem.Update(); Assert.That(InputSystem.devices, Has.Count.EqualTo(1)); var device = InputSystem.devices[0]; Assert.That(device, Is.TypeOf <Joystick>()); Assert.That(device["Stick"], Is.TypeOf <StickControl>()); }
public HIDDescriptorTreeView(TreeViewState state, HID.HIDDeviceDescriptor descriptor) : base(state) { m_Descriptor = descriptor; Reload(); }
public unsafe void Devices_SupportsHIDHatSwitches() { var hidDescriptor = new HID.HIDDeviceDescriptor { usage = (int)HID.GenericDesktop.MultiAxisController, usagePage = HID.UsagePage.GenericDesktop, vendorId = 0x1234, productId = 0x5678, inputReportSize = 4, elements = new[] { new HID.HIDElementDescriptor { usage = (int)HID.GenericDesktop.HatSwitch, usagePage = HID.UsagePage.GenericDesktop, reportType = HID.HIDReportType.Input, reportId = 1, reportSizeInBits = 4, reportOffsetInBits = 0, logicalMin = 0, logicalMax = 7, // This combination of min/max means that 8 (given we have 4 bits) is out of range and thus the null state. physicalMin = 0, physicalMax = 315, flags = HID.HIDElementFlags.NullState } } }; testRuntime.ReportNewInputDevice( new InputDeviceDescription { interfaceName = HID.kHIDInterface, capabilities = hidDescriptor.ToJson() }.ToJson()); InputSystem.Update(); var hid = (HID)InputSystem.devices.First(x => x is HID); Assert.That(hid["dpad"], Is.TypeOf <DpadControl>()); // Assert that default state is set correctly. Assert.That(hid["dpad/up"].ReadValueAsObject(), Is.EqualTo(0).Within(0.00001)); Assert.That(hid["dpad/down"].ReadValueAsObject(), Is.EqualTo(0).Within(0.00001)); Assert.That(hid["dpad/left"].ReadValueAsObject(), Is.EqualTo(0).Within(0.00001)); Assert.That(hid["dpad/right"].ReadValueAsObject(), Is.EqualTo(0).Within(0.00001)); InputEventPtr eventPtr; using (StateEvent.From(hid, out eventPtr)) { var stateData = (byte *)StateEvent.From(eventPtr)->state; const int kNull = 8; const int kUp = 0; const int kUpRight = 1; const int kRight = 2; const int kRightDown = 3; const int kDown = 4; const int kDownLeft = 5; const int kLeft = 6; const int kLeftUp = 7; stateData[0] = kNull; InputSystem.QueueEvent(eventPtr); InputSystem.Update(); Assert.That(hid["dpad"].ReadValueAsObject(), Is.EqualTo(Vector2.zero).Using(vector2Comparer)); stateData[0] = kUp; InputSystem.QueueEvent(eventPtr); InputSystem.Update(); Assert.That(hid["dpad"].ReadValueAsObject(), Is.EqualTo(Vector2.up).Using(vector2Comparer)); stateData[0] = kUpRight; InputSystem.QueueEvent(eventPtr); InputSystem.Update(); Assert.That(hid["dpad"].ReadValueAsObject(), Is.EqualTo((Vector2.up + Vector2.right).normalized).Using(vector2Comparer)); stateData[0] = kRight; InputSystem.QueueEvent(eventPtr); InputSystem.Update(); Assert.That(hid["dpad"].ReadValueAsObject(), Is.EqualTo(Vector2.right).Using(vector2Comparer)); stateData[0] = kRightDown; InputSystem.QueueEvent(eventPtr); InputSystem.Update(); Assert.That(hid["dpad"].ReadValueAsObject(), Is.EqualTo((Vector2.right + Vector2.down).normalized).Using(vector2Comparer)); stateData[0] = kDown; InputSystem.QueueEvent(eventPtr); InputSystem.Update(); Assert.That(hid["dpad"].ReadValueAsObject(), Is.EqualTo(Vector2.down).Using(vector2Comparer)); stateData[0] = kDownLeft; InputSystem.QueueEvent(eventPtr); InputSystem.Update(); Assert.That(hid["dpad"].ReadValueAsObject(), Is.EqualTo((Vector2.down + Vector2.left).normalized).Using(vector2Comparer)); stateData[0] = kLeft; InputSystem.QueueEvent(eventPtr); InputSystem.Update(); Assert.That(hid["dpad"].ReadValueAsObject(), Is.EqualTo(Vector2.left).Using(vector2Comparer)); stateData[0] = kLeftUp; InputSystem.QueueEvent(eventPtr); InputSystem.Update(); Assert.That(hid["dpad"].ReadValueAsObject(), Is.EqualTo((Vector2.left + Vector2.up).normalized).Using(vector2Comparer)); } }
public unsafe static bool ParseReportDescriptor(byte *bufferPtr, int bufferLength, ref HID.HIDDeviceDescriptor deviceDescriptor) { // Item state. var localItemState = new HIDItemStateLocal(); var globalItemState = new HIDItemStateGlobal(); // Lists where we accumulate the data from the HID items. var reports = new List <HIDReportData>(); var elements = new List <HID.HIDElementDescriptor>(); var collections = new List <HID.HIDCollectionDescriptor>(); var currentCollection = -1; // Parse the linear list of items. var endPtr = bufferPtr + bufferLength; var currentPtr = bufferPtr; while (currentPtr < endPtr) { var firstByte = *currentPtr; ////TODO if (firstByte == 0xFE) { throw new NotImplementedException("long item support"); } // Read item header. var itemSize = (byte)(firstByte & 0x3); var itemTypeAndTag = (byte)(firstByte & 0xFC); ++currentPtr; // Process item. switch (itemTypeAndTag) { // ------------ Global Items -------------- // These set item state permanently until it is reset. // Usage Page case (int)HIDItemTypeAndTag.UsagePage: globalItemState.usagePage = ReadData(itemSize, currentPtr, endPtr); break; // Report Count case (int)HIDItemTypeAndTag.ReportCount: globalItemState.reportCount = ReadData(itemSize, currentPtr, endPtr); break; // Report Size case (int)HIDItemTypeAndTag.ReportSize: globalItemState.reportSize = ReadData(itemSize, currentPtr, endPtr); break; // Report ID case (int)HIDItemTypeAndTag.ReportID: globalItemState.reportId = ReadData(itemSize, currentPtr, endPtr); break; // Logical Minimum case (int)HIDItemTypeAndTag.LogicalMinimum: globalItemState.logicalMinimum = ReadData(itemSize, currentPtr, endPtr); break; // Logical Maximum case (int)HIDItemTypeAndTag.LogicalMaximum: globalItemState.logicalMaximum = ReadData(itemSize, currentPtr, endPtr); break; // Physical Minimum case (int)HIDItemTypeAndTag.PhysicalMinimum: globalItemState.physicalMinimum = ReadData(itemSize, currentPtr, endPtr); break; // Physical Maximum case (int)HIDItemTypeAndTag.PhysicalMaximum: globalItemState.physicalMaximum = ReadData(itemSize, currentPtr, endPtr); break; // Unit Exponent case (int)HIDItemTypeAndTag.UnitExponent: globalItemState.unitExponent = ReadData(itemSize, currentPtr, endPtr); break; // Unit case (int)HIDItemTypeAndTag.Unit: globalItemState.unit = ReadData(itemSize, currentPtr, endPtr); break; // ------------ Local Items -------------- // These set the state for the very next elements to be generated. // Usage case (int)HIDItemTypeAndTag.Usage: localItemState.SetUsage(ReadData(itemSize, currentPtr, endPtr)); break; // Usage Minimum case (int)HIDItemTypeAndTag.UsageMinimum: localItemState.usageMinimum = ReadData(itemSize, currentPtr, endPtr); break; // Usage Maximum case (int)HIDItemTypeAndTag.UsageMaximum: localItemState.usageMaximum = ReadData(itemSize, currentPtr, endPtr); break; // ------------ Main Items -------------- // These emit things into the descriptor based on the local and global item state. // Collection case (int)HIDItemTypeAndTag.Collection: // Start new collection. var parentCollection = currentCollection; currentCollection = collections.Count; collections.Add(new HID.HIDCollectionDescriptor { type = (HID.HIDCollectionType)ReadData(itemSize, currentPtr, endPtr), parent = parentCollection, usagePage = globalItemState.GetUsagePage(0, ref localItemState), usage = localItemState.GetUsage(0), firstChild = elements.Count }); HIDItemStateLocal.Reset(ref localItemState); break; // EndCollection case (int)HIDItemTypeAndTag.EndCollection: if (currentCollection == -1) { return(false); } // Close collection. var collection = collections[currentCollection]; collection.childCount = elements.Count - collection.firstChild; collections[currentCollection] = collection; // Switch back to parent collection (if any). currentCollection = collection.parent; HIDItemStateLocal.Reset(ref localItemState); break; // Input/Output/Feature case (int)HIDItemTypeAndTag.Input: case (int)HIDItemTypeAndTag.Output: case (int)HIDItemTypeAndTag.Feature: // Determine report type. var reportType = itemTypeAndTag == (int)HIDItemTypeAndTag.Input ? HID.HIDReportType.Input : itemTypeAndTag == (int)HIDItemTypeAndTag.Output ? HID.HIDReportType.Output : HID.HIDReportType.Feature; // Find report. var reportIndex = HIDReportData.FindOrAddReport(globalItemState.reportId, reportType, reports); var report = reports[reportIndex]; // If we have a report ID, then reports start with an 8 byte report ID. // Shift our offsets accordingly. if (report.currentBitOffset == 0 && globalItemState.reportId.HasValue) { report.currentBitOffset = 8; } // Add elements to report. var reportCount = globalItemState.reportCount.GetValueOrDefault(1); var flags = ReadData(itemSize, currentPtr, endPtr); for (var i = 0; i < reportCount; ++i) { var element = new HID.HIDElementDescriptor { usage = localItemState.GetUsage(i) & 0xFFFF, // Mask off usage page, if set. usagePage = globalItemState.GetUsagePage(i, ref localItemState), reportType = reportType, reportSizeInBits = globalItemState.reportSize.GetValueOrDefault(8), reportOffsetInBits = report.currentBitOffset, reportId = globalItemState.reportId.GetValueOrDefault(1), flags = (HID.HIDElementFlags)flags, logicalMin = globalItemState.logicalMinimum.GetValueOrDefault(0), logicalMax = globalItemState.logicalMaximum.GetValueOrDefault(0), physicalMin = globalItemState.GetPhysicalMin(), physicalMax = globalItemState.GetPhysicalMax(), unitExponent = globalItemState.unitExponent.GetValueOrDefault(0), unit = globalItemState.unit.GetValueOrDefault(0), }; report.currentBitOffset += element.reportSizeInBits; elements.Add(element); } reports[reportIndex] = report; HIDItemStateLocal.Reset(ref localItemState); break; } if (itemSize == 3) { currentPtr += 4; } else { currentPtr += itemSize; } } deviceDescriptor.elements = elements.ToArray(); deviceDescriptor.collections = collections.ToArray(); // Set usage and usage page on device descriptor to what's // on the toplevel application collection. foreach (var collection in collections) { if (collection.parent == -1 && collection.type == HID.HIDCollectionType.Application) { deviceDescriptor.usage = collection.usage; deviceDescriptor.usagePage = collection.usagePage; break; } } return(true); }
public void Devices_CanCreateGenericHID_FromDeviceWithBinaryReportDescriptor() { // This is several snippets from the PS4 controller's HID report descriptor // pasted together. var reportDescriptor = new byte[] { 0x05, 0x01, // Usage Page (Generic Desktop) 0x09, 0x05, // Usage (Gamepad) 0xA1, 0x01, // Collection (Application) 0x85, 0x01, // Report ID (1) 0x09, 0x30, // Usage (X) 0x09, 0x31, // Usage (Y) 0x09, 0x32, // Usage (Z) 0x09, 0x35, // Usage (Rz) 0x15, 0x00, // Logical Minimum (0) 0x26, 0xFF, 0x00, // Logical Maximum (255) 0x75, 0x08, // Report Size (8) 0x95, 0x04, // Report Count (4) 0x81, 0x02, // Input (Data, Var, Abs, NWrp, Lin, Pref, NNul, Bit) 0x09, 0x39, // Usage (Hat Switch) 0x15, 0x00, // Logical Minimum (0) 0x25, 0x07, // Logical Maximum (7) 0x35, 0x00, // Physical Maximum (0) 0x46, 0x3B, 0x01, // Physical Maximum (315) 0x65, 0x14, // Unit (Eng Rot: Degree) 0x75, 0x04, // Report Size (4) 0x95, 0x01, // Report Count (1) 0x81, 0x42, // Input (Data, Var, Abs, NWrp, Lin, Pref, Null, Bit) 0x65, 0x00, // Unit (None) 0x05, 0x09, // Usage Page (Button) 0x19, 0x01, // Usage Minimum (Button 1) 0x29, 0x0E, // Usage Maximum (Button 14) 0x15, 0x00, // Logical Minimum (0) 0x25, 0x01, // Logical Maximum (1) 0x75, 0x01, // Report Size (1) 0x95, 0x0E, // Report Count (14) 0x81, 0x02, // Input (Data, Var, Abs, NWrp, Lin, Pref, NNul, Bit) 0x06, 0x00, 0xFF, // Usage Page (Vendor-Defined 1) 0x09, 0x21, // Usage (Vendor-Defined 33) 0x95, 0x36, // Report Count (54) 0x81, 0x02, // Input (Data, Var, Abs, NWrp, Lin, Pref, NNul, Bit) 0x85, 0x05, // Report ID (5) 0x09, 0x22, // Usage (Vendor-Defined 34) 0x95, 0x1F, // Report Count (31) 0x91, 0x02, // Output (Data, Var, Abs, NWrp, Lin, Pref, NNul, NVol, Bit) 0xC0, // End Collection }; const int kNumElements = 4 + 1 + 14 + 54 + 31; // The HID report descriptor is fetched from the device via an IOCTL. var deviceId = runtime.AllocateDeviceId(); unsafe { runtime.SetDeviceCommandCallback(deviceId, (id, commandPtr) => { if (commandPtr->type == HID.QueryHIDReportDescriptorSizeDeviceCommandType) { return(reportDescriptor.Length); } if (commandPtr->type == HID.QueryHIDReportDescriptorDeviceCommandType && commandPtr->payloadSizeInBytes >= reportDescriptor.Length) { fixed(byte *ptr = reportDescriptor) { UnsafeUtility.MemCpy(commandPtr->payloadPtr, ptr, reportDescriptor.Length); return(reportDescriptor.Length); } } return(InputDeviceCommand.kGenericFailure); }); } // Report device. runtime.ReportNewInputDevice( new InputDeviceDescription { interfaceName = HID.kHIDInterface, manufacturer = "TestVendor", product = "TestHID", capabilities = new HID.HIDDeviceDescriptor { vendorId = 0x123, productId = 0x234 }.ToJson() }.ToJson(), deviceId); InputSystem.Update(); // Grab device. var device = (Joystick)InputSystem.GetDeviceById(deviceId); Assert.That(device, Is.Not.Null); Assert.That(device, Is.TypeOf <Joystick>()); InputDeviceDescription deviceDescription = device.description; Assert.That(deviceDescription.interfaceName, Is.EqualTo(HID.kHIDInterface)); HID.HIDDeviceDescriptor hidDescriptor = HID.ReadHIDDeviceDescriptor(device, runtime); // Check HID descriptor. Assert.That(hidDescriptor.vendorId, Is.EqualTo(0x123)); Assert.That(hidDescriptor.productId, Is.EqualTo(0x234)); Assert.That(hidDescriptor.usagePage, Is.EqualTo(HID.UsagePage.GenericDesktop)); Assert.That(hidDescriptor.usage, Is.EqualTo((int)HID.GenericDesktop.Gamepad)); Assert.That(hidDescriptor.elements.Length, Is.EqualTo(kNumElements)); Assert.That(hidDescriptor.elements[0].usagePage, Is.EqualTo(HID.UsagePage.GenericDesktop)); Assert.That(hidDescriptor.elements[0].usage, Is.EqualTo((int)HID.GenericDesktop.X)); Assert.That(hidDescriptor.elements[0].reportId, Is.EqualTo(1)); Assert.That(hidDescriptor.elements[0].reportOffsetInBits, Is.EqualTo(8)); // Descriptor has report ID so that's the first thing in reports. Assert.That(hidDescriptor.elements[0].reportSizeInBits, Is.EqualTo(8)); Assert.That(hidDescriptor.elements[0].logicalMin, Is.EqualTo(0)); Assert.That(hidDescriptor.elements[0].logicalMax, Is.EqualTo(255)); Assert.That(hidDescriptor.elements[1].usagePage, Is.EqualTo(HID.UsagePage.GenericDesktop)); Assert.That(hidDescriptor.elements[1].usage, Is.EqualTo((int)HID.GenericDesktop.Y)); Assert.That(hidDescriptor.elements[1].reportId, Is.EqualTo(1)); Assert.That(hidDescriptor.elements[1].reportOffsetInBits, Is.EqualTo(16)); Assert.That(hidDescriptor.elements[1].reportSizeInBits, Is.EqualTo(8)); Assert.That(hidDescriptor.elements[1].logicalMin, Is.EqualTo(0)); Assert.That(hidDescriptor.elements[1].logicalMax, Is.EqualTo(255)); Assert.That(hidDescriptor.elements[4].hasNullState, Is.True); Assert.That(hidDescriptor.elements[4].physicalMax, Is.EqualTo(315)); Assert.That(hidDescriptor.elements[4].unit, Is.EqualTo(0x14)); Assert.That(hidDescriptor.elements[5].unit, Is.Zero); Assert.That(hidDescriptor.elements[5].reportOffsetInBits, Is.EqualTo(5 * 8 + 4)); Assert.That(hidDescriptor.elements[5].usagePage, Is.EqualTo(HID.UsagePage.Button)); Assert.That(hidDescriptor.elements[6].usagePage, Is.EqualTo(HID.UsagePage.Button)); Assert.That(hidDescriptor.elements[7].usagePage, Is.EqualTo(HID.UsagePage.Button)); Assert.That(hidDescriptor.elements[5].usage, Is.EqualTo(1)); Assert.That(hidDescriptor.elements[6].usage, Is.EqualTo(2)); Assert.That(hidDescriptor.elements[7].usage, Is.EqualTo(3)); Assert.That(hidDescriptor.collections.Length, Is.EqualTo(1)); Assert.That(hidDescriptor.collections[0].type, Is.EqualTo(HID.HIDCollectionType.Application)); Assert.That(hidDescriptor.collections[0].childCount, Is.EqualTo(kNumElements)); ////TODO: check hat switch }
public void Devices_CanCreateGenericHID_FromDeviceWithParsedReportDescriptor() { var deviceId = testRuntime.AllocateDeviceId(); unsafe { testRuntime.SetDeviceCommandCallback(deviceId, (id, commandPtr) => { if (commandPtr->type == HID.QueryHIDParsedReportDescriptorDeviceCommandType) { var hidDescriptor = new HID.HIDDeviceDescriptor { usage = (int)HID.GenericDesktop.MultiAxisController, usagePage = HID.UsagePage.GenericDesktop, elements = new[] { new HID.HIDElementDescriptor { usage = (int)HID.GenericDesktop.X, usagePage = HID.UsagePage.GenericDesktop, reportType = HID.HIDReportType.Input, reportId = 1, reportOffsetInBits = 0, reportSizeInBits = 16 }, new HID.HIDElementDescriptor { usage = (int)HID.GenericDesktop.Y, usagePage = HID.UsagePage.GenericDesktop, reportType = HID.HIDReportType.Input, reportId = 1, reportOffsetInBits = 16, reportSizeInBits = 16 }, new HID.HIDElementDescriptor { usage = (int)HID.Button.Primary, usagePage = HID.UsagePage.Button, reportType = HID.HIDReportType.Input, reportId = 1, reportOffsetInBits = 32, reportSizeInBits = 1 }, new HID.HIDElementDescriptor { usage = (int)HID.Button.Secondary, usagePage = HID.UsagePage.Button, reportType = HID.HIDReportType.Input, reportId = 1, reportOffsetInBits = 33, reportSizeInBits = 1 }, } }; var hidDescriptorString = hidDescriptor.ToJson(); var utf8 = Encoding.UTF8.GetBytes(hidDescriptorString); var utf8Length = utf8.Length; if (commandPtr->payloadSizeInBytes < utf8Length) { return(-utf8Length); } fixed(byte *utf8Ptr = utf8) { UnsafeUtility.MemCpy(commandPtr->payloadPtr, utf8Ptr, utf8Length); } return(utf8Length); } return(-1); }); } testRuntime.ReportNewInputDevice( new InputDeviceDescription { interfaceName = HID.kHIDInterface, manufacturer = "TestVendor", product = "TestHID", }.ToJson(), deviceId); InputSystem.Update(); Assert.That(InputSystem.devices, Has.Count.EqualTo(1)); var device = InputSystem.devices[0]; Assert.That(device, Is.TypeOf <HID>()); Assert.That(device.description.interfaceName, Is.EqualTo(HID.kHIDInterface)); var hid = (HID)device; Assert.That(hid.hidDescriptor.elements, Is.Not.Null); Assert.That(hid.hidDescriptor.elements.Length, Is.EqualTo(4)); Assert.That(device.children, Has.Count.EqualTo(4)); Assert.That(device.children, Has.Exactly(1).With.Property("name").EqualTo("x").And.TypeOf <AxisControl>()); Assert.That(device.children, Has.Exactly(1).With.Property("name").EqualTo("y").And.TypeOf <AxisControl>()); Assert.That(device.children, Has.Exactly(1).With.Property("name").EqualTo("button1").And.TypeOf <ButtonControl>()); Assert.That(device.children, Has.Exactly(1).With.Property("name").EqualTo("button2").And.TypeOf <ButtonControl>()); }
public void Devices_CanCreateGenericHID() { // Construct a HID descriptor for a bogus multi-axis controller. var hidDescriptor = new HID.HIDDeviceDescriptor { usage = (int)HID.GenericDesktop.MultiAxisController, usagePage = HID.UsagePage.GenericDesktop, elements = new[] { // 16bit X and Y axes. new HID.HIDElementDescriptor { usage = (int)HID.GenericDesktop.X, usagePage = HID.UsagePage.GenericDesktop, reportType = HID.HIDReportType.Input, reportId = 1, reportOffsetInBits = 0, reportSizeInBits = 16 }, new HID.HIDElementDescriptor { usage = (int)HID.GenericDesktop.Y, usagePage = HID.UsagePage.GenericDesktop, reportType = HID.HIDReportType.Input, reportId = 1, reportOffsetInBits = 16, reportSizeInBits = 16 }, // 1bit primary and secondary buttons. new HID.HIDElementDescriptor { usage = (int)HID.Button.Primary, usagePage = HID.UsagePage.Button, reportType = HID.HIDReportType.Input, reportId = 1, reportOffsetInBits = 32, reportSizeInBits = 1 }, new HID.HIDElementDescriptor { usage = (int)HID.Button.Secondary, usagePage = HID.UsagePage.Button, reportType = HID.HIDReportType.Input, reportId = 1, reportOffsetInBits = 33, reportSizeInBits = 1 }, } }; testRuntime.ReportNewInputDevice( new InputDeviceDescription { interfaceName = HID.kHIDInterface, manufacturer = "TestVendor", product = "TestHID", capabilities = hidDescriptor.ToJson() }.ToJson()); InputSystem.Update(); Assert.That(InputSystem.devices, Has.Count.EqualTo(1)); var device = InputSystem.devices[0]; Assert.That(device, Is.TypeOf <HID>()); Assert.That(device.description.interfaceName, Is.EqualTo(HID.kHIDInterface)); Assert.That(device.children, Has.Count.EqualTo(4)); Assert.That(device.children, Has.Exactly(1).With.Property("name").EqualTo("x").And.TypeOf <AxisControl>()); Assert.That(device.children, Has.Exactly(1).With.Property("name").EqualTo("y").And.TypeOf <AxisControl>()); Assert.That(device.children, Has.Exactly(1).With.Property("name").EqualTo("button1").And.TypeOf <ButtonControl>()); Assert.That(device.children, Has.Exactly(1).With.Property("name").EqualTo("button2").And.TypeOf <ButtonControl>()); var x = device["x"]; var y = device["y"]; var button1 = device["button1"]; var button2 = device["button2"]; Assert.That(device.stateBlock.sizeInBits, Is.EqualTo(5 * 8)); Assert.That(x.stateBlock.byteOffset, Is.Zero); Assert.That(y.stateBlock.byteOffset, Is.EqualTo(2)); Assert.That(x.stateBlock.bitOffset, Is.Zero); Assert.That(y.stateBlock.bitOffset, Is.Zero); Assert.That(button1.stateBlock.byteOffset, Is.EqualTo(4)); Assert.That(button2.stateBlock.byteOffset, Is.EqualTo(4)); Assert.That(button1.stateBlock.bitOffset, Is.EqualTo(0)); Assert.That(button2.stateBlock.bitOffset, Is.EqualTo(1)); }