368 lines
13 KiB
C#
368 lines
13 KiB
C#
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Copyright (C) 2007-2020 , Inc. All Rights Reserved.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
|
|
using UnityEngine;
|
|
using UnityEngine.EventSystems;
|
|
|
|
using GCSeries.Core.Input;
|
|
|
|
namespace GCSeries.Core.EventSystems
|
|
{
|
|
[DefaultExecutionOrder(ScriptPriority)]
|
|
public class ZInputModule : StandaloneInputModule
|
|
{
|
|
public const int ScriptPriority = ZProvider.ScriptPriority + 40;
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// BaseInputModule Overrides
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
public override bool IsModuleSupported()
|
|
{
|
|
return true;
|
|
}
|
|
|
|
public override void Process()
|
|
{
|
|
// Process keyboard events.
|
|
bool sentEvent = this.SendUpdateEventToSelectedObject();
|
|
|
|
if (this.eventSystem.sendNavigationEvents)
|
|
{
|
|
if (!sentEvent)
|
|
{
|
|
sentEvent |= this.SendMoveEventToSelectedObject();
|
|
}
|
|
|
|
if (!sentEvent)
|
|
{
|
|
this.SendSubmitEventToSelectedObject();
|
|
}
|
|
}
|
|
|
|
// Fall back to the default logic for processing mouse events if
|
|
// no ZMouse pointer is active.
|
|
if (!this.IsMousePointerActive())
|
|
{
|
|
this.ProcessMouseEvent();
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// MonoBehaviour Callbacks
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
private void Update()
|
|
{
|
|
// Process events for all currently active pointers.
|
|
//
|
|
// NOTE: This is being called in Update() instead of Process()
|
|
// since we need to ensure that ZCore, ZCamera(s), and
|
|
// ZPointer(s) are up-to-date (through an explicitly defined
|
|
// script execution order).
|
|
this.ProcessPointers();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// Protected Methods
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
protected void ProcessPointers()
|
|
{
|
|
IList<ZPointer> pointers = ZPointer.GetInstances();
|
|
|
|
for (int i = 0; i < pointers.Count; ++i)
|
|
{
|
|
this.ProcessPointerEvent(pointers[i]);
|
|
}
|
|
}
|
|
|
|
protected void ProcessPointerEvent(ZPointer pointer)
|
|
{
|
|
for (int i = 0; i < pointer.ButtonCount; ++i)
|
|
{
|
|
ZPointerEventData eventData = this.GetEventData(pointer, i);
|
|
|
|
// Process button press/release events.
|
|
if (pointer.GetButtonDown(i))
|
|
{
|
|
this.ProcessButtonPress(eventData);
|
|
}
|
|
|
|
if (pointer.GetButtonUp(i))
|
|
{
|
|
this.ProcessButtonRelease(eventData);
|
|
}
|
|
|
|
// Process move/scroll events only for the primary button.
|
|
if (eventData.button == PointerEventData.InputButton.Left)
|
|
{
|
|
this.ProcessMove(eventData);
|
|
this.ProcessScroll(eventData);
|
|
}
|
|
|
|
// Process drag events.
|
|
this.ProcessDrag(eventData);
|
|
}
|
|
}
|
|
|
|
protected ZPointerEventData GetEventData(ZPointer pointer, int buttonId)
|
|
{
|
|
int id = pointer.Id + buttonId;
|
|
|
|
RaycastResult hitInfo = pointer.HitInfo;
|
|
|
|
// Attempt to retrieve the pointer event data. If it doesn't exist,
|
|
// create it.
|
|
ZPointerEventData eventData = null;
|
|
|
|
if (!this._eventDataCache.TryGetValue(id, out eventData))
|
|
{
|
|
eventData = new ZPointerEventData(this.eventSystem);
|
|
eventData.position = hitInfo.screenPosition;
|
|
|
|
this._eventDataCache.Add(id, eventData);
|
|
}
|
|
|
|
// Reset the pointer event data before populating it with latest
|
|
// information from the pointer.
|
|
eventData.Reset();
|
|
|
|
eventData.Pointer = pointer;
|
|
eventData.ButtonId = buttonId;
|
|
eventData.IsUIObject =
|
|
(hitInfo.gameObject?.GetComponent<RectTransform>() != null);
|
|
eventData.Delta3D =
|
|
hitInfo.worldPosition -
|
|
eventData.pointerCurrentRaycast.worldPosition;
|
|
|
|
eventData.button = pointer.GetButtonMapping(buttonId);
|
|
eventData.delta = hitInfo.screenPosition - eventData.position;
|
|
eventData.position = hitInfo.screenPosition;
|
|
eventData.scrollDelta = pointer.ScrollDelta;
|
|
eventData.pointerCurrentRaycast = hitInfo;
|
|
|
|
return eventData;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// Private Methods
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
private void ProcessButtonPress(ZPointerEventData eventData)
|
|
{
|
|
GameObject hitObject = eventData.pointerCurrentRaycast.gameObject;
|
|
|
|
eventData.eligibleForClick = true;
|
|
eventData.delta = Vector2.zero;
|
|
eventData.dragging = false;
|
|
eventData.useDragThreshold = true;
|
|
eventData.pressPosition = eventData.position;
|
|
eventData.pointerPressRaycast = eventData.pointerCurrentRaycast;
|
|
|
|
this.DeselectIfSelectionChanged(hitObject, eventData);
|
|
|
|
// Attempt to execute pointer down event.
|
|
GameObject pressHandler = ExecuteEvents.ExecuteHierarchy(
|
|
hitObject, eventData, ExecuteEvents.pointerDownHandler);
|
|
|
|
// If a pointer down handler could not be found, attempt to
|
|
// grab the hit object's pointer click handler as a fallback.
|
|
if (pressHandler == null)
|
|
{
|
|
pressHandler =
|
|
ExecuteEvents.GetEventHandler<IPointerClickHandler>(
|
|
hitObject);
|
|
}
|
|
|
|
// Determine the click count.
|
|
float time = Time.unscaledTime;
|
|
|
|
if (pressHandler == eventData.lastPress)
|
|
{
|
|
float timeSincePress = time - eventData.clickTime;
|
|
|
|
eventData.clickCount =
|
|
(timeSincePress < eventData.Pointer.ClickTimeThreshold) ?
|
|
eventData.clickCount + 1 : 1;
|
|
}
|
|
else
|
|
{
|
|
eventData.clickCount = 1;
|
|
}
|
|
|
|
// Update the event data's press/click information.
|
|
eventData.clickTime = time;
|
|
eventData.rawPointerPress = hitObject;
|
|
eventData.pointerPress = pressHandler;
|
|
eventData.pointerDrag =
|
|
ExecuteEvents.GetEventHandler<IDragHandler>(hitObject);
|
|
|
|
if (eventData.pointerDrag != null)
|
|
{
|
|
ExecuteEvents.Execute(
|
|
eventData.pointerDrag,
|
|
eventData,
|
|
ExecuteEvents.initializePotentialDrag);
|
|
}
|
|
}
|
|
|
|
private void ProcessButtonRelease(ZPointerEventData eventData)
|
|
{
|
|
GameObject hitObject = eventData.pointerCurrentRaycast.gameObject;
|
|
float timeSincePress = Time.unscaledTime - eventData.clickTime;
|
|
|
|
// Execute pointer up event.
|
|
ExecuteEvents.Execute(
|
|
eventData.pointerPress,
|
|
eventData,
|
|
ExecuteEvents.pointerUpHandler);
|
|
|
|
GameObject clickHandler =
|
|
ExecuteEvents.GetEventHandler<IPointerClickHandler>(hitObject);
|
|
|
|
// Execute pointer click and drop events.
|
|
if (eventData.eligibleForClick &&
|
|
(eventData.pointerPress == clickHandler ||
|
|
timeSincePress < eventData.Pointer.ClickTimeThreshold))
|
|
{
|
|
ExecuteEvents.Execute(
|
|
eventData.pointerPress,
|
|
eventData,
|
|
ExecuteEvents.pointerClickHandler);
|
|
}
|
|
else if (eventData.pointerDrag != null)
|
|
{
|
|
ExecuteEvents.ExecuteHierarchy(
|
|
hitObject, eventData, ExecuteEvents.dropHandler);
|
|
}
|
|
|
|
// Reset the event data's press/click information.
|
|
eventData.eligibleForClick = false;
|
|
eventData.pointerPress = null;
|
|
eventData.rawPointerPress = null;
|
|
|
|
// Execute end drag event.
|
|
if (eventData.pointerDrag != null && eventData.dragging)
|
|
{
|
|
ExecuteEvents.Execute(
|
|
eventData.pointerDrag,
|
|
eventData,
|
|
ExecuteEvents.endDragHandler);
|
|
}
|
|
|
|
// Reset the event data's drag information.
|
|
eventData.dragging = false;
|
|
eventData.pointerDrag = null;
|
|
|
|
// Redo pointer enter/exit to refresh state.
|
|
if (hitObject != eventData.pointerEnter)
|
|
{
|
|
this.HandlePointerExitAndEnter(eventData, null);
|
|
this.HandlePointerExitAndEnter(eventData, hitObject);
|
|
}
|
|
}
|
|
|
|
// NOTE: The base ProcessDrag() implementation was originally
|
|
// being used until there was a need to determine if the input
|
|
// device's 3D position is changing as well as having the ability
|
|
// to associate input scrolling with movement (e.g. scrolling
|
|
// moves mouse input in the Z direction). So, reimplementing this
|
|
// here to account for 3D movement and scrolling.
|
|
private void ProcessDrag(ZPointerEventData eventData)
|
|
{
|
|
bool isPointerActive =
|
|
eventData.IsPointerMoving3D() || eventData.IsScrolling();
|
|
|
|
bool shouldStartDrag =
|
|
!eventData.IsUIObject ||
|
|
!eventData.useDragThreshold ||
|
|
this.ShouldStartDrag(
|
|
eventData.pressPosition,
|
|
eventData.position,
|
|
eventSystem.pixelDragThreshold);
|
|
|
|
// Execute drag begin event.
|
|
if (shouldStartDrag &&
|
|
eventData.pointerDrag != null &&
|
|
!eventData.dragging)
|
|
{
|
|
ExecuteEvents.Execute(
|
|
eventData.pointerDrag,
|
|
eventData,
|
|
ExecuteEvents.beginDragHandler);
|
|
|
|
eventData.dragging = true;
|
|
}
|
|
|
|
// Execute drag event.
|
|
if (eventData.dragging &&
|
|
isPointerActive &&
|
|
eventData.pointerDrag != null)
|
|
{
|
|
// Before performing a drag, cancel any pointer down state
|
|
// and clear the current selection.
|
|
if (eventData.pointerPress != eventData.pointerDrag)
|
|
{
|
|
ExecuteEvents.Execute(
|
|
eventData.pointerPress,
|
|
eventData,
|
|
ExecuteEvents.pointerUpHandler);
|
|
|
|
eventData.eligibleForClick = false;
|
|
eventData.pointerPress = null;
|
|
eventData.rawPointerPress = null;
|
|
}
|
|
|
|
ExecuteEvents.Execute(
|
|
eventData.pointerDrag,
|
|
eventData,
|
|
ExecuteEvents.dragHandler);
|
|
}
|
|
}
|
|
|
|
private void ProcessScroll(ZPointerEventData eventData)
|
|
{
|
|
if (!Mathf.Approximately(eventData.scrollDelta.sqrMagnitude, 0))
|
|
{
|
|
GameObject hitObject =
|
|
eventData.pointerCurrentRaycast.gameObject;
|
|
|
|
GameObject scrollHandler =
|
|
ExecuteEvents.GetEventHandler<IScrollHandler>(hitObject);
|
|
|
|
ExecuteEvents.ExecuteHierarchy(
|
|
scrollHandler, eventData, ExecuteEvents.scrollHandler);
|
|
}
|
|
}
|
|
|
|
private bool IsMousePointerActive()
|
|
{
|
|
IList<ZPointer> pointers = ZPointer.GetInstances();
|
|
|
|
return pointers.Any(p => p is ZMouse);
|
|
}
|
|
|
|
private bool ShouldStartDrag(
|
|
Vector2 pressPosition, Vector2 currentPosition, float threshold)
|
|
{
|
|
Vector2 deltaPosition = (pressPosition - currentPosition);
|
|
|
|
return deltaPosition.sqrMagnitude >= (threshold * threshold);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// Private Members
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
private Dictionary<int, ZPointerEventData> _eventDataCache =
|
|
new Dictionary<int, ZPointerEventData>();
|
|
}
|
|
}
|