Maze / Library /PackageCache /com.unity.ugui@1.0.0 /Runtime /EventSystem /InputModules /PointerInputModule.cs
| using System.Collections.Generic; | |
| using System.Text; | |
| using UnityEngine.UI; | |
| namespace UnityEngine.EventSystems | |
| { | |
| /// <summary> | |
| /// A BaseInputModule for pointer input. | |
| /// </summary> | |
| public abstract class PointerInputModule : BaseInputModule | |
| { | |
| /// <summary> | |
| /// Id of the cached left mouse pointer event. | |
| /// </summary> | |
| public const int kMouseLeftId = -1; | |
| /// <summary> | |
| /// Id of the cached right mouse pointer event. | |
| /// </summary> | |
| public const int kMouseRightId = -2; | |
| /// <summary> | |
| /// Id of the cached middle mouse pointer event. | |
| /// </summary> | |
| public const int kMouseMiddleId = -3; | |
| /// <summary> | |
| /// Touch id for when simulating touches on a non touch device. | |
| /// </summary> | |
| public const int kFakeTouchesId = -4; | |
| protected Dictionary<int, PointerEventData> m_PointerData = new Dictionary<int, PointerEventData>(); | |
| /// <summary> | |
| /// Search the cache for currently active pointers, return true if found. | |
| /// </summary> | |
| /// <param name="id">Touch ID</param> | |
| /// <param name="data">Found data</param> | |
| /// <param name="create">If not found should it be created</param> | |
| /// <returns>True if pointer is found.</returns> | |
| protected bool GetPointerData(int id, out PointerEventData data, bool create) | |
| { | |
| if (!m_PointerData.TryGetValue(id, out data) && create) | |
| { | |
| data = new PointerEventData(eventSystem) | |
| { | |
| pointerId = id, | |
| }; | |
| m_PointerData.Add(id, data); | |
| return true; | |
| } | |
| return false; | |
| } | |
| /// <summary> | |
| /// Remove the PointerEventData from the cache. | |
| /// </summary> | |
| protected void RemovePointerData(PointerEventData data) | |
| { | |
| m_PointerData.Remove(data.pointerId); | |
| } | |
| /// <summary> | |
| /// Given a touch populate the PointerEventData and return if we are pressed or released. | |
| /// </summary> | |
| /// <param name="input">Touch being processed</param> | |
| /// <param name="pressed">Are we pressed this frame</param> | |
| /// <param name="released">Are we released this frame</param> | |
| /// <returns></returns> | |
| protected PointerEventData GetTouchPointerEventData(Touch input, out bool pressed, out bool released) | |
| { | |
| PointerEventData pointerData; | |
| var created = GetPointerData(input.fingerId, out pointerData, true); | |
| pointerData.Reset(); | |
| pressed = created || (input.phase == TouchPhase.Began); | |
| released = (input.phase == TouchPhase.Canceled) || (input.phase == TouchPhase.Ended); | |
| if (created) | |
| pointerData.position = input.position; | |
| if (pressed) | |
| pointerData.delta = Vector2.zero; | |
| else | |
| pointerData.delta = input.position - pointerData.position; | |
| pointerData.position = input.position; | |
| pointerData.button = PointerEventData.InputButton.Left; | |
| if (input.phase == TouchPhase.Canceled) | |
| { | |
| pointerData.pointerCurrentRaycast = new RaycastResult(); | |
| } | |
| else | |
| { | |
| eventSystem.RaycastAll(pointerData, m_RaycastResultCache); | |
| var raycast = FindFirstRaycast(m_RaycastResultCache); | |
| pointerData.pointerCurrentRaycast = raycast; | |
| m_RaycastResultCache.Clear(); | |
| } | |
| pointerData.pressure = input.pressure; | |
| pointerData.altitudeAngle = input.altitudeAngle; | |
| pointerData.azimuthAngle = input.azimuthAngle; | |
| pointerData.radius = Vector2.one * input.radius; | |
| pointerData.radiusVariance = Vector2.one * input.radiusVariance; | |
| return pointerData; | |
| } | |
| /// <summary> | |
| /// Copy one PointerEventData to another. | |
| /// </summary> | |
| protected void CopyFromTo(PointerEventData @from, PointerEventData @to) | |
| { | |
| @to.position = @from.position; | |
| @to.delta = @from.delta; | |
| @to.scrollDelta = @from.scrollDelta; | |
| @to.pointerCurrentRaycast = @from.pointerCurrentRaycast; | |
| @to.pointerEnter = @from.pointerEnter; | |
| @to.pressure = @from.pressure; | |
| @to.tangentialPressure = @from.tangentialPressure; | |
| @to.altitudeAngle = @from.altitudeAngle; | |
| @to.azimuthAngle = @from.azimuthAngle; | |
| @to.twist = @from.twist; | |
| @to.radius = @from.radius; | |
| @to.radiusVariance = @from.radiusVariance; | |
| } | |
| /// <summary> | |
| /// Given a mouse button return the current state for the frame. | |
| /// </summary> | |
| /// <param name="buttonId">Mouse button ID</param> | |
| protected PointerEventData.FramePressState StateForMouseButton(int buttonId) | |
| { | |
| var pressed = input.GetMouseButtonDown(buttonId); | |
| var released = input.GetMouseButtonUp(buttonId); | |
| if (pressed && released) | |
| return PointerEventData.FramePressState.PressedAndReleased; | |
| if (pressed) | |
| return PointerEventData.FramePressState.Pressed; | |
| if (released) | |
| return PointerEventData.FramePressState.Released; | |
| return PointerEventData.FramePressState.NotChanged; | |
| } | |
| protected class ButtonState | |
| { | |
| private PointerEventData.InputButton m_Button = PointerEventData.InputButton.Left; | |
| public MouseButtonEventData eventData | |
| { | |
| get { return m_EventData; } | |
| set { m_EventData = value; } | |
| } | |
| public PointerEventData.InputButton button | |
| { | |
| get { return m_Button; } | |
| set { m_Button = value; } | |
| } | |
| private MouseButtonEventData m_EventData; | |
| } | |
| protected class MouseState | |
| { | |
| private List<ButtonState> m_TrackedButtons = new List<ButtonState>(); | |
| public bool AnyPressesThisFrame() | |
| { | |
| var trackedButtonsCount = m_TrackedButtons.Count; | |
| for (int i = 0; i < trackedButtonsCount; i++) | |
| { | |
| if (m_TrackedButtons[i].eventData.PressedThisFrame()) | |
| return true; | |
| } | |
| return false; | |
| } | |
| public bool AnyReleasesThisFrame() | |
| { | |
| var trackedButtonsCount = m_TrackedButtons.Count; | |
| for (int i = 0; i < trackedButtonsCount; i++) | |
| { | |
| if (m_TrackedButtons[i].eventData.ReleasedThisFrame()) | |
| return true; | |
| } | |
| return false; | |
| } | |
| public ButtonState GetButtonState(PointerEventData.InputButton button) | |
| { | |
| ButtonState tracked = null; | |
| var trackedButtonsCount = m_TrackedButtons.Count; | |
| for (int i = 0; i < trackedButtonsCount; i++) | |
| { | |
| if (m_TrackedButtons[i].button == button) | |
| { | |
| tracked = m_TrackedButtons[i]; | |
| break; | |
| } | |
| } | |
| if (tracked == null) | |
| { | |
| tracked = new ButtonState { button = button, eventData = new MouseButtonEventData() }; | |
| m_TrackedButtons.Add(tracked); | |
| } | |
| return tracked; | |
| } | |
| public void SetButtonState(PointerEventData.InputButton button, PointerEventData.FramePressState stateForMouseButton, PointerEventData data) | |
| { | |
| var toModify = GetButtonState(button); | |
| toModify.eventData.buttonState = stateForMouseButton; | |
| toModify.eventData.buttonData = data; | |
| } | |
| } | |
| /// <summary> | |
| /// Information about a mouse button event. | |
| /// </summary> | |
| public class MouseButtonEventData | |
| { | |
| /// <summary> | |
| /// The state of the button this frame. | |
| /// </summary> | |
| public PointerEventData.FramePressState buttonState; | |
| /// <summary> | |
| /// Pointer data associated with the mouse event. | |
| /// </summary> | |
| public PointerEventData buttonData; | |
| /// <summary> | |
| /// Was the button pressed this frame? | |
| /// </summary> | |
| public bool PressedThisFrame() | |
| { | |
| return buttonState == PointerEventData.FramePressState.Pressed || buttonState == PointerEventData.FramePressState.PressedAndReleased; | |
| } | |
| /// <summary> | |
| /// Was the button released this frame? | |
| /// </summary> | |
| public bool ReleasedThisFrame() | |
| { | |
| return buttonState == PointerEventData.FramePressState.Released || buttonState == PointerEventData.FramePressState.PressedAndReleased; | |
| } | |
| } | |
| private readonly MouseState m_MouseState = new MouseState(); | |
| /// <summary> | |
| /// Return the current MouseState. Using the default pointer. | |
| /// </summary> | |
| protected virtual MouseState GetMousePointerEventData() | |
| { | |
| return GetMousePointerEventData(0); | |
| } | |
| /// <summary> | |
| /// Return the current MouseState. | |
| /// </summary> | |
| protected virtual MouseState GetMousePointerEventData(int id) | |
| { | |
| // Populate the left button... | |
| PointerEventData leftData; | |
| var created = GetPointerData(kMouseLeftId, out leftData, true); | |
| leftData.Reset(); | |
| if (created) | |
| leftData.position = input.mousePosition; | |
| Vector2 pos = input.mousePosition; | |
| if (Cursor.lockState == CursorLockMode.Locked) | |
| { | |
| // We don't want to do ANY cursor-based interaction when the mouse is locked | |
| leftData.position = new Vector2(-1.0f, -1.0f); | |
| leftData.delta = Vector2.zero; | |
| } | |
| else | |
| { | |
| leftData.delta = pos - leftData.position; | |
| leftData.position = pos; | |
| } | |
| leftData.scrollDelta = input.mouseScrollDelta; | |
| leftData.button = PointerEventData.InputButton.Left; | |
| eventSystem.RaycastAll(leftData, m_RaycastResultCache); | |
| var raycast = FindFirstRaycast(m_RaycastResultCache); | |
| leftData.pointerCurrentRaycast = raycast; | |
| m_RaycastResultCache.Clear(); | |
| // copy the apropriate data into right and middle slots | |
| PointerEventData rightData; | |
| GetPointerData(kMouseRightId, out rightData, true); | |
| rightData.Reset(); | |
| CopyFromTo(leftData, rightData); | |
| rightData.button = PointerEventData.InputButton.Right; | |
| PointerEventData middleData; | |
| GetPointerData(kMouseMiddleId, out middleData, true); | |
| middleData.Reset(); | |
| CopyFromTo(leftData, middleData); | |
| middleData.button = PointerEventData.InputButton.Middle; | |
| m_MouseState.SetButtonState(PointerEventData.InputButton.Left, StateForMouseButton(0), leftData); | |
| m_MouseState.SetButtonState(PointerEventData.InputButton.Right, StateForMouseButton(1), rightData); | |
| m_MouseState.SetButtonState(PointerEventData.InputButton.Middle, StateForMouseButton(2), middleData); | |
| return m_MouseState; | |
| } | |
| /// <summary> | |
| /// Return the last PointerEventData for the given touch / mouse id. | |
| /// </summary> | |
| protected PointerEventData GetLastPointerEventData(int id) | |
| { | |
| PointerEventData data; | |
| GetPointerData(id, out data, false); | |
| return data; | |
| } | |
| private static bool ShouldStartDrag(Vector2 pressPos, Vector2 currentPos, float threshold, bool useDragThreshold) | |
| { | |
| if (!useDragThreshold) | |
| return true; | |
| return (pressPos - currentPos).sqrMagnitude >= threshold * threshold; | |
| } | |
| /// <summary> | |
| /// Process movement for the current frame with the given pointer event. | |
| /// </summary> | |
| protected virtual void ProcessMove(PointerEventData pointerEvent) | |
| { | |
| var targetGO = (Cursor.lockState == CursorLockMode.Locked ? null : pointerEvent.pointerCurrentRaycast.gameObject); | |
| HandlePointerExitAndEnter(pointerEvent, targetGO); | |
| } | |
| /// <summary> | |
| /// Process the drag for the current frame with the given pointer event. | |
| /// </summary> | |
| protected virtual void ProcessDrag(PointerEventData pointerEvent) | |
| { | |
| if (!pointerEvent.IsPointerMoving() || | |
| Cursor.lockState == CursorLockMode.Locked || | |
| pointerEvent.pointerDrag == null) | |
| return; | |
| if (!pointerEvent.dragging | |
| && ShouldStartDrag(pointerEvent.pressPosition, pointerEvent.position, eventSystem.pixelDragThreshold, pointerEvent.useDragThreshold)) | |
| { | |
| ExecuteEvents.Execute(pointerEvent.pointerDrag, pointerEvent, ExecuteEvents.beginDragHandler); | |
| pointerEvent.dragging = true; | |
| } | |
| // Drag notification | |
| if (pointerEvent.dragging) | |
| { | |
| // Before doing drag we should cancel any pointer down state | |
| // And clear selection! | |
| if (pointerEvent.pointerPress != pointerEvent.pointerDrag) | |
| { | |
| ExecuteEvents.Execute(pointerEvent.pointerPress, pointerEvent, ExecuteEvents.pointerUpHandler); | |
| pointerEvent.eligibleForClick = false; | |
| pointerEvent.pointerPress = null; | |
| pointerEvent.rawPointerPress = null; | |
| } | |
| ExecuteEvents.Execute(pointerEvent.pointerDrag, pointerEvent, ExecuteEvents.dragHandler); | |
| } | |
| } | |
| public override bool IsPointerOverGameObject(int pointerId) | |
| { | |
| var lastPointer = GetLastPointerEventData(pointerId); | |
| if (lastPointer != null) | |
| return lastPointer.pointerEnter != null; | |
| return false; | |
| } | |
| /// <summary> | |
| /// Clear all pointers and deselect any selected objects in the EventSystem. | |
| /// </summary> | |
| protected void ClearSelection() | |
| { | |
| var baseEventData = GetBaseEventData(); | |
| foreach (var pointer in m_PointerData.Values) | |
| { | |
| // clear all selection | |
| HandlePointerExitAndEnter(pointer, null); | |
| } | |
| m_PointerData.Clear(); | |
| eventSystem.SetSelectedGameObject(null, baseEventData); | |
| } | |
| public override string ToString() | |
| { | |
| var sb = new StringBuilder("<b>Pointer Input Module of type: </b>" + GetType()); | |
| sb.AppendLine(); | |
| foreach (var pointer in m_PointerData) | |
| { | |
| if (pointer.Value == null) | |
| continue; | |
| sb.AppendLine("<B>Pointer:</b> " + pointer.Key); | |
| sb.AppendLine(pointer.Value.ToString()); | |
| } | |
| return sb.ToString(); | |
| } | |
| /// <summary> | |
| /// Deselect the current selected GameObject if the currently pointed-at GameObject is different. | |
| /// </summary> | |
| /// <param name="currentOverGo">The GameObject the pointer is currently over.</param> | |
| /// <param name="pointerEvent">Current event data.</param> | |
| protected void DeselectIfSelectionChanged(GameObject currentOverGo, BaseEventData pointerEvent) | |
| { | |
| // Selection tracking | |
| var selectHandlerGO = ExecuteEvents.GetEventHandler<ISelectHandler>(currentOverGo); | |
| // if we have clicked something new, deselect the old thing | |
| // leave 'selection handling' up to the press event though. | |
| if (selectHandlerGO != eventSystem.currentSelectedGameObject) | |
| eventSystem.SetSelectedGameObject(null, pointerEvent); | |
| } | |
| } | |
| } | |