33
44using UnityEngine ;
55using UnityEngine . VR . WSA . Input ;
6+ using System . Collections . Generic ;
67
78namespace HoloToolkit . Unity
89{
910 /// <summary>
10- /// GestureManager creates a gesture recognizer and signs up for a tap gesture.
11+ /// GestureManager provides access to several different input gestures, including
12+ /// Tap and Manipulation.
13+ /// </summary>
14+ /// <remarks>
1115 /// When a tap gesture is detected, GestureManager uses GazeManager to find the game object.
1216 /// GestureManager then sends a message to that game object.
13- /// </summary>
17+ ///
18+ /// Using Manipulation requires subscribing the the ManipulationStarted events and then querying
19+ /// information about the manipulation gesture via ManipulationOffset and ManipulationHandPosition
20+ /// </remarks>
1421 [ RequireComponent ( typeof ( GazeManager ) ) ]
1522 public partial class GestureManager : Singleton < GestureManager >
1623 {
24+ /// <summary>
25+ /// Occurs when a manipulation gesture has started
26+ /// </summary>
27+ public System . Action ManipulationStarted ;
28+
29+ /// <summary>
30+ /// Occurs when a manipulation gesture ended as a result of user input
31+ /// </summary>
32+ public System . Action ManipulationCompleted ;
33+
34+ /// <summary>
35+ /// Occurs when a manipulated gesture ended as a result of some other condition.
36+ /// (e.g. the hand being used for the gesture is no longer visible).
37+ /// </summary>
38+ public System . Action ManipulationCanceled ;
39+
1740 /// <summary>
1841 /// Key to press in the editor to select the currently gazed hologram
1942 /// </summary>
@@ -24,66 +47,180 @@ public partial class GestureManager : Singleton<GestureManager>
2447 /// set the override focused object.
2548 /// If its null, then the gazed at object will be selected.
2649 /// </summary>
27- public GameObject OverrideFocusedObject
28- {
29- get ; set ;
30- }
31-
50+ public GameObject OverrideFocusedObject { get ; set ; }
51+
3252 /// <summary>
3353 /// Gets the currently focused object, or null if none.
3454 /// </summary>
35- public GameObject FocusedObject
55+ public GameObject FocusedObject { get ; private set ; }
56+
57+ /// <summary>
58+ /// Whether or not a manipulation gesture is currently in progress
59+ /// </summary>
60+ public bool ManipulationInProgress { get ; private set ; }
61+
62+ /// <summary>
63+ /// The offset of the hand from its position at the beginning of
64+ /// the currently active manipulation gesture, in world space. Not valid if
65+ /// a manipulation gesture is not in progress
66+ /// </summary>
67+ public Vector3 ManipulationOffset { get ; private set ; }
68+
69+ /// <summary>
70+ /// The world space position of the hand being used for the current manipulation gesture. Not valid
71+ /// if a manipulation gesture is not in progress.
72+ /// </summary>
73+ public Vector3 ManipulationHandPosition
3674 {
37- get { return focusedObject ; }
75+ get
76+ {
77+ Vector3 handPosition = Vector3 . zero ;
78+ currentHandState . properties . location . TryGetPosition ( out handPosition ) ;
79+ return handPosition ;
80+ }
3881 }
3982
4083 private GestureRecognizer gestureRecognizer ;
41- private GameObject focusedObject ;
84+ // We use a separate manipulation recognizer here because the tap gesture recognizer cancels
85+ // capturing gestures whenever the GazeManager focus changes, which is not the behavior
86+ // we want for manipulation
87+ private GestureRecognizer manipulationRecognizer ;
88+
89+ private bool HandPressed { get { return pressedHands . Count > 0 ; } }
90+ private HashSet < uint > pressedHands = new HashSet < uint > ( ) ;
91+
92+ private InteractionSourceState currentHandState ;
4293
4394 void Start ( )
4495 {
96+ InteractionManager . SourcePressed += InteractionManager_SourcePressed ;
97+ InteractionManager . SourceReleased += InteractionManager_SourceReleased ;
98+ InteractionManager . SourceUpdated += InteractionManager_SourceUpdated ;
99+ InteractionManager . SourceLost += InteractionManager_SourceLost ;
100+
45101 // Create a new GestureRecognizer. Sign up for tapped events.
46102 gestureRecognizer = new GestureRecognizer ( ) ;
47103 gestureRecognizer . SetRecognizableGestures ( GestureSettings . Tap ) ;
48104
105+ manipulationRecognizer = new GestureRecognizer ( ) ;
106+ manipulationRecognizer . SetRecognizableGestures ( GestureSettings . ManipulationTranslate ) ;
107+
49108 gestureRecognizer . TappedEvent += GestureRecognizer_TappedEvent ;
50109
110+ manipulationRecognizer . ManipulationStartedEvent += ManipulationRecognizer_ManipulationStartedEvent ;
111+ manipulationRecognizer . ManipulationUpdatedEvent += ManipulationRecognizer_ManipulationUpdatedEvent ;
112+ manipulationRecognizer . ManipulationCompletedEvent += ManipulationRecognizer_ManipulationCompletedEvent ;
113+ manipulationRecognizer . ManipulationCanceledEvent += ManipulationRecognizer_ManipulationCanceledEvent ;
114+
51115 // Start looking for gestures.
52116 gestureRecognizer . StartCapturingGestures ( ) ;
117+ manipulationRecognizer . StartCapturingGestures ( ) ;
53118 }
54119
55- private void OnTap ( )
120+
121+
122+ private void InteractionManager_SourcePressed ( InteractionSourceState state )
123+ {
124+ if ( ! HandPressed )
125+ {
126+ currentHandState = state ;
127+ }
128+
129+ pressedHands . Add ( state . source . id ) ;
130+ }
131+
132+ private void InteractionManager_SourceUpdated ( InteractionSourceState state )
56133 {
57- if ( focusedObject != null )
134+ if ( HandPressed && state . source . id == currentHandState . source . id )
58135 {
59- focusedObject . SendMessage ( "OnSelect" ) ;
136+ currentHandState = state ;
60137 }
61138 }
62139
140+ private void InteractionManager_SourceReleased ( InteractionSourceState state )
141+ {
142+ pressedHands . Remove ( state . source . id ) ;
143+ }
144+
145+ private void InteractionManager_SourceLost ( InteractionSourceState state )
146+ {
147+ pressedHands . Remove ( state . source . id ) ;
148+ }
149+
63150 private void GestureRecognizer_TappedEvent ( InteractionSourceKind source , int tapCount , Ray headRay )
64151 {
65152 OnTap ( ) ;
66153 }
67154
155+ private void OnTap ( )
156+ {
157+ if ( FocusedObject != null )
158+ {
159+ FocusedObject . SendMessage ( "OnSelect" ) ;
160+ }
161+ }
162+
163+ private void ManipulationRecognizer_ManipulationStartedEvent ( InteractionSourceKind source , Vector3 cumulativeDelta , Ray headRay )
164+ {
165+ // Don't start another manipulation gesture if one is already underway
166+ if ( ! ManipulationInProgress )
167+ {
168+ OnManipulation ( true , cumulativeDelta ) ;
169+ if ( ManipulationStarted != null )
170+ {
171+ ManipulationStarted ( ) ;
172+ }
173+ }
174+ }
175+
176+ private void ManipulationRecognizer_ManipulationUpdatedEvent ( InteractionSourceKind source , Vector3 cumulativeDelta , Ray headRay )
177+ {
178+ OnManipulation ( true , cumulativeDelta ) ;
179+ }
180+
181+ private void ManipulationRecognizer_ManipulationCompletedEvent ( InteractionSourceKind source , Vector3 cumulativeDelta , Ray headRay )
182+ {
183+ OnManipulation ( false , cumulativeDelta ) ;
184+ if ( ManipulationCompleted != null )
185+ {
186+ ManipulationCompleted ( ) ;
187+ }
188+ }
189+
190+ private void ManipulationRecognizer_ManipulationCanceledEvent ( InteractionSourceKind source , Vector3 cumulativeDelta , Ray headRay )
191+ {
192+ OnManipulation ( false , cumulativeDelta ) ;
193+ if ( ManipulationCanceled != null )
194+ {
195+ ManipulationCanceled ( ) ;
196+ }
197+ }
198+
199+ private void OnManipulation ( bool inProgress , Vector3 offset )
200+ {
201+ ManipulationInProgress = inProgress ;
202+ ManipulationOffset = offset ;
203+ }
204+
68205 void LateUpdate ( )
69206 {
70- GameObject oldFocusedObject = focusedObject ;
207+ GameObject oldFocusedObject = FocusedObject ;
71208
72209 if ( GazeManager . Instance . Hit &&
73210 OverrideFocusedObject == null &&
74211 GazeManager . Instance . HitInfo . collider != null )
75212 {
76213 // If gaze hits a hologram, set the focused object to that game object.
77214 // Also if the caller has not decided to override the focused object.
78- focusedObject = GazeManager . Instance . HitInfo . collider . gameObject ;
215+ FocusedObject = GazeManager . Instance . HitInfo . collider . gameObject ;
79216 }
80217 else
81218 {
82219 // If our gaze doesn't hit a hologram, set the focused object to null or override focused object.
83- focusedObject = OverrideFocusedObject ;
220+ FocusedObject = OverrideFocusedObject ;
84221 }
85222
86- if ( focusedObject != oldFocusedObject )
223+ if ( FocusedObject != oldFocusedObject )
87224 {
88225 // If the currently focused object doesn't match the old focused object, cancel the current gesture.
89226 // Start looking for new gestures. This is to prevent applying gestures from one hologram to another.
@@ -103,6 +240,17 @@ void OnDestroy()
103240 {
104241 gestureRecognizer . StopCapturingGestures ( ) ;
105242 gestureRecognizer . TappedEvent -= GestureRecognizer_TappedEvent ;
243+
244+ manipulationRecognizer . StopCapturingGestures ( ) ;
245+ manipulationRecognizer . ManipulationStartedEvent -= ManipulationRecognizer_ManipulationStartedEvent ;
246+ manipulationRecognizer . ManipulationUpdatedEvent -= ManipulationRecognizer_ManipulationUpdatedEvent ;
247+ manipulationRecognizer . ManipulationCompletedEvent -= ManipulationRecognizer_ManipulationCompletedEvent ;
248+ manipulationRecognizer . ManipulationCanceledEvent -= ManipulationRecognizer_ManipulationCanceledEvent ;
249+
250+ InteractionManager . SourcePressed -= InteractionManager_SourcePressed ;
251+ InteractionManager . SourceReleased -= InteractionManager_SourceReleased ;
252+ InteractionManager . SourceUpdated -= InteractionManager_SourceUpdated ;
253+ InteractionManager . SourceLost -= InteractionManager_SourceLost ;
106254 }
107255 }
108256}
0 commit comments