@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.
- package/LICENSE.txt +0 -6
- package/README.md +16 -6
- package/core/decoders/copyrect.js +5 -0
- package/core/decoders/hextile.js +57 -3
- package/core/decoders/jpeg.js +141 -0
- package/core/decoders/raw.js +12 -2
- package/core/decoders/tight.js +24 -8
- package/core/decoders/zrle.js +185 -0
- package/core/display.js +9 -151
- package/core/encodings.js +4 -0
- package/core/input/domkeytable.js +25 -21
- package/core/input/keyboard.js +12 -127
- package/core/input/util.js +18 -35
- package/core/input/vkeys.js +0 -1
- package/core/input/xtscancodes.js +5 -3
- package/core/ra2.js +567 -0
- package/core/rfb.js +332 -114
- package/core/util/browser.js +0 -17
- package/core/util/cursor.js +1 -11
- package/core/util/events.js +0 -4
- package/core/util/md5.js +79 -0
- package/core/websock.js +76 -17
- package/docs/API.md +46 -6
- package/docs/LIBRARY.md +3 -7
- package/lib/base64.js +5 -5
- package/lib/decoders/copyrect.js +8 -3
- package/lib/decoders/hextile.js +65 -9
- package/lib/decoders/jpeg.js +188 -0
- package/lib/decoders/raw.js +14 -5
- package/lib/decoders/rre.js +3 -3
- package/lib/decoders/tight.js +40 -22
- package/lib/decoders/tightpng.js +10 -10
- package/lib/decoders/zrle.js +234 -0
- package/lib/deflator.js +5 -5
- package/lib/des.js +3 -3
- package/lib/display.js +47 -214
- package/lib/encodings.js +8 -0
- package/lib/inflator.js +5 -5
- package/lib/input/domkeytable.js +197 -194
- package/lib/input/fixedkeys.js +2 -2
- package/lib/input/gesturehandler.js +3 -3
- package/lib/input/keyboard.js +40 -160
- package/lib/input/keysym.js +2 -2
- package/lib/input/keysymdef.js +2 -2
- package/lib/input/util.js +35 -80
- package/lib/input/vkeys.js +2 -4
- package/lib/input/xtscancodes.js +11 -5
- package/lib/ra2.js +1257 -0
- package/lib/rfb.js +656 -306
- package/lib/util/browser.js +9 -27
- package/lib/util/cursor.js +5 -17
- package/lib/util/events.js +3 -5
- package/lib/util/eventtarget.js +4 -4
- package/lib/util/int.js +1 -1
- package/lib/util/logging.js +2 -2
- package/lib/util/md5.js +103 -0
- package/lib/vendor/pako/lib/utils/common.js +2 -2
- package/lib/vendor/pako/lib/zlib/adler32.js +1 -1
- package/lib/vendor/pako/lib/zlib/constants.js +2 -2
- package/lib/vendor/pako/lib/zlib/crc32.js +1 -1
- package/lib/vendor/pako/lib/zlib/deflate.js +114 -113
- package/lib/vendor/pako/lib/zlib/gzheader.js +1 -1
- package/lib/vendor/pako/lib/zlib/inffast.js +5 -5
- package/lib/vendor/pako/lib/zlib/inflate.js +51 -49
- package/lib/vendor/pako/lib/zlib/inftrees.js +4 -4
- package/lib/vendor/pako/lib/zlib/messages.js +2 -2
- package/lib/vendor/pako/lib/zlib/trees.js +5 -5
- package/lib/vendor/pako/lib/zlib/zstream.js +1 -1
- package/lib/websock.js +107 -46
- package/package.json +2 -10
- package/core/util/polyfill.js +0 -61
- package/lib/util/polyfill.js +0 -72
- 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
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
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[
|
|
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
|
-
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
121
|
+
// 3.8. IME and Composition Keys
|
|
120
122
|
|
|
121
123
|
addStandard("AllCandidates", KeyTable.XK_MultipleCandidate);
|
|
122
|
-
addStandard("Alphanumeric", KeyTable.
|
|
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("
|
|
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("
|
|
152
|
+
addStandard("ZenkakuHankaku", KeyTable.XK_Zenkaku_Hankaku);
|
|
151
153
|
|
|
152
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
217
|
+
// 3.11. Multimedia Numpad Keys
|
|
215
218
|
|
|
216
219
|
// - Key11
|
|
217
220
|
// - Key12
|
|
218
221
|
|
|
219
|
-
//
|
|
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
|
-
//
|
|
242
|
+
// 3.13. Speech Keys
|
|
240
243
|
|
|
241
244
|
// - SpeechCorrectionList
|
|
242
245
|
// - SpeechInputToggle
|
|
243
246
|
|
|
244
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
273
|
+
// 3.16. Mobile Phone Keys
|
|
270
274
|
|
|
271
275
|
// - A whole bunch...
|
|
272
276
|
|
|
273
|
-
//
|
|
277
|
+
// 3.17. TV Keys
|
|
274
278
|
|
|
275
279
|
// - A whole bunch...
|
|
276
280
|
|
|
277
|
-
//
|
|
281
|
+
// 3.18. Media Controller Keys
|
|
278
282
|
|
|
279
283
|
// - A whole bunch...
|
|
280
284
|
addStandard("Dimmer", KeyTable.XF86XK_BrightnessAdjust);
|
package/core/input/keyboard.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
//
|
|
173
|
-
//
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
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
|
package/core/input/util.js
CHANGED
|
@@ -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
|
|
26
|
-
|
|
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
|
-
|
|
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
|
|