@@ -29,6 +29,9 @@ public EditorHandData(uint handId)
2929 IsFingerDownPending = false ;
3030 FingerStateChanged = false ;
3131 FingerStateUpdateTimer = - 1 ;
32+ ManipulationInProgress = false ;
33+ HoldInProgress = false ;
34+ CumulativeDelta = Vector3 . zero ;
3235 }
3336
3437 public readonly uint HandId ;
@@ -38,13 +41,16 @@ public EditorHandData(uint handId)
3841 public bool IsFingerDownPending ;
3942 public bool FingerStateChanged ;
4043 public float FingerStateUpdateTimer ;
41- public float FingerDownStartTime ;
44+ public float FingerDownStartTime ;
45+ public bool ManipulationInProgress ;
46+ public bool HoldInProgress ;
47+ public Vector3 CumulativeDelta ;
4248 }
4349
4450 private ManualHandControl manualHandControl ;
4551
4652 /// <summary>
47- /// Dispatched each frame that a hand is moving
53+ /// Dispatched each frame that a hand is moving.
4854 /// </summary>
4955 public event Action < IInputSource , uint > HandMoved ;
5056
@@ -65,7 +71,7 @@ public EditorHandData(uint handId)
6571 private const int EditorHandsCount = 2 ;
6672
6773 /// <summary>
68- /// Array containing the hands data for the two fake hands
74+ /// Array containing the hands data for the two fake hands.
6975 /// </summary>
7076 private readonly EditorHandData [ ] editorHandsData = new EditorHandData [ EditorHandsCount ] ;
7177
@@ -75,10 +81,14 @@ public EditorHandData(uint handId)
7581 private readonly Dictionary < uint , EditorHandData > handIdToData = new Dictionary < uint , EditorHandData > ( 4 ) ;
7682 private readonly List < uint > pendingHandIdDeletes = new List < uint > ( ) ;
7783
78- // HashSets used to be able to quickly update the hands data when hands become visible / not visible
84+ // HashSets used to be able to quickly update the hands data when hands become visible / not visible.
7985 private readonly HashSet < uint > currentHands = new HashSet < uint > ( ) ;
8086 private readonly HashSet < uint > newHands = new HashSet < uint > ( ) ;
8187
88+ [ SerializeField ]
89+ [ Tooltip ( "The total amount of hand movement that needs to happen to signal intent to start a manipulation. This is a distance, but not a distance in any one direction." ) ]
90+ private float manipulationStartMovementThreshold = 0.03f ;
91+
8292 public override SupportedInputInfo GetSupportedInputInfo ( uint sourceId )
8393 {
8494 return SupportedInputInfo . Position ;
@@ -98,7 +108,7 @@ public override bool TryGetPosition(uint sourceId, out Vector3 position)
98108
99109 public override bool TryGetOrientation ( uint sourceId , out Quaternion orientation )
100110 {
101- // Orientation is not supported by hands
111+ // Orientation is not supported by hands.
102112 orientation = Quaternion . identity ;
103113 return false ;
104114 }
@@ -112,55 +122,55 @@ public Vector3 GetHandDelta(uint handId)
112122 {
113123 if ( handId >= editorHandsData . Length )
114124 {
115- string message = string . Format ( "GetHandDelta called with invalid hand ID {0}." , handId ) ;
125+ string message = string . Format ( "GetHandDelta called with invalid hand ID {0}." , handId . ToString ( ) ) ;
116126 throw new ArgumentException ( message , "handId" ) ;
117127 }
118128
119129 return editorHandsData [ handId ] . HandDelta ;
120130 }
121131
122132 /// <summary>
123- /// Gets the pressed state of the specified hand
133+ /// Gets the pressed state of the specified hand.
124134 /// </summary>
125135 /// <param name="handId">ID of the hand to get.</param>
126136 /// <returns>True if the specified hand is currently in an airtap.</returns>
127137 public bool GetFingerState ( uint handId )
128138 {
129139 if ( handId >= editorHandsData . Length )
130140 {
131- var message = string . Format ( "GetFingerState called with invalid hand ID {0}." , handId ) ;
141+ var message = string . Format ( "GetFingerState called with invalid hand ID {0}." , handId . ToString ( ) ) ;
132142 throw new ArgumentException ( message , "handId" ) ;
133143 }
134144
135145 return editorHandsData [ handId ] . IsFingerDown ;
136146 }
137147
138148 /// <summary>
139- /// Gets whether the specified hand just started an airtap this frame
149+ /// Gets whether the specified hand just started an airtap this frame.
140150 /// </summary>
141151 /// <param name="handId">ID of the hand to get.</param>
142152 /// <returns>True for the first frame of an airtap</returns>
143153 public bool GetFingerDown ( uint handId )
144154 {
145155 if ( handId >= editorHandsData . Length )
146156 {
147- var message = string . Format ( "GetFingerDown called with invalid hand ID {0}." , handId ) ;
157+ var message = string . Format ( "GetFingerDown called with invalid hand ID {0}." , handId . ToString ( ) ) ;
148158 throw new ArgumentException ( message , "handId" ) ;
149159 }
150160
151161 return editorHandsData [ handId ] . IsFingerDown && editorHandsData [ handId ] . FingerStateChanged ;
152162 }
153163
154164 /// <summary>
155- /// Gets whether the specified hand just ended an airtap this frame
165+ /// Gets whether the specified hand just ended an airtap this frame.
156166 /// </summary>
157167 /// <param name="handId">ID of the hand to get.</param>
158168 /// <returns>True for the first frame of the release of an airtap</returns>
159169 public bool GetFingerUp ( uint handId )
160170 {
161171 if ( handId >= editorHandsData . Length )
162172 {
163- var message = string . Format ( "GetFingerUp called with invalid hand ID {0}." , handId ) ;
173+ var message = string . Format ( "GetFingerUp called with invalid hand ID {0}." , handId . ToString ( ) ) ;
164174 throw new ArgumentException ( message , "handId" ) ;
165175 }
166176
@@ -171,12 +181,13 @@ private void Awake()
171181 {
172182#if ! UNITY_EDITOR
173183 Destroy ( this ) ;
174- #endif
184+ #else
175185 manualHandControl = GetComponent < ManualHandControl > ( ) ;
176186 for ( uint i = 0 ; i < editorHandsData . Length ; i ++ )
177187 {
178188 editorHandsData [ i ] = new EditorHandData ( i ) ;
179189 }
190+ #endif
180191 }
181192
182193#if UNITY_EDITOR
@@ -238,7 +249,6 @@ private EditorHandData GetOrAddHandData(uint sourceId)
238249 handData = new EditorHandData ( sourceId ) ;
239250 handIdToData . Add ( handData . HandId , handData ) ;
240251 newHands . Add ( handData . HandId ) ;
241-
242252 }
243253
244254 return handData ;
@@ -249,24 +259,26 @@ private EditorHandData GetOrAddHandData(uint sourceId)
249259 /// </summary>
250260 /// <param name="handSource">Hand source to use to update the position.</param>
251261 /// <param name="editorHandData">EditorHandData structure to update.</param>
262+ /// <param name="deltaTime">Unscaled delta time of last event.</param>
263+ /// <param name="time">Unscaled time of last event.</param>
252264 private void UpdateHandState ( DebugInteractionSourceState handSource , EditorHandData editorHandData , float deltaTime , float time )
253265 {
254- // Update hand position
266+ // Update hand position.
255267 Vector3 handPosition ;
256268 if ( handSource . Properties . Location . TryGetPosition ( out handPosition ) )
257269 {
258270 editorHandData . HandDelta = handPosition - editorHandData . HandPosition ;
259271 editorHandData . HandPosition = handPosition ;
260272 }
261273
262- // Check for finger presses
274+ // Check for finger presses.
263275 if ( handSource . Pressed != editorHandData . IsFingerDownPending )
264276 {
265277 editorHandData . IsFingerDownPending = handSource . Pressed ;
266278 editorHandData . FingerStateUpdateTimer = FingerPressDelay ;
267279 }
268280
269- // Finger presses are delayed to mitigate issue with hand position shifting during air tap
281+ // Finger presses are delayed to mitigate issue with hand position shifting during air tap.
270282 editorHandData . FingerStateChanged = false ;
271283 if ( editorHandData . FingerStateUpdateTimer > 0 )
272284 {
@@ -289,31 +301,79 @@ private void UpdateHandState(DebugInteractionSourceState handSource, EditorHandD
289301 /// Sends the events for hand state changes.
290302 /// </summary>
291303 /// <param name="editorHandData">Hand data for which events should be sent.</param>
304+ /// <param name="time">Unscaled time of last event.</param>
292305 private void SendHandStateEvents ( EditorHandData editorHandData , float time )
293306 {
294- // Hand moved event
307+ // Hand moved event.
295308 if ( editorHandData . HandDelta . sqrMagnitude > 0 )
296309 {
297310 HandMoved . RaiseEvent ( this , editorHandData . HandId ) ;
298311 }
299312
300- // Finger pressed/released events
313+ // If the finger state has just changed to be down vs up.
301314 if ( editorHandData . FingerStateChanged )
302315 {
316+ // New down presses are straightforward - fire input down and be on your way.
303317 if ( editorHandData . IsFingerDown )
304318 {
305319 inputManager . RaiseSourceDown ( this , editorHandData . HandId ) ;
320+ editorHandData . CumulativeDelta = Vector3 . zero ;
306321 }
322+ // New up presses require sending different events depending on whether it's also a click, hold, or manipulation.
307323 else
308324 {
325+ // A gesture is always either a click, a hold or a manipulation.
326+ if ( editorHandData . ManipulationInProgress )
327+ {
328+ inputManager . RaiseManipulationCompleted ( this , editorHandData . HandId , editorHandData . CumulativeDelta ) ;
329+ editorHandData . ManipulationInProgress = false ;
330+ }
331+ // Clicks and holds are based on time, and both are overruled by manipulations.
332+ else if ( editorHandData . HoldInProgress )
333+ {
334+ inputManager . RaiseHoldCompleted ( this , editorHandData . HandId ) ;
335+ editorHandData . HoldInProgress = false ;
336+ }
337+ else
338+ {
339+ // We currently only support single taps in editor.
340+ inputManager . RaiseInputClicked ( this , editorHandData . HandId , 1 ) ;
341+ }
342+
309343 inputManager . RaiseSourceUp ( this , editorHandData . HandId ) ;
344+ }
345+ }
346+ // If the finger state hasn't changed, and the finger is down, that means if calculations need to be done
347+ // nothing might change, or it might trigger a hold or a manipulation (or a hold and then a manipulation).
348+ else if ( editorHandData . IsFingerDown )
349+ {
350+ editorHandData . CumulativeDelta += editorHandData . HandDelta ;
310351
311- // Also send click event when using this hands replacement input
312- if ( time - editorHandData . FingerDownStartTime < MaxClickDuration )
352+ if ( ! editorHandData . ManipulationInProgress )
353+ {
354+ // Manipulations are triggered by the amount of movement since the finger was pressed down.
355+ if ( editorHandData . CumulativeDelta . magnitude > manipulationStartMovementThreshold )
313356 {
314- // We currently only support single taps in editor
315- inputManager . RaiseInputClicked ( this , editorHandData . HandId , 1 ) ;
316- }
357+ // Starting a manipulation will cancel an existing hold.
358+ if ( editorHandData . HoldInProgress )
359+ {
360+ inputManager . RaiseHoldCanceled ( this , editorHandData . HandId ) ;
361+ editorHandData . HoldInProgress = false ;
362+ }
363+
364+ inputManager . RaiseManipulationStarted ( this , editorHandData . HandId , editorHandData . CumulativeDelta ) ;
365+ editorHandData . ManipulationInProgress = true ;
366+ }
367+ // Holds are triggered by time.
368+ else if ( ! editorHandData . HoldInProgress && ( time - editorHandData . FingerDownStartTime >= MaxClickDuration ) )
369+ {
370+ inputManager . RaiseHoldStarted ( this , editorHandData . HandId ) ;
371+ editorHandData . HoldInProgress = true ;
372+ }
373+ }
374+ else
375+ {
376+ inputManager . RaiseManipulationUpdated ( this , editorHandData . HandId , editorHandData . CumulativeDelta ) ;
317377 }
318378 }
319379 }
@@ -323,13 +383,13 @@ private void SendHandStateEvents(EditorHandData editorHandData, float time)
323383 /// </summary>
324384 private void SendHandVisibilityEvents ( )
325385 {
326- // Send event for new hands that were added
386+ // Send event for new hands that were added.
327387 foreach ( uint newHand in newHands )
328388 {
329389 inputManager . RaiseSourceDetected ( this , newHand ) ;
330390 }
331391
332- // Send event for hands that are no longer visible and remove them from our dictionary
392+ // Send event for hands that are no longer visible and remove them from our dictionary.
333393 foreach ( uint existingHand in handIdToData . Keys )
334394 {
335395 if ( ! currentHands . Contains ( existingHand ) )
@@ -339,12 +399,12 @@ private void SendHandVisibilityEvents()
339399 }
340400 }
341401
342- // Remove pending hand IDs
402+ // Remove pending hand IDs.
343403 for ( int i = 0 ; i < pendingHandIdDeletes . Count ; ++ i )
344404 {
345405 handIdToData . Remove ( pendingHandIdDeletes [ i ] ) ;
346406 }
347407 pendingHandIdDeletes . Clear ( ) ;
348408 }
349409 }
350- }
410+ }
0 commit comments