Nav apraksta
Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

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