#if PACKAGE_DOCS_GENERATION || UNITY_INPUT_SYSTEM_ENABLE_UI
using System.Text;
using UnityEngine.EventSystems;
using UnityEngine.InputSystem.Controls;
using UnityEngine.InputSystem.Utilities;
namespace UnityEngine.InputSystem.UI
{
///
/// An extension to PointerEventData which makes additional data about the input event available.
///
///
/// Instances of this class are sent instead of by
/// for all pointer-type input.
///
/// The property will generally correspond to the
/// of . An exception to this are touches as each may generate several pointers
/// (one for each active finger).
///
public class ExtendedPointerEventData : PointerEventData
{
public ExtendedPointerEventData(EventSystem eventSystem)
: base(eventSystem)
{
}
///
/// The that generated the pointer input.
/// The device associated with this control should be the same as this event's device.
///
///
public InputControl control { get; set; }
///
/// The that generated the pointer input.
///
///
///
///
///
public InputDevice device { get; set; }
///
/// For type pointer input, this is the touch ID as reported by the
/// device.
///
///
/// For pointer input that is not coming from touch, this will be 0 (which is not considered a valid touch ID
/// by the input system).
///
/// Note that for touch input, will be a combination of the
/// device ID of and the touch ID to generate a unique pointer ID even if there
/// are multiple touchscreens.
///
///
public int touchId { get; set; }
///
/// Type of pointer that generated the input.
///
public UIPointerType pointerType { get; set; }
public int uiToolkitPointerId { get; set; }
///
/// For type pointer input, this is the world-space position of
/// the .
///
///
public Vector3 trackedDevicePosition { get; set; }
///
/// For type pointer input, this is the world-space orientation of
/// the .
///
///
public Quaternion trackedDeviceOrientation { get; set; }
public override string ToString()
{
var stringBuilder = new StringBuilder();
stringBuilder.Append(base.ToString());
stringBuilder.AppendLine("button: " + button); // Defined in PointerEventData but PointerEventData.ToString() does not include it.
stringBuilder.AppendLine("clickTime: " + clickTime); // Same here.
stringBuilder.AppendLine("clickCount: " + clickCount); // Same here.
stringBuilder.AppendLine("device: " + device);
stringBuilder.AppendLine("pointerType: " + pointerType);
stringBuilder.AppendLine("touchId: " + touchId);
stringBuilder.AppendLine("pressPosition: " + pressPosition);
stringBuilder.AppendLine("trackedDevicePosition: " + trackedDevicePosition);
stringBuilder.AppendLine("trackedDeviceOrientation: " + trackedDeviceOrientation);
#if UNITY_2021_1_OR_NEWER
stringBuilder.AppendLine("pressure" + pressure);
stringBuilder.AppendLine("radius: " + radius);
stringBuilder.AppendLine("azimuthAngle: " + azimuthAngle);
stringBuilder.AppendLine("altitudeAngle: " + altitudeAngle);
stringBuilder.AppendLine("twist: " + twist);
#endif
#if UNITY_2023_1_OR_NEWER
stringBuilder.AppendLine("displayIndex: " + displayIndex);
#endif
return stringBuilder.ToString();
}
internal static int MakePointerIdForTouch(int deviceId, int touchId)
{
unchecked
{
return (deviceId << 24) + touchId;
}
}
internal static int TouchIdFromPointerId(int pointerId)
{
return pointerId & 0xff;
}
////TODO: add pressure and tilt support (probably add after 1.0; probably should have separate actions)
/*
///
/// If supported by the input device, this is the pressure level of the pointer contact. This is generally
/// only supported by devices as well as by s on phones. If not
/// supported, this will be 1.
///
///
public float pressure { get; set; }
///
/// If the pointer input is coming from a , this is pen's .
///
public Vector2 tilt { get; set; }
*/
internal void ReadDeviceState()
{
if (control.parent is Pen pen)
{
uiToolkitPointerId = GetPenPointerId(pen);
#if UNITY_2021_1_OR_NEWER
pressure = pen.pressure.magnitude;
azimuthAngle = (pen.tilt.value.x + 1) * Mathf.PI / 2;
altitudeAngle = (pen.tilt.value.y + 1) * Mathf.PI / 2;
twist = pen.twist.value * Mathf.PI * 2;
#endif
#if UNITY_2023_1_OR_NEWER
displayIndex = pen.displayIndex.ReadValue();
#endif
}
else if (control.parent is TouchControl touchControl)
{
uiToolkitPointerId = GetTouchPointerId(touchControl);
#if UNITY_2021_1_OR_NEWER
pressure = touchControl.pressure.magnitude;
radius = touchControl.radius.value;
#endif
#if UNITY_2023_1_OR_NEWER
displayIndex = touchControl.displayIndex.ReadValue();
#endif
}
else if (control.parent is Touchscreen touchscreen)
{
uiToolkitPointerId = GetTouchPointerId(touchscreen.primaryTouch);
#if UNITY_2021_1_OR_NEWER
pressure = touchscreen.pressure.magnitude;
radius = touchscreen.radius.value;
#endif
#if UNITY_2023_1_OR_NEWER
displayIndex = touchscreen.displayIndex.ReadValue();
#endif
}
else
{
uiToolkitPointerId = UIElements.PointerId.mousePointerId;
}
}
private static int GetPenPointerId(Pen pen)
{
var n = 0;
foreach (var otherDevice in InputSystem.devices)
if (otherDevice is Pen otherPen)
{
if (pen == otherPen)
{
return UIElements.PointerId.penPointerIdBase +
Mathf.Min(n, UIElements.PointerId.penPointerCount - 1);
}
n++;
}
return UIElements.PointerId.penPointerIdBase;
}
private static int GetTouchPointerId(TouchControl touchControl)
{
var i = ((Touchscreen)touchControl.device).touches.IndexOfReference(touchControl);
return UIElements.PointerId.touchPointerIdBase +
Mathf.Clamp(i, 0, UIElements.PointerId.touchPointerCount - 1);
}
}
///
/// General type of pointer that generated a pointer event.
///
public enum UIPointerType
{
None,
///
/// A or or other general .
///
MouseOrPen,
///
/// A .
///
Touch,
///
/// A .
///
Tracked,
}
///
/// Determine how the UI behaves in the presence of multiple pointer devices.
///
///
/// While running, an application may, for example, have both a and a device
/// and both may end up getting bound to the actions of and thus both may route
/// input into the UI. When this happens, the pointer behavior decides how the UI input module resolves the ambiguity.
///
public enum UIPointerBehavior
{
///
/// Any input that isn't or input is
/// treated as a single unified pointer.
///
/// This is the default behavior based on the expectation that mice and pens will generally drive a single on-screen
/// cursor whereas touch and tracked devices have an inherent ability to generate multiple pointers.
///
/// Note that when input from touch or tracked devices is received, the combined pointer for mice and pens (if it exists)
/// will be removed. If it was over UI objects, IPointerExitHandlers will be invoked.
///
SingleMouseOrPenButMultiTouchAndTrack,
///
/// All input is unified to a single pointer. This means that all input from all pointing devices (,
/// , , and ) is routed into a single pointer
/// instance. There is only one position on screen which can be controlled from any of these devices.
///
SingleUnifiedPointer,
///
/// Any pointing device, whether it's , , ,
/// or input, is treated as its own independent pointer and arbitrary many
/// such pointers can be active at any one time.
///
AllPointersAsIs,
}
}
#endif