@novnc/novnc 1.2.0-test → 1.3.0-g1075cd8

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 (73) hide show
  1. package/LICENSE.txt +0 -6
  2. package/README.md +16 -6
  3. package/core/decoders/copyrect.js +5 -0
  4. package/core/decoders/hextile.js +57 -3
  5. package/core/decoders/jpeg.js +141 -0
  6. package/core/decoders/raw.js +12 -2
  7. package/core/decoders/tight.js +24 -8
  8. package/core/decoders/zrle.js +185 -0
  9. package/core/display.js +9 -151
  10. package/core/encodings.js +4 -0
  11. package/core/input/domkeytable.js +25 -21
  12. package/core/input/keyboard.js +12 -127
  13. package/core/input/util.js +18 -35
  14. package/core/input/vkeys.js +0 -1
  15. package/core/input/xtscancodes.js +5 -3
  16. package/core/ra2.js +567 -0
  17. package/core/rfb.js +332 -114
  18. package/core/util/browser.js +0 -17
  19. package/core/util/cursor.js +1 -11
  20. package/core/util/events.js +0 -4
  21. package/core/util/md5.js +79 -0
  22. package/core/websock.js +76 -17
  23. package/docs/API.md +46 -6
  24. package/docs/LIBRARY.md +3 -7
  25. package/lib/base64.js +5 -5
  26. package/lib/decoders/copyrect.js +8 -3
  27. package/lib/decoders/hextile.js +65 -9
  28. package/lib/decoders/jpeg.js +188 -0
  29. package/lib/decoders/raw.js +14 -5
  30. package/lib/decoders/rre.js +3 -3
  31. package/lib/decoders/tight.js +40 -22
  32. package/lib/decoders/tightpng.js +10 -10
  33. package/lib/decoders/zrle.js +234 -0
  34. package/lib/deflator.js +5 -5
  35. package/lib/des.js +3 -3
  36. package/lib/display.js +47 -214
  37. package/lib/encodings.js +8 -0
  38. package/lib/inflator.js +5 -5
  39. package/lib/input/domkeytable.js +197 -194
  40. package/lib/input/fixedkeys.js +2 -2
  41. package/lib/input/gesturehandler.js +3 -3
  42. package/lib/input/keyboard.js +40 -160
  43. package/lib/input/keysym.js +2 -2
  44. package/lib/input/keysymdef.js +2 -2
  45. package/lib/input/util.js +35 -80
  46. package/lib/input/vkeys.js +2 -4
  47. package/lib/input/xtscancodes.js +11 -5
  48. package/lib/ra2.js +1257 -0
  49. package/lib/rfb.js +656 -306
  50. package/lib/util/browser.js +9 -27
  51. package/lib/util/cursor.js +5 -17
  52. package/lib/util/events.js +3 -5
  53. package/lib/util/eventtarget.js +4 -4
  54. package/lib/util/int.js +1 -1
  55. package/lib/util/logging.js +2 -2
  56. package/lib/util/md5.js +103 -0
  57. package/lib/vendor/pako/lib/utils/common.js +2 -2
  58. package/lib/vendor/pako/lib/zlib/adler32.js +1 -1
  59. package/lib/vendor/pako/lib/zlib/constants.js +2 -2
  60. package/lib/vendor/pako/lib/zlib/crc32.js +1 -1
  61. package/lib/vendor/pako/lib/zlib/deflate.js +114 -113
  62. package/lib/vendor/pako/lib/zlib/gzheader.js +1 -1
  63. package/lib/vendor/pako/lib/zlib/inffast.js +5 -5
  64. package/lib/vendor/pako/lib/zlib/inflate.js +51 -49
  65. package/lib/vendor/pako/lib/zlib/inftrees.js +4 -4
  66. package/lib/vendor/pako/lib/zlib/messages.js +2 -2
  67. package/lib/vendor/pako/lib/zlib/trees.js +5 -5
  68. package/lib/vendor/pako/lib/zlib/zstream.js +1 -1
  69. package/lib/websock.js +107 -46
  70. package/package.json +2 -10
  71. package/core/util/polyfill.js +0 -61
  72. package/lib/util/polyfill.js +0 -72
  73. package/lib/vendor/promise.js +0 -255
package/core/display.js CHANGED
@@ -8,7 +8,6 @@
8
8
 
