暂无描述
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

VirtualMouseInput.cs 27KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613
  1. #if PACKAGE_DOCS_GENERATION || UNITY_INPUT_SYSTEM_ENABLE_UI
  2. using System;
  3. using UnityEngine.InputSystem.LowLevel;
  4. using UnityEngine.UI;
  5. ////TODO: respect cursor lock mode
  6. ////TODO: investigate how driving the HW cursor behaves when FPS drops low
  7. //// (also, maybe we can add support where we turn the gamepad mouse on and off automatically based on whether the system mouse is used)
  8. ////TODO: add support for acceleration
  9. ////TODO: automatically scale mouse speed to resolution such that it stays constant regardless of resolution
  10. ////TODO: make it work with PlayerInput such that it will automatically look up actions in the actual PlayerInput instance it is used with (based on the action IDs it has)
  11. ////REVIEW: should we default the SW cursor position to the center of the screen?
  12. ////REVIEW: consider this for inclusion directly in the input system
  13. namespace UnityEngine.InputSystem.UI
  14. {
  15. /// <summary>
  16. /// A component that creates a virtual <see cref="Mouse"/> device and drives its input from gamepad-style inputs. This effectively
  17. /// adds a software mouse cursor.
  18. /// </summary>
  19. /// <remarks>
  20. /// This component can be used with UIs that are designed for mouse input, i.e. need to be operated with a cursor.
  21. /// By hooking up the <see cref="InputAction"/>s of this component to gamepad input and directing <see cref="cursorTransform"/>
  22. /// to the UI transform of the cursor, you can use this component to drive an on-screen cursor.
  23. ///
  24. /// Note that this component does not actually trigger UI input itself. Instead, it creates a virtual <see cref="Mouse"/>
  25. /// device which can then be picked up elsewhere (such as by <see cref="InputSystemUIInputModule"/>) where mouse/pointer input
  26. /// is expected.
  27. ///
  28. /// Also note that if there is a <see cref="Mouse"/> added by the platform, it is not impacted by this component. More specifically,
  29. /// the system mouse cursor will not be moved or otherwise used by this component.
  30. ///
  31. /// Input from the component is visible in the same frame as the source input on its actions by virtue of using <see cref="InputState.Change"/>.
  32. /// </remarks>
  33. /// <seealso cref="Gamepad"/>
  34. /// <seealso cref="Mouse"/>
  35. [AddComponentMenu("Input/Virtual Mouse")]
  36. [HelpURL(InputSystem.kDocUrl + "/manual/UISupport.html#virtual-mouse-cursor-control")]
  37. public class VirtualMouseInput : MonoBehaviour
  38. {
  39. /// <summary>
  40. /// Optional transform that will be updated to correspond to the current mouse position.
  41. /// </summary>
  42. /// <value>Transform to update with mouse position.</value>
  43. /// <remarks>
  44. /// This is useful for having a UI object that directly represents the mouse cursor. Simply add both the
  45. /// <c>VirtualMouseInput</c> component and an <a href="https://docs.unity3d.com/Manual/script-Image.html">Image</a>
  46. /// component and hook the <a href="https://docs.unity3d.com/ScriptReference/RectTransform.html">RectTransform</a>
  47. /// component for the UI object into here. The object as a whole will then follow the generated mouse cursor
  48. /// motion.
  49. /// </remarks>
  50. public RectTransform cursorTransform
  51. {
  52. get => m_CursorTransform;
  53. set => m_CursorTransform = value;
  54. }
  55. /// <summary>
  56. /// How many pixels per second the cursor travels in one axis when the respective axis from
  57. /// <see cref="stickAction"/> is 1.
  58. /// </summary>
  59. /// <value>Mouse speed in pixels per second.</value>
  60. public float cursorSpeed
  61. {
  62. get => m_CursorSpeed;
  63. set => m_CursorSpeed = value;
  64. }
  65. /// <summary>
  66. /// Determines which cursor representation to use. If this is set to <see cref="CursorMode.SoftwareCursor"/>
  67. /// (the default), then <see cref="cursorGraphic"/> and <see cref="cursorTransform"/> define a software cursor
  68. /// that is made to correspond to the position of <see cref="virtualMouse"/>. If this is set to <see
  69. /// cref="CursorMode.HardwareCursorIfAvailable"/> and there is a native <see cref="Mouse"/> device present,
  70. /// the component will take over that mouse device and disable it (so as for it to not also generate position
  71. /// updates). It will then use <see cref="Mouse.WarpCursorPosition"/> to move the system mouse cursor to
  72. /// correspond to the position of the <see cref="virtualMouse"/>. In this case, <see cref="cursorGraphic"/>
  73. /// will be disabled and <see cref="cursorTransform"/> will not be updated.
  74. /// </summary>
  75. /// <value>Whether the system mouse cursor (if present) should be made to correspond with the virtual mouse position.</value>
  76. /// <remarks>
  77. /// Note that regardless of which mode is used for the cursor, mouse input is expected to be picked up from <see cref="virtualMouse"/>.
  78. ///
  79. /// Note that if <see cref="CursorMode.HardwareCursorIfAvailable"/> is used, the software cursor is still used
  80. /// if no native <see cref="Mouse"/> device is present.
  81. /// </remarks>
  82. public CursorMode cursorMode
  83. {
  84. get => m_CursorMode;
  85. set
  86. {
  87. if (m_CursorMode == value)
  88. return;
  89. // If we're turning it off, make sure we re-enable the system mouse.
  90. if (m_CursorMode == CursorMode.HardwareCursorIfAvailable && m_SystemMouse != null)
  91. {
  92. InputSystem.EnableDevice(m_SystemMouse);
  93. m_SystemMouse = null;
  94. }
  95. m_CursorMode = value;
  96. if (m_CursorMode == CursorMode.HardwareCursorIfAvailable)
  97. TryEnableHardwareCursor();
  98. else if (m_CursorGraphic != null)
  99. m_CursorGraphic.enabled = true;
  100. }
  101. }
  102. /// <summary>
  103. /// The UI graphic element that represents the mouse cursor.
  104. /// </summary>
  105. /// <value>Graphic element for the software mouse cursor.</value>
  106. /// <remarks>
  107. /// If <see cref="cursorMode"/> is set to <see cref="CursorMode.HardwareCursorIfAvailable"/>, this graphic will
  108. /// be disabled.
  109. ///
  110. /// Also, this UI component implicitly determines the <c>Canvas</c> that defines the screen area for the cursor.
  111. /// The canvas that this graphic is on will be looked up using <c>GetComponentInParent</c> and then the <c>Canvas.pixelRect</c>
  112. /// of the canvas is used as the bounds for the cursor motion range.
  113. /// </remarks>
  114. /// <seealso cref="CursorMode.SoftwareCursor"/>
  115. public Graphic cursorGraphic
  116. {
  117. get => m_CursorGraphic;
  118. set
  119. {
  120. m_CursorGraphic = value;
  121. TryFindCanvas();
  122. }
  123. }
  124. /// <summary>
  125. /// Multiplier for values received from <see cref="scrollWheelAction"/>.
  126. /// </summary>
  127. /// <value>Multiplier for scroll values.</value>
  128. public float scrollSpeed
  129. {
  130. get => m_ScrollSpeed;
  131. set => m_ScrollSpeed = value;
  132. }
  133. /// <summary>
  134. /// The virtual mouse device that the component feeds with input.
  135. /// </summary>
  136. /// <value>Instance of virtual mouse or <c>null</c>.</value>
  137. /// <remarks>
  138. /// This is only initialized after the component has been enabled for the first time. Note that
  139. /// when subsequently disabling the component, the property will continue to return the mouse device
  140. /// but the device will not be added to the system while the component is not enabled.
  141. /// </remarks>
  142. public Mouse virtualMouse => m_VirtualMouse;
  143. /// <summary>
  144. /// The Vector2 stick input that drives the mouse cursor, i.e. <see cref="Pointer.position"/> on
  145. /// <see cref="virtualMouse"/> and the <a
  146. /// href="https://docs.unity3d.com/ScriptReference/RectTransform-anchoredPosition.html">anchoredPosition</a>
  147. /// on <see cref="cursorTransform"/> (if set).
  148. /// </summary>
  149. /// <value>Stick input that drives cursor position.</value>
  150. /// <remarks>
  151. /// This should normally be bound to controls such as <see cref="Gamepad.leftStick"/> and/or
  152. /// <see cref="Gamepad.rightStick"/>.
  153. /// </remarks>
  154. public InputActionProperty stickAction
  155. {
  156. get => m_StickAction;
  157. set => SetAction(ref m_StickAction, value);
  158. }
  159. /// <summary>
  160. /// Optional button input that determines when <see cref="Mouse.leftButton"/> is pressed on
  161. /// <see cref="virtualMouse"/>.
  162. /// </summary>
  163. /// <value>Input for <see cref="Mouse.leftButton"/>.</value>
  164. public InputActionProperty leftButtonAction
  165. {
  166. get => m_LeftButtonAction;
  167. set
  168. {
  169. if (m_ButtonActionTriggeredDelegate != null)
  170. SetActionCallback(m_LeftButtonAction, m_ButtonActionTriggeredDelegate, false);
  171. SetAction(ref m_LeftButtonAction, value);
  172. if (m_ButtonActionTriggeredDelegate != null)
  173. SetActionCallback(m_LeftButtonAction, m_ButtonActionTriggeredDelegate, true);
  174. }
  175. }
  176. /// <summary>
  177. /// Optional button input that determines when <see cref="Mouse.rightButton"/> is pressed on
  178. /// <see cref="virtualMouse"/>.
  179. /// </summary>
  180. /// <value>Input for <see cref="Mouse.rightButton"/>.</value>
  181. public InputActionProperty rightButtonAction
  182. {
  183. get => m_RightButtonAction;
  184. set
  185. {
  186. if (m_ButtonActionTriggeredDelegate != null)
  187. SetActionCallback(m_RightButtonAction, m_ButtonActionTriggeredDelegate, false);
  188. SetAction(ref m_RightButtonAction, value);
  189. if (m_ButtonActionTriggeredDelegate != null)
  190. SetActionCallback(m_RightButtonAction, m_ButtonActionTriggeredDelegate, true);
  191. }
  192. }
  193. /// <summary>
  194. /// Optional button input that determines when <see cref="Mouse.middleButton"/> is pressed on
  195. /// <see cref="virtualMouse"/>.
  196. /// </summary>
  197. /// <value>Input for <see cref="Mouse.middleButton"/>.</value>
  198. public InputActionProperty middleButtonAction
  199. {
  200. get => m_MiddleButtonAction;
  201. set
  202. {
  203. if (m_ButtonActionTriggeredDelegate != null)
  204. SetActionCallback(m_MiddleButtonAction, m_ButtonActionTriggeredDelegate, false);
  205. SetAction(ref m_MiddleButtonAction, value);
  206. if (m_ButtonActionTriggeredDelegate != null)
  207. SetActionCallback(m_MiddleButtonAction, m_ButtonActionTriggeredDelegate, true);
  208. }
  209. }
  210. /// <summary>
  211. /// Optional button input that determines when <see cref="Mouse.forwardButton"/> is pressed on
  212. /// <see cref="virtualMouse"/>.
  213. /// </summary>
  214. /// <value>Input for <see cref="Mouse.forwardButton"/>.</value>
  215. public InputActionProperty forwardButtonAction
  216. {
  217. get => m_ForwardButtonAction;
  218. set
  219. {
  220. if (m_ButtonActionTriggeredDelegate != null)
  221. SetActionCallback(m_ForwardButtonAction, m_ButtonActionTriggeredDelegate, false);
  222. SetAction(ref m_ForwardButtonAction, value);
  223. if (m_ButtonActionTriggeredDelegate != null)
  224. SetActionCallback(m_ForwardButtonAction, m_ButtonActionTriggeredDelegate, true);
  225. }
  226. }
  227. /// <summary>
  228. /// Optional button input that determines when <see cref="Mouse.forwardButton"/> is pressed on
  229. /// <see cref="virtualMouse"/>.
  230. /// </summary>
  231. /// <value>Input for <see cref="Mouse.forwardButton"/>.</value>
  232. public InputActionProperty backButtonAction
  233. {
  234. get => m_BackButtonAction;
  235. set
  236. {
  237. if (m_ButtonActionTriggeredDelegate != null)
  238. SetActionCallback(m_BackButtonAction, m_ButtonActionTriggeredDelegate, false);
  239. SetAction(ref m_BackButtonAction, value);
  240. if (m_ButtonActionTriggeredDelegate != null)
  241. SetActionCallback(m_BackButtonAction, m_ButtonActionTriggeredDelegate, true);
  242. }
  243. }
  244. /// <summary>
  245. /// Optional Vector2 value input that determines the value of <see cref="Mouse.scroll"/> on
  246. /// <see cref="virtualMouse"/>.
  247. /// </summary>
  248. /// <value>Input for <see cref="Mouse.scroll"/>.</value>
  249. /// <remarks>
  250. /// In case you want to only bind vertical scrolling, simply have a <see cref="Composites.Vector2Composite"/>
  251. /// with only <c>Up</c> and <c>Down</c> bound and <c>Left</c> and <c>Right</c> deleted or bound to nothing.
  252. /// </remarks>
  253. public InputActionProperty scrollWheelAction
  254. {
  255. get => m_ScrollWheelAction;
  256. set => SetAction(ref m_ScrollWheelAction, value);
  257. }
  258. protected void OnEnable()
  259. {
  260. // Hijack system mouse, if enabled.
  261. if (m_CursorMode == CursorMode.HardwareCursorIfAvailable)
  262. TryEnableHardwareCursor();
  263. // Add mouse device.
  264. if (m_VirtualMouse == null)
  265. m_VirtualMouse = (Mouse)InputSystem.AddDevice("VirtualMouse");
  266. else if (!m_VirtualMouse.added)
  267. InputSystem.AddDevice(m_VirtualMouse);
  268. // Set initial cursor position.
  269. if (m_CursorTransform != null)
  270. {
  271. var position = m_CursorTransform.anchoredPosition;
  272. InputState.Change(m_VirtualMouse.position, position);
  273. m_SystemMouse?.WarpCursorPosition(position);
  274. }
  275. // Hook into input update.
  276. if (m_AfterInputUpdateDelegate == null)
  277. m_AfterInputUpdateDelegate = OnAfterInputUpdate;
  278. InputSystem.onAfterUpdate += m_AfterInputUpdateDelegate;
  279. // Hook into actions.
  280. if (m_ButtonActionTriggeredDelegate == null)
  281. m_ButtonActionTriggeredDelegate = OnButtonActionTriggered;
  282. SetActionCallback(m_LeftButtonAction, m_ButtonActionTriggeredDelegate, true);
  283. SetActionCallback(m_RightButtonAction, m_ButtonActionTriggeredDelegate, true);
  284. SetActionCallback(m_MiddleButtonAction, m_ButtonActionTriggeredDelegate, true);
  285. SetActionCallback(m_ForwardButtonAction, m_ButtonActionTriggeredDelegate, true);
  286. SetActionCallback(m_BackButtonAction, m_ButtonActionTriggeredDelegate, true);
  287. // Enable actions.
  288. m_StickAction.action?.Enable();
  289. m_LeftButtonAction.action?.Enable();
  290. m_RightButtonAction.action?.Enable();
  291. m_MiddleButtonAction.action?.Enable();
  292. m_ForwardButtonAction.action?.Enable();
  293. m_BackButtonAction.action?.Enable();
  294. m_ScrollWheelAction.action?.Enable();
  295. }
  296. protected void OnDisable()
  297. {
  298. // Remove mouse device.
  299. if (m_VirtualMouse != null && m_VirtualMouse.added)
  300. InputSystem.RemoveDevice(m_VirtualMouse);
  301. // Let go of system mouse.
  302. if (m_SystemMouse != null)
  303. {
  304. InputSystem.EnableDevice(m_SystemMouse);
  305. m_SystemMouse = null;
  306. }
  307. // Remove ourselves from input update.
  308. if (m_AfterInputUpdateDelegate != null)
  309. InputSystem.onAfterUpdate -= m_AfterInputUpdateDelegate;
  310. // Disable actions.
  311. m_StickAction.action?.Disable();
  312. m_LeftButtonAction.action?.Disable();
  313. m_RightButtonAction.action?.Disable();
  314. m_MiddleButtonAction.action?.Disable();
  315. m_ForwardButtonAction.action?.Disable();
  316. m_BackButtonAction.action?.Disable();
  317. m_ScrollWheelAction.action?.Disable();
  318. // Unhock from actions.
  319. if (m_ButtonActionTriggeredDelegate != null)
  320. {
  321. SetActionCallback(m_LeftButtonAction, m_ButtonActionTriggeredDelegate, false);
  322. SetActionCallback(m_RightButtonAction, m_ButtonActionTriggeredDelegate, false);
  323. SetActionCallback(m_MiddleButtonAction, m_ButtonActionTriggeredDelegate, false);
  324. SetActionCallback(m_ForwardButtonAction, m_ButtonActionTriggeredDelegate, false);
  325. SetActionCallback(m_BackButtonAction, m_ButtonActionTriggeredDelegate, false);
  326. }
  327. m_LastTime = default;
  328. m_LastStickValue = default;
  329. }
  330. private void TryFindCanvas()
  331. {
  332. m_Canvas = m_CursorGraphic?.GetComponentInParent<Canvas>();
  333. }
  334. private void TryEnableHardwareCursor()
  335. {
  336. var devices = InputSystem.devices;
  337. for (var i = 0; i < devices.Count; ++i)
  338. {
  339. var device = devices[i];
  340. if (device.native && device is Mouse mouse)
  341. {
  342. m_SystemMouse = mouse;
  343. break;
  344. }
  345. }
  346. if (m_SystemMouse == null)
  347. {
  348. if (m_CursorGraphic != null)
  349. m_CursorGraphic.enabled = true;
  350. return;
  351. }
  352. InputSystem.DisableDevice(m_SystemMouse);
  353. // Sync position.
  354. if (m_VirtualMouse != null)
  355. m_SystemMouse.WarpCursorPosition(m_VirtualMouse.position.value);
  356. // Turn off mouse cursor image.
  357. if (m_CursorGraphic != null)
  358. m_CursorGraphic.enabled = false;
  359. }
  360. private void UpdateMotion()
  361. {
  362. if (m_VirtualMouse == null)
  363. return;
  364. // Read current stick value.
  365. var stickAction = m_StickAction.action;
  366. if (stickAction == null)
  367. return;
  368. var stickValue = stickAction.ReadValue<Vector2>();
  369. if (Mathf.Approximately(0, stickValue.x) && Mathf.Approximately(0, stickValue.y))
  370. {
  371. // Motion has stopped.
  372. m_LastTime = default;
  373. m_LastStickValue = default;
  374. }
  375. else
  376. {
  377. var currentTime = InputState.currentTime;
  378. if (Mathf.Approximately(0, m_LastStickValue.x) && Mathf.Approximately(0, m_LastStickValue.y))
  379. {
  380. // Motion has started.
  381. m_LastTime = currentTime;
  382. }
  383. // Compute delta.
  384. var deltaTime = (float)(currentTime - m_LastTime);
  385. var delta = new Vector2(m_CursorSpeed * stickValue.x * deltaTime, m_CursorSpeed * stickValue.y * deltaTime);
  386. // Update position.
  387. var currentPosition = m_VirtualMouse.position.value;
  388. var newPosition = currentPosition + delta;
  389. ////REVIEW: for the hardware cursor, clamp to something else?
  390. // Clamp to canvas.
  391. if (m_Canvas != null)
  392. {
  393. // Clamp to canvas.
  394. var pixelRect = m_Canvas.pixelRect;
  395. newPosition.x = Mathf.Clamp(newPosition.x, pixelRect.xMin, pixelRect.xMax);
  396. newPosition.y = Mathf.Clamp(newPosition.y, pixelRect.yMin, pixelRect.yMax);
  397. }
  398. ////REVIEW: the fact we have no events on these means that actions won't have an event ID to go by; problem?
  399. InputState.Change(m_VirtualMouse.position, newPosition);
  400. InputState.Change(m_VirtualMouse.delta, delta);
  401. // Update software cursor transform, if any.
  402. if (m_CursorTransform != null &&
  403. (m_CursorMode == CursorMode.SoftwareCursor ||
  404. (m_CursorMode == CursorMode.HardwareCursorIfAvailable && m_SystemMouse == null)))
  405. m_CursorTransform.anchoredPosition = newPosition;
  406. m_LastStickValue = stickValue;
  407. m_LastTime = currentTime;
  408. // Update hardware cursor.
  409. m_SystemMouse?.WarpCursorPosition(newPosition);
  410. }
  411. // Update scroll wheel.
  412. var scrollAction = m_ScrollWheelAction.action;
  413. if (scrollAction != null)
  414. {
  415. var scrollValue = scrollAction.ReadValue<Vector2>();
  416. scrollValue.x *= m_ScrollSpeed;
  417. scrollValue.y *= m_ScrollSpeed;
  418. InputState.Change(m_VirtualMouse.scroll, scrollValue);
  419. }
  420. }
  421. [Header("Cursor")]
  422. [Tooltip("Whether the component should set the cursor position of the hardware mouse cursor, if one is available. If so, "
  423. + "the software cursor pointed (to by 'Cursor Graphic') will be hidden.")]
  424. [SerializeField] private CursorMode m_CursorMode;
  425. [Tooltip("The graphic that represents the software cursor. This is hidden if a hardware cursor (see 'Cursor Mode') is used.")]
  426. [SerializeField] private Graphic m_CursorGraphic;
  427. [Tooltip("The transform for the software cursor. Will only be set if a software cursor is used (see 'Cursor Mode'). Moving the cursor "
  428. + "updates the anchored position of the transform.")]
  429. [SerializeField] private RectTransform m_CursorTransform;
  430. [Header("Motion")]
  431. [Tooltip("Speed in pixels per second with which to move the cursor. Scaled by the input from 'Stick Action'.")]
  432. [SerializeField] private float m_CursorSpeed = 400;
  433. [Tooltip("Scale factor to apply to 'Scroll Wheel Action' when setting the mouse 'scrollWheel' control.")]
  434. [SerializeField] private float m_ScrollSpeed = 45;
  435. [Space(10)]
  436. [Tooltip("Vector2 action that moves the cursor left/right (X) and up/down (Y) on screen.")]
  437. [SerializeField] private InputActionProperty m_StickAction;
  438. [Tooltip("Button action that triggers a left-click on the mouse.")]
  439. [SerializeField] private InputActionProperty m_LeftButtonAction;
  440. [Tooltip("Button action that triggers a middle-click on the mouse.")]
  441. [SerializeField] private InputActionProperty m_MiddleButtonAction;
  442. [Tooltip("Button action that triggers a right-click on the mouse.")]
  443. [SerializeField] private InputActionProperty m_RightButtonAction;
  444. [Tooltip("Button action that triggers a forward button (button #4) click on the mouse.")]
  445. [SerializeField] private InputActionProperty m_ForwardButtonAction;
  446. [Tooltip("Button action that triggers a back button (button #5) click on the mouse.")]
  447. [SerializeField] private InputActionProperty m_BackButtonAction;
  448. [Tooltip("Vector2 action that feeds into the mouse 'scrollWheel' action (scaled by 'Scroll Speed').")]
  449. [SerializeField] private InputActionProperty m_ScrollWheelAction;
  450. private Canvas m_Canvas; // Canvas that gives the motion range for the software cursor.
  451. private Mouse m_VirtualMouse;
  452. private Mouse m_SystemMouse;
  453. private Action m_AfterInputUpdateDelegate;
  454. private Action<InputAction.CallbackContext> m_ButtonActionTriggeredDelegate;
  455. private double m_LastTime;
  456. private Vector2 m_LastStickValue;
  457. private void OnButtonActionTriggered(InputAction.CallbackContext context)
  458. {
  459. if (m_VirtualMouse == null)
  460. return;
  461. // The button controls are bit controls. We can't (yet?) use InputState.Change to state
  462. // the change of those controls as the state update machinery of InputManager only supports
  463. // byte region updates. So we just grab the full state of our virtual mouse, then update
  464. // the button in there and then simply overwrite the entire state.
  465. var action = context.action;
  466. MouseButton? button = null;
  467. if (action == m_LeftButtonAction.action)
  468. button = MouseButton.Left;
  469. else if (action == m_RightButtonAction.action)
  470. button = MouseButton.Right;
  471. else if (action == m_MiddleButtonAction.action)
  472. button = MouseButton.Middle;
  473. else if (action == m_ForwardButtonAction.action)
  474. button = MouseButton.Forward;
  475. else if (action == m_BackButtonAction.action)
  476. button = MouseButton.Back;
  477. if (button != null)
  478. {
  479. var isPressed = context.control.IsPressed();
  480. m_VirtualMouse.CopyState<MouseState>(out var mouseState);
  481. mouseState.WithButton(button.Value, isPressed);
  482. InputState.Change(m_VirtualMouse, mouseState);
  483. }
  484. }
  485. private static void SetActionCallback(InputActionProperty field, Action<InputAction.CallbackContext> callback, bool install = true)
  486. {
  487. var action = field.action;
  488. if (action == null)
  489. return;
  490. // We don't need the performed callback as our mouse buttons are binary and thus
  491. // we only care about started (1) and canceled (0).
  492. if (install)
  493. {
  494. action.started += callback;
  495. action.canceled += callback;
  496. }
  497. else
  498. {
  499. action.started -= callback;
  500. action.canceled -= callback;
  501. }
  502. }
  503. private static void SetAction(ref InputActionProperty field, InputActionProperty value)
  504. {
  505. var oldValue = field;
  506. field = value;
  507. if (oldValue.reference == null)
  508. {
  509. var oldAction = oldValue.action;
  510. if (oldAction != null && oldAction.enabled)
  511. {
  512. oldAction.Disable();
  513. if (value.reference == null)
  514. value.action?.Enable();
  515. }
  516. }
  517. }
  518. private void OnAfterInputUpdate()
  519. {
  520. UpdateMotion();
  521. }
  522. /// <summary>
  523. /// Determines how the cursor for the virtual mouse is represented.
  524. /// </summary>
  525. /// <seealso cref="cursorMode"/>
  526. public enum CursorMode
  527. {
  528. /// <summary>
  529. /// The cursor is represented as a UI element. See <see cref="cursorGraphic"/>.
  530. /// </summary>
  531. SoftwareCursor,
  532. /// <summary>
  533. /// If a native <see cref="Mouse"/> device is present, its cursor will be used and driven
  534. /// by the virtual mouse using <see cref="Mouse.WarpCursorPosition"/>. The software cursor
  535. /// referenced by <see cref="cursorGraphic"/> will be disabled.
  536. ///
  537. /// Note that if no native <see cref="Mouse"/> is present, behavior will fall back to
  538. /// <see cref="SoftwareCursor"/>.
  539. /// </summary>
  540. HardwareCursorIfAvailable,
  541. }
  542. }
  543. }
  544. #endif // PACKAGE_DOCS_GENERATION || UNITY_INPUT_SYSTEM_ENABLE_UI