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.

PointerInputModule.cs 16KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437
  1. using System.Collections.Generic;
  2. using System.Text;
  3. using UnityEngine.UI;
  4. namespace UnityEngine.EventSystems
  5. {
  6. /// <summary>
  7. /// A BaseInputModule for pointer input.
  8. /// </summary>
  9. public abstract class PointerInputModule : BaseInputModule
  10. {
  11. /// <summary>
  12. /// Id of the cached left mouse pointer event.
  13. /// </summary>
  14. public const int kMouseLeftId = -1;
  15. /// <summary>
  16. /// Id of the cached right mouse pointer event.
  17. /// </summary>
  18. public const int kMouseRightId = -2;
  19. /// <summary>
  20. /// Id of the cached middle mouse pointer event.
  21. /// </summary>
  22. public const int kMouseMiddleId = -3;
  23. /// <summary>
  24. /// Touch id for when simulating touches on a non touch device.
  25. /// </summary>
  26. public const int kFakeTouchesId = -4;
  27. protected Dictionary<int, PointerEventData> m_PointerData = new Dictionary<int, PointerEventData>();
  28. /// <summary>
  29. /// Search the cache for currently active pointers, return true if found.
  30. /// </summary>
  31. /// <param name="id">Touch ID</param>
  32. /// <param name="data">Found data</param>
  33. /// <param name="create">If not found should it be created</param>
  34. /// <returns>True if pointer is found.</returns>
  35. protected bool GetPointerData(int id, out PointerEventData data, bool create)
  36. {
  37. if (!m_PointerData.TryGetValue(id, out data) && create)
  38. {
  39. data = new PointerEventData(eventSystem)
  40. {
  41. pointerId = id,
  42. };
  43. m_PointerData.Add(id, data);
  44. return true;
  45. }
  46. return false;
  47. }
  48. /// <summary>
  49. /// Remove the PointerEventData from the cache.
  50. /// </summary>
  51. protected void RemovePointerData(PointerEventData data)
  52. {
  53. m_PointerData.Remove(data.pointerId);
  54. }
  55. /// <summary>
  56. /// Given a touch populate the PointerEventData and return if we are pressed or released.
  57. /// </summary>
  58. /// <param name="input">Touch being processed</param>
  59. /// <param name="pressed">Are we pressed this frame</param>
  60. /// <param name="released">Are we released this frame</param>
  61. /// <returns></returns>
  62. protected PointerEventData GetTouchPointerEventData(Touch input, out bool pressed, out bool released)
  63. {
  64. PointerEventData pointerData;
  65. var created = GetPointerData(input.fingerId, out pointerData, true);
  66. pointerData.Reset();
  67. pressed = created || (input.phase == TouchPhase.Began);
  68. released = (input.phase == TouchPhase.Canceled) || (input.phase == TouchPhase.Ended);
  69. if (created)
  70. pointerData.position = input.position;
  71. if (pressed)
  72. pointerData.delta = Vector2.zero;
  73. else
  74. pointerData.delta = input.position - pointerData.position;
  75. pointerData.position = input.position;
  76. pointerData.button = PointerEventData.InputButton.Left;
  77. if (input.phase == TouchPhase.Canceled)
  78. {
  79. pointerData.pointerCurrentRaycast = new RaycastResult();
  80. }
  81. else
  82. {
  83. eventSystem.RaycastAll(pointerData, m_RaycastResultCache);
  84. var raycast = FindFirstRaycast(m_RaycastResultCache);
  85. pointerData.pointerCurrentRaycast = raycast;
  86. m_RaycastResultCache.Clear();
  87. }
  88. pointerData.pressure = input.pressure;
  89. pointerData.altitudeAngle = input.altitudeAngle;
  90. pointerData.azimuthAngle = input.azimuthAngle;
  91. pointerData.radius = Vector2.one * input.radius;
  92. pointerData.radiusVariance = Vector2.one * input.radiusVariance;
  93. return pointerData;
  94. }
  95. /// <summary>
  96. /// Copy one PointerEventData to another.
  97. /// </summary>
  98. protected void CopyFromTo(PointerEventData @from, PointerEventData @to)
  99. {
  100. @to.position = @from.position;
  101. @to.delta = @from.delta;
  102. @to.scrollDelta = @from.scrollDelta;
  103. @to.pointerCurrentRaycast = @from.pointerCurrentRaycast;
  104. @to.pointerEnter = @from.pointerEnter;
  105. @to.pressure = @from.pressure;
  106. @to.tangentialPressure = @from.tangentialPressure;
  107. @to.altitudeAngle = @from.altitudeAngle;
  108. @to.azimuthAngle = @from.azimuthAngle;
  109. @to.twist = @from.twist;
  110. @to.radius = @from.radius;
  111. @to.radiusVariance = @from.radiusVariance;
  112. }
  113. /// <summary>
  114. /// Given a mouse button return the current state for the frame.
  115. /// </summary>
  116. /// <param name="buttonId">Mouse button ID</param>
  117. protected PointerEventData.FramePressState StateForMouseButton(int buttonId)
  118. {
  119. var pressed = input.GetMouseButtonDown(buttonId);
  120. var released = input.GetMouseButtonUp(buttonId);
  121. if (pressed && released)
  122. return PointerEventData.FramePressState.PressedAndReleased;
  123. if (pressed)
  124. return PointerEventData.FramePressState.Pressed;
  125. if (released)
  126. return PointerEventData.FramePressState.Released;
  127. return PointerEventData.FramePressState.NotChanged;
  128. }
  129. protected class ButtonState
  130. {
  131. private PointerEventData.InputButton m_Button = PointerEventData.InputButton.Left;
  132. public MouseButtonEventData eventData
  133. {
  134. get { return m_EventData; }
  135. set { m_EventData = value; }
  136. }
  137. public PointerEventData.InputButton button
  138. {
  139. get { return m_Button; }
  140. set { m_Button = value; }
  141. }
  142. private MouseButtonEventData m_EventData;
  143. }
  144. protected class MouseState
  145. {
  146. private List<ButtonState> m_TrackedButtons = new List<ButtonState>();
  147. public bool AnyPressesThisFrame()
  148. {
  149. var trackedButtonsCount = m_TrackedButtons.Count;
  150. for (int i = 0; i < trackedButtonsCount; i++)
  151. {
  152. if (m_TrackedButtons[i].eventData.PressedThisFrame())
  153. return true;
  154. }
  155. return false;
  156. }
  157. public bool AnyReleasesThisFrame()
  158. {
  159. var trackedButtonsCount = m_TrackedButtons.Count;
  160. for (int i = 0; i < trackedButtonsCount; i++)
  161. {
  162. if (m_TrackedButtons[i].eventData.ReleasedThisFrame())
  163. return true;
  164. }
  165. return false;
  166. }
  167. public ButtonState GetButtonState(PointerEventData.InputButton button)
  168. {
  169. ButtonState tracked = null;
  170. var trackedButtonsCount = m_TrackedButtons.Count;
  171. for (int i = 0; i < trackedButtonsCount; i++)
  172. {
  173. if (m_TrackedButtons[i].button == button)
  174. {
  175. tracked = m_TrackedButtons[i];
  176. break;
  177. }
  178. }
  179. if (tracked == null)
  180. {
  181. tracked = new ButtonState { button = button, eventData = new MouseButtonEventData() };
  182. m_TrackedButtons.Add(tracked);
  183. }
  184. return tracked;
  185. }
  186. public void SetButtonState(PointerEventData.InputButton button, PointerEventData.FramePressState stateForMouseButton, PointerEventData data)
  187. {
  188. var toModify = GetButtonState(button);
  189. toModify.eventData.buttonState = stateForMouseButton;
  190. toModify.eventData.buttonData = data;
  191. }
  192. }
  193. /// <summary>
  194. /// Information about a mouse button event.
  195. /// </summary>
  196. public class MouseButtonEventData
  197. {
  198. /// <summary>
  199. /// The state of the button this frame.
  200. /// </summary>
  201. public PointerEventData.FramePressState buttonState;
  202. /// <summary>
  203. /// Pointer data associated with the mouse event.
  204. /// </summary>
  205. public PointerEventData buttonData;
  206. /// <summary>
  207. /// Was the button pressed this frame?
  208. /// </summary>
  209. public bool PressedThisFrame()
  210. {
  211. return buttonState == PointerEventData.FramePressState.Pressed || buttonState == PointerEventData.FramePressState.PressedAndReleased;
  212. }
  213. /// <summary>
  214. /// Was the button released this frame?
  215. /// </summary>
  216. public bool ReleasedThisFrame()
  217. {
  218. return buttonState == PointerEventData.FramePressState.Released || buttonState == PointerEventData.FramePressState.PressedAndReleased;
  219. }
  220. }
  221. private readonly MouseState m_MouseState = new MouseState();
  222. /// <summary>
  223. /// Return the current MouseState. Using the default pointer.
  224. /// </summary>
  225. protected virtual MouseState GetMousePointerEventData()
  226. {
  227. return GetMousePointerEventData(0);
  228. }
  229. /// <summary>
  230. /// Return the current MouseState.
  231. /// </summary>
  232. protected virtual MouseState GetMousePointerEventData(int id)
  233. {
  234. // Populate the left button...
  235. PointerEventData leftData;
  236. var created = GetPointerData(kMouseLeftId, out leftData, true);
  237. leftData.Reset();
  238. if (created)
  239. leftData.position = input.mousePosition;
  240. Vector2 pos = input.mousePosition;
  241. if (Cursor.lockState == CursorLockMode.Locked)
  242. {
  243. // We don't want to do ANY cursor-based interaction when the mouse is locked
  244. leftData.position = new Vector2(-1.0f, -1.0f);
  245. leftData.delta = Vector2.zero;
  246. }
  247. else
  248. {
  249. leftData.delta = pos - leftData.position;
  250. leftData.position = pos;
  251. }
  252. leftData.scrollDelta = input.mouseScrollDelta;
  253. leftData.button = PointerEventData.InputButton.Left;
  254. eventSystem.RaycastAll(leftData, m_RaycastResultCache);
  255. var raycast = FindFirstRaycast(m_RaycastResultCache);
  256. leftData.pointerCurrentRaycast = raycast;
  257. m_RaycastResultCache.Clear();
  258. // copy the apropriate data into right and middle slots
  259. PointerEventData rightData;
  260. GetPointerData(kMouseRightId, out rightData, true);
  261. rightData.Reset();
  262. CopyFromTo(leftData, rightData);
  263. rightData.button = PointerEventData.InputButton.Right;
  264. PointerEventData middleData;
  265. GetPointerData(kMouseMiddleId, out middleData, true);
  266. middleData.Reset();
  267. CopyFromTo(leftData, middleData);
  268. middleData.button = PointerEventData.InputButton.Middle;
  269. m_MouseState.SetButtonState(PointerEventData.InputButton.Left, StateForMouseButton(0), leftData);
  270. m_MouseState.SetButtonState(PointerEventData.InputButton.Right, StateForMouseButton(1), rightData);
  271. m_MouseState.SetButtonState(PointerEventData.InputButton.Middle, StateForMouseButton(2), middleData);
  272. return m_MouseState;
  273. }
  274. /// <summary>
  275. /// Return the last PointerEventData for the given touch / mouse id.
  276. /// </summary>
  277. protected PointerEventData GetLastPointerEventData(int id)
  278. {
  279. PointerEventData data;
  280. GetPointerData(id, out data, false);
  281. return data;
  282. }
  283. private static bool ShouldStartDrag(Vector2 pressPos, Vector2 currentPos, float threshold, bool useDragThreshold)
  284. {
  285. if (!useDragThreshold)
  286. return true;
  287. return (pressPos - currentPos).sqrMagnitude >= threshold * threshold;
  288. }
  289. /// <summary>
  290. /// Process movement for the current frame with the given pointer event.
  291. /// </summary>
  292. protected virtual void ProcessMove(PointerEventData pointerEvent)
  293. {
  294. var targetGO = (Cursor.lockState == CursorLockMode.Locked ? null : pointerEvent.pointerCurrentRaycast.gameObject);
  295. HandlePointerExitAndEnter(pointerEvent, targetGO);
  296. }
  297. /// <summary>
  298. /// Process the drag for the current frame with the given pointer event.
  299. /// </summary>
  300. protected virtual void ProcessDrag(PointerEventData pointerEvent)
  301. {
  302. if (!pointerEvent.IsPointerMoving() ||
  303. Cursor.lockState == CursorLockMode.Locked ||
  304. pointerEvent.pointerDrag == null)
  305. return;
  306. if (!pointerEvent.dragging
  307. && ShouldStartDrag(pointerEvent.pressPosition, pointerEvent.position, eventSystem.pixelDragThreshold, pointerEvent.useDragThreshold))
  308. {
  309. ExecuteEvents.Execute(pointerEvent.pointerDrag, pointerEvent, ExecuteEvents.beginDragHandler);
  310. pointerEvent.dragging = true;
  311. }
  312. // Drag notification
  313. if (pointerEvent.dragging)
  314. {
  315. // Before doing drag we should cancel any pointer down state
  316. // And clear selection!
  317. if (pointerEvent.pointerPress != pointerEvent.pointerDrag)
  318. {
  319. ExecuteEvents.Execute(pointerEvent.pointerPress, pointerEvent, ExecuteEvents.pointerUpHandler);
  320. pointerEvent.eligibleForClick = false;
  321. pointerEvent.pointerPress = null;
  322. pointerEvent.rawPointerPress = null;
  323. }
  324. ExecuteEvents.Execute(pointerEvent.pointerDrag, pointerEvent, ExecuteEvents.dragHandler);
  325. }
  326. }
  327. public override bool IsPointerOverGameObject(int pointerId)
  328. {
  329. var lastPointer = GetLastPointerEventData(pointerId);
  330. if (lastPointer != null)
  331. return lastPointer.pointerEnter != null;
  332. return false;
  333. }
  334. /// <summary>
  335. /// Clear all pointers and deselect any selected objects in the EventSystem.
  336. /// </summary>
  337. protected void ClearSelection()
  338. {
  339. var baseEventData = GetBaseEventData();
  340. foreach (var pointer in m_PointerData.Values)
  341. {
  342. // clear all selection
  343. HandlePointerExitAndEnter(pointer, null);
  344. }
  345. m_PointerData.Clear();
  346. eventSystem.SetSelectedGameObject(null, baseEventData);
  347. }
  348. public override string ToString()
  349. {
  350. var sb = new StringBuilder("<b>Pointer Input Module of type: </b>" + GetType());
  351. sb.AppendLine();
  352. foreach (var pointer in m_PointerData)
  353. {
  354. if (pointer.Value == null)
  355. continue;
  356. sb.AppendLine("<B>Pointer:</b> " + pointer.Key);
  357. sb.AppendLine(pointer.Value.ToString());
  358. }
  359. return sb.ToString();
  360. }
  361. /// <summary>
  362. /// Deselect the current selected GameObject if the currently pointed-at GameObject is different.
  363. /// </summary>
  364. /// <param name="currentOverGo">The GameObject the pointer is currently over.</param>
  365. /// <param name="pointerEvent">Current event data.</param>
  366. protected void DeselectIfSelectionChanged(GameObject currentOverGo, BaseEventData pointerEvent)
  367. {
  368. // Selection tracking
  369. var selectHandlerGO = ExecuteEvents.GetEventHandler<ISelectHandler>(currentOverGo);
  370. // if we have clicked something new, deselect the old thing
  371. // leave 'selection handling' up to the press event though.
  372. if (selectHandlerGO != eventSystem.currentSelectedGameObject)
  373. eventSystem.SetSelectedGameObject(null, pointerEvent);
  374. }
  375. }
  376. }