]>
Commit | Line | Data |
---|---|---|
6d6f0db0 SR |
1 | /* |
2 | * noVNC: HTML5 VNC client | |
3 | * Copyright (C) 2012 Joel Martin | |
4 | * Licensed under MPL 2.0 (see LICENSE.txt) | |
5 | * | |
6 | * See README.md for usage and integration instructions. | |
7 | */ | |
8 | ||
9 | /* | |
10 | * Cross-browser event and position routines | |
11 | */ | |
12 | ||
6d6f0db0 SR |
13 | export function getPointerEvent (e) { |
14 | return e.changedTouches ? e.changedTouches[0] : e.touches ? e.touches[0] : e; | |
8727f598 | 15 | } |
6d6f0db0 SR |
16 | |
17 | export function stopEvent (e) { | |
18 | e.stopPropagation(); | |
19 | e.preventDefault(); | |
8727f598 | 20 | } |
6d6f0db0 SR |
21 | |
22 | // Emulate Element.setCapture() when not supported | |
23 | var _captureRecursion = false; | |
24 | var _captureElem = null; | |
858ea4a7 | 25 | function _captureProxy(e) { |
6d6f0db0 SR |
26 | // Recursion protection as we'll see our own event |
27 | if (_captureRecursion) return; | |
28 | ||
29 | // Clone the event as we cannot dispatch an already dispatched event | |
30 | var newEv = new e.constructor(e.type, e); | |
31 | ||
32 | _captureRecursion = true; | |
33 | _captureElem.dispatchEvent(newEv); | |
34 | _captureRecursion = false; | |
35 | ||
36 | // Avoid double events | |
37 | e.stopPropagation(); | |
38 | ||
39 | // Respect the wishes of the redirected event handlers | |
40 | if (newEv.defaultPrevented) { | |
41 | e.preventDefault(); | |
42 | } | |
43 | ||
44 | // Implicitly release the capture on button release | |
333ad45c | 45 | if (e.type === "mouseup") { |
6d6f0db0 SR |
46 | releaseCapture(); |
47 | } | |
8727f598 | 48 | } |
6d6f0db0 SR |
49 | |
50 | // Follow cursor style of target element | |
858ea4a7 | 51 | function _captureElemChanged() { |
6d6f0db0 SR |
52 | var captureElem = document.getElementById("noVNC_mouse_capture_elem"); |
53 | captureElem.style.cursor = window.getComputedStyle(_captureElem).cursor; | |
8727f598 | 54 | } |
858ea4a7 | 55 | var _captureObserver = new MutationObserver(_captureElemChanged); |
6d6f0db0 SR |
56 | |
57 | var _captureIndex = 0; | |
58 | ||
59 | export function setCapture (elem) { | |
60 | if (elem.setCapture) { | |
61 | ||
62 | elem.setCapture(); | |
63 | ||
64 | // IE releases capture on 'click' events which might not trigger | |
65 | elem.addEventListener('mouseup', releaseCapture); | |
6d6f0db0 SR |
66 | |
67 | } else { | |
68 | // Release any existing capture in case this method is | |
69 | // called multiple times without coordination | |
70 | releaseCapture(); | |
71 | ||
6d6f0db0 SR |
72 | var captureElem = document.getElementById("noVNC_mouse_capture_elem"); |
73 | ||
74 | if (captureElem === null) { | |
75 | captureElem = document.createElement("div"); | |
76 | captureElem.id = "noVNC_mouse_capture_elem"; | |
77 | captureElem.style.position = "fixed"; | |
78 | captureElem.style.top = "0px"; | |
79 | captureElem.style.left = "0px"; | |
80 | captureElem.style.width = "100%"; | |
81 | captureElem.style.height = "100%"; | |
82 | captureElem.style.zIndex = 10000; | |
83 | captureElem.style.display = "none"; | |
84 | document.body.appendChild(captureElem); | |
85 | ||
86 | // This is to make sure callers don't get confused by having | |
87 | // our blocking element as the target | |
88 | captureElem.addEventListener('contextmenu', _captureProxy); | |
89 | ||
90 | captureElem.addEventListener('mousemove', _captureProxy); | |
91 | captureElem.addEventListener('mouseup', _captureProxy); | |
6d6f0db0 SR |
92 | } |
93 | ||
94 | _captureElem = elem; | |
95 | _captureIndex++; | |
96 | ||
97 | // Track cursor and get initial cursor | |
98 | _captureObserver.observe(elem, {attributes:true}); | |
99 | _captureElemChanged(); | |
100 | ||
41c958d4 | 101 | captureElem.style.display = ""; |
6d6f0db0 SR |
102 | |
103 | // We listen to events on window in order to keep tracking if it | |
104 | // happens to leave the viewport | |
105 | window.addEventListener('mousemove', _captureProxy); | |
106 | window.addEventListener('mouseup', _captureProxy); | |
6d6f0db0 | 107 | } |
8727f598 | 108 | } |
6d6f0db0 SR |
109 | |
110 | export function releaseCapture () { | |
111 | if (document.releaseCapture) { | |
112 | ||
113 | document.releaseCapture(); | |
114 | ||
115 | } else { | |
116 | if (!_captureElem) { | |
117 | return; | |
118 | } | |
119 | ||
120 | // There might be events already queued, so we need to wait for | |
121 | // them to flush. E.g. contextmenu in Microsoft Edge | |
122 | window.setTimeout(function(expected) { | |
123 | // Only clear it if it's the expected grab (i.e. no one | |
124 | // else has initiated a new grab) | |
125 | if (_captureIndex === expected) { | |
126 | _captureElem = null; | |
127 | } | |
128 | }, 0, _captureIndex); | |
129 | ||
130 | _captureObserver.disconnect(); | |
131 | ||
132 | var captureElem = document.getElementById("noVNC_mouse_capture_elem"); | |
133 | captureElem.style.display = "none"; | |
134 | ||
135 | window.removeEventListener('mousemove', _captureProxy); | |
136 | window.removeEventListener('mouseup', _captureProxy); | |
6d6f0db0 | 137 | } |
8727f598 | 138 | } |