@novnc/novnc 1.2.0 → 1.3.0-g0ef7582
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 +21 -151
- package/core/encodings.js +4 -0
- package/core/input/domkeytable.js +25 -21
- package/core/input/keyboard.js +22 -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 +487 -171
- 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 +107 -6
- package/docs/LIBRARY.md +3 -7
- package/lib/base64.js +24 -38
- package/lib/decoders/copyrect.js +6 -11
- package/lib/decoders/hextile.js +68 -44
- package/lib/decoders/jpeg.js +146 -0
- package/lib/decoders/raw.js +14 -21
- package/lib/decoders/rre.js +3 -17
- package/lib/decoders/tight.js +43 -93
- package/lib/decoders/tightpng.js +11 -33
- package/lib/decoders/zrle.js +185 -0
- package/lib/deflator.js +9 -26
- package/lib/des.js +22 -38
- package/lib/display.js +100 -315
- package/lib/encodings.js +7 -8
- package/lib/inflator.js +6 -22
- package/lib/input/domkeytable.js +240 -208
- package/lib/input/fixedkeys.js +10 -5
- package/lib/input/gesturehandler.js +84 -154
- package/lib/input/keyboard.js +87 -238
- package/lib/input/keysym.js +16 -272
- package/lib/input/keysymdef.js +7 -9
- package/lib/input/util.js +69 -156
- package/lib/input/vkeys.js +2 -7
- package/lib/input/xtscancodes.js +10 -171
- package/lib/ra2.js +1033 -0
- package/lib/rfb.js +947 -1149
- package/lib/util/browser.js +25 -52
- package/lib/util/cursor.js +25 -81
- package/lib/util/element.js +3 -5
- package/lib/util/events.js +26 -35
- package/lib/util/eventtarget.js +4 -16
- package/lib/util/int.js +2 -3
- package/lib/util/logging.js +3 -21
- package/lib/util/md5.js +83 -0
- package/lib/util/strings.js +3 -5
- package/lib/vendor/pako/lib/utils/common.js +10 -19
- package/lib/vendor/pako/lib/zlib/adler32.js +4 -8
- package/lib/vendor/pako/lib/zlib/constants.js +4 -7
- package/lib/vendor/pako/lib/zlib/crc32.js +6 -13
- package/lib/vendor/pako/lib/zlib/deflate.js +304 -708
- package/lib/vendor/pako/lib/zlib/gzheader.js +2 -14
- package/lib/vendor/pako/lib/zlib/inffast.js +61 -177
- package/lib/vendor/pako/lib/zlib/inflate.js +421 -909
- package/lib/vendor/pako/lib/zlib/inftrees.js +66 -172
- package/lib/vendor/pako/lib/zlib/messages.js +3 -13
- package/lib/vendor/pako/lib/zlib/trees.js +250 -592
- package/lib/vendor/pako/lib/zlib/zstream.js +3 -19
- package/lib/websock.js +119 -111
- 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 =====
|
|
@@ -235,6 +224,18 @@ export default class Display {
|
|
|
235
224
|
this.viewportChangePos(0, 0);
|
|
236
225
|
}
|
|
237
226
|
|
|
227
|
+
getImageData() {
|
|
228
|
+
return this._drawCtx.getImageData(0, 0, this.width, this.height);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
toDataURL(type, encoderOptions) {
|
|
232
|
+
return this._backbuffer.toDataURL(type, encoderOptions);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
toBlob(callback, type, quality) {
|
|
236
|
+
return this._backbuffer.toBlob(callback, type, quality);
|
|
237
|
+
}
|
|
238
|
+
|
|
238
239
|
// Track what parts of the visible canvas that need updating
|
|
239
240
|
_damage(x, y, w, h) {
|
|
240
241
|
if (x < this._damageBounds.left) {
|
|
@@ -378,57 +379,6 @@ export default class Display {
|
|
|
378
379
|
});
|
|
379
380
|
}
|
|
380
381
|
|
|
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
382
|
blitImage(x, y, width, height, arr, offset, fromQueue) {
|
|
433
383
|
if (this._renderQ.length !== 0 && !fromQueue) {
|
|
434
384
|
// NB(directxman12): it's technically more performant here to use preallocated arrays,
|
|
@@ -445,47 +395,13 @@ export default class Display {
|
|
|
445
395
|
'height': height,
|
|
446
396
|
});
|
|
447
397
|
} 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);
|
|
398
|
+
// NB(directxman12): arr must be an Type Array view
|
|
399
|
+
let data = new Uint8ClampedArray(arr.buffer,
|
|
400
|
+
arr.byteOffset + offset,
|
|
401
|
+
width * height * 4);
|
|
402
|
+
let img = new ImageData(data, width, height);
|
|
403
|
+
this._drawCtx.putImageData(img, x, y);
|
|
404
|
+
this._damage(x, y, width, height);
|
|
489
405
|
}
|
|
490
406
|
}
|
|
491
407
|
|
|
@@ -537,52 +453,13 @@ export default class Display {
|
|
|
537
453
|
}
|
|
538
454
|
|
|
539
455
|
_setFillColor(color) {
|
|
540
|
-
const newStyle = 'rgb(' + color[
|
|
456
|
+
const newStyle = 'rgb(' + color[0] + ',' + color[1] + ',' + color[2] + ')';
|
|
541
457
|
if (newStyle !== this._prevDrawStyle) {
|
|
542
458
|
this._drawCtx.fillStyle = newStyle;
|
|
543
459
|
this._prevDrawStyle = newStyle;
|
|
544
460
|
}
|
|
545
461
|
}
|
|
546
462
|
|
|
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
463
|
_renderQPush(action) {
|
|
587
464
|
this._renderQ.push(action);
|
|
588
465
|
if (this._renderQ.length === 1) {
|
|
@@ -616,15 +493,8 @@ export default class Display {
|
|
|
616
493
|
case 'blit':
|
|
617
494
|
this.blitImage(a.x, a.y, a.width, a.height, a.data, 0, true);
|
|
618
495
|
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
496
|
case 'img':
|
|
626
|
-
|
|
627
|
-
if (a.img.complete && (a.img.width !== 0) && (a.img.height !== 0)) {
|
|
497
|
+
if (a.img.complete) {
|
|
628
498
|
if (a.img.width !== a.width || a.img.height !== a.height) {
|
|
629
499
|
Log.Error("Decoded image has incorrect dimensions. Got " +
|
|
630
500
|
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;
|
|
@@ -158,6 +153,16 @@ export default class Keyboard {
|
|
|
158
153
|
keysym = this._keyDownList[code];
|
|
159
154
|
}
|
|
160
155
|
|
|
156
|
+
// macOS doesn't send proper key releases if a key is pressed
|
|
157
|
+
// while meta is held down
|
|
158
|
+
if ((browser.isMac() || browser.isIOS()) &&
|
|
159
|
+
(e.metaKey && code !== 'MetaLeft' && code !== 'MetaRight')) {
|
|
160
|
+
this._sendKeyEvent(keysym, code, true);
|
|
161
|
+
this._sendKeyEvent(keysym, code, false);
|
|
162
|
+
stopEvent(e);
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
|
|
161
166
|
// macOS doesn't send proper key events for modifiers, only
|
|
162
167
|
// state change events. That gets extra confusing for CapsLock
|
|
163
168
|
// which toggles on each press, but not on release. So pretend
|
|
@@ -169,20 +174,20 @@ export default class Keyboard {
|
|
|
169
174
|
return;
|
|
170
175
|
}
|
|
171
176
|
|
|
172
|
-
//
|
|
173
|
-
//
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
177
|
+
// Windows doesn't send proper key releases for a bunch of
|
|
178
|
+
// Japanese IM keys so we have to fake the release right away
|
|
179
|
+
const jpBadKeys = [ KeyTable.XK_Zenkaku_Hankaku,
|
|
180
|
+
KeyTable.XK_Eisu_toggle,
|
|
181
|
+
KeyTable.XK_Katakana,
|
|
182
|
+
KeyTable.XK_Hiragana,
|
|
183
|
+
KeyTable.XK_Romaji ];
|
|
184
|
+
if (browser.isWindows() && jpBadKeys.includes(keysym)) {
|
|
185
|
+
this._sendKeyEvent(keysym, code, true);
|
|
186
|
+
this._sendKeyEvent(keysym, code, false);
|
|
187
|
+
stopEvent(e);
|
|
182
188
|
return;
|
|
183
189
|
}
|
|
184
190
|
|
|
185
|
-
this._pendingKey = null;
|
|
186
191
|
stopEvent(e);
|
|
187
192
|
|
|
188
193
|
// Possible start of AltGr sequence? (see above)
|
|
@@ -197,69 +202,6 @@ export default class Keyboard {
|
|
|
197
202
|
this._sendKeyEvent(keysym, code, true);
|
|
198
203
|
}
|
|
199
204
|
|
|
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
205
|
_handleKeyUp(e) {
|
|
264
206
|
stopEvent(e);
|
|
265
207
|
|
|
@@ -312,30 +254,6 @@ export default class Keyboard {
|
|
|
312
254
|
Log.Debug("<< Keyboard.allKeysUp");
|
|
313
255
|
}
|
|
314
256
|
|
|
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
257
|
// ===== PUBLIC METHODS =====
|
|
340
258
|
|
|
341
259
|
grab() {
|
|
@@ -343,41 +261,18 @@ export default class Keyboard {
|
|
|
343
261
|
|
|
344
262
|
this._target.addEventListener('keydown', this._eventHandlers.keydown);
|
|
345
263
|
this._target.addEventListener('keyup', this._eventHandlers.keyup);
|
|
346
|
-
this._target.addEventListener('keypress', this._eventHandlers.keypress);
|
|
347
264
|
|
|
348
265
|
// Release (key up) if window loses focus
|
|
349
266
|
window.addEventListener('blur', this._eventHandlers.blur);
|
|
350
267
|
|
|
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
268
|
//Log.Debug("<< Keyboard.grab");
|
|
366
269
|
}
|
|
367
270
|
|
|
368
271
|
ungrab() {
|
|
369
272
|
//Log.Debug(">> Keyboard.ungrab");
|
|
370
273
|
|
|
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
274
|
this._target.removeEventListener('keydown', this._eventHandlers.keydown);
|
|
379
275
|
this._target.removeEventListener('keyup', this._eventHandlers.keyup);
|
|
380
|
-
this._target.removeEventListener('keypress', this._eventHandlers.keypress);
|
|
381
276
|
window.removeEventListener('blur', this._eventHandlers.blur);
|
|
382
277
|
|
|
383
278
|
// Release (key up) all keys that are in a down state
|