9
9
  import * as Log from './util/logging.js';
10
10
  import Base64 from "./base64.js";
11
- import { supportsImageMetadata } from './util/browser.js';
12
11
  import { toSigned32bit } from './util/int.js';
13
12
 
14
13
  export default class Display {
@@ -23,10 +22,6 @@ export default class Display {
23
22
  this._fbHeight = 0;
24
23
 
25
24
  this._prevDrawStyle = "";
26
- this._tile = null;
27
- this._tile16x16 = null;
28
- this._tileX = 0;
29
- this._tileY = 0;
30
25
 
31
26
  Log.Debug(">> Display.constructor");
32
27
 
@@ -60,12 +55,6 @@ export default class Display {
60
55
 
61
56
  Log.Debug("User Agent: " + navigator.userAgent);
62
57
 
63
- // Check canvas features
64
- if (!('createImageData' in this._drawCtx)) {
65
- throw new Error("Canvas does not support createImageData");
66
- }
67
-
68
- this._tile16x16 = this._drawCtx.createImageData(16, 16);
69
58
  Log.Debug("<< Display.constructor");
70
59
 
71
60
  // ===== PROPERTIES =====
@@ -378,57 +367,6 @@ export default class Display {
378
367
  });
379
368
  }
380
369
 
381
- // start updating a tile
382
- startTile(x, y, width, height, color) {
383
- this._tileX = x;
384
- this._tileY = y;
385
- if (width === 16 && height === 16) {
386
- this._tile = this._tile16x16;
387
- } else {
388
- this._tile = this._drawCtx.createImageData(width, height);
389
- }
390
-
391
- const red = color[2];
392
- const green = color[1];
393
- const blue = color[0];
394
-
395
- const data = this._tile.data;
396
- for (let i = 0; i < width * height * 4; i += 4) {
397
- data[i] = red;
398
- data[i + 1] = green;
399
- data[i + 2] = blue;
400
- data[i + 3] = 255;
401
- }
402
- }
403
-
404
- // update sub-rectangle of the current tile
405
- subTile(x, y, w, h, color) {
406
- const red = color[2];
407
- const green = color[1];
408
- const blue = color[0];
409
- const xend = x + w;
410
- const yend = y + h;
411
-
412
- const data = this._tile.data;
413
- const width = this._tile.width;
414
- for (let j = y; j < yend; j++) {
415
- for (let i = x; i < xend; i++) {
416
- const p = (i + (j * width)) * 4;
417
- data[p] = red;
418
- data[p + 1] = green;
419
- data[p + 2] = blue;
420
- data[p + 3] = 255;
421
- }
422
- }
423
- }
424
-
425
- // draw the current tile to the screen
426
- finishTile() {
427
- this._drawCtx.putImageData(this._tile, this._tileX, this._tileY);
428
- this._damage(this._tileX, this._tileY,
429
- this._tile.width, this._tile.height);
430
- }
431
-
432
370
  blitImage(x, y, width, height, arr, offset, fromQueue) {
433
371
  if (this._renderQ.length !== 0 && !fromQueue) {
434
372
  // NB(directxman12): it's technically more performant here to use preallocated arrays,
@@ -445,47 +383,13 @@ export default class Display {
445
383
  'height': height,
446
384
  });
447
385
  } else {
448
- this._bgrxImageData(x, y, width, height, arr, offset);
449
- }
450
- }
451
-
452
- blitRgbImage(x, y, width, height, arr, offset, fromQueue) {
453
- if (this._renderQ.length !== 0 && !fromQueue) {
454
- // NB(directxman12): it's technically more performant here to use preallocated arrays,
455
- // but it's a lot of extra work for not a lot of payoff -- if we're using the render queue,
456
- // this probably isn't getting called *nearly* as much
457
- const newArr = new Uint8Array(width * height * 3);
458
- newArr.set(new Uint8Array(arr.buffer, 0, newArr.length));
459
- this._renderQPush({
460
- 'type': 'blitRgb',
461
- 'data': newArr,
462
- 'x': x,
463
- 'y': y,
464
- 'width': width,
465
- 'height': height,
466
- });
467
- } else {
468
- this._rgbImageData(x, y, width, height, arr, offset);
469
- }
470
- }
471
-
472
- blitRgbxImage(x, y, width, height, arr, offset, fromQueue) {
473
- if (this._renderQ.length !== 0 && !fromQueue) {
474
- // NB(directxman12): it's technically more performant here to use preallocated arrays,
475
- // but it's a lot of extra work for not a lot of payoff -- if we're using the render queue,
476
- // this probably isn't getting called *nearly* as much
477
- const newArr = new Uint8Array(width * height * 4);
478
- newArr.set(new Uint8Array(arr.buffer, 0, newArr.length));
479
- this._renderQPush({
480
- 'type': 'blitRgbx',
481
- 'data': newArr,
482
- 'x': x,
483
- 'y': y,
484
- 'width': width,
485
- 'height': height,
486
- });
487
- } else {
488
- this._rgbxImageData(x, y, width, height, arr, offset);
386
+ // NB(directxman12): arr must be an Type Array view
387
+ let data = new Uint8ClampedArray(arr.buffer,
388
+ arr.byteOffset + offset,
389
+ width * height * 4);
390
+ let img = new ImageData(data, width, height);
391
+ this._drawCtx.putImageData(img, x, y);
392
+ this._damage(x, y, width, height);
489
393
  }
490
394
  }
