File size: 6,501 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
156
157
158
#if UNITY_WEBGL || UNITY_EDITOR || PACKAGE_DOCS_GENERATION
using System;
using System.ComponentModel;
using UnityEngine.InputSystem.Layouts;
using UnityEngine.InputSystem.LowLevel;
using UnityEngine.InputSystem.WebGL.LowLevel;
using UnityEngine.InputSystem.Utilities;

namespace UnityEngine.InputSystem.WebGL.LowLevel
{
    internal unsafe struct WebGLGamepadState : IInputStateTypeInfo
    {
        public const int NumAxes = 4;
        public const int NumButtons = 16;
        private const int ButtonOffset = NumAxes * 4;

        // Stick default format is already two floats so all we need to do is move the sticks and
        // put inverts on Y.
        [InputControl(name = "leftStick", offset = 0)]
        [InputControl(name = "rightStick", offset = 8)]
        [InputControl(name = "leftStick/y", parameters = "invert")]
        [InputControl(name = "leftStick/up", parameters = "clamp=2,clampMin=0,clampMax=1,invert")]
        [InputControl(name = "leftStick/down", parameters = "clamp=2,clampMin=-1,clampMax=0,invert=false")]
        [InputControl(name = "rightStick/y", parameters = "invert")]
        [InputControl(name = "rightStick/up", parameters = "clamp=2,clampMin=0,clampMax=1,invert")]
        [InputControl(name = "rightStick/down", parameters = "clamp=2,clampMin=-1,clampMax=0,invert=false")]
        // All the buttons we need to bump from single bits to full floats and reset bit offsets.
        [InputControl(name = "buttonSouth", offset = ButtonOffset + 0 * 4, bit = 0, format = "FLT")]
        [InputControl(name = "buttonEast", offset = ButtonOffset + 1 * 4, bit = 0, format = "FLT")]
        [InputControl(name = "buttonWest", offset = ButtonOffset + 2 * 4, bit = 0, format = "FLT")]
        [InputControl(name = "buttonNorth", offset = ButtonOffset + 3 * 4, bit = 0, format = "FLT")]
        [InputControl(name = "leftShoulder", offset = ButtonOffset + 4 * 4, bit = 0, format = "FLT")]
        [InputControl(name = "rightShoulder", offset = ButtonOffset + 5 * 4, bit = 0, format = "FLT")]
        [InputControl(name = "leftTrigger", offset = ButtonOffset + 6 * 4, bit = 0, format = "FLT")]
        [InputControl(name = "rightTrigger", offset = ButtonOffset + 7 * 4, bit = 0, format = "FLT")]
        [InputControl(name = "select", offset = ButtonOffset + 8 * 4, bit = 0, format = "FLT")]
        [InputControl(name = "start", offset = ButtonOffset + 9 * 4, bit = 0, format = "FLT")]
        [InputControl(name = "leftStickPress", offset = ButtonOffset + 10 * 4, bit = 0, format = "FLT")]
        [InputControl(name = "rightStickPress", offset = ButtonOffset + 11 * 4, bit = 0, format = "FLT")]
        [InputControl(name = "dpad", offset = ButtonOffset + 12 * 4, bit = 0, sizeInBits = 4 * 4 * 8)]
        [InputControl(name = "dpad/up", offset = 0, bit = 0, format = "FLT")]
        [InputControl(name = "dpad/down", offset = 4, bit = 0, format = "FLT")]
        [InputControl(name = "dpad/left", offset = 8, bit = 0, format = "FLT")]
        [InputControl(name = "dpad/right", offset = 12, bit = 0, format = "FLT")]
        public fixed float values[NumButtons + NumAxes];

        public float leftTrigger
        {
            get => GetValue(NumAxes + 6);
            set => SetValue(NumAxes + 6, value);
        }

        public float rightTrigger
        {
            get => GetValue(NumAxes + 7);
            set => SetValue(NumAxes + 7, value);
        }

        public Vector2 leftStick
        {
            get => new Vector2(GetValue(0), GetValue(1));
            set
            {
                SetValue(0, value.x);
                SetValue(1, value.y);
            }
        }

        public Vector2 rightStick
        {
            get => new Vector2(GetValue(2), GetValue(3));
            set
            {
                SetValue(2, value.x);
                SetValue(3, value.y);
            }
        }

        public FourCC format
        {
            get { return new FourCC('H', 'T', 'M', 'L'); }
        }

        public WebGLGamepadState WithButton(GamepadButton button, float value = 1)
        {
            int index;
            switch (button)
            {
                case GamepadButton.South: index = 0; break;
                case GamepadButton.East: index = 1; break;
                case GamepadButton.West: index = 2; break;
                case GamepadButton.North: index = 3; break;
                case GamepadButton.LeftShoulder: index = 4; break;
                case GamepadButton.RightShoulder: index = 5; break;
                case GamepadButton.Select: index = 8; break;
                case GamepadButton.Start: index = 9; break;
                case GamepadButton.LeftStick: index = 10; break;
                case GamepadButton.RightStick: index = 11; break;
                case GamepadButton.DpadUp: index = 12; break;
                case GamepadButton.DpadDown: index = 13; break;
                case GamepadButton.DpadLeft: index = 14; break;
                case GamepadButton.DpadRight: index = 15; break;

                default:
                    throw new InvalidEnumArgumentException(nameof(button), (int)button, typeof(GamepadButton));
            }

            SetValue(NumAxes + index, value);
            return this;
        }

        private float GetValue(int index)
        {
            fixed(float* valuePtr = values)
            return valuePtr[index];
        }

        private void SetValue(int index, float value)
        {
            fixed(float* valuePtr = values)
            valuePtr[index] = value;
        }
    }

    [Serializable]
    internal struct WebGLDeviceCapabilities
    {
        public int numAxes;
        public int numButtons;
        public string mapping;

        public string ToJson()
        {
            return JsonUtility.ToJson(this);
        }

        public static WebGLDeviceCapabilities FromJson(string json)
        {
            if (string.IsNullOrEmpty(json))
                throw new ArgumentNullException(nameof(json));
            return JsonUtility.FromJson<WebGLDeviceCapabilities>(json);
        }
    }
}

namespace UnityEngine.InputSystem.WebGL
{
    /// <summary>
    /// Gamepad on WebGL that uses the "standard" mapping.
    /// </summary>
    /// <seealso href="https://w3c.github.io/gamepad/#remapping"/>
    [InputControlLayout(stateType = typeof(WebGLGamepadState), displayName = "WebGL Gamepad (\"standard\" mapping)")]
    public class WebGLGamepad : Gamepad
    {
    }
}
#endif // UNITY_WEBGL || UNITY_EDITOR