Skip to content

Commit 0db48ef

Browse files
Julia Schwarzkeveleigh
authored andcommitted
Input System Fix Pointers Dispatching PointerEvents to all other Pointers
1 parent 0993c94 commit 0db48ef

File tree

1 file changed

+101
-53
lines changed

1 file changed

+101
-53
lines changed

Assets/MixedRealityToolkit.Services/InputSystem/MixedRealityInputSystem.cs

Lines changed: 101 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -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!\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>
@@ -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

Comments
 (0)