Unity SDK Docs 1.5.0-beta.6
Loading...
Searching...
No Matches
Input.cs
1/*
2 * Copyright (C) 2020-2023 Tilt Five, Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16using System;
17using UnityEngine;
18
19#if UNITY_2019_1_OR_NEWER && INPUTSYSTEM_AVAILABLE
20using UnityEngine.InputSystem;
21#endif
22
24
25namespace TiltFive
26{
30 public static class Input
31 {
32 #region Public Enums
33
34 public enum WandButton : UInt32
35 {
36 T5 = 1 << 0,
37 One = 1 << 1,
38 Two = 1 << 2,
39 Three = 1 << 7,
40 Y = 1 << 3,
41 B = 1 << 4,
42 A = 1 << 5,
43 X = 1 << 6,
44 [Obsolete("WandButton.System is deprecated, please use Wandbutton.T5 instead.", true)]
45 System = T5,
46 [Obsolete("WandButton.Z is deprecated, please use Wandbutton.Three instead.", true)]
47 Z = Three,
48 }
49
50 #endregion Public Enums
51
52
53 #region Private Fields
54
55#if UNITY_2019_1_OR_NEWER && INPUTSYSTEM_AVAILABLE
56 internal static GlassesDevice[] glassesDevices = new GlassesDevice[PlayerSettings.MAX_SUPPORTED_PLAYERS];
57 internal static WandDevice[,] wandDevices = new WandDevice[PlayerSettings.MAX_SUPPORTED_PLAYERS, 2];
58#endif
59
60 #endregion
61
62
63 #region Public Functions
64
74 public static bool GetButton(WandButton button,
75 ControllerIndex controllerIndex = ControllerIndex.Right, PlayerIndex playerIndex = PlayerIndex.One)
76 {
77 return TryGetButton(button, out var pressed, controllerIndex, playerIndex) && pressed;
78 }
79
89 public static bool TryGetButton(WandButton button, out bool pressed,
90 ControllerIndex controllerIndex = ControllerIndex.Right, PlayerIndex playerIndex = PlayerIndex.One)
91 {
92 if(!Player.TryGetGlassesHandle(playerIndex, out var glassesHandle))
93 {
94 pressed = false;
95 return false;
96 }
97
98 return Wand.TryGetButton(button, out pressed, glassesHandle, controllerIndex);
99 }
100
109 public static bool GetButtonDown(WandButton button,
110 ControllerIndex controllerIndex = ControllerIndex.Right, PlayerIndex playerIndex = PlayerIndex.One)
111 {
112 return TryGetButtonDown(button, out var buttonDown, controllerIndex, playerIndex) && buttonDown;
113 }
114
124 public static bool TryGetButtonDown(WandButton button, out bool buttonDown,
125 ControllerIndex controllerIndex = ControllerIndex.Right, PlayerIndex playerIndex = PlayerIndex.One)
126 {
127 // The specified player's glasses aren't even connected, let alone the wand. No way to get a rising edge here.
128 if(!Player.TryGetGlassesHandle(playerIndex, out var glassesHandle))
129 {
130 buttonDown = false;
131 return false;
132 }
133
134 return Wand.TryGetButtonDown(button, out buttonDown, glassesHandle, controllerIndex);
135 }
136
144 public static bool GetButtonUp(WandButton button,
145 ControllerIndex controllerIndex = ControllerIndex.Right, PlayerIndex playerIndex = PlayerIndex.One)
146 {
147 return TryGetButtonUp(button, out var buttonUp, controllerIndex, playerIndex) && buttonUp;
148 }
149
160 public static bool TryGetButtonUp(WandButton button, out bool buttonUp,
161 ControllerIndex controllerIndex = ControllerIndex.Right, PlayerIndex playerIndex = PlayerIndex.One)
162 {
163 // TODO: Tweak the Wand.cs TryGetButtonDown to check if the glasses disconnected this frame.
164 // If it did, and the button was held last frame, then buttonUp can be true.
165 if(!Player.TryGetGlassesHandle(playerIndex, out var glassesHandle))
166 {
167 buttonUp = false;
168 return false;
169 }
170
171 return Wand.TryGetButtonUp(button, out buttonUp, glassesHandle, controllerIndex);
172 }
173
180 public static Vector2 GetStickTilt(ControllerIndex controllerIndex = ControllerIndex.Right, PlayerIndex playerIndex = PlayerIndex.One)
181 {
182 if(TryGetStickTilt(out var stickTilt, controllerIndex, playerIndex))
183 {
184 return stickTilt;
185 }
186 return Vector2.zero;
187 }
188
196 public static bool TryGetStickTilt(out Vector2 stickTilt,
197 ControllerIndex controllerIndex = ControllerIndex.Right, PlayerIndex playerIndex = PlayerIndex.One)
198 {
199 if(!Player.TryGetGlassesHandle(playerIndex, out var glassesHandle))
200 {
201 stickTilt = Vector2.zero;
202 return false;
203 }
204 return Wand.TryGetStickTilt(out stickTilt, glassesHandle, controllerIndex);
205 }
206
214 public static float GetTrigger(ControllerIndex controllerIndex = ControllerIndex.Right, PlayerIndex playerIndex = PlayerIndex.One)
215 {
216 if(TryGetTrigger(out var triggerDisplacement, controllerIndex, playerIndex))
217 {
218 return triggerDisplacement;
219 }
220 return 0f;
221 }
222
231 public static bool TryGetTrigger(out float triggerDisplacement,
232 ControllerIndex controllerIndex = ControllerIndex.Right, PlayerIndex playerIndex = PlayerIndex.One)
233 {
234 if (!Player.TryGetGlassesHandle(playerIndex, out var glassesHandle))
235 {
236 triggerDisplacement = 0f;
237 return false;
238 }
239 return Wand.TryGetTrigger(out triggerDisplacement, glassesHandle, controllerIndex);
240 }
241
247 public static bool GetWandAvailability(ControllerIndex controllerIndex = ControllerIndex.Right)
248 {
249 return Wand.TryCheckConnected(out var connected, PlayerIndex.One, controllerIndex) && connected;
250 }
251
252 public static void Update()
253 {
254 // Deleting this function would be appropriate, but since it's public,
255 // there's a small chance it could break someone's code...
256 // ...not that I can think of a use-case that involves calling TiltFive.Input.Update()
257 }
258
259 #endregion Public Functions
260
261
262 #region Internal Functions
263
264 internal static bool GetButton(this T5_ControllerState controllerState, WandButton button)
265 {
266 var buttonsState = controllerState.ButtonsState;
267
268 switch (button)
269 {
270 case WandButton.T5:
271 return buttonsState.T5;
272 case WandButton.One:
273 return buttonsState.One;
274 case WandButton.Two:
275 return buttonsState.Two;
276 case WandButton.Y:
277 return buttonsState.Y;
278 case WandButton.B:
279 return buttonsState.B;
280 case WandButton.A:
281 return buttonsState.A;
282 case WandButton.X:
283 return buttonsState.X;
284 case WandButton.Three:
285 return buttonsState.Three;
286 default:
287 throw new ArgumentException("Invalid WandButton argument - enum value does not exist");
288 }
289
290 }
291
292 internal static bool TryGetButton(this T5_ControllerState controllerState, WandButton button)
293 {
294 return controllerState.ButtonsValid && controllerState.GetButton(button);
295 }
296
297 internal static Vector2 TryGetStick(this T5_ControllerState controllerState)
298 {
299 return controllerState.AnalogValid ? controllerState.Stick : Vector2.zero;
300 }
301
302 internal static float TryGetTrigger(this T5_ControllerState controllerState)
303 {
304 return controllerState.AnalogValid ? controllerState.Trigger : 0f;
305 }
306
307#if UNITY_2019_1_OR_NEWER && INPUTSYSTEM_AVAILABLE
308 internal static GlassesDevice GetGlassesDevice(PlayerIndex playerIndex)
309 {
310 return glassesDevices[(int)playerIndex - 1];
311 }
312
313 internal static WandDevice GetWandDevice(PlayerIndex playerIndex, ControllerIndex controllerIndex)
314 {
315 return wandDevices[(int)playerIndex - 1, (int)controllerIndex];
316 }
317#endif
318
319 #endregion Internal Functions
320
321
322 #region Private Functions
323
324 static Input()
325 {
326 Wand.Scan();
327 }
328
329#if UNITY_2019_1_OR_NEWER && INPUTSYSTEM_AVAILABLE
330 internal static void AddGlassesDevice(PlayerIndex playerIndex)
331 {
332 var glassesDevices = Input.glassesDevices;
333 int i = (int)playerIndex - 1;
334
335 // Create a GlassesDevice if necessary
336 if (glassesDevices[i] == null)
337 {
338 var preexistingGlassesDevice = InputSystem.GetDevice<GlassesDevice>($"Player{playerIndex}");
339 if (preexistingGlassesDevice != null)
340 {
341 glassesDevices[i] = preexistingGlassesDevice;
342 glassesDevices[i].PlayerIndex = playerIndex;
343 }
344 else
345 {
346 glassesDevices[i] = InputSystem.AddDevice<GlassesDevice>($"T5 Glasses - Player {playerIndex}");
347 glassesDevices[i].PlayerIndex = playerIndex;
348 InputSystem.AddDeviceUsage(glassesDevices[i], $"Player{playerIndex}");
349 }
350
351 }
352 else if (!glassesDevices[i].added)
353 {
354 InputSystem.AddDevice(glassesDevices[i]);
355 }
356 }
357
358 internal static void AddWandDevice(PlayerIndex playerIndex, ControllerIndex controllerIndex)
359 {
360 var wandDevices = Input.wandDevices;
361 int i = (int)playerIndex - 1;
362 int j = (int)controllerIndex;
363
364 // Unfortunately, the enum ControllerIndex.Primary still exists, and Unity seems to have a habit
365 // of substituting its display name when we're trying to get the display name for ControllerIndex.Right.
366 // TODO: Localize
367 var handednessLabel = controllerIndex == ControllerIndex.Right ? "Right" : "Left";
368
369 // If we already know about a wandDevice corresponding to our input parameters, add it to the input system if it isn't already added
370 if (wandDevices[i, j] != null && !wandDevices[i, j].added)
371 {
372 var wandDevice = wandDevices[i, j];
373 InputSystem.AddDevice(wandDevice);
374 wandDevice.ControllerIndex = controllerIndex;
375 InputSystem.QueueConfigChangeEvent(wandDevice);
376 InputSystem.AddDevice(wandDevice);
377 }
378 else
379 {
380 // Otherwise, ask the input system if it has a matching wandDevice.
381 // This corner case (in which a matching wandDevice exists, but the static field in Player.cs is empty)
382 // can occur when reloading scripts. Unity's input system keeps the device alive, but this class suffers amnesia.
383 WandDevice currentWandDevice = InputSystem.GetDevice<WandDevice>($"Player{playerIndex}-{handednessLabel}Hand");
384
385 // If the input system does have a matching wandDevice, just remember it and we're done
386 if (currentWandDevice != null)
387 {
388 wandDevices[i, j] = currentWandDevice;
389 }
390 // Otherwise, add a brand new wandDevice to the input system and remember it.
391 else
392 {
393 wandDevices[i, j] = InputSystem.AddDevice<WandDevice>($"T5 Wand - P{(int)playerIndex} {handednessLabel}");
394 }
395
396 wandDevices[i, j].playerIndex = playerIndex;
397 wandDevices[i, j].ControllerIndex = controllerIndex;
398 InputSystem.AddDeviceUsage(wandDevices[i, j], $"Player{playerIndex}");
399 InputSystem.AddDeviceUsage(wandDevices[i, j], $"Player{playerIndex}-{handednessLabel}Hand");
400 InputSystem.AddDeviceUsage(wandDevices[i, j], wandDevices[i, j].ControllerIndex == ControllerIndex.Left ? CommonUsages.LeftHand : CommonUsages.RightHand);
401 InputSystem.QueueConfigChangeEvent(wandDevices[i, j]);
402 }
403 }
404
405 internal static void RemoveGlassesDevice(PlayerIndex playerIndex)
406 {
407 var glassesDevices = Input.glassesDevices;
408 int i = (int)playerIndex - 1;
409
410 // Destroy a GlassesDevice if it exists
411 if (glassesDevices[i] != null)
412 {
413 var preexistingGlassesDevice = InputSystem.GetDevice<GlassesDevice>($"Player{playerIndex}");
414 if (preexistingGlassesDevice != null)
415 {
416 InputSystem.RemoveDevice(preexistingGlassesDevice);
417 glassesDevices[i] = null;
418 }
419 }
420 }
421
422 internal static void RemoveWandDevice(PlayerIndex playerIndex, ControllerIndex controllerIndex)
423 {
424 var wandDevices = Input.wandDevices;
425 int i = (int)playerIndex - 1;
426 int j = (int)controllerIndex;
427
428 // Unfortunately, the enum ControllerIndex.Primary still exists, and Unity seems to have a habit
429 // of substituting its display name when we're trying to get the display name for ControllerIndex.Right.
430 // TODO: Localize
431 var handednessLabel = controllerIndex == ControllerIndex.Right ? "Right" : "Left";
432
433 // If we already know about a wandDevice corresponding to our input parameters, Remove the Device and let the system know if it's disappearance
434 if (wandDevices[i, j] != null && !wandDevices[i, j].added)
435 {
436 var wandDevice = wandDevices[i, j];
437 InputSystem.RemoveDevice(wandDevice);
438 InputSystem.QueueConfigChangeEvent(wandDevice);
439 wandDevices[i, j] = null;
440 }
441 else
442 {
443 // Otherwise, ask the input system if it has a matching wandDevice.
444 // This corner case (in which a matching wandDevice exists, but the static field in Player.cs is empty)
445 // can occur when reloading scripts. Unity's input system keeps the device alive, but this class suffers amnesia.
446 WandDevice currentWandDevice = InputSystem.GetDevice<WandDevice>($"Player{playerIndex}-{handednessLabel}Hand");
447
448 // If the input system does have a matching wandDevice, just destroy it
449 if (currentWandDevice != null)
450 {
451 InputSystem.RemoveDevice(currentWandDevice);
452 InputSystem.QueueConfigChangeEvent(currentWandDevice);
453 wandDevices[i, j] = null;
454 }
455 }
456 }
457#endif
458
459 #endregion Private Functions
460 }
461
462}
ControllerIndex
Since wands are all physically identical (they have no "handedness"), it doesn't make sense to addres...
PlayerIndex
The Player index (e.g. Player One, Player Two, etc)