events.js 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. /*
  2. * noVNC: HTML5 VNC client
  3. * Copyright (C) 2018 The noVNC Authors
  4. * Licensed under MPL 2.0 (see LICENSE.txt)
  5. *
  6. * See README.md for usage and integration instructions.
  7. */
  8. /*
  9. * Cross-browser event and position routines
  10. */
  11. export function getPointerEvent(e) {
  12. return e.changedTouches ? e.changedTouches[0] : e.touches ? e.touches[0] : e;
  13. }
  14. export function stopEvent(e) {
  15. e.stopPropagation();
  16. e.preventDefault();
  17. }
  18. // Emulate Element.setCapture() when not supported
  19. let _captureRecursion = false;
  20. let _elementForUnflushedEvents = null;
  21. document.captureElement = null;
  22. function _captureProxy(e) {
  23. // Recursion protection as we'll see our own event
  24. if (_captureRecursion) return;
  25. // Clone the event as we cannot dispatch an already dispatched event
  26. const newEv = new e.constructor(e.type, e);
  27. _captureRecursion = true;
  28. if (document.captureElement) {
  29. document.captureElement.dispatchEvent(newEv);
  30. } else {
  31. _elementForUnflushedEvents.dispatchEvent(newEv);
  32. }
  33. _captureRecursion = false;
  34. // Avoid double events
  35. e.stopPropagation();
  36. // Respect the wishes of the redirected event handlers
  37. if (newEv.defaultPrevented) {
  38. e.preventDefault();
  39. }
  40. // Implicitly release the capture on button release
  41. if (e.type === "mouseup") {
  42. releaseCapture();
  43. }
  44. }
  45. // Follow cursor style of target element
  46. function _capturedElemChanged() {
  47. const proxyElem = document.getElementById("noVNC_mouse_capture_elem");
  48. proxyElem.style.cursor = window.getComputedStyle(document.captureElement).cursor;
  49. }
  50. const _captureObserver = new MutationObserver(_capturedElemChanged);
  51. export function setCapture(target) {
  52. if (target.setCapture) {
  53. target.setCapture();
  54. document.captureElement = target;
  55. } else {
  56. // Release any existing capture in case this method is
  57. // called multiple times without coordination
  58. releaseCapture();
  59. let proxyElem = document.getElementById("noVNC_mouse_capture_elem");
  60. if (proxyElem === null) {
  61. proxyElem = document.createElement("div");
  62. proxyElem.id = "noVNC_mouse_capture_elem";
  63. proxyElem.style.position = "fixed";
  64. proxyElem.style.top = "0px";
  65. proxyElem.style.left = "0px";
  66. proxyElem.style.width = "100%";
  67. proxyElem.style.height = "100%";
  68. proxyElem.style.zIndex = 10000;
  69. proxyElem.style.display = "none";
  70. document.body.appendChild(proxyElem);
  71. // This is to make sure callers don't get confused by having
  72. // our blocking element as the target
  73. proxyElem.addEventListener('contextmenu', _captureProxy);
  74. proxyElem.addEventListener('mousemove', _captureProxy);
  75. proxyElem.addEventListener('mouseup', _captureProxy);
  76. }
  77. document.captureElement = target;
  78. // Track cursor and get initial cursor
  79. _captureObserver.observe(target, {attributes: true});
  80. _capturedElemChanged();
  81. proxyElem.style.display = "";
  82. // We listen to events on window in order to keep tracking if it
  83. // happens to leave the viewport
  84. window.addEventListener('mousemove', _captureProxy);
  85. window.addEventListener('mouseup', _captureProxy);
  86. }
  87. }
  88. export function releaseCapture() {
  89. if (document.releaseCapture) {
  90. document.releaseCapture();
  91. document.captureElement = null;
  92. } else {
  93. if (!document.captureElement) {
  94. return;
  95. }
  96. // There might be events already queued. The event proxy needs
  97. // access to the captured element for these queued events.
  98. // E.g. contextmenu (right-click) in Microsoft Edge
  99. //
  100. // Before removing the capturedElem pointer we save it to a
  101. // temporary variable that the unflushed events can use.
  102. _elementForUnflushedEvents = document.captureElement;
  103. document.captureElement = null;
  104. _captureObserver.disconnect();
  105. const proxyElem = document.getElementById("noVNC_mouse_capture_elem");
  106. proxyElem.style.display = "none";
  107. window.removeEventListener('mousemove', _captureProxy);
  108. window.removeEventListener('mouseup', _captureProxy);
  109. }
  110. }