AR Design
UBC EML collab with UBC SALA - visualizing IoT data in AR
InteractionInputSource.cs
Go to the documentation of this file.
1 // Copyright (c) Microsoft Corporation. All rights reserved.
2 // Licensed under the MIT License. See LICENSE in the project root for license information.
3 
4 using UnityEngine;
5 
6 #if UNITY_WSA
7 using System.Collections.Generic;
8 #if UNITY_2017_2_OR_NEWER
9 using UnityEngine.XR.WSA.Input;
10 #else
11 using UnityEngine.VR.WSA.Input;
12 #endif
13 #endif
14 
15 namespace HoloToolkit.Unity.InputModule
16 {
23  {
24  // This enumeration gives the manager two different ways to handle the recognizer. Both will
25  // set up the recognizer. The first causes the recognizer to start
26  // immediately. The second allows the recognizer to be manually started at a later time.
27  public enum RecognizerStartBehavior { AutoStart, ManualStart }
28 
29  [Tooltip("Whether the recognizer should be activated on start.")]
31 
32  [Tooltip("Set to true to use the use rails (guides) for the navigation gesture, as opposed to full 3D navigation.")]
33  public bool UseRailsNavigation = false;
34 
39  private bool delayInitialization = true;
40 
41 #if UNITY_WSA
42  protected GestureRecognizer GestureRecognizer;
43  protected GestureRecognizer NavigationGestureRecognizer;
44 #endif
45 
46  #region IInputSource Capabilities and SourceData
47 
48 #if UNITY_WSA
49  private struct SourceCapability<TReading>
50  {
51  public bool IsSupported;
52  public bool IsAvailable;
53  public TReading CurrentReading;
54  }
55 
56  private struct AxisButton2D
57  {
58  public bool Pressed;
59  public Vector2 Position;
60 
61  public static AxisButton2D GetThumbstick(InteractionSourceState interactionSource)
62  {
63  return new AxisButton2D
64  {
65 #if UNITY_2017_2_OR_NEWER
66  Pressed = interactionSource.thumbstickPressed,
67  Position = interactionSource.thumbstickPosition,
68 #else
69  Pressed = false,
70  Position = default(Vector2)
71 #endif
72  };
73  }
74 
75  public static AxisButton2D GetTouchpad(InteractionSourceState interactionSource)
76  {
77  return new AxisButton2D
78  {
79 #if UNITY_2017_2_OR_NEWER
80  Pressed = interactionSource.touchpadPressed,
81  Position = interactionSource.touchpadPosition,
82 #else
83  Pressed = false,
84  Position = default(Vector2)
85 #endif
86  };
87  }
88  }
89 
90  private struct TouchpadData
91  {
92  public AxisButton2D AxisButton;
93  public bool Touched;
94 
95  public static TouchpadData GetTouchpad(InteractionSourceState interactionSource)
96  {
97  return new TouchpadData
98  {
99  AxisButton = AxisButton2D.GetTouchpad(interactionSource),
100 #if UNITY_2017_2_OR_NEWER
101  Touched = interactionSource.touchpadTouched,
102 #else
103  Touched = false,
104 #endif
105  };
106  }
107  }
108 
109  private struct AxisButton1D
110  {
111  public bool Pressed;
112  public double PressedAmount;
113 
114  public static AxisButton1D GetSelect(InteractionSourceState interactionSource)
115  {
116  return new AxisButton1D
117  {
118 #if UNITY_2017_2_OR_NEWER
119  Pressed = interactionSource.selectPressed,
120  PressedAmount = interactionSource.selectPressedAmount,
121 #else
122  Pressed = false,
123  PressedAmount = 0f
124 #endif
125  };
126  }
127  }
128 
132  private class SourceData
133  {
134  public SourceData(InteractionSource interactionSource)
135  {
136  Source = interactionSource;
137  }
138 
139  public void ResetUpdatedBooleans()
140  {
141  ThumbstickPositionUpdated = false;
142  TouchpadPositionUpdated = false;
143  TouchpadTouchedUpdated = false;
144  PositionUpdated = false;
145  RotationUpdated = false;
146  SelectPressedAmountUpdated = false;
147  }
148 
149  public uint SourceId { get { return Source.id; } }
150  public InteractionSourceKind SourceKind { get { return Source.kind; } }
151 #if UNITY_2017_2_OR_NEWER
152  public InteractionSourceHandedness Handedness { get { return Source.handedness; } }
153 #endif
154  public readonly InteractionSource Source;
155  public SourceCapability<Vector3> PointerPosition;
156  public SourceCapability<Quaternion> PointerRotation;
157  public SourceCapability<Ray> PointingRay;
158  public SourceCapability<Vector3> GripPosition;
159  public SourceCapability<Quaternion> GripRotation;
160  public SourceCapability<AxisButton2D> Thumbstick;
161  public SourceCapability<TouchpadData> Touchpad;
162  public SourceCapability<AxisButton1D> Select;
163  public SourceCapability<bool> Grasp;
164  public SourceCapability<bool> Menu;
165 
166  public bool ThumbstickPositionUpdated;
167  public bool TouchpadPositionUpdated;
168  public bool TouchpadTouchedUpdated;
169  public bool PositionUpdated;
170  public bool RotationUpdated;
171  public bool SelectPressedAmountUpdated;
172  }
173 
177  private readonly Dictionary<uint, SourceData> sourceIdToData = new Dictionary<uint, SourceData>(4);
178 #endif
179  #endregion IInputSource Capabilities and SourceData
180 
181  #region MonoBehaviour APIs
182 
183  protected virtual void Awake()
184  {
185 #if UNITY_WSA
186  GestureRecognizer = new GestureRecognizer();
187 #if UNITY_2017_2_OR_NEWER
188  GestureRecognizer.Tapped += GestureRecognizer_Tapped;
189 
190  GestureRecognizer.HoldStarted += GestureRecognizer_HoldStarted;
191  GestureRecognizer.HoldCompleted += GestureRecognizer_HoldCompleted;
192  GestureRecognizer.HoldCanceled += GestureRecognizer_HoldCanceled;
193 
194  GestureRecognizer.ManipulationStarted += GestureRecognizer_ManipulationStarted;
195  GestureRecognizer.ManipulationUpdated += GestureRecognizer_ManipulationUpdated;
196  GestureRecognizer.ManipulationCompleted += GestureRecognizer_ManipulationCompleted;
197  GestureRecognizer.ManipulationCanceled += GestureRecognizer_ManipulationCanceled;
198 #else
199  GestureRecognizer.TappedEvent += GestureRecognizer_Tapped;
200 
201  GestureRecognizer.HoldStartedEvent += GestureRecognizer_HoldStarted;
202  GestureRecognizer.HoldCompletedEvent += GestureRecognizer_HoldCompleted;
203  GestureRecognizer.HoldCanceledEvent += GestureRecognizer_HoldCanceled;
204 
205  GestureRecognizer.ManipulationStartedEvent += GestureRecognizer_ManipulationStarted;
206  GestureRecognizer.ManipulationUpdatedEvent += GestureRecognizer_ManipulationUpdated;
207  GestureRecognizer.ManipulationCompletedEvent += GestureRecognizer_ManipulationCompleted;
208  GestureRecognizer.ManipulationCanceledEvent += GestureRecognizer_ManipulationCanceled;
209 #endif
210  GestureRecognizer.SetRecognizableGestures(GestureSettings.Tap |
211  GestureSettings.ManipulationTranslate |
212  GestureSettings.Hold);
213 
214  // We need a separate gesture recognizer for navigation, since it isn't compatible with manipulation
215  NavigationGestureRecognizer = new GestureRecognizer();
216 
217 #if UNITY_2017_2_OR_NEWER
218  NavigationGestureRecognizer.NavigationStarted += NavigationGestureRecognizer_NavigationStarted;
219  NavigationGestureRecognizer.NavigationUpdated += NavigationGestureRecognizer_NavigationUpdated;
220  NavigationGestureRecognizer.NavigationCompleted += NavigationGestureRecognizer_NavigationCompleted;
221  NavigationGestureRecognizer.NavigationCanceled += NavigationGestureRecognizer_NavigationCanceled;
222 #else
223  NavigationGestureRecognizer.NavigationStartedEvent += NavigationGestureRecognizer_NavigationStarted;
224  NavigationGestureRecognizer.NavigationUpdatedEvent += NavigationGestureRecognizer_NavigationUpdated;
225  NavigationGestureRecognizer.NavigationCompletedEvent += NavigationGestureRecognizer_NavigationCompleted;
226  NavigationGestureRecognizer.NavigationCanceledEvent += NavigationGestureRecognizer_NavigationCanceled;
227 #endif
228  if (UseRailsNavigation)
229  {
230  NavigationGestureRecognizer.SetRecognizableGestures(GestureSettings.NavigationRailsX |
231  GestureSettings.NavigationRailsY |
232  GestureSettings.NavigationRailsZ);
233  }
234  else
235  {
236  NavigationGestureRecognizer.SetRecognizableGestures(GestureSettings.NavigationX |
237  GestureSettings.NavigationY |
238  GestureSettings.NavigationZ);
239  }
240 
241  if (RecognizerStart == RecognizerStartBehavior.AutoStart)
242  {
243  GestureRecognizer.StartCapturingGestures();
244  NavigationGestureRecognizer.StartCapturingGestures();
245  }
246 #endif
247  }
248 
249  protected virtual void OnEnable()
250  {
251  if (!delayInitialization)
252  {
253  // The first time we call OnEnable we skip this.
254  InitializeSources();
255  }
256  }
257 
258  protected virtual void Start()
259  {
260  if (delayInitialization)
261  {
262  delayInitialization = false;
263  InitializeSources();
264  }
265  }
266 
267  protected virtual void OnDisable()
268  {
269 #if UNITY_WSA
270  StopGestureRecognizer();
271 
272 #if UNITY_2017_2_OR_NEWER
273  InteractionManager.InteractionSourceDetected -= InteractionManager_InteractionSourceDetected;
274  InteractionManager.InteractionSourcePressed -= InteractionManager_InteractionSourcePressed;
275  InteractionManager.InteractionSourceUpdated -= InteractionManager_InteractionSourceUpdated;
276  InteractionManager.InteractionSourceReleased -= InteractionManager_InteractionSourceReleased;
277  InteractionManager.InteractionSourceLost -= InteractionManager_InteractionSourceLost;
278 #else
279  InteractionManager.SourceDetected -= InteractionManager_InteractionSourceDetected;
280  InteractionManager.SourcePressed -= InteractionManager_InteractionSourcePressed;
281  InteractionManager.SourceUpdated -= InteractionManager_InteractionSourceUpdated;
282  InteractionManager.SourceReleased -= InteractionManager_InteractionSourceReleased;
283  InteractionManager.SourceLost -= InteractionManager_InteractionSourceLost;
284 #endif
285 
286  InteractionSourceState[] states = InteractionManager.GetCurrentReading();
287  for (var i = 0; i < states.Length; i++)
288  {
289  // NOTE: We don't care whether the source ID previously existed or not, so we blindly call Remove:
290  sourceIdToData.Remove(states[i].source.id);
291  InputManager.Instance.RaiseSourceLost(this, states[i].source.id);
292  }
293 #endif
294  }
295 
296  protected virtual void OnDestroy()
297  {
298 #if UNITY_WSA
299  if (GestureRecognizer != null)
300  {
301 #if UNITY_2017_2_OR_NEWER
302  GestureRecognizer.Tapped -= GestureRecognizer_Tapped;
303 
304  GestureRecognizer.HoldStarted -= GestureRecognizer_HoldStarted;
305  GestureRecognizer.HoldCompleted -= GestureRecognizer_HoldCompleted;
306  GestureRecognizer.HoldCanceled -= GestureRecognizer_HoldCanceled;
307 
308  GestureRecognizer.ManipulationStarted -= GestureRecognizer_ManipulationStarted;
309  GestureRecognizer.ManipulationUpdated -= GestureRecognizer_ManipulationUpdated;
310  GestureRecognizer.ManipulationCompleted -= GestureRecognizer_ManipulationCompleted;
311  GestureRecognizer.ManipulationCanceled -= GestureRecognizer_ManipulationCanceled;
312 #else
313  GestureRecognizer.TappedEvent -= GestureRecognizer_Tapped;
314 
315  GestureRecognizer.HoldStartedEvent -= GestureRecognizer_HoldStarted;
316  GestureRecognizer.HoldCompletedEvent -= GestureRecognizer_HoldCompleted;
317  GestureRecognizer.HoldCanceledEvent -= GestureRecognizer_HoldCanceled;
318 
319  GestureRecognizer.ManipulationStartedEvent -= GestureRecognizer_ManipulationStarted;
320  GestureRecognizer.ManipulationUpdatedEvent -= GestureRecognizer_ManipulationUpdated;
321  GestureRecognizer.ManipulationCompletedEvent -= GestureRecognizer_ManipulationCompleted;
322  GestureRecognizer.ManipulationCanceledEvent -= GestureRecognizer_ManipulationCanceled;
323 
324 #endif
325  GestureRecognizer.Dispose();
326  }
327 
328  if (NavigationGestureRecognizer != null)
329  {
330 #if UNITY_2017_2_OR_NEWER
331  NavigationGestureRecognizer.NavigationStarted -= NavigationGestureRecognizer_NavigationStarted;
332  NavigationGestureRecognizer.NavigationUpdated -= NavigationGestureRecognizer_NavigationUpdated;
333  NavigationGestureRecognizer.NavigationCompleted -= NavigationGestureRecognizer_NavigationCompleted;
334  NavigationGestureRecognizer.NavigationCanceled -= NavigationGestureRecognizer_NavigationCanceled;
335 #else
336  NavigationGestureRecognizer.NavigationStartedEvent -= NavigationGestureRecognizer_NavigationStarted;
337  NavigationGestureRecognizer.NavigationUpdatedEvent -= NavigationGestureRecognizer_NavigationUpdated;
338  NavigationGestureRecognizer.NavigationCompletedEvent -= NavigationGestureRecognizer_NavigationCompleted;
339  NavigationGestureRecognizer.NavigationCanceledEvent -= NavigationGestureRecognizer_NavigationCanceled;
340 #endif
341  NavigationGestureRecognizer.Dispose();
342  }
343 #endif
344  }
345 
346  #endregion MonoBehaviour APIs
347 
353  {
354 #if UNITY_WSA
355  if (GestureRecognizer != null && !GestureRecognizer.IsCapturingGestures())
356  {
357  GestureRecognizer.StartCapturingGestures();
358  }
359  if (NavigationGestureRecognizer != null && !NavigationGestureRecognizer.IsCapturingGestures())
360  {
361  NavigationGestureRecognizer.StartCapturingGestures();
362  }
363 #endif
364  }
365 
370  public void StopGestureRecognizer()
371  {
372 #if UNITY_WSA
373  if (GestureRecognizer != null && GestureRecognizer.IsCapturingGestures())
374  {
375  GestureRecognizer.StopCapturingGestures();
376  }
377 
378  if (NavigationGestureRecognizer != null && NavigationGestureRecognizer.IsCapturingGestures())
379  {
380  NavigationGestureRecognizer.StopCapturingGestures();
381  }
382 #endif
383  }
384 
385  private void InitializeSources()
386  {
388 
389 #if UNITY_WSA
390  if (RecognizerStart == RecognizerStartBehavior.AutoStart)
391  {
392  StartGestureRecognizer();
393  }
394 
395  InteractionSourceState[] states = InteractionManager.GetCurrentReading();
396  for (var i = 0; i < states.Length; i++)
397  {
398  GetOrAddSourceData(states[i].source);
399  InputManager.Instance.RaiseSourceDetected(this, states[i].source.id);
400  }
401 
402 #if UNITY_2017_2_OR_NEWER
403  InteractionManager.InteractionSourceDetected += InteractionManager_InteractionSourceDetected;
404  InteractionManager.InteractionSourcePressed += InteractionManager_InteractionSourcePressed;
405  InteractionManager.InteractionSourceUpdated += InteractionManager_InteractionSourceUpdated;
406  InteractionManager.InteractionSourceReleased += InteractionManager_InteractionSourceReleased;
407  InteractionManager.InteractionSourceLost += InteractionManager_InteractionSourceLost;
408 #else
409  InteractionManager.SourceDetected += InteractionManager_InteractionSourceDetected;
410  InteractionManager.SourcePressed += InteractionManager_InteractionSourcePressed;
411  InteractionManager.SourceUpdated += InteractionManager_InteractionSourceUpdated;
412  InteractionManager.SourceReleased += InteractionManager_InteractionSourceReleased;
413  InteractionManager.SourceLost += InteractionManager_InteractionSourceLost;
414 #endif
415 
416 #else
417  RecognizerStart = RecognizerStartBehavior.ManualStart;
418 #endif
419  }
420 
421  public void StartHaptics(uint sourceId, float intensity)
422  {
423 #if UNITY_WSA && UNITY_2017_2_OR_NEWER
424  SourceData sourceData;
425  if (sourceIdToData.TryGetValue(sourceId, out sourceData))
426  {
427  sourceData.Source.StartHaptics(intensity);
428  }
429 #endif
430  }
431 
432  public void StartHaptics(uint sourceId, float intensity, float durationInSeconds)
433  {
434 #if UNITY_WSA && UNITY_2017_2_OR_NEWER
435  SourceData sourceData;
436  if (sourceIdToData.TryGetValue(sourceId, out sourceData))
437  {
438  sourceData.Source.StartHaptics(intensity, durationInSeconds);
439  }
440 #endif
441  }
442 
443  public void StopHaptics(uint sourceId)
444  {
445 #if UNITY_WSA && UNITY_2017_2_OR_NEWER
446  SourceData sourceData;
447  if (sourceIdToData.TryGetValue(sourceId, out sourceData))
448  {
449  sourceData.Source.StopHaptics();
450  }
451 #endif
452  }
453 
454  public bool TryGetHandedness(uint sourceId, out Handedness handedness)
455  {
456 #if UNITY_WSA && UNITY_2017_2_OR_NEWER
457  SourceData sourceData;
458  if (sourceIdToData.TryGetValue(sourceId, out sourceData))
459  {
460  handedness = (Handedness)sourceData.Handedness;
461  return true;
462  }
463 #endif
464 
465  handedness = default(Handedness);
466  return false;
467  }
468 
469  #region BaseInputSource implementations
470 
471  public override SupportedInputInfo GetSupportedInputInfo(uint sourceId)
472  {
473  var retVal = SupportedInputInfo.None;
474 #if UNITY_WSA
475  SourceData sourceData;
476  if (sourceIdToData.TryGetValue(sourceId, out sourceData))
477  {
478  retVal |= GetSupportFlag(sourceData.PointerPosition, SupportedInputInfo.PointerPosition);
479  retVal |= GetSupportFlag(sourceData.PointerRotation, SupportedInputInfo.PointerRotation);
480  retVal |= GetSupportFlag(sourceData.GripPosition, SupportedInputInfo.GripPosition);
481  retVal |= GetSupportFlag(sourceData.GripRotation, SupportedInputInfo.GripRotation);
482  retVal |= GetSupportFlag(sourceData.PointingRay, SupportedInputInfo.Pointing);
483  retVal |= GetSupportFlag(sourceData.Thumbstick, SupportedInputInfo.Thumbstick);
484  retVal |= GetSupportFlag(sourceData.Touchpad, SupportedInputInfo.Touchpad);
485  retVal |= GetSupportFlag(sourceData.Select, SupportedInputInfo.Select);
486  retVal |= GetSupportFlag(sourceData.Menu, SupportedInputInfo.Menu);
487  retVal |= GetSupportFlag(sourceData.Grasp, SupportedInputInfo.Grasp);
488  }
489 #endif
490  return retVal;
491  }
492 
493  public override bool TryGetSourceKind(uint sourceId, out InteractionSourceInfo sourceKind)
494  {
495 #if UNITY_WSA
496  SourceData sourceData;
497  if (sourceIdToData.TryGetValue(sourceId, out sourceData))
498  {
499  sourceKind = (InteractionSourceInfo)sourceData.SourceKind;
500  return true;
501  }
502 #endif
503 
504  sourceKind = default(InteractionSourceInfo);
505  return false;
506  }
507 
508  public override bool TryGetPointerPosition(uint sourceId, out Vector3 position)
509  {
510 #if UNITY_WSA
511  SourceData sourceData;
512  if (sourceIdToData.TryGetValue(sourceId, out sourceData) && TryGetReading(sourceData.PointerPosition, out position))
513  {
514  return true;
515  }
516 #endif
517 
518  position = default(Vector3);
519  return false;
520  }
521 
522  public override bool TryGetPointerRotation(uint sourceId, out Quaternion rotation)
523  {
524 #if UNITY_WSA
525  SourceData sourceData;
526  if (sourceIdToData.TryGetValue(sourceId, out sourceData) && TryGetReading(sourceData.PointerRotation, out rotation))
527  {
528  return true;
529  }
530 #endif
531 
532  rotation = default(Quaternion);
533  return false;
534  }
535 
536  public override bool TryGetPointingRay(uint sourceId, out Ray pointingRay)
537  {
538 #if UNITY_WSA
539  SourceData sourceData;
540  if (sourceIdToData.TryGetValue(sourceId, out sourceData) && TryGetReading(sourceData.PointingRay, out pointingRay))
541  {
542  return true;
543  }
544 #endif
545 
546  pointingRay = default(Ray);
547  return false;
548  }
549 
550  public override bool TryGetGripPosition(uint sourceId, out Vector3 position)
551  {
552 #if UNITY_WSA
553  SourceData sourceData;
554  if (sourceIdToData.TryGetValue(sourceId, out sourceData) && TryGetReading(sourceData.GripPosition, out position))
555  {
556  return true;
557  }
558 #endif
559 
560  position = default(Vector3);
561  return false;
562  }
563 
564  public override bool TryGetGripRotation(uint sourceId, out Quaternion rotation)
565  {
566 #if UNITY_WSA
567  SourceData sourceData;
568  if (sourceIdToData.TryGetValue(sourceId, out sourceData) && TryGetReading(sourceData.GripRotation, out rotation))
569  {
570  return true;
571  }
572 #endif
573 
574  rotation = default(Quaternion);
575  return false;
576  }
577 
578  public override bool TryGetThumbstick(uint sourceId, out bool thumbstickPressed, out Vector2 thumbstickPosition)
579  {
580 #if UNITY_WSA
581  SourceData sourceData;
582  AxisButton2D thumbstick;
583  if (sourceIdToData.TryGetValue(sourceId, out sourceData) && TryGetReading(sourceData.Thumbstick, out thumbstick))
584  {
585  thumbstickPressed = thumbstick.Pressed;
586  thumbstickPosition = thumbstick.Position;
587  return true;
588  }
589 #endif
590 
591  thumbstickPressed = false;
592  thumbstickPosition = Vector2.zero;
593  return false;
594  }
595 
596  public override bool TryGetTouchpad(uint sourceId, out bool touchpadPressed, out bool touchpadTouched, out Vector2 touchpadPosition)
597  {
598 #if UNITY_WSA
599  SourceData sourceData;
600  TouchpadData touchpad;
601  if (sourceIdToData.TryGetValue(sourceId, out sourceData) && TryGetReading(sourceData.Touchpad, out touchpad))
602  {
603  touchpadPressed = touchpad.AxisButton.Pressed;
604  touchpadTouched = touchpad.Touched;
605  touchpadPosition = touchpad.AxisButton.Position;
606  return true;
607  }
608 #endif
609 
610  touchpadPressed = false;
611  touchpadTouched = false;
612  touchpadPosition = Vector2.zero;
613  return false;
614  }
615 
616  public override bool TryGetSelect(uint sourceId, out bool selectPressed, out double selectPressedAmount)
617  {
618 #if UNITY_WSA
619  SourceData sourceData;
620  AxisButton1D select;
621  if (sourceIdToData.TryGetValue(sourceId, out sourceData) && TryGetReading(sourceData.Select, out select))
622  {
623  selectPressed = select.Pressed;
624  selectPressedAmount = select.PressedAmount;
625  return true;
626  }
627 #endif
628 
629  selectPressed = false;
630  selectPressedAmount = 0;
631  return false;
632  }
633 
634  public override bool TryGetGrasp(uint sourceId, out bool graspPressed)
635  {
636 #if UNITY_WSA
637  SourceData sourceData;
638  if (sourceIdToData.TryGetValue(sourceId, out sourceData) && TryGetReading(sourceData.Grasp, out graspPressed))
639  {
640  return true;
641  }
642 #endif
643 
644  graspPressed = false;
645  return false;
646  }
647 
648  public override bool TryGetMenu(uint sourceId, out bool menuPressed)
649  {
650 
651 #if UNITY_WSA
652  SourceData sourceData;
653  if (sourceIdToData.TryGetValue(sourceId, out sourceData) && TryGetReading(sourceData.Menu, out menuPressed))
654  {
655  return true;
656  }
657 #endif
658 
659  menuPressed = false;
660  return false;
661  }
662 
663 #if UNITY_WSA
664  private bool TryGetReading<TReading>(SourceCapability<TReading> capability, out TReading reading)
665  {
666  if (capability.IsAvailable)
667  {
668  Debug.Assert(capability.IsSupported);
669 
670  reading = capability.CurrentReading;
671  return true;
672  }
673  reading = default(TReading);
674  return false;
675  }
676 
677  private SupportedInputInfo GetSupportFlag<TReading>(SourceCapability<TReading> capability, SupportedInputInfo flagIfSupported)
678  {
679  return (capability.IsSupported ? flagIfSupported : SupportedInputInfo.None);
680  }
681 #endif
682  #endregion
683 
684 #if UNITY_WSA
685  private SourceData GetOrAddSourceData(InteractionSource interactionSource)
691  {
692  SourceData sourceData;
693  if (!sourceIdToData.TryGetValue(interactionSource.id, out sourceData))
694  {
695  sourceData = new SourceData(interactionSource);
696  sourceIdToData.Add(sourceData.SourceId, sourceData);
697 
698  // TODO: robertes: whenever we end up adding, should we first synthesize a SourceDetected? Or
699  // perhaps if we keep strict track of all sources, we should never need to just-in-time add anymore.
700  }
701 
702  return sourceData;
703  }
704 
710  private void UpdateSourceData(InteractionSourceState interactionSourceState, SourceData sourceData)
711  {
712  Debug.Assert(interactionSourceState.source.id == sourceData.SourceId, "An UpdateSourceState call happened with mismatched source ID.");
713  Debug.Assert(interactionSourceState.source.kind == sourceData.SourceKind, "An UpdateSourceState call happened with mismatched source kind.");
714 
715  Vector3 newPointerPosition = Vector3.zero;
716  sourceData.PointerPosition.IsAvailable =
717 #if UNITY_2017_2_OR_NEWER
718  interactionSourceState.sourcePose.TryGetPosition(out newPointerPosition, InteractionSourceNode.Pointer);
719 #else
720  interactionSourceState.properties.location.TryGetPosition(out newPointerPosition);
721 #endif
722  // Using a heuristic for IsSupported, since the APIs don't yet support querying this capability directly.
723  sourceData.PointerPosition.IsSupported |= sourceData.PointerPosition.IsAvailable;
724 
725  Vector3 newGripPosition = Vector3.zero;
726  sourceData.GripPosition.IsAvailable =
727 #if UNITY_2017_2_OR_NEWER
728  interactionSourceState.sourcePose.TryGetPosition(out newGripPosition, InteractionSourceNode.Grip);
729 #else
730  false;
731 #endif
732  // Using a heuristic for IsSupported, since the APIs don't yet support querying this capability directly.
733  sourceData.GripPosition.IsSupported |= sourceData.GripPosition.IsAvailable;
734 
735  if (CameraCache.Main.transform.parent != null)
736  {
737  newPointerPosition = CameraCache.Main.transform.parent.TransformPoint(newPointerPosition);
738  newGripPosition = CameraCache.Main.transform.parent.TransformPoint(newGripPosition);
739  }
740 
741  if (sourceData.PointerPosition.IsAvailable || sourceData.GripPosition.IsAvailable)
742  {
743  sourceData.PositionUpdated = !(sourceData.PointerPosition.CurrentReading.Equals(newPointerPosition) && sourceData.GripPosition.CurrentReading.Equals(newGripPosition));
744  }
745 
746  sourceData.PointerPosition.CurrentReading = newPointerPosition;
747  sourceData.GripPosition.CurrentReading = newGripPosition;
748 
749  Quaternion newPointerRotation = Quaternion.identity;
750  sourceData.PointerRotation.IsAvailable =
751 #if UNITY_2017_2_OR_NEWER
752  interactionSourceState.sourcePose.TryGetRotation(out newPointerRotation, InteractionSourceNode.Pointer);
753 #else
754  false;
755 #endif
756  // Using a heuristic for IsSupported, since the APIs don't yet support querying this capability directly.
757  sourceData.PointerRotation.IsSupported |= sourceData.PointerRotation.IsAvailable;
758 
759  Quaternion newGripRotation = Quaternion.identity;
760  sourceData.GripRotation.IsAvailable =
761 #if UNITY_2017_2_OR_NEWER
762  interactionSourceState.sourcePose.TryGetRotation(out newGripRotation, InteractionSourceNode.Grip);
763 #else
764  false;
765 #endif
766  // Using a heuristic for IsSupported, since the APIs don't yet support querying this capability directly.
767  sourceData.GripRotation.IsSupported |= sourceData.GripRotation.IsAvailable;
768 
769  if (CameraCache.Main.transform.parent != null)
770  {
771  newPointerRotation.eulerAngles = CameraCache.Main.transform.parent.TransformDirection(newPointerRotation.eulerAngles);
772  newGripRotation.eulerAngles = CameraCache.Main.transform.parent.TransformDirection(newGripRotation.eulerAngles);
773  }
774 
775  if (sourceData.PointerRotation.IsAvailable || sourceData.GripRotation.IsAvailable)
776  {
777  sourceData.RotationUpdated = !(sourceData.PointerRotation.CurrentReading.Equals(newPointerRotation) && sourceData.GripRotation.CurrentReading.Equals(newGripRotation));
778  }
779  sourceData.PointerRotation.CurrentReading = newPointerRotation;
780  sourceData.GripRotation.CurrentReading = newGripRotation;
781 
782  Vector3 pointerForward = Vector3.zero;
783  sourceData.PointingRay.IsSupported =
784 #if UNITY_2017_2_OR_NEWER
785  interactionSourceState.source.supportsPointing;
786 #else
787  false;
788 #endif
789  sourceData.PointingRay.IsAvailable =
790 #if UNITY_2017_2_OR_NEWER
791  sourceData.PointerPosition.IsAvailable && interactionSourceState.sourcePose.TryGetForward(out pointerForward, InteractionSourceNode.Pointer);
792 #else
793  false;
794 #endif
795 
796  if (CameraCache.Main.transform.parent != null)
797  {
798  pointerForward = CameraCache.Main.transform.parent.TransformDirection(pointerForward);
799  }
800 
801  sourceData.PointingRay.CurrentReading = new Ray(sourceData.PointerPosition.CurrentReading, pointerForward);
802 
803  sourceData.Thumbstick.IsSupported =
804 #if UNITY_2017_2_OR_NEWER
805  interactionSourceState.source.supportsThumbstick;
806 #else
807  false;
808 #endif
809  sourceData.Thumbstick.IsAvailable = sourceData.Thumbstick.IsSupported;
810  if (sourceData.Thumbstick.IsAvailable)
811  {
812  AxisButton2D newThumbstick = AxisButton2D.GetThumbstick(interactionSourceState);
813  sourceData.ThumbstickPositionUpdated = sourceData.Thumbstick.CurrentReading.Position != newThumbstick.Position;
814  sourceData.Thumbstick.CurrentReading = newThumbstick;
815  }
816  else
817  {
818  sourceData.Thumbstick.CurrentReading = default(AxisButton2D);
819  }
820 
821  sourceData.Touchpad.IsSupported =
822 #if UNITY_2017_2_OR_NEWER
823  interactionSourceState.source.supportsTouchpad;
824 #else
825  false;
826 #endif
827  sourceData.Touchpad.IsAvailable = sourceData.Touchpad.IsSupported;
828  if (sourceData.Touchpad.IsAvailable)
829  {
830  TouchpadData newTouchpad = TouchpadData.GetTouchpad(interactionSourceState);
831  sourceData.TouchpadPositionUpdated = !sourceData.Touchpad.CurrentReading.AxisButton.Position.Equals(newTouchpad.AxisButton.Position);
832  sourceData.TouchpadTouchedUpdated = !sourceData.Touchpad.CurrentReading.Touched.Equals(newTouchpad.Touched);
833  sourceData.Touchpad.CurrentReading = newTouchpad;
834  }
835  else
836  {
837  sourceData.Touchpad.CurrentReading = default(TouchpadData);
838  }
839 
840  sourceData.Select.IsSupported = true; // All input mechanisms support "select".
841  sourceData.Select.IsAvailable = sourceData.Select.IsSupported;
842  AxisButton1D newSelect = AxisButton1D.GetSelect(interactionSourceState);
843  sourceData.SelectPressedAmountUpdated = !sourceData.Select.CurrentReading.PressedAmount.Equals(newSelect.PressedAmount);
844  sourceData.Select.CurrentReading = newSelect;
845 
846  sourceData.Grasp.IsSupported =
847 #if UNITY_2017_2_OR_NEWER
848  interactionSourceState.source.supportsGrasp;
849 #else
850  false;
851 #endif
852  sourceData.Grasp.IsAvailable = sourceData.Grasp.IsSupported;
853  sourceData.Grasp.CurrentReading =
854 #if UNITY_2017_2_OR_NEWER
855  (sourceData.Grasp.IsAvailable && interactionSourceState.grasped);
856 #else
857  false;
858 #endif
859 
860  sourceData.Menu.IsSupported =
861 #if UNITY_2017_2_OR_NEWER
862  interactionSourceState.source.supportsMenu;
863 #else
864  false;
865 #endif
866  sourceData.Menu.IsAvailable = sourceData.Menu.IsSupported;
867  sourceData.Menu.CurrentReading =
868 #if UNITY_2017_2_OR_NEWER
869  (sourceData.Menu.IsAvailable && interactionSourceState.menuPressed);
870 #else
871  false;
872 #endif
873  }
874 #if UNITY_2017_2_OR_NEWER
875  #region InteractionManager Events
876 
877  private void InteractionManager_InteractionSourceUpdated(InteractionSourceUpdatedEventArgs args)
878  {
879  SourceData sourceData = GetOrAddSourceData(args.state.source);
880 
881  sourceData.ResetUpdatedBooleans();
882 
883  UpdateSourceData(args.state, sourceData);
884 
885  if (sourceData.PositionUpdated)
886  {
887  InputManager.Instance.RaiseSourcePositionChanged(this, sourceData.SourceId, sourceData.PointerPosition.CurrentReading, sourceData.GripPosition.CurrentReading);
888  }
889 
890  if (sourceData.RotationUpdated)
891  {
892  InputManager.Instance.RaiseSourceRotationChanged(this, sourceData.SourceId, sourceData.PointerRotation.CurrentReading, sourceData.GripRotation.CurrentReading);
893  }
894 
895  if (sourceData.ThumbstickPositionUpdated)
896  {
897  InputManager.Instance.RaiseInputPositionChanged(this, sourceData.SourceId, InteractionSourcePressInfo.Thumbstick, sourceData.Thumbstick.CurrentReading.Position);
898  }
899 
900  if (sourceData.TouchpadPositionUpdated)
901  {
902  InputManager.Instance.RaiseInputPositionChanged(this, sourceData.SourceId, InteractionSourcePressInfo.Touchpad, sourceData.Touchpad.CurrentReading.AxisButton.Position);
903  }
904 
905  if (sourceData.TouchpadTouchedUpdated)
906  {
907  if (sourceData.Touchpad.CurrentReading.Touched)
908  {
909  InputManager.Instance.RaiseTouchpadTouched(this, sourceData.SourceId);
910  }
911  else
912  {
913  InputManager.Instance.RaiseTouchpadReleased(this, sourceData.SourceId);
914  }
915  }
916 
917  if (sourceData.SelectPressedAmountUpdated)
918  {
919  InputManager.Instance.RaiseSelectPressedAmountChanged(this, sourceData.SourceId, sourceData.Select.CurrentReading.PressedAmount);
920  }
921  }
922 
923  private void InteractionManager_InteractionSourceReleased(InteractionSourceReleasedEventArgs args)
924  {
925  var pressType = (InteractionSourcePressInfo)args.pressType;
926  // HACK: If we're not dealing with a spatial controller we may not get Select called properly
927  if (args.state.source.kind != InteractionSourceKind.Controller || !args.state.source.supportsPointing)
928  {
929  pressType = InteractionSourcePressInfo.Select;
930  }
931 
932  InputManager.Instance.RaiseSourceUp(this, args.state.source.id, pressType);
933  }
934 
935  private void InteractionManager_InteractionSourcePressed(InteractionSourcePressedEventArgs args)
936  {
937  var pressType = (InteractionSourcePressInfo)args.pressType;
938  // HACK: If we're not dealing with a spatial controller we may not get Select called properly
939  if (args.state.source.kind != InteractionSourceKind.Controller || !args.state.source.supportsPointing)
940  {
941  pressType = InteractionSourcePressInfo.Select;
942  }
943 
944  InputManager.Instance.RaiseSourceDown(this, args.state.source.id, pressType);
945  }
946 
947  private void InteractionManager_InteractionSourceLost(InteractionSourceLostEventArgs args)
948  {
949  InputManager.Instance.RaiseSourceLost(this, args.state.source.id);
950 
951  // NOTE: We don't care whether the source ID previously existed or not, so we blindly call Remove:
952  sourceIdToData.Remove(args.state.source.id);
953  }
954 
955  private void InteractionManager_InteractionSourceDetected(InteractionSourceDetectedEventArgs args)
956  {
957  // NOTE: We update the source state data, in case an app wants to query it on source detected.
958  UpdateSourceData(args.state, GetOrAddSourceData(args.state.source));
959 
960  InputManager.Instance.RaiseSourceDetected(this, args.state.source.id);
961  }
962 
963  #endregion InteractionManager Events
964 
965  #region Raise GestureRecognizer Events
966 
967  // TODO: robertes: Should these also cause source state data to be stored/updated? What about SourceDetected synthesized events?
968 
969  protected void GestureRecognizer_Tapped(TappedEventArgs args)
970  {
971  InputManager.Instance.RaiseInputClicked(this, args.source.id, InteractionSourcePressInfo.Select, args.tapCount);
972  }
973 
974  protected void GestureRecognizer_HoldStarted(HoldStartedEventArgs args)
975  {
976  InputManager.Instance.RaiseHoldStarted(this, args.source.id);
977  }
978 
979  protected void GestureRecognizer_HoldCanceled(HoldCanceledEventArgs args)
980  {
981  InputManager.Instance.RaiseHoldCanceled(this, args.source.id);
982  }
983 
984  protected void GestureRecognizer_HoldCompleted(HoldCompletedEventArgs args)
985  {
986  InputManager.Instance.RaiseHoldCompleted(this, args.source.id);
987  }
988 
989  protected void GestureRecognizer_ManipulationStarted(ManipulationStartedEventArgs args)
990  {
991  InputManager.Instance.RaiseManipulationStarted(this, args.source.id);
992  }
993 
994  protected void GestureRecognizer_ManipulationUpdated(ManipulationUpdatedEventArgs args)
995  {
996  InputManager.Instance.RaiseManipulationUpdated(this, args.source.id, args.cumulativeDelta);
997  }
998 
999  protected void GestureRecognizer_ManipulationCompleted(ManipulationCompletedEventArgs args)
1000  {
1001  InputManager.Instance.RaiseManipulationCompleted(this, args.source.id, args.cumulativeDelta);
1002  }
1003 
1004  protected void GestureRecognizer_ManipulationCanceled(ManipulationCanceledEventArgs args)
1005  {
1006  InputManager.Instance.RaiseManipulationCanceled(this, args.source.id);
1007  }
1008 
1009  protected void NavigationGestureRecognizer_NavigationStarted(NavigationStartedEventArgs args)
1010  {
1011  InputManager.Instance.RaiseNavigationStarted(this, args.source.id);
1012  }
1013 
1014  protected void NavigationGestureRecognizer_NavigationUpdated(NavigationUpdatedEventArgs args)
1015  {
1016  InputManager.Instance.RaiseNavigationUpdated(this, args.source.id, args.normalizedOffset);
1017  }
1018 
1019  protected void NavigationGestureRecognizer_NavigationCompleted(NavigationCompletedEventArgs args)
1020  {
1021  InputManager.Instance.RaiseNavigationCompleted(this, args.source.id, args.normalizedOffset);
1022  }
1023 
1024  protected void NavigationGestureRecognizer_NavigationCanceled(NavigationCanceledEventArgs args)
1025  {
1026  InputManager.Instance.RaiseNavigationCanceled(this, args.source.id);
1027  }
1028 
1029  #endregion //Raise GestureRecognizer Events
1030 #else
1031 
1032  #region InteractionManager Events
1033 
1034  private void InteractionManager_InteractionSourceUpdated(InteractionSourceState state)
1035  {
1036  SourceData sourceData = GetOrAddSourceData(state.source);
1037 
1038  sourceData.ResetUpdatedBooleans();
1039 
1040  UpdateSourceData(state, sourceData);
1041 
1042  if (sourceData.PositionUpdated)
1043  {
1044  InputManager.Instance.RaiseSourcePositionChanged(this, sourceData.SourceId, sourceData.PointerPosition.CurrentReading, sourceData.GripPosition.CurrentReading);
1045  }
1046 
1047  if (sourceData.RotationUpdated)
1048  {
1049  InputManager.Instance.RaiseSourceRotationChanged(this, sourceData.SourceId, sourceData.PointerRotation.CurrentReading, sourceData.GripRotation.CurrentReading);
1050  }
1051 
1052  if (sourceData.ThumbstickPositionUpdated)
1053  {
1054  InputManager.Instance.RaiseInputPositionChanged(this, sourceData.SourceId, InteractionSourcePressInfo.Thumbstick, sourceData.Thumbstick.CurrentReading.Position);
1055  }
1056 
1057  if (sourceData.TouchpadPositionUpdated)
1058  {
1059  InputManager.Instance.RaiseInputPositionChanged(this, sourceData.SourceId, InteractionSourcePressInfo.Touchpad, sourceData.Touchpad.CurrentReading.AxisButton.Position);
1060  }
1061 
1062  if (sourceData.TouchpadTouchedUpdated)
1063  {
1064  if (sourceData.Touchpad.CurrentReading.Touched)
1065  {
1066  InputManager.Instance.RaiseTouchpadTouched(this, sourceData.SourceId);
1067  }
1068  else
1069  {
1070  InputManager.Instance.RaiseTouchpadReleased(this, sourceData.SourceId);
1071  }
1072  }
1073 
1074  if (sourceData.SelectPressedAmountUpdated)
1075  {
1076  InputManager.Instance.RaiseSelectPressedAmountChanged(this, sourceData.SourceId, sourceData.Select.CurrentReading.PressedAmount);
1077  }
1078  }
1079 
1080  private void InteractionManager_InteractionSourceReleased(InteractionSourceState state)
1081  {
1082  InputManager.Instance.RaiseSourceUp(this, state.source.id, InteractionSourcePressInfo.Select);
1083  }
1084 
1085  private void InteractionManager_InteractionSourcePressed(InteractionSourceState state)
1086  {
1087  InputManager.Instance.RaiseSourceDown(this, state.source.id, InteractionSourcePressInfo.Select);
1088  }
1089 
1090  private void InteractionManager_InteractionSourceLost(InteractionSourceState state)
1091  {
1092  // NOTE: We don't care whether the source ID previously existed or not, so we blindly call Remove:
1093  sourceIdToData.Remove(state.source.id);
1094 
1095  InputManager.Instance.RaiseSourceLost(this, state.source.id);
1096  }
1097 
1098  private void InteractionManager_InteractionSourceDetected(InteractionSourceState state)
1099  {
1100  // NOTE: We update the source state data, in case an app wants to query it on source detected.
1101  UpdateSourceData(state, GetOrAddSourceData(state.source));
1102 
1103  InputManager.Instance.RaiseSourceDetected(this, state.source.id);
1104  }
1105 
1106  #endregion InteractionManager Events
1107 
1108  #region Raise GestureRecognizer Events
1109 
1110  protected void GestureRecognizer_Tapped(InteractionSourceKind source, int tapCount, Ray headRay)
1111  {
1112  InputManager.Instance.RaiseInputClicked(this, 0, InteractionSourcePressInfo.Select, tapCount);
1113  }
1114 
1115  protected void GestureRecognizer_HoldStarted(InteractionSourceKind source, Ray headray)
1116  {
1117  InputManager.Instance.RaiseHoldStarted(this, 0);
1118  }
1119 
1120  protected void GestureRecognizer_HoldCanceled(InteractionSourceKind source, Ray headray)
1121  {
1122  InputManager.Instance.RaiseHoldCanceled(this, 0);
1123  }
1124 
1125  protected void GestureRecognizer_HoldCompleted(InteractionSourceKind source, Ray headray)
1126  {
1127  InputManager.Instance.RaiseHoldCompleted(this, 0);
1128  }
1129 
1130  protected void GestureRecognizer_ManipulationStarted(InteractionSourceKind source, Vector3 cumulativeDelta, Ray headray)
1131  {
1132  InputManager.Instance.RaiseManipulationStarted(this, 0);
1133  }
1134 
1135  protected void GestureRecognizer_ManipulationUpdated(InteractionSourceKind source, Vector3 cumulativeDelta, Ray headray)
1136  {
1137  InputManager.Instance.RaiseManipulationUpdated(this, 0, cumulativeDelta);
1138  }
1139 
1140  protected void GestureRecognizer_ManipulationCompleted(InteractionSourceKind source, Vector3 cumulativeDelta, Ray headray)
1141  {
1142  InputManager.Instance.RaiseManipulationCompleted(this, 0, cumulativeDelta);
1143  }
1144 
1145  protected void GestureRecognizer_ManipulationCanceled(InteractionSourceKind source, Vector3 cumulativeDelta, Ray headray)
1146  {
1147  InputManager.Instance.RaiseManipulationCanceled(this, 0);
1148  }
1149 
1150  protected void NavigationGestureRecognizer_NavigationStarted(InteractionSourceKind source, Vector3 normalizedOffset, Ray headray)
1151  {
1152  InputManager.Instance.RaiseNavigationStarted(this, 0);
1153  }
1154 
1155  protected void NavigationGestureRecognizer_NavigationUpdated(InteractionSourceKind source, Vector3 normalizedOffset, Ray headray)
1156  {
1157  InputManager.Instance.RaiseNavigationUpdated(this, 0, normalizedOffset);
1158  }
1159 
1160  protected void NavigationGestureRecognizer_NavigationCompleted(InteractionSourceKind source, Vector3 normalizedOffset, Ray headray)
1161  {
1162  InputManager.Instance.RaiseNavigationCompleted(this, 0, normalizedOffset);
1163  }
1164 
1165  protected void NavigationGestureRecognizer_NavigationCanceled(InteractionSourceKind source, Vector3 normalizedOffset, Ray headray)
1166  {
1167  InputManager.Instance.RaiseNavigationCanceled(this, 0);
1168  }
1169 
1170  #endregion //Raise GestureRecognizer Events
1171 #endif
1172 #endif
1173 
1174  }
1175 }
void StopGestureRecognizer()
Make sure the gesture recognizer is on, then stop it. Otherwise, leave it alone because it&#39;s already ...
Input source for gestures and interaction source information from the WSA APIs, which gives access to...
override bool TryGetSelect(uint sourceId, out bool selectPressed, out double selectPressedAmount)
Input Manager is responsible for managing input sources and dispatching relevant events to the approp...
Definition: InputManager.cs:19
override bool TryGetTouchpad(uint sourceId, out bool touchpadPressed, out bool touchpadTouched, out Vector2 touchpadPosition)
override bool TryGetGripPosition(uint sourceId, out Vector3 position)
Returns the position of the input source, if available. Not all input sources support positional info...
IsHandVisible AND IsInputSourceDown
override bool TryGetThumbstick(uint sourceId, out bool thumbstickPressed, out Vector2 thumbstickPosition)
override SupportedInputInfo GetSupportedInputInfo(uint sourceId)
Returns the input info that the input source can provide.
SupportedInputInfo
Flags used to indicate which input information is supported by an input source.
static void AssertIsInitialized()
Definition: Singleton.cs:49
The purpose of this class is to provide a cached reference to the main camera. Calling Camera...
Definition: CameraCache.cs:12
static T Instance
Returns the Singleton instance of the classes type. If no instance is found, then we search for an in...
Definition: Singleton.cs:26
void StartHaptics(uint sourceId, float intensity, float durationInSeconds)
static Camera Main
Returns a cached reference to the main camera and uses Camera.main if it hasn&#39;t been cached yet...
Definition: CameraCache.cs:20
bool TryGetHandedness(uint sourceId, out Handedness handedness)
override bool TryGetPointerPosition(uint sourceId, out Vector3 position)
Returns the position of the input source, if available. Not all input sources support positional info...
void StartGestureRecognizer()
Make sure the gesture recognizer is off, then start it. Otherwise, leave it alone because it&#39;s alread...
override bool TryGetPointerRotation(uint sourceId, out Quaternion rotation)
Returns the rotation of the input source, if available. Not all input sources support rotation inform...
Base class for an input source.
override bool TryGetMenu(uint sourceId, out bool menuPressed)
override bool TryGetGripRotation(uint sourceId, out Quaternion rotation)
Returns the rotation of the input source, if available. Not all input sources support rotation inform...
override bool TryGetPointingRay(uint sourceId, out Ray pointingRay)
Returns the pointing ray of the input source, if available. Not all input sources support pointing in...
override bool TryGetGrasp(uint sourceId, out bool graspPressed)
override bool TryGetSourceKind(uint sourceId, out InteractionSourceInfo sourceKind)