@novnc/novnc 1.4.0-gcbbd9ab → 1.4.0-gd3aaf4d
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/core/decoders/hextile.js +12 -22
- package/core/decoders/jpeg.js +111 -106
- package/core/decoders/raw.js +22 -29
- package/core/decoders/tight.js +3 -7
- package/core/decoders/zrle.js +1 -1
- package/core/deflator.js +2 -3
- package/core/display.js +13 -10
- package/core/encodings.js +1 -0
- package/core/inflator.js +1 -2
- package/core/input/keyboard.js +21 -13
- package/core/ra2.js +13 -7
- package/core/rfb.js +215 -285
- package/core/websock.js +69 -57
- package/lib/base64.js +5 -6
- package/lib/crypto/aes.js +7 -9
- package/lib/crypto/crypto.js +4 -5
- package/lib/crypto/des.js +6 -9
- package/lib/crypto/dh.js +5 -6
- package/lib/crypto/md5.js +2 -2
- package/lib/crypto/rsa.js +6 -7
- package/lib/decoders/copyrect.js +5 -6
- package/lib/decoders/hextile.js +26 -36
- package/lib/decoders/jpeg.js +132 -105
- package/lib/decoders/raw.js +27 -34
- package/lib/decoders/rre.js +5 -6
- package/lib/decoders/tight.js +18 -22
- package/lib/decoders/tightpng.js +18 -20
- package/lib/decoders/zrle.js +13 -15
- package/lib/deflator.js +12 -14
- package/lib/display.js +26 -24
- package/lib/encodings.js +2 -2
- package/lib/inflator.js +12 -14
- package/lib/input/domkeytable.js +1 -2
- package/lib/input/fixedkeys.js +2 -3
- package/lib/input/gesturehandler.js +5 -6
- package/lib/input/keyboard.js +33 -24
- package/lib/input/keysym.js +2 -3
- package/lib/input/keysymdef.js +2 -3
- package/lib/input/util.js +3 -3
- package/lib/input/vkeys.js +2 -3
- package/lib/input/xtscancodes.js +2 -3
- package/lib/ra2.js +89 -85
- package/lib/rfb.js +248 -290
- package/lib/util/browser.js +8 -11
- package/lib/util/cursor.js +9 -10
- package/lib/util/eventtarget.js +5 -6
- package/lib/util/logging.js +4 -9
- package/lib/vendor/pako/lib/utils/common.js +3 -6
- package/lib/vendor/pako/lib/zlib/constants.js +2 -3
- package/lib/vendor/pako/lib/zlib/deflate.js +24 -58
- package/lib/vendor/pako/lib/zlib/inffast.js +0 -2
- package/lib/vendor/pako/lib/zlib/inflate.js +17 -41
- package/lib/vendor/pako/lib/zlib/inftrees.js +3 -5
- package/lib/vendor/pako/lib/zlib/messages.js +2 -3
- package/lib/vendor/pako/lib/zlib/trees.js +3 -10
- package/lib/websock.js +97 -97
- package/package.json +1 -7
package/core/decoders/hextile.js
CHANGED
|
@@ -31,10 +31,7 @@ export default class HextileDecoder {
|
|
|
31
31
|
return false;
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
let
|
|
35
|
-
let rQi = sock.rQi;
|
|
36
|
-
|
|
37
|
-
let subencoding = rQ[rQi]; // Peek
|
|
34
|
+
let subencoding = sock.rQpeek8();
|
|
38
35
|
if (subencoding > 30) { // Raw
|
|
39
36
|
throw new Error("Illegal hextile subencoding (subencoding: " +
|
|
40
37
|
subencoding + ")");
|
|
@@ -65,7 +62,7 @@ export default class HextileDecoder {
|
|
|
65
62
|
return false;
|
|
66
63
|
}
|
|
67
64
|
|
|
68
|
-
let subrects =
|
|
65
|
+
let subrects = sock.rQpeekBytes(bytes).at(-1);
|
|
69
66
|
if (subencoding & 0x10) { // SubrectsColoured
|
|
70
67
|
bytes += subrects * (4 + 2);
|
|
71
68
|
} else {
|
|
@@ -79,7 +76,7 @@ export default class HextileDecoder {
|
|
|
79
76
|
}
|
|
80
77
|
|
|
81
78
|
// We know the encoding and have a whole tile
|
|
82
|
-
|
|
79
|
+
sock.rQshift8();
|
|
83
80
|
if (subencoding === 0) {
|
|
84
81
|
if (this._lastsubencoding & 0x01) {
|
|
85
82
|
// Weird: ignore blanks are RAW
|
|
@@ -89,42 +86,36 @@ export default class HextileDecoder {
|
|
|
89
86
|
}
|
|
90
87
|
} else if (subencoding & 0x01) { // Raw
|
|
91
88
|
let pixels = tw * th;
|
|
89
|
+
let data = sock.rQshiftBytes(pixels * 4, false);
|
|
92
90
|
// Max sure the image is fully opaque
|
|
93
91
|
for (let i = 0;i < pixels;i++) {
|
|
94
|
-
|
|
92
|
+
data[i * 4 + 3] = 255;
|
|
95
93
|
}
|
|
96
|
-
display.blitImage(tx, ty, tw, th,
|
|
97
|
-
rQi += bytes - 1;
|
|
94
|
+
display.blitImage(tx, ty, tw, th, data, 0);
|
|
98
95
|
} else {
|
|
99
96
|
if (subencoding & 0x02) { // Background
|
|
100
|
-
this._background =
|
|
101
|
-
rQi += 4;
|
|
97
|
+
this._background = new Uint8Array(sock.rQshiftBytes(4));
|
|
102
98
|
}
|
|
103
99
|
if (subencoding & 0x04) { // Foreground
|
|
104
|
-
this._foreground =
|
|
105
|
-
rQi += 4;
|
|
100
|
+
this._foreground = new Uint8Array(sock.rQshiftBytes(4));
|
|
106
101
|
}
|
|
107
102
|
|
|
108
103
|
this._startTile(tx, ty, tw, th, this._background);
|
|
109
104
|
if (subencoding & 0x08) { // AnySubrects
|
|
110
|
-
let subrects =
|
|
111
|
-
rQi++;
|
|
105
|
+
let subrects = sock.rQshift8();
|
|
112
106
|
|
|
113
107
|
for (let s = 0; s < subrects; s++) {
|
|
114
108
|
let color;
|
|
115
109
|
if (subencoding & 0x10) { // SubrectsColoured
|
|
116
|
-
color =
|
|
117
|
-
rQi += 4;
|
|
110
|
+
color = sock.rQshiftBytes(4);
|
|
118
111
|
} else {
|
|
119
112
|
color = this._foreground;
|
|
120
113
|
}
|
|
121
|
-
const xy =
|
|
122
|
-
rQi++;
|
|
114
|
+
const xy = sock.rQshift8();
|
|
123
115
|
const sx = (xy >> 4);
|
|
124
116
|
const sy = (xy & 0x0f);
|
|
125
117
|
|
|
126
|
-
const wh =
|
|
127
|
-
rQi++;
|
|
118
|
+
const wh = sock.rQshift8();
|
|
128
119
|
const sw = (wh >> 4) + 1;
|
|
129
120
|
const sh = (wh & 0x0f) + 1;
|
|
130
121
|
|
|
@@ -133,7 +124,6 @@ export default class HextileDecoder {
|
|
|
133
124
|
}
|
|
134
125
|
this._finishTile(display);
|
|
135
126
|
}
|
|
136
|
-
sock.rQi = rQi;
|
|
137
127
|
this._lastsubencoding = subencoding;
|
|
138
128
|
this._tiles--;
|
|
139
129
|
}
|
package/core/decoders/jpeg.js
CHANGED
|
@@ -11,131 +11,136 @@ export default class JPEGDecoder {
|
|
|
11
11
|
constructor() {
|
|
12
12
|
// RealVNC will reuse the quantization tables
|
|
13
13
|
// and Huffman tables, so we need to cache them.
|
|
14
|
-
this._quantTables = [];
|
|
15
|
-
this._huffmanTables = [];
|
|
16
14
|
this._cachedQuantTables = [];
|
|
17
15
|
this._cachedHuffmanTables = [];
|
|
18
16
|
|
|
19
|
-
this._jpegLength = 0;
|
|
20
17
|
this._segments = [];
|
|
21
18
|
}
|
|
22
19
|
|
|
23
20
|
decodeRect(x, y, width, height, sock, display, depth) {
|
|
24
21
|
// A rect of JPEG encodings is simply a JPEG file
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
if (this._quantTables.length != 0 && this._huffmanTables.length != 0) {
|
|
30
|
-
// If there are quantization tables and Huffman tables in the JPEG
|
|
31
|
-
// image, we can directly render it.
|
|
32
|
-
display.imageRect(x, y, width, height, "image/jpeg", data);
|
|
33
|
-
return true;
|
|
34
|
-
} else {
|
|
35
|
-
// Otherwise we need to insert cached tables.
|
|
36
|
-
const sofIndex = this._segments.findIndex(
|
|
37
|
-
x => x[1] == 0xC0 || x[1] == 0xC2
|
|
38
|
-
);
|
|
39
|
-
if (sofIndex == -1) {
|
|
40
|
-
throw new Error("Illegal JPEG image without SOF");
|
|
22
|
+
while (true) {
|
|
23
|
+
let segment = this._readSegment(sock);
|
|
24
|
+
if (segment === null) {
|
|
25
|
+
return false;
|
|
41
26
|
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
segments.push(this._segments[sofIndex]);
|
|
47
|
-
segments = segments.concat(this._huffmanTables.length ?
|
|
48
|
-
this._huffmanTables :
|
|
49
|
-
this._cachedHuffmanTables,
|
|
50
|
-
this._segments.slice(sofIndex + 1));
|
|
51
|
-
let length = 0;
|
|
52
|
-
for (let i = 0; i < segments.length; i++) {
|
|
53
|
-
length += segments[i].length;
|
|
27
|
+
this._segments.push(segment);
|
|
28
|
+
// End of image?
|
|
29
|
+
if (segment[1] === 0xD9) {
|
|
30
|
+
break;
|
|
54
31
|
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
let huffmanTables = [];
|
|
35
|
+
let quantTables = [];
|
|
36
|
+
for (let segment of this._segments) {
|
|
37
|
+
let type = segment[1];
|
|
38
|
+
if (type === 0xC4) {
|
|
39
|
+
// Huffman tables
|
|
40
|
+
huffmanTables.push(segment);
|
|
41
|
+
} else if (type === 0xDB) {
|
|
42
|
+
// Quantization tables
|
|
43
|
+
quantTables.push(segment);
|
|
60
44
|
}
|
|
61
|
-
display.imageRect(x, y, width, height, "image/jpeg", data);
|
|
62
|
-
return true;
|
|
63
45
|
}
|
|
64
|
-
}
|
|
65
46
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
47
|
+
const sofIndex = this._segments.findIndex(
|
|
48
|
+
x => x[1] == 0xC0 || x[1] == 0xC2
|
|
49
|
+
);
|
|
50
|
+
if (sofIndex == -1) {
|
|
51
|
+
throw new Error("Illegal JPEG image without SOF");
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (quantTables.length === 0) {
|
|
55
|
+
this._segments.splice(sofIndex+1, 0,
|
|
56
|
+
...this._cachedQuantTables);
|
|
57
|
+
}
|
|
58
|
+
if (huffmanTables.length === 0) {
|
|
59
|
+
this._segments.splice(sofIndex+1, 0,
|
|
60
|
+
...this._cachedHuffmanTables);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
let length = 0;
|
|
64
|
+
for (let segment of this._segments) {
|
|
65
|
+
length += segment.length;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
let data = new Uint8Array(length);
|
|
69
|
+
length = 0;
|
|
70
|
+
for (let segment of this._segments) {
|
|
71
|
+
data.set(segment, length);
|
|
72
|
+
length += segment.length;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
display.imageRect(x, y, width, height, "image/jpeg", data);
|
|
76
|
+
|
|
77
|
+
if (huffmanTables.length !== 0) {
|
|
78
|
+
this._cachedHuffmanTables = huffmanTables;
|
|
69
79
|
}
|
|
70
|
-
if (
|
|
71
|
-
this.
|
|
80
|
+
if (quantTables.length !== 0) {
|
|
81
|
+
this._cachedQuantTables = quantTables;
|
|
72
82
|
}
|
|
73
|
-
|
|
74
|
-
this._huffmanTables = [];
|
|
83
|
+
|
|
75
84
|
this._segments = [];
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
85
|
+
|
|
86
|
+
return true;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
_readSegment(sock) {
|
|
90
|
+
if (sock.rQwait("JPEG", 2)) {
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
let marker = sock.rQshift8();
|
|
95
|
+
if (marker != 0xFF) {
|
|
96
|
+
throw new Error("Illegal JPEG marker received (byte: " +
|
|
97
|
+
marker + ")");
|
|
98
|
+
}
|
|
99
|
+
let type = sock.rQshift8();
|
|
100
|
+
if (type >= 0xD0 && type <= 0xD9 || type == 0x01) {
|
|
101
|
+
// No length after marker
|
|
102
|
+
return new Uint8Array([marker, type]);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (sock.rQwait("JPEG", 2, 2)) {
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
let length = sock.rQshift16();
|
|
110
|
+
if (length < 2) {
|
|
111
|
+
throw new Error("Illegal JPEG length received (length: " +
|
|
112
|
+
length + ")");
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (sock.rQwait("JPEG", length-2, 4)) {
|
|
116
|
+
return null;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
let extra = 0;
|
|
120
|
+
if (type === 0xDA) {
|
|
121
|
+
// start of scan
|
|
122
|
+
extra += 2;
|
|
123
|
+
while (true) {
|
|
124
|
+
if (sock.rQwait("JPEG", length-2+extra, 4)) {
|
|
125
|
+
return null;
|
|
103
126
|
}
|
|
104
|
-
|
|
105
|
-
|
|
127
|
+
let data = sock.rQpeekBytes(length-2+extra, false);
|
|
128
|
+
if (data.at(-2) === 0xFF && data.at(-1) !== 0x00 &&
|
|
129
|
+
!(data.at(-1) >= 0xD0 && data.at(-1) <= 0xD7)) {
|
|
130
|
+
extra -= 2;
|
|
131
|
+
break;
|
|
106
132
|
}
|
|
107
|
-
|
|
108
|
-
i = j;
|
|
109
|
-
continue;
|
|
110
|
-
} else if (type >= 0xD0 && type < 0xD9 || type == 0x01) {
|
|
111
|
-
// No length after marker
|
|
112
|
-
this._segments.push(buffer.slice(i, j));
|
|
113
|
-
i = j;
|
|
114
|
-
continue;
|
|
115
|
-
}
|
|
116
|
-
if (j + 2 > bufferLength) {
|
|
117
|
-
return false;
|
|
118
|
-
}
|
|
119
|
-
const length = (buffer[j] << 8) + buffer[j+1] - 2;
|
|
120
|
-
if (length < 0) {
|
|
121
|
-
throw new Error("Illegal JPEG length received (length: " +
|
|
122
|
-
length + ")");
|
|
123
|
-
}
|
|
124
|
-
j += 2;
|
|
125
|
-
if (j + length > bufferLength) {
|
|
126
|
-
return false;
|
|
133
|
+
extra++;
|
|
127
134
|
}
|
|
128
|
-
j += length;
|
|
129
|
-
const segment = buffer.slice(i, j);
|
|
130
|
-
if (type == 0xC4) {
|
|
131
|
-
// Huffman tables
|
|
132
|
-
this._huffmanTables.push(segment);
|
|
133
|
-
} else if (type == 0xDB) {
|
|
134
|
-
// Quantization tables
|
|
135
|
-
this._quantTables.push(segment);
|
|
136
|
-
}
|
|
137
|
-
this._segments.push(segment);
|
|
138
|
-
i = j;
|
|
139
135
|
}
|
|
136
|
+
|
|
137
|
+
let segment = new Uint8Array(2 + length + extra);
|
|
138
|
+
segment[0] = marker;
|
|
139
|
+
segment[1] = type;
|
|
140
|
+
segment[2] = length >> 8;
|
|
141
|
+
segment[3] = length;
|
|
142
|
+
segment.set(sock.rQshiftBytes(length-2+extra, false), 4);
|
|
143
|
+
|
|
144
|
+
return segment;
|
|
140
145
|
}
|
|
141
146
|
}
|
package/core/decoders/raw.js
CHANGED
|
@@ -24,41 +24,34 @@ export default class RawDecoder {
|
|
|
24
24
|
const pixelSize = depth == 8 ? 1 : 4;
|
|
25
25
|
const bytesPerLine = width * pixelSize;
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
while (this._lines > 0) {
|
|
28
|
+
if (sock.rQwait("RAW", bytesPerLine)) {
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
30
31
|
|
|
31
|
-
|
|
32
|
-
const currHeight = Math.min(this._lines,
|
|
33
|
-
Math.floor(sock.rQlen / bytesPerLine));
|
|
34
|
-
const pixels = width * currHeight;
|
|
32
|
+
const curY = y + (height - this._lines);
|
|
35
33
|
|
|
36
|
-
|
|
37
|
-
let index = sock.rQi;
|
|
34
|
+
let data = sock.rQshiftBytes(bytesPerLine, false);
|
|
38
35
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
36
|
+
// Convert data if needed
|
|
37
|
+
if (depth == 8) {
|
|
38
|
+
const newdata = new Uint8Array(width * 4);
|
|
39
|
+
for (let i = 0; i < width; i++) {
|
|
40
|
+
newdata[i * 4 + 0] = ((data[i] >> 0) & 0x3) * 255 / 3;
|
|
41
|
+
newdata[i * 4 + 1] = ((data[i] >> 2) & 0x3) * 255 / 3;
|
|
42
|
+
newdata[i * 4 + 2] = ((data[i] >> 4) & 0x3) * 255 / 3;
|
|
43
|
+
newdata[i * 4 + 3] = 255;
|
|
44
|
+
}
|
|
45
|
+
data = newdata;
|
|
47
46
|
}
|
|
48
|
-
data = newdata;
|
|
49
|
-
index = 0;
|
|
50
|
-
}
|
|
51
47
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
48
|
+
// Max sure the image is fully opaque
|
|
49
|
+
for (let i = 0; i < width; i++) {
|
|
50
|
+
data[i * 4 + 3] = 255;
|
|
51
|
+
}
|
|
56
52
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
this._lines -= currHeight;
|
|
60
|
-
if (this._lines > 0) {
|
|
61
|
-
return false;
|
|
53
|
+
display.blitImage(x, curY, width, 1, data, 0);
|
|
54
|
+
this._lines--;
|
|
62
55
|
}
|
|
63
56
|
|
|
64
57
|
return true;
|
package/core/decoders/tight.js
CHANGED
|
@@ -76,12 +76,8 @@ export default class TightDecoder {
|
|
|
76
76
|
return false;
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
display.fillRect(x, y, width, height,
|
|
83
|
-
[rQ[rQi], rQ[rQi + 1], rQ[rQi + 2]], false);
|
|
84
|
-
sock.rQskipBytes(3);
|
|
79
|
+
let pixel = sock.rQshiftBytes(3);
|
|
80
|
+
display.fillRect(x, y, width, height, pixel, false);
|
|
85
81
|
|
|
86
82
|
return true;
|
|
87
83
|
}
|
|
@@ -316,7 +312,7 @@ export default class TightDecoder {
|
|
|
316
312
|
return null;
|
|
317
313
|
}
|
|
318
314
|
|
|
319
|
-
let data = sock.rQshiftBytes(this._len);
|
|
315
|
+
let data = sock.rQshiftBytes(this._len, false);
|
|
320
316
|
this._len = 0;
|
|
321
317
|
|
|
322
318
|
return data;
|
package/core/decoders/zrle.js
CHANGED
package/core/deflator.js
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import { deflateInit, deflate } from "../vendor/pako/lib/zlib/deflate.js";
|
|
10
|
-
import { Z_FULL_FLUSH } from "../vendor/pako/lib/zlib/deflate.js";
|
|
10
|
+
import { Z_FULL_FLUSH, Z_DEFAULT_COMPRESSION } from "../vendor/pako/lib/zlib/deflate.js";
|
|
11
11
|
import ZStream from "../vendor/pako/lib/zlib/zstream.js";
|
|
12
12
|
|
|
13
13
|
export default class Deflator {
|
|
@@ -15,9 +15,8 @@ export default class Deflator {
|
|
|
15
15
|
this.strm = new ZStream();
|
|
16
16
|
this.chunkSize = 1024 * 10 * 10;
|
|
17
17
|
this.outputBuffer = new Uint8Array(this.chunkSize);
|
|
18
|
-
this.windowBits = 5;
|
|
19
18
|
|
|
20
|
-
deflateInit(this.strm,
|
|
19
|
+
deflateInit(this.strm, Z_DEFAULT_COMPRESSION);
|
|
21
20
|
}
|
|
22
21
|
|
|
23
22
|
deflate(inData) {
|
package/core/display.js
CHANGED
|
@@ -15,7 +15,7 @@ export default class Display {
|
|
|
15
15
|
this._drawCtx = null;
|
|
16
16
|
|
|
17
17
|
this._renderQ = []; // queue drawing actions for in-oder rendering
|
|
18
|
-
this.
|
|
18
|
+
this._flushPromise = null;
|
|
19
19
|
|
|
20
20
|
// the full frame buffer (logical canvas) size
|
|
21
21
|
this._fbWidth = 0;
|
|
@@ -61,10 +61,6 @@ export default class Display {
|
|
|
61
61
|
|
|
62
62
|
this._scale = 1.0;
|
|
63
63
|
this._clipViewport = false;
|
|
64
|
-
|
|
65
|
-
// ===== EVENT HANDLERS =====
|
|
66
|
-
|
|
67
|
-
this.onflush = () => {}; // A flush request has finished
|
|
68
64
|
}
|
|
69
65
|
|
|
70
66
|
// ===== PROPERTIES =====
|
|
@@ -306,9 +302,14 @@ export default class Display {
|
|
|
306
302
|
|
|
307
303
|
flush() {
|
|
308
304
|
if (this._renderQ.length === 0) {
|
|
309
|
-
|
|
305
|
+
return Promise.resolve();
|
|
310
306
|
} else {
|
|
311
|
-
this.
|
|
307
|
+
if (this._flushPromise === null) {
|
|
308
|
+
this._flushPromise = new Promise((resolve) => {
|
|
309
|
+
this._flushResolve = resolve;
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
return this._flushPromise;
|
|
312
313
|
}
|
|
313
314
|
}
|
|
314
315
|
|
|
@@ -517,9 +518,11 @@ export default class Display {
|
|
|
517
518
|
}
|
|
518
519
|
}
|
|
519
520
|
|
|
520
|
-
if (this._renderQ.length === 0 &&
|
|
521
|
-
this.
|
|
522
|
-
this.
|
|
521
|
+
if (this._renderQ.length === 0 &&
|
|
522
|
+
this._flushPromise !== null) {
|
|
523
|
+
this._flushResolve();
|
|
524
|
+
this._flushPromise = null;
|
|
525
|
+
this._flushResolve = null;
|
|
523
526
|
}
|
|
524
527
|
}
|
|
525
528
|
}
|
package/core/encodings.js
CHANGED
|
@@ -22,6 +22,7 @@ export const encodings = {
|
|
|
22
22
|
pseudoEncodingLastRect: -224,
|
|
23
23
|
pseudoEncodingCursor: -239,
|
|
24
24
|
pseudoEncodingQEMUExtendedKeyEvent: -258,
|
|
25
|
+
pseudoEncodingQEMULedEvent: -261,
|
|
25
26
|
pseudoEncodingDesktopName: -307,
|
|
26
27
|
pseudoEncodingExtendedDesktopSize: -308,
|
|
27
28
|
pseudoEncodingXvp: -309,
|
package/core/inflator.js
CHANGED
|
@@ -14,9 +14,8 @@ export default class Inflate {
|
|
|
14
14
|
this.strm = new ZStream();
|
|
15
15
|
this.chunkSize = 1024 * 10 * 10;
|
|
16
16
|
this.strm.output = new Uint8Array(this.chunkSize);
|
|
17
|
-
this.windowBits = 5;
|
|
18
17
|
|
|
19
|
-
inflateInit(this.strm
|
|
18
|
+
inflateInit(this.strm);
|
|
20
19
|
}
|
|
21
20
|
|
|
22
21
|
setInput(data) {
|
package/core/input/keyboard.js
CHANGED
|
@@ -36,7 +36,7 @@ export default class Keyboard {
|
|
|
36
36
|
|
|
37
37
|
// ===== PRIVATE METHODS =====
|
|
38
38
|
|
|
39
|
-
_sendKeyEvent(keysym, code, down) {
|
|
39
|
+
_sendKeyEvent(keysym, code, down, numlock = null, capslock = null) {
|
|
40
40
|
if (down) {
|
|
41
41
|
this._keyDownList[code] = keysym;
|
|
42
42
|
} else {
|
|
@@ -48,8 +48,8 @@ export default class Keyboard {
|
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
Log.Debug("onkeyevent " + (down ? "down" : "up") +
|
|
51
|
-
|
|
52
|
-
this.onkeyevent(keysym, code, down);
|
|
51
|
+
", keysym: " + keysym, ", code: " + code, + ", numlock: " + numlock + ", capslock: " + capslock);
|
|
52
|
+
this.onkeyevent(keysym, code, down, numlock, capslock);
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
_getKeyCode(e) {
|
|
@@ -86,6 +86,14 @@ export default class Keyboard {
|
|
|
86
86
|
_handleKeyDown(e) {
|
|
87
87
|
const code = this._getKeyCode(e);
|
|
88
88
|
let keysym = KeyboardUtil.getKeysym(e);
|
|
89
|
+
let numlock = e.getModifierState('NumLock');
|
|
90
|
+
let capslock = e.getModifierState('CapsLock');
|
|
91
|
+
|
|
92
|
+
// getModifierState for NumLock is not supported on mac and ios and always returns false.
|
|
93
|
+
// Set to null to indicate unknown/unsupported instead.
|
|
94
|
+
if (browser.isMac() || browser.isIOS()) {
|
|
95
|
+
numlock = null;
|
|
96
|
+
}
|
|
89
97
|
|
|
90
98
|
// Windows doesn't have a proper AltGr, but handles it using
|
|
91
99
|
// fake Ctrl+Alt. However the remote end might not be Windows,
|
|
@@ -107,7 +115,7 @@ export default class Keyboard {
|
|
|
107
115
|
// key to "AltGraph".
|
|
108
116
|
keysym = KeyTable.XK_ISO_Level3_Shift;
|
|
109
117
|
} else {
|
|
110
|
-
this._sendKeyEvent(KeyTable.XK_Control_L, "ControlLeft", true);
|
|
118
|
+
this._sendKeyEvent(KeyTable.XK_Control_L, "ControlLeft", true, numlock, capslock);
|
|
111
119
|
}
|
|
112
120
|
}
|
|
113
121
|
|
|
@@ -118,8 +126,8 @@ export default class Keyboard {
|
|
|
118
126
|
// If it's a virtual keyboard then it should be
|
|
119
127
|
// sufficient to just send press and release right
|
|
120
128
|
// after each other
|
|
121
|
-
this._sendKeyEvent(keysym, code, true);
|
|
122
|
-
this._sendKeyEvent(keysym, code, false);
|
|
129
|
+
this._sendKeyEvent(keysym, code, true, numlock, capslock);
|
|
130
|
+
this._sendKeyEvent(keysym, code, false, numlock, capslock);
|
|
123
131
|
}
|
|
124
132
|
|
|
125
133
|
stopEvent(e);
|
|
@@ -157,8 +165,8 @@ export default class Keyboard {
|
|
|
157
165
|
// while meta is held down
|
|
158
166
|
if ((browser.isMac() || browser.isIOS()) &&
|
|
159
167
|
(e.metaKey && code !== 'MetaLeft' && code !== 'MetaRight')) {
|
|
160
|
-
this._sendKeyEvent(keysym, code, true);
|
|
161
|
-
this._sendKeyEvent(keysym, code, false);
|
|
168
|
+
this._sendKeyEvent(keysym, code, true, numlock, capslock);
|
|
169
|
+
this._sendKeyEvent(keysym, code, false, numlock, capslock);
|
|
162
170
|
stopEvent(e);
|
|
163
171
|
return;
|
|
164
172
|
}
|
|
@@ -168,8 +176,8 @@ export default class Keyboard {
|
|
|
168
176
|
// which toggles on each press, but not on release. So pretend
|
|
169
177
|
// it was a quick press and release of the button.
|
|
170
178
|
if ((browser.isMac() || browser.isIOS()) && (code === 'CapsLock')) {
|
|
171
|
-
this._sendKeyEvent(KeyTable.XK_Caps_Lock, 'CapsLock', true);
|
|
172
|
-
this._sendKeyEvent(KeyTable.XK_Caps_Lock, 'CapsLock', false);
|
|
179
|
+
this._sendKeyEvent(KeyTable.XK_Caps_Lock, 'CapsLock', true, numlock, capslock);
|
|
180
|
+
this._sendKeyEvent(KeyTable.XK_Caps_Lock, 'CapsLock', false, numlock, capslock);
|
|
173
181
|
stopEvent(e);
|
|
174
182
|
return;
|
|
175
183
|
}
|
|
@@ -182,8 +190,8 @@ export default class Keyboard {
|
|
|
182
190
|
KeyTable.XK_Hiragana,
|
|
183
191
|
KeyTable.XK_Romaji ];
|
|
184
192
|
if (browser.isWindows() && jpBadKeys.includes(keysym)) {
|
|
185
|
-
this._sendKeyEvent(keysym, code, true);
|
|
186
|
-
this._sendKeyEvent(keysym, code, false);
|
|
193
|
+
this._sendKeyEvent(keysym, code, true, numlock, capslock);
|
|
194
|
+
this._sendKeyEvent(keysym, code, false, numlock, capslock);
|
|
187
195
|
stopEvent(e);
|
|
188
196
|
return;
|
|
189
197
|
}
|
|
@@ -199,7 +207,7 @@ export default class Keyboard {
|
|
|
199
207
|
return;
|
|
200
208
|
}
|
|
201
209
|
|
|
202
|
-
this._sendKeyEvent(keysym, code, true);
|
|
210
|
+
this._sendKeyEvent(keysym, code, true, numlock, capslock);
|
|
203
211
|
}
|
|
204
212
|
|
|
205
213
|
_handleKeyUp(e) {
|