@@ -244,24 +244,55 @@ public override void Disable()
244244 /// <inheritdoc />
245245 public override void HandleEvent < T > ( BaseEventData eventData , ExecuteEvents . EventFunction < T > eventHandler )
246246 {
247+ Debug . Assert ( eventData != null ) ;
248+ Debug . Assert ( ! ( eventData is MixedRealityPointerEventData ) , "HandleEvent called with a pointer event. All events raised by pointer should call HandlePointerEvent" ) ;
249+
247250 if ( disabledRefCount > 0 )
248251 {
249252 return ;
250253 }
251254
252- Debug . Assert ( eventData != null ) ;
253255 var baseInputEventData = ExecuteEvents . ValidateEventData < BaseInputEventData > ( eventData ) ;
254- Debug . Assert ( baseInputEventData != null ) ;
255- Debug . Assert ( ! baseInputEventData . used ) ;
256+ DispatchEventToGlobalListeners ( baseInputEventData , eventHandler ) ;
257+
258+ if ( baseInputEventData . used )
259+ {
260+ // All global listeners get a chance to see the event,
261+ // but if any of them marked it used,
262+ // we stop the event from going any further.
263+ return ;
264+ }
265+
266+ Debug . Assert ( baseInputEventData . InputSource . Pointers != null , $ "InputSource { baseInputEventData . InputSource . SourceName } doesn't have any registered pointers! Input Sources without pointers should use the GazeProvider's pointer as a default fallback.") ;
267+
268+ var modalEventHandled = false ;
269+ // Get the focused object for each pointer of the event source
270+ for ( int i = 0 ; i < baseInputEventData . InputSource . Pointers . Length && ! baseInputEventData . used ; i ++ )
271+ {
272+ modalEventHandled = DispatchEventToObjectFocusedByPointer ( baseInputEventData . InputSource . Pointers [ i ] , baseInputEventData , modalEventHandled , eventHandler ) ;
273+ }
256274
257- if ( baseInputEventData . InputSource == null )
275+ if ( ! baseInputEventData . used )
276+ {
277+ DispatchEventToFallbackHandlers ( baseInputEventData , eventHandler ) ;
278+ }
279+ }
280+
281+ /// <summary>
282+ /// Handles a pointer event
283+ /// Assumption: We only send pointer events to the objects that pointers are focusing, except for global event listeners (which listen to everything)
284+ /// In contract, all other events get sent to all other pointers attached to a given input source
285+ /// </summary>
286+ private void HandlePointerEvent < T > ( BaseEventData eventData , ExecuteEvents . EventFunction < T > eventHandler ) where T : IMixedRealityPointerHandler
287+ {
288+ if ( disabledRefCount > 0 )
258289 {
259- Debug . LogError ( $ "Failed to find an input source for { baseInputEventData } ") ;
260290 return ;
261291 }
262292
263- // Send the event to global listeners
264- base . HandleEvent ( eventData , eventHandler ) ;
293+ Debug . Assert ( eventData != null ) ;
294+ var baseInputEventData = ExecuteEvents . ValidateEventData < BaseInputEventData > ( eventData ) ;
295+ DispatchEventToGlobalListeners ( baseInputEventData , eventHandler ) ;
265296
266297 if ( baseInputEventData . used )
267298 {
@@ -271,70 +302,86 @@ public override void HandleEvent<T>(BaseEventData eventData, ExecuteEvents.Event
271302 return ;
272303 }
273304
274- if ( baseInputEventData . InputSource . Pointers == null )
305+ Debug . Assert ( pointerEventData . Pointer != null , "Trying to dispatch event on pointer but pointerEventData is null" ) ;
306+
307+ DispatchEventToObjectFocusedByPointer ( pointerEventData . Pointer , baseInputEventData , false , eventHandler ) ;
308+
309+ if ( ! baseInputEventData . used )
275310 {
276- Debug . LogError ( $ "InputSource { baseInputEventData . InputSource . SourceName } doesn't have any registered pointers! Input Sources without pointers should use the GazeProvider's pointer as a default fallback.") ;
277- return ;
311+ DispatchEventToFallbackHandlers ( baseInputEventData , eventHandler ) ;
278312 }
313+ }
279314
280- var modalEventHandled = false ;
315+ /// <summary>
316+ /// Dispatch an input event to all global event listeners
317+ /// Return true if the event has been handled by a global event listener
318+ /// </summary>
319+ private void DispatchEventToGlobalListeners < T > ( BaseInputEventData baseInputEventData , ExecuteEvents . EventFunction < T > eventHandler ) where T : IEventSystemHandler
320+ {
321+ Debug . Assert ( baseInputEventData != null ) ;
322+ Debug . Assert ( ! baseInputEventData . used ) ;
323+ Debug . Assert ( baseInputEventData . InputSource != null , $ "Failed to find an input source for { baseInputEventData } ") ;
281324
282- // Get the focused object for each pointer of the event source
283- for ( int i = 0 ; i < baseInputEventData . InputSource . Pointers . Length ; i ++ )
325+ // Send the event to global listeners
326+ base . HandleEvent ( baseInputEventData , eventHandler ) ;
327+ }
328+
329+ private void DispatchEventToFallbackHandlers < T > ( BaseInputEventData baseInputEventData , ExecuteEvents . EventFunction < T > eventHandler ) where T : IEventSystemHandler
330+ {
331+ // If event was not handled by the focused object, pass it on to any fallback handlers
332+ if ( ! baseInputEventData . used && fallbackInputStack . Count > 0 )
284333 {
285- GameObject focusedObject = FocusProvider ? . GetFocusedObject ( baseInputEventData . InputSource . Pointers [ i ] ) ;
334+ GameObject fallbackInput = fallbackInputStack . Peek ( ) ;
335+ ExecuteEvents . ExecuteHierarchy ( fallbackInput , baseInputEventData , eventHandler ) ;
336+ }
337+ }
286338
287- // Handle modal input if one exists
288- if ( modalInputStack . Count > 0 && ! modalEventHandled )
289- {
290- GameObject modalInput = modalInputStack . Peek ( ) ;
339+
340+ /// <summary>
341+ /// Dispatch an input event to the object focused by the given IMixedRealityPointer.
342+ /// If a modal dialog is active, dispatch the pointer event to that modal dialog
343+ /// Returns true if the event was handled by a modal handler
344+ private bool DispatchEventToObjectFocusedByPointer < T > ( IMixedRealityPointer mixedRealityPointer , BaseInputEventData baseInputEventData ,
345+ bool modalEventHandled , ExecuteEvents . EventFunction < T > eventHandler ) where T : IEventSystemHandler
346+ {
347+ GameObject focusedObject = FocusProvider ? . GetFocusedObject ( mixedRealityPointer ) ;
291348
292- if ( modalInput != null )
293- {
294- modalEventHandled = true ;
349+ // Handle modal input if one exists
350+ if ( modalInputStack . Count > 0 && ! modalEventHandled )
351+ {
352+ GameObject modalInput = modalInputStack . Peek ( ) ;
295353
296- // If there is a focused object in the hierarchy of the modal handler, start the event bubble there
297- if ( focusedObject != null && focusedObject . transform . IsChildOf ( modalInput . transform ) )
298- {
299- if ( ExecuteEvents . ExecuteHierarchy ( focusedObject , baseInputEventData , eventHandler ) && baseInputEventData . used )
300- {
301- return ;
302- }
303- }
304- // Otherwise, just invoke the event on the modal handler itself
305- else
354+ if ( modalInput != null )
355+ {
356+ // If there is a focused object in the hierarchy of the modal handler, start the event bubble there
357+ if ( focusedObject != null && focusedObject . transform . IsChildOf ( modalInput . transform ) )
358+ {
359+ if ( ExecuteEvents . ExecuteHierarchy ( focusedObject , baseInputEventData , eventHandler ) && baseInputEventData . used )
306360 {
307- if ( ExecuteEvents . ExecuteHierarchy ( modalInput , baseInputEventData , eventHandler ) && baseInputEventData . used )
308- {
309- return ;
310- }
361+ return true ;
311362 }
312363 }
364+ // Otherwise, just invoke the event on the modal handler itself
313365 else
314366 {
315- Debug . LogError ( "ModalInput GameObject reference was null!\n Did this GameObject get destroyed?" ) ;
367+ if ( ExecuteEvents . ExecuteHierarchy ( modalInput , baseInputEventData , eventHandler ) && baseInputEventData . used )
368+ {
369+ return true ;
370+ }
316371 }
317372 }
318-
319- // If event was not handled by modal, pass it on to the current focused object
320- if ( focusedObject != null )
373+ else
321374 {
322- if ( ExecuteEvents . ExecuteHierarchy ( focusedObject , baseInputEventData , eventHandler ) && baseInputEventData . used )
323- {
324- return ;
325- }
375+ Debug . LogError ( "ModalInput GameObject reference was null!\n Did this GameObject get destroyed?" ) ;
326376 }
327377 }
328378
329- // If event was not handled by the focused object , pass it on to any fallback handlers
330- if ( fallbackInputStack . Count > 0 )
379+ // If event was not handled by modal , pass it on to the current focused object
380+ if ( focusedObject != null )
331381 {
332- GameObject fallbackInput = fallbackInputStack . Peek ( ) ;
333- if ( ExecuteEvents . ExecuteHierarchy ( fallbackInput , baseInputEventData , eventHandler ) && baseInputEventData . used )
334- {
335- // return;
336- }
382+ ExecuteEvents . ExecuteHierarchy ( focusedObject , baseInputEventData , eventHandler ) ;
337383 }
384+ return modalEventHandled ;
338385 }
339386
340387 /// <summary>
@@ -820,7 +867,8 @@ public void RaisePointerDown(IMixedRealityPointer pointer, MixedRealityInputActi
820867 private GraphicInputEventData HandlePointerDown ( IMixedRealityPointer pointer )
821868 {
822869 // Pass handler through HandleEvent to perform modal/fallback logic
823- HandleEvent ( pointerEventData , OnPointerDownEventHandler ) ;
870+ HandlePointerEvent ( pointerEventData , OnPointerDownEventHandler ) ;
871+
824872 GraphicInputEventData graphicEventData ;
825873 FocusProvider . TryGetSpecificPointerGraphicEventData ( pointer , out graphicEventData ) ;
826874 return graphicEventData ;
@@ -866,7 +914,7 @@ public void RaisePointerClicked(IMixedRealityPointer pointer, MixedRealityInputA
866914 private void HandleClick ( )
867915 {
868916 // Pass handler through HandleEvent to perform modal/fallback logic
869- HandleEvent ( pointerEventData , OnInputClickedEventHandler ) ;
917+ HandlePointerEvent ( pointerEventData , OnInputClickedEventHandler ) ;
870918
871919 // NOTE: In Unity UI, a "click" happens on every pointer up, so we have RaisePointerUp call the pointerClickHandler.
872920 }
@@ -917,7 +965,7 @@ private static void ExecutePointerUp(GraphicInputEventData graphicInputEventData
917965 private GraphicInputEventData HandlePointerUp ( IMixedRealityPointer pointer )
918966 {
919967 // Pass handler through HandleEvent to perform modal/fallback logic
920- HandleEvent ( pointerEventData , OnPointerUpEventHandler ) ;
968+ HandlePointerEvent ( pointerEventData , OnPointerUpEventHandler ) ;
921969
922970 GraphicInputEventData graphicEventData ;
923971 FocusProvider . TryGetSpecificPointerGraphicEventData ( pointer , out graphicEventData ) ;
0 commit comments