491
395
 
@@ -537,52 +441,13 @@ export default class Display {
537
441
  }
538
442
 
539
443
  _setFillColor(color) {
540
- const newStyle = 'rgb(' + color[2] + ',' + color[1] + ',' + color[0] + ')';
444
+ const newStyle = 'rgb(' + color[0] + ',' + color[1] + ',' + color[2] + ')';
541
445
  if (newStyle !== this._prevDrawStyle) {
542
446
  this._drawCtx.fillStyle = newStyle;
543
447
  this._prevDrawStyle = newStyle;
544
448
  }
545
449
  }
546
450
 
547
- _rgbImageData(x, y, width, height, arr, offset) {
548
- const img = this._drawCtx.createImageData(width, height);
549
- const data = img.data;
550
- for (let i = 0, j = offset; i < width * height * 4; i += 4, j += 3) {
551
- data[i] = arr[j];
552
- data[i + 1] = arr[j + 1];
553
- data[i + 2] = arr[j + 2];
554
- data[i + 3] = 255; // Alpha
555
- }
556
- this._drawCtx.putImageData(img, x, y);
557
- this._damage(x, y, img.width, img.height);
558
- }
559
-
560
- _bgrxImageData(x, y, width, height, arr, offset) {
561
- const img = this._drawCtx.createImageData(width, height);
562
- const data = img.data;
563
- for (let i = 0, j = offset; i < width * height * 4; i += 4, j += 4) {
564
- data[i] = arr[j + 2];
565
- data[i + 1] = arr[j + 1];
566
- data[i + 2] = arr[j];
567
- data[i + 3] = 255; // Alpha
568
- }
569
- this._drawCtx.putImageData(img, x, y);
570
- this._damage(x, y, img.width, img.height);
571
- }
572
-
573
- _rgbxImageData(x, y, width, height, arr, offset) {
574
- // NB(directxman12): arr must be an Type Array view
575
- let img;
576
- if (supportsImageMetadata) {
577
- img = new ImageData(new Uint8ClampedArray(arr.buffer, arr.byteOffset, width * height * 4), width, height);
578
- } else {
579
- img = this._drawCtx.createImageData(width, height);
580
- img.data.set(new Uint8ClampedArray(arr.buffer, arr.byteOffset, width * height * 4));
581
- }
582
- this._drawCtx.putImageData(img, x, y);
583
- this._damage(x, y, img.width, img.height);
584
- }
585
-
586
451
  _renderQPush(action) {
587
452
  this._renderQ.push(action);
588
453
  if (this._renderQ.length === 1) {
@@ -616,15 +481,8 @@ export default class Display {
616
481
  case 'blit':
617
482
  this.blitImage(a.x, a.y, a.width, a.height, a.data, 0, true);
618
483
  break;
619
- case 'blitRgb':
620
- this.blitRgbImage(a.x, a.y, a.width, a.height, a.data, 0, true);
621
- break;
622
- case 'blitRgbx':
623
- this.blitRgbxImage(a.x, a.y, a.width, a.height, a.data, 0, true);
624
- break;
625
484
  case 'img':
626
- /* IE tends to set "complete" prematurely, so check dimensions */
627
- if (a.img.complete && (a.img.width !== 0) && (a.img.height !== 0)) {
485
+ if (a.img.complete) {
628
486
  if (a.img.width !== a.width || a.img.height !== a.height) {
629
487
  Log.Error("Decoded image has incorrect dimensions. Got " +
630
488
  a.img.width + "x" + a.img.height + ". Expected " +
package/core/encodings.js CHANGED
@@ -12,7 +12,9 @@ export const encodings = {
12
12
  encodingRRE: 2,
13
13
  encodingHextile: 5,
14
14
  encodingTight: 7,
15
+ encodingZRLE: 16,
15
16
  encodingTightPNG: -260,
17
+ encodingJPEG: 21,
16
18
 
17
19
  pseudoEncodingQualityLevel9: -23,
18
20
  pseudoEncodingQualityLevel0: -32,
@@ -38,7 +40,9 @@ export function encodingName(num) {
38
40
  case encodings.encodingRRE: return "RRE";
39
41
  case encodings.encodingHextile: return "Hextile";
40
42
  case encodings.encodingTight: return "Tight";
43
+ case encodings.encodingZRLE: return "ZRLE";
41
44
  case encodings.encodingTightPNG: return "TightPNG";
45
+ case encodings.encodingJPEG: return "JPEG";
42
46
  default: return "[unknown encoding " + num + "]";
43
47
  }
44
48
  }
@@ -35,7 +35,7 @@ function addNumpad(key, standard, numpad) {
35
35
  DOMKeyTable[key] = [standard, standard, standard, numpad];
36
36
  }
37
37
 
38
- // 2.2. Modifier Keys
38
+ // 3.2. Modifier Keys
39
39
 
40
40
  addLeftRight("Alt", KeyTable.XK_Alt_L, KeyTable.XK_Alt_R);
41
41
  addStandard("AltGraph", KeyTable.XK_ISO_Level3_Shift);
@@ -49,25 +49,27 @@ addStandard("ScrollLock", KeyTable.XK_Scroll_Lock);
49
49
  addLeftRight("Shift", KeyTable.XK_Shift_L, KeyTable.XK_Shift_R);
50
50
  // - Symbol
51
51
  // - SymbolLock
52
+ // - Hyper
53
+ // - Super
52
54
 
53
- // 2.3. Whitespace Keys
55
+ // 3.3. Whitespace Keys
54
56
 
55
57
  addNumpad("Enter", KeyTable.XK_Return, KeyTable.XK_KP_Enter);
56
58
  addStandard("Tab", KeyTable.XK_Tab);
57
59
  addNumpad(" ", KeyTable.XK_space, KeyTable.XK_KP_Space);
58
60
 
59
- // 2.4. Navigation Keys
61
+ // 3.4. Navigation Keys
60
62
 
61
63
  addNumpad("ArrowDown", KeyTable.XK_Down, KeyTable.XK_KP_Down);
62
- addNumpad("ArrowUp", KeyTable.XK_Up, KeyTable.XK_KP_Up);
63
64
  addNumpad("ArrowLeft", KeyTable.XK_Left, KeyTable.XK_KP_Left);
64
65
  addNumpad("ArrowRight", KeyTable.XK_Right, KeyTable.XK_KP_Right);
66
+ addNumpad("ArrowUp", KeyTable.XK_Up, KeyTable.XK_KP_Up);
65
67
  addNumpad("End", KeyTable.XK_End, KeyTable.XK_KP_End);
66
68
  addNumpad("Home", KeyTable.XK_Home, KeyTable.XK_KP_Home);
67
69
  addNumpad("PageDown", KeyTable.XK_Next, KeyTable.XK_KP_Next);
68
70
  addNumpad("PageUp", KeyTable.XK_Prior, KeyTable.XK_KP_Prior);
69
71
 
70
- // 2.5. Editing Keys
72
+ // 3.5. Editing Keys
71
73
 
72
74
  addStandard("Backspace", KeyTable.XK_BackSpace);
73
75
  // Browsers send "Clear" for the numpad 5 without NumLock because
@@ -85,7 +87,7 @@ addStandard("Paste", KeyTable.XF86XK_Paste);
85
87
  addStandard("Redo", KeyTable.XK_Redo);
86
88
  addStandard("Undo", KeyTable.XK_Undo);
87
89
 
88
- // 2.6. UI Keys
90
+ // 3.6. UI Keys
89
91
 
90
92
  // - Accept
91
93
  // - Again (could just be XK_Redo)
@@ -103,7 +105,7 @@ addStandard("Select", KeyTable.XK_Select);
103
105
  addStandard("ZoomIn", KeyTable.XF86XK_ZoomIn);
104
106
  addStandard("ZoomOut", KeyTable.XF86XK_ZoomOut);
105
107
 
106
- // 2.7. Device Keys
108
+ // 3.7. Device Keys
107
109
 
108
110
  addStandard("BrightnessDown", KeyTable.XF86XK_MonBrightnessDown);
109
111
  addStandard("BrightnessUp", KeyTable.XF86XK_MonBrightnessUp);
@@ -116,10 +118,10 @@ addStandard("Hibernate", KeyTable.XF86XK_Hibernate);
116
118
  addStandard("Standby", KeyTable.XF86XK_Standby);
117
119
  addStandard("WakeUp", KeyTable.XF86XK_WakeUp);
118
120
 
119
- // 2.8. IME and Composition Keys
121
+ // 3.8. IME and Composition Keys
120
122
 
121
123
  addStandard("AllCandidates", KeyTable.XK_MultipleCandidate);
122
- addStandard("Alphanumeric", KeyTable.XK_Eisu_Shift); // could also be _Eisu_Toggle
124
+ addStandard("Alphanumeric", KeyTable.XK_Eisu_toggle);
123
125
  addStandard("CodeInput", KeyTable.XK_Codeinput);
124
126
  addStandard("Compose", KeyTable.XK_Multi_key);
125
127
  addStandard("Convert", KeyTable.XK_Henkan);
@@ -137,7 +139,7 @@ addStandard("PreviousCandidate", KeyTable.XK_PreviousCandidate);
137
139
  addStandard("SingleCandidate", KeyTable.XK_SingleCandidate);
138
140
  addStandard("HangulMode", KeyTable.XK_Hangul);
139
141
  addStandard("HanjaMode", KeyTable.XK_Hangul_Hanja);
140
- addStandard("JunjuaMode", KeyTable.XK_Hangul_Jeonja);
142
+ addStandard("JunjaMode", KeyTable.XK_Hangul_Jeonja);
141
143
  addStandard("Eisu", KeyTable.XK_Eisu_toggle);
142
144
  addStandard("Hankaku", KeyTable.XK_Hankaku);
143
145
  addStandard("Hiragana", KeyTable.XK_Hiragana);
@@ -147,9 +149,9 @@ addStandard("KanjiMode", KeyTable.XK_Kanji);
147
149
  addStandard("Katakana", KeyTable.XK_Katakana);
148
150
  addStandard("Romaji", KeyTable.XK_Romaji);
149
151
  addStandard("Zenkaku", KeyTable.XK_Zenkaku);
150
- addStandard("ZenkakuHanaku", KeyTable.XK_Zenkaku_Hankaku);
152
+ addStandard("ZenkakuHankaku", KeyTable.XK_Zenkaku_Hankaku);
151
153
 
152
- // 2.9. General-Purpose Function Keys
154
+ // 3.9. General-Purpose Function Keys
153
155
 
154
156
  addStandard("F1", KeyTable.XK_F1);
155
157
  addStandard("F2", KeyTable.XK_F2);
@@ -188,7 +190,7 @@ addStandard("F34", KeyTable.XK_F34);
188
190
  addStandard("F35", KeyTable.XK_F35);
189
191
  // - Soft1...
190
192
 
191
- // 2.10. Multimedia Keys
193
+ // 3.10. Multimedia Keys
192
194
 
193
195
  // - ChannelDown
194
196
  // - ChannelUp
@@ -200,6 +202,7 @@ addStandard("MailSend", KeyTable.XF86XK_Send);
200
202
  addStandard("MediaFastForward", KeyTable.XF86XK_AudioForward);
201
203
  addStandard("MediaPause", KeyTable.XF86XK_AudioPause);
202
204
  addStandard("MediaPlay", KeyTable.XF86XK_AudioPlay);
205
+ // - MediaPlayPause
203
206
  addStandard("MediaRecord", KeyTable.XF86XK_AudioRecord);
204
207
  addStandard("MediaRewind", KeyTable.XF86XK_AudioRewind);
205
208
  addStandard("MediaStop", KeyTable.XF86XK_AudioStop);
@@ -211,12 +214,12 @@ addStandard("Print", KeyTable.XK_Print);
211
214
  addStandard("Save", KeyTable.XF86XK_Save);
212
215
  addStandard("SpellCheck", KeyTable.XF86XK_Spell);
213
216
 
214
- // 2.11. Multimedia Numpad Keys
217
+ // 3.11. Multimedia Numpad Keys
215
218
 
216
219
  // - Key11
217
220
  // - Key12
218
221
 
219
- // 2.12. Audio Keys
222
+ // 3.12. Audio Keys
220
223
 
221
224
  // - AudioBalanceLeft
222
225
  // - AudioBalanceRight
@@ -236,16 +239,17 @@ addStandard("AudioVolumeMute", KeyTable.XF86XK_AudioMute);
236
239
  // - MicrophoneVolumeUp
237
240
  addStandard("MicrophoneVolumeMute", KeyTable.XF86XK_AudioMicMute);
238
241
 
239
- // 2.13. Speech Keys
242
+ // 3.13. Speech Keys
240
243
 
241
244
  // - SpeechCorrectionList
242
245
  // - SpeechInputToggle
243
246
 
244
- // 2.14. Application Keys
247
+ // 3.14. Application Keys
245
248
 
246
249
  addStandard("LaunchApplication1", KeyTable.XF86XK_MyComputer);
247
250
  addStandard("LaunchApplication2", KeyTable.XF86XK_Calculator);
248
251
  addStandard("LaunchCalendar", KeyTable.XF86XK_Calendar);
252
+ // - LaunchContacts
249
253
  addStandard("LaunchMail", KeyTable.XF86XK_Mail);
250
254
  addStandard("LaunchMediaPlayer", KeyTable.XF86XK_AudioMedia);
251
255
  addStandard("LaunchMusicPlayer", KeyTable.XF86XK_Music);
@@ -256,7 +260,7 @@ addStandard("LaunchWebBrowser", KeyTable.XF86XK_WWW);
256
260
  addStandard("LaunchWebCam", KeyTable.XF86XK_WebCam);
257
261
  addStandard("LaunchWordProcessor", KeyTable.XF86XK_Word);
258
262
 
259
- // 2.15. Browser Keys
263
+ // 3.15. Browser Keys
260
264
 
261
265
  addStandard("BrowserBack", KeyTable.XF86XK_Back);
262
266
  addStandard("BrowserFavorites", KeyTable.XF86XK_Favorites);
@@ -266,15 +270,15 @@ addStandard("BrowserRefresh", KeyTable.XF86XK_Refresh);
266
270
  addStandard("BrowserSearch", KeyTable.XF86XK_Search);
267
271
  addStandard("BrowserStop", KeyTable.XF86XK_Stop);
268
272
 
269
- // 2.16. Mobile Phone Keys
273
+ // 3.16. Mobile Phone Keys
270
274
 
271
275
  // - A whole bunch...
272
276
 
273
- // 2.17. TV Keys
277
+ // 3.17. TV Keys
274
278
 
275
279
  // - A whole bunch...
276
280
 
277
- // 2.18. Media Controller Keys
281
+ // 3.18. Media Controller Keys
278
282
 
279
283
  // - A whole bunch...
280
284
  addStandard("Dimmer", KeyTable.XF86XK_BrightnessAdjust);
@@ -20,16 +20,13 @@ export default class Keyboard {
20
20
 
21
21
  this._keyDownList = {}; // List of depressed keys
22
22
  // (even if they are happy)
23
- this._pendingKey = null; // Key waiting for keypress
24
23
  this._altGrArmed = false; // Windows AltGr detection
25
24
 
26
25
  // keep these here so we can refer to them later
27
26
  this._eventHandlers = {
28
27
  'keyup': this._handleKeyUp.bind(this),
29
28
  'keydown': this._handleKeyDown.bind(this),
30
- 'keypress': this._handleKeyPress.bind(this),
31
29
  'blur': this._allKeysUp.bind(this),
32
- 'checkalt': this._checkAlt.bind(this),
33
30
  };
34
31
 
35
32
  // ===== EVENT HANDLERS =====
@@ -62,9 +59,7 @@ export default class Keyboard {
62
59
  }
63
60
 
64
61
  // Unstable, but we don't have anything else to go on
65
- // (don't use it for 'keypress' events thought since
66
- // WebKit sets it to the same as charCode)
67
- if (e.keyCode && (e.type !== 'keypress')) {
62
+ if (e.keyCode) {
68
63
  // 229 is used for composition events
69
64
  if (e.keyCode !== 229) {
70
65
  return 'Platform' + e.keyCode;
@@ -169,20 +164,20 @@ export default class Keyboard {
169
164
  return;
170
165
  }
171
166
 
172
- // If this is a legacy browser then we'll need to wait for
173
- // a keypress event as well
174
- // (IE and Edge has a broken KeyboardEvent.key, so we can't
175
- // just check for the presence of that field)
176
- if (!keysym && (!e.key || browser.isIE() || browser.isEdge())) {
177
- this._pendingKey = code;
178
- // However we might not get a keypress event if the key
179
- // is non-printable, which needs some special fallback
180
- // handling
181
- setTimeout(this._handleKeyPressTimeout.bind(this), 10, e);
167
+ // Windows doesn't send proper key releases for a bunch of
168
+ // Japanese IM keys so we have to fake the release right away
169
+ const jpBadKeys = [ KeyTable.XK_Zenkaku_Hankaku,
170
+ KeyTable.XK_Eisu_toggle,
171
+ KeyTable.XK_Katakana,
172
+ KeyTable.XK_Hiragana,
173
+ KeyTable.XK_Romaji ];
174
+ if (browser.isWindows() && jpBadKeys.includes(keysym)) {
175
+ this._sendKeyEvent(keysym, code, true);
176
+ this._sendKeyEvent(keysym, code, false);
177
+ stopEvent(e);
182
178
  return;
183
179
  }
184
180
 
185
- this._pendingKey = null;
186
181
  stopEvent(e);
187
182
 
188
183
  // Possible start of AltGr sequence? (see above)
@@ -197,69 +192,6 @@ export default class Keyboard {
197
192
  this._sendKeyEvent(keysym, code, true);
198
193
  }
199
194
 
200
- // Legacy event for browsers without code/key
201
- _handleKeyPress(e) {
202
- stopEvent(e);
203
-
204
- // Are we expecting a keypress?
205
- if (this._pendingKey === null) {
206
- return;
207
- }
208
-
209
- let code = this._getKeyCode(e);
210
- const keysym = KeyboardUtil.getKeysym(e);
211
-
212
- // The key we were waiting for?
213
- if ((code !== 'Unidentified') && (code != this._pendingKey)) {
214
- return;
215
- }
216
-
217
- code = this._pendingKey;
218
- this._pendingKey = null;
219
-
220
- if (!keysym) {
221
- Log.Info('keypress with no keysym:', e);
222
- return;
223
- }
224
-
225
- this._sendKeyEvent(keysym, code, true);
226
- }
227
-
228
- _handleKeyPressTimeout(e) {
229
- // Did someone manage to sort out the key already?
230
- if (this._pendingKey === null) {
231
- return;
232
- }
233
-
234
- let keysym;
235
-
236
- const code = this._pendingKey;
237
- this._pendingKey = null;
238
-
239
- // We have no way of knowing the proper keysym with the
240
- // information given, but the following are true for most
241
- // layouts
242
- if ((e.keyCode >= 0x30) && (e.keyCode <= 0x39)) {
243
- // Digit
244
- keysym = e.keyCode;
245
- } else if ((e.keyCode >= 0x41) && (e.keyCode <= 0x5a)) {
246
- // Character (A-Z)
247
- let char = String.fromCharCode(e.keyCode);
248
- // A feeble attempt at the correct case
249
- if (e.shiftKey) {
250
- char = char.toUpperCase();
251
- } else {
252
- char = char.toLowerCase();
253
- }
254
- keysym = char.charCodeAt();
255
- } else {
256
- // Unknown, give up
257
- keysym = 0;
258
- }
259
-
260
- this._sendKeyEvent(keysym, code, true);
261
- }
262
-
263
195
  _handleKeyUp(e) {
264
196
  stopEvent(e);
265
197
 
@@ -312,30 +244,6 @@ export default class Keyboard {
312
244
  Log.Debug("<< Keyboard.allKeysUp");
313
245
  }
314
246
 
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
- }
338
-
339
247
  // ===== PUBLIC METHODS =====
340
248
 
341
249
  grab() {
@@ -343,41 +251,18 @@ export default class Keyboard {
343
251
 
344
252
  this._target.addEventListener('keydown', this._eventHandlers.keydown);
345
253
  this._target.addEventListener('keyup', this._eventHandlers.keyup);
346
- this._target.addEventListener('keypress', this._eventHandlers.keypress);
347
254
 
348
255
  // Release (key up) if window loses focus
349
256
  window.addEventListener('blur', this._eventHandlers.blur);
350
257
 
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
-
365
258
  //Log.Debug("<< Keyboard.grab");
366
259
  }
367
260
 
368
261
  ungrab() {
369
262
  //Log.Debug(">> Keyboard.ungrab");
370
263
 
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
264
  this._target.removeEventListener('keydown', this._eventHandlers.keydown);
379
265
  this._target.removeEventListener('keyup', this._eventHandlers.keyup);
380
- this._target.removeEventListener('keypress', this._eventHandlers.keypress);
381
266
  window.removeEventListener('blur', this._eventHandlers.blur);
382
267
 
383
268
  // Release (key up) all keys that are in a down state
@@ -22,9 +22,8 @@ export function getKeycode(evt) {
22
22
  }
23
23
 
24
24
  // The de-facto standard is to use Windows Virtual-Key codes
25
- // in the 'keyCode' field for non-printable characters. However
26
- // Webkit sets it to the same as charCode in 'keypress' events.
27
- if ((evt.type !== 'keypress') && (evt.keyCode in vkeys)) {
25
+ // in the 'keyCode' field for non-printable characters
26
+ if (evt.keyCode in vkeys) {
28
27
  let code = vkeys[evt.keyCode];
29
28
 
30
29
  // macOS has messed up this code for some reason
@@ -69,26 +68,6 @@ export function getKeycode(evt) {
69
68
  export function getKey(evt) {
70
69
  // Are we getting a proper key value?
71
70
  if (evt.key !== undefined) {
72
- // IE and Edge use some ancient version of the spec
73
- // https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/8860571/
74
- switch (evt.key) {
75
- case 'Spacebar': return ' ';
76
- case 'Esc': return 'Escape';
77
- case 'Scroll': return 'ScrollLock';
78
- case 'Win': return 'Meta';
79
- case 'Apps': return 'ContextMenu';
80
- case 'Up': return 'ArrowUp';
81
- case 'Left': return 'ArrowLeft';
82
- case 'Right': return 'ArrowRight';
83
- case 'Down': return 'ArrowDown';
84
- case 'Del': return 'Delete';
85
- case 'Divide': return '/';
86
- case 'Multiply': return '*';
87
- case 'Subtract': return '-';
88
- case 'Add': return '+';
89
- case 'Decimal': return evt.char;
90
- }
91
-
92
71
  // Mozilla isn't fully in sync with the spec yet
93
72
  switch (evt.key) {
94
73
  case 'OS': return 'Meta';
@@ -110,18 +89,7 @@ export function getKey(evt) {
110
89
  return 'Delete';
111
90
  }
112
91
 
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')) {
123
- return evt.key;
124
- }
92
+ return evt.key;
125
93
  }
126
94
 
127
95
  // Try to deduce it based on the physical key
@@ -189,6 +157,21 @@ export function getKeysym(evt) {
189
157
  }
190
158
  }
191
159
 
160
+ // Windows sends alternating symbols for some keys when using a
161
+ // Japanese layout. We have no way of synchronising with the IM
162
+ // running on the remote system, so we send some combined keysym
163
+ // instead and hope for the best.
164
+ if (browser.isWindows()) {
165
+ switch (key) {
166
+ case 'Zenkaku':
167
+ case 'Hankaku':
168
+ return KeyTable.XK_Zenkaku_Hankaku;
169
+ case 'Romaji':
170
+ case 'KanaMode':
171
+ return KeyTable.XK_Romaji;
172
+ }
173
+ }
174
+
192
175
  return DOMKeyTable[key][location];
193
176
  }
194
177