susi-qemu 0.0.3 → 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/susi +9 -4
- data/lib/disk.rb +7 -5
- data/lib/novnc/core/base64.js +104 -0
- data/lib/novnc/core/crypto/aes.js +178 -0
- data/lib/novnc/core/crypto/bigint.js +34 -0
- data/lib/novnc/core/crypto/crypto.js +90 -0
- data/lib/novnc/core/crypto/des.js +330 -0
- data/lib/novnc/core/crypto/dh.js +55 -0
- data/lib/novnc/core/crypto/md5.js +82 -0
- data/lib/novnc/core/crypto/rsa.js +132 -0
- data/lib/novnc/core/decoders/copyrect.js +27 -0
- data/lib/novnc/core/decoders/h264.js +321 -0
- data/lib/novnc/core/decoders/hextile.js +181 -0
- data/lib/novnc/core/decoders/jpeg.js +146 -0
- data/lib/novnc/core/decoders/raw.js +59 -0
- data/lib/novnc/core/decoders/rre.js +44 -0
- data/lib/novnc/core/decoders/tight.js +393 -0
- data/lib/novnc/core/decoders/tightpng.js +27 -0
- data/lib/novnc/core/decoders/zlib.js +51 -0
- data/lib/novnc/core/decoders/zrle.js +185 -0
- data/lib/novnc/core/deflator.js +84 -0
- data/lib/novnc/core/display.js +575 -0
- data/lib/novnc/core/encodings.js +53 -0
- data/lib/novnc/core/inflator.js +65 -0
- data/lib/novnc/core/input/domkeytable.js +311 -0
- data/lib/novnc/core/input/fixedkeys.js +129 -0
- data/lib/novnc/core/input/gesturehandler.js +567 -0
- data/lib/novnc/core/input/keyboard.js +294 -0
- data/lib/novnc/core/input/keysym.js +616 -0
- data/lib/novnc/core/input/keysymdef.js +688 -0
- data/lib/novnc/core/input/util.js +191 -0
- data/lib/novnc/core/input/vkeys.js +116 -0
- data/lib/novnc/core/input/xtscancodes.js +173 -0
- data/lib/novnc/core/ra2.js +312 -0
- data/lib/novnc/core/rfb.js +3257 -0
- data/lib/novnc/core/util/browser.js +172 -0
- data/lib/novnc/core/util/cursor.js +249 -0
- data/lib/novnc/core/util/element.js +32 -0
- data/lib/novnc/core/util/events.js +138 -0
- data/lib/novnc/core/util/eventtarget.js +35 -0
- data/lib/novnc/core/util/int.js +15 -0
- data/lib/novnc/core/util/logging.js +56 -0
- data/lib/novnc/core/util/strings.js +28 -0
- data/lib/novnc/core/websock.js +365 -0
- data/lib/novnc/screen.html +21 -0
- data/lib/novnc/vendor/pako/lib/utils/common.js +45 -0
- data/lib/novnc/vendor/pako/lib/zlib/adler32.js +27 -0
- data/lib/novnc/vendor/pako/lib/zlib/constants.js +47 -0
- data/lib/novnc/vendor/pako/lib/zlib/crc32.js +36 -0
- data/lib/novnc/vendor/pako/lib/zlib/deflate.js +1846 -0
- data/lib/novnc/vendor/pako/lib/zlib/gzheader.js +35 -0
- data/lib/novnc/vendor/pako/lib/zlib/inffast.js +324 -0
- data/lib/novnc/vendor/pako/lib/zlib/inflate.js +1527 -0
- data/lib/novnc/vendor/pako/lib/zlib/inftrees.js +322 -0
- data/lib/novnc/vendor/pako/lib/zlib/messages.js +11 -0
- data/lib/novnc/vendor/pako/lib/zlib/trees.js +1195 -0
- data/lib/novnc/vendor/pako/lib/zlib/zstream.js +24 -0
- data/lib/output.rb +11 -0
- data/lib/qmp.rb +6 -0
- data/lib/ssh.rb +3 -1
- data/lib/susi.rb +7 -6
- data/lib/version.rb +1 -1
- data/lib/vm.rb +36 -13
- data/lib/vnc.rb +34 -30
- metadata +57 -1
@@ -0,0 +1,172 @@
|
|
1
|
+
/*
|
2
|
+
* noVNC: HTML5 VNC client
|
3
|
+
* Copyright (C) 2019 The noVNC Authors
|
4
|
+
* Licensed under MPL 2.0 (see LICENSE.txt)
|
5
|
+
*
|
6
|
+
* See README.md for usage and integration instructions.
|
7
|
+
*
|
8
|
+
* Browser feature support detection
|
9
|
+
*/
|
10
|
+
|
11
|
+
import * as Log from './logging.js';
|
12
|
+
|
13
|
+
// Touch detection
|
14
|
+
export let isTouchDevice = ('ontouchstart' in document.documentElement) ||
|
15
|
+
// requried for Chrome debugger
|
16
|
+
(document.ontouchstart !== undefined) ||
|
17
|
+
// required for MS Surface
|
18
|
+
(navigator.maxTouchPoints > 0) ||
|
19
|
+
(navigator.msMaxTouchPoints > 0);
|
20
|
+
window.addEventListener('touchstart', function onFirstTouch() {
|
21
|
+
isTouchDevice = true;
|
22
|
+
window.removeEventListener('touchstart', onFirstTouch, false);
|
23
|
+
}, false);
|
24
|
+
|
25
|
+
|
26
|
+
// The goal is to find a certain physical width, the devicePixelRatio
|
27
|
+
// brings us a bit closer but is not optimal.
|
28
|
+
export let dragThreshold = 10 * (window.devicePixelRatio || 1);
|
29
|
+
|
30
|
+
let _supportsCursorURIs = false;
|
31
|
+
|
32
|
+
try {
|
33
|
+
const target = document.createElement('canvas');
|
34
|
+
target.style.cursor = 'url("data:image/x-icon;base64,AAACAAEACAgAAAIAAgA4AQAAFgAAACgAAAAIAAAAEAAAAAEAIAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////AAAAAAAAAAAAAAAAAAAAAA==") 2 2, default';
|
35
|
+
|
36
|
+
if (target.style.cursor.indexOf("url") === 0) {
|
37
|
+
Log.Info("Data URI scheme cursor supported");
|
38
|
+
_supportsCursorURIs = true;
|
39
|
+
} else {
|
40
|
+
Log.Warn("Data URI scheme cursor not supported");
|
41
|
+
}
|
42
|
+
} catch (exc) {
|
43
|
+
Log.Error("Data URI scheme cursor test exception: " + exc);
|
44
|
+
}
|
45
|
+
|
46
|
+
export const supportsCursorURIs = _supportsCursorURIs;
|
47
|
+
|
48
|
+
let _hasScrollbarGutter = true;
|
49
|
+
try {
|
50
|
+
// Create invisible container
|
51
|
+
const container = document.createElement('div');
|
52
|
+
container.style.visibility = 'hidden';
|
53
|
+
container.style.overflow = 'scroll'; // forcing scrollbars
|
54
|
+
document.body.appendChild(container);
|
55
|
+
|
56
|
+
// Create a div and place it in the container
|
57
|
+
const child = document.createElement('div');
|
58
|
+
container.appendChild(child);
|
59
|
+
|
60
|
+
// Calculate the difference between the container's full width
|
61
|
+
// and the child's width - the difference is the scrollbars
|
62
|
+
const scrollbarWidth = (container.offsetWidth - child.offsetWidth);
|
63
|
+
|
64
|
+
// Clean up
|
65
|
+
container.parentNode.removeChild(container);
|
66
|
+
|
67
|
+
_hasScrollbarGutter = scrollbarWidth != 0;
|
68
|
+
} catch (exc) {
|
69
|
+
Log.Error("Scrollbar test exception: " + exc);
|
70
|
+
}
|
71
|
+
export const hasScrollbarGutter = _hasScrollbarGutter;
|
72
|
+
|
73
|
+
export let supportsWebCodecsH264Decode = false;
|
74
|
+
|
75
|
+
async function _checkWebCodecsH264DecodeSupport() {
|
76
|
+
if (!('VideoDecoder' in window)) {
|
77
|
+
return;
|
78
|
+
}
|
79
|
+
|
80
|
+
// We'll need to make do with some placeholders here
|
81
|
+
const config = {
|
82
|
+
codec: 'avc1.42401f',
|
83
|
+
codedWidth: 1920,
|
84
|
+
codedHeight: 1080,
|
85
|
+
optimizeForLatency: true,
|
86
|
+
};
|
87
|
+
|
88
|
+
const result = await VideoDecoder.isConfigSupported(config);
|
89
|
+
supportsWebCodecsH264Decode = result.supported;
|
90
|
+
}
|
91
|
+
_checkWebCodecsH264DecodeSupport();
|
92
|
+
|
93
|
+
/*
|
94
|
+
* The functions for detection of platforms and browsers below are exported
|
95
|
+
* but the use of these should be minimized as much as possible.
|
96
|
+
*
|
97
|
+
* It's better to use feature detection than platform detection.
|
98
|
+
*/
|
99
|
+
|
100
|
+
/* OS */
|
101
|
+
|
102
|
+
export function isMac() {
|
103
|
+
return !!(/mac/i).exec(navigator.platform);
|
104
|
+
}
|
105
|
+
|
106
|
+
export function isWindows() {
|
107
|
+
return !!(/win/i).exec(navigator.platform);
|
108
|
+
}
|
109
|
+
|
110
|
+
export function isIOS() {
|
111
|
+
return (!!(/ipad/i).exec(navigator.platform) ||
|
112
|
+
!!(/iphone/i).exec(navigator.platform) ||
|
113
|
+
!!(/ipod/i).exec(navigator.platform));
|
114
|
+
}
|
115
|
+
|
116
|
+
export function isAndroid() {
|
117
|
+
/* Android sets navigator.platform to Linux :/ */
|
118
|
+
return !!navigator.userAgent.match('Android ');
|
119
|
+
}
|
120
|
+
|
121
|
+
export function isChromeOS() {
|
122
|
+
/* ChromeOS sets navigator.platform to Linux :/ */
|
123
|
+
return !!navigator.userAgent.match(' CrOS ');
|
124
|
+
}
|
125
|
+
|
126
|
+
/* Browser */
|
127
|
+
|
128
|
+
export function isSafari() {
|
129
|
+
return !!navigator.userAgent.match('Safari/...') &&
|
130
|
+
!navigator.userAgent.match('Chrome/...') &&
|
131
|
+
!navigator.userAgent.match('Chromium/...') &&
|
132
|
+
!navigator.userAgent.match('Epiphany/...');
|
133
|
+
}
|
134
|
+
|
135
|
+
export function isFirefox() {
|
136
|
+
return !!navigator.userAgent.match('Firefox/...') &&
|
137
|
+
!navigator.userAgent.match('Seamonkey/...');
|
138
|
+
}
|
139
|
+
|
140
|
+
export function isChrome() {
|
141
|
+
return !!navigator.userAgent.match('Chrome/...') &&
|
142
|
+
!navigator.userAgent.match('Chromium/...') &&
|
143
|
+
!navigator.userAgent.match('Edg/...') &&
|
144
|
+
!navigator.userAgent.match('OPR/...');
|
145
|
+
}
|
146
|
+
|
147
|
+
export function isChromium() {
|
148
|
+
return !!navigator.userAgent.match('Chromium/...');
|
149
|
+
}
|
150
|
+
|
151
|
+
export function isOpera() {
|
152
|
+
return !!navigator.userAgent.match('OPR/...');
|
153
|
+
}
|
154
|
+
|
155
|
+
export function isEdge() {
|
156
|
+
return !!navigator.userAgent.match('Edg/...');
|
157
|
+
}
|
158
|
+
|
159
|
+
/* Engine */
|
160
|
+
|
161
|
+
export function isGecko() {
|
162
|
+
return !!navigator.userAgent.match('Gecko/...');
|
163
|
+
}
|
164
|
+
|
165
|
+
export function isWebKit() {
|
166
|
+
return !!navigator.userAgent.match('AppleWebKit/...') &&
|
167
|
+
!navigator.userAgent.match('Chrome/...');
|
168
|
+
}
|
169
|
+
|
170
|
+
export function isBlink() {
|
171
|
+
return !!navigator.userAgent.match('Chrome/...');
|
172
|
+
}
|
@@ -0,0 +1,249 @@
|
|
1
|
+
/*
|
2
|
+
* noVNC: HTML5 VNC client
|
3
|
+
* Copyright (C) 2019 The noVNC Authors
|
4
|
+
* Licensed under MPL 2.0 or any later version (see LICENSE.txt)
|
5
|
+
*/
|
6
|
+
|
7
|
+
import { supportsCursorURIs, isTouchDevice } from './browser.js';
|
8
|
+
|
9
|
+
const useFallback = !supportsCursorURIs || isTouchDevice;
|
10
|
+
|
11
|
+
export default class Cursor {
|
12
|
+
constructor() {
|
13
|
+
this._target = null;
|
14
|
+
|
15
|
+
this._canvas = document.createElement('canvas');
|
16
|
+
|
17
|
+
if (useFallback) {
|
18
|
+
this._canvas.style.position = 'fixed';
|
19
|
+
this._canvas.style.zIndex = '65535';
|
20
|
+
this._canvas.style.pointerEvents = 'none';
|
21
|
+
// Safari on iOS can select the cursor image
|
22
|
+
// https://bugs.webkit.org/show_bug.cgi?id=249223
|
23
|
+
this._canvas.style.userSelect = 'none';
|
24
|
+
this._canvas.style.WebkitUserSelect = 'none';
|
25
|
+
// Can't use "display" because of Firefox bug #1445997
|
26
|
+
this._canvas.style.visibility = 'hidden';
|
27
|
+
}
|
28
|
+
|
29
|
+
this._position = { x: 0, y: 0 };
|
30
|
+
this._hotSpot = { x: 0, y: 0 };
|
31
|
+
|
32
|
+
this._eventHandlers = {
|
33
|
+
'mouseover': this._handleMouseOver.bind(this),
|
34
|
+
'mouseleave': this._handleMouseLeave.bind(this),
|
35
|
+
'mousemove': this._handleMouseMove.bind(this),
|
36
|
+
'mouseup': this._handleMouseUp.bind(this),
|
37
|
+
};
|
38
|
+
}
|
39
|
+
|
40
|
+
attach(target) {
|
41
|
+
if (this._target) {
|
42
|
+
this.detach();
|
43
|
+
}
|
44
|
+
|
45
|
+
this._target = target;
|
46
|
+
|
47
|
+
if (useFallback) {
|
48
|
+
document.body.appendChild(this._canvas);
|
49
|
+
|
50
|
+
const options = { capture: true, passive: true };
|
51
|
+
this._target.addEventListener('mouseover', this._eventHandlers.mouseover, options);
|
52
|
+
this._target.addEventListener('mouseleave', this._eventHandlers.mouseleave, options);
|
53
|
+
this._target.addEventListener('mousemove', this._eventHandlers.mousemove, options);
|
54
|
+
this._target.addEventListener('mouseup', this._eventHandlers.mouseup, options);
|
55
|
+
}
|
56
|
+
|
57
|
+
this.clear();
|
58
|
+
}
|
59
|
+
|
60
|
+
detach() {
|
61
|
+
if (!this._target) {
|
62
|
+
return;
|
63
|
+
}
|
64
|
+
|
65
|
+
if (useFallback) {
|
66
|
+
const options = { capture: true, passive: true };
|
67
|
+
this._target.removeEventListener('mouseover', this._eventHandlers.mouseover, options);
|
68
|
+
this._target.removeEventListener('mouseleave', this._eventHandlers.mouseleave, options);
|
69
|
+
this._target.removeEventListener('mousemove', this._eventHandlers.mousemove, options);
|
70
|
+
this._target.removeEventListener('mouseup', this._eventHandlers.mouseup, options);
|
71
|
+
|
72
|
+
if (document.contains(this._canvas)) {
|
73
|
+
document.body.removeChild(this._canvas);
|
74
|
+
}
|
75
|
+
}
|
76
|
+
|
77
|
+
this._target = null;
|
78
|
+
}
|
79
|
+
|
80
|
+
change(rgba, hotx, hoty, w, h) {
|
81
|
+
if ((w === 0) || (h === 0)) {
|
82
|
+
this.clear();
|
83
|
+
return;
|
84
|
+
}
|
85
|
+
|
86
|
+
this._position.x = this._position.x + this._hotSpot.x - hotx;
|
87
|
+
this._position.y = this._position.y + this._hotSpot.y - hoty;
|
88
|
+
this._hotSpot.x = hotx;
|
89
|
+
this._hotSpot.y = hoty;
|
90
|
+
|
91
|
+
let ctx = this._canvas.getContext('2d');
|
92
|
+
|
93
|
+
this._canvas.width = w;
|
94
|
+
this._canvas.height = h;
|
95
|
+
|
96
|
+
let img = new ImageData(new Uint8ClampedArray(rgba), w, h);
|
97
|
+
ctx.clearRect(0, 0, w, h);
|
98
|
+
ctx.putImageData(img, 0, 0);
|
99
|
+
|
100
|
+
if (useFallback) {
|
101
|
+
this._updatePosition();
|
102
|
+
} else {
|
103
|
+
let url = this._canvas.toDataURL();
|
104
|
+
this._target.style.cursor = 'url(' + url + ')' + hotx + ' ' + hoty + ', default';
|
105
|
+
}
|
106
|
+
}
|
107
|
+
|
108
|
+
clear() {
|
109
|
+
this._target.style.cursor = 'none';
|
110
|
+
this._canvas.width = 0;
|
111
|
+
this._canvas.height = 0;
|
112
|
+
this._position.x = this._position.x + this._hotSpot.x;
|
113
|
+
this._position.y = this._position.y + this._hotSpot.y;
|
114
|
+
this._hotSpot.x = 0;
|
115
|
+
this._hotSpot.y = 0;
|
116
|
+
}
|
117
|
+
|
118
|
+
// Mouse events might be emulated, this allows
|
119
|
+
// moving the cursor in such cases
|
120
|
+
move(clientX, clientY) {
|
121
|
+
if (!useFallback) {
|
122
|
+
return;
|
123
|
+
}
|
124
|
+
// clientX/clientY are relative the _visual viewport_,
|
125
|
+
// but our position is relative the _layout viewport_,
|
126
|
+
// so try to compensate when we can
|
127
|
+
if (window.visualViewport) {
|
128
|
+
this._position.x = clientX + window.visualViewport.offsetLeft;
|
129
|
+
this._position.y = clientY + window.visualViewport.offsetTop;
|
130
|
+
} else {
|
131
|
+
this._position.x = clientX;
|
132
|
+
this._position.y = clientY;
|
133
|
+
}
|
134
|
+
this._updatePosition();
|
135
|
+
let target = document.elementFromPoint(clientX, clientY);
|
136
|
+
this._updateVisibility(target);
|
137
|
+
}
|
138
|
+
|
139
|
+
_handleMouseOver(event) {
|
140
|
+
// This event could be because we're entering the target, or
|
141
|
+
// moving around amongst its sub elements. Let the move handler
|
142
|
+
// sort things out.
|
143
|
+
this._handleMouseMove(event);
|
144
|
+
}
|
145
|
+
|
146
|
+
_handleMouseLeave(event) {
|
147
|
+
// Check if we should show the cursor on the element we are leaving to
|
148
|
+
this._updateVisibility(event.relatedTarget);
|
149
|
+
}
|
150
|
+
|
151
|
+
_handleMouseMove(event) {
|
152
|
+
this._updateVisibility(event.target);
|
153
|
+
|
154
|
+
this._position.x = event.clientX - this._hotSpot.x;
|
155
|
+
this._position.y = event.clientY - this._hotSpot.y;
|
156
|
+
|
157
|
+
this._updatePosition();
|
158
|
+
}
|
159
|
+
|
160
|
+
_handleMouseUp(event) {
|
161
|
+
// We might get this event because of a drag operation that
|
162
|
+
// moved outside of the target. Check what's under the cursor
|
163
|
+
// now and adjust visibility based on that.
|
164
|
+
let target = document.elementFromPoint(event.clientX, event.clientY);
|
165
|
+
this._updateVisibility(target);
|
166
|
+
|
167
|
+
// Captures end with a mouseup but we can't know the event order of
|
168
|
+
// mouseup vs releaseCapture.
|
169
|
+
//
|
170
|
+
// In the cases when releaseCapture comes first, the code above is
|
171
|
+
// enough.
|
172
|
+
//
|
173
|
+
// In the cases when the mouseup comes first, we need wait for the
|
174
|
+
// browser to flush all events and then check again if the cursor
|
175
|
+
// should be visible.
|
176
|
+
if (this._captureIsActive()) {
|
177
|
+
window.setTimeout(() => {
|
178
|
+
// We might have detached at this point
|
179
|
+
if (!this._target) {
|
180
|
+
return;
|
181
|
+
}
|
182
|
+
// Refresh the target from elementFromPoint since queued events
|
183
|
+
// might have altered the DOM
|
184
|
+
target = document.elementFromPoint(event.clientX,
|
185
|
+
event.clientY);
|
186
|
+
this._updateVisibility(target);
|
187
|
+
}, 0);
|
188
|
+
}
|
189
|
+
}
|
190
|
+
|
191
|
+
_showCursor() {
|
192
|
+
if (this._canvas.style.visibility === 'hidden') {
|
193
|
+
this._canvas.style.visibility = '';
|
194
|
+
}
|
195
|
+
}
|
196
|
+
|
197
|
+
_hideCursor() {
|
198
|
+
if (this._canvas.style.visibility !== 'hidden') {
|
199
|
+
this._canvas.style.visibility = 'hidden';
|
200
|
+
}
|
201
|
+
}
|
202
|
+
|
203
|
+
// Should we currently display the cursor?
|
204
|
+
// (i.e. are we over the target, or a child of the target without a
|
205
|
+
// different cursor set)
|
206
|
+
_shouldShowCursor(target) {
|
207
|
+
if (!target) {
|
208
|
+
return false;
|
209
|
+
}
|
210
|
+
// Easy case
|
211
|
+
if (target === this._target) {
|
212
|
+
return true;
|
213
|
+
}
|
214
|
+
// Other part of the DOM?
|
215
|
+
if (!this._target.contains(target)) {
|
216
|
+
return false;
|
217
|
+
}
|
218
|
+
// Has the child its own cursor?
|
219
|
+
// FIXME: How can we tell that a sub element has an
|
220
|
+
// explicit "cursor: none;"?
|
221
|
+
if (window.getComputedStyle(target).cursor !== 'none') {
|
222
|
+
return false;
|
223
|
+
}
|
224
|
+
return true;
|
225
|
+
}
|
226
|
+
|
227
|
+
_updateVisibility(target) {
|
228
|
+
// When the cursor target has capture we want to show the cursor.
|
229
|
+
// So, if a capture is active - look at the captured element instead.
|
230
|
+
if (this._captureIsActive()) {
|
231
|
+
target = document.captureElement;
|
232
|
+
}
|
233
|
+
if (this._shouldShowCursor(target)) {
|
234
|
+
this._showCursor();
|
235
|
+
} else {
|
236
|
+
this._hideCursor();
|
237
|
+
}
|
238
|
+
}
|
239
|
+
|
240
|
+
_updatePosition() {
|
241
|
+
this._canvas.style.left = this._position.x + "px";
|
242
|
+
this._canvas.style.top = this._position.y + "px";
|
243
|
+
}
|
244
|
+
|
245
|
+
_captureIsActive() {
|
246
|
+
return document.captureElement &&
|
247
|
+
document.documentElement.contains(document.captureElement);
|
248
|
+
}
|
249
|
+
}
|
@@ -0,0 +1,32 @@
|
|
1
|
+
/*
|
2
|
+
* noVNC: HTML5 VNC client
|
3
|
+
* Copyright (C) 2020 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
|
+
/*
|
10
|
+
* HTML element utility functions
|
11
|
+
*/
|
12
|
+
|
13
|
+
export function clientToElement(x, y, elem) {
|
14
|
+
const bounds = elem.getBoundingClientRect();
|
15
|
+
let pos = { x: 0, y: 0 };
|
16
|
+
// Clip to target bounds
|
17
|
+
if (x < bounds.left) {
|
18
|
+
pos.x = 0;
|
19
|
+
} else if (x >= bounds.right) {
|
20
|
+
pos.x = bounds.width - 1;
|
21
|
+
} else {
|
22
|
+
pos.x = x - bounds.left;
|
23
|
+
}
|
24
|
+
if (y < bounds.top) {
|
25
|
+
pos.y = 0;
|
26
|
+
} else if (y >= bounds.bottom) {
|
27
|
+
pos.y = bounds.height - 1;
|
28
|
+
} else {
|
29
|
+
pos.y = y - bounds.top;
|
30
|
+
}
|
31
|
+
return pos;
|
32
|
+
}
|
@@ -0,0 +1,138 @@
|
|
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
|
+
/*
|
10
|
+
* Cross-browser event and position routines
|
11
|
+
*/
|
12
|
+
|
13
|
+
export function getPointerEvent(e) {
|
14
|
+
return e.changedTouches ? e.changedTouches[0] : e.touches ? e.touches[0] : e;
|
15
|
+
}
|
16
|
+
|
17
|
+
export function stopEvent(e) {
|
18
|
+
e.stopPropagation();
|
19
|
+
e.preventDefault();
|
20
|
+
}
|
21
|
+
|
22
|
+
// Emulate Element.setCapture() when not supported
|
23
|
+
let _captureRecursion = false;
|
24
|
+
let _elementForUnflushedEvents = null;
|
25
|
+
document.captureElement = null;
|
26
|
+
function _captureProxy(e) {
|
27
|
+
// Recursion protection as we'll see our own event
|
28
|
+
if (_captureRecursion) return;
|
29
|
+
|
30
|
+
// Clone the event as we cannot dispatch an already dispatched event
|
31
|
+
const newEv = new e.constructor(e.type, e);
|
32
|
+
|
33
|
+
_captureRecursion = true;
|
34
|
+
if (document.captureElement) {
|
35
|
+
document.captureElement.dispatchEvent(newEv);
|
36
|
+
} else {
|
37
|
+
_elementForUnflushedEvents.dispatchEvent(newEv);
|
38
|
+
}
|
39
|
+
_captureRecursion = false;
|
40
|
+
|
41
|
+
// Avoid double events
|
42
|
+
e.stopPropagation();
|
43
|
+
|
44
|
+
// Respect the wishes of the redirected event handlers
|
45
|
+
if (newEv.defaultPrevented) {
|
46
|
+
e.preventDefault();
|
47
|
+
}
|
48
|
+
|
49
|
+
// Implicitly release the capture on button release
|
50
|
+
if (e.type === "mouseup") {
|
51
|
+
releaseCapture();
|
52
|
+
}
|
53
|
+
}
|
54
|
+
|
55
|
+
// Follow cursor style of target element
|
56
|
+
function _capturedElemChanged() {
|
57
|
+
const proxyElem = document.getElementById("noVNC_mouse_capture_elem");
|
58
|
+
proxyElem.style.cursor = window.getComputedStyle(document.captureElement).cursor;
|
59
|
+
}
|
60
|
+
|
61
|
+
const _captureObserver = new MutationObserver(_capturedElemChanged);
|
62
|
+
|
63
|
+
export function setCapture(target) {
|
64
|
+
if (target.setCapture) {
|
65
|
+
|
66
|
+
target.setCapture();
|
67
|
+
document.captureElement = target;
|
68
|
+
} else {
|
69
|
+
// Release any existing capture in case this method is
|
70
|
+
// called multiple times without coordination
|
71
|
+
releaseCapture();
|
72
|
+
|
73
|
+
let proxyElem = document.getElementById("noVNC_mouse_capture_elem");
|
74
|
+
|
75
|
+
if (proxyElem === null) {
|
76
|
+
proxyElem = document.createElement("div");
|
77
|
+
proxyElem.id = "noVNC_mouse_capture_elem";
|
78
|
+
proxyElem.style.position = "fixed";
|
79
|
+
proxyElem.style.top = "0px";
|
80
|
+
proxyElem.style.left = "0px";
|
81
|
+
proxyElem.style.width = "100%";
|
82
|
+
proxyElem.style.height = "100%";
|
83
|
+
proxyElem.style.zIndex = 10000;
|
84
|
+
proxyElem.style.display = "none";
|
85
|
+
document.body.appendChild(proxyElem);
|
86
|
+
|
87
|
+
// This is to make sure callers don't get confused by having
|
88
|
+
// our blocking element as the target
|
89
|
+
proxyElem.addEventListener('contextmenu', _captureProxy);
|
90
|
+
|
91
|
+
proxyElem.addEventListener('mousemove', _captureProxy);
|
92
|
+
proxyElem.addEventListener('mouseup', _captureProxy);
|
93
|
+
}
|
94
|
+
|
95
|
+
document.captureElement = target;
|
96
|
+
|
97
|
+
// Track cursor and get initial cursor
|
98
|
+
_captureObserver.observe(target, {attributes: true});
|
99
|
+
_capturedElemChanged();
|
100
|
+
|
101
|
+
proxyElem.style.display = "";
|
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);
|
107
|
+
}
|
108
|
+
}
|
109
|
+
|
110
|
+
export function releaseCapture() {
|
111
|
+
if (document.releaseCapture) {
|
112
|
+
|
113
|
+
document.releaseCapture();
|
114
|
+
document.captureElement = null;
|
115
|
+
|
116
|
+
} else {
|
117
|
+
if (!document.captureElement) {
|
118
|
+
return;
|
119
|
+
}
|
120
|
+
|
121
|
+
// There might be events already queued. The event proxy needs
|
122
|
+
// access to the captured element for these queued events.
|
123
|
+
// E.g. contextmenu (right-click) in Microsoft Edge
|
124
|
+
//
|
125
|
+
// Before removing the capturedElem pointer we save it to a
|
126
|
+
// temporary variable that the unflushed events can use.
|
127
|
+
_elementForUnflushedEvents = document.captureElement;
|
128
|
+
document.captureElement = null;
|
129
|
+
|
130
|
+
_captureObserver.disconnect();
|
131
|
+
|
132
|
+
const proxyElem = document.getElementById("noVNC_mouse_capture_elem");
|
133
|
+
proxyElem.style.display = "none";
|
134
|
+
|
135
|
+
window.removeEventListener('mousemove', _captureProxy);
|
136
|
+
window.removeEventListener('mouseup', _captureProxy);
|
137
|
+
}
|
138
|
+
}
|
@@ -0,0 +1,35 @@
|
|
1
|
+
/*
|
2
|
+
* noVNC: HTML5 VNC client
|
3
|
+
* Copyright (C) 2019 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
|
+
export default class EventTargetMixin {
|
10
|
+
constructor() {
|
11
|
+
this._listeners = new Map();
|
12
|
+
}
|
13
|
+
|
14
|
+
addEventListener(type, callback) {
|
15
|
+
if (!this._listeners.has(type)) {
|
16
|
+
this._listeners.set(type, new Set());
|
17
|
+
}
|
18
|
+
this._listeners.get(type).add(callback);
|
19
|
+
}
|
20
|
+
|
21
|
+
removeEventListener(type, callback) {
|
22
|
+
if (this._listeners.has(type)) {
|
23
|
+
this._listeners.get(type).delete(callback);
|
24
|
+
}
|
25
|
+
}
|
26
|
+
|
27
|
+
dispatchEvent(event) {
|
28
|
+
if (!this._listeners.has(event.type)) {
|
29
|
+
return true;
|
30
|
+
}
|
31
|
+
this._listeners.get(event.type)
|
32
|
+
.forEach(callback => callback.call(this, event));
|
33
|
+
return !event.defaultPrevented;
|
34
|
+
}
|
35
|
+
}
|
@@ -0,0 +1,15 @@
|
|
1
|
+
/*
|
2
|
+
* noVNC: HTML5 VNC client
|
3
|
+
* Copyright (C) 2020 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
|
+
export function toUnsigned32bit(toConvert) {
|
10
|
+
return toConvert >>> 0;
|
11
|
+
}
|
12
|
+
|
13
|
+
export function toSigned32bit(toConvert) {
|
14
|
+
return toConvert | 0;
|
15
|
+
}
|
@@ -0,0 +1,56 @@
|
|
1
|
+
/*
|
2
|
+
* noVNC: HTML5 VNC client
|
3
|
+
* Copyright (C) 2019 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
|
+
/*
|
10
|
+
* Logging/debug routines
|
11
|
+
*/
|
12
|
+
|
13
|
+
let _logLevel = 'warn';
|
14
|
+
|
15
|
+
let Debug = () => {};
|
16
|
+
let Info = () => {};
|
17
|
+
let Warn = () => {};
|
18
|
+
let Error = () => {};
|
19
|
+
|
20
|
+
export function initLogging(level) {
|
21
|
+
if (typeof level === 'undefined') {
|
22
|
+
level = _logLevel;
|
23
|
+
} else {
|
24
|
+
_logLevel = level;
|
25
|
+
}
|
26
|
+
|
27
|
+
Debug = Info = Warn = Error = () => {};
|
28
|
+
|
29
|
+
if (typeof window.console !== "undefined") {
|
30
|
+
/* eslint-disable no-console, no-fallthrough */
|
31
|
+
switch (level) {
|
32
|
+
case 'debug':
|
33
|
+
Debug = console.debug.bind(window.console);
|
34
|
+
case 'info':
|
35
|
+
Info = console.info.bind(window.console);
|
36
|
+
case 'warn':
|
37
|
+
Warn = console.warn.bind(window.console);
|
38
|
+
case 'error':
|
39
|
+
Error = console.error.bind(window.console);
|
40
|
+
case 'none':
|
41
|
+
break;
|
42
|
+
default:
|
43
|
+
throw new window.Error("invalid logging type '" + level + "'");
|
44
|
+
}
|
45
|
+
/* eslint-enable no-console, no-fallthrough */
|
46
|
+
}
|
47
|
+
}
|
48
|
+
|
49
|
+
export function getLogging() {
|
50
|
+
return _logLevel;
|
51
|
+
}
|
52
|
+
|
53
|
+
export { Debug, Info, Warn, Error };
|
54
|
+
|
55
|
+
// Initialize logging level
|
56
|
+
initLogging();
|