@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.
Files changed (87) hide show
  1. package/AUTHORS +13 -0
  2. package/LICENSE.txt +2 -1
  3. package/README.md +69 -3
  4. package/core/base64.js +35 -41
  5. package/core/decoders/copyrect.js +22 -0
  6. package/core/decoders/hextile.js +137 -0
  7. package/core/decoders/raw.js +56 -0
  8. package/core/decoders/rre.js +44 -0
  9. package/core/decoders/tight.js +315 -0
  10. package/core/decoders/tightpng.js +27 -0
  11. package/core/deflator.js +85 -0
  12. package/core/des.js +90 -95
  13. package/core/display.js +254 -297
  14. package/core/encodings.js +7 -3
  15. package/core/inflator.js +48 -20
  16. package/core/input/domkeytable.js +21 -24
  17. package/core/input/fixedkeys.js +3 -1
  18. package/core/input/gesturehandler.js +567 -0
  19. package/core/input/keyboard.js +194 -120
  20. package/core/input/keysym.js +2 -0
  21. package/core/input/keysymdef.js +3 -3
  22. package/core/input/util.js +53 -12
  23. package/core/input/vkeys.js +2 -1
  24. package/core/rfb.js +1937 -1496
  25. package/core/util/browser.js +80 -29
  26. package/core/util/cursor.js +253 -0
  27. package/core/util/element.js +32 -0
  28. package/core/util/events.js +59 -55
  29. package/core/util/eventtarget.js +25 -30
  30. package/core/util/int.js +15 -0
  31. package/core/util/logging.js +21 -16
  32. package/core/util/polyfill.js +15 -8
  33. package/core/util/strings.js +21 -8
  34. package/core/websock.js +145 -167
  35. package/docs/API.md +31 -10
  36. package/lib/base64.js +115 -0
  37. package/lib/decoders/copyrect.js +44 -0
  38. package/lib/decoders/hextile.js +173 -0
  39. package/lib/decoders/raw.js +78 -0
  40. package/lib/decoders/rre.js +65 -0
  41. package/lib/decoders/tight.js +350 -0
  42. package/lib/decoders/tightpng.js +67 -0
  43. package/lib/deflator.js +99 -0
  44. package/lib/des.js +314 -0
  45. package/lib/display.js +733 -0
  46. package/lib/encodings.js +64 -0
  47. package/lib/inflator.js +87 -0
  48. package/lib/input/domkeytable.js +282 -0
  49. package/lib/input/fixedkeys.js +123 -0
  50. package/lib/input/gesturehandler.js +642 -0
  51. package/lib/input/keyboard.js +429 -0
  52. package/lib/input/keysym.js +1135 -0
  53. package/lib/input/keysymdef.js +1354 -0
  54. package/lib/input/util.js +304 -0
  55. package/lib/input/vkeys.js +127 -0
  56. package/lib/input/xtscancodes.js +505 -0
  57. package/lib/rfb.js +3448 -0
  58. package/lib/util/browser.js +131 -0
  59. package/lib/util/cursor.js +314 -0
  60. package/lib/util/element.js +43 -0
  61. package/lib/util/events.js +142 -0
  62. package/lib/util/eventtarget.js +64 -0
  63. package/lib/util/int.js +22 -0
  64. package/lib/util/logging.js +79 -0
  65. package/lib/util/polyfill.js +72 -0
  66. package/lib/util/strings.js +38 -0
  67. package/lib/vendor/pako/lib/utils/common.js +67 -0
  68. package/lib/vendor/pako/lib/zlib/adler32.js +33 -0
  69. package/lib/vendor/pako/lib/zlib/constants.js +51 -0
  70. package/lib/vendor/pako/lib/zlib/crc32.js +42 -0
  71. package/lib/vendor/pako/lib/zlib/deflate.js +2159 -0
  72. package/lib/vendor/pako/lib/zlib/gzheader.js +53 -0
  73. package/lib/vendor/pako/lib/zlib/inffast.js +445 -0
  74. package/lib/vendor/pako/lib/zlib/inflate.js +2114 -0
  75. package/lib/vendor/pako/lib/zlib/inftrees.js +418 -0
  76. package/lib/vendor/pako/lib/zlib/messages.js +36 -0
  77. package/lib/vendor/pako/lib/zlib/trees.js +1499 -0
  78. package/lib/vendor/pako/lib/zlib/zstream.js +46 -0
  79. package/lib/vendor/promise.js +255 -0
  80. package/lib/websock.js +374 -0
  81. package/package.json +48 -28
  82. package/vendor/pako/lib/zlib/deflate.js +30 -30
  83. package/vendor/pako/lib/zlib/inflate.js +17 -17
  84. package/core/input/mouse.js +0 -280
  85. package/docs/API-internal.md +0 -125
  86. package/docs/EMBEDDING.md +0 -83
  87. package/docs/VERSION +0 -1
