306 lines
10 KiB
C#
306 lines
10 KiB
C#
|
#if UNITY_INPUT_SYSTEM_ENABLE_UI
|
||
|
using UnityEngine.EventSystems;
|
||
|
|
||
|
namespace UnityEngine.InputSystem.UI
|
||
|
{
|
||
|
// A pointer is identified by a single unique integer ID. It has an associated position and the ability to press
|
||
|
// on up to three buttons. It can also scroll.
|
||
|
//
|
||
|
// There's a single ExtendedPointerEventData instance allocated for the pointer which is used to retain the pointer's
|
||
|
// event state. As part of that state is specific to button presses, each button retains a partial copy of press-specific
|
||
|
// event information.
|
||
|
//
|
||
|
// A pointer can operate in 2D (mouse, pen, touch) or 3D (tracked). For 3D, screen-space 2D positions are derived
|
||
|
// via raycasts based on world-space position and orientation.
|
||
|
internal struct PointerModel
|
||
|
{
|
||
|
public bool changedThisFrame;
|
||
|
public UIPointerType pointerType => eventData.pointerType;
|
||
|
|
||
|
public Vector2 screenPosition
|
||
|
{
|
||
|
get => m_ScreenPosition;
|
||
|
set
|
||
|
{
|
||
|
if (m_ScreenPosition != value)
|
||
|
{
|
||
|
m_ScreenPosition = value;
|
||
|
changedThisFrame = true;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public Vector3 worldPosition
|
||
|
{
|
||
|
get => m_WorldPosition;
|
||
|
set
|
||
|
{
|
||
|
if (m_WorldPosition != value)
|
||
|
{
|
||
|
m_WorldPosition = value;
|
||
|
changedThisFrame = true;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public Quaternion worldOrientation
|
||
|
{
|
||
|
get => m_WorldOrientation;
|
||
|
set
|
||
|
{
|
||
|
if (m_WorldOrientation != value)
|
||
|
{
|
||
|
m_WorldOrientation = value;
|
||
|
changedThisFrame = true;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public Vector2 scrollDelta
|
||
|
{
|
||
|
get => m_ScrollDelta;
|
||
|
set
|
||
|
{
|
||
|
if (m_ScrollDelta != value)
|
||
|
{
|
||
|
changedThisFrame = true;
|
||
|
m_ScrollDelta = value;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public float pressure
|
||
|
{
|
||
|
get => m_Pressure;
|
||
|
set
|
||
|
{
|
||
|
if (m_Pressure != value)
|
||
|
{
|
||
|
changedThisFrame = true;
|
||
|
m_Pressure = value;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public float azimuthAngle
|
||
|
{
|
||
|
get => m_AzimuthAngle;
|
||
|
set
|
||
|
{
|
||
|
if (m_AzimuthAngle != value)
|
||
|
{
|
||
|
changedThisFrame = true;
|
||
|
m_AzimuthAngle = value;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public float altitudeAngle
|
||
|
{
|
||
|
get => m_AltitudeAngle;
|
||
|
set
|
||
|
{
|
||
|
if (m_AltitudeAngle != value)
|
||
|
{
|
||
|
changedThisFrame = true;
|
||
|
m_AltitudeAngle = value;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public float twist
|
||
|
{
|
||
|
get => m_Twist;
|
||
|
set
|
||
|
{
|
||
|
if (m_Twist != value)
|
||
|
{
|
||
|
changedThisFrame = true;
|
||
|
m_Twist = value;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public Vector2 radius
|
||
|
{
|
||
|
get => m_Radius;
|
||
|
set
|
||
|
{
|
||
|
if (m_Radius != value)
|
||
|
{
|
||
|
changedThisFrame = true;
|
||
|
m_Radius = value;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public ButtonState leftButton;
|
||
|
public ButtonState rightButton;
|
||
|
public ButtonState middleButton;
|
||
|
public ExtendedPointerEventData eventData;
|
||
|
|
||
|
public PointerModel(ExtendedPointerEventData eventData)
|
||
|
{
|
||
|
this.eventData = eventData;
|
||
|
|
||
|
changedThisFrame = false;
|
||
|
|
||
|
leftButton = default; leftButton.OnEndFrame();
|
||
|
rightButton = default; rightButton.OnEndFrame();
|
||
|
middleButton = default; middleButton.OnEndFrame();
|
||
|
|
||
|
m_ScreenPosition = default;
|
||
|
m_ScrollDelta = default;
|
||
|
m_WorldOrientation = default;
|
||
|
m_WorldPosition = default;
|
||
|
|
||
|
m_Pressure = default;
|
||
|
m_AzimuthAngle = default;
|
||
|
m_AltitudeAngle = default;
|
||
|
m_Twist = default;
|
||
|
m_Radius = default;
|
||
|
}
|
||
|
|
||
|
public void OnFrameFinished()
|
||
|
{
|
||
|
changedThisFrame = false;
|
||
|
scrollDelta = default;
|
||
|
leftButton.OnEndFrame();
|
||
|
rightButton.OnEndFrame();
|
||
|
middleButton.OnEndFrame();
|
||
|
}
|
||
|
|
||
|
private Vector2 m_ScreenPosition;
|
||
|
private Vector2 m_ScrollDelta;
|
||
|
private Vector3 m_WorldPosition;
|
||
|
private Quaternion m_WorldOrientation;
|
||
|
|
||
|
private float m_Pressure;
|
||
|
private float m_AzimuthAngle;
|
||
|
private float m_AltitudeAngle;
|
||
|
private float m_Twist;
|
||
|
private Vector2 m_Radius;
|
||
|
|
||
|
public void CopyTouchOrPenStateFrom(PointerEventData eventData)
|
||
|
{
|
||
|
#if UNITY_2021_1_OR_NEWER
|
||
|
pressure = eventData.pressure;
|
||
|
azimuthAngle = eventData.azimuthAngle;
|
||
|
altitudeAngle = eventData.altitudeAngle;
|
||
|
twist = eventData.twist;
|
||
|
radius = eventData.radius;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
// State related to pressing and releasing individual bodies. Retains those parts of
|
||
|
// PointerInputEvent that are specific to presses and releases.
|
||
|
public struct ButtonState
|
||
|
{
|
||
|
private bool m_IsPressed;
|
||
|
private PointerEventData.FramePressState m_FramePressState;
|
||
|
private float m_PressTime;
|
||
|
|
||
|
public bool isPressed
|
||
|
{
|
||
|
get => m_IsPressed;
|
||
|
set
|
||
|
{
|
||
|
if (m_IsPressed != value)
|
||
|
{
|
||
|
m_IsPressed = value;
|
||
|
|
||
|
if (m_FramePressState == PointerEventData.FramePressState.NotChanged && value)
|
||
|
m_FramePressState = PointerEventData.FramePressState.Pressed;
|
||
|
else if (m_FramePressState == PointerEventData.FramePressState.NotChanged && !value)
|
||
|
m_FramePressState = PointerEventData.FramePressState.Released;
|
||
|
else if (m_FramePressState == PointerEventData.FramePressState.Pressed && !value)
|
||
|
m_FramePressState = PointerEventData.FramePressState.PressedAndReleased;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// When we "release" a button other than through user interaction (e.g. through focus switching),
|
||
|
/// we don't want this to count as an actual release that ends up clicking. This flag will cause
|
||
|
/// generated events to have <c>eligibleForClick</c> to be false.
|
||
|
/// </summary>
|
||
|
public bool ignoreNextClick
|
||
|
{
|
||
|
get => m_IgnoreNextClick;
|
||
|
set => m_IgnoreNextClick = value;
|
||
|
}
|
||
|
|
||
|
public float pressTime
|
||
|
{
|
||
|
get => m_PressTime;
|
||
|
set => m_PressTime = value;
|
||
|
}
|
||
|
|
||
|
public bool clickedOnSameGameObject
|
||
|
{
|
||
|
get => m_ClickedOnSameGameObject;
|
||
|
set => m_ClickedOnSameGameObject = value;
|
||
|
}
|
||
|
|
||
|
public bool wasPressedThisFrame => m_FramePressState == PointerEventData.FramePressState.Pressed ||
|
||
|
m_FramePressState == PointerEventData.FramePressState.PressedAndReleased;
|
||
|
public bool wasReleasedThisFrame => m_FramePressState == PointerEventData.FramePressState.Released ||
|
||
|
m_FramePressState == PointerEventData.FramePressState.PressedAndReleased;
|
||
|
|
||
|
private RaycastResult m_PressRaycast;
|
||
|
private GameObject m_PressObject;
|
||
|
private GameObject m_RawPressObject;
|
||
|
private GameObject m_LastPressObject;
|
||
|
private GameObject m_DragObject;
|
||
|
private Vector2 m_PressPosition;
|
||
|
private float m_ClickTime; // On Time.unscaledTime timeline, NOT input event time.
|
||
|
private int m_ClickCount;
|
||
|
private bool m_Dragging;
|
||
|
private bool m_ClickedOnSameGameObject;
|
||
|
private bool m_IgnoreNextClick;
|
||
|
|
||
|
public void CopyPressStateTo(PointerEventData eventData)
|
||
|
{
|
||
|
eventData.pointerPressRaycast = m_PressRaycast;
|
||
|
eventData.pressPosition = m_PressPosition;
|
||
|
eventData.clickCount = m_ClickCount;
|
||
|
eventData.clickTime = m_ClickTime;
|
||
|
// We can't set lastPress directly. Old input module uses three different event instances, one for each
|
||
|
// button. We share one instance and just switch press states. Set pointerPress twice to get the lastPress
|
||
|
// we need.
|
||
|
//
|
||
|
// NOTE: This does *NOT* quite work as stated in the docs. pointerPress is nulled out on button release which
|
||
|
// will set lastPress as a side-effect. This means that lastPress will only be non-null while no press is
|
||
|
// going on and will *NOT* refer to the last pressed object when a new object has been pressed on.
|
||
|
eventData.pointerPress = m_LastPressObject;
|
||
|
eventData.pointerPress = m_PressObject;
|
||
|
eventData.rawPointerPress = m_RawPressObject;
|
||
|
eventData.pointerDrag = m_DragObject;
|
||
|
eventData.dragging = m_Dragging;
|
||
|
|
||
|
if (ignoreNextClick)
|
||
|
eventData.eligibleForClick = false;
|
||
|
}
|
||
|
|
||
|
public void CopyPressStateFrom(PointerEventData eventData)
|
||
|
{
|
||
|
m_PressRaycast = eventData.pointerPressRaycast;
|
||
|
m_PressObject = eventData.pointerPress;
|
||
|
m_RawPressObject = eventData.rawPointerPress;
|
||
|
m_LastPressObject = eventData.lastPress;
|
||
|
m_PressPosition = eventData.pressPosition;
|
||
|
m_ClickTime = eventData.clickTime;
|
||
|
m_ClickCount = eventData.clickCount;
|
||
|
m_DragObject = eventData.pointerDrag;
|
||
|
m_Dragging = eventData.dragging;
|
||
|
}
|
||
|
|
||
|
public void OnEndFrame()
|
||
|
{
|
||
|
m_FramePressState = PointerEventData.FramePressState.NotChanged;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
#endif
|