@novnc/novnc 1.0.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AUTHORS +13 -0
- package/LICENSE.txt +2 -1
- package/README.md +69 -3
- package/core/base64.js +35 -41
- package/core/decoders/copyrect.js +22 -0
- package/core/decoders/hextile.js +137 -0
- package/core/decoders/raw.js +56 -0
- package/core/decoders/rre.js +44 -0
- package/core/decoders/tight.js +315 -0
- package/core/decoders/tightpng.js +27 -0
- package/core/deflator.js +85 -0
- package/core/des.js +90 -95
- package/core/display.js +254 -297
- package/core/encodings.js +7 -3
- package/core/inflator.js +48 -20
- package/core/input/domkeytable.js +21 -24
- package/core/input/fixedkeys.js +3 -1
- package/core/input/gesturehandler.js +567 -0
- package/core/input/keyboard.js +194 -120
- package/core/input/keysym.js +2 -0
- package/core/input/keysymdef.js +3 -3
- package/core/input/util.js +53 -12
- package/core/input/vkeys.js +2 -1
- package/core/rfb.js +1937 -1496
- package/core/util/browser.js +80 -29
- package/core/util/cursor.js +253 -0
- package/core/util/element.js +32 -0
- package/core/util/events.js +59 -55
- package/core/util/eventtarget.js +25 -30
- package/core/util/int.js +15 -0
- package/core/util/logging.js +21 -16
- package/core/util/polyfill.js +15 -8
- package/core/util/strings.js +21 -8
- package/core/websock.js +145 -167
- package/docs/API.md +31 -10
- package/lib/base64.js +115 -0
- package/lib/decoders/copyrect.js +44 -0
- package/lib/decoders/hextile.js +173 -0
- package/lib/decoders/raw.js +78 -0
- package/lib/decoders/rre.js +65 -0
- package/lib/decoders/tight.js +350 -0
- package/lib/decoders/tightpng.js +67 -0
- package/lib/deflator.js +99 -0
- package/lib/des.js +314 -0
- package/lib/display.js +733 -0
- package/lib/encodings.js +64 -0
- package/lib/inflator.js +87 -0
- package/lib/input/domkeytable.js +282 -0
- package/lib/input/fixedkeys.js +123 -0
- package/lib/input/gesturehandler.js +642 -0
- package/lib/input/keyboard.js +429 -0
- package/lib/input/keysym.js +1135 -0
- package/lib/input/keysymdef.js +1354 -0
- package/lib/input/util.js +304 -0
- package/lib/input/vkeys.js +127 -0
- package/lib/input/xtscancodes.js +505 -0
- package/lib/rfb.js +3448 -0
- package/lib/util/browser.js +131 -0
- package/lib/util/cursor.js +314 -0
- package/lib/util/element.js +43 -0
- package/lib/util/events.js +142 -0
- package/lib/util/eventtarget.js +64 -0
- package/lib/util/int.js +22 -0
- package/lib/util/logging.js +79 -0
- package/lib/util/polyfill.js +72 -0
- package/lib/util/strings.js +38 -0
- package/lib/vendor/pako/lib/utils/common.js +67 -0
- package/lib/vendor/pako/lib/zlib/adler32.js +33 -0
- package/lib/vendor/pako/lib/zlib/constants.js +51 -0
- package/lib/vendor/pako/lib/zlib/crc32.js +42 -0
- package/lib/vendor/pako/lib/zlib/deflate.js +2159 -0
- package/lib/vendor/pako/lib/zlib/gzheader.js +53 -0
- package/lib/vendor/pako/lib/zlib/inffast.js +445 -0
- package/lib/vendor/pako/lib/zlib/inflate.js +2114 -0
- package/lib/vendor/pako/lib/zlib/inftrees.js +418 -0
- package/lib/vendor/pako/lib/zlib/messages.js +36 -0
- package/lib/vendor/pako/lib/zlib/trees.js +1499 -0
- package/lib/vendor/pako/lib/zlib/zstream.js +46 -0
- package/lib/vendor/promise.js +255 -0
- package/lib/websock.js +374 -0
- package/package.json +48 -28
- package/vendor/pako/lib/zlib/deflate.js +30 -30
- package/vendor/pako/lib/zlib/inflate.js +17 -17
- package/core/input/mouse.js +0 -280
- package/docs/API-internal.md +0 -125
- package/docs/EMBEDDING.md +0 -83
- package/docs/VERSION +0 -1
package/core/input/keyboard.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* noVNC: HTML5 VNC client
|
|
3
|
-
* Copyright (C)
|
|
4
|
-
* Copyright (C) 2013 Samuel Mannehed for Cendio AB
|
|
3
|
+
* Copyright (C) 2019 The noVNC Authors
|
|
5
4
|
* Licensed under MPL 2.0 or any later version (see LICENSE.txt)
|
|
6
5
|
*/
|
|
7
6
|
|
|
@@ -15,63 +14,49 @@ import * as browser from "../util/browser.js";
|
|
|
15
14
|
// Keyboard event handler
|
|
16
15
|
//
|
|
17
16
|
|
|
18
|
-
export default
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
17
|
+
export default class Keyboard {
|
|
18
|
+
constructor(target) {
|
|
19
|
+
this._target = target || null;
|
|
20
|
+
|
|
21
|
+
this._keyDownList = {}; // List of depressed keys
|
|
22
|
+
// (even if they are happy)
|
|
23
|
+
this._pendingKey = null; // Key waiting for keypress
|
|
24
|
+
this._altGrArmed = false; // Windows AltGr detection
|
|
25
|
+
|
|
26
|
+
// keep these here so we can refer to them later
|
|
27
|
+
this._eventHandlers = {
|
|
28
|
+
'keyup': this._handleKeyUp.bind(this),
|
|
29
|
+
'keydown': this._handleKeyDown.bind(this),
|
|
30
|
+
'keypress': this._handleKeyPress.bind(this),
|
|
31
|
+
'blur': this._allKeysUp.bind(this),
|
|
32
|
+
'checkalt': this._checkAlt.bind(this),
|
|
33
|
+
};
|
|
33
34
|
|
|
34
|
-
|
|
35
|
-
// ===== EVENT HANDLERS =====
|
|
35
|
+
// ===== EVENT HANDLERS =====
|
|
36
36
|
|
|
37
|
-
|
|
37
|
+
this.onkeyevent = () => {}; // Handler for key press/release
|
|
38
|
+
}
|
|
38
39
|
|
|
39
40
|
// ===== PRIVATE METHODS =====
|
|
40
41
|
|
|
41
|
-
_sendKeyEvent
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
// there is a way to detect AltGraph properly.
|
|
49
|
-
var fakeAltGraph = false;
|
|
50
|
-
if (down && browser.isWindows()) {
|
|
51
|
-
if ((code !== 'ControlLeft') &&
|
|
52
|
-
(code !== 'AltRight') &&
|
|
53
|
-
('ControlLeft' in this._keyDownList) &&
|
|
54
|
-
('AltRight' in this._keyDownList)) {
|
|
55
|
-
fakeAltGraph = true;
|
|
56
|
-
this.onkeyevent(this._keyDownList['AltRight'],
|
|
57
|
-
'AltRight', false);
|
|
58
|
-
this.onkeyevent(this._keyDownList['ControlLeft'],
|
|
59
|
-
'ControlLeft', false);
|
|
42
|
+
_sendKeyEvent(keysym, code, down) {
|
|
43
|
+
if (down) {
|
|
44
|
+
this._keyDownList[code] = keysym;
|
|
45
|
+
} else {
|
|
46
|
+
// Do we really think this key is down?
|
|
47
|
+
if (!(code in this._keyDownList)) {
|
|
48
|
+
return;
|
|
60
49
|
}
|
|
50
|
+
delete this._keyDownList[code];
|
|
61
51
|
}
|
|
62
52
|
|
|
53
|
+
Log.Debug("onkeyevent " + (down ? "down" : "up") +
|
|
54
|
+
", keysym: " + keysym, ", code: " + code);
|
|
63
55
|
this.onkeyevent(keysym, code, down);
|
|
56
|
+
}
|
|
64
57
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
'ControlLeft', true);
|
|
68
|
-
this.onkeyevent(this._keyDownList['AltRight'],
|
|
69
|
-
'AltRight', true);
|
|
70
|
-
}
|
|
71
|
-
},
|
|
72
|
-
|
|
73
|
-
_getKeyCode: function (e) {
|
|
74
|
-
var code = KeyboardUtil.getKeycode(e);
|
|
58
|
+
_getKeyCode(e) {
|
|
59
|
+
const code = KeyboardUtil.getKeycode(e);
|
|
75
60
|
if (code !== 'Unidentified') {
|
|
76
61
|
return code;
|
|
77
62
|
}
|
|
@@ -94,26 +79,46 @@ Keyboard.prototype = {
|
|
|
94
79
|
return e.keyIdentifier;
|
|
95
80
|
}
|
|
96
81
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
// Some implementations fail to uppercase the symbols
|
|
100
|
-
char = char.toUpperCase();
|
|
82
|
+
const codepoint = parseInt(e.keyIdentifier.substr(2), 16);
|
|
83
|
+
const char = String.fromCharCode(codepoint).toUpperCase();
|
|
101
84
|
|
|
102
85
|
return 'Platform' + char.charCodeAt();
|
|
103
86
|
}
|
|
104
87
|
|
|
105
88
|
return 'Unidentified';
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
_handleKeyDown
|
|
109
|
-
|
|
110
|
-
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
_handleKeyDown(e) {
|
|
92
|
+
const code = this._getKeyCode(e);
|
|
93
|
+
let keysym = KeyboardUtil.getKeysym(e);
|
|
94
|
+
|
|
95
|
+
// Windows doesn't have a proper AltGr, but handles it using
|
|
96
|
+
// fake Ctrl+Alt. However the remote end might not be Windows,
|
|
97
|
+
// so we need to merge those in to a single AltGr event. We
|
|
98
|
+
// detect this case by seeing the two key events directly after
|
|
99
|
+
// each other with a very short time between them (<50ms).
|
|
100
|
+
if (this._altGrArmed) {
|
|
101
|
+
this._altGrArmed = false;
|
|
102
|
+
clearTimeout(this._altGrTimeout);
|
|
103
|
+
|
|
104
|
+
if ((code === "AltRight") &&
|
|
105
|
+
((e.timeStamp - this._altGrCtrlTime) < 50)) {
|
|
106
|
+
// FIXME: We fail to detect this if either Ctrl key is
|
|
107
|
+
// first manually pressed as Windows then no
|
|
108
|
+
// longer sends the fake Ctrl down event. It
|
|
109
|
+
// does however happily send real Ctrl events
|
|
110
|
+
// even when AltGr is already down. Some
|
|
111
|
+
// browsers detect this for us though and set the
|
|
112
|
+
// key to "AltGraph".
|
|
113
|
+
keysym = KeyTable.XK_ISO_Level3_Shift;
|
|
114
|
+
} else {
|
|
115
|
+
this._sendKeyEvent(KeyTable.XK_Control_L, "ControlLeft", true);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
111
118
|
|
|
112
119
|
// We cannot handle keys we cannot track, but we also need
|
|
113
120
|
// to deal with virtual keyboards which omit key info
|
|
114
|
-
|
|
115
|
-
// special treat that platform here)
|
|
116
|
-
if ((code === 'Unidentified') || browser.isIOS()) {
|
|
121
|
+
if (code === 'Unidentified') {
|
|
117
122
|
if (keysym) {
|
|
118
123
|
// If it's a virtual keyboard then it should be
|
|
119
124
|
// sufficient to just send press and release right
|
|
@@ -130,20 +135,20 @@ Keyboard.prototype = {
|
|
|
130
135
|
// keys around a bit to make things more sane for the remote
|
|
131
136
|
// server. This method is used by RealVNC and TigerVNC (and
|
|
132
137
|
// possibly others).
|
|
133
|
-
if (browser.isMac()) {
|
|
138
|
+
if (browser.isMac() || browser.isIOS()) {
|
|
134
139
|
switch (keysym) {
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
140
|
+
case KeyTable.XK_Super_L:
|
|
141
|
+
keysym = KeyTable.XK_Alt_L;
|
|
142
|
+
break;
|
|
143
|
+
case KeyTable.XK_Super_R:
|
|
144
|
+
keysym = KeyTable.XK_Super_L;
|
|
145
|
+
break;
|
|
146
|
+
case KeyTable.XK_Alt_L:
|
|
147
|
+
keysym = KeyTable.XK_Mode_switch;
|
|
148
|
+
break;
|
|
149
|
+
case KeyTable.XK_Alt_R:
|
|
150
|
+
keysym = KeyTable.XK_ISO_Level3_Shift;
|
|
151
|
+
break;
|
|
147
152
|
}
|
|
148
153
|
}
|
|
149
154
|
|
|
@@ -157,7 +162,7 @@ Keyboard.prototype = {
|
|
|
157
162
|
// state change events. That gets extra confusing for CapsLock
|
|
158
163
|
// which toggles on each press, but not on release. So pretend
|
|
159
164
|
// it was a quick press and release of the button.
|
|
160
|
-
if (browser.isMac() && (code === 'CapsLock')) {
|
|
165
|
+
if ((browser.isMac() || browser.isIOS()) && (code === 'CapsLock')) {
|
|
161
166
|
this._sendKeyEvent(KeyTable.XK_Caps_Lock, 'CapsLock', true);
|
|
162
167
|
this._sendKeyEvent(KeyTable.XK_Caps_Lock, 'CapsLock', false);
|
|
163
168
|
stopEvent(e);
|
|
@@ -180,13 +185,20 @@ Keyboard.prototype = {
|
|
|
180
185
|
this._pendingKey = null;
|
|
181
186
|
stopEvent(e);
|
|
182
187
|
|
|
183
|
-
|
|
188
|
+
// Possible start of AltGr sequence? (see above)
|
|
189
|
+
if ((code === "ControlLeft") && browser.isWindows() &&
|
|
190
|
+
!("ControlLeft" in this._keyDownList)) {
|
|
191
|
+
this._altGrArmed = true;
|
|
192
|
+
this._altGrTimeout = setTimeout(this._handleAltGrTimeout.bind(this), 100);
|
|
193
|
+
this._altGrCtrlTime = e.timeStamp;
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
184
196
|
|
|
185
197
|
this._sendKeyEvent(keysym, code, true);
|
|
186
|
-
}
|
|
198
|
+
}
|
|
187
199
|
|
|
188
200
|
// Legacy event for browsers without code/key
|
|
189
|
-
_handleKeyPress
|
|
201
|
+
_handleKeyPress(e) {
|
|
190
202
|
stopEvent(e);
|
|
191
203
|
|
|
192
204
|
// Are we expecting a keypress?
|
|
@@ -194,8 +206,8 @@ Keyboard.prototype = {
|
|
|
194
206
|
return;
|
|
195
207
|
}
|
|
196
208
|
|
|
197
|
-
|
|
198
|
-
|
|
209
|
+
let code = this._getKeyCode(e);
|
|
210
|
+
const keysym = KeyboardUtil.getKeysym(e);
|
|
199
211
|
|
|
200
212
|
// The key we were waiting for?
|
|
201
213
|
if ((code !== 'Unidentified') && (code != this._pendingKey)) {
|
|
@@ -210,19 +222,18 @@ Keyboard.prototype = {
|
|
|
210
222
|
return;
|
|
211
223
|
}
|
|
212
224
|
|
|
213
|
-
this._keyDownList[code] = keysym;
|
|
214
|
-
|
|
215
225
|
this._sendKeyEvent(keysym, code, true);
|
|
216
|
-
}
|
|
217
|
-
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
_handleKeyPressTimeout(e) {
|
|
218
229
|
// Did someone manage to sort out the key already?
|
|
219
230
|
if (this._pendingKey === null) {
|
|
220
231
|
return;
|
|
221
232
|
}
|
|
222
233
|
|
|
223
|
-
|
|
234
|
+
let keysym;
|
|
224
235
|
|
|
225
|
-
code = this._pendingKey;
|
|
236
|
+
const code = this._pendingKey;
|
|
226
237
|
this._pendingKey = null;
|
|
227
238
|
|
|
228
239
|
// We have no way of knowing the proper keysym with the
|
|
@@ -233,82 +244,145 @@ Keyboard.prototype = {
|
|
|
233
244
|
keysym = e.keyCode;
|
|
234
245
|
} else if ((e.keyCode >= 0x41) && (e.keyCode <= 0x5a)) {
|
|
235
246
|
// Character (A-Z)
|
|
236
|
-
|
|
247
|
+
let char = String.fromCharCode(e.keyCode);
|
|
237
248
|
// A feeble attempt at the correct case
|
|
238
|
-
if (e.shiftKey)
|
|
249
|
+
if (e.shiftKey) {
|
|
239
250
|
char = char.toUpperCase();
|
|
240
|
-
else
|
|
251
|
+
} else {
|
|
241
252
|
char = char.toLowerCase();
|
|
253
|
+
}
|
|
242
254
|
keysym = char.charCodeAt();
|
|
243
255
|
} else {
|
|
244
256
|
// Unknown, give up
|
|
245
257
|
keysym = 0;
|
|
246
258
|
}
|
|
247
259
|
|
|
248
|
-
this._keyDownList[code] = keysym;
|
|
249
|
-
|
|
250
260
|
this._sendKeyEvent(keysym, code, true);
|
|
251
|
-
}
|
|
261
|
+
}
|
|
252
262
|
|
|
253
|
-
_handleKeyUp
|
|
263
|
+
_handleKeyUp(e) {
|
|
254
264
|
stopEvent(e);
|
|
255
265
|
|
|
256
|
-
|
|
266
|
+
const code = this._getKeyCode(e);
|
|
267
|
+
|
|
268
|
+
// We can't get a release in the middle of an AltGr sequence, so
|
|
269
|
+
// abort that detection
|
|
270
|
+
if (this._altGrArmed) {
|
|
271
|
+
this._altGrArmed = false;
|
|
272
|
+
clearTimeout(this._altGrTimeout);
|
|
273
|
+
this._sendKeyEvent(KeyTable.XK_Control_L, "ControlLeft", true);
|
|
274
|
+
}
|
|
257
275
|
|
|
258
276
|
// See comment in _handleKeyDown()
|
|
259
|
-
if (browser.isMac() && (code === 'CapsLock')) {
|
|
277
|
+
if ((browser.isMac() || browser.isIOS()) && (code === 'CapsLock')) {
|
|
260
278
|
this._sendKeyEvent(KeyTable.XK_Caps_Lock, 'CapsLock', true);
|
|
261
279
|
this._sendKeyEvent(KeyTable.XK_Caps_Lock, 'CapsLock', false);
|
|
262
280
|
return;
|
|
263
281
|
}
|
|
264
282
|
|
|
265
|
-
// Do we really think this key is down?
|
|
266
|
-
if (!(code in this._keyDownList)) {
|
|
267
|
-
return;
|
|
268
|
-
}
|
|
269
|
-
|
|
270
283
|
this._sendKeyEvent(this._keyDownList[code], code, false);
|
|
271
284
|
|
|
272
|
-
|
|
273
|
-
|
|
285
|
+
// Windows has a rather nasty bug where it won't send key
|
|
286
|
+
// release events for a Shift button if the other Shift is still
|
|
287
|
+
// pressed
|
|
288
|
+
if (browser.isWindows() && ((code === 'ShiftLeft') ||
|
|
289
|
+
(code === 'ShiftRight'))) {
|
|
290
|
+
if ('ShiftRight' in this._keyDownList) {
|
|
291
|
+
this._sendKeyEvent(this._keyDownList['ShiftRight'],
|
|
292
|
+
'ShiftRight', false);
|
|
293
|
+
}
|
|
294
|
+
if ('ShiftLeft' in this._keyDownList) {
|
|
295
|
+
this._sendKeyEvent(this._keyDownList['ShiftLeft'],
|
|
296
|
+
'ShiftLeft', false);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
_handleAltGrTimeout() {
|
|
302
|
+
this._altGrArmed = false;
|
|
303
|
+
clearTimeout(this._altGrTimeout);
|
|
304
|
+
this._sendKeyEvent(KeyTable.XK_Control_L, "ControlLeft", true);
|
|
305
|
+
}
|
|
274
306
|
|
|
275
|
-
_allKeysUp
|
|
307
|
+
_allKeysUp() {
|
|
276
308
|
Log.Debug(">> Keyboard.allKeysUp");
|
|
277
|
-
for (
|
|
309
|
+
for (let code in this._keyDownList) {
|
|
278
310
|
this._sendKeyEvent(this._keyDownList[code], code, false);
|
|
279
|
-
}
|
|
280
|
-
this._keyDownList = {};
|
|
311
|
+
}
|
|
281
312
|
Log.Debug("<< Keyboard.allKeysUp");
|
|
282
|
-
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
// Alt workaround for Firefox on Windows, see below
|
|
316
|
+
_checkAlt(e) {
|
|
317
|
+
if (e.skipCheckAlt) {
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
if (e.altKey) {
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
const target = this._target;
|
|
325
|
+
const downList = this._keyDownList;
|
|
326
|
+
['AltLeft', 'AltRight'].forEach((code) => {
|
|
327
|
+
if (!(code in downList)) {
|
|
328
|
+
return;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
const event = new KeyboardEvent('keyup',
|
|
332
|
+
{ key: downList[code],
|
|
333
|
+
code: code });
|
|
334
|
+
event.skipCheckAlt = true;
|
|
335
|
+
target.dispatchEvent(event);
|
|
336
|
+
});
|
|
337
|
+
}
|
|
283
338
|
|
|
284
339
|
// ===== PUBLIC METHODS =====
|
|
285
340
|
|
|
286
|
-
grab
|
|
341
|
+
grab() {
|
|
287
342
|
//Log.Debug(">> Keyboard.grab");
|
|
288
|
-
var c = this._target;
|
|
289
343
|
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
344
|
+
this._target.addEventListener('keydown', this._eventHandlers.keydown);
|
|
345
|
+
this._target.addEventListener('keyup', this._eventHandlers.keyup);
|
|
346
|
+
this._target.addEventListener('keypress', this._eventHandlers.keypress);
|
|
293
347
|
|
|
294
348
|
// Release (key up) if window loses focus
|
|
295
349
|
window.addEventListener('blur', this._eventHandlers.blur);
|
|
296
350
|
|
|
351
|
+
// Firefox on Windows has broken handling of Alt, so we need to
|
|
352
|
+
// poll as best we can for releases (still doesn't prevent the
|
|
353
|
+
// menu from popping up though as we can't call
|
|
354
|
+
// preventDefault())
|
|
355
|
+
if (browser.isWindows() && browser.isFirefox()) {
|
|
356
|
+
const handler = this._eventHandlers.checkalt;
|
|
357
|
+
['mousedown', 'mouseup', 'mousemove', 'wheel',
|
|
358
|
+
'touchstart', 'touchend', 'touchmove',
|
|
359
|
+
'keydown', 'keyup'].forEach(type =>
|
|
360
|
+
document.addEventListener(type, handler,
|
|
361
|
+
{ capture: true,
|
|
362
|
+
passive: true }));
|
|
363
|
+
}
|
|
364
|
+
|
|
297
365
|
//Log.Debug("<< Keyboard.grab");
|
|
298
|
-
}
|
|
366
|
+
}
|
|
299
367
|
|
|
300
|
-
ungrab
|
|
368
|
+
ungrab() {
|
|
301
369
|
//Log.Debug(">> Keyboard.ungrab");
|
|
302
|
-
var c = this._target;
|
|
303
370
|
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
371
|
+
if (browser.isWindows() && browser.isFirefox()) {
|
|
372
|
+
const handler = this._eventHandlers.checkalt;
|
|
373
|
+
['mousedown', 'mouseup', 'mousemove', 'wheel',
|
|
374
|
+
'touchstart', 'touchend', 'touchmove',
|
|
375
|
+
'keydown', 'keyup'].forEach(type => document.removeEventListener(type, handler));
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
this._target.removeEventListener('keydown', this._eventHandlers.keydown);
|
|
379
|
+
this._target.removeEventListener('keyup', this._eventHandlers.keyup);
|
|
380
|
+
this._target.removeEventListener('keypress', this._eventHandlers.keypress);
|
|
307
381
|
window.removeEventListener('blur', this._eventHandlers.blur);
|
|
308
382
|
|
|
309
383
|
// Release (key up) all keys that are in a down state
|
|
310
384
|
this._allKeysUp();
|
|
311
385
|
|
|
312
386
|
//Log.Debug(">> Keyboard.ungrab");
|
|
313
|
-
}
|
|
314
|
-
}
|
|
387
|
+
}
|
|
388
|
+
}
|
package/core/input/keysym.js
CHANGED
package/core/input/keysymdef.js
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
/* Functions at the bottom */
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
const codepoints = {
|
|
11
11
|
0x0100: 0x03c0, // XK_Amacron
|
|
12
12
|
0x0101: 0x03e0, // XK_amacron
|
|
13
13
|
0x0102: 0x01c3, // XK_Abreve
|
|
@@ -670,14 +670,14 @@ var codepoints = {
|
|
|
670
670
|
};
|
|
671
671
|
|
|
672
672
|
export default {
|
|
673
|
-
lookup
|
|
673
|
+
lookup(u) {
|
|
674
674
|
// Latin-1 is one-to-one mapping
|
|
675
675
|
if ((u >= 0x20) && (u <= 0xff)) {
|
|
676
676
|
return u;
|
|
677
677
|
}
|
|
678
678
|
|
|
679
679
|
// Lookup table (fairly random)
|
|
680
|
-
|
|
680
|
+
const keysym = codepoints[u];
|
|
681
681
|
if (keysym !== undefined) {
|
|
682
682
|
return keysym;
|
|
683
683
|
}
|
package/core/input/util.js
CHANGED
|
@@ -6,7 +6,7 @@ import DOMKeyTable from "./domkeytable.js";
|
|
|
6
6
|
import * as browser from "../util/browser.js";
|
|
7
7
|
|
|
8
8
|
// Get 'KeyboardEvent.code', handling legacy browsers
|
|
9
|
-
export function getKeycode(evt){
|
|
9
|
+
export function getKeycode(evt) {
|
|
10
10
|
// Are we getting proper key identifiers?
|
|
11
11
|
// (unfortunately Firefox and Chrome are crappy here and gives
|
|
12
12
|
// us an empty string on some platforms, rather than leaving it
|
|
@@ -25,7 +25,7 @@ export function getKeycode(evt){
|
|
|
25
25
|
// in the 'keyCode' field for non-printable characters. However
|
|
26
26
|
// Webkit sets it to the same as charCode in 'keypress' events.
|
|
27
27
|
if ((evt.type !== 'keypress') && (evt.keyCode in vkeys)) {
|
|
28
|
-
|
|
28
|
+
let code = vkeys[evt.keyCode];
|
|
29
29
|
|
|
30
30
|
// macOS has messed up this code for some reason
|
|
31
31
|
if (browser.isMac() && (code === 'ContextMenu')) {
|
|
@@ -92,6 +92,8 @@ export function getKey(evt) {
|
|
|
92
92
|
// Mozilla isn't fully in sync with the spec yet
|
|
93
93
|
switch (evt.key) {
|
|
94
94
|
case 'OS': return 'Meta';
|
|
95
|
+
case 'LaunchMyComputer': return 'LaunchApplication1';
|
|
96
|
+
case 'LaunchCalculator': return 'LaunchApplication2';
|
|
95
97
|
}
|
|
96
98
|
|
|
97
99
|
// iOS leaks some OS names
|
|
@@ -103,15 +105,27 @@ export function getKey(evt) {
|
|
|
103
105
|
case 'UIKeyInputEscape': return 'Escape';
|
|
104
106
|
}
|
|
105
107
|
|
|
106
|
-
//
|
|
107
|
-
|
|
108
|
-
|
|
108
|
+
// Broken behaviour in Chrome
|
|
109
|
+
if ((evt.key === '\x00') && (evt.code === 'NumpadDecimal')) {
|
|
110
|
+
return 'Delete';
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// IE and Edge need special handling, but for everyone else we
|
|
114
|
+
// can trust the value provided
|
|
115
|
+
if (!browser.isIE() && !browser.isEdge()) {
|
|
116
|
+
return evt.key;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// IE and Edge have broken handling of AltGraph so we can only
|
|
120
|
+
// trust them for non-printable characters (and unfortunately
|
|
121
|
+
// they also specify 'Unidentified' for some problem keys)
|
|
122
|
+
if ((evt.key.length !== 1) && (evt.key !== 'Unidentified')) {
|
|
109
123
|
return evt.key;
|
|
110
124
|
}
|
|
111
125
|
}
|
|
112
126
|
|
|
113
127
|
// Try to deduce it based on the physical key
|
|
114
|
-
|
|
128
|
+
const code = getKeycode(evt);
|
|
115
129
|
if (code in fixedkeys) {
|
|
116
130
|
return fixedkeys[code];
|
|
117
131
|
}
|
|
@@ -126,8 +140,8 @@ export function getKey(evt) {
|
|
|
126
140
|
}
|
|
127
141
|
|
|
128
142
|
// Get the most reliable keysym value we can get from a key event
|
|
129
|
-
export function getKeysym(evt){
|
|
130
|
-
|
|
143
|
+
export function getKeysym(evt) {
|
|
144
|
+
const key = getKey(evt);
|
|
131
145
|
|
|
132
146
|
if (key === 'Unidentified') {
|
|
133
147
|
return null;
|
|
@@ -135,30 +149,57 @@ export function getKeysym(evt){
|
|
|
135
149
|
|
|
136
150
|
// First look up special keys
|
|
137
151
|
if (key in DOMKeyTable) {
|
|
138
|
-
|
|
152
|
+
let location = evt.location;
|
|
139
153
|
|
|
140
154
|
// Safari screws up location for the right cmd key
|
|
141
155
|
if ((key === 'Meta') && (location === 0)) {
|
|
142
156
|
location = 2;
|
|
143
157
|
}
|
|
144
158
|
|
|
159
|
+
// And for Clear
|
|
160
|
+
if ((key === 'Clear') && (location === 3)) {
|
|
161
|
+
let code = getKeycode(evt);
|
|
162
|
+
if (code === 'NumLock') {
|
|
163
|
+
location = 0;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
145
167
|
if ((location === undefined) || (location > 3)) {
|
|
146
168
|
location = 0;
|
|
147
169
|
}
|
|
148
170
|
|
|
171
|
+
// The original Meta key now gets confused with the Windows key
|
|
172
|
+
// https://bugs.chromium.org/p/chromium/issues/detail?id=1020141
|
|
173
|
+
// https://bugzilla.mozilla.org/show_bug.cgi?id=1232918
|
|
174
|
+
if (key === 'Meta') {
|
|
175
|
+
let code = getKeycode(evt);
|
|
176
|
+
if (code === 'AltLeft') {
|
|
177
|
+
return KeyTable.XK_Meta_L;
|
|
178
|
+
} else if (code === 'AltRight') {
|
|
179
|
+
return KeyTable.XK_Meta_R;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// macOS has Clear instead of NumLock, but the remote system is
|
|
184
|
+
// probably not macOS, so lying here is probably best...
|
|
185
|
+
if (key === 'Clear') {
|
|
186
|
+
let code = getKeycode(evt);
|
|
187
|
+
if (code === 'NumLock') {
|
|
188
|
+
return KeyTable.XK_Num_Lock;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
149
192
|
return DOMKeyTable[key][location];
|
|
150
193
|
}
|
|
151
194
|
|
|
152
195
|
// Now we need to look at the Unicode symbol instead
|
|
153
196
|
|
|
154
|
-
var codepoint;
|
|
155
|
-
|
|
156
197
|
// Special key? (FIXME: Should have been caught earlier)
|
|
157
198
|
if (key.length !== 1) {
|
|
158
199
|
return null;
|
|
159
200
|
}
|
|
160
201
|
|
|
161
|
-
codepoint = key.charCodeAt();
|
|
202
|
+
const codepoint = key.charCodeAt();
|
|
162
203
|
if (codepoint) {
|
|
163
204
|
return keysyms.lookup(codepoint);
|
|
164
205
|
}
|
package/core/input/vkeys.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* noVNC: HTML5 VNC client
|
|
3
|
-
* Copyright (C)
|
|
3
|
+
* Copyright (C) 2018 The noVNC Authors
|
|
4
4
|
* Licensed under MPL 2.0 or any later version (see LICENSE.txt)
|
|
5
5
|
*/
|
|
6
6
|
|
|
@@ -13,6 +13,7 @@ export default {
|
|
|
13
13
|
0x08: 'Backspace',
|
|
14
14
|
0x09: 'Tab',
|
|
15
15
|
0x0a: 'NumpadClear',
|
|
16
|
+
0x0c: 'Numpad5', // IE11 sends evt.keyCode: 12 when numlock is off
|
|
16
17
|
0x0d: 'Enter',
|
|
17
18
|
0x10: 'ShiftLeft',
|
|
18
19
|
0x11: 'ControlLeft',
|