@novnc/novnc 1.3.0 → 1.4.0-beta
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/AUTHORS +2 -2
- package/LICENSE.txt +1 -1
- package/README.md +23 -7
- package/core/decoders/jpeg.js +141 -0
- package/core/decoders/raw.js +1 -1
- package/core/decoders/zrle.js +185 -0
- package/core/des.js +1 -1
- package/core/display.js +12 -0
- package/core/encodings.js +4 -0
- package/core/input/keyboard.js +10 -0
- package/core/ra2.js +567 -0
- package/core/rfb.js +469 -84
- package/core/util/browser.js +56 -7
- package/core/util/cursor.js +4 -0
- package/core/util/md5.js +79 -0
- package/docs/API.md +318 -157
- package/lib/base64.js +20 -34
- package/lib/decoders/copyrect.js +5 -12
- package/lib/decoders/hextile.js +17 -47
- package/lib/decoders/jpeg.js +149 -0
- package/lib/decoders/raw.js +10 -23
- package/lib/decoders/rre.js +5 -16
- package/lib/decoders/tight.js +13 -79
- package/lib/decoders/tightpng.js +8 -28
- package/lib/decoders/zrle.js +188 -0
- package/lib/deflator.js +9 -23
- package/lib/des.js +24 -37
- package/lib/display.js +62 -108
- package/lib/encodings.js +7 -8
- package/lib/inflator.js +6 -19
- package/lib/input/domkeytable.js +77 -48
- package/lib/input/fixedkeys.js +8 -3
- package/lib/input/gesturehandler.js +86 -153
- package/lib/input/keyboard.js +62 -91
- package/lib/input/keysym.js +14 -270
- package/lib/input/keysymdef.js +5 -7
- package/lib/input/util.js +43 -85
- package/lib/input/vkeys.js +0 -3
- package/lib/input/xtscancodes.js +1 -168
- package/lib/ra2.js +1005 -0
- package/lib/rfb.js +795 -923
- package/lib/util/browser.js +66 -29
- package/lib/util/cursor.js +29 -66
- package/lib/util/element.js +3 -5
- package/lib/util/events.js +23 -30
- package/lib/util/eventtarget.js +5 -14
- package/lib/util/int.js +1 -2
- package/lib/util/logging.js +1 -19
- package/lib/util/md5.js +77 -0
- package/lib/util/strings.js +3 -5
- package/lib/vendor/pako/lib/utils/common.js +8 -17
- package/lib/vendor/pako/lib/zlib/adler32.js +3 -7
- package/lib/vendor/pako/lib/zlib/constants.js +2 -5
- package/lib/vendor/pako/lib/zlib/crc32.js +5 -12
- package/lib/vendor/pako/lib/zlib/deflate.js +213 -618
- package/lib/vendor/pako/lib/zlib/gzheader.js +1 -13
- package/lib/vendor/pako/lib/zlib/inffast.js +60 -176
- package/lib/vendor/pako/lib/zlib/inflate.js +398 -888
- package/lib/vendor/pako/lib/zlib/inftrees.js +63 -169
- package/lib/vendor/pako/lib/zlib/messages.js +1 -11
- package/lib/vendor/pako/lib/zlib/trees.js +246 -588
- package/lib/vendor/pako/lib/zlib/zstream.js +2 -18
- package/lib/websock.js +37 -88
- package/package.json +32 -35
package/AUTHORS
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
maintainers:
|
|
2
|
-
- Joel Martin (@kanaka)
|
|
3
|
-
- Solly Ross (@directxman12)
|
|
4
2
|
- Samuel Mannehed for Cendio AB (@samhed)
|
|
5
3
|
- Pierre Ossman for Cendio AB (@CendioOssman)
|
|
6
4
|
maintainersEmeritus:
|
|
5
|
+
- Joel Martin (@kanaka)
|
|
6
|
+
- Solly Ross (@directxman12)
|
|
7
7
|
- @astrand
|
|
8
8
|
contributors:
|
|
9
9
|
# There are a bunch of people that should be here.
|
package/LICENSE.txt
CHANGED
package/README.md
CHANGED
|
@@ -65,10 +65,14 @@ Please tweet [@noVNC](http://www.twitter.com/noVNC) if you do.
|
|
|
65
65
|
### Features
|
|
66
66
|
|
|
67
67
|
* Supports all modern browsers including mobile (iOS, Android)
|
|
68
|
-
* Supported
|
|
68
|
+
* Supported authentication methods: none, classical VNC, RealVNC's
|
|
69
|
+
RSA-AES, Tight, VeNCrypt Plain, XVP, Apple's Diffie-Hellman,
|
|
70
|
+
UltraVNC's MSLogonII
|
|
71
|
+
* Supported VNC encodings: raw, copyrect, rre, hextile, tight, tightPNG,
|
|
72
|
+
ZRLE, JPEG
|
|
69
73
|
* Supports scaling, clipping and resizing the desktop
|
|
70
74
|
* Local cursor rendering
|
|
71
|
-
* Clipboard copy/paste
|
|
75
|
+
* Clipboard copy/paste with full Unicode support
|
|
72
76
|
* Translations
|
|
73
77
|
* Touch gestures for emulating common mouse actions
|
|
74
78
|
* Licensed mainly under the [MPL 2.0](http://www.mozilla.org/MPL/2.0/), see
|
|
@@ -113,8 +117,13 @@ proxy.
|
|
|
113
117
|
used to specify the location of a running VNC server:
|
|
114
118
|
|
|
115
119
|
`./utils/novnc_proxy --vnc localhost:5901`
|
|
120
|
+
|
|
121
|
+
* If you don't need to expose the web server to public internet, you can
|
|
122
|
+
bind to localhost:
|
|
123
|
+
|
|
124
|
+
`./utils/novnc_proxy --vnc localhost:5901 --listen localhost:6081`
|
|
116
125
|
|
|
117
|
-
* Point your browser to the cut-and-paste URL that is output by the `
|
|
126
|
+
* Point your browser to the cut-and-paste URL that is output by the `novnc_proxy`
|
|
118
127
|
script. Hit the Connect button, enter a password if the VNC server has one
|
|
119
128
|
configured, and enjoy!
|
|
120
129
|
|
|
@@ -123,13 +132,17 @@ Running the command below will install the latest release of noVNC from Snap:
|
|
|
123
132
|
|
|
124
133
|
`sudo snap install novnc`
|
|
125
134
|
|
|
126
|
-
#### Running noVNC
|
|
135
|
+
#### Running noVNC from Snap Directly
|
|
127
136
|
|
|
128
137
|
You can run the Snap-package installed novnc directly with, for example:
|
|
129
138
|
|
|
130
139
|
`novnc --listen 6081 --vnc localhost:5901 # /snap/bin/novnc if /snap/bin is not in your PATH`
|
|
131
140
|
|
|
132
|
-
|
|
141
|
+
If you want to use certificate files, due to standard Snap confinement restrictions you need to have them in the /home/\<user\>/snap/novnc/current/ directory. If your username is jsmith an example command would be:
|
|
142
|
+
|
|
143
|
+
`novnc --listen 8443 --cert ~jsmith/snap/novnc/current/self.crt --key ~jsmith/snap/novnc/current/self.key --vnc ubuntu.example.com:5901`
|
|
144
|
+
|
|
145
|
+
#### Running noVNC from Snap as a Service (Daemon)
|
|
133
146
|
The Snap package also has the capability to run a 'novnc' service which can be
|
|
134
147
|
configured to listen on multiple ports connecting to multiple VNC servers
|
|
135
148
|
(effectively a service runing multiple instances of novnc).
|
|
@@ -194,15 +207,18 @@ See [AUTHORS](AUTHORS) for a (full-ish) list of authors. If you're not on
|
|
|
194
207
|
that list and you think you should be, feel free to send a PR to fix that.
|
|
195
208
|
|
|
196
209
|
* Core team:
|
|
197
|
-
* [Joel Martin](https://github.com/kanaka)
|
|
198
210
|
* [Samuel Mannehed](https://github.com/samhed) (Cendio)
|
|
199
|
-
* [Solly Ross](https://github.com/DirectXMan12) (Red Hat / OpenStack)
|
|
200
211
|
* [Pierre Ossman](https://github.com/CendioOssman) (Cendio)
|
|
201
212
|
|
|
213
|
+
* Previous core contributors:
|
|
214
|
+
* [Joel Martin](https://github.com/kanaka) (Project founder)
|
|
215
|
+
* [Solly Ross](https://github.com/DirectXMan12) (Red Hat / OpenStack)
|
|
216
|
+
|
|
202
217
|
* Notable contributions:
|
|
203
218
|
* UI and Icons : Pierre Ossman, Chris Gordon
|
|
204
219
|
* Original Logo : Michael Sersen
|
|
205
220
|
* tight encoding : Michael Tinglof (Mercuri.ca)
|
|
221
|
+
* RealVNC RSA AES authentication : USTC Vlab Team
|
|
206
222
|
|
|
207
223
|
* Included libraries:
|
|
208
224
|
* base64 : Martijn Pieters (Digital Creations 2), Samuel Sieb (sieb.net)
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* noVNC: HTML5 VNC client
|
|
3
|
+
* Copyright (C) 2019 The noVNC Authors
|
|
4
|
+
* Licensed under MPL 2.0 (see LICENSE.txt)
|
|
5
|
+
*
|
|
6
|
+
* See README.md for usage and integration instructions.
|
|
7
|
+
*
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
export default class JPEGDecoder {
|
|
11
|
+
constructor() {
|
|
12
|
+
// RealVNC will reuse the quantization tables
|
|
13
|
+
// and Huffman tables, so we need to cache them.
|
|
14
|
+
this._quantTables = [];
|
|
15
|
+
this._huffmanTables = [];
|
|
16
|
+
this._cachedQuantTables = [];
|
|
17
|
+
this._cachedHuffmanTables = [];
|
|
18
|
+
|
|
19
|
+
this._jpegLength = 0;
|
|
20
|
+
this._segments = [];
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
decodeRect(x, y, width, height, sock, display, depth) {
|
|
24
|
+
// A rect of JPEG encodings is simply a JPEG file
|
|
25
|
+
if (!this._parseJPEG(sock.rQslice(0))) {
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
const data = sock.rQshiftBytes(this._jpegLength);
|
|
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");
|
|
41
|
+
}
|
|
42
|
+
let segments = this._segments.slice(0, sofIndex);
|
|
43
|
+
segments = segments.concat(this._quantTables.length ?
|
|
44
|
+
this._quantTables :
|
|
45
|
+
this._cachedQuantTables);
|
|
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;
|
|
54
|
+
}
|
|
55
|
+
const data = new Uint8Array(length);
|
|
56
|
+
length = 0;
|
|
57
|
+
for (let i = 0; i < segments.length; i++) {
|
|
58
|
+
data.set(segments[i], length);
|
|
59
|
+
length += segments[i].length;
|
|
60
|
+
}
|
|
61
|
+
display.imageRect(x, y, width, height, "image/jpeg", data);
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
_parseJPEG(buffer) {
|
|
67
|
+
if (this._quantTables.length != 0) {
|
|
68
|
+
this._cachedQuantTables = this._quantTables;
|
|
69
|
+
}
|
|
70
|
+
if (this._huffmanTables.length != 0) {
|
|
71
|
+
this._cachedHuffmanTables = this._huffmanTables;
|
|
72
|
+
}
|
|
73
|
+
this._quantTables = [];
|
|
74
|
+
this._huffmanTables = [];
|
|
75
|
+
this._segments = [];
|
|
76
|
+
let i = 0;
|
|
77
|
+
let bufferLength = buffer.length;
|
|
78
|
+
while (true) {
|
|
79
|
+
let j = i;
|
|
80
|
+
if (j + 2 > bufferLength) {
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
if (buffer[j] != 0xFF) {
|
|
84
|
+
throw new Error("Illegal JPEG marker received (byte: " +
|
|
85
|
+
buffer[j] + ")");
|
|
86
|
+
}
|
|
87
|
+
const type = buffer[j+1];
|
|
88
|
+
j += 2;
|
|
89
|
+
if (type == 0xD9) {
|
|
90
|
+
this._jpegLength = j;
|
|
91
|
+
this._segments.push(buffer.slice(i, j));
|
|
92
|
+
return true;
|
|
93
|
+
} else if (type == 0xDA) {
|
|
94
|
+
// start of scan
|
|
95
|
+
let hasFoundEndOfScan = false;
|
|
96
|
+
for (let k = j + 3; k + 1 < bufferLength; k++) {
|
|
97
|
+
if (buffer[k] == 0xFF && buffer[k+1] != 0x00 &&
|
|
98
|
+
!(buffer[k+1] >= 0xD0 && buffer[k+1] <= 0xD7)) {
|
|
99
|
+
j = k;
|
|
100
|
+
hasFoundEndOfScan = true;
|
|
101
|
+
break;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
if (!hasFoundEndOfScan) {
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
this._segments.push(buffer.slice(i, j));
|
|
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;
|
|
127
|
+
}
|
|
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
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
package/core/decoders/raw.js
CHANGED
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* noVNC: HTML5 VNC client
|
|
3
|
+
* Copyright (C) 2021 The noVNC Authors
|
|
4
|
+
* Licensed under MPL 2.0 (see LICENSE.txt)
|
|
5
|
+
*
|
|
6
|
+
* See README.md for usage and integration instructions.
|
|
7
|
+
*
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import Inflate from "../inflator.js";
|
|
11
|
+
|
|
12
|
+
const ZRLE_TILE_WIDTH = 64;
|
|
13
|
+
const ZRLE_TILE_HEIGHT = 64;
|
|
14
|
+
|
|
15
|
+
export default class ZRLEDecoder {
|
|
16
|
+
constructor() {
|
|
17
|
+
this._length = 0;
|
|
18
|
+
this._inflator = new Inflate();
|
|
19
|
+
|
|
20
|
+
this._pixelBuffer = new Uint8Array(ZRLE_TILE_WIDTH * ZRLE_TILE_HEIGHT * 4);
|
|
21
|
+
this._tileBuffer = new Uint8Array(ZRLE_TILE_WIDTH * ZRLE_TILE_HEIGHT * 4);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
decodeRect(x, y, width, height, sock, display, depth) {
|
|
25
|
+
if (this._length === 0) {
|
|
26
|
+
if (sock.rQwait("ZLib data length", 4)) {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
this._length = sock.rQshift32();
|
|
30
|
+
}
|
|
31
|
+
if (sock.rQwait("Zlib data", this._length)) {
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const data = sock.rQshiftBytes(this._length);
|
|
36
|
+
|
|
37
|
+
this._inflator.setInput(data);
|
|
38
|
+
|
|
39
|
+
for (let ty = y; ty < y + height; ty += ZRLE_TILE_HEIGHT) {
|
|
40
|
+
let th = Math.min(ZRLE_TILE_HEIGHT, y + height - ty);
|
|
41
|
+
|
|
42
|
+
for (let tx = x; tx < x + width; tx += ZRLE_TILE_WIDTH) {
|
|
43
|
+
let tw = Math.min(ZRLE_TILE_WIDTH, x + width - tx);
|
|
44
|
+
|
|
45
|
+
const tileSize = tw * th;
|
|
46
|
+
const subencoding = this._inflator.inflate(1)[0];
|
|
47
|
+
if (subencoding === 0) {
|
|
48
|
+
// raw data
|
|
49
|
+
const data = this._readPixels(tileSize);
|
|
50
|
+
display.blitImage(tx, ty, tw, th, data, 0, false);
|
|
51
|
+
} else if (subencoding === 1) {
|
|
52
|
+
// solid
|
|
53
|
+
const background = this._readPixels(1);
|
|
54
|
+
display.fillRect(tx, ty, tw, th, [background[0], background[1], background[2]]);
|
|
55
|
+
} else if (subencoding >= 2 && subencoding <= 16) {
|
|
56
|
+
const data = this._decodePaletteTile(subencoding, tileSize, tw, th);
|
|
57
|
+
display.blitImage(tx, ty, tw, th, data, 0, false);
|
|
58
|
+
} else if (subencoding === 128) {
|
|
59
|
+
const data = this._decodeRLETile(tileSize);
|
|
60
|
+
display.blitImage(tx, ty, tw, th, data, 0, false);
|
|
61
|
+
} else if (subencoding >= 130 && subencoding <= 255) {
|
|
62
|
+
const data = this._decodeRLEPaletteTile(subencoding - 128, tileSize);
|
|
63
|
+
display.blitImage(tx, ty, tw, th, data, 0, false);
|
|
64
|
+
} else {
|
|
65
|
+
throw new Error('Unknown subencoding: ' + subencoding);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
this._length = 0;
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
_getBitsPerPixelInPalette(paletteSize) {
|
|
74
|
+
if (paletteSize <= 2) {
|
|
75
|
+
return 1;
|
|
76
|
+
} else if (paletteSize <= 4) {
|
|
77
|
+
return 2;
|
|
78
|
+
} else if (paletteSize <= 16) {
|
|
79
|
+
return 4;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
_readPixels(pixels) {
|
|
84
|
+
let data = this._pixelBuffer;
|
|
85
|
+
const buffer = this._inflator.inflate(3*pixels);
|
|
86
|
+
for (let i = 0, j = 0; i < pixels*4; i += 4, j += 3) {
|
|
87
|
+
data[i] = buffer[j];
|
|
88
|
+
data[i + 1] = buffer[j + 1];
|
|
89
|
+
data[i + 2] = buffer[j + 2];
|
|
90
|
+
data[i + 3] = 255; // Add the Alpha
|
|
91
|
+
}
|
|
92
|
+
return data;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
_decodePaletteTile(paletteSize, tileSize, tilew, tileh) {
|
|
96
|
+
const data = this._tileBuffer;
|
|
97
|
+
const palette = this._readPixels(paletteSize);
|
|
98
|
+
const bitsPerPixel = this._getBitsPerPixelInPalette(paletteSize);
|
|
99
|
+
const mask = (1 << bitsPerPixel) - 1;
|
|
100
|
+
|
|
101
|
+
let offset = 0;
|
|
102
|
+
let encoded = this._inflator.inflate(1)[0];
|
|
103
|
+
|
|
104
|
+
for (let y=0; y<tileh; y++) {
|
|
105
|
+
let shift = 8-bitsPerPixel;
|
|
106
|
+
for (let x=0; x<tilew; x++) {
|
|
107
|
+
if (shift<0) {
|
|
108
|
+
shift=8-bitsPerPixel;
|
|
109
|
+
encoded = this._inflator.inflate(1)[0];
|
|
110
|
+
}
|
|
111
|
+
let indexInPalette = (encoded>>shift) & mask;
|
|
112
|
+
|
|
113
|
+
data[offset] = palette[indexInPalette * 4];
|
|
114
|
+
data[offset + 1] = palette[indexInPalette * 4 + 1];
|
|
115
|
+
data[offset + 2] = palette[indexInPalette * 4 + 2];
|
|
116
|
+
data[offset + 3] = palette[indexInPalette * 4 + 3];
|
|
117
|
+
offset += 4;
|
|
118
|
+
shift-=bitsPerPixel;
|
|
119
|
+
}
|
|
120
|
+
if (shift<8-bitsPerPixel && y<tileh-1) {
|
|
121
|
+
encoded = this._inflator.inflate(1)[0];
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return data;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
_decodeRLETile(tileSize) {
|
|
128
|
+
const data = this._tileBuffer;
|
|
129
|
+
let i = 0;
|
|
130
|
+
while (i < tileSize) {
|
|
131
|
+
const pixel = this._readPixels(1);
|
|
132
|
+
const length = this._readRLELength();
|
|
133
|
+
for (let j = 0; j < length; j++) {
|
|
134
|
+
data[i * 4] = pixel[0];
|
|
135
|
+
data[i * 4 + 1] = pixel[1];
|
|
136
|
+
data[i * 4 + 2] = pixel[2];
|
|
137
|
+
data[i * 4 + 3] = pixel[3];
|
|
138
|
+
i++;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return data;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
_decodeRLEPaletteTile(paletteSize, tileSize) {
|
|
145
|
+
const data = this._tileBuffer;
|
|
146
|
+
|
|
147
|
+
// palette
|
|
148
|
+
const palette = this._readPixels(paletteSize);
|
|
149
|
+
|
|
150
|
+
let offset = 0;
|
|
151
|
+
while (offset < tileSize) {
|
|
152
|
+
let indexInPalette = this._inflator.inflate(1)[0];
|
|
153
|
+
let length = 1;
|
|
154
|
+
if (indexInPalette >= 128) {
|
|
155
|
+
indexInPalette -= 128;
|
|
156
|
+
length = this._readRLELength();
|
|
157
|
+
}
|
|
158
|
+
if (indexInPalette > paletteSize) {
|
|
159
|
+
throw new Error('Too big index in palette: ' + indexInPalette + ', palette size: ' + paletteSize);
|
|
160
|
+
}
|
|
161
|
+
if (offset + length > tileSize) {
|
|
162
|
+
throw new Error('Too big rle length in palette mode: ' + length + ', allowed length is: ' + (tileSize - offset));
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
for (let j = 0; j < length; j++) {
|
|
166
|
+
data[offset * 4] = palette[indexInPalette * 4];
|
|
167
|
+
data[offset * 4 + 1] = palette[indexInPalette * 4 + 1];
|
|
168
|
+
data[offset * 4 + 2] = palette[indexInPalette * 4 + 2];
|
|
169
|
+
data[offset * 4 + 3] = palette[indexInPalette * 4 + 3];
|
|
170
|
+
offset++;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
return data;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
_readRLELength() {
|
|
177
|
+
let length = 0;
|
|
178
|
+
let current = 0;
|
|
179
|
+
do {
|
|
180
|
+
current = this._inflator.inflate(1)[0];
|
|
181
|
+
length += current;
|
|
182
|
+
} while (current === 255);
|
|
183
|
+
return length + 1;
|
|
184
|
+
}
|
|
185
|
+
}
|
package/core/des.js
CHANGED
|
@@ -81,7 +81,7 @@
|
|
|
81
81
|
const PC2 = [13,16,10,23, 0, 4, 2,27,14, 5,20, 9,22,18,11, 3,
|
|
82
82
|
25, 7,15, 6,26,19,12, 1,40,51,30,36,46,54,29,39,
|
|
83
83
|
50,44,32,47,43,48,38,55,33,52,45,41,49,35,28,31 ],
|
|
84
|
-
|
|
84
|
+
totrot = [ 1, 2, 4, 6, 8,10,12,14,15,17,19,21,23,25,27,28];
|
|
85
85
|
|
|
86
86
|
const z = 0x0;
|
|
87
87
|
let a,b,c,d,e,f;
|
package/core/display.js
CHANGED
|
@@ -224,6 +224,18 @@ export default class Display {
|
|
|
224
224
|
this.viewportChangePos(0, 0);
|
|
225
225
|
}
|
|
226
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
|
+
|
|
227
239
|
// Track what parts of the visible canvas that need updating
|
|
228
240
|
_damage(x, y, w, h) {
|
|
229
241
|
if (x < this._damageBounds.left) {
|
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
|
}
|
package/core/input/keyboard.js
CHANGED
|
@@ -153,6 +153,16 @@ export default class Keyboard {
|
|
|
153
153
|
keysym = this._keyDownList[code];
|
|
154
154
|
}
|
|
155
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
|
+
|
|
156
166
|
// macOS doesn't send proper key events for modifiers, only
|
|
157
167
|
// state change events. That gets extra confusing for CapsLock
|
|
158
168
|
// which toggles on each press, but not on release. So pretend
|