File size: 6,018 Bytes
18a519f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
using System.Linq;
using UnityEngine.InputSystem.Utilities;
#if UNITY_EDITOR
using UnityEditor;
using UnityEngine.InputSystem.Editor;
using UnityEngine.InputSystem.HID.Editor;
#endif

namespace UnityEngine.InputSystem.HID
{
    using ShouldCreateHIDCallback = System.Func<HID.HIDDeviceDescriptor, bool?>;

    /// <summary>
    /// Adds support for generic HID devices to the input system.
    /// </summary>
    /// <remarks>
    /// Even without this module, HIDs can be used on platforms where we
    /// support HID has a native backend (Windows and OSX, at the moment).
    /// However, each supported HID requires a layout specifically targeting
    /// it as a product.
    ///
    /// What this module adds is the ability to turn any HID with usable
    /// controls into an InputDevice. It will make a best effort to figure
    /// out a suitable class for the device and will use the HID elements
    /// present in the HID report descriptor to populate the device.
    ///
    /// If there is an existing product-specific layout for a HID, it will
    /// take precedence and HIDSupport will leave the device alone.
    /// </remarks>
    public static class HIDSupport
    {
        /// <summary>
        /// A pair of HID usage page and HID usage number.
        /// </summary>
        /// <remarks>
        /// Used to describe a HID usage for the <see cref="supportedHIDUsages"/> property.
        /// </remarks>
        public struct HIDPageUsage
        {
            /// <summary>
            /// The usage page.
            /// </summary>
            public HID.UsagePage page;

            /// <summary>
            /// A number specifying the usage on the usage page.
            /// </summary>
            public int usage;

            /// <summary>
            /// Create a HIDPageUsage struct by specifying a page and usage.
            /// </summary>
            public HIDPageUsage(HID.UsagePage page, int usage)
            {
                this.page = page;
                this.usage = usage;
            }

            /// <summary>
            /// Create a HIDPageUsage struct from the GenericDesktop usage page by specifying the usage.
            /// </summary>
            public HIDPageUsage(HID.GenericDesktop usage)
            {
                page = HID.UsagePage.GenericDesktop;
                this.usage = (int)usage;
            }
        }

        private static HIDPageUsage[] s_SupportedHIDUsages;

        /// <summary>
        /// An array of HID usages the input is configured to support.
        /// </summary>
        /// <remarks>
        /// The input system will only create <see cref="InputDevice"/>s for HIDs with usages
        /// listed in this array. Any other HID will be ignored. This saves the input system from
        /// spending resources on creating layouts and devices for HIDs which are not supported or
        /// not usable for game input.
        ///
        /// By default, this includes only <see cref="HID.GenericDesktop.Joystick"/>,
        /// <see cref="HID.GenericDesktop.Gamepad"/> and <see cref="HID.GenericDesktop.MultiAxisController"/>,
        /// but you can set this property to include any other HID usages.
        ///
        /// Note that currently on macOS, the only HID usages which can be enabled are
        /// <see cref="HID.GenericDesktop.Joystick"/>, <see cref="HID.GenericDesktop.Gamepad"/>,
        /// <see cref="HID.GenericDesktop.MultiAxisController"/>, <see cref="HID.GenericDesktop.TabletPCControls"/>,
        /// and <see cref="HID.GenericDesktop.AssistiveControl"/>.
        /// </remarks>
        public static ReadOnlyArray<HIDPageUsage> supportedHIDUsages
        {
            get => s_SupportedHIDUsages;
            set
            {
                s_SupportedHIDUsages = value.ToArray();

                // Add HIDs we now support.
                InputSystem.s_Manager.AddAvailableDevicesThatAreNowRecognized();

                // Remove HIDs we no longer support.
                for (var i = 0; i < InputSystem.devices.Count; ++i)
                {
                    var device = InputSystem.devices[i];
                    if (device is HID hid && !s_SupportedHIDUsages.Contains(new HIDPageUsage(hid.hidDescriptor.usagePage, hid.hidDescriptor.usage)))
                    {
                        // Remove the entire generated layout. This will also remove all devices based on it.
                        InputSystem.RemoveLayout(device.layout);
                        --i;
                    }
                }
            }
        }

        /// <summary>
        /// Add support for generic HIDs to InputSystem.
        /// </summary>
#if UNITY_DISABLE_DEFAULT_INPUT_PLUGIN_INITIALIZATION
        public
#else
        internal
#endif
        static void Initialize()
        {
            s_SupportedHIDUsages = new[]
            {
                new HIDPageUsage(HID.GenericDesktop.Joystick),
                new HIDPageUsage(HID.GenericDesktop.Gamepad),
                new HIDPageUsage(HID.GenericDesktop.MultiAxisController),
            };

            InputSystem.RegisterLayout<HID>();
            InputSystem.onFindLayoutForDevice += HID.OnFindLayoutForDevice;

            // Add toolbar button to any devices using the "HID" interface. Opens
            // a windows to browse the HID descriptor of the device.
            #if UNITY_EDITOR
            InputDeviceDebuggerWindow.onToolbarGUI +=
                device =>
            {
                if (device.description.interfaceName == HID.kHIDInterface)
                {
                    if (GUILayout.Button(s_HIDDescriptor, EditorStyles.toolbarButton))
                    {
                        HIDDescriptorWindow.CreateOrShowExisting(device.deviceId, device.description);
                    }
                }
            };
            #endif
        }

        #if UNITY_EDITOR
        private static readonly GUIContent s_HIDDescriptor = new GUIContent("HID Descriptor");
        #endif
    }
}