@@ -1,7 +1,6 @@
1
1
  /*
2
2
  * noVNC: HTML5 VNC client
3
- * Copyright (C) 2012 Joel Martin
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 function Keyboard(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
-
25
- // keep these here so we can refer to them later
26
- this._eventHandlers = {
27
- 'keyup': this._handleKeyUp.bind(this),
28
- 'keydown': this._handleKeyDown.bind(this),
29
- 'keypress': this._handleKeyPress.bind(this),
30
- 'blur': this._allKeysUp.bind(this)
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
- Keyboard.prototype = {
35
- // ===== EVENT HANDLERS =====
35
+ // ===== EVENT HANDLERS =====
36
36
 
37
- onkeyevent: function () {}, // Handler for key press/release
37
+ this.onkeyevent = () => {}; // Handler for key press/release
38
+ }
38
39
 
39
40
  // ===== PRIVATE METHODS =====
40
41
 
41
- _sendKeyEvent: function (keysym, code, down) {
42
- Log.Debug("onkeyevent " + (down ? "down" : "up") +
43
- ", keysym: " + keysym, ", code: " + code);
44
-
45
- // Windows sends CtrlLeft+AltRight when you press
46
- // AltGraph, which tends to confuse the hell out of
47
- // remote systems. Fake a release of these keys until
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
- if (fakeAltGraph) {
66
- this.onkeyevent(this._keyDownList['ControlLeft'],
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
- var codepoint = parseInt(e.keyIdentifier.substr(2), 16);
98
- var char = String.fromCharCode(codepoint);
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: function (e) {
109
- var code = this._getKeyCode(e);
110
- var keysym = KeyboardUtil.getKeysym(e);
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
- // (iOS omits tracking info on keyup events, which forces us to
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
- case KeyTable.XK_Super_L:
136
- keysym = KeyTable.XK_Alt_L;
137
- break;
138
- case KeyTable.XK_Super_R:
139
- keysym = KeyTable.XK_Super_L;
140
- break;
141
- case KeyTable.XK_Alt_L:
142
- keysym = KeyTable.XK_Mode_switch;
143
- break;
144
- case KeyTable.XK_Alt_R:
145
- keysym = KeyTable.XK_ISO_Level3_Shift;
146
- break;
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
- this._keyDownList[code] = keysym;
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: function (e) {
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
- var code = this._getKeyCode(e);
198
- var keysym = KeyboardUtil.getKeysym(e);
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
- _handleKeyPressTimeout: function (e) {
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
- var code, keysym;
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
- var char = String.fromCharCode(e.keyCode);
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: function (e) {
263
+ _handleKeyUp(e) {
254
264
  stopEvent(e);
255
265
 
256
- var code = this._getKeyCode(e);
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
- delete this._keyDownList[code];
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: function () {
307
+ _allKeysUp() {
276
308
  Log.Debug(">> Keyboard.allKeysUp");
277
- for (var code in this._keyDownList) {
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: function () {
341
+ grab() {
287
342
  //Log.Debug(">> Keyboard.grab");
288
- var c = this._target;
289
343
 
290
- c.addEventListener('keydown', this._eventHandlers.keydown);
291
- c.addEventListener('keyup', this._eventHandlers.keyup);
292
- c.addEventListener('keypress', this._eventHandlers.keypress);
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: function () {
368
+ ungrab() {
301
369
  //Log.Debug(">> Keyboard.ungrab");
302
- var c = this._target;
303
370
 
304
- c.removeEventListener('keydown', this._eventHandlers.keydown);
305
- c.removeEventListener('keyup', this._eventHandlers.keyup);
306
- c.removeEventListener('keypress', this._eventHandlers.keypress);
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
+ }
@@ -1,3 +1,5 @@
1
+ /* eslint-disable key-spacing */
2
+
1
3
  export default {
2
4
  XK_VoidSymbol: 0xffffff, /* Void symbol */
3
5
 
@@ -7,7 +7,7 @@
7
7
 
8
8
  /* Functions at the bottom */
9
9
 
10
- var codepoints = {
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 : function(u) {
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
- var keysym = codepoints[u];
680
+ const keysym = codepoints[u];
681
681
  if (keysym !== undefined) {
682
682
  return keysym;
683
683
  }
@@ -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
- var code = vkeys[evt.keyCode];
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
- // IE and Edge have broken handling of AltGraph so we cannot
107
- // trust them for printable characters
108
- if ((evt.key.length !== 1) || (!browser.isIE() && !browser.isEdge())) {
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
- var code = getKeycode(evt);
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
- var key = getKey(evt);
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
- var location = evt.location;
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
  }
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  * noVNC: HTML5 VNC client
3
- * Copyright (C) 2017 Pierre Ossman for Cendio AB
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',