shenjianxing 6b341ae2b4 适配VR
2025-04-01 16:16:45 +08:00

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>();
}
}