A game about forced loneliness, made by TACStudios
at master 385 lines 16 kB view raw
1using System; 2using System.ComponentModel; 3using System.Runtime.InteropServices; 4using UnityEngine.InputSystem.Controls; 5using UnityEngine.InputSystem.Layouts; 6using UnityEngine.InputSystem.LowLevel; 7using UnityEngine.InputSystem.Utilities; 8 9////TODO: expose whether pen actually has eraser and which barrel buttons it has 10 11////TODO: hook up pointerId in backend to allow identifying different pens 12 13////REVIEW: have surface distance property to detect how far pen is when hovering? 14 15////REVIEW: does it make sense to have orientation support for pen, too? 16 17namespace UnityEngine.InputSystem.LowLevel 18{ 19 /// <summary> 20 /// Default state layout for pen devices. 21 /// </summary> 22 // IMPORTANT: Must match with PenInputState in native. 23 [StructLayout(LayoutKind.Explicit, Size = 36)] 24 public struct PenState : IInputStateTypeInfo 25 { 26 /// <summary> 27 /// Format code for PenState. 28 /// </summary> 29 /// <value>Returns "PEN ".</value> 30 /// <seealso cref="InputStateBlock.format"/> 31 public static FourCC Format => new FourCC('P', 'E', 'N'); 32 33 /// <summary> 34 /// Current screen-space position of the pen. 35 /// </summary> 36 /// <value>Screen-space position.</value> 37 /// <seealso cref="Pointer.position"/> 38 [InputControl(usage = "Point", dontReset = true)] 39 [FieldOffset(0)] 40 public Vector2 position; 41 42 /// <summary> 43 /// Screen-space motion delta. 44 /// </summary> 45 /// <value>Screen-space motion delta.</value> 46 /// <seealso cref="Pointer.delta"/> 47 [InputControl(usage = "Secondary2DMotion", layout = "Delta")] 48 [FieldOffset(8)] 49 public Vector2 delta; 50 51 /// <summary> 52 /// The way the pen is leaned over perpendicular to the tablet surface. X goes [-1..1] left to right 53 /// (with -1 and 1 being completely flush to the surface) and Y goes [-1..1] bottom to top. 54 /// </summary> 55 /// <value>Amount pen is leaning over.</value> 56 /// <seealso cref="Pen.tilt"/> 57 [InputControl(layout = "Vector2", displayName = "Tilt", usage = "Tilt")] 58 [FieldOffset(16)] 59 public Vector2 tilt; 60 61 /// <summary> 62 /// Pressure with which the pen is pressed against the surface. 0 is none, 1 is full pressure. 63 /// </summary> 64 /// <value>Pressure with which the pen is pressed.</value> 65 /// <remarks> 66 /// May go beyond 1 depending on pressure calibration on the system. The maximum pressure point 67 /// may be set to less than the physical maximum pressure point determined by the hardware. 68 /// </remarks> 69 /// <seealso cref="Pointer.pressure"/> 70 [InputControl(layout = "Analog", usage = "Pressure", defaultState = 0.0f)] 71 [FieldOffset(24)] 72 public float pressure; 73 74 /// <summary> 75 /// Amount by which the pen is rotated around itself. 76 /// </summary> 77 /// <value>Rotation of the pen around itself.</value> 78 /// <seealso cref="Pen.twist"/> 79 [InputControl(layout = "Axis", displayName = "Twist", usage = "Twist")] 80 [FieldOffset(28)] 81 public float twist; 82 83 /// <summary> 84 /// Button mask for which buttons on the pen are active. 85 /// </summary> 86 /// <value>Bitmask for buttons on the pen.</value> 87 [InputControl(name = "tip", displayName = "Tip", layout = "Button", bit = (int)PenButton.Tip, usage = "PrimaryAction")] 88 [InputControl(name = "press", useStateFrom = "tip", synthetic = true, usages = new string[0])] 89 [InputControl(name = "eraser", displayName = "Eraser", layout = "Button", bit = (int)PenButton.Eraser)] 90 [InputControl(name = "inRange", displayName = "In Range?", layout = "Button", bit = (int)PenButton.InRange, synthetic = true)] 91 [InputControl(name = "barrel1", displayName = "Barrel Button #1", layout = "Button", bit = (int)PenButton.BarrelFirst, alias = "barrelFirst", usage = "SecondaryAction")] 92 [InputControl(name = "barrel2", displayName = "Barrel Button #2", layout = "Button", bit = (int)PenButton.BarrelSecond, alias = "barrelSecond")] 93 [InputControl(name = "barrel3", displayName = "Barrel Button #3", layout = "Button", bit = (int)PenButton.BarrelThird, alias = "barrelThird")] 94 [InputControl(name = "barrel4", displayName = "Barrel Button #4", layout = "Button", bit = (int)PenButton.BarrelFourth, alias = "barrelFourth")] 95 // "Park" unused controls. 96 [InputControl(name = "radius", layout = "Vector2", format = "VEC2", sizeInBits = 64, usage = "Radius", offset = InputStateBlock.AutomaticOffset)] 97 [InputControl(name = "pointerId", layout = "Digital", format = "UINT", sizeInBits = 32, offset = InputStateBlock.AutomaticOffset)] ////TODO: this should be used 98 [FieldOffset(32)] 99 public ushort buttons; 100 101 // Not currently used, but still needed in this struct for padding, 102 // as il2cpp does not implement FieldOffset. 103 [FieldOffset(34)] 104 ushort displayIndex; 105 106 /// <summary> 107 /// Set or unset the bit in <see cref="buttons"/> for the given <paramref name="button"/>. 108 /// </summary> 109 /// <param name="button">Button whose state to set.</param> 110 /// <param name="state">Whether the button is on or off.</param> 111 /// <returns>Same PenState with an updated <see cref="buttons"/> mask.</returns> 112 public PenState WithButton(PenButton button, bool state = true) 113 { 114 Debug.Assert((int)button < 16, $"Expected button < 16, so we fit into the 16 bit wide bitmask"); 115 var bit = 1U << (int)button; 116 if (state) 117 buttons |= (ushort)bit; 118 else 119 buttons &= (ushort)~bit; 120 return this; 121 } 122 123 /// <inheritdoc /> 124 public FourCC format => Format; 125 } 126} 127 128namespace UnityEngine.InputSystem 129{ 130 /// <summary> 131 /// Enumeration of buttons on a <see cref="Pen"/>. 132 /// </summary> 133 public enum PenButton 134 { 135 /// <summary> 136 /// Button at the tip of a pen. 137 /// </summary> 138 /// <seealso cref="Pen.tip"/> 139 Tip, 140 141 /// <summary> 142 /// Button located end of pen opposite to <see cref="Tip"/>. 143 /// </summary> 144 /// <remarks> 145 /// Pens do not necessarily have an eraser. If a pen doesn't, the respective button 146 /// does nothing and will always be unpressed. 147 /// </remarks> 148 /// <seealso cref="Pen.eraser"/> 149 Eraser, 150 151 /// <summary> 152 /// First button on the side of the pen. 153 /// </summary> 154 /// <see cref="Pen.firstBarrelButton"/> 155 BarrelFirst, 156 157 /// <summary> 158 /// Second button on the side of the pen. 159 /// </summary> 160 /// <seealso cref="Pen.secondBarrelButton"/> 161 BarrelSecond, 162 163 /// <summary> 164 /// Artificial button that indicates whether the pen is in detection range or not. 165 /// </summary> 166 /// <remarks> 167 /// Range detection may not be supported by a pen/tablet. 168 /// </remarks> 169 /// <seealso cref="Pen.inRange"/> 170 InRange, 171 172 /// <summary> 173 /// Third button on the side of the pen. 174 /// </summary> 175 /// <seealso cref="Pen.thirdBarrelButton"/> 176 BarrelThird, 177 178 /// <summary> 179 /// Fourth button on the side of the pen. 180 /// </summary> 181 /// <see cref="Pen.fourthBarrelButton"/> 182 BarrelFourth, 183 184 /// <summary> 185 /// Synonym for <see cref="BarrelFirst"/>. 186 /// </summary> 187 Barrel1 = BarrelFirst, 188 189 /// <summary> 190 /// Synonym for <see cref="BarrelSecond"/>. 191 /// </summary> 192 Barrel2 = BarrelSecond, 193 194 /// <summary> 195 /// Synonym for <see cref="BarrelThird"/>. 196 /// </summary> 197 Barrel3 = BarrelThird, 198 199 /// <summary> 200 /// Synonym for <see cref="BarrelFourth"/>. 201 /// </summary> 202 Barrel4 = BarrelFourth, 203 } 204 205 /// <summary> 206 /// Represents a pen/stylus input device. 207 /// </summary> 208 /// <remarks> 209 /// Unlike mice but like touch, pens are absolute pointing devices moving across a fixed 210 /// surface area. 211 /// 212 /// The <see cref="tip"/> acts as a button that is considered pressed as long as the pen is in contact with the 213 /// tablet surface. 214 /// </remarks> 215 [InputControlLayout(stateType = typeof(PenState), isGenericTypeOfDevice = true)] 216 public class Pen : Pointer 217 { 218 ////TODO: give the tip and eraser a very low press point 219 /// <summary> 220 /// The tip button of the pen. 221 /// </summary> 222 /// <value>Control representing the tip button.</value> 223 /// <seealso cref="PenButton.Tip"/> 224 public ButtonControl tip { get; protected set; } 225 226 /// <summary> 227 /// The eraser button of the pen, i.e. the button on the end opposite to the tip. 228 /// </summary> 229 /// <value>Control representing the eraser button.</value> 230 /// <remarks> 231 /// If the pen does not have an eraser button, this control will still be present 232 /// but will not trigger. 233 /// </remarks> 234 /// <seealso cref="PenButton.Eraser"/> 235 public ButtonControl eraser { get; protected set; } 236 237 /// <summary> 238 /// The button on the side of the pen barrel and located closer to the tip of the pen. 239 /// </summary> 240 /// <value>Control representing the first side button.</value> 241 /// <remarks> 242 /// If the pen does not have barrel buttons, this control will still be present 243 /// but will not trigger. 244 /// </remarks> 245 /// <seealso cref="PenButton.BarrelFirst"/> 246 public ButtonControl firstBarrelButton { get; protected set; } 247 248 /// <summary> 249 /// The button on the side of the pen barrel and located closer to the eraser end of the pen. 250 /// </summary> 251 /// <value>Control representing the second side button.</value> 252 /// <remarks> 253 /// If the pen does not have barrel buttons, this control will still be present 254 /// but will not trigger. 255 /// </remarks> 256 /// <seealso cref="PenButton.BarrelSecond"/> 257 public ButtonControl secondBarrelButton { get; protected set; } 258 259 /// <summary> 260 /// Third button the side of the pen barrel. 261 /// </summary> 262 /// <value>Control representing the third side button.</value> 263 /// <remarks> 264 /// If the pen does not have a third barrel buttons, this control will still be present 265 /// but will not trigger. 266 /// </remarks> 267 /// <seealso cref="PenButton.BarrelThird"/> 268 public ButtonControl thirdBarrelButton { get; protected set; } 269 270 /// <summary> 271 /// Fourth button the side of the pen barrel. 272 /// </summary> 273 /// <value>Control representing the fourth side button.</value> 274 /// <remarks> 275 /// If the pen does not have a fourth barrel buttons, this control will still be present 276 /// but will not trigger. 277 /// </remarks> 278 /// <seealso cref="PenButton.BarrelFourth"/> 279 public ButtonControl fourthBarrelButton { get; protected set; } 280 281 /// <summary> 282 /// Button control that indicates whether the pen is in range of the tablet surface or not. 283 /// </summary> 284 /// <remarks> 285 /// This is a synthetic control (<see cref="InputControl.synthetic"/>). 286 /// 287 /// If range detection is not supported by the pen, this button will always be "pressed". 288 /// </remarks> 289 /// <seealso cref="PenButton.InRange"/> 290 public ButtonControl inRange { get; protected set; } 291 292 /// <summary> 293 /// Orientation of the pen relative to the tablet surface, i.e. the amount by which it is leaning 294 /// over along the X and Y axis. 295 /// </summary> 296 /// <value>Control presenting the amount the pen is leaning over.</value> 297 /// <remarks> 298 /// X axis goes from [-1..1] left to right with -1 and 1 meaning the pen is flush with the tablet surface. Y axis 299 /// goes from [-1..1] bottom to top. 300 /// </remarks> 301 public Vector2Control tilt { get; protected set; } 302 303 /// <summary> 304 /// Rotation of the pointer around its own axis. 0 means the pointer is facing away from the user (12 'o clock position) 305 /// and ~1 means the pointer has been rotated clockwise almost one full rotation. 306 /// </summary> 307 /// <value>Control representing the twist of the pen around itself.</value> 308 /// <remarks> 309 /// Twist is generally only supported by pens and even among pens, twist support is rare. An example product that 310 /// supports twist is the Wacom Art Pen. 311 /// 312 /// The axis of rotation is the vector facing away from the pointer surface when the pointer is facing straight up 313 /// (i.e. the surface normal of the pointer surface). When the pointer is tilted, the rotation axis is tilted along 314 /// with it. 315 /// </remarks> 316 public AxisControl twist { get; protected set; } 317 318 /// <summary> 319 /// The pen that was active or connected last or <c>null</c> if there is no pen. 320 /// </summary> 321 public new static Pen current { get; internal set; } 322 323 /// <summary> 324 /// Return the given pen button. 325 /// </summary> 326 /// <param name="button">Pen button to return.</param> 327 /// <exception cref="ArgumentException"><paramref name="button"/> is not a valid pen button.</exception> 328 public ButtonControl this[PenButton button] 329 { 330 get 331 { 332 switch (button) 333 { 334 case PenButton.Tip: return tip; 335 case PenButton.Eraser: return eraser; 336 case PenButton.BarrelFirst: return firstBarrelButton; 337 case PenButton.BarrelSecond: return secondBarrelButton; 338 case PenButton.BarrelThird: return thirdBarrelButton; 339 case PenButton.BarrelFourth: return fourthBarrelButton; 340 case PenButton.InRange: return inRange; 341 default: 342 throw new InvalidEnumArgumentException(nameof(button), (int)button, typeof(PenButton)); 343 } 344 } 345 } 346 347 /// <summary> 348 /// Make this the last used pen, i.e. <see cref="current"/>. 349 /// </summary> 350 /// <remarks> 351 /// This is called automatically by the system when a pen is added or receives 352 /// input. 353 /// </remarks> 354 public override void MakeCurrent() 355 { 356 base.MakeCurrent(); 357 current = this; 358 } 359 360 /// <summary> 361 /// Called when the pen is removed from the system. 362 /// </summary> 363 protected override void OnRemoved() 364 { 365 base.OnRemoved(); 366 if (current == this) 367 current = null; 368 } 369 370 /// <inheritdoc /> 371 protected override void FinishSetup() 372 { 373 tip = GetChildControl<ButtonControl>("tip"); 374 eraser = GetChildControl<ButtonControl>("eraser"); 375 firstBarrelButton = GetChildControl<ButtonControl>("barrel1"); 376 secondBarrelButton = GetChildControl<ButtonControl>("barrel2"); 377 thirdBarrelButton = GetChildControl<ButtonControl>("barrel3"); 378 fourthBarrelButton = GetChildControl<ButtonControl>("barrel4"); 379 inRange = GetChildControl<ButtonControl>("inRange"); 380 tilt = GetChildControl<Vector2Control>("tilt"); 381 twist = GetChildControl<AxisControl>("twist"); 382 base.FinishSetup(); 383 } 384 } 385}