File size: 11,133 Bytes
18a519f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
#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
{
    /// <summary>
    /// An extension to <c>PointerEventData</c> which makes additional data about the input event available.
    /// </summary>
    /// <remarks>
    /// Instances of this class are sent instead of <see cref="PointerEventData"/>  by <see cref="InputSystemUIInputModule"/>
    /// for all pointer-type input.
    ///
    /// The <see cref="PointerEventData.pointerId"/> property will generally correspond to the <see cref="InputDevice.deviceId"/>
    /// of <see cref="device"/>. An exception to this are touches as each <see cref="Touchscreen"/> may generate several pointers
    /// (one for each active finger).
    /// </remarks>
    public class ExtendedPointerEventData : PointerEventData
    {
        public ExtendedPointerEventData(EventSystem eventSystem)
            : base(eventSystem)
        {
        }

        /// <summary>
        /// The <see cref="InputControl"/> that generated the pointer input.
        /// The device associated with this control should be the same as this event's device.
        /// </summary>
        /// <seealso cref="device"/>
        public InputControl control { get; set; }

        /// <summary>
        /// The <see cref="InputDevice"/> that generated the pointer input.
        /// </summary>
        /// <seealso cref="Pointer"/>
        /// <seealso cref="Touchscreen"/>
        /// <seealso cref="Mouse"/>
        /// <seealso cref="Pen"/>
        public InputDevice device { get; set; }

        /// <summary>
        /// For <see cref="UIPointerType.Touch"/> type pointer input, this is the touch ID as reported by the
        /// <see cref="Touchscreen"/> device.
        /// </summary>
        /// <remarks>
        /// 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, <see cref="PointerEventData.pointerId"/> will be a combination of the
        /// device ID of <see cref="device"/> and the touch ID to generate a unique pointer ID even if there
        /// are multiple touchscreens.
        /// </remarks>
        /// <seealso cref="TouchControl.touchId"/>
        public int touchId { get; set; }

        /// <summary>
        /// Type of pointer that generated the input.
        /// </summary>
        public UIPointerType pointerType { get; set; }

        public int uiToolkitPointerId { get; set; }

        /// <summary>
        /// For <see cref="UIPointerType.Tracked"/> type pointer input, this is the world-space position of
        /// the <see cref="TrackedDevice"/>.
        /// </summary>
        /// <seealso cref="InputSystemUIInputModule.trackedDevicePosition"/>
        public Vector3 trackedDevicePosition { get; set; }

        /// <summary>
        /// For <see cref="UIPointerType.Tracked"/> type pointer input, this is the world-space orientation of
        /// the <see cref="TrackedDevice"/>.
        /// </summary>
        /// <seealso cref="InputSystemUIInputModule.trackedDeviceOrientation"/>
        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)
        /*
        /// <summary>
        /// If supported by the input device, this is the pressure level of the pointer contact. This is generally
        /// only supported by <see cref="Pen"/> devices as well as by <see cref="Touchscreen"/>s on phones. If not
        /// supported, this will be 1.
        /// </summary>
        /// <seealso cref="Pointer.pressure"/>
        public float pressure { get; set; }

        /// <summary>
        /// If the pointer input is coming from a <see cref="Pen"/>, this is pen's <see cref="Pen.tilt"/>.
        /// </summary>
        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);
        }
    }

    /// <summary>
    /// General type of pointer that generated a <see cref="PointerEventData"/> pointer event.
    /// </summary>
    public enum UIPointerType
    {
        None,

        /// <summary>
        /// A <see cref="Mouse"/> or <see cref="Pen"/> or other general <see cref="Pointer"/>.
        /// </summary>
        MouseOrPen,

        /// <summary>
        /// A <see cref="Touchscreen"/>.
        /// </summary>
        Touch,

        /// <summary>
        /// A <see cref="TrackedDevice"/>.
        /// </summary>
        Tracked,
    }

    /// <summary>
    /// Determine how the UI behaves in the presence of multiple pointer devices.
    /// </summary>
    /// <remarks>
    /// While running, an application may, for example, have both a <see cref="Mouse"/> and a <see cref="Touchscreen"/> device
    /// and both may end up getting bound to the actions of <see cref="InputSystemUIInputModule"/> and thus both may route
    /// input into the UI. When this happens, the pointer behavior decides how the UI input module resolves the ambiguity.
    /// </remarks>
    public enum UIPointerBehavior
    {
        /// <summary>
        /// Any input that isn't <see cref="Touchscreen"/> or <see cref="TrackedDevice"/> 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, <c>IPointerExitHandler</c>s will be invoked.
        /// </summary>
        SingleMouseOrPenButMultiTouchAndTrack,

        /// <summary>
        /// All input is unified to a single pointer. This means that all input from all pointing devices (<see cref="Mouse"/>,
        /// <see cref="Pen"/>, <see cref="Touchscreen"/>, and <see cref="TrackedDevice"/>) is routed into a single pointer
        /// instance. There is only one position on screen which can be controlled from any of these devices.
        /// </summary>
        SingleUnifiedPointer,

        /// <summary>
        /// Any pointing device, whether it's <see cref="Mouse"/>, <see cref="Pen"/>, <see cref="Touchscreen"/>,
        /// or <see cref="TrackedDevice"/> input, is treated as its own independent pointer and arbitrary many
        /// such pointers can be active at any one time.
        /// </summary>
        AllPointersAsIs,
    }
}
#endif