A game about forced loneliness, made by TACStudios
1#if PACKAGE_DOCS_GENERATION || UNITY_INPUT_SYSTEM_ENABLE_UI
2using System.Text;
3using UnityEngine.EventSystems;
4using UnityEngine.InputSystem.Controls;
5using UnityEngine.InputSystem.Utilities;
6
7namespace UnityEngine.InputSystem.UI
8{
9 /// <summary>
10 /// An extension to <c>PointerEventData</c> which makes additional data about the input event available.
11 /// </summary>
12 /// <remarks>
13 /// Instances of this class are sent instead of <see cref="PointerEventData"/> by <see cref="InputSystemUIInputModule"/>
14 /// for all pointer-type input.
15 ///
16 /// The <see cref="PointerEventData.pointerId"/> property will generally correspond to the <see cref="InputDevice.deviceId"/>
17 /// of <see cref="device"/>. An exception to this are touches as each <see cref="Touchscreen"/> may generate several pointers
18 /// (one for each active finger).
19 /// </remarks>
20 public class ExtendedPointerEventData : PointerEventData
21 {
22 public ExtendedPointerEventData(EventSystem eventSystem)
23 : base(eventSystem)
24 {
25 }
26
27 /// <summary>
28 /// The <see cref="InputControl"/> that generated the pointer input.
29 /// The device associated with this control should be the same as this event's device.
30 /// </summary>
31 /// <seealso cref="device"/>
32 public InputControl control { get; set; }
33
34 /// <summary>
35 /// The <see cref="InputDevice"/> that generated the pointer input.
36 /// </summary>
37 /// <seealso cref="Pointer"/>
38 /// <seealso cref="Touchscreen"/>
39 /// <seealso cref="Mouse"/>
40 /// <seealso cref="Pen"/>
41 public InputDevice device { get; set; }
42
43 /// <summary>
44 /// For <see cref="UIPointerType.Touch"/> type pointer input, this is the touch ID as reported by the
45 /// <see cref="Touchscreen"/> device.
46 /// </summary>
47 /// <remarks>
48 /// For pointer input that is not coming from touch, this will be 0 (which is not considered a valid touch ID
49 /// by the input system).
50 ///
51 /// Note that for touch input, <see cref="PointerEventData.pointerId"/> will be a combination of the
52 /// device ID of <see cref="device"/> and the touch ID to generate a unique pointer ID even if there
53 /// are multiple touchscreens.
54 /// </remarks>
55 /// <seealso cref="TouchControl.touchId"/>
56 public int touchId { get; set; }
57
58 /// <summary>
59 /// Type of pointer that generated the input.
60 /// </summary>
61 public UIPointerType pointerType { get; set; }
62
63 public int uiToolkitPointerId { get; set; }
64
65 /// <summary>
66 /// For <see cref="UIPointerType.Tracked"/> type pointer input, this is the world-space position of
67 /// the <see cref="TrackedDevice"/>.
68 /// </summary>
69 /// <seealso cref="InputSystemUIInputModule.trackedDevicePosition"/>
70 public Vector3 trackedDevicePosition { get; set; }
71
72 /// <summary>
73 /// For <see cref="UIPointerType.Tracked"/> type pointer input, this is the world-space orientation of
74 /// the <see cref="TrackedDevice"/>.
75 /// </summary>
76 /// <seealso cref="InputSystemUIInputModule.trackedDeviceOrientation"/>
77 public Quaternion trackedDeviceOrientation { get; set; }
78
79 public override string ToString()
80 {
81 var stringBuilder = new StringBuilder();
82 stringBuilder.Append(base.ToString());
83 stringBuilder.AppendLine("button: " + button); // Defined in PointerEventData but PointerEventData.ToString() does not include it.
84 stringBuilder.AppendLine("clickTime: " + clickTime); // Same here.
85 stringBuilder.AppendLine("clickCount: " + clickCount); // Same here.
86 stringBuilder.AppendLine("device: " + device);
87 stringBuilder.AppendLine("pointerType: " + pointerType);
88 stringBuilder.AppendLine("touchId: " + touchId);
89 stringBuilder.AppendLine("pressPosition: " + pressPosition);
90 stringBuilder.AppendLine("trackedDevicePosition: " + trackedDevicePosition);
91 stringBuilder.AppendLine("trackedDeviceOrientation: " + trackedDeviceOrientation);
92 #if UNITY_2021_1_OR_NEWER
93 stringBuilder.AppendLine("pressure" + pressure);
94 stringBuilder.AppendLine("radius: " + radius);
95 stringBuilder.AppendLine("azimuthAngle: " + azimuthAngle);
96 stringBuilder.AppendLine("altitudeAngle: " + altitudeAngle);
97 stringBuilder.AppendLine("twist: " + twist);
98 #endif
99 #if UNITY_2022_3_OR_NEWER
100 stringBuilder.AppendLine("displayIndex: " + displayIndex);
101 #endif
102 return stringBuilder.ToString();
103 }
104
105 internal static int MakePointerIdForTouch(int deviceId, int touchId)
106 {
107 unchecked
108 {
109 return (deviceId << 24) + touchId;
110 }
111 }
112
113 internal static int TouchIdFromPointerId(int pointerId)
114 {
115 return pointerId & 0xff;
116 }
117
118 ////TODO: add pressure and tilt support (probably add after 1.0; probably should have separate actions)
119 /*
120 /// <summary>
121 /// If supported by the input device, this is the pressure level of the pointer contact. This is generally
122 /// only supported by <see cref="Pen"/> devices as well as by <see cref="Touchscreen"/>s on phones. If not
123 /// supported, this will be 1.
124 /// </summary>
125 /// <seealso cref="Pointer.pressure"/>
126 public float pressure { get; set; }
127
128 /// <summary>
129 /// If the pointer input is coming from a <see cref="Pen"/>, this is pen's <see cref="Pen.tilt"/>.
130 /// </summary>
131 public Vector2 tilt { get; set; }
132 */
133
134 internal void ReadDeviceState()
135 {
136 if (control.parent is Pen pen)
137 {
138 uiToolkitPointerId = GetPenPointerId(pen);
139 #if UNITY_2021_1_OR_NEWER
140 pressure = pen.pressure.magnitude;
141 azimuthAngle = (pen.tilt.value.x + 1) * Mathf.PI / 2;
142 altitudeAngle = (pen.tilt.value.y + 1) * Mathf.PI / 2;
143 twist = pen.twist.value * Mathf.PI * 2;
144 #endif
145 #if UNITY_2022_3_OR_NEWER
146 displayIndex = pen.displayIndex.ReadValue();
147 #endif
148 }
149 else if (control.parent is TouchControl touchControl)
150 {
151 uiToolkitPointerId = GetTouchPointerId(touchControl);
152 #if UNITY_2021_1_OR_NEWER
153 pressure = touchControl.pressure.magnitude;
154 radius = touchControl.radius.value;
155 #endif
156 #if UNITY_2022_3_OR_NEWER
157 displayIndex = touchControl.displayIndex.ReadValue();
158 #endif
159 }
160 else if (control.parent is Touchscreen touchscreen)
161 {
162 uiToolkitPointerId = GetTouchPointerId(touchscreen.primaryTouch);
163 #if UNITY_2021_1_OR_NEWER
164 pressure = touchscreen.pressure.magnitude;
165 radius = touchscreen.radius.value;
166 #endif
167 #if UNITY_2022_3_OR_NEWER
168 displayIndex = touchscreen.displayIndex.ReadValue();
169 #endif
170 }
171 else
172 {
173 uiToolkitPointerId = UIElements.PointerId.mousePointerId;
174 }
175 }
176
177 private static int GetPenPointerId(Pen pen)
178 {
179 var n = 0;
180 foreach (var otherDevice in InputSystem.devices)
181 if (otherDevice is Pen otherPen)
182 {
183 if (pen == otherPen)
184 {
185 return UIElements.PointerId.penPointerIdBase +
186 Mathf.Min(n, UIElements.PointerId.penPointerCount - 1);
187 }
188 n++;
189 }
190 return UIElements.PointerId.penPointerIdBase;
191 }
192
193 private static int GetTouchPointerId(TouchControl touchControl)
194 {
195 var i = ((Touchscreen)touchControl.device).touches.IndexOfReference(touchControl);
196 return UIElements.PointerId.touchPointerIdBase +
197 Mathf.Clamp(i, 0, UIElements.PointerId.touchPointerCount - 1);
198 }
199 }
200
201 /// <summary>
202 /// General type of pointer that generated a <see cref="PointerEventData"/> pointer event.
203 /// </summary>
204 public enum UIPointerType
205 {
206 None,
207
208 /// <summary>
209 /// A <see cref="Mouse"/> or <see cref="Pen"/> or other general <see cref="Pointer"/>.
210 /// </summary>
211 MouseOrPen,
212
213 /// <summary>
214 /// A <see cref="Touchscreen"/>.
215 /// </summary>
216 Touch,
217
218 /// <summary>
219 /// A <see cref="TrackedDevice"/>.
220 /// </summary>
221 Tracked,
222 }
223
224 /// <summary>
225 /// Determine how the UI behaves in the presence of multiple pointer devices.
226 /// </summary>
227 /// <remarks>
228 /// While running, an application may, for example, have both a <see cref="Mouse"/> and a <see cref="Touchscreen"/> device
229 /// and both may end up getting bound to the actions of <see cref="InputSystemUIInputModule"/> and thus both may route
230 /// input into the UI. When this happens, the pointer behavior decides how the UI input module resolves the ambiguity.
231 /// </remarks>
232 public enum UIPointerBehavior
233 {
234 /// <summary>
235 /// Any input that isn't <see cref="Touchscreen"/> or <see cref="TrackedDevice"/> input is
236 /// treated as a single unified pointer.
237 ///
238 /// This is the default behavior based on the expectation that mice and pens will generally drive a single on-screen
239 /// cursor whereas touch and tracked devices have an inherent ability to generate multiple pointers.
240 ///
241 /// Note that when input from touch or tracked devices is received, the combined pointer for mice and pens (if it exists)
242 /// will be removed. If it was over UI objects, <c>IPointerExitHandler</c>s will be invoked.
243 /// </summary>
244 SingleMouseOrPenButMultiTouchAndTrack,
245
246 /// <summary>
247 /// All input is unified to a single pointer. This means that all input from all pointing devices (<see cref="Mouse"/>,
248 /// <see cref="Pen"/>, <see cref="Touchscreen"/>, and <see cref="TrackedDevice"/>) is routed into a single pointer
249 /// instance. There is only one position on screen which can be controlled from any of these devices.
250 /// </summary>
251 SingleUnifiedPointer,
252
253 /// <summary>
254 /// Any pointing device, whether it's <see cref="Mouse"/>, <see cref="Pen"/>, <see cref="Touchscreen"/>,
255 /// or <see cref="TrackedDevice"/> input, is treated as its own independent pointer and arbitrary many
256 /// such pointers can be active at any one time.
257 /// </summary>
258 AllPointersAsIs,
259 }
260}
261#endif