コード例 #1
0
    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"));
    }
コード例 #2
0
    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));
    }
コード例 #3
0
 /// <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));
     }
 }
コード例 #4
0
    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));
    }
コード例 #5
0
    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));
    }
コード例 #6
0
    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));
    }
コード例 #7
0
            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);
            }
コード例 #8
0
ファイル: HIDParser.cs プロジェクト: Aidan-0/Roll-A-Ball
        /// <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));
                }
        }
コード例 #9
0
    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);
    }
コード例 #10
0
    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));
    }
コード例 #11
0
    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>());
    }
コード例 #12
0
    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();
    }
コード例 #13
0
ファイル: HIDTests.cs プロジェクト: virgiliu/InputSystem
    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);
    }
コード例 #14
0
    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);
    }
コード例 #15
0
    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>());
    }
コード例 #16
0
 public HIDDescriptorTreeView(TreeViewState state, HID.HIDDeviceDescriptor descriptor)
     : base(state)
 {
     m_Descriptor = descriptor;
     Reload();
 }
コード例 #17
0
    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));
        }
    }
コード例 #18
0
        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);
        }
コード例 #19
0
    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
    }
コード例 #20
0
    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>());
    }
コード例 #21
0
    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));
    }