Skip to content

Commit 6055d4e

Browse files
author
David Kline
authored
Merge pull request #3725 from keveleigh/pointer-focus-dispatch-rework
Pointer focus dispatch rework
2 parents 21358fc + 5e7a8dd commit 6055d4e

File tree

1 file changed

+102
-60
lines changed

1 file changed

+102
-60
lines changed

Assets/MixedRealityToolkit.Services/InputSystem/MixedRealityInputSystem.cs

Lines changed: 102 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -250,18 +250,49 @@ public override void HandleEvent<T>(BaseEventData eventData, ExecuteEvents.Event
250250
}
251251

252252
Debug.Assert(eventData != null);
253+
Debug.Assert(!(eventData is MixedRealityPointerEventData), "HandleEvent called with a pointer event. All events raised by pointer should call HandlePointerEvent");
254+
253255
var baseInputEventData = ExecuteEvents.ValidateEventData<BaseInputEventData>(eventData);
254-
Debug.Assert(baseInputEventData != null);
255-
Debug.Assert(!baseInputEventData.used);
256+
DispatchEventToGlobalListeners(baseInputEventData, eventHandler);
256257

257-
if (baseInputEventData.InputSource == null)
258+
if (baseInputEventData.used)
258259
{
259-
Debug.LogError($"Failed to find an input source for {baseInputEventData}");
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.
260263
return;
261264
}
262265

263-
// Send the event to global listeners
264-
base.HandleEvent(eventData, eventHandler);
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+
}
274+
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)
289+
{
290+
return;
291+
}
292+
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+
/// <summary>
340+
/// Dispatch an input event to the object focused by the given IMixedRealityPointer.
341+
/// If a modal dialog is active, dispatch the pointer event to that modal dialog
342+
/// Returns true if the event was handled by a modal handler
343+
/// </summary>
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!\nDid 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!\nDid 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>
@@ -802,10 +849,7 @@ public void RaiseFocusExit(IMixedRealityPointer pointer, GameObject unfocusedObj
802849
/// <inheritdoc />
803850
public void RaisePointerDown(IMixedRealityPointer pointer, Handedness handedness, MixedRealityInputAction inputAction)
804851
{
805-
// Create input event
806-
pointerEventData.Initialize(pointer, handedness, inputAction);
807-
808-
ExecutePointerDown(HandlePointerDown(pointer));
852+
RaisePointerDown(pointer, inputAction, handedness);
809853
}
810854

811855
/// <inheritdoc />
@@ -820,7 +864,8 @@ public void RaisePointerDown(IMixedRealityPointer pointer, MixedRealityInputActi
820864
private GraphicInputEventData HandlePointerDown(IMixedRealityPointer pointer)
821865
{
822866
// Pass handler through HandleEvent to perform modal/fallback logic
823-
HandleEvent(pointerEventData, OnPointerDownEventHandler);
867+
HandlePointerEvent(pointerEventData, OnPointerDownEventHandler);
868+
824869
GraphicInputEventData graphicEventData;
825870
FocusProvider.TryGetSpecificPointerGraphicEventData(pointer, out graphicEventData);
826871
return graphicEventData;
@@ -866,7 +911,7 @@ public void RaisePointerClicked(IMixedRealityPointer pointer, MixedRealityInputA
866911
private void HandleClick()
867912
{
868913
// Pass handler through HandleEvent to perform modal/fallback logic
869-
HandleEvent(pointerEventData, OnInputClickedEventHandler);
914+
HandlePointerEvent(pointerEventData, OnInputClickedEventHandler);
870915

871916
// NOTE: In Unity UI, a "click" happens on every pointer up, so we have RaisePointerUp call the pointerClickHandler.
872917
}
@@ -885,10 +930,7 @@ private void HandleClick()
885930
/// <inheritdoc />
886931
public void RaisePointerUp(IMixedRealityPointer pointer, Handedness handedness, MixedRealityInputAction inputAction)
887932
{
888-
// Create input event
889-
pointerEventData.Initialize(pointer, handedness, inputAction);
890-
891-
ExecutePointerUp(HandlePointerUp(pointer));
933+
RaisePointerUp(pointer, inputAction, handedness);
892934
}
893935

894936
/// <inheritdoc />
@@ -917,7 +959,7 @@ private static void ExecutePointerUp(GraphicInputEventData graphicInputEventData
917959
private GraphicInputEventData HandlePointerUp(IMixedRealityPointer pointer)
918960
{
919961
// Pass handler through HandleEvent to perform modal/fallback logic
920-
HandleEvent(pointerEventData, OnPointerUpEventHandler);
962+
HandlePointerEvent(pointerEventData, OnPointerUpEventHandler);
921963

922964
GraphicInputEventData graphicEventData;
923965
FocusProvider.TryGetSpecificPointerGraphicEventData(pointer, out graphicEventData);

0 commit comments

Comments
 (0)