-
Notifications
You must be signed in to change notification settings - Fork 2
/
PressAndRepeatInteraction.cs
162 lines (133 loc) · 5.74 KB
/
PressAndRepeatInteraction.cs
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
159
160
161
162
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEditor;
using UnityEngine.InputSystem.Editor;
#if UNITY_EDITOR
[InitializeOnLoad]
#endif
public class PressAndRepeatInteraction : IInputInteraction
{
// Parameters
public float holdTime = 0.4f; // Time to consider binding held
public float repeatTime = 0.2f; // Time to repeat "performed" event when the binding is held
public bool press = false; // Option to send "performed" event when the key is pressed
// Private attributes
private InputInteractionContext ctx; // Interaction context
private float heldTime = 0f; // Current time held
private bool firstEventSend = false; // Memory for the first "performed" event when binding is held
private float nextEventTime = 0f; // Time of the next "performed" event
private bool doingCancel; // Prevent Stack Overflows
// Constructor
static PressAndRepeatInteraction()
{
InputSystem.RegisterInteraction<PressAndRepeatInteraction>();
}
// Initialization, it calls the constructor on load
[RuntimeInitializeOnLoadMethod]
private static void Initialize() { }
// Process of the interaction
public void Process(ref InputInteractionContext context)
{
// Saving context to use in "OnUpdate" function
ctx = context;
// If binding is pressed, then start the process
if (ctx.phase != InputActionPhase.Performed && ctx.phase != InputActionPhase.Started && ctx.ControlIsActuated(0.5f))
{
// Save the context
ctx.Started();
// If press option is select, send a "performed" event on the binding press
if (press)
ctx.PerformedAndStayStarted();
//Adding "OnUpdate" fonction to an event call every update, to process the interaction
InputSystem.onAfterUpdate -= OnUpdate;
InputSystem.onAfterUpdate += OnUpdate;
}
}
// Process of the interaction execute on each update
private void OnUpdate()
{
// Get the actual value of the binding
var isActuated = ctx.ControlIsActuated(0.5f);
// Get the actual phase
var phase = ctx.phase;
heldTime += Time.deltaTime;
// Check if the action is canceled outside of this script, or disable, or just released
if (phase == InputActionPhase.Canceled || phase == InputActionPhase.Disabled || !ctx.action.actionMap.enabled || (!isActuated && (phase == InputActionPhase.Performed || phase == InputActionPhase.Started)))
{
Cancel(ref ctx);
return;
}
// Waiting the hold time to consider the bingind held
if (heldTime < holdTime)
{
return;
}
// The hold time is reached, send one time "performed" event. And calculate the next event time
if (!firstEventSend)
{
ctx.PerformedAndStayStarted();
nextEventTime = heldTime + repeatTime;
firstEventSend = true;
return;
}
// The next event time is reached, send one more time "performed" event. And calculate the next event time
if (heldTime >= nextEventTime)
{
ctx.PerformedAndStayStarted();
nextEventTime = heldTime + repeatTime;
}
}
// Reset function
public void Reset()
{
Cancel(ref ctx);
}
// Cancelation of the interaction
private void Cancel(ref InputInteractionContext context)
{
if (doingCancel) // Prevent stack overflows, context.Cancel() can result in Reset() eventually being called if multiple input sources trigger this action in the same frame
return;
// Remove "OnUpdate" from update event
InputSystem.onAfterUpdate -= OnUpdate;
// Reset held time, and the memory for the first hold event
heldTime = 0f;
firstEventSend = false;
// Canceled the interaction if it's not already
if (context.phase != InputActionPhase.Canceled)
{
doingCancel = true;
context.Canceled();
doingCancel = false;
}
}
}
#if UNITY_EDITOR
// This class is used by Unity to have public parameters in the interaction configuration in the action properties
internal class PressAndRepeatInteractionEditor : InputParameterEditor<PressAndRepeatInteraction>
{
private static GUIContent holdTimeLabel, repeatTimeLabel, pressLabel;
// Seting the label and description on each parameters
protected override void OnEnable()
{
holdTimeLabel = new GUIContent("Hold Time", "The minimum amount of realtime seconds before the input is considered \"held\".");
repeatTimeLabel = new GUIContent("Repeating time", "The time between each event while button is \"held\".");
pressLabel = new GUIContent("Press", "\"Press\" send a \"Performed\" event when the key is pressed. Like normal behaviour");
}
// Draw parameters and get changed value
public override void OnGUI()
{
// Press option
EditorGUILayout.BeginHorizontal();
target.press = EditorGUILayout.Toggle(pressLabel, target.press);
EditorGUILayout.EndHorizontal();
// Hold time
EditorGUILayout.BeginHorizontal();
target.holdTime = EditorGUILayout.FloatField(holdTimeLabel, target.holdTime);
EditorGUILayout.EndHorizontal();
// Repeat time
EditorGUILayout.BeginHorizontal();
target.repeatTime = EditorGUILayout.FloatField(repeatTimeLabel, target.repeatTime);
EditorGUILayout.EndHorizontal();
}
}
#endif