File size: 5,088 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
using System;
using System.Runtime.InteropServices;
using UnityEngine.InputSystem.Utilities;

////REVIEW: move this inside InputActionTrace?

namespace UnityEngine.InputSystem.LowLevel
{
    /// <summary>
    /// A variable-size event that captures the triggering of an action.
    /// </summary>
    /// <remarks>
    /// Action events capture fully processed values only.
    ///
    /// This struct is internal as the data it stores requires having access to <see cref="InputActionState"/>.
    /// Public access is meant to go through <see cref="InputActionTrace"/> which provides a wrapper around
    /// action events in the form of <see cref="InputActionTrace.ActionEventPtr"/>.
    /// </remarks>
    [StructLayout(LayoutKind.Explicit, Size = InputEvent.kBaseEventSize + 16 + 1)]
    internal unsafe struct ActionEvent : IInputEventTypeInfo
    {
        public static FourCC Type => new FourCC('A', 'C', 'T', 'N');

        ////REVIEW: should we decouple this from InputEvent? we get deviceId which we don't really have a use for
        [FieldOffset(0)] public InputEvent baseEvent;

        [FieldOffset(InputEvent.kBaseEventSize + 0)] private ushort m_ControlIndex;
        [FieldOffset(InputEvent.kBaseEventSize + 2)] private ushort m_BindingIndex;
        [FieldOffset(InputEvent.kBaseEventSize + 4)] private ushort m_InteractionIndex;
        [FieldOffset(InputEvent.kBaseEventSize + 6)] private byte m_StateIndex;
        [FieldOffset(InputEvent.kBaseEventSize + 7)] private byte m_Phase;
        [FieldOffset(InputEvent.kBaseEventSize + 8)] private double m_StartTime;
        [FieldOffset(InputEvent.kBaseEventSize + 16)] public fixed byte m_ValueData[1]; // Variable-sized.

        public double startTime
        {
            get => m_StartTime;
            set => m_StartTime = value;
        }

        public InputActionPhase phase
        {
            get => (InputActionPhase)m_Phase;
            set => m_Phase = (byte)value;
        }

        public byte* valueData
        {
            get
            {
                fixed(byte* data = m_ValueData)
                {
                    return data;
                }
            }
        }

        public int valueSizeInBytes => (int)baseEvent.sizeInBytes - InputEvent.kBaseEventSize - 16;

        public int stateIndex
        {
            get => m_StateIndex;
            set
            {
                Debug.Assert(value >= 0 && value <= byte.MaxValue);
                if (value < 0 || value > byte.MaxValue)
                    throw new NotSupportedException("State count cannot exceed byte.MaxValue");
                m_StateIndex = (byte)value;
            }
        }

        public int controlIndex
        {
            get => m_ControlIndex;
            set
            {
                Debug.Assert(value >= 0 && value <= ushort.MaxValue);
                if (value < 0 || value > ushort.MaxValue)
                    throw new NotSupportedException("Control count cannot exceed ushort.MaxValue");
                m_ControlIndex = (ushort)value;
            }
        }

        public int bindingIndex
        {
            get => m_BindingIndex;
            set
            {
                Debug.Assert(value >= 0 && value <= ushort.MaxValue);
                if (value < 0 || value > ushort.MaxValue)
                    throw new NotSupportedException("Binding count cannot exceed ushort.MaxValue");
                m_BindingIndex = (ushort)value;
            }
        }

        public int interactionIndex
        {
            get
            {
                if (m_InteractionIndex == ushort.MaxValue)
                    return InputActionState.kInvalidIndex;
                return m_InteractionIndex;
            }
            set
            {
                Debug.Assert(value == InputActionState.kInvalidIndex || (value >= 0 && value < ushort.MaxValue));
                if (value == InputActionState.kInvalidIndex)
                    m_InteractionIndex = ushort.MaxValue;
                else
                {
                    if (value < 0 || value >= ushort.MaxValue)
                        throw new NotSupportedException("Interaction count cannot exceed ushort.MaxValue-1");
                    m_InteractionIndex = (ushort)value;
                }
            }
        }

        public InputEventPtr ToEventPtr()
        {
            fixed(ActionEvent* ptr = &this)
            {
                return new InputEventPtr((InputEvent*)ptr);
            }
        }

        public FourCC typeStatic => Type;

        public static int GetEventSizeWithValueSize(int valueSizeInBytes)
        {
            return InputEvent.kBaseEventSize + 16 + valueSizeInBytes;
        }

        public static ActionEvent* From(InputEventPtr ptr)
        {
            if (!ptr.valid)
                throw new ArgumentNullException(nameof(ptr));
            if (!ptr.IsA<ActionEvent>())
                throw new InvalidCastException($"Cannot cast event with type '{ptr.type}' into ActionEvent");

            return (ActionEvent*)ptr.data;
        }
    }
}