A game about forced loneliness, made by TACStudios
1using System;
2using System.Runtime.InteropServices;
3using UnityEngine.InputSystem.Utilities;
4
5////REVIEW: move this inside InputActionTrace?
6
7namespace UnityEngine.InputSystem.LowLevel
8{
9 /// <summary>
10 /// A variable-size event that captures the triggering of an action.
11 /// </summary>
12 /// <remarks>
13 /// Action events capture fully processed values only.
14 ///
15 /// This struct is internal as the data it stores requires having access to <see cref="InputActionState"/>.
16 /// Public access is meant to go through <see cref="InputActionTrace"/> which provides a wrapper around
17 /// action events in the form of <see cref="InputActionTrace.ActionEventPtr"/>.
18 /// </remarks>
19 [StructLayout(LayoutKind.Explicit, Size = InputEvent.kBaseEventSize + 16 + 1)]
20 internal unsafe struct ActionEvent : IInputEventTypeInfo
21 {
22 public static FourCC Type => new FourCC('A', 'C', 'T', 'N');
23
24 ////REVIEW: should we decouple this from InputEvent? we get deviceId which we don't really have a use for
25 [FieldOffset(0)] public InputEvent baseEvent;
26
27 [FieldOffset(InputEvent.kBaseEventSize + 0)] private ushort m_ControlIndex;
28 [FieldOffset(InputEvent.kBaseEventSize + 2)] private ushort m_BindingIndex;
29 [FieldOffset(InputEvent.kBaseEventSize + 4)] private ushort m_InteractionIndex;
30 [FieldOffset(InputEvent.kBaseEventSize + 6)] private byte m_StateIndex;
31 [FieldOffset(InputEvent.kBaseEventSize + 7)] private byte m_Phase;
32 [FieldOffset(InputEvent.kBaseEventSize + 8)] private double m_StartTime;
33 [FieldOffset(InputEvent.kBaseEventSize + 16)] public fixed byte m_ValueData[1]; // Variable-sized.
34
35 public double startTime
36 {
37 get => m_StartTime;
38 set => m_StartTime = value;
39 }
40
41 public InputActionPhase phase
42 {
43 get => (InputActionPhase)m_Phase;
44 set => m_Phase = (byte)value;
45 }
46
47 public byte* valueData
48 {
49 get
50 {
51 fixed(byte* data = m_ValueData)
52 {
53 return data;
54 }
55 }
56 }
57
58 public int valueSizeInBytes => (int)baseEvent.sizeInBytes - InputEvent.kBaseEventSize - 16;
59
60 public int stateIndex
61 {
62 get => m_StateIndex;
63 set
64 {
65 Debug.Assert(value >= 0 && value <= byte.MaxValue);
66 if (value < 0 || value > byte.MaxValue)
67 throw new NotSupportedException("State count cannot exceed byte.MaxValue");
68 m_StateIndex = (byte)value;
69 }
70 }
71
72 public int controlIndex
73 {
74 get => m_ControlIndex;
75 set
76 {
77 Debug.Assert(value >= 0 && value <= ushort.MaxValue);
78 if (value < 0 || value > ushort.MaxValue)
79 throw new NotSupportedException("Control count cannot exceed ushort.MaxValue");
80 m_ControlIndex = (ushort)value;
81 }
82 }
83
84 public int bindingIndex
85 {
86 get => m_BindingIndex;
87 set
88 {
89 Debug.Assert(value >= 0 && value <= ushort.MaxValue);
90 if (value < 0 || value > ushort.MaxValue)
91 throw new NotSupportedException("Binding count cannot exceed ushort.MaxValue");
92 m_BindingIndex = (ushort)value;
93 }
94 }
95
96 public int interactionIndex
97 {
98 get
99 {
100 if (m_InteractionIndex == ushort.MaxValue)
101 return InputActionState.kInvalidIndex;
102 return m_InteractionIndex;
103 }
104 set
105 {
106 Debug.Assert(value == InputActionState.kInvalidIndex || (value >= 0 && value < ushort.MaxValue));
107 if (value == InputActionState.kInvalidIndex)
108 m_InteractionIndex = ushort.MaxValue;
109 else
110 {
111 if (value < 0 || value >= ushort.MaxValue)
112 throw new NotSupportedException("Interaction count cannot exceed ushort.MaxValue-1");
113 m_InteractionIndex = (ushort)value;
114 }
115 }
116 }
117
118 public InputEventPtr ToEventPtr()
119 {
120 fixed(ActionEvent* ptr = &this)
121 {
122 return new InputEventPtr((InputEvent*)ptr);
123 }
124 }
125
126 public FourCC typeStatic => Type;
127
128 public static int GetEventSizeWithValueSize(int valueSizeInBytes)
129 {
130 return InputEvent.kBaseEventSize + 16 + valueSizeInBytes;
131 }
132
133 public static ActionEvent* From(InputEventPtr ptr)
134 {
135 if (!ptr.valid)
136 throw new ArgumentNullException(nameof(ptr));
137 if (!ptr.IsA<ActionEvent>())
138 throw new InvalidCastException($"Cannot cast event with type '{ptr.type}' into ActionEvent");
139
140 return (ActionEvent*)ptr.data;
141 }
142 }
143}