A game about forced loneliness, made by TACStudios
1using System;
2using System.Diagnostics;
3using UnityEngine.InputSystem.LowLevel;
4#if UNITY_EDITOR
5using UnityEditor;
6#endif
7
8////REVIEW: this *really* should be renamed to TouchPolling or something like that
9
10////REVIEW: Should this auto-enable itself when the API is used? Problem with this is that it means the first touch inputs will get missed
11//// as by the time the API is polled, we're already into the first frame.
12
13////TODO: gesture support
14////TODO: high-frequency touch support
15
16////REVIEW: have TouchTap, TouchSwipe, etc. wrapper MonoBehaviours like LeanTouch?
17
18////TODO: as soon as we can break the API, remove the EnhancedTouchSupport class altogether and rename UnityEngine.InputSystem.EnhancedTouch to TouchPolling
19
20////FIXME: does not survive domain reloads
21
22namespace UnityEngine.InputSystem.EnhancedTouch
23{
24 /// <summary>
25 /// API to control enhanced touch facilities like <see cref="Touch"/> that are not
26 /// enabled by default.
27 /// </summary>
28 /// <remarks>
29 /// Enhanced touch support provides automatic finger tracking and touch history recording.
30 /// It is an API designed for polling, i.e. for querying touch state directly in methods
31 /// such as <c>MonoBehaviour.Update</c>. Enhanced touch support cannot be used in combination
32 /// with <see cref="InputAction"/>s though both can be used side-by-side.
33 ///
34 /// <example>
35 /// <code>
36 /// public class MyBehavior : MonoBehaviour
37 /// {
38 /// protected void OnEnable()
39 /// {
40 /// EnhancedTouchSupport.Enable();
41 /// }
42 ///
43 /// protected void OnDisable()
44 /// {
45 /// EnhancedTouchSupport.Disable();
46 /// }
47 ///
48 /// protected void Update()
49 /// {
50 /// var activeTouches = Touch.activeTouches;
51 /// for (var i = 0; i < activeTouches.Count; ++i)
52 /// Debug.Log("Active touch: " + activeTouches[i]);
53 /// }
54 /// }
55 /// </code>
56 /// </example>
57 /// </remarks>
58 /// <seealso cref="Touch"/>
59 /// <seealso cref="Finger"/>
60 public static class EnhancedTouchSupport
61 {
62 /// <summary>
63 /// Whether enhanced touch support is currently enabled.
64 /// </summary>
65 /// <value>True if EnhancedTouch support has been enabled.</value>
66 public static bool enabled => s_Enabled > 0;
67
68 private static int s_Enabled;
69 private static InputSettings.UpdateMode s_UpdateMode;
70
71 /// <summary>
72 /// Enable enhanced touch support.
73 /// </summary>
74 /// <remarks>
75 /// Calling this method is necessary to enable the functionality provided
76 /// by <see cref="Touch"/> and <see cref="Finger"/>. These APIs add extra
77 /// processing to touches and are thus disabled by default.
78 ///
79 /// Calls to <c>Enable</c> and <see cref="Disable"/> balance each other out.
80 /// If <c>Enable</c> is called repeatedly, it will take as many calls to
81 /// <see cref="Disable"/> to disable the system again.
82 /// </remarks>
83 public static void Enable()
84 {
85 ++s_Enabled;
86 if (s_Enabled > 1)
87 return;
88
89 InputSystem.onDeviceChange += OnDeviceChange;
90 InputSystem.onBeforeUpdate += Touch.BeginUpdate;
91 InputSystem.onSettingsChange += OnSettingsChange;
92
93 #if UNITY_EDITOR
94 AssemblyReloadEvents.beforeAssemblyReload += OnBeforeDomainReload;
95 #endif
96
97 SetUpState();
98 }
99
100 /// <summary>
101 /// Disable enhanced touch support.
102 /// </summary>
103 /// <remarks>
104 /// This method only undoes a single call to <see cref="Enable"/>.
105 /// </remarks>
106 public static void Disable()
107 {
108 if (!enabled)
109 return;
110 --s_Enabled;
111 if (s_Enabled > 0)
112 return;
113
114 InputSystem.onDeviceChange -= OnDeviceChange;
115 InputSystem.onBeforeUpdate -= Touch.BeginUpdate;
116 InputSystem.onSettingsChange -= OnSettingsChange;
117
118 #if UNITY_EDITOR
119 AssemblyReloadEvents.beforeAssemblyReload -= OnBeforeDomainReload;
120 #endif
121
122 TearDownState();
123 }
124
125 internal static void Reset()
126 {
127 Touch.s_GlobalState.touchscreens = default;
128 Touch.s_GlobalState.playerState.Destroy();
129 Touch.s_GlobalState.playerState = default;
130 #if UNITY_EDITOR
131 Touch.s_GlobalState.editorState.Destroy();
132 Touch.s_GlobalState.editorState = default;
133 #endif
134 s_Enabled = 0;
135 }
136
137 private static void SetUpState()
138 {
139 Touch.s_GlobalState.playerState.updateMask = InputUpdateType.Dynamic | InputUpdateType.Manual | InputUpdateType.Fixed;
140 #if UNITY_EDITOR
141 Touch.s_GlobalState.editorState.updateMask = InputUpdateType.Editor;
142 #endif
143
144 s_UpdateMode = InputSystem.settings.updateMode;
145
146 foreach (var device in InputSystem.devices)
147 OnDeviceChange(device, InputDeviceChange.Added);
148 }
149
150 internal static void TearDownState()
151 {
152 foreach (var device in InputSystem.devices)
153 OnDeviceChange(device, InputDeviceChange.Removed);
154
155 Touch.s_GlobalState.playerState.Destroy();
156 #if UNITY_EDITOR
157 Touch.s_GlobalState.editorState.Destroy();
158 #endif
159
160 Touch.s_GlobalState.playerState = default;
161 #if UNITY_EDITOR
162 Touch.s_GlobalState.editorState = default;
163 #endif
164 }
165
166 private static void OnDeviceChange(InputDevice device, InputDeviceChange change)
167 {
168 switch (change)
169 {
170 case InputDeviceChange.Added:
171 {
172 if (device is Touchscreen touchscreen)
173 Touch.AddTouchscreen(touchscreen);
174 break;
175 }
176
177 case InputDeviceChange.Removed:
178 {
179 if (device is Touchscreen touchscreen)
180 Touch.RemoveTouchscreen(touchscreen);
181 break;
182 }
183 }
184 }
185
186 private static void OnSettingsChange()
187 {
188 var currentUpdateMode = InputSystem.settings.updateMode;
189 if (s_UpdateMode == currentUpdateMode)
190 return;
191 TearDownState();
192 SetUpState();
193 }
194
195 #if UNITY_EDITOR
196 private static void OnBeforeDomainReload()
197 {
198 // We need to release NativeArrays we're holding before losing track of them during domain reloads.
199 Touch.s_GlobalState.playerState.Destroy();
200 Touch.s_GlobalState.editorState.Destroy();
201 }
202
203 #endif
204
205 [Conditional("DEVELOPMENT_BUILD")]
206 [Conditional("UNITY_EDITOR")]
207 internal static void CheckEnabled()
208 {
209 if (!enabled)
210 throw new InvalidOperationException("EnhancedTouch API is not enabled; call EnhancedTouchSupport.Enable()");
211 }
212 }
213}