PointableCanvasModule.cs 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735
  1. using System.Collections.Generic;
  2. using UnityEngine.EventSystems;
  3. using UnityEngine;
  4. using UnityEngine.Assertions;
  5. using System;
  6. using UnityEngine.UI;
  7. namespace Rokid.UXR.Interaction
  8. {
  9. public class PointableCanvasEventArgs
  10. {
  11. public readonly Canvas Canvas;
  12. public readonly GameObject Hovered;
  13. public readonly bool Dragging;
  14. public PointableCanvasEventArgs(Canvas canvas, GameObject hovered, bool dragging)
  15. {
  16. Canvas = canvas;
  17. Hovered = hovered;
  18. Dragging = dragging;
  19. }
  20. }
  21. /// <summary>
  22. /// IPointerInteractableModule manages all InteractableCanvas events in
  23. /// the scene and translates them into pointer events for Unity Canvas UIs.
  24. /// </summary>
  25. public class PointableCanvasModule : PointerInputModule
  26. {
  27. public static event Action<PointableCanvasEventArgs> WhenSelected;
  28. public static event Action<PointableCanvasEventArgs> WhenUnselected;
  29. public static event Action<PointableCanvasEventArgs> WhenSelectableHovered;
  30. public static event Action<PointableCanvasEventArgs> WhenSelectableUnhovered;
  31. [SerializeField]
  32. private bool _useInitialPressPositionForDrag = true;
  33. private Camera _pointerEventCamera;
  34. private static PointableCanvasModule _instance = null;
  35. [SerializeField]
  36. private GameObject m_PreOverGo;
  37. [SerializeField]
  38. private Text eventLogText;
  39. private List<int> draggingPointerData = new List<int>();
  40. private static PointableCanvasModule Instance
  41. {
  42. get
  43. {
  44. if (_instance == null)
  45. {
  46. _instance = FindObjectOfType<PointableCanvasModule>();
  47. }
  48. return _instance;
  49. }
  50. }
  51. public static void RegisterPointableCanvas(IPointableCanvas pointerCanvas)
  52. {
  53. RKLog.Info($"====PointableCanvasModule====: +RegisterPointableCanvas");
  54. Assert.IsNotNull(Instance, "A PointableCanvasModule is required in the scene.");
  55. Instance.AddPointerCanvas(pointerCanvas);
  56. }
  57. public static void UnregisterPointableCanvas(IPointableCanvas pointerCanvas)
  58. {
  59. Instance?.RemovePointerCanvas(pointerCanvas);
  60. }
  61. private Dictionary<int, Pointer> _pointerMap = new Dictionary<int, Pointer>();
  62. private List<RaycastResult> _raycastResultCache = new List<RaycastResult>();
  63. private Dictionary<int, Pointer> _pointersForDeletion = new Dictionary<int, Pointer>();
  64. private Dictionary<IPointableCanvas, Action<PointerEvent>> _pointerCanvasActionMap =
  65. new Dictionary<IPointableCanvas, Action<PointerEvent>>();
  66. private void AddPointerCanvas(IPointableCanvas pointerCanvas)
  67. {
  68. //1.New A PoitnerToCanvasAction
  69. //2.Add PointerCanvasAction To Map
  70. //3.Regist PointerCanvasAction To pointerCanvas.WhenPointerEventRaised
  71. Action<PointerEvent> pointerCanvasAction = (args) =>
  72. {
  73. HandlePointerEvent(pointerCanvas.Canvas, args);
  74. };
  75. _pointerCanvasActionMap.Add(pointerCanvas, pointerCanvasAction);
  76. pointerCanvas.WhenPointerEventRaised += pointerCanvasAction;
  77. }
  78. private void RemovePointerCanvas(IPointableCanvas pointerCanvas)
  79. {
  80. RKLog.Info("====PointableCanvasModule==== : RemovePointerCanvas");
  81. Action<PointerEvent> pointerCanvasAction = _pointerCanvasActionMap[pointerCanvas];
  82. _pointerCanvasActionMap.Remove(pointerCanvas);
  83. pointerCanvas.WhenPointerEventRaised -= pointerCanvasAction;
  84. List<int> pointerIDs = new List<int>(_pointerMap.Keys);
  85. foreach (int pointerID in pointerIDs)
  86. {
  87. Pointer pointer = _pointerMap[pointerID];
  88. if (pointer.Canvas != pointerCanvas.Canvas)
  89. {
  90. continue;
  91. }
  92. ClearPointerSelection(pointer.PointerEventData);
  93. pointer.MarkForDeletion();
  94. _pointersForDeletion[pointerID] = pointer;
  95. }
  96. }
  97. private void HandlePointerEvent(Canvas canvas, PointerEvent evt)
  98. {
  99. Pointer pointer;
  100. switch (evt.Type)
  101. {
  102. case PointerEventType.Hover:
  103. pointer = new Pointer(canvas);
  104. pointer.PointerEventData = new PointerEventData(eventSystem);
  105. pointer.SetPosition(evt.Pose.position);
  106. _pointerMap.Add(evt.Identifier, pointer);
  107. // RKLog.Info($"====PointableCanvasModule====: Hover AddPointer:{evt.Identifier},{_pointerMap.Count}");
  108. pointer.PointerEventData.pointerId = evt.Identifier;
  109. if (!m_PointerData.ContainsKey(evt.Identifier))
  110. m_PointerData.Add(evt.Identifier, pointer.PointerEventData);
  111. RKPointerLisener.OnPointerEnter?.Invoke(pointer.PointerEventData);
  112. break;
  113. case PointerEventType.Unhover:
  114. if (_pointerMap.ContainsKey(evt.Identifier))
  115. {
  116. pointer = _pointerMap[evt.Identifier];
  117. _pointerMap.Remove(evt.Identifier);
  118. pointer.MarkForDeletion();
  119. _pointersForDeletion[evt.Identifier] = pointer;
  120. }
  121. break;
  122. case PointerEventType.Select:
  123. if (_pointerMap.ContainsKey(evt.Identifier))
  124. {
  125. pointer = _pointerMap[evt.Identifier];
  126. pointer.SetPosition(evt.Pose.position);
  127. pointer.Press();
  128. }
  129. break;
  130. case PointerEventType.Unselect:
  131. if (_pointerMap.ContainsKey(evt.Identifier))
  132. {
  133. pointer = _pointerMap[evt.Identifier];
  134. pointer.SetPosition(evt.Pose.position);
  135. pointer.Release();
  136. }
  137. break;
  138. case PointerEventType.Move:
  139. if (_pointerMap.ContainsKey(evt.Identifier))
  140. {
  141. pointer = _pointerMap[evt.Identifier];
  142. pointer.SetPosition(evt.Pose.position);
  143. // RKLog.Debug($"====PointableCanvasModule==== Move: {evt.Pose.position}");
  144. }
  145. break;
  146. case PointerEventType.Cancel:
  147. if (_pointerMap.ContainsKey(evt.Identifier))
  148. {
  149. pointer = _pointerMap[evt.Identifier];
  150. _pointerMap.Remove(evt.Identifier);
  151. ClearPointerSelection(pointer.PointerEventData);
  152. pointer.MarkForDeletion();
  153. _pointersForDeletion[evt.Identifier] = pointer;
  154. }
  155. break;
  156. }
  157. }
  158. /// <summary>
  159. /// Pointer class that is used for state associated with IPointables that are currently
  160. /// tracked by any IPointableCanvases in the scene.
  161. /// </summary>
  162. private class Pointer
  163. {
  164. public PointerEventData PointerEventData { get; set; }
  165. public bool MarkedForDeletion { get; private set; }
  166. private Canvas _canvas;
  167. public Canvas Canvas => _canvas;
  168. private Vector3 _position;
  169. public Vector3 Position => _position;
  170. private GameObject _hoveredSelectable;
  171. public GameObject HoveredSelectable => _hoveredSelectable;
  172. private bool _pressing = false;
  173. private bool _pressed;
  174. private bool _released;
  175. public Pointer(Canvas canvas)
  176. {
  177. _canvas = canvas;
  178. _pressed = _released = false;
  179. }
  180. public void Press()
  181. {
  182. if (_pressing) return;
  183. _pressing = true;
  184. _pressed = true;
  185. }
  186. public void Release()
  187. {
  188. if (!_pressing) return;
  189. _pressing = false;
  190. _released = true;
  191. }
  192. public void ReadAndResetPressedReleased(out bool pressed, out bool released)
  193. {
  194. pressed = _pressed;
  195. released = _released;
  196. _pressed = _released = false;
  197. }
  198. public void MarkForDeletion()
  199. {
  200. MarkedForDeletion = true;
  201. Release();
  202. }
  203. public void SetPosition(Vector3 position)
  204. {
  205. _position = position;
  206. }
  207. public void SetHoveredSelectable(GameObject hoveredSelectable)
  208. {
  209. _hoveredSelectable = hoveredSelectable;
  210. }
  211. }
  212. protected override void OnEnable()
  213. {
  214. base.OnEnable();
  215. if (_pointerEventCamera == null)
  216. {
  217. _pointerEventCamera = gameObject.AddComponent<Camera>();
  218. _pointerEventCamera.nearClipPlane = 0.1f;
  219. _pointerEventCamera.enabled = false;
  220. }
  221. RKPointerLisener.OnPointerDragBegin += OnPointerDragBegin;
  222. RKPointerLisener.OnPointerDragEnd += OnPointerDragEnd;
  223. }
  224. private void OnPointerDragBegin(PointerEventData eventData)
  225. {
  226. RKLog.KeyInfo($" ===PointableCanvas=== {eventData.pointerId} is begin dragging");
  227. draggingPointerData.Add(eventData.pointerId);
  228. }
  229. private void OnPointerDragEnd(PointerEventData eventData)
  230. {
  231. RKLog.KeyInfo($" ===PointableCanvas=== {eventData.pointerId} is end dragging");
  232. draggingPointerData.Remove(eventData.pointerId);
  233. }
  234. protected override void OnDisable()
  235. {
  236. ProcessOnDisable();
  237. Destroy(_pointerEventCamera);
  238. _pointerEventCamera = null;
  239. base.OnDisable();
  240. RKPointerLisener.OnPointerDragBegin -= OnPointerDragBegin;
  241. RKPointerLisener.OnPointerDragEnd -= OnPointerDragEnd;
  242. draggingPointerData.Clear();
  243. }
  244. // Based On FindFirstRaycast
  245. protected static RaycastResult FindFirstRaycastWithinCanvas(List<RaycastResult> candidates, Canvas canvas)
  246. {
  247. GameObject candidateGameObject;
  248. Canvas candidateCanvas;
  249. for (var i = 0; i < candidates.Count; ++i)
  250. {
  251. candidateGameObject = candidates[i].gameObject;
  252. if (candidateGameObject == null) continue;
  253. candidateCanvas = candidateGameObject.GetComponentInParent<Canvas>();
  254. if (candidateCanvas == null) continue;
  255. if (candidateCanvas.rootCanvas != canvas) continue;
  256. return candidates[i];
  257. }
  258. return new RaycastResult();
  259. }
  260. private void UpdateRaycasts(Pointer pointer, out bool pressed, out bool released)
  261. {
  262. if (_pointerEventCamera == null)
  263. {
  264. _pointerEventCamera = gameObject.AddComponent<Camera>();
  265. _pointerEventCamera.nearClipPlane = 0.1f;
  266. _pointerEventCamera.enabled = false;
  267. }
  268. PointerEventData pointerEventData = pointer.PointerEventData;
  269. Vector2 prevPosition = pointerEventData.position;
  270. Canvas canvas = pointer.Canvas;
  271. if (canvas == null)
  272. {
  273. pressed = false;
  274. released = true;
  275. return;
  276. }
  277. canvas.worldCamera = _pointerEventCamera;
  278. pointerEventData.Reset();
  279. pointer.ReadAndResetPressedReleased(out pressed, out released);
  280. //计算射线和平面的交点的关键计算逻辑,计算Pointer和Canvas的交点,position 为世界坐标
  281. Vector3 position = Vector3.zero;
  282. var plane = new Plane(-1f * canvas.transform.forward, canvas.transform.position);
  283. var ray = new Ray(pointer.Position - canvas.transform.forward, canvas.transform.forward);
  284. float enter;
  285. if (plane.Raycast(ray, out enter))
  286. {
  287. position = ray.GetPoint(enter);
  288. }
  289. // We need to position our camera at an offset from the Pointer position or else
  290. // a graphic raycast may ignore a world canvas that's outside of our regular camera view(s)
  291. // 我们需要将我们的相机定位在与指针位置的偏移处,否则图形光线投射可能会忽略我们常规相机视图之外的世界画布
  292. // 所以这里重新设置了事件相机的位置和朝向
  293. _pointerEventCamera.transform.position = pointer.Position - canvas.transform.forward;
  294. _pointerEventCamera.transform.LookAt(pointer.Position, canvas.transform.up);
  295. //pointerPosition 为screenPosition
  296. Vector2 pointerPosition = _pointerEventCamera.WorldToScreenPoint(position);
  297. pointerEventData.position = pointerPosition;
  298. // RaycastAll raycasts against with every GraphicRaycaster in the scene,
  299. // including nested ones like in the case of a dropdown
  300. eventSystem.RaycastAll(pointerEventData, _raycastResultCache);
  301. RaycastResult firstResult = FindFirstRaycastWithinCanvas(_raycastResultCache, canvas);
  302. pointer.PointerEventData.pointerCurrentRaycast = firstResult;
  303. _raycastResultCache.Clear();
  304. // We use a static translation offset from the canvas for 2D position delta tracking
  305. _pointerEventCamera.transform.position = canvas.transform.position - canvas.transform.forward;
  306. _pointerEventCamera.transform.LookAt(canvas.transform.position, canvas.transform.up);
  307. pointerPosition = _pointerEventCamera.WorldToScreenPoint(position);
  308. pointerEventData.position = pointerPosition;
  309. if (pressed)
  310. {
  311. pointerEventData.delta = Vector2.zero;
  312. }
  313. else
  314. {
  315. pointerEventData.delta = pointerEventData.position - prevPosition;
  316. }
  317. pointerEventData.button = PointerEventData.InputButton.Left;
  318. }
  319. public override void Process()
  320. {
  321. if (eventLogText != null)
  322. {
  323. eventLogText.text = "====PointableCanvasModule==== _pointerMap.Count:" + _pointerMap.Count;
  324. }
  325. foreach (KeyValuePair<int, Pointer> pair in _pointersForDeletion)
  326. {
  327. ProcessPointer(pair.Value, true);
  328. RKLog.Debug($"====PointableCanvasModule====: RemovePointer:{pair.Key}");
  329. _pointerMap.Remove(pair.Key);
  330. }
  331. _pointersForDeletion.Clear();
  332. foreach (Pointer pointer in _pointerMap.Values)
  333. {
  334. if (pointer.MarkedForDeletion)
  335. continue;
  336. ProcessPointer(pointer);
  337. }
  338. }
  339. private void ProcessOnDisable()
  340. {
  341. Process();
  342. foreach (var pointer in _pointerMap.Values)
  343. {
  344. RKLog.Debug($"====PointableCanvasModule==== : ProcessOnDisable HandlePointerExitAndEnter ");
  345. HandlePointerExitAndEnter(pointer.PointerEventData, null);
  346. RKPointerLisener.OnPointerExit?.Invoke(pointer.PointerEventData, null);
  347. }
  348. foreach (var pointer in _pointersForDeletion.Values)
  349. {
  350. RKLog.Debug($"====PointableCanvasModule==== : ProcessOnDisable HandlePointerExitAndEnter ");
  351. HandlePointerExitAndEnter(pointer.PointerEventData, null);
  352. RKPointerLisener.OnPointerExit?.Invoke(pointer.PointerEventData, null);
  353. }
  354. }
  355. private void ProcessPointer(Pointer pointer, bool forceRelease = false)
  356. {
  357. RKPointerLisener.OnPointerHover?.Invoke(pointer.PointerEventData);
  358. RKPointerLisener.OnGraphicPointerHover?.Invoke(pointer.PointerEventData);
  359. bool pressed = false;
  360. bool released = false;
  361. bool wasDragging = pointer.PointerEventData.dragging;
  362. UpdateRaycasts(pointer, out pressed, out released);
  363. PointerEventData pointerEventData = pointer.PointerEventData;
  364. if (InputModuleManager.Instance.GetButtonMouseActive())
  365. {
  366. pointerEventData.scrollDelta = ButtonMouseEventInput.Instance.GetMouseScrollDelta();
  367. }
  368. else
  369. {
  370. #if UNITY_EDITOR
  371. pointerEventData.scrollDelta = Input.mouseScrollDelta;
  372. #else
  373. if (InputModuleManager.Instance.GetMouseActive())
  374. {
  375. pointerEventData.scrollDelta = MouseEventInput.Instance.GetMouseScrollDelta();
  376. }
  377. #endif
  378. }
  379. // RKLog.Debug("====PointableCanvasModule==== ProcessPointer IScrollHandler " + pointerEventData.scrollDelta.sqrMagnitude);
  380. if (!Mathf.Approximately(pointerEventData.scrollDelta.sqrMagnitude, 0.0f))
  381. {
  382. var scrollHandler = ExecuteEvents.GetEventHandler<IScrollHandler>(pointerEventData.pointerCurrentRaycast.gameObject);
  383. ExecuteEvents.ExecuteHierarchy(scrollHandler, pointerEventData, ExecuteEvents.scrollHandler);
  384. }
  385. ProcessPress(pointerEventData, pressed, released);
  386. released |= forceRelease;
  387. if (!released)
  388. {
  389. // PointableCanvasModule Press
  390. if (!draggingPointerData.Contains(pointer.PointerEventData.pointerId))
  391. {
  392. ProcessMove(pointerEventData);
  393. }
  394. ProcessDrag(pointerEventData);
  395. }
  396. else
  397. {
  398. // PointableCanvasModule Release
  399. if (pointer.MarkedForDeletion)
  400. {
  401. HandlePointerExitAndEnter(pointerEventData, null);
  402. RKPointerLisener.OnPointerExit?.Invoke(pointerEventData, null);
  403. }
  404. RemovePointerData(pointerEventData);
  405. }
  406. HandleSelectableHover(pointer, wasDragging);
  407. HandleSelectablePress(pointer, pressed, released, wasDragging);
  408. }
  409. /// <summary>
  410. /// 处理可选物体的Hover问题
  411. /// </summary>
  412. /// <param name="pointer"></param>
  413. /// <param name="wasDragging"></param>
  414. private void HandleSelectableHover(Pointer pointer, bool wasDragging)
  415. {
  416. bool dragging = pointer.PointerEventData.dragging || wasDragging;
  417. GameObject currentOverGo = pointer.PointerEventData.pointerCurrentRaycast.gameObject;
  418. GameObject prevHoveredSelectable = pointer.HoveredSelectable;
  419. GameObject newHoveredSelectable = ExecuteEvents.GetEventHandler<ISelectHandler>(currentOverGo);
  420. pointer.SetHoveredSelectable(newHoveredSelectable);
  421. if (newHoveredSelectable != null && newHoveredSelectable != prevHoveredSelectable)
  422. {
  423. WhenSelectableHovered?.Invoke(new PointableCanvasEventArgs(pointer.Canvas, pointer.HoveredSelectable, dragging));
  424. }
  425. else if (prevHoveredSelectable != null && newHoveredSelectable == null)
  426. {
  427. WhenSelectableUnhovered?.Invoke(new PointableCanvasEventArgs(pointer.Canvas, pointer.HoveredSelectable, dragging));
  428. }
  429. }
  430. /// <summary>
  431. /// 处理可选物体的按压事件
  432. /// </summary>
  433. /// <param name="pointer"></param>
  434. /// <param name="pressed"></param>
  435. /// <param name="released"></param>
  436. /// <param name="wasDragging"></param>
  437. private void HandleSelectablePress(Pointer pointer, bool pressed, bool released, bool wasDragging)
  438. {
  439. bool dragging = pointer.PointerEventData.dragging || wasDragging;
  440. if (pressed)
  441. {
  442. WhenSelected?.Invoke(new PointableCanvasEventArgs(pointer.Canvas, pointer.HoveredSelectable, dragging));
  443. }
  444. else if (released && !pointer.MarkedForDeletion)
  445. {
  446. // Unity handles UI selection on release, so we verify the hovered element has been selected
  447. bool hasSelectedHoveredObject = pointer.HoveredSelectable != null &&
  448. pointer.HoveredSelectable == pointer.PointerEventData.selectedObject;
  449. GameObject selectedObject = hasSelectedHoveredObject ? pointer.HoveredSelectable : null;
  450. WhenUnselected?.Invoke(new PointableCanvasEventArgs(pointer.Canvas, selectedObject, dragging));
  451. }
  452. }
  453. /// <summary>
  454. /// This method is based on ProcessTouchPoint in StandaloneInputModule,
  455. /// but is instead used for Pointer events
  456. /// </summary>
  457. protected void ProcessPress(PointerEventData pointerEvent, bool pressed, bool released)
  458. {
  459. // RKLog.Info($"====PointableCanvasModule==== : ProcessPress {pressed},{released}");
  460. var currentOverGo = pointerEvent.pointerCurrentRaycast.gameObject;
  461. // PointerDown notification
  462. if (pressed)
  463. {
  464. pointerEvent.eligibleForClick = true;
  465. pointerEvent.delta = Vector2.zero;
  466. pointerEvent.dragging = false;
  467. pointerEvent.useDragThreshold = true;
  468. pointerEvent.pressPosition = pointerEvent.position;
  469. pointerEvent.pointerPressRaycast = pointerEvent.pointerCurrentRaycast;
  470. DeselectIfSelectionChanged(currentOverGo, pointerEvent);
  471. // if (pointerEvent.pointerEnter != currentOverGo)
  472. // {
  473. // // send a pointer enter to the touched element if it isn't the one to select...
  474. // HandlePointerExitAndEnter(pointerEvent, currentOverGo);
  475. // pointerEvent.pointerEnter = currentOverGo;
  476. // }
  477. // search for the control that will receive the press
  478. // if we can't find a press handler set the press
  479. // handler to be what would receive a click.
  480. var newPressed = ExecuteEvents.ExecuteHierarchy(currentOverGo, pointerEvent, ExecuteEvents.pointerDownHandler);
  481. RKLog.Debug($"====PointableCanvasModule====: Trigger RKPointerLisener.OnPointerDown {pointerEvent.pointerCurrentRaycast}");
  482. RKPointerLisener.OnPointerDown?.Invoke(pointerEvent);
  483. // didnt find a press handler... search for a click handler
  484. if (newPressed == null)
  485. newPressed = ExecuteEvents.GetEventHandler<IPointerClickHandler>(currentOverGo);
  486. float time = Time.unscaledTime;
  487. if (newPressed == pointerEvent.lastPress)
  488. {
  489. var diffTime = time - pointerEvent.clickTime;
  490. if (diffTime < 0.3f)
  491. ++pointerEvent.clickCount;
  492. else
  493. pointerEvent.clickCount = 1;
  494. pointerEvent.clickTime = time;
  495. }
  496. else
  497. {
  498. pointerEvent.clickCount = 1;
  499. }
  500. pointerEvent.pointerPress = newPressed;
  501. pointerEvent.rawPointerPress = currentOverGo;
  502. pointerEvent.clickTime = time;
  503. // Save the drag handler as well
  504. pointerEvent.pointerDrag = ExecuteEvents.GetEventHandler<IDragHandler>(currentOverGo);
  505. if (pointerEvent.pointerDrag != null)
  506. ExecuteEvents.Execute(pointerEvent.pointerDrag, pointerEvent, ExecuteEvents.initializePotentialDrag);
  507. }
  508. // PointerUp notification
  509. if (released)
  510. {
  511. ExecuteEvents.Execute(pointerEvent.pointerPress, pointerEvent, ExecuteEvents.pointerUpHandler);
  512. RKLog.Debug($"====PointableCanvasModule====: Trigger RKPointerLisener.OnPointerUp {pointerEvent.pointerCurrentRaycast}");
  513. RKPointerLisener.OnPointerUp?.Invoke(pointerEvent);
  514. // see if we mouse up on the same element that we clicked on...
  515. var pointerUpHandler = ExecuteEvents.GetEventHandler<IPointerClickHandler>(currentOverGo);
  516. // PointerClick and Drop events
  517. if (pointerEvent.pointerPress == pointerUpHandler && pointerEvent.eligibleForClick)
  518. {
  519. ExecuteEvents.Execute(pointerEvent.pointerPress, pointerEvent, ExecuteEvents.pointerClickHandler);
  520. }
  521. if (pointerEvent.pointerDrag != null && pointerEvent.dragging)
  522. {
  523. ExecuteEvents.ExecuteHierarchy(currentOverGo, pointerEvent, ExecuteEvents.dropHandler);
  524. }
  525. pointerEvent.eligibleForClick = false;
  526. pointerEvent.pointerPress = null;
  527. pointerEvent.rawPointerPress = null;
  528. if (pointerEvent.pointerDrag != null && pointerEvent.dragging)
  529. {
  530. ExecuteEvents.Execute(pointerEvent.pointerDrag, pointerEvent, ExecuteEvents.endDragHandler);
  531. RKPointerLisener.OnPointerDragEnd?.Invoke(pointerEvent);
  532. }
  533. pointerEvent.dragging = false;
  534. pointerEvent.pointerDrag = null;
  535. // send exit events as we need to simulate this on touch up on touch device
  536. // ExecuteEvents.ExecuteHierarchy(pointerEvent.pointerEnter, pointerEvent, ExecuteEvents.pointerExitHandler);
  537. // pointerEvent.pointerEnter = null;
  538. }
  539. }
  540. /// <summary>
  541. /// Override of PointerInputModule's ProcessDrag to allow using the initial press position for drag begin.
  542. /// Set _useInitialPressPositionForDrag to false if you prefer the default behaviour of PointerInputModule.
  543. /// </summary>
  544. protected override void ProcessDrag(PointerEventData pointerEvent)
  545. {
  546. if (!pointerEvent.IsPointerMoving() ||
  547. Cursor.lockState == CursorLockMode.Locked ||
  548. pointerEvent.pointerDrag == null)
  549. return;
  550. if (!pointerEvent.dragging
  551. && ShouldStartDrag(pointerEvent.pressPosition, pointerEvent.position,
  552. eventSystem.pixelDragThreshold, pointerEvent.useDragThreshold))
  553. {
  554. if (_useInitialPressPositionForDrag)
  555. {
  556. pointerEvent.position = pointerEvent.pressPosition;
  557. }
  558. ExecuteEvents.Execute(pointerEvent.pointerDrag, pointerEvent,
  559. ExecuteEvents.beginDragHandler);
  560. pointerEvent.dragging = true;
  561. RKLog.Debug($"====PointableCanvasModule==== : ProcessDrag");
  562. RKPointerLisener.OnPointerDragBegin?.Invoke(pointerEvent);
  563. }
  564. // Drag notification
  565. if (pointerEvent.dragging)
  566. {
  567. // Before doing drag we should cancel any pointer down state
  568. // And clear selection!
  569. if (pointerEvent.pointerPress != pointerEvent.pointerDrag)
  570. {
  571. ClearPointerSelection(pointerEvent);
  572. }
  573. ExecuteEvents.Execute(pointerEvent.pointerDrag, pointerEvent,
  574. ExecuteEvents.dragHandler);
  575. RKPointerLisener.OnPointerDrag?.Invoke(pointerEvent);
  576. }
  577. }
  578. private void ClearPointerSelection(PointerEventData pointerEvent)
  579. {
  580. ExecuteEvents.Execute(pointerEvent.pointerPress, pointerEvent,
  581. ExecuteEvents.pointerUpHandler);
  582. RKPointerLisener.OnPointerUp?.Invoke(pointerEvent);
  583. pointerEvent.eligibleForClick = false;
  584. pointerEvent.pointerPress = null;
  585. pointerEvent.rawPointerPress = null;
  586. }
  587. /// <summary>
  588. /// Used in PointerInputModule's ProcessDrag implementation. Brought into this subclass with a protected
  589. /// signature (as opposed to the parent's private signature) to be used in this subclass's overridden ProcessDrag.
  590. /// </summary>
  591. protected static bool ShouldStartDrag(Vector2 pressPos, Vector2 currentPos, float threshold, bool useDragThreshold)
  592. {
  593. if (!useDragThreshold)
  594. return true;
  595. return (pressPos - currentPos).sqrMagnitude >= threshold * threshold;
  596. }
  597. protected new void DeselectIfSelectionChanged(GameObject currentOverGo, BaseEventData pointerEvent)
  598. {
  599. // if currentOverGo has added the component "DontGetFocus", eventSystem.currentSelectedGameObject will not do "OnDeselect".
  600. // we need to add "DontGetFocus" to the virtual keyboard,or inputField's focus will become false when click virtual key.
  601. if (currentOverGo == null || (currentOverGo != null && IsComponentInParent<DontGetFocus>(currentOverGo)))
  602. {
  603. return;
  604. }
  605. // Selection tracking
  606. var selectHandlerGO = ExecuteEvents.GetEventHandler<ISelectHandler>(currentOverGo);
  607. // if we have clicked something new, deselect the old thing
  608. // leave 'selection handling' up to the press event though.
  609. if (selectHandlerGO != eventSystem.currentSelectedGameObject)
  610. eventSystem.SetSelectedGameObject(null, pointerEvent);
  611. }
  612. public static bool IsComponentInParent<T>(GameObject curGo) where T : MonoBehaviour
  613. {
  614. if (!curGo)
  615. {
  616. return false;
  617. }
  618. if (curGo.GetComponent<T>() != null)
  619. {
  620. return true;
  621. }
  622. if (curGo.transform.parent == null)
  623. {
  624. return false;
  625. }
  626. return IsComponentInParent<T>(curGo.transform.parent.gameObject);
  627. }
  628. }
  629. }