No Description
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Mouse.cs 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  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="Pointer.position"/>
  27. [InputControl(usage = "Point", dontReset = true)] // Mouse should stay put when we reset devices.
  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="Pointer.delta"/>
  35. [InputControl(usage = "Secondary2DMotion", layout = "Delta")]
  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", layout = "Delta")]
  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. /// <summary>
  76. /// The index of the display that was moused.
  77. /// </summary>
  78. [InputControl(name = "displayIndex", layout = "Integer", displayName = "Display Index")]
  79. [FieldOffset(26)]
  80. public ushort displayIndex;
  81. /// <summary>
  82. /// Number of clicks performed in succession.
  83. /// </summary>
  84. /// <value>Successive click count.</value>
  85. /// <seealso cref="Mouse.clickCount"/>
  86. [InputControl(name = "clickCount", layout = "Integer", displayName = "Click Count", synthetic = true)]
  87. [FieldOffset(28)]
  88. public ushort clickCount;
  89. /// <summary>
  90. /// Set the button mask for the given button.
  91. /// </summary>
  92. /// <param name="button">Button whose state to set.</param>
  93. /// <param name="state">Whether to set the bit on or off.</param>
  94. /// <returns>The same MouseState with the change applied.</returns>
  95. /// <seealso cref="buttons"/>
  96. public MouseState WithButton(MouseButton button, bool state = true)
  97. {
  98. Debug.Assert((int)button < 16, $"Expected button < 16, so we fit into the 16 bit wide bitmask");
  99. var bit = 1U << (int)button;
  100. if (state)
  101. buttons |= (ushort)bit;
  102. else
  103. buttons &= (ushort)~bit;
  104. return this;
  105. }
  106. /// <summary>
  107. /// Returns <see cref="Format"/>.
  108. /// </summary>
  109. /// <seealso cref="InputStateBlock.format"/>
  110. public FourCC format => Format;
  111. }
  112. /// <summary>
  113. /// Button indices for <see cref="MouseState.buttons"/>.
  114. /// </summary>
  115. public enum MouseButton
  116. {
  117. /// <summary>
  118. /// Left mouse button.
  119. /// </summary>
  120. /// <seealso cref="Mouse.leftButton"/>
  121. Left,
  122. /// <summary>
  123. /// Right mouse button.
  124. /// </summary>
  125. /// <seealso cref="Mouse.rightButton"/>
  126. Right,
  127. /// <summary>
  128. /// Middle mouse button.
  129. /// </summary>
  130. /// <seealso cref="Mouse.middleButton"/>
  131. Middle,
  132. /// <summary>
  133. /// Second side button.
  134. /// </summary>
  135. /// <seealso cref="Mouse.forwardButton"/>
  136. Forward,
  137. /// <summary>
  138. /// First side button.
  139. /// </summary>
  140. /// <seealso cref="Mouse.backButton"/>
  141. Back
  142. }
  143. }
  144. namespace UnityEngine.InputSystem
  145. {
  146. /// <summary>
  147. /// An input device representing a mouse.
  148. /// </summary>
  149. /// <remarks>
  150. /// Adds a scroll wheel and a typical 3-button setup with a left, middle, and right
  151. /// button.
  152. ///
  153. /// To control cursor display and behavior, use <see cref="UnityEngine.Cursor"/>.
  154. /// </remarks>
  155. [InputControlLayout(stateType = typeof(MouseState), isGenericTypeOfDevice = true)]
  156. public class Mouse : Pointer, IInputStateCallbackReceiver
  157. {
  158. /// <summary>
  159. /// The horizontal and vertical scroll wheels.
  160. /// </summary>
  161. /// <value>Control representing the mouse scroll wheels.</value>
  162. /// <remarks>
  163. /// The <c>x</c> component corresponds to the horizontal scroll wheel, the
  164. /// <c>y</c> component to the vertical scroll wheel. Most mice do not have
  165. /// horizontal scroll wheels and will thus only see activity on <c>y</c>.
  166. /// </remarks>
  167. public DeltaControl scroll { get; protected set; }
  168. /// <summary>
  169. /// The left mouse button.
  170. /// </summary>
  171. /// <value>Control representing the left mouse button.</value>
  172. public ButtonControl leftButton { get; protected set; }
  173. /// <summary>
  174. /// The middle mouse button.
  175. /// </summary>
  176. /// <value>Control representing the middle mouse button.</value>
  177. public ButtonControl middleButton { get; protected set; }
  178. /// <summary>
  179. /// The right mouse button.
  180. /// </summary>
  181. /// <value>Control representing the right mouse button.</value>
  182. public ButtonControl rightButton { get; protected set; }
  183. /// <summary>
  184. /// The first side button, often labeled/used as "back".
  185. /// </summary>
  186. /// <value>Control representing the back button on the mouse.</value>
  187. /// <remarks>
  188. /// On Windows, this corresponds to <c>RI_MOUSE_BUTTON_4</c>.
  189. /// </remarks>
  190. public ButtonControl backButton { get; protected set; }
  191. /// <summary>
  192. /// The second side button, often labeled/used as "forward".
  193. /// </summary>
  194. /// <value>Control representing the forward button on the mouse.</value>
  195. /// <remarks>
  196. /// On Windows, this corresponds to <c>RI_MOUSE_BUTTON_5</c>.
  197. /// </remarks>
  198. public ButtonControl forwardButton { get; protected set; }
  199. /// <summary>
  200. /// Number of times any of the mouse buttons has been clicked in succession within
  201. /// the system-defined click time threshold.
  202. /// </summary>
  203. /// <value>Control representing the mouse click count.</value>
  204. public IntegerControl clickCount { get; protected set; }
  205. /// <summary>
  206. /// The mouse that was added or updated last or null if there is no mouse
  207. /// connected to the system.
  208. /// </summary>
  209. /// <seealso cref="InputDevice.MakeCurrent"/>
  210. public new static Mouse current { get; private set; }
  211. /// <summary>
  212. /// Called when the mouse becomes the current mouse.
  213. /// </summary>
  214. public override void MakeCurrent()
  215. {
  216. base.MakeCurrent();
  217. current = this;
  218. }
  219. /// <summary>
  220. /// Called when the mouse is added to the system.
  221. /// </summary>
  222. protected override void OnAdded()
  223. {
  224. base.OnAdded();
  225. if (native && s_PlatformMouseDevice == null)
  226. s_PlatformMouseDevice = this;
  227. }
  228. /// <summary>
  229. /// Called when the device is removed from the system.
  230. /// </summary>
  231. protected override void OnRemoved()
  232. {
  233. base.OnRemoved();
  234. if (current == this)
  235. current = null;
  236. }
  237. internal static Mouse s_PlatformMouseDevice;
  238. ////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)
  239. /// <summary>
  240. /// Move the operating system's mouse cursor.
  241. /// </summary>
  242. /// <param name="position">New position in player window space.</param>
  243. /// <remarks>
  244. /// The <see cref="Pointer.position"/> property will not update immediately but rather will update in the
  245. /// next input update.
  246. /// </remarks>
  247. public void WarpCursorPosition(Vector2 position)
  248. {
  249. var command = WarpMousePositionCommand.Create(position);
  250. ExecuteCommand(ref command);
  251. }
  252. /// <inheritdoc />
  253. protected override void FinishSetup()
  254. {
  255. scroll = GetChildControl<DeltaControl>("scroll");
  256. leftButton = GetChildControl<ButtonControl>("leftButton");
  257. middleButton = GetChildControl<ButtonControl>("middleButton");
  258. rightButton = GetChildControl<ButtonControl>("rightButton");
  259. forwardButton = GetChildControl<ButtonControl>("forwardButton");
  260. backButton = GetChildControl<ButtonControl>("backButton");
  261. displayIndex = GetChildControl<IntegerControl>("displayIndex");
  262. clickCount = GetChildControl<IntegerControl>("clickCount");
  263. base.FinishSetup();
  264. }
  265. /// <summary>
  266. /// Implements <see cref="IInputStateCallbackReceiver.OnNextUpdate"/> for the mouse.
  267. /// </summary>
  268. protected new void OnNextUpdate()
  269. {
  270. base.OnNextUpdate();
  271. InputState.Change(scroll, Vector2.zero);
  272. }
  273. /// <summary>
  274. /// Implements <see cref="IInputStateCallbackReceiver.OnStateEvent"/> for the mouse.
  275. /// </summary>
  276. /// <param name="eventPtr"></param>
  277. protected new unsafe void OnStateEvent(InputEventPtr eventPtr)
  278. {
  279. scroll.AccumulateValueInEvent(currentStatePtr, eventPtr);
  280. base.OnStateEvent(eventPtr);
  281. }
  282. void IInputStateCallbackReceiver.OnNextUpdate()
  283. {
  284. OnNextUpdate();
  285. }
  286. void IInputStateCallbackReceiver.OnStateEvent(InputEventPtr eventPtr)
  287. {
  288. OnStateEvent(eventPtr);
  289. }
  290. }
  291. }