events.js 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  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 _captureElem = null;
  21. function _captureProxy(e) {
  22. // Recursion protection as we'll see our own event
  23. if (_captureRecursion) return;
  24. // Clone the event as we cannot dispatch an already dispatched event
  25. const newEv = new e.constructor(e.type, e);
  26. _captureRecursion = true;
  27. _captureElem.dispatchEvent(newEv);
  28. _captureRecursion = false;
  29. // Avoid double events
  30. e.stopPropagation();
  31. // Respect the wishes of the redirected event handlers
  32. if (newEv.defaultPrevented) {
  33. e.preventDefault();
  34. }
  35. // Implicitly release the capture on button release
  36. if (e.type === "mouseup") {
  37. releaseCapture();
  38. }
  39. }
  40. // Follow cursor style of target element
  41. function _captureElemChanged() {
  42. const captureElem = document.getElementById("noVNC_mouse_capture_elem");
  43. captureElem.style.cursor = window.getComputedStyle(_captureElem).cursor;
  44. }
  45. const _captureObserver = new MutationObserver(_captureElemChanged);
  46. let _captureIndex = 0;
  47. export function setCapture(elem) {
  48. if (elem.setCapture) {
  49. elem.setCapture();
  50. // IE releases capture on 'click' events which might not trigger
  51. elem.addEventListener('mouseup', releaseCapture);
  52. } else {
  53. // Release any existing capture in case this method is
  54. // called multiple times without coordination
  55. releaseCapture();
  56. let captureElem = document.getElementById("noVNC_mouse_capture_elem");
  57. if (captureElem === null) {
  58. captureElem = document.createElement("div");
  59. captureElem.id = "noVNC_mouse_capture_elem";
  60. captureElem.style.position = "fixed";
  61. captureElem.style.top = "0px";
  62. captureElem.style.left = "0px";
  63. captureElem.style.width = "100%";
  64. captureElem.style.height = "100%";
  65. captureElem.style.zIndex = 10000;
  66. captureElem.style.display = "none";
  67. document.body.appendChild(captureElem);
  68. // This is to make sure callers don't get confused by having
  69. // our blocking element as the target
  70. captureElem.addEventListener('contextmenu', _captureProxy);
  71. captureElem.addEventListener('mousemove', _captureProxy);
  72. captureElem.addEventListener('mouseup', _captureProxy);
  73. }
  74. _captureElem = elem;
  75. _captureIndex++;
  76. // Track cursor and get initial cursor
  77. _captureObserver.observe(elem, {attributes: true});
  78. _captureElemChanged();
  79. captureElem.style.display = "";
  80. // We listen to events on window in order to keep tracking if it
  81. // happens to leave the viewport
  82. window.addEventListener('mousemove', _captureProxy);
  83. window.addEventListener('mouseup', _captureProxy);
  84. }
  85. }
  86. export function releaseCapture() {
  87. if (document.releaseCapture) {
  88. document.releaseCapture();
  89. } else {
  90. if (!_captureElem) {
  91. return;
  92. }
  93. // There might be events already queued, so we need to wait for
  94. // them to flush. E.g. contextmenu in Microsoft Edge
  95. window.setTimeout((expected) => {
  96. // Only clear it if it's the expected grab (i.e. no one
  97. // else has initiated a new grab)
  98. if (_captureIndex === expected) {
  99. _captureElem = null;
  100. }
  101. }, 0, _captureIndex);
  102. _captureObserver.disconnect();
  103. const captureElem = document.getElementById("noVNC_mouse_capture_elem");
  104. captureElem.style.display = "none";
  105. window.removeEventListener('mousemove', _captureProxy);
  106. window.removeEventListener('mouseup', _captureProxy);
  107. }
  108. }