Mouse.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  1. using System.Runtime.InteropServices;
  2. using UnityEngine.InputSystem.Controls;
  3. using UnityEngine.InputSystem.Layouts;
  4. using UnityEngine.InputSystem.LowLevel;
  5. using UnityEngine.InputSystem.Utilities;
  6. ////TODO: option to allow to constrain mouse input to the screen area (i.e. no input once mouse leaves player window)
  7. namespace UnityEngine.InputSystem.LowLevel
  8. {
  9. /// <summary>
  10. /// Combine a single pointer with buttons and a scroll wheel.
  11. /// </summary>
  12. // IMPORTANT: State layout must match with MouseInputState in native.
  13. [StructLayout(LayoutKind.Explicit, Size = 30)]
  14. public struct MouseState : IInputStateTypeInfo
  15. {
  16. /// <summary>
  17. /// Memory format identifier for MouseState.
  18. /// </summary>
  19. /// <value>Returns "MOUS".</value>
  20. /// <seealso cref="InputStateBlock.format"/>
  21. public static FourCC Format => new FourCC('M', 'O', 'U', 'S');
  22. /// <summary>
  23. /// Screen-space position of the mouse in pixels.
  24. /// </summary>
  25. /// <value>Position of mouse on screen.</value>
  26. /// <seealso cref="Mouse.position"/>
  27. [InputControl(usage = "Point")]
  28. [FieldOffset(0)]
  29. public Vector2 position;
  30. /// <summary>
  31. /// Screen-space motion delta of the mouse in pixels.
  32. /// </summary>
  33. /// <value>Mouse movement.</value>
  34. /// <seealso cref="Mouse.delta"/>
  35. [InputControl(usage = "Secondary2DMotion")]
  36. [FieldOffset(8)]
  37. public Vector2 delta;
  38. ////REVIEW: have half-axis buttons on the scroll axes? (up, down, left, right)
  39. /// <summary>
  40. /// Scroll-wheel delta of the mouse.
  41. /// </summary>
  42. /// <value>Scroll wheel delta.</value>
  43. /// <seealso cref="Mouse.scroll"/>
  44. [InputControl(displayName = "Scroll")]
  45. [InputControl(name = "scroll/x", aliases = new[] { "horizontal" }, usage = "ScrollHorizontal", displayName = "Left/Right")]
  46. [InputControl(name = "scroll/y", aliases = new[] { "vertical" }, usage = "ScrollVertical", displayName = "Up/Down", shortDisplayName = "Wheel")]
  47. [FieldOffset(16)]
  48. public Vector2 scroll;
  49. /// <summary>
  50. /// Button mask for which buttons on the mouse are currently pressed.
  51. /// </summary>
  52. /// <value>Button state mask.</value>
  53. /// <seealso cref="MouseButton"/>
  54. /// <seealso cref="Mouse.leftButton"/>
  55. /// <seealso cref="Mouse.middleButton"/>
  56. /// <seealso cref="Mouse.rightButton"/>
  57. /// <seealso cref="Mouse.forwardButton"/>
  58. /// <seealso cref="Mouse.backButton"/>
  59. [InputControl(name = "press", useStateFrom = "leftButton", synthetic = true, usages = new string[0])]
  60. [InputControl(name = "leftButton", layout = "Button", bit = (int)MouseButton.Left, usage = "PrimaryAction", displayName = "Left Button", shortDisplayName = "LMB")]
  61. [InputControl(name = "rightButton", layout = "Button", bit = (int)MouseButton.Right, usage = "SecondaryAction", displayName = "Right Button", shortDisplayName = "RMB")]
  62. [InputControl(name = "middleButton", layout = "Button", bit = (int)MouseButton.Middle, displayName = "Middle Button", shortDisplayName = "MMB")]
  63. [InputControl(name = "forwardButton", layout = "Button", bit = (int)MouseButton.Forward, usage = "Forward", displayName = "Forward")]
  64. [InputControl(name = "backButton", layout = "Button", bit = (int)MouseButton.Back, usage = "Back", displayName = "Back")]
  65. [FieldOffset(24)]
  66. // "Park" all the controls that are common to pointers but aren't use for mice such that they get
  67. // appended to the end of device state where they will always have default values.
  68. ////FIXME: InputDeviceBuilder will get fooled and set up an incorrect state layout if we don't force this to VEC2; InputControlLayout will
  69. //// "infer" USHT as the format which will then end up with a layout where two 4 byte float controls are "packed" into a 16bit sized parent;
  70. //// in other words, setting VEC2 here manually should *not* be necessary
  71. [InputControl(name = "pressure", layout = "Axis", usage = "Pressure", offset = InputStateBlock.AutomaticOffset, format = "FLT", sizeInBits = 32)]
  72. [InputControl(name = "radius", layout = "Vector2", usage = "Radius", offset = InputStateBlock.AutomaticOffset, format = "VEC2", sizeInBits = 64)]
  73. [InputControl(name = "pointerId", layout = "Digital", format = "BIT", sizeInBits = 1, offset = InputStateBlock.AutomaticOffset)] // Will stay at 0.
  74. public ushort buttons;
  75. // Not currently used, but still needed in this struct for padding,
  76. // as il2cpp does not implement FieldOffset.
  77. [FieldOffset(26)]
  78. ushort displayIndex;
  79. /// <summary>
  80. /// Number of clicks performed in succession.
  81. /// </summary>
  82. /// <value>Successive click count.</value>
  83. /// <seealso cref="Mouse.clickCount"/>
  84. [InputControl(layout = "Integer", displayName = "Click Count", synthetic = true)]
  85. [FieldOffset(28)]
  86. public ushort clickCount;
  87. /// <summary>
  88. /// Set the button mask for the given button.
  89. /// </summary>
  90. /// <param name="button">Button whose state to set.</param>
  91. /// <param name="state">Whether to set the bit on or off.</param>
  92. /// <returns>The same MouseState with the change applied.</returns>
  93. /// <seealso cref="buttons"/>
  94. public MouseState WithButton(MouseButton button, bool state = true)
  95. {
  96. var bit = 1 << (int)button;
  97. if (state)
  98. buttons |= (ushort)bit;
  99. else
  100. buttons &= (ushort)~bit;
  101. return this;
  102. }
  103. /// <summary>
  104. /// Returns <see cref="Format"/>.
  105. /// </summary>
  106. /// <seealso cref="InputStateBlock.format"/>
  107. public FourCC format => Format;
  108. }
  109. /// <summary>
  110. /// Button indices for <see cref="MouseState.buttons"/>.
  111. /// </summary>
  112. public enum MouseButton
  113. {
  114. /// <summary>
  115. /// Left mouse button.
  116. /// </summary>
  117. /// <seealso cref="Mouse.leftButton"/>
  118. Left,
  119. /// <summary>
  120. /// Right mouse button.
  121. /// </summary>
  122. /// <seealso cref="Mouse.rightButton"/>
  123. Right,
  124. /// <summary>
  125. /// Middle mouse button.
  126. /// </summary>
  127. /// <seealso cref="Mouse.middleButton"/>
  128. Middle,
  129. /// <summary>
  130. /// Second side button.
  131. /// </summary>
  132. /// <seealso cref="Mouse.forwardButton"/>
  133. Forward,
  134. /// <summary>
  135. /// First side button.
  136. /// </summary>
  137. /// <seealso cref="Mouse.backButton"/>
  138. Back
  139. }
  140. }
  141. namespace UnityEngine.InputSystem
  142. {
  143. /// <summary>
  144. /// An input device representing a mouse.
  145. /// </summary>
  146. /// <remarks>
  147. /// Adds a scroll wheel and a typical 3-button setup with a left, middle, and right
  148. /// button.
  149. ///
  150. /// To control cursor display and behavior, use <see cref="UnityEngine.Cursor"/>.
  151. /// </remarks>
  152. [InputControlLayout(stateType = typeof(MouseState), isGenericTypeOfDevice = true)]
  153. [Scripting.Preserve]
  154. public class Mouse : Pointer, IInputStateCallbackReceiver
  155. {
  156. /// <summary>
  157. /// The horizontal and vertical scroll wheels.
  158. /// </summary>
  159. /// <value>Control representing the mouse scroll wheels.</value>
  160. /// <remarks>
  161. /// The <c>x</c> component corresponds to the horizontal scroll wheel, the
  162. /// <c>y</c> component to the vertical scroll wheel. Most mice do not have
  163. /// horizontal scroll wheels and will thus only see activity on <c>y</c>.
  164. /// </remarks>
  165. public Vector2Control scroll { get; private set; }
  166. /// <summary>
  167. /// The left mouse button.
  168. /// </summary>
  169. /// <value>Control representing the left mouse button.</value>
  170. public ButtonControl leftButton { get; private set; }
  171. /// <summary>
  172. /// The middle mouse button.
  173. /// </summary>
  174. /// <value>Control representing the middle mouse button.</value>
  175. public ButtonControl middleButton { get; private set; }
  176. /// <summary>
  177. /// The right mouse button.
  178. /// </summary>
  179. /// <value>Control representing the right mouse button.</value>
  180. public ButtonControl rightButton { get; private set; }
  181. /// <summary>
  182. /// The first side button, often labeled/used as "back".
  183. /// </summary>
  184. /// <value>Control representing the back button on the mouse.</value>
  185. /// <remarks>
  186. /// On Windows, this corresponds to <c>RI_MOUSE_BUTTON_4</c>.
  187. /// </remarks>
  188. public ButtonControl backButton { get; private set; }
  189. /// <summary>
  190. /// The second side button, often labeled/used as "forward".
  191. /// </summary>
  192. /// <value>Control representing the forward button on the mouse.</value>
  193. /// <remarks>
  194. /// On Windows, this corresponds to <c>RI_MOUSE_BUTTON_5</c>.
  195. /// </remarks>
  196. public ButtonControl forwardButton { get; private set; }
  197. /// <summary>
  198. /// Number of times any of the mouse buttons has been clicked in succession within
  199. /// the system-defined click time threshold.
  200. /// </summary>
  201. /// <value>Control representing the mouse click count.</value>
  202. public IntegerControl clickCount { get; private set; }
  203. /// <summary>
  204. /// The mouse that was added or updated last or null if there is no mouse
  205. /// connected to the system.
  206. /// </summary>
  207. /// <seealso cref="InputDevice.MakeCurrent"/>
  208. public new static Mouse current { get; private set; }
  209. /// <summary>
  210. /// Called when the mouse becomes the current mouse.
  211. /// </summary>
  212. public override void MakeCurrent()
  213. {
  214. base.MakeCurrent();
  215. current = this;
  216. }
  217. /// <summary>
  218. /// Called when the mouse is added to the system.
  219. /// </summary>
  220. protected override void OnAdded()
  221. {
  222. base.OnAdded();
  223. if (native && s_PlatformMouseDevice == null)
  224. s_PlatformMouseDevice = this;
  225. }
  226. /// <summary>
  227. /// Called when the device is removed from the system.
  228. /// </summary>
  229. protected override void OnRemoved()
  230. {
  231. base.OnRemoved();
  232. if (current == this)
  233. current = null;
  234. }
  235. internal static Mouse s_PlatformMouseDevice;
  236. ////REVIEW: how should we handle this being called from EditorWindow's? (where the editor window space processor will turn coordinates automatically into editor window space)
  237. /// <summary>
  238. /// Move the operating system's mouse cursor.
  239. /// </summary>
  240. /// <param name="position">New position in player window space.</param>
  241. /// <remarks>
  242. /// The <see cref="Pointer.position"/> property will not update immediately but rather will update in the
  243. /// next input update.
  244. /// </remarks>
  245. public void WarpCursorPosition(Vector2 position)
  246. {
  247. var command = WarpMousePositionCommand.Create(position);
  248. ExecuteCommand(ref command);
  249. }
  250. /// <inheritdoc />
  251. protected override void FinishSetup()
  252. {
  253. scroll = GetChildControl<Vector2Control>("scroll");
  254. leftButton = GetChildControl<ButtonControl>("leftButton");
  255. middleButton = GetChildControl<ButtonControl>("middleButton");
  256. rightButton = GetChildControl<ButtonControl>("rightButton");
  257. forwardButton = GetChildControl<ButtonControl>("forwardButton");
  258. backButton = GetChildControl<ButtonControl>("backButton");
  259. clickCount = GetChildControl<IntegerControl>("clickCount");
  260. base.FinishSetup();
  261. }
  262. /// <summary>
  263. /// Implements <see cref="IInputStateCallbackReceiver.OnNextUpdate"/> for the mouse.
  264. /// </summary>
  265. protected new void OnNextUpdate()
  266. {
  267. base.OnNextUpdate();
  268. InputState.Change(scroll, Vector2.zero);
  269. }
  270. /// <summary>
  271. /// Implements <see cref="IInputStateCallbackReceiver.OnStateEvent"/> for the mouse.
  272. /// </summary>
  273. /// <param name="eventPtr"></param>
  274. protected new unsafe void OnStateEvent(InputEventPtr eventPtr)
  275. {
  276. var statePtr = currentStatePtr;
  277. scroll.x.AccumulateValueInEvent(statePtr, eventPtr);
  278. scroll.y.AccumulateValueInEvent(statePtr, eventPtr);
  279. base.OnStateEvent(eventPtr);
  280. }
  281. void IInputStateCallbackReceiver.OnNextUpdate()
  282. {
  283. OnNextUpdate();
  284. }
  285. void IInputStateCallbackReceiver.OnStateEvent(InputEventPtr eventPtr)
  286. {
  287. OnStateEvent(eventPtr);
  288. }
  289. }
  290. }