14165 lines
383 KiB
JavaScript
14165 lines
383 KiB
JavaScript
// core/util/int.js
|
|
function toUnsigned32bit(toConvert) {
|
|
return toConvert >>> 0;
|
|
}
|
|
function toSigned32bit(toConvert) {
|
|
return toConvert | 0;
|
|
}
|
|
|
|
// core/util/logging.js
|
|
var _logLevel = "warn";
|
|
var Debug = () => {
|
|
};
|
|
var Info = () => {
|
|
};
|
|
var Warn = () => {
|
|
};
|
|
var Error2 = () => {
|
|
};
|
|
function initLogging(level) {
|
|
if (typeof level === "undefined") {
|
|
level = _logLevel;
|
|
} else {
|
|
_logLevel = level;
|
|
}
|
|
Debug = Info = Warn = Error2 = () => {
|
|
};
|
|
if (typeof window.console !== "undefined") {
|
|
switch (level) {
|
|
case "debug":
|
|
Debug = console.debug.bind(window.console);
|
|
case "info":
|
|
Info = console.info.bind(window.console);
|
|
case "warn":
|
|
Warn = console.warn.bind(window.console);
|
|
case "error":
|
|
Error2 = console.error.bind(window.console);
|
|
case "none":
|
|
break;
|
|
default:
|
|
throw new window.Error("invalid logging type '" + level + "'");
|
|
}
|
|
}
|
|
}
|
|
initLogging();
|
|
|
|
// core/util/strings.js
|
|
function decodeUTF8(utf8string, allowLatin1 = false) {
|
|
try {
|
|
return decodeURIComponent(escape(utf8string));
|
|
} catch (e2) {
|
|
if (e2 instanceof URIError) {
|
|
if (allowLatin1) {
|
|
return utf8string;
|
|
}
|
|
}
|
|
throw e2;
|
|
}
|
|
}
|
|
function encodeUTF8(DOMString) {
|
|
return unescape(encodeURIComponent(DOMString));
|
|
}
|
|
|
|
// core/base64.js
|
|
var base64_default = {
|
|
/* Convert data (an array of integers) to a Base64 string. */
|
|
toBase64Table: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".split(""),
|
|
base64Pad: "=",
|
|
encode(data) {
|
|
"use strict";
|
|
let result = "";
|
|
const length = data.length;
|
|
const lengthpad = length % 3;
|
|
for (let i = 0; i < length - 2; i += 3) {
|
|
result += this.toBase64Table[data[i] >> 2];
|
|
result += this.toBase64Table[((data[i] & 3) << 4) + (data[i + 1] >> 4)];
|
|
result += this.toBase64Table[((data[i + 1] & 15) << 2) + (data[i + 2] >> 6)];
|
|
result += this.toBase64Table[data[i + 2] & 63];
|
|
}
|
|
const j = length - lengthpad;
|
|
if (lengthpad === 2) {
|
|
result += this.toBase64Table[data[j] >> 2];
|
|
result += this.toBase64Table[((data[j] & 3) << 4) + (data[j + 1] >> 4)];
|
|
result += this.toBase64Table[(data[j + 1] & 15) << 2];
|
|
result += this.toBase64Table[64];
|
|
} else if (lengthpad === 1) {
|
|
result += this.toBase64Table[data[j] >> 2];
|
|
result += this.toBase64Table[(data[j] & 3) << 4];
|
|
result += this.toBase64Table[64];
|
|
result += this.toBase64Table[64];
|
|
}
|
|
return result;
|
|
},
|
|
/* Convert Base64 data to a string */
|
|
/* eslint-disable comma-spacing */
|
|
toBinaryTable: [
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
62,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
63,
|
|
52,
|
|
53,
|
|
54,
|
|
55,
|
|
56,
|
|
57,
|
|
58,
|
|
59,
|
|
60,
|
|
61,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
0,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
0,
|
|
1,
|
|
2,
|
|
3,
|
|
4,
|
|
5,
|
|
6,
|
|
7,
|
|
8,
|
|
9,
|
|
10,
|
|
11,
|
|
12,
|
|
13,
|
|
14,
|
|
15,
|
|
16,
|
|
17,
|
|
18,
|
|
19,
|
|
20,
|
|
21,
|
|
22,
|
|
23,
|
|
24,
|
|
25,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
26,
|
|
27,
|
|
28,
|
|
29,
|
|
30,
|
|
31,
|
|
32,
|
|
33,
|
|
34,
|
|
35,
|
|
36,
|
|
37,
|
|
38,
|
|
39,
|
|
40,
|
|
41,
|
|
42,
|
|
43,
|
|
44,
|
|
45,
|
|
46,
|
|
47,
|
|
48,
|
|
49,
|
|
50,
|
|
51,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1
|
|
],
|
|
/* eslint-enable comma-spacing */
|
|
decode(data, offset = 0) {
|
|
let dataLength = data.indexOf("=") - offset;
|
|
if (dataLength < 0) {
|
|
dataLength = data.length - offset;
|
|
}
|
|
const resultLength = (dataLength >> 2) * 3 + Math.floor(dataLength % 4 / 1.5);
|
|
const result = new Array(resultLength);
|
|
let leftbits = 0;
|
|
let leftdata = 0;
|
|
for (let idx = 0, i = offset; i < data.length; i++) {
|
|
const c2 = this.toBinaryTable[data.charCodeAt(i) & 127];
|
|
const padding = data.charAt(i) === this.base64Pad;
|
|
if (c2 === -1) {
|
|
Error2("Illegal character code " + data.charCodeAt(i) + " at position " + i);
|
|
continue;
|
|
}
|
|
leftdata = leftdata << 6 | c2;
|
|
leftbits += 6;
|
|
if (leftbits >= 8) {
|
|
leftbits -= 8;
|
|
if (!padding) {
|
|
result[idx++] = leftdata >> leftbits & 255;
|
|
}
|
|
leftdata &= (1 << leftbits) - 1;
|
|
}
|
|
}
|
|
if (leftbits) {
|
|
const err2 = new Error("Corrupted base64 string");
|
|
err2.name = "Base64-Error";
|
|
throw err2;
|
|
}
|
|
return result;
|
|
}
|
|
};
|
|
|
|
// core/util/browser.js
|
|
async function browserAsyncClipboardSupport() {
|
|
if (!(navigator?.permissions?.query && navigator?.clipboard?.writeText && navigator?.clipboard?.readText)) {
|
|
return "unsupported";
|
|
}
|
|
try {
|
|
const writePerm = await navigator.permissions.query(
|
|
{ name: "clipboard-write", allowWithoutGesture: true }
|
|
);
|
|
const readPerm = await navigator.permissions.query(
|
|
{ name: "clipboard-read", allowWithoutGesture: false }
|
|
);
|
|
if (writePerm.state === "denied" || readPerm.state === "denied") {
|
|
return "denied";
|
|
}
|
|
if ((writePerm.state === "granted" || writePerm.state === "prompt") && (readPerm.state === "granted" || readPerm.state === "prompt")) {
|
|
return "available";
|
|
}
|
|
} catch {
|
|
return "unsupported";
|
|
}
|
|
return "unsupported";
|
|
}
|
|
var isTouchDevice = "ontouchstart" in document.documentElement || // required for Chrome debugger
|
|
document.ontouchstart !== void 0 || // required for MS Surface
|
|
navigator.maxTouchPoints > 0 || navigator.msMaxTouchPoints > 0;
|
|
window.addEventListener("touchstart", function onFirstTouch() {
|
|
isTouchDevice = true;
|
|
window.removeEventListener("touchstart", onFirstTouch, false);
|
|
}, false);
|
|
var dragThreshold = 10 * (window.devicePixelRatio || 1);
|
|
var _supportsCursorURIs = false;
|
|
try {
|
|
const target = document.createElement("canvas");
|
|
target.style.cursor = 'url("data:image/x-icon;base64,AAACAAEACAgAAAIAAgA4AQAAFgAAACgAAAAIAAAAEAAAAAEAIAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////AAAAAAAAAAAAAAAAAAAAAA==") 2 2, default';
|
|
if (target.style.cursor.indexOf("url") === 0) {
|
|
Info("Data URI scheme cursor supported");
|
|
_supportsCursorURIs = true;
|
|
} else {
|
|
Warn("Data URI scheme cursor not supported");
|
|
}
|
|
} catch (exc) {
|
|
Error2("Data URI scheme cursor test exception: " + exc);
|
|
}
|
|
var supportsCursorURIs = _supportsCursorURIs;
|
|
var _hasScrollbarGutter = true;
|
|
try {
|
|
const container = document.createElement("div");
|
|
container.style.visibility = "hidden";
|
|
container.style.overflow = "scroll";
|
|
document.body.appendChild(container);
|
|
const child = document.createElement("div");
|
|
container.appendChild(child);
|
|
const scrollbarWidth = container.offsetWidth - child.offsetWidth;
|
|
container.parentNode.removeChild(container);
|
|
_hasScrollbarGutter = scrollbarWidth != 0;
|
|
} catch (exc) {
|
|
Error2("Scrollbar test exception: " + exc);
|
|
}
|
|
var supportsWebCodecsH264Decode = false;
|
|
async function _checkWebCodecsH264DecodeSupport() {
|
|
if (!("VideoDecoder" in window)) {
|
|
return false;
|
|
}
|
|
const config = {
|
|
codec: "avc1.42401f",
|
|
codedWidth: 1920,
|
|
codedHeight: 1080,
|
|
optimizeForLatency: true
|
|
};
|
|
let support = await VideoDecoder.isConfigSupported(config);
|
|
if (!support.supported) {
|
|
return false;
|
|
}
|
|
const data = new Uint8Array(base64_default.decode(
|
|
"AAAAAWdCwBTZnpuAgICgAAADACAAAAZB4oVNAAAAAWjJYyyAAAABBgX//4HcRem95tlIt5Ys2CDZI+7veDI2NCAtIGNvcmUgMTY0IHIzMTA4IDMxZTE5ZjkgLSBILjI2NC9NUEVHLTQgQVZDIGNvZGVjIC0gQ29weWxlZnQgMjAwMy0yMDIzIC0gaHR0cDovL3d3dy52aWRlb2xhbi5vcmcveDI2NC5odG1sIC0gb3B0aW9uczogY2FiYWM9MCByZWY9NSBkZWJsb2NrPTE6MDowIGFuYWx5c2U9MHgxOjB4MTExIG1lPWhleCBzdWJtZT04IHBzeT0xIHBzeV9yZD0xLjAwOjAuMDAgbWl4ZWRfcmVmPTEgbWVfcmFuZ2U9MTYgY2hyb21hX21lPTEgdHJlbGxpcz0yIDh4OGRjdD0wIGNxbT0wIGRlYWR6b25lPTIxLDExIGZhc3RfcHNraXA9MSBjaHJvbWFfcXBfb2Zmc2V0PS0yIHRocmVhZHM9MSBsb29rYWhlYWRfdGhyZWFkcz0xIHNsaWNlZF90aHJlYWRzPTAgbnI9MCBkZWNpbWF0ZT0xIGludGVybGFjZWQ9MCBibHVyYXlfY29tcGF0PTAgY29uc3RyYWluZWRfaW50cmE9MCBiZnJhbWVzPTAgd2VpZ2h0cD0wIGtleWludD1pbmZpbml0ZSBrZXlpbnRfbWluPTI1IHNjZW5lY3V0PTQwIGludHJhX3JlZnJlc2g9MCByY19sb29rYWhlYWQ9NTAgcmM9YWJyIG1idHJlZT0xIGJpdHJhdGU9NDAwIHJhdGV0b2w9MS4wIHFjb21wPTAuNjAgcXBtaW49MCBxcG1heD02OSBxcHN0ZXA9NCBpcF9yYXRpbz0xLjQwIGFxPTE6MS4wMACAAAABZYiEBrxmKAAPVccAAS044AA5DRJMnkycJk4TPw=="
|
|
));
|
|
let gotframe = false;
|
|
let error = null;
|
|
let decoder = new VideoDecoder({
|
|
output: (frame) => {
|
|
gotframe = true;
|
|
frame.close();
|
|
},
|
|
error: (e2) => {
|
|
error = e2;
|
|
}
|
|
});
|
|
let chunk = new EncodedVideoChunk({
|
|
timestamp: 0,
|
|
type: "key",
|
|
data
|
|
});
|
|
decoder.configure(config);
|
|
decoder.decode(chunk);
|
|
try {
|
|
await decoder.flush();
|
|
} catch (e2) {
|
|
error = e2;
|
|
}
|
|
if (!gotframe) {
|
|
return false;
|
|
}
|
|
if (error !== null) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
supportsWebCodecsH264Decode = await _checkWebCodecsH264DecodeSupport();
|
|
function isMac() {
|
|
return !!/mac/i.exec(navigator.platform);
|
|
}
|
|
function isWindows() {
|
|
return !!/win/i.exec(navigator.platform);
|
|
}
|
|
function isIOS() {
|
|
return !!/ipad/i.exec(navigator.platform) || !!/iphone/i.exec(navigator.platform) || !!/ipod/i.exec(navigator.platform);
|
|
}
|
|
|
|
// core/util/element.js
|
|
function clientToElement(x, y, elem) {
|
|
const bounds = elem.getBoundingClientRect();
|
|
let pos = { x: 0, y: 0 };
|
|
if (x < bounds.left) {
|
|
pos.x = 0;
|
|
} else if (x >= bounds.right) {
|
|
pos.x = bounds.width - 1;
|
|
} else {
|
|
pos.x = x - bounds.left;
|
|
}
|
|
if (y < bounds.top) {
|
|
pos.y = 0;
|
|
} else if (y >= bounds.bottom) {
|
|
pos.y = bounds.height - 1;
|
|
} else {
|
|
pos.y = y - bounds.top;
|
|
}
|
|
return pos;
|
|
}
|
|
|
|
// core/util/events.js
|
|
function stopEvent(e2) {
|
|
e2.stopPropagation();
|
|
e2.preventDefault();
|
|
}
|
|
var _captureRecursion = false;
|
|
var _elementForUnflushedEvents = null;
|
|
document.captureElement = null;
|
|
function _captureProxy(e2) {
|
|
if (_captureRecursion) return;
|
|
const newEv = new e2.constructor(e2.type, e2);
|
|
_captureRecursion = true;
|
|
if (document.captureElement) {
|
|
document.captureElement.dispatchEvent(newEv);
|
|
} else {
|
|
_elementForUnflushedEvents.dispatchEvent(newEv);
|
|
}
|
|
_captureRecursion = false;
|
|
e2.stopPropagation();
|
|
if (newEv.defaultPrevented) {
|
|
e2.preventDefault();
|
|
}
|
|
if (e2.type === "mouseup") {
|
|
releaseCapture();
|
|
}
|
|
}
|
|
function _capturedElemChanged() {
|
|
const proxyElem = document.getElementById("noVNC_mouse_capture_elem");
|
|
proxyElem.style.cursor = window.getComputedStyle(document.captureElement).cursor;
|
|
}
|
|
var _captureObserver = new MutationObserver(_capturedElemChanged);
|
|
function setCapture(target) {
|
|
if (target.setCapture) {
|
|
target.setCapture();
|
|
document.captureElement = target;
|
|
} else {
|
|
releaseCapture();
|
|
let proxyElem = document.getElementById("noVNC_mouse_capture_elem");
|
|
if (proxyElem === null) {
|
|
proxyElem = document.createElement("div");
|
|
proxyElem.id = "noVNC_mouse_capture_elem";
|
|
proxyElem.style.position = "fixed";
|
|
proxyElem.style.top = "0px";
|
|
proxyElem.style.left = "0px";
|
|
proxyElem.style.width = "100%";
|
|
proxyElem.style.height = "100%";
|
|
proxyElem.style.zIndex = 1e4;
|
|
proxyElem.style.display = "none";
|
|
document.body.appendChild(proxyElem);
|
|
proxyElem.addEventListener("contextmenu", _captureProxy);
|
|
proxyElem.addEventListener("mousemove", _captureProxy);
|
|
proxyElem.addEventListener("mouseup", _captureProxy);
|
|
}
|
|
document.captureElement = target;
|
|
_captureObserver.observe(target, { attributes: true });
|
|
_capturedElemChanged();
|
|
proxyElem.style.display = "";
|
|
window.addEventListener("mousemove", _captureProxy);
|
|
window.addEventListener("mouseup", _captureProxy);
|
|
}
|
|
}
|
|
function releaseCapture() {
|
|
if (document.releaseCapture) {
|
|
document.releaseCapture();
|
|
document.captureElement = null;
|
|
} else {
|
|
if (!document.captureElement) {
|
|
return;
|
|
}
|
|
_elementForUnflushedEvents = document.captureElement;
|
|
document.captureElement = null;
|
|
_captureObserver.disconnect();
|
|
const proxyElem = document.getElementById("noVNC_mouse_capture_elem");
|
|
proxyElem.style.display = "none";
|
|
window.removeEventListener("mousemove", _captureProxy);
|
|
window.removeEventListener("mouseup", _captureProxy);
|
|
}
|
|
}
|
|
|
|
// core/util/eventtarget.js
|
|
var EventTargetMixin = class {
|
|
constructor() {
|
|
this._listeners = /* @__PURE__ */ new Map();
|
|
}
|
|
addEventListener(type, callback) {
|
|
if (!this._listeners.has(type)) {
|
|
this._listeners.set(type, /* @__PURE__ */ new Set());
|
|
}
|
|
this._listeners.get(type).add(callback);
|
|
}
|
|
removeEventListener(type, callback) {
|
|
if (this._listeners.has(type)) {
|
|
this._listeners.get(type).delete(callback);
|
|
}
|
|
}
|
|
dispatchEvent(event) {
|
|
if (!this._listeners.has(event.type)) {
|
|
return true;
|
|
}
|
|
this._listeners.get(event.type).forEach((callback) => callback.call(this, event));
|
|
return !event.defaultPrevented;
|
|
}
|
|
};
|
|
|
|
// core/display.js
|
|
var Display = class {
|
|
constructor(target) {
|
|
this._drawCtx = null;
|
|
this._renderQ = [];
|
|
this._flushPromise = null;
|
|
this._fbWidth = 0;
|
|
this._fbHeight = 0;
|
|
this._prevDrawStyle = "";
|
|
Debug(">> Display.constructor");
|
|
this._target = target;
|
|
if (!this._target) {
|
|
throw new Error("Target must be set");
|
|
}
|
|
if (typeof this._target === "string") {
|
|
throw new Error("target must be a DOM element");
|
|
}
|
|
if (!this._target.getContext) {
|
|
throw new Error("no getContext method");
|
|
}
|
|
this._targetCtx = this._target.getContext("2d");
|
|
this._viewportLoc = { "x": 0, "y": 0, "w": this._target.width, "h": this._target.height };
|
|
this._backbuffer = document.createElement("canvas");
|
|
this._drawCtx = this._backbuffer.getContext("2d");
|
|
this._damageBounds = {
|
|
left: 0,
|
|
top: 0,
|
|
right: this._backbuffer.width,
|
|
bottom: this._backbuffer.height
|
|
};
|
|
Debug("User Agent: " + navigator.userAgent);
|
|
Debug("<< Display.constructor");
|
|
this._scale = 1;
|
|
this._clipViewport = false;
|
|
}
|
|
// ===== PROPERTIES =====
|
|
get scale() {
|
|
return this._scale;
|
|
}
|
|
set scale(scale) {
|
|
this._rescale(scale);
|
|
}
|
|
get clipViewport() {
|
|
return this._clipViewport;
|
|
}
|
|
set clipViewport(viewport) {
|
|
this._clipViewport = viewport;
|
|
const vp = this._viewportLoc;
|
|
this.viewportChangeSize(vp.w, vp.h);
|
|
this.viewportChangePos(0, 0);
|
|
}
|
|
get width() {
|
|
return this._fbWidth;
|
|
}
|
|
get height() {
|
|
return this._fbHeight;
|
|
}
|
|
// ===== PUBLIC METHODS =====
|
|
viewportChangePos(deltaX, deltaY) {
|
|
const vp = this._viewportLoc;
|
|
deltaX = Math.floor(deltaX);
|
|
deltaY = Math.floor(deltaY);
|
|
if (!this._clipViewport) {
|
|
deltaX = -vp.w;
|
|
deltaY = -vp.h;
|
|
}
|
|
const vx2 = vp.x + vp.w - 1;
|
|
const vy2 = vp.y + vp.h - 1;
|
|
if (deltaX < 0 && vp.x + deltaX < 0) {
|
|
deltaX = -vp.x;
|
|
}
|
|
if (vx2 + deltaX >= this._fbWidth) {
|
|
deltaX -= vx2 + deltaX - this._fbWidth + 1;
|
|
}
|
|
if (vp.y + deltaY < 0) {
|
|
deltaY = -vp.y;
|
|
}
|
|
if (vy2 + deltaY >= this._fbHeight) {
|
|
deltaY -= vy2 + deltaY - this._fbHeight + 1;
|
|
}
|
|
if (deltaX === 0 && deltaY === 0) {
|
|
return;
|
|
}
|
|
Debug("viewportChange deltaX: " + deltaX + ", deltaY: " + deltaY);
|
|
vp.x += deltaX;
|
|
vp.y += deltaY;
|
|
this._damage(vp.x, vp.y, vp.w, vp.h);
|
|
this.flip();
|
|
}
|
|
viewportChangeSize(width, height) {
|
|
if (!this._clipViewport || typeof width === "undefined" || typeof height === "undefined") {
|
|
Debug("Setting viewport to full display region");
|
|
width = this._fbWidth;
|
|
height = this._fbHeight;
|
|
}
|
|
width = Math.floor(width);
|
|
height = Math.floor(height);
|
|
if (width > this._fbWidth) {
|
|
width = this._fbWidth;
|
|
}
|
|
if (height > this._fbHeight) {
|
|
height = this._fbHeight;
|
|
}
|
|
const vp = this._viewportLoc;
|
|
if (vp.w !== width || vp.h !== height) {
|
|
vp.w = width;
|
|
vp.h = height;
|
|
const canvas = this._target;
|
|
canvas.width = width;
|
|
canvas.height = height;
|
|
this.viewportChangePos(0, 0);
|
|
this._damage(vp.x, vp.y, vp.w, vp.h);
|
|
this.flip();
|
|
this._rescale(this._scale);
|
|
}
|
|
}
|
|
absX(x) {
|
|
if (this._scale === 0) {
|
|
return 0;
|
|
}
|
|
return toSigned32bit(x / this._scale + this._viewportLoc.x);
|
|
}
|
|
absY(y) {
|
|
if (this._scale === 0) {
|
|
return 0;
|
|
}
|
|
return toSigned32bit(y / this._scale + this._viewportLoc.y);
|
|
}
|
|
resize(width, height) {
|
|
this._prevDrawStyle = "";
|
|
this._fbWidth = width;
|
|
this._fbHeight = height;
|
|
const canvas = this._backbuffer;
|
|
if (canvas.width !== width || canvas.height !== height) {
|
|
let saveImg = null;
|
|
if (canvas.width > 0 && canvas.height > 0) {
|
|
saveImg = this._drawCtx.getImageData(0, 0, canvas.width, canvas.height);
|
|
}
|
|
if (canvas.width !== width) {
|
|
canvas.width = width;
|
|
}
|
|
if (canvas.height !== height) {
|
|
canvas.height = height;
|
|
}
|
|
if (saveImg) {
|
|
this._drawCtx.putImageData(saveImg, 0, 0);
|
|
}
|
|
}
|
|
const vp = this._viewportLoc;
|
|
this.viewportChangeSize(vp.w, vp.h);
|
|
this.viewportChangePos(0, 0);
|
|
}
|
|
getImageData() {
|
|
return this._drawCtx.getImageData(0, 0, this.width, this.height);
|
|
}
|
|
toDataURL(type, encoderOptions) {
|
|
return this._backbuffer.toDataURL(type, encoderOptions);
|
|
}
|
|
toBlob(callback, type, quality) {
|
|
return this._backbuffer.toBlob(callback, type, quality);
|
|
}
|
|
// Track what parts of the visible canvas that need updating
|
|
_damage(x, y, w, h) {
|
|
if (x < this._damageBounds.left) {
|
|
this._damageBounds.left = x;
|
|
}
|
|
if (y < this._damageBounds.top) {
|
|
this._damageBounds.top = y;
|
|
}
|
|
if (x + w > this._damageBounds.right) {
|
|
this._damageBounds.right = x + w;
|
|
}
|
|
if (y + h > this._damageBounds.bottom) {
|
|
this._damageBounds.bottom = y + h;
|
|
}
|
|
}
|
|
// Update the visible canvas with the contents of the
|
|
// rendering canvas
|
|
flip(fromQueue) {
|
|
if (this._renderQ.length !== 0 && !fromQueue) {
|
|
this._renderQPush({
|
|
"type": "flip"
|
|
});
|
|
} else {
|
|
let x = this._damageBounds.left;
|
|
let y = this._damageBounds.top;
|
|
let w = this._damageBounds.right - x;
|
|
let h = this._damageBounds.bottom - y;
|
|
let vx = x - this._viewportLoc.x;
|
|
let vy = y - this._viewportLoc.y;
|
|
if (vx < 0) {
|
|
w += vx;
|
|
x -= vx;
|
|
vx = 0;
|
|
}
|
|
if (vy < 0) {
|
|
h += vy;
|
|
y -= vy;
|
|
vy = 0;
|
|
}
|
|
if (vx + w > this._viewportLoc.w) {
|
|
w = this._viewportLoc.w - vx;
|
|
}
|
|
if (vy + h > this._viewportLoc.h) {
|
|
h = this._viewportLoc.h - vy;
|
|
}
|
|
if (w > 0 && h > 0) {
|
|
this._targetCtx.drawImage(
|
|
this._backbuffer,
|
|
x,
|
|
y,
|
|
w,
|
|
h,
|
|
vx,
|
|
vy,
|
|
w,
|
|
h
|
|
);
|
|
}
|
|
this._damageBounds.left = this._damageBounds.top = 65535;
|
|
this._damageBounds.right = this._damageBounds.bottom = 0;
|
|
}
|
|
}
|
|
pending() {
|
|
return this._renderQ.length > 0;
|
|
}
|
|
flush() {
|
|
if (this._renderQ.length === 0) {
|
|
return Promise.resolve();
|
|
} else {
|
|
if (this._flushPromise === null) {
|
|
this._flushPromise = new Promise((resolve) => {
|
|
this._flushResolve = resolve;
|
|
});
|
|
}
|
|
return this._flushPromise;
|
|
}
|
|
}
|
|
fillRect(x, y, width, height, color, fromQueue) {
|
|
if (this._renderQ.length !== 0 && !fromQueue) {
|
|
this._renderQPush({
|
|
"type": "fill",
|
|
"x": x,
|
|
"y": y,
|
|
"width": width,
|
|
"height": height,
|
|
"color": color
|
|
});
|
|
} else {
|
|
this._setFillColor(color);
|
|
this._drawCtx.fillRect(x, y, width, height);
|
|
this._damage(x, y, width, height);
|
|
}
|
|
}
|
|
copyImage(oldX, oldY, newX, newY, w, h, fromQueue) {
|
|
if (this._renderQ.length !== 0 && !fromQueue) {
|
|
this._renderQPush({
|
|
"type": "copy",
|
|
"oldX": oldX,
|
|
"oldY": oldY,
|
|
"x": newX,
|
|
"y": newY,
|
|
"width": w,
|
|
"height": h
|
|
});
|
|
} else {
|
|
this._drawCtx.mozImageSmoothingEnabled = false;
|
|
this._drawCtx.webkitImageSmoothingEnabled = false;
|
|
this._drawCtx.msImageSmoothingEnabled = false;
|
|
this._drawCtx.imageSmoothingEnabled = false;
|
|
this._drawCtx.drawImage(
|
|
this._backbuffer,
|
|
oldX,
|
|
oldY,
|
|
w,
|
|
h,
|
|
newX,
|
|
newY,
|
|
w,
|
|
h
|
|
);
|
|
this._damage(newX, newY, w, h);
|
|
}
|
|
}
|
|
imageRect(x, y, width, height, mime, arr) {
|
|
if (width === 0 || height === 0) {
|
|
return;
|
|
}
|
|
const img = new Image();
|
|
img.src = "data: " + mime + ";base64," + base64_default.encode(arr);
|
|
this._renderQPush({
|
|
"type": "img",
|
|
"img": img,
|
|
"x": x,
|
|
"y": y,
|
|
"width": width,
|
|
"height": height
|
|
});
|
|
}
|
|
videoFrame(x, y, width, height, frame) {
|
|
this._renderQPush({
|
|
"type": "frame",
|
|
"frame": frame,
|
|
"x": x,
|
|
"y": y,
|
|
"width": width,
|
|
"height": height
|
|
});
|
|
}
|
|
blitImage(x, y, width, height, arr, offset, fromQueue) {
|
|
if (this._renderQ.length !== 0 && !fromQueue) {
|
|
const newArr = new Uint8Array(width * height * 4);
|
|
newArr.set(new Uint8Array(arr.buffer, 0, newArr.length));
|
|
this._renderQPush({
|
|
"type": "blit",
|
|
"data": newArr,
|
|
"x": x,
|
|
"y": y,
|
|
"width": width,
|
|
"height": height
|
|
});
|
|
} else {
|
|
let data = new Uint8ClampedArray(
|
|
arr.buffer,
|
|
arr.byteOffset + offset,
|
|
width * height * 4
|
|
);
|
|
let img = new ImageData(data, width, height);
|
|
this._drawCtx.putImageData(img, x, y);
|
|
this._damage(x, y, width, height);
|
|
}
|
|
}
|
|
drawImage(img, ...args) {
|
|
this._drawCtx.drawImage(img, ...args);
|
|
if (args.length <= 4) {
|
|
const [x, y] = args;
|
|
this._damage(x, y, img.width, img.height);
|
|
} else {
|
|
const [, , sw, sh, dx, dy] = args;
|
|
this._damage(dx, dy, sw, sh);
|
|
}
|
|
}
|
|
autoscale(containerWidth, containerHeight) {
|
|
let scaleRatio;
|
|
if (containerWidth === 0 || containerHeight === 0) {
|
|
scaleRatio = 0;
|
|
} else {
|
|
const vp = this._viewportLoc;
|
|
const targetAspectRatio = containerWidth / containerHeight;
|
|
const fbAspectRatio = vp.w / vp.h;
|
|
if (fbAspectRatio >= targetAspectRatio) {
|
|
scaleRatio = containerWidth / vp.w;
|
|
} else {
|
|
scaleRatio = containerHeight / vp.h;
|
|
}
|
|
}
|
|
this._rescale(scaleRatio);
|
|
}
|
|
// ===== PRIVATE METHODS =====
|
|
_rescale(factor) {
|
|
this._scale = factor;
|
|
const vp = this._viewportLoc;
|
|
const width = factor * vp.w + "px";
|
|
const height = factor * vp.h + "px";
|
|
if (this._target.style.width !== width || this._target.style.height !== height) {
|
|
this._target.style.width = width;
|
|
this._target.style.height = height;
|
|
}
|
|
}
|
|
_setFillColor(color) {
|
|
const newStyle = "rgb(" + color[0] + "," + color[1] + "," + color[2] + ")";
|
|
if (newStyle !== this._prevDrawStyle) {
|
|
this._drawCtx.fillStyle = newStyle;
|
|
this._prevDrawStyle = newStyle;
|
|
}
|
|
}
|
|
_renderQPush(action) {
|
|
this._renderQ.push(action);
|
|
if (this._renderQ.length === 1) {
|
|
this._scanRenderQ();
|
|
}
|
|
}
|
|
_resumeRenderQ() {
|
|
this.removeEventListener("load", this._noVNCDisplay._resumeRenderQ);
|
|
this._noVNCDisplay._scanRenderQ();
|
|
}
|
|
_scanRenderQ() {
|
|
let ready = true;
|
|
while (ready && this._renderQ.length > 0) {
|
|
const a2 = this._renderQ[0];
|
|
switch (a2.type) {
|
|
case "flip":
|
|
this.flip(true);
|
|
break;
|
|
case "copy":
|
|
this.copyImage(a2.oldX, a2.oldY, a2.x, a2.y, a2.width, a2.height, true);
|
|
break;
|
|
case "fill":
|
|
this.fillRect(a2.x, a2.y, a2.width, a2.height, a2.color, true);
|
|
break;
|
|
case "blit":
|
|
this.blitImage(a2.x, a2.y, a2.width, a2.height, a2.data, 0, true);
|
|
break;
|
|
case "img":
|
|
if (a2.img.complete) {
|
|
if (a2.img.width !== a2.width || a2.img.height !== a2.height) {
|
|
Error2("Decoded image has incorrect dimensions. Got " + a2.img.width + "x" + a2.img.height + ". Expected " + a2.width + "x" + a2.height + ".");
|
|
return;
|
|
}
|
|
this.drawImage(a2.img, a2.x, a2.y);
|
|
a2.img.src = "";
|
|
} else {
|
|
a2.img._noVNCDisplay = this;
|
|
a2.img.addEventListener("load", this._resumeRenderQ);
|
|
ready = false;
|
|
}
|
|
break;
|
|
case "frame":
|
|
if (a2.frame.ready) {
|
|
let frame = a2.frame.frame;
|
|
if (frame.codedWidth < a2.width || frame.codedHeight < a2.height) {
|
|
Warn("Decoded video frame does not cover its full rectangle area. Expecting at least " + a2.width + "x" + a2.height + " but got " + frame.codedWidth + "x" + frame.codedHeight);
|
|
}
|
|
const sx = 0;
|
|
const sy = 0;
|
|
const sw = a2.width;
|
|
const sh = a2.height;
|
|
const dx = a2.x;
|
|
const dy = a2.y;
|
|
const dw = sw;
|
|
const dh = sh;
|
|
this.drawImage(frame, sx, sy, sw, sh, dx, dy, dw, dh);
|
|
frame.close();
|
|
} else {
|
|
let display = this;
|
|
a2.frame.promise.then(() => {
|
|
display._scanRenderQ();
|
|
});
|
|
ready = false;
|
|
}
|
|
break;
|
|
}
|
|
if (ready) {
|
|
this._renderQ.shift();
|
|
}
|
|
}
|
|
if (this._renderQ.length === 0 && this._flushPromise !== null) {
|
|
this._flushResolve();
|
|
this._flushPromise = null;
|
|
this._flushResolve = null;
|
|
}
|
|
}
|
|
};
|
|
|
|
// core/clipboard.js
|
|
var AsyncClipboard = class {
|
|
constructor(target) {
|
|
this._target = target || null;
|
|
this._isAvailable = null;
|
|
this._eventHandlers = {
|
|
"focus": this._handleFocus.bind(this)
|
|
};
|
|
this.onpaste = () => {
|
|
};
|
|
}
|
|
// ===== PRIVATE METHODS =====
|
|
async _ensureAvailable() {
|
|
if (this._isAvailable !== null) return this._isAvailable;
|
|
try {
|
|
const status = await browserAsyncClipboardSupport();
|
|
this._isAvailable = status === "available";
|
|
} catch {
|
|
this._isAvailable = false;
|
|
}
|
|
return this._isAvailable;
|
|
}
|
|
async _handleFocus(event) {
|
|
if (!await this._ensureAvailable()) return;
|
|
try {
|
|
const text = await navigator.clipboard.readText();
|
|
this.onpaste(text);
|
|
} catch (error) {
|
|
Error2("Clipboard read failed: ", error);
|
|
}
|
|
}
|
|
// ===== PUBLIC METHODS =====
|
|
writeClipboard(text) {
|
|
if (!this._isAvailable) return false;
|
|
navigator.clipboard.writeText(text).catch((error) => Error2("Clipboard write failed: ", error));
|
|
return true;
|
|
}
|
|
grab() {
|
|
if (!this._target) return;
|
|
this._ensureAvailable().then((isAvailable) => {
|
|
if (isAvailable) {
|
|
this._target.addEventListener("focus", this._eventHandlers.focus);
|
|
}
|
|
});
|
|
}
|
|
ungrab() {
|
|
if (!this._target) return;
|
|
this._target.removeEventListener("focus", this._eventHandlers.focus);
|
|
}
|
|
};
|
|
|
|
// vendor/pako/lib/utils/common.js
|
|
function arraySet(dest, src, src_offs, len, dest_offs) {
|
|
if (src.subarray && dest.subarray) {
|
|
dest.set(src.subarray(src_offs, src_offs + len), dest_offs);
|
|
return;
|
|
}
|
|
for (var i = 0; i < len; i++) {
|
|
dest[dest_offs + i] = src[src_offs + i];
|
|
}
|
|
}
|
|
var Buf8 = Uint8Array;
|
|
var Buf16 = Uint16Array;
|
|
var Buf32 = Int32Array;
|
|
|
|
// vendor/pako/lib/zlib/adler32.js
|
|
function adler32(adler, buf, len, pos) {
|
|
var s1 = adler & 65535 | 0, s2 = adler >>> 16 & 65535 | 0, n = 0;
|
|
while (len !== 0) {
|
|
n = len > 2e3 ? 2e3 : len;
|
|
len -= n;
|
|
do {
|
|
s1 = s1 + buf[pos++] | 0;
|
|
s2 = s2 + s1 | 0;
|
|
} while (--n);
|
|
s1 %= 65521;
|
|
s2 %= 65521;
|
|
}
|
|
return s1 | s2 << 16 | 0;
|
|
}
|
|
|
|
// vendor/pako/lib/zlib/crc32.js
|
|
function makeTable() {
|
|
var c2, table = [];
|
|
for (var n = 0; n < 256; n++) {
|
|
c2 = n;
|
|
for (var k = 0; k < 8; k++) {
|
|
c2 = c2 & 1 ? 3988292384 ^ c2 >>> 1 : c2 >>> 1;
|
|
}
|
|
table[n] = c2;
|
|
}
|
|
return table;
|
|
}
|
|
var crcTable = makeTable();
|
|
|
|
// vendor/pako/lib/zlib/inffast.js
|
|
var BAD = 30;
|
|
var TYPE = 12;
|
|
function inflate_fast(strm, start) {
|
|
var state;
|
|
var _in;
|
|
var last;
|
|
var _out;
|
|
var beg;
|
|
var end;
|
|
var dmax;
|
|
var wsize;
|
|
var whave;
|
|
var wnext;
|
|
var s_window;
|
|
var hold;
|
|
var bits;
|
|
var lcode;
|
|
var dcode;
|
|
var lmask;
|
|
var dmask;
|
|
var here;
|
|
var op;
|
|
var len;
|
|
var dist;
|
|
var from;
|
|
var from_source;
|
|
var input, output;
|
|
state = strm.state;
|
|
_in = strm.next_in;
|
|
input = strm.input;
|
|
last = _in + (strm.avail_in - 5);
|
|
_out = strm.next_out;
|
|
output = strm.output;
|
|
beg = _out - (start - strm.avail_out);
|
|
end = _out + (strm.avail_out - 257);
|
|
dmax = state.dmax;
|
|
wsize = state.wsize;
|
|
whave = state.whave;
|
|
wnext = state.wnext;
|
|
s_window = state.window;
|
|
hold = state.hold;
|
|
bits = state.bits;
|
|
lcode = state.lencode;
|
|
dcode = state.distcode;
|
|
lmask = (1 << state.lenbits) - 1;
|
|
dmask = (1 << state.distbits) - 1;
|
|
top:
|
|
do {
|
|
if (bits < 15) {
|
|
hold += input[_in++] << bits;
|
|
bits += 8;
|
|
hold += input[_in++] << bits;
|
|
bits += 8;
|
|
}
|
|
here = lcode[hold & lmask];
|
|
dolen:
|
|
for (; ; ) {
|
|
op = here >>> 24;
|
|
hold >>>= op;
|
|
bits -= op;
|
|
op = here >>> 16 & 255;
|
|
if (op === 0) {
|
|
output[_out++] = here & 65535;
|
|
} else if (op & 16) {
|
|
len = here & 65535;
|
|
op &= 15;
|
|
if (op) {
|
|
if (bits < op) {
|
|
hold += input[_in++] << bits;
|
|
bits += 8;
|
|
}
|
|
len += hold & (1 << op) - 1;
|
|
hold >>>= op;
|
|
bits -= op;
|
|
}
|
|
if (bits < 15) {
|
|
hold += input[_in++] << bits;
|
|
bits += 8;
|
|
hold += input[_in++] << bits;
|
|
bits += 8;
|
|
}
|
|
here = dcode[hold & dmask];
|
|
dodist:
|
|
for (; ; ) {
|
|
op = here >>> 24;
|
|
hold >>>= op;
|
|
bits -= op;
|
|
op = here >>> 16 & 255;
|
|
if (op & 16) {
|
|
dist = here & 65535;
|
|
op &= 15;
|
|
if (bits < op) {
|
|
hold += input[_in++] << bits;
|
|
bits += 8;
|
|
if (bits < op) {
|
|
hold += input[_in++] << bits;
|
|
bits += 8;
|
|
}
|
|
}
|
|
dist += hold & (1 << op) - 1;
|
|
if (dist > dmax) {
|
|
strm.msg = "invalid distance too far back";
|
|
state.mode = BAD;
|
|
break top;
|
|
}
|
|
hold >>>= op;
|
|
bits -= op;
|
|
op = _out - beg;
|
|
if (dist > op) {
|
|
op = dist - op;
|
|
if (op > whave) {
|
|
if (state.sane) {
|
|
strm.msg = "invalid distance too far back";
|
|
state.mode = BAD;
|
|
break top;
|
|
}
|
|
}
|
|
from = 0;
|
|
from_source = s_window;
|
|
if (wnext === 0) {
|
|
from += wsize - op;
|
|
if (op < len) {
|
|
len -= op;
|
|
do {
|
|
output[_out++] = s_window[from++];
|
|
} while (--op);
|
|
from = _out - dist;
|
|
from_source = output;
|
|
}
|
|
} else if (wnext < op) {
|
|
from += wsize + wnext - op;
|
|
op -= wnext;
|
|
if (op < len) {
|
|
len -= op;
|
|
do {
|
|
output[_out++] = s_window[from++];
|
|
} while (--op);
|
|
from = 0;
|
|
if (wnext < len) {
|
|
op = wnext;
|
|
len -= op;
|
|
do {
|
|
output[_out++] = s_window[from++];
|
|
} while (--op);
|
|
from = _out - dist;
|
|
from_source = output;
|
|
}
|
|
}
|
|
} else {
|
|
from += wnext - op;
|
|
if (op < len) {
|
|
len -= op;
|
|
do {
|
|
output[_out++] = s_window[from++];
|
|
} while (--op);
|
|
from = _out - dist;
|
|
from_source = output;
|
|
}
|
|
}
|
|
while (len > 2) {
|
|
output[_out++] = from_source[from++];
|
|
output[_out++] = from_source[from++];
|
|
output[_out++] = from_source[from++];
|
|
len -= 3;
|
|
}
|
|
if (len) {
|
|
output[_out++] = from_source[from++];
|
|
if (len > 1) {
|
|
output[_out++] = from_source[from++];
|
|
}
|
|
}
|
|
} else {
|
|
from = _out - dist;
|
|
do {
|
|
output[_out++] = output[from++];
|
|
output[_out++] = output[from++];
|
|
output[_out++] = output[from++];
|
|
len -= 3;
|
|
} while (len > 2);
|
|
if (len) {
|
|
output[_out++] = output[from++];
|
|
if (len > 1) {
|
|
output[_out++] = output[from++];
|
|
}
|
|
}
|
|
}
|
|
} else if ((op & 64) === 0) {
|
|
here = dcode[(here & 65535) + (hold & (1 << op) - 1)];
|
|
continue dodist;
|
|
} else {
|
|
strm.msg = "invalid distance code";
|
|
state.mode = BAD;
|
|
break top;
|
|
}
|
|
break;
|
|
}
|
|
} else if ((op & 64) === 0) {
|
|
here = lcode[(here & 65535) + (hold & (1 << op) - 1)];
|
|
continue dolen;
|
|
} else if (op & 32) {
|
|
state.mode = TYPE;
|
|
break top;
|
|
} else {
|
|
strm.msg = "invalid literal/length code";
|
|
state.mode = BAD;
|
|
break top;
|
|
}
|
|
break;
|
|
}
|
|
} while (_in < last && _out < end);
|
|
len = bits >> 3;
|
|
_in -= len;
|
|
bits -= len << 3;
|
|
hold &= (1 << bits) - 1;
|
|
strm.next_in = _in;
|
|
strm.next_out = _out;
|
|
strm.avail_in = _in < last ? 5 + (last - _in) : 5 - (_in - last);
|
|
strm.avail_out = _out < end ? 257 + (end - _out) : 257 - (_out - end);
|
|
state.hold = hold;
|
|
state.bits = bits;
|
|
return;
|
|
}
|
|
|
|
// vendor/pako/lib/zlib/inftrees.js
|
|
var MAXBITS = 15;
|
|
var ENOUGH_LENS = 852;
|
|
var ENOUGH_DISTS = 592;
|
|
var CODES = 0;
|
|
var LENS = 1;
|
|
var DISTS = 2;
|
|
var lbase = [
|
|
/* Length codes 257..285 base */
|
|
3,
|
|
4,
|
|
5,
|
|
6,
|
|
7,
|
|
8,
|
|
9,
|
|
10,
|
|
11,
|
|
13,
|
|
15,
|
|
17,
|
|
19,
|
|
23,
|
|
27,
|
|
31,
|
|
35,
|
|
43,
|
|
51,
|
|
59,
|
|
67,
|
|
83,
|
|
99,
|
|
115,
|
|
131,
|
|
163,
|
|
195,
|
|
227,
|
|
258,
|
|
0,
|
|
0
|
|
];
|
|
var lext = [
|
|
/* Length codes 257..285 extra */
|
|
16,
|
|
16,
|
|
16,
|
|
16,
|
|
16,
|
|
16,
|
|
16,
|
|
16,
|
|
17,
|
|
17,
|
|
17,
|
|
17,
|
|
18,
|
|
18,
|
|
18,
|
|
18,
|
|
19,
|
|
19,
|
|
19,
|
|
19,
|
|
20,
|
|
20,
|
|
20,
|
|
20,
|
|
21,
|
|
21,
|
|
21,
|
|
21,
|
|
16,
|
|
72,
|
|
78
|
|
];
|
|
var dbase = [
|
|
/* Distance codes 0..29 base */
|
|
1,
|
|
2,
|
|
3,
|
|
4,
|
|
5,
|
|
7,
|
|
9,
|
|
13,
|
|
17,
|
|
25,
|
|
33,
|
|
49,
|
|
65,
|
|
97,
|
|
129,
|
|
193,
|
|
257,
|
|
385,
|
|
513,
|
|
769,
|
|
1025,
|
|
1537,
|
|
2049,
|
|
3073,
|
|
4097,
|
|
6145,
|
|
8193,
|
|
12289,
|
|
16385,
|
|
24577,
|
|
0,
|
|
0
|
|
];
|
|
var dext = [
|
|
/* Distance codes 0..29 extra */
|
|
16,
|
|
16,
|
|
16,
|
|
16,
|
|
17,
|
|
17,
|
|
18,
|
|
18,
|
|
19,
|
|
19,
|
|
20,
|
|
20,
|
|
21,
|
|
21,
|
|
22,
|
|
22,
|
|
23,
|
|
23,
|
|
24,
|
|
24,
|
|
25,
|
|
25,
|
|
26,
|
|
26,
|
|
27,
|
|
27,
|
|
28,
|
|
28,
|
|
29,
|
|
29,
|
|
64,
|
|
64
|
|
];
|
|
function inflate_table(type, lens, lens_index, codes, table, table_index, work, opts) {
|
|
var bits = opts.bits;
|
|
var len = 0;
|
|
var sym = 0;
|
|
var min = 0, max = 0;
|
|
var root = 0;
|
|
var curr = 0;
|
|
var drop = 0;
|
|
var left = 0;
|
|
var used = 0;
|
|
var huff = 0;
|
|
var incr;
|
|
var fill;
|
|
var low;
|
|
var mask;
|
|
var next;
|
|
var base = null;
|
|
var base_index = 0;
|
|
var end;
|
|
var count = new Buf16(MAXBITS + 1);
|
|
var offs = new Buf16(MAXBITS + 1);
|
|
var extra = null;
|
|
var extra_index = 0;
|
|
var here_bits, here_op, here_val;
|
|
for (len = 0; len <= MAXBITS; len++) {
|
|
count[len] = 0;
|
|
}
|
|
for (sym = 0; sym < codes; sym++) {
|
|
count[lens[lens_index + sym]]++;
|
|
}
|
|
root = bits;
|
|
for (max = MAXBITS; max >= 1; max--) {
|
|
if (count[max] !== 0) {
|
|
break;
|
|
}
|
|
}
|
|
if (root > max) {
|
|
root = max;
|
|
}
|
|
if (max === 0) {
|
|
table[table_index++] = 1 << 24 | 64 << 16 | 0;
|
|
table[table_index++] = 1 << 24 | 64 << 16 | 0;
|
|
opts.bits = 1;
|
|
return 0;
|
|
}
|
|
for (min = 1; min < max; min++) {
|
|
if (count[min] !== 0) {
|
|
break;
|
|
}
|
|
}
|
|
if (root < min) {
|
|
root = min;
|
|
}
|
|
left = 1;
|
|
for (len = 1; len <= MAXBITS; len++) {
|
|
left <<= 1;
|
|
left -= count[len];
|
|
if (left < 0) {
|
|
return -1;
|
|
}
|
|
}
|
|
if (left > 0 && (type === CODES || max !== 1)) {
|
|
return -1;
|
|
}
|
|
offs[1] = 0;
|
|
for (len = 1; len < MAXBITS; len++) {
|
|
offs[len + 1] = offs[len] + count[len];
|
|
}
|
|
for (sym = 0; sym < codes; sym++) {
|
|
if (lens[lens_index + sym] !== 0) {
|
|
work[offs[lens[lens_index + sym]]++] = sym;
|
|
}
|
|
}
|
|
if (type === CODES) {
|
|
base = extra = work;
|
|
end = 19;
|
|
} else if (type === LENS) {
|
|
base = lbase;
|
|
base_index -= 257;
|
|
extra = lext;
|
|
extra_index -= 257;
|
|
end = 256;
|
|
} else {
|
|
base = dbase;
|
|
extra = dext;
|
|
end = -1;
|
|
}
|
|
huff = 0;
|
|
sym = 0;
|
|
len = min;
|
|
next = table_index;
|
|
curr = root;
|
|
drop = 0;
|
|
low = -1;
|
|
used = 1 << root;
|
|
mask = used - 1;
|
|
if (type === LENS && used > ENOUGH_LENS || type === DISTS && used > ENOUGH_DISTS) {
|
|
return 1;
|
|
}
|
|
for (; ; ) {
|
|
here_bits = len - drop;
|
|
if (work[sym] < end) {
|
|
here_op = 0;
|
|
here_val = work[sym];
|
|
} else if (work[sym] > end) {
|
|
here_op = extra[extra_index + work[sym]];
|
|
here_val = base[base_index + work[sym]];
|
|
} else {
|
|
here_op = 32 + 64;
|
|
here_val = 0;
|
|
}
|
|
incr = 1 << len - drop;
|
|
fill = 1 << curr;
|
|
min = fill;
|
|
do {
|
|
fill -= incr;
|
|
table[next + (huff >> drop) + fill] = here_bits << 24 | here_op << 16 | here_val | 0;
|
|
} while (fill !== 0);
|
|
incr = 1 << len - 1;
|
|
while (huff & incr) {
|
|
incr >>= 1;
|
|
}
|
|
if (incr !== 0) {
|
|
huff &= incr - 1;
|
|
huff += incr;
|
|
} else {
|
|
huff = 0;
|
|
}
|
|
sym++;
|
|
if (--count[len] === 0) {
|
|
if (len === max) {
|
|
break;
|
|
}
|
|
len = lens[lens_index + work[sym]];
|
|
}
|
|
if (len > root && (huff & mask) !== low) {
|
|
if (drop === 0) {
|
|
drop = root;
|
|
}
|
|
next += min;
|
|
curr = len - drop;
|
|
left = 1 << curr;
|
|
while (curr + drop < max) {
|
|
left -= count[curr + drop];
|
|
if (left <= 0) {
|
|
break;
|
|
}
|
|
curr++;
|
|
left <<= 1;
|
|
}
|
|
used += 1 << curr;
|
|
if (type === LENS && used > ENOUGH_LENS || type === DISTS && used > ENOUGH_DISTS) {
|
|
return 1;
|
|
}
|
|
low = huff & mask;
|
|
table[low] = root << 24 | curr << 16 | next - table_index | 0;
|
|
}
|
|
}
|
|
if (huff !== 0) {
|
|
table[next + huff] = len - drop << 24 | 64 << 16 | 0;
|
|
}
|
|
opts.bits = root;
|
|
return 0;
|
|
}
|
|
|
|
// vendor/pako/lib/zlib/inflate.js
|
|
var CODES2 = 0;
|
|
var LENS2 = 1;
|
|
var DISTS2 = 2;
|
|
var Z_FINISH = 4;
|
|
var Z_BLOCK = 5;
|
|
var Z_TREES = 6;
|
|
var Z_OK = 0;
|
|
var Z_STREAM_END = 1;
|
|
var Z_NEED_DICT = 2;
|
|
var Z_STREAM_ERROR = -2;
|
|
var Z_DATA_ERROR = -3;
|
|
var Z_MEM_ERROR = -4;
|
|
var Z_BUF_ERROR = -5;
|
|
var Z_DEFLATED = 8;
|
|
var HEAD = 1;
|
|
var FLAGS = 2;
|
|
var TIME = 3;
|
|
var OS = 4;
|
|
var EXLEN = 5;
|
|
var EXTRA = 6;
|
|
var NAME = 7;
|
|
var COMMENT = 8;
|
|
var HCRC = 9;
|
|
var DICTID = 10;
|
|
var DICT = 11;
|
|
var TYPE2 = 12;
|
|
var TYPEDO = 13;
|
|
var STORED = 14;
|
|
var COPY_ = 15;
|
|
var COPY = 16;
|
|
var TABLE = 17;
|
|
var LENLENS = 18;
|
|
var CODELENS = 19;
|
|
var LEN_ = 20;
|
|
var LEN = 21;
|
|
var LENEXT = 22;
|
|
var DIST = 23;
|
|
var DISTEXT = 24;
|
|
var MATCH = 25;
|
|
var LIT = 26;
|
|
var CHECK = 27;
|
|
var LENGTH = 28;
|
|
var DONE = 29;
|
|
var BAD2 = 30;
|
|
var MEM = 31;
|
|
var SYNC = 32;
|
|
var ENOUGH_LENS2 = 852;
|
|
var ENOUGH_DISTS2 = 592;
|
|
var MAX_WBITS = 15;
|
|
var DEF_WBITS = MAX_WBITS;
|
|
function zswap32(q) {
|
|
return (q >>> 24 & 255) + (q >>> 8 & 65280) + ((q & 65280) << 8) + ((q & 255) << 24);
|
|
}
|
|
function InflateState() {
|
|
this.mode = 0;
|
|
this.last = false;
|
|
this.wrap = 0;
|
|
this.havedict = false;
|
|
this.flags = 0;
|
|
this.dmax = 0;
|
|
this.check = 0;
|
|
this.total = 0;
|
|
this.head = null;
|
|
this.wbits = 0;
|
|
this.wsize = 0;
|
|
this.whave = 0;
|
|
this.wnext = 0;
|
|
this.window = null;
|
|
this.hold = 0;
|
|
this.bits = 0;
|
|
this.length = 0;
|
|
this.offset = 0;
|
|
this.extra = 0;
|
|
this.lencode = null;
|
|
this.distcode = null;
|
|
this.lenbits = 0;
|
|
this.distbits = 0;
|
|
this.ncode = 0;
|
|
this.nlen = 0;
|
|
this.ndist = 0;
|
|
this.have = 0;
|
|
this.next = null;
|
|
this.lens = new Buf16(320);
|
|
this.work = new Buf16(288);
|
|
this.lendyn = null;
|
|
this.distdyn = null;
|
|
this.sane = 0;
|
|
this.back = 0;
|
|
this.was = 0;
|
|
}
|
|
function inflateResetKeep(strm) {
|
|
var state;
|
|
if (!strm || !strm.state) {
|
|
return Z_STREAM_ERROR;
|
|
}
|
|
state = strm.state;
|
|
strm.total_in = strm.total_out = state.total = 0;
|
|
strm.msg = "";
|
|
if (state.wrap) {
|
|
strm.adler = state.wrap & 1;
|
|
}
|
|
state.mode = HEAD;
|
|
state.last = 0;
|
|
state.havedict = 0;
|
|
state.dmax = 32768;
|
|
state.head = null;
|
|
state.hold = 0;
|
|
state.bits = 0;
|
|
state.lencode = state.lendyn = new Buf32(ENOUGH_LENS2);
|
|
state.distcode = state.distdyn = new Buf32(ENOUGH_DISTS2);
|
|
state.sane = 1;
|
|
state.back = -1;
|
|
return Z_OK;
|
|
}
|
|
function inflateReset(strm) {
|
|
var state;
|
|
if (!strm || !strm.state) {
|
|
return Z_STREAM_ERROR;
|
|
}
|
|
state = strm.state;
|
|
state.wsize = 0;
|
|
state.whave = 0;
|
|
state.wnext = 0;
|
|
return inflateResetKeep(strm);
|
|
}
|
|
function inflateReset2(strm, windowBits) {
|
|
var wrap;
|
|
var state;
|
|
if (!strm || !strm.state) {
|
|
return Z_STREAM_ERROR;
|
|
}
|
|
state = strm.state;
|
|
if (windowBits < 0) {
|
|
wrap = 0;
|
|
windowBits = -windowBits;
|
|
} else {
|
|
wrap = (windowBits >> 4) + 1;
|
|
if (windowBits < 48) {
|
|
windowBits &= 15;
|
|
}
|
|
}
|
|
if (windowBits && (windowBits < 8 || windowBits > 15)) {
|
|
return Z_STREAM_ERROR;
|
|
}
|
|
if (state.window !== null && state.wbits !== windowBits) {
|
|
state.window = null;
|
|
}
|
|
state.wrap = wrap;
|
|
state.wbits = windowBits;
|
|
return inflateReset(strm);
|
|
}
|
|
function inflateInit2(strm, windowBits) {
|
|
var ret;
|
|
var state;
|
|
if (!strm) {
|
|
return Z_STREAM_ERROR;
|
|
}
|
|
state = new InflateState();
|
|
strm.state = state;
|
|
state.window = null;
|
|
ret = inflateReset2(strm, windowBits);
|
|
if (ret !== Z_OK) {
|
|
strm.state = null;
|
|
}
|
|
return ret;
|
|
}
|
|
function inflateInit(strm) {
|
|
return inflateInit2(strm, DEF_WBITS);
|
|
}
|
|
var virgin = true;
|
|
var lenfix;
|
|
var distfix;
|
|
function fixedtables(state) {
|
|
if (virgin) {
|
|
var sym;
|
|
lenfix = new Buf32(512);
|
|
distfix = new Buf32(32);
|
|
sym = 0;
|
|
while (sym < 144) {
|
|
state.lens[sym++] = 8;
|
|
}
|
|
while (sym < 256) {
|
|
state.lens[sym++] = 9;
|
|
}
|
|
while (sym < 280) {
|
|
state.lens[sym++] = 7;
|
|
}
|
|
while (sym < 288) {
|
|
state.lens[sym++] = 8;
|
|
}
|
|
inflate_table(LENS2, state.lens, 0, 288, lenfix, 0, state.work, { bits: 9 });
|
|
sym = 0;
|
|
while (sym < 32) {
|
|
state.lens[sym++] = 5;
|
|
}
|
|
inflate_table(DISTS2, state.lens, 0, 32, distfix, 0, state.work, { bits: 5 });
|
|
virgin = false;
|
|
}
|
|
state.lencode = lenfix;
|
|
state.lenbits = 9;
|
|
state.distcode = distfix;
|
|
state.distbits = 5;
|
|
}
|
|
function updatewindow(strm, src, end, copy) {
|
|
var dist;
|
|
var state = strm.state;
|
|
if (state.window === null) {
|
|
state.wsize = 1 << state.wbits;
|
|
state.wnext = 0;
|
|
state.whave = 0;
|
|
state.window = new Buf8(state.wsize);
|
|
}
|
|
if (copy >= state.wsize) {
|
|
arraySet(state.window, src, end - state.wsize, state.wsize, 0);
|
|
state.wnext = 0;
|
|
state.whave = state.wsize;
|
|
} else {
|
|
dist = state.wsize - state.wnext;
|
|
if (dist > copy) {
|
|
dist = copy;
|
|
}
|
|
arraySet(state.window, src, end - copy, dist, state.wnext);
|
|
copy -= dist;
|
|
if (copy) {
|
|
arraySet(state.window, src, end - copy, copy, 0);
|
|
state.wnext = copy;
|
|
state.whave = state.wsize;
|
|
} else {
|
|
state.wnext += dist;
|
|
if (state.wnext === state.wsize) {
|
|
state.wnext = 0;
|
|
}
|
|
if (state.whave < state.wsize) {
|
|
state.whave += dist;
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
function inflate(strm, flush) {
|
|
var state;
|
|
var input, output;
|
|
var next;
|
|
var put;
|
|
var have, left;
|
|
var hold;
|
|
var bits;
|
|
var _in, _out;
|
|
var copy;
|
|
var from;
|
|
var from_source;
|
|
var here = 0;
|
|
var here_bits, here_op, here_val;
|
|
var last_bits, last_op, last_val;
|
|
var len;
|
|
var ret;
|
|
var hbuf = new Buf8(4);
|
|
var opts;
|
|
var n;
|
|
var order = (
|
|
/* permutation of code lengths */
|
|
[16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15]
|
|
);
|
|
if (!strm || !strm.state || !strm.output || !strm.input && strm.avail_in !== 0) {
|
|
return Z_STREAM_ERROR;
|
|
}
|
|
state = strm.state;
|
|
if (state.mode === TYPE2) {
|
|
state.mode = TYPEDO;
|
|
}
|
|
put = strm.next_out;
|
|
output = strm.output;
|
|
left = strm.avail_out;
|
|
next = strm.next_in;
|
|
input = strm.input;
|
|
have = strm.avail_in;
|
|
hold = state.hold;
|
|
bits = state.bits;
|
|
_in = have;
|
|
_out = left;
|
|
ret = Z_OK;
|
|
inf_leave:
|
|
for (; ; ) {
|
|
switch (state.mode) {
|
|
case HEAD:
|
|
if (state.wrap === 0) {
|
|
state.mode = TYPEDO;
|
|
break;
|
|
}
|
|
while (bits < 16) {
|
|
if (have === 0) {
|
|
break inf_leave;
|
|
}
|
|
have--;
|
|
hold += input[next++] << bits;
|
|
bits += 8;
|
|
}
|
|
if (state.wrap & 2 && hold === 35615) {
|
|
state.check = 0;
|
|
hbuf[0] = hold & 255;
|
|
hbuf[1] = hold >>> 8 & 255;
|
|
state.check = makeTable(state.check, hbuf, 2, 0);
|
|
hold = 0;
|
|
bits = 0;
|
|
state.mode = FLAGS;
|
|
break;
|
|
}
|
|
state.flags = 0;
|
|
if (state.head) {
|
|
state.head.done = false;
|
|
}
|
|
if (!(state.wrap & 1) || /* check if zlib header allowed */
|
|
(((hold & 255) << 8) + (hold >> 8)) % 31) {
|
|
strm.msg = "incorrect header check";
|
|
state.mode = BAD2;
|
|
break;
|
|
}
|
|
if ((hold & 15) !== Z_DEFLATED) {
|
|
strm.msg = "unknown compression method";
|
|
state.mode = BAD2;
|
|
break;
|
|
}
|
|
hold >>>= 4;
|
|
bits -= 4;
|
|
len = (hold & 15) + 8;
|
|
if (state.wbits === 0) {
|
|
state.wbits = len;
|
|
} else if (len > state.wbits) {
|
|
strm.msg = "invalid window size";
|
|
state.mode = BAD2;
|
|
break;
|
|
}
|
|
state.dmax = 1 << len;
|
|
strm.adler = state.check = 1;
|
|
state.mode = hold & 512 ? DICTID : TYPE2;
|
|
hold = 0;
|
|
bits = 0;
|
|
break;
|
|
case FLAGS:
|
|
while (bits < 16) {
|
|
if (have === 0) {
|
|
break inf_leave;
|
|
}
|
|
have--;
|
|
hold += input[next++] << bits;
|
|
bits += 8;
|
|
}
|
|
state.flags = hold;
|
|
if ((state.flags & 255) !== Z_DEFLATED) {
|
|
strm.msg = "unknown compression method";
|
|
state.mode = BAD2;
|
|
break;
|
|
}
|
|
if (state.flags & 57344) {
|
|
strm.msg = "unknown header flags set";
|
|
state.mode = BAD2;
|
|
break;
|
|
}
|
|
if (state.head) {
|
|
state.head.text = hold >> 8 & 1;
|
|
}
|
|
if (state.flags & 512) {
|
|
hbuf[0] = hold & 255;
|
|
hbuf[1] = hold >>> 8 & 255;
|
|
state.check = makeTable(state.check, hbuf, 2, 0);
|
|
}
|
|
hold = 0;
|
|
bits = 0;
|
|
state.mode = TIME;
|
|
/* falls through */
|
|
case TIME:
|
|
while (bits < 32) {
|
|
if (have === 0) {
|
|
break inf_leave;
|
|
}
|
|
have--;
|
|
hold += input[next++] << bits;
|
|
bits += 8;
|
|
}
|
|
if (state.head) {
|
|
state.head.time = hold;
|
|
}
|
|
if (state.flags & 512) {
|
|
hbuf[0] = hold & 255;
|
|
hbuf[1] = hold >>> 8 & 255;
|
|
hbuf[2] = hold >>> 16 & 255;
|
|
hbuf[3] = hold >>> 24 & 255;
|
|
state.check = makeTable(state.check, hbuf, 4, 0);
|
|
}
|
|
hold = 0;
|
|
bits = 0;
|
|
state.mode = OS;
|
|
/* falls through */
|
|
case OS:
|
|
while (bits < 16) {
|
|
if (have === 0) {
|
|
break inf_leave;
|
|
}
|
|
have--;
|
|
hold += input[next++] << bits;
|
|
bits += 8;
|
|
}
|
|
if (state.head) {
|
|
state.head.xflags = hold & 255;
|
|
state.head.os = hold >> 8;
|
|
}
|
|
if (state.flags & 512) {
|
|
hbuf[0] = hold & 255;
|
|
hbuf[1] = hold >>> 8 & 255;
|
|
state.check = makeTable(state.check, hbuf, 2, 0);
|
|
}
|
|
hold = 0;
|
|
bits = 0;
|
|
state.mode = EXLEN;
|
|
/* falls through */
|
|
case EXLEN:
|
|
if (state.flags & 1024) {
|
|
while (bits < 16) {
|
|
if (have === 0) {
|
|
break inf_leave;
|
|
}
|
|
have--;
|
|
hold += input[next++] << bits;
|
|
bits += 8;
|
|
}
|
|
state.length = hold;
|
|
if (state.head) {
|
|
state.head.extra_len = hold;
|
|
}
|
|
if (state.flags & 512) {
|
|
hbuf[0] = hold & 255;
|
|
hbuf[1] = hold >>> 8 & 255;
|
|
state.check = makeTable(state.check, hbuf, 2, 0);
|
|
}
|
|
hold = 0;
|
|
bits = 0;
|
|
} else if (state.head) {
|
|
state.head.extra = null;
|
|
}
|
|
state.mode = EXTRA;
|
|
/* falls through */
|
|
case EXTRA:
|
|
if (state.flags & 1024) {
|
|
copy = state.length;
|
|
if (copy > have) {
|
|
copy = have;
|
|
}
|
|
if (copy) {
|
|
if (state.head) {
|
|
len = state.head.extra_len - state.length;
|
|
if (!state.head.extra) {
|
|
state.head.extra = new Array(state.head.extra_len);
|
|
}
|
|
arraySet(
|
|
state.head.extra,
|
|
input,
|
|
next,
|
|
// extra field is limited to 65536 bytes
|
|
// - no need for additional size check
|
|
copy,
|
|
/*len + copy > state.head.extra_max - len ? state.head.extra_max : copy,*/
|
|
len
|
|
);
|
|
}
|
|
if (state.flags & 512) {
|
|
state.check = makeTable(state.check, input, copy, next);
|
|
}
|
|
have -= copy;
|
|
next += copy;
|
|
state.length -= copy;
|
|
}
|
|
if (state.length) {
|
|
break inf_leave;
|
|
}
|
|
}
|
|
state.length = 0;
|
|
state.mode = NAME;
|
|
/* falls through */
|
|
case NAME:
|
|
if (state.flags & 2048) {
|
|
if (have === 0) {
|
|
break inf_leave;
|
|
}
|
|
copy = 0;
|
|
do {
|
|
len = input[next + copy++];
|
|
if (state.head && len && state.length < 65536) {
|
|
state.head.name += String.fromCharCode(len);
|
|
}
|
|
} while (len && copy < have);
|
|
if (state.flags & 512) {
|
|
state.check = makeTable(state.check, input, copy, next);
|
|
}
|
|
have -= copy;
|
|
next += copy;
|
|
if (len) {
|
|
break inf_leave;
|
|
}
|
|
} else if (state.head) {
|
|
state.head.name = null;
|
|
}
|
|
state.length = 0;
|
|
state.mode = COMMENT;
|
|
/* falls through */
|
|
case COMMENT:
|
|
if (state.flags & 4096) {
|
|
if (have === 0) {
|
|
break inf_leave;
|
|
}
|
|
copy = 0;
|
|
do {
|
|
len = input[next + copy++];
|
|
if (state.head && len && state.length < 65536) {
|
|
state.head.comment += String.fromCharCode(len);
|
|
}
|
|
} while (len && copy < have);
|
|
if (state.flags & 512) {
|
|
state.check = makeTable(state.check, input, copy, next);
|
|
}
|
|
have -= copy;
|
|
next += copy;
|
|
if (len) {
|
|
break inf_leave;
|
|
}
|
|
} else if (state.head) {
|
|
state.head.comment = null;
|
|
}
|
|
state.mode = HCRC;
|
|
/* falls through */
|
|
case HCRC:
|
|
if (state.flags & 512) {
|
|
while (bits < 16) {
|
|
if (have === 0) {
|
|
break inf_leave;
|
|
}
|
|
have--;
|
|
hold += input[next++] << bits;
|
|
bits += 8;
|
|
}
|
|
if (hold !== (state.check & 65535)) {
|
|
strm.msg = "header crc mismatch";
|
|
state.mode = BAD2;
|
|
break;
|
|
}
|
|
hold = 0;
|
|
bits = 0;
|
|
}
|
|
if (state.head) {
|
|
state.head.hcrc = state.flags >> 9 & 1;
|
|
state.head.done = true;
|
|
}
|
|
strm.adler = state.check = 0;
|
|
state.mode = TYPE2;
|
|
break;
|
|
case DICTID:
|
|
while (bits < 32) {
|
|
if (have === 0) {
|
|
break inf_leave;
|
|
}
|
|
have--;
|
|
hold += input[next++] << bits;
|
|
bits += 8;
|
|
}
|
|
strm.adler = state.check = zswap32(hold);
|
|
hold = 0;
|
|
bits = 0;
|
|
state.mode = DICT;
|
|
/* falls through */
|
|
case DICT:
|
|
if (state.havedict === 0) {
|
|
strm.next_out = put;
|
|
strm.avail_out = left;
|
|
strm.next_in = next;
|
|
strm.avail_in = have;
|
|
state.hold = hold;
|
|
state.bits = bits;
|
|
return Z_NEED_DICT;
|
|
}
|
|
strm.adler = state.check = 1;
|
|
state.mode = TYPE2;
|
|
/* falls through */
|
|
case TYPE2:
|
|
if (flush === Z_BLOCK || flush === Z_TREES) {
|
|
break inf_leave;
|
|
}
|
|
/* falls through */
|
|
case TYPEDO:
|
|
if (state.last) {
|
|
hold >>>= bits & 7;
|
|
bits -= bits & 7;
|
|
state.mode = CHECK;
|
|
break;
|
|
}
|
|
while (bits < 3) {
|
|
if (have === 0) {
|
|
break inf_leave;
|
|
}
|
|
have--;
|
|
hold += input[next++] << bits;
|
|
bits += 8;
|
|
}
|
|
state.last = hold & 1;
|
|
hold >>>= 1;
|
|
bits -= 1;
|
|
switch (hold & 3) {
|
|
case 0:
|
|
state.mode = STORED;
|
|
break;
|
|
case 1:
|
|
fixedtables(state);
|
|
state.mode = LEN_;
|
|
if (flush === Z_TREES) {
|
|
hold >>>= 2;
|
|
bits -= 2;
|
|
break inf_leave;
|
|
}
|
|
break;
|
|
case 2:
|
|
state.mode = TABLE;
|
|
break;
|
|
case 3:
|
|
strm.msg = "invalid block type";
|
|
state.mode = BAD2;
|
|
}
|
|
hold >>>= 2;
|
|
bits -= 2;
|
|
break;
|
|
case STORED:
|
|
hold >>>= bits & 7;
|
|
bits -= bits & 7;
|
|
while (bits < 32) {
|
|
if (have === 0) {
|
|
break inf_leave;
|
|
}
|
|
have--;
|
|
hold += input[next++] << bits;
|
|
bits += 8;
|
|
}
|
|
if ((hold & 65535) !== (hold >>> 16 ^ 65535)) {
|
|
strm.msg = "invalid stored block lengths";
|
|
state.mode = BAD2;
|
|
break;
|
|
}
|
|
state.length = hold & 65535;
|
|
hold = 0;
|
|
bits = 0;
|
|
state.mode = COPY_;
|
|
if (flush === Z_TREES) {
|
|
break inf_leave;
|
|
}
|
|
/* falls through */
|
|
case COPY_:
|
|
state.mode = COPY;
|
|
/* falls through */
|
|
case COPY:
|
|
copy = state.length;
|
|
if (copy) {
|
|
if (copy > have) {
|
|
copy = have;
|
|
}
|
|
if (copy > left) {
|
|
copy = left;
|
|
}
|
|
if (copy === 0) {
|
|
break inf_leave;
|
|
}
|
|
arraySet(output, input, next, copy, put);
|
|
have -= copy;
|
|
next += copy;
|
|
left -= copy;
|
|
put += copy;
|
|
state.length -= copy;
|
|
break;
|
|
}
|
|
state.mode = TYPE2;
|
|
break;
|
|
case TABLE:
|
|
while (bits < 14) {
|
|
if (have === 0) {
|
|
break inf_leave;
|
|
}
|
|
have--;
|
|
hold += input[next++] << bits;
|
|
bits += 8;
|
|
}
|
|
state.nlen = (hold & 31) + 257;
|
|
hold >>>= 5;
|
|
bits -= 5;
|
|
state.ndist = (hold & 31) + 1;
|
|
hold >>>= 5;
|
|
bits -= 5;
|
|
state.ncode = (hold & 15) + 4;
|
|
hold >>>= 4;
|
|
bits -= 4;
|
|
if (state.nlen > 286 || state.ndist > 30) {
|
|
strm.msg = "too many length or distance symbols";
|
|
state.mode = BAD2;
|
|
break;
|
|
}
|
|
state.have = 0;
|
|
state.mode = LENLENS;
|
|
/* falls through */
|
|
case LENLENS:
|
|
while (state.have < state.ncode) {
|
|
while (bits < 3) {
|
|
if (have === 0) {
|
|
break inf_leave;
|
|
}
|
|
have--;
|
|
hold += input[next++] << bits;
|
|
bits += 8;
|
|
}
|
|
state.lens[order[state.have++]] = hold & 7;
|
|
hold >>>= 3;
|
|
bits -= 3;
|
|
}
|
|
while (state.have < 19) {
|
|
state.lens[order[state.have++]] = 0;
|
|
}
|
|
state.lencode = state.lendyn;
|
|
state.lenbits = 7;
|
|
opts = { bits: state.lenbits };
|
|
ret = inflate_table(CODES2, state.lens, 0, 19, state.lencode, 0, state.work, opts);
|
|
state.lenbits = opts.bits;
|
|
if (ret) {
|
|
strm.msg = "invalid code lengths set";
|
|
state.mode = BAD2;
|
|
break;
|
|
}
|
|
state.have = 0;
|
|
state.mode = CODELENS;
|
|
/* falls through */
|
|
case CODELENS:
|
|
while (state.have < state.nlen + state.ndist) {
|
|
for (; ; ) {
|
|
here = state.lencode[hold & (1 << state.lenbits) - 1];
|
|
here_bits = here >>> 24;
|
|
here_op = here >>> 16 & 255;
|
|
here_val = here & 65535;
|
|
if (here_bits <= bits) {
|
|
break;
|
|
}
|
|
if (have === 0) {
|
|
break inf_leave;
|
|
}
|
|
have--;
|
|
hold += input[next++] << bits;
|
|
bits += 8;
|
|
}
|
|
if (here_val < 16) {
|
|
hold >>>= here_bits;
|
|
bits -= here_bits;
|
|
state.lens[state.have++] = here_val;
|
|
} else {
|
|
if (here_val === 16) {
|
|
n = here_bits + 2;
|
|
while (bits < n) {
|
|
if (have === 0) {
|
|
break inf_leave;
|
|
}
|
|
have--;
|
|
hold += input[next++] << bits;
|
|
bits += 8;
|
|
}
|
|
hold >>>= here_bits;
|
|
bits -= here_bits;
|
|
if (state.have === 0) {
|
|
strm.msg = "invalid bit length repeat";
|
|
state.mode = BAD2;
|
|
break;
|
|
}
|
|
len = state.lens[state.have - 1];
|
|
copy = 3 + (hold & 3);
|
|
hold >>>= 2;
|
|
bits -= 2;
|
|
} else if (here_val === 17) {
|
|
n = here_bits + 3;
|
|
while (bits < n) {
|
|
if (have === 0) {
|
|
break inf_leave;
|
|
}
|
|
have--;
|
|
hold += input[next++] << bits;
|
|
bits += 8;
|
|
}
|
|
hold >>>= here_bits;
|
|
bits -= here_bits;
|
|
len = 0;
|
|
copy = 3 + (hold & 7);
|
|
hold >>>= 3;
|
|
bits -= 3;
|
|
} else {
|
|
n = here_bits + 7;
|
|
while (bits < n) {
|
|
if (have === 0) {
|
|
break inf_leave;
|
|
}
|
|
have--;
|
|
hold += input[next++] << bits;
|
|
bits += 8;
|
|
}
|
|
hold >>>= here_bits;
|
|
bits -= here_bits;
|
|
len = 0;
|
|
copy = 11 + (hold & 127);
|
|
hold >>>= 7;
|
|
bits -= 7;
|
|
}
|
|
if (state.have + copy > state.nlen + state.ndist) {
|
|
strm.msg = "invalid bit length repeat";
|
|
state.mode = BAD2;
|
|
break;
|
|
}
|
|
while (copy--) {
|
|
state.lens[state.have++] = len;
|
|
}
|
|
}
|
|
}
|
|
if (state.mode === BAD2) {
|
|
break;
|
|
}
|
|
if (state.lens[256] === 0) {
|
|
strm.msg = "invalid code -- missing end-of-block";
|
|
state.mode = BAD2;
|
|
break;
|
|
}
|
|
state.lenbits = 9;
|
|
opts = { bits: state.lenbits };
|
|
ret = inflate_table(LENS2, state.lens, 0, state.nlen, state.lencode, 0, state.work, opts);
|
|
state.lenbits = opts.bits;
|
|
if (ret) {
|
|
strm.msg = "invalid literal/lengths set";
|
|
state.mode = BAD2;
|
|
break;
|
|
}
|
|
state.distbits = 6;
|
|
state.distcode = state.distdyn;
|
|
opts = { bits: state.distbits };
|
|
ret = inflate_table(DISTS2, state.lens, state.nlen, state.ndist, state.distcode, 0, state.work, opts);
|
|
state.distbits = opts.bits;
|
|
if (ret) {
|
|
strm.msg = "invalid distances set";
|
|
state.mode = BAD2;
|
|
break;
|
|
}
|
|
state.mode = LEN_;
|
|
if (flush === Z_TREES) {
|
|
break inf_leave;
|
|
}
|
|
/* falls through */
|
|
case LEN_:
|
|
state.mode = LEN;
|
|
/* falls through */
|
|
case LEN:
|
|
if (have >= 6 && left >= 258) {
|
|
strm.next_out = put;
|
|
strm.avail_out = left;
|
|
strm.next_in = next;
|
|
strm.avail_in = have;
|
|
state.hold = hold;
|
|
state.bits = bits;
|
|
inflate_fast(strm, _out);
|
|
put = strm.next_out;
|
|
output = strm.output;
|
|
left = strm.avail_out;
|
|
next = strm.next_in;
|
|
input = strm.input;
|
|
have = strm.avail_in;
|
|
hold = state.hold;
|
|
bits = state.bits;
|
|
if (state.mode === TYPE2) {
|
|
state.back = -1;
|
|
}
|
|
break;
|
|
}
|
|
state.back = 0;
|
|
for (; ; ) {
|
|
here = state.lencode[hold & (1 << state.lenbits) - 1];
|
|
here_bits = here >>> 24;
|
|
here_op = here >>> 16 & 255;
|
|
here_val = here & 65535;
|
|
if (here_bits <= bits) {
|
|
break;
|
|
}
|
|
if (have === 0) {
|
|
break inf_leave;
|
|
}
|
|
have--;
|
|
hold += input[next++] << bits;
|
|
bits += 8;
|
|
}
|
|
if (here_op && (here_op & 240) === 0) {
|
|
last_bits = here_bits;
|
|
last_op = here_op;
|
|
last_val = here_val;
|
|
for (; ; ) {
|
|
here = state.lencode[last_val + ((hold & (1 << last_bits + last_op) - 1) >> last_bits)];
|
|
here_bits = here >>> 24;
|
|
here_op = here >>> 16 & 255;
|
|
here_val = here & 65535;
|
|
if (last_bits + here_bits <= bits) {
|
|
break;
|
|
}
|
|
if (have === 0) {
|
|
break inf_leave;
|
|
}
|
|
have--;
|
|
hold += input[next++] << bits;
|
|
bits += 8;
|
|
}
|
|
hold >>>= last_bits;
|
|
bits -= last_bits;
|
|
state.back += last_bits;
|
|
}
|
|
hold >>>= here_bits;
|
|
bits -= here_bits;
|
|
state.back += here_bits;
|
|
state.length = here_val;
|
|
if (here_op === 0) {
|
|
state.mode = LIT;
|
|
break;
|
|
}
|
|
if (here_op & 32) {
|
|
state.back = -1;
|
|
state.mode = TYPE2;
|
|
break;
|
|
}
|
|
if (here_op & 64) {
|
|
strm.msg = "invalid literal/length code";
|
|
state.mode = BAD2;
|
|
break;
|
|
}
|
|
state.extra = here_op & 15;
|
|
state.mode = LENEXT;
|
|
/* falls through */
|
|
case LENEXT:
|
|
if (state.extra) {
|
|
n = state.extra;
|
|
while (bits < n) {
|
|
if (have === 0) {
|
|
break inf_leave;
|
|
}
|
|
have--;
|
|
hold += input[next++] << bits;
|
|
bits += 8;
|
|
}
|
|
state.length += hold & (1 << state.extra) - 1;
|
|
hold >>>= state.extra;
|
|
bits -= state.extra;
|
|
state.back += state.extra;
|
|
}
|
|
state.was = state.length;
|
|
state.mode = DIST;
|
|
/* falls through */
|
|
case DIST:
|
|
for (; ; ) {
|
|
here = state.distcode[hold & (1 << state.distbits) - 1];
|
|
here_bits = here >>> 24;
|
|
here_op = here >>> 16 & 255;
|
|
here_val = here & 65535;
|
|
if (here_bits <= bits) {
|
|
break;
|
|
}
|
|
if (have === 0) {
|
|
break inf_leave;
|
|
}
|
|
have--;
|
|
hold += input[next++] << bits;
|
|
bits += 8;
|
|
}
|
|
if ((here_op & 240) === 0) {
|
|
last_bits = here_bits;
|
|
last_op = here_op;
|
|
last_val = here_val;
|
|
for (; ; ) {
|
|
here = state.distcode[last_val + ((hold & (1 << last_bits + last_op) - 1) >> last_bits)];
|
|
here_bits = here >>> 24;
|
|
here_op = here >>> 16 & 255;
|
|
here_val = here & 65535;
|
|
if (last_bits + here_bits <= bits) {
|
|
break;
|
|
}
|
|
if (have === 0) {
|
|
break inf_leave;
|
|
}
|
|
have--;
|
|
hold += input[next++] << bits;
|
|
bits += 8;
|
|
}
|
|
hold >>>= last_bits;
|
|
bits -= last_bits;
|
|
state.back += last_bits;
|
|
}
|
|
hold >>>= here_bits;
|
|
bits -= here_bits;
|
|
state.back += here_bits;
|
|
if (here_op & 64) {
|
|
strm.msg = "invalid distance code";
|
|
state.mode = BAD2;
|
|
break;
|
|
}
|
|
state.offset = here_val;
|
|
state.extra = here_op & 15;
|
|
state.mode = DISTEXT;
|
|
/* falls through */
|
|
case DISTEXT:
|
|
if (state.extra) {
|
|
n = state.extra;
|
|
while (bits < n) {
|
|
if (have === 0) {
|
|
break inf_leave;
|
|
}
|
|
have--;
|
|
hold += input[next++] << bits;
|
|
bits += 8;
|
|
}
|
|
state.offset += hold & (1 << state.extra) - 1;
|
|
hold >>>= state.extra;
|
|
bits -= state.extra;
|
|
state.back += state.extra;
|
|
}
|
|
if (state.offset > state.dmax) {
|
|
strm.msg = "invalid distance too far back";
|
|
state.mode = BAD2;
|
|
break;
|
|
}
|
|
state.mode = MATCH;
|
|
/* falls through */
|
|
case MATCH:
|
|
if (left === 0) {
|
|
break inf_leave;
|
|
}
|
|
copy = _out - left;
|
|
if (state.offset > copy) {
|
|
copy = state.offset - copy;
|
|
if (copy > state.whave) {
|
|
if (state.sane) {
|
|
strm.msg = "invalid distance too far back";
|
|
state.mode = BAD2;
|
|
break;
|
|
}
|
|
}
|
|
if (copy > state.wnext) {
|
|
copy -= state.wnext;
|
|
from = state.wsize - copy;
|
|
} else {
|
|
from = state.wnext - copy;
|
|
}
|
|
if (copy > state.length) {
|
|
copy = state.length;
|
|
}
|
|
from_source = state.window;
|
|
} else {
|
|
from_source = output;
|
|
from = put - state.offset;
|
|
copy = state.length;
|
|
}
|
|
if (copy > left) {
|
|
copy = left;
|
|
}
|
|
left -= copy;
|
|
state.length -= copy;
|
|
do {
|
|
output[put++] = from_source[from++];
|
|
} while (--copy);
|
|
if (state.length === 0) {
|
|
state.mode = LEN;
|
|
}
|
|
break;
|
|
case LIT:
|
|
if (left === 0) {
|
|
break inf_leave;
|
|
}
|
|
output[put++] = state.length;
|
|
left--;
|
|
state.mode = LEN;
|
|
break;
|
|
case CHECK:
|
|
if (state.wrap) {
|
|
while (bits < 32) {
|
|
if (have === 0) {
|
|
break inf_leave;
|
|
}
|
|
have--;
|
|
hold |= input[next++] << bits;
|
|
bits += 8;
|
|
}
|
|
_out -= left;
|
|
strm.total_out += _out;
|
|
state.total += _out;
|
|
if (_out) {
|
|
strm.adler = state.check = /*UPDATE(state.check, put - _out, _out);*/
|
|
state.flags ? makeTable(state.check, output, _out, put - _out) : adler32(state.check, output, _out, put - _out);
|
|
}
|
|
_out = left;
|
|
if ((state.flags ? hold : zswap32(hold)) !== state.check) {
|
|
strm.msg = "incorrect data check";
|
|
state.mode = BAD2;
|
|
break;
|
|
}
|
|
hold = 0;
|
|
bits = 0;
|
|
}
|
|
state.mode = LENGTH;
|
|
/* falls through */
|
|
case LENGTH:
|
|
if (state.wrap && state.flags) {
|
|
while (bits < 32) {
|
|
if (have === 0) {
|
|
break inf_leave;
|
|
}
|
|
have--;
|
|
hold += input[next++] << bits;
|
|
bits += 8;
|
|
}
|
|
if (hold !== (state.total & 4294967295)) {
|
|
strm.msg = "incorrect length check";
|
|
state.mode = BAD2;
|
|
break;
|
|
}
|
|
hold = 0;
|
|
bits = 0;
|
|
}
|
|
state.mode = DONE;
|
|
/* falls through */
|
|
case DONE:
|
|
ret = Z_STREAM_END;
|
|
break inf_leave;
|
|
case BAD2:
|
|
ret = Z_DATA_ERROR;
|
|
break inf_leave;
|
|
case MEM:
|
|
return Z_MEM_ERROR;
|
|
case SYNC:
|
|
/* falls through */
|
|
default:
|
|
return Z_STREAM_ERROR;
|
|
}
|
|
}
|
|
strm.next_out = put;
|
|
strm.avail_out = left;
|
|
strm.next_in = next;
|
|
strm.avail_in = have;
|
|
state.hold = hold;
|
|
state.bits = bits;
|
|
if (state.wsize || _out !== strm.avail_out && state.mode < BAD2 && (state.mode < CHECK || flush !== Z_FINISH)) {
|
|
if (updatewindow(strm, strm.output, strm.next_out, _out - strm.avail_out)) {
|
|
state.mode = MEM;
|
|
return Z_MEM_ERROR;
|
|
}
|
|
}
|
|
_in -= strm.avail_in;
|
|
_out -= strm.avail_out;
|
|
strm.total_in += _in;
|
|
strm.total_out += _out;
|
|
state.total += _out;
|
|
if (state.wrap && _out) {
|
|
strm.adler = state.check = /*UPDATE(state.check, strm.next_out - _out, _out);*/
|
|
state.flags ? makeTable(state.check, output, _out, strm.next_out - _out) : adler32(state.check, output, _out, strm.next_out - _out);
|
|
}
|
|
strm.data_type = state.bits + (state.last ? 64 : 0) + (state.mode === TYPE2 ? 128 : 0) + (state.mode === LEN_ || state.mode === COPY_ ? 256 : 0);
|
|
if ((_in === 0 && _out === 0 || flush === Z_FINISH) && ret === Z_OK) {
|
|
ret = Z_BUF_ERROR;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
// vendor/pako/lib/zlib/zstream.js
|
|
function ZStream() {
|
|
this.input = null;
|
|
this.next_in = 0;
|
|
this.avail_in = 0;
|
|
this.total_in = 0;
|
|
this.output = null;
|
|
this.next_out = 0;
|
|
this.avail_out = 0;
|
|
this.total_out = 0;
|
|
this.msg = "";
|
|
this.state = null;
|
|
this.data_type = 2;
|
|
this.adler = 0;
|
|
}
|
|
|
|
// core/inflator.js
|
|
var Inflate = class {
|
|
constructor() {
|
|
this.strm = new ZStream();
|
|
this.chunkSize = 1024 * 10 * 10;
|
|
this.strm.output = new Uint8Array(this.chunkSize);
|
|
inflateInit(this.strm);
|
|
}
|
|
setInput(data) {
|
|
if (!data) {
|
|
this.strm.input = null;
|
|
this.strm.avail_in = 0;
|
|
this.strm.next_in = 0;
|
|
} else {
|
|
this.strm.input = data;
|
|
this.strm.avail_in = this.strm.input.length;
|
|
this.strm.next_in = 0;
|
|
}
|
|
}
|
|
inflate(expected) {
|
|
if (expected > this.chunkSize) {
|
|
this.chunkSize = expected;
|
|
this.strm.output = new Uint8Array(this.chunkSize);
|
|
}
|
|
this.strm.next_out = 0;
|
|
this.strm.avail_out = expected;
|
|
let ret = inflate(this.strm, 0);
|
|
if (ret < 0) {
|
|
throw new Error("zlib inflate failed");
|
|
}
|
|
if (this.strm.next_out != expected) {
|
|
throw new Error("Incomplete zlib block");
|
|
}
|
|
return new Uint8Array(this.strm.output.buffer, 0, this.strm.next_out);
|
|
}
|
|
reset() {
|
|
inflateReset(this.strm);
|
|
}
|
|
};
|
|
|
|
// vendor/pako/lib/zlib/trees.js
|
|
var Z_FIXED = 4;
|
|
var Z_BINARY = 0;
|
|
var Z_TEXT = 1;
|
|
var Z_UNKNOWN = 2;
|
|
function zero(buf) {
|
|
var len = buf.length;
|
|
while (--len >= 0) {
|
|
buf[len] = 0;
|
|
}
|
|
}
|
|
var STORED_BLOCK = 0;
|
|
var STATIC_TREES = 1;
|
|
var DYN_TREES = 2;
|
|
var MIN_MATCH = 3;
|
|
var MAX_MATCH = 258;
|
|
var LENGTH_CODES = 29;
|
|
var LITERALS = 256;
|
|
var L_CODES = LITERALS + 1 + LENGTH_CODES;
|
|
var D_CODES = 30;
|
|
var BL_CODES = 19;
|
|
var HEAP_SIZE = 2 * L_CODES + 1;
|
|
var MAX_BITS = 15;
|
|
var Buf_size = 16;
|
|
var MAX_BL_BITS = 7;
|
|
var END_BLOCK = 256;
|
|
var REP_3_6 = 16;
|
|
var REPZ_3_10 = 17;
|
|
var REPZ_11_138 = 18;
|
|
var extra_lbits = (
|
|
/* extra bits for each length code */
|
|
[0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0]
|
|
);
|
|
var extra_dbits = (
|
|
/* extra bits for each distance code */
|
|
[0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13]
|
|
);
|
|
var extra_blbits = (
|
|
/* extra bits for each bit length code */
|
|
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 7]
|
|
);
|
|
var bl_order = [16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15];
|
|
var DIST_CODE_LEN = 512;
|
|
var static_ltree = new Array((L_CODES + 2) * 2);
|
|
zero(static_ltree);
|
|
var static_dtree = new Array(D_CODES * 2);
|
|
zero(static_dtree);
|
|
var _dist_code = new Array(DIST_CODE_LEN);
|
|
zero(_dist_code);
|
|
var _length_code = new Array(MAX_MATCH - MIN_MATCH + 1);
|
|
zero(_length_code);
|
|
var base_length = new Array(LENGTH_CODES);
|
|
zero(base_length);
|
|
var base_dist = new Array(D_CODES);
|
|
zero(base_dist);
|
|
function StaticTreeDesc(static_tree, extra_bits, extra_base, elems, max_length) {
|
|
this.static_tree = static_tree;
|
|
this.extra_bits = extra_bits;
|
|
this.extra_base = extra_base;
|
|
this.elems = elems;
|
|
this.max_length = max_length;
|
|
this.has_stree = static_tree && static_tree.length;
|
|
}
|
|
var static_l_desc;
|
|
var static_d_desc;
|
|
var static_bl_desc;
|
|
function TreeDesc(dyn_tree, stat_desc) {
|
|
this.dyn_tree = dyn_tree;
|
|
this.max_code = 0;
|
|
this.stat_desc = stat_desc;
|
|
}
|
|
function d_code(dist) {
|
|
return dist < 256 ? _dist_code[dist] : _dist_code[256 + (dist >>> 7)];
|
|
}
|
|
function put_short(s, w) {
|
|
s.pending_buf[s.pending++] = w & 255;
|
|
s.pending_buf[s.pending++] = w >>> 8 & 255;
|
|
}
|
|
function send_bits(s, value, length) {
|
|
if (s.bi_valid > Buf_size - length) {
|
|
s.bi_buf |= value << s.bi_valid & 65535;
|
|
put_short(s, s.bi_buf);
|
|
s.bi_buf = value >> Buf_size - s.bi_valid;
|
|
s.bi_valid += length - Buf_size;
|
|
} else {
|
|
s.bi_buf |= value << s.bi_valid & 65535;
|
|
s.bi_valid += length;
|
|
}
|
|
}
|
|
function send_code(s, c2, tree) {
|
|
send_bits(
|
|
s,
|
|
tree[c2 * 2],
|
|
tree[c2 * 2 + 1]
|
|
/*.Len*/
|
|
);
|
|
}
|
|
function bi_reverse(code, len) {
|
|
var res = 0;
|
|
do {
|
|
res |= code & 1;
|
|
code >>>= 1;
|
|
res <<= 1;
|
|
} while (--len > 0);
|
|
return res >>> 1;
|
|
}
|
|
function bi_flush(s) {
|
|
if (s.bi_valid === 16) {
|
|
put_short(s, s.bi_buf);
|
|
s.bi_buf = 0;
|
|
s.bi_valid = 0;
|
|
} else if (s.bi_valid >= 8) {
|
|
s.pending_buf[s.pending++] = s.bi_buf & 255;
|
|
s.bi_buf >>= 8;
|
|
s.bi_valid -= 8;
|
|
}
|
|
}
|
|
function gen_bitlen(s, desc) {
|
|
var tree = desc.dyn_tree;
|
|
var max_code = desc.max_code;
|
|
var stree = desc.stat_desc.static_tree;
|
|
var has_stree = desc.stat_desc.has_stree;
|
|
var extra = desc.stat_desc.extra_bits;
|
|
var base = desc.stat_desc.extra_base;
|
|
var max_length = desc.stat_desc.max_length;
|
|
var h;
|
|
var n, m;
|
|
var bits;
|
|
var xbits;
|
|
var f2;
|
|
var overflow = 0;
|
|
for (bits = 0; bits <= MAX_BITS; bits++) {
|
|
s.bl_count[bits] = 0;
|
|
}
|
|
tree[s.heap[s.heap_max] * 2 + 1] = 0;
|
|
for (h = s.heap_max + 1; h < HEAP_SIZE; h++) {
|
|
n = s.heap[h];
|
|
bits = tree[tree[n * 2 + 1] * 2 + 1] + 1;
|
|
if (bits > max_length) {
|
|
bits = max_length;
|
|
overflow++;
|
|
}
|
|
tree[n * 2 + 1] = bits;
|
|
if (n > max_code) {
|
|
continue;
|
|
}
|
|
s.bl_count[bits]++;
|
|
xbits = 0;
|
|
if (n >= base) {
|
|
xbits = extra[n - base];
|
|
}
|
|
f2 = tree[n * 2];
|
|
s.opt_len += f2 * (bits + xbits);
|
|
if (has_stree) {
|
|
s.static_len += f2 * (stree[n * 2 + 1] + xbits);
|
|
}
|
|
}
|
|
if (overflow === 0) {
|
|
return;
|
|
}
|
|
do {
|
|
bits = max_length - 1;
|
|
while (s.bl_count[bits] === 0) {
|
|
bits--;
|
|
}
|
|
s.bl_count[bits]--;
|
|
s.bl_count[bits + 1] += 2;
|
|
s.bl_count[max_length]--;
|
|
overflow -= 2;
|
|
} while (overflow > 0);
|
|
for (bits = max_length; bits !== 0; bits--) {
|
|
n = s.bl_count[bits];
|
|
while (n !== 0) {
|
|
m = s.heap[--h];
|
|
if (m > max_code) {
|
|
continue;
|
|
}
|
|
if (tree[m * 2 + 1] !== bits) {
|
|
s.opt_len += (bits - tree[m * 2 + 1]) * tree[m * 2];
|
|
tree[m * 2 + 1] = bits;
|
|
}
|
|
n--;
|
|
}
|
|
}
|
|
}
|
|
function gen_codes(tree, max_code, bl_count) {
|
|
var next_code = new Array(MAX_BITS + 1);
|
|
var code = 0;
|
|
var bits;
|
|
var n;
|
|
for (bits = 1; bits <= MAX_BITS; bits++) {
|
|
next_code[bits] = code = code + bl_count[bits - 1] << 1;
|
|
}
|
|
for (n = 0; n <= max_code; n++) {
|
|
var len = tree[n * 2 + 1];
|
|
if (len === 0) {
|
|
continue;
|
|
}
|
|
tree[n * 2] = bi_reverse(next_code[len]++, len);
|
|
}
|
|
}
|
|
function tr_static_init() {
|
|
var n;
|
|
var bits;
|
|
var length;
|
|
var code;
|
|
var dist;
|
|
var bl_count = new Array(MAX_BITS + 1);
|
|
length = 0;
|
|
for (code = 0; code < LENGTH_CODES - 1; code++) {
|
|
base_length[code] = length;
|
|
for (n = 0; n < 1 << extra_lbits[code]; n++) {
|
|
_length_code[length++] = code;
|
|
}
|
|
}
|
|
_length_code[length - 1] = code;
|
|
dist = 0;
|
|
for (code = 0; code < 16; code++) {
|
|
base_dist[code] = dist;
|
|
for (n = 0; n < 1 << extra_dbits[code]; n++) {
|
|
_dist_code[dist++] = code;
|
|
}
|
|
}
|
|
dist >>= 7;
|
|
for (; code < D_CODES; code++) {
|
|
base_dist[code] = dist << 7;
|
|
for (n = 0; n < 1 << extra_dbits[code] - 7; n++) {
|
|
_dist_code[256 + dist++] = code;
|
|
}
|
|
}
|
|
for (bits = 0; bits <= MAX_BITS; bits++) {
|
|
bl_count[bits] = 0;
|
|
}
|
|
n = 0;
|
|
while (n <= 143) {
|
|
static_ltree[n * 2 + 1] = 8;
|
|
n++;
|
|
bl_count[8]++;
|
|
}
|
|
while (n <= 255) {
|
|
static_ltree[n * 2 + 1] = 9;
|
|
n++;
|
|
bl_count[9]++;
|
|
}
|
|
while (n <= 279) {
|
|
static_ltree[n * 2 + 1] = 7;
|
|
n++;
|
|
bl_count[7]++;
|
|
}
|
|
while (n <= 287) {
|
|
static_ltree[n * 2 + 1] = 8;
|
|
n++;
|
|
bl_count[8]++;
|
|
}
|
|
gen_codes(static_ltree, L_CODES + 1, bl_count);
|
|
for (n = 0; n < D_CODES; n++) {
|
|
static_dtree[n * 2 + 1] = 5;
|
|
static_dtree[n * 2] = bi_reverse(n, 5);
|
|
}
|
|
static_l_desc = new StaticTreeDesc(static_ltree, extra_lbits, LITERALS + 1, L_CODES, MAX_BITS);
|
|
static_d_desc = new StaticTreeDesc(static_dtree, extra_dbits, 0, D_CODES, MAX_BITS);
|
|
static_bl_desc = new StaticTreeDesc(new Array(0), extra_blbits, 0, BL_CODES, MAX_BL_BITS);
|
|
}
|
|
function init_block(s) {
|
|
var n;
|
|
for (n = 0; n < L_CODES; n++) {
|
|
s.dyn_ltree[n * 2] = 0;
|
|
}
|
|
for (n = 0; n < D_CODES; n++) {
|
|
s.dyn_dtree[n * 2] = 0;
|
|
}
|
|
for (n = 0; n < BL_CODES; n++) {
|
|
s.bl_tree[n * 2] = 0;
|
|
}
|
|
s.dyn_ltree[END_BLOCK * 2] = 1;
|
|
s.opt_len = s.static_len = 0;
|
|
s.last_lit = s.matches = 0;
|
|
}
|
|
function bi_windup(s) {
|
|
if (s.bi_valid > 8) {
|
|
put_short(s, s.bi_buf);
|
|
} else if (s.bi_valid > 0) {
|
|
s.pending_buf[s.pending++] = s.bi_buf;
|
|
}
|
|
s.bi_buf = 0;
|
|
s.bi_valid = 0;
|
|
}
|
|
function copy_block(s, buf, len, header) {
|
|
bi_windup(s);
|
|
if (header) {
|
|
put_short(s, len);
|
|
put_short(s, ~len);
|
|
}
|
|
arraySet(s.pending_buf, s.window, buf, len, s.pending);
|
|
s.pending += len;
|
|
}
|
|
function smaller(tree, n, m, depth) {
|
|
var _n2 = n * 2;
|
|
var _m2 = m * 2;
|
|
return tree[_n2] < tree[_m2] || tree[_n2] === tree[_m2] && depth[n] <= depth[m];
|
|
}
|
|
function pqdownheap(s, tree, k) {
|
|
var v = s.heap[k];
|
|
var j = k << 1;
|
|
while (j <= s.heap_len) {
|
|
if (j < s.heap_len && smaller(tree, s.heap[j + 1], s.heap[j], s.depth)) {
|
|
j++;
|
|
}
|
|
if (smaller(tree, v, s.heap[j], s.depth)) {
|
|
break;
|
|
}
|
|
s.heap[k] = s.heap[j];
|
|
k = j;
|
|
j <<= 1;
|
|
}
|
|
s.heap[k] = v;
|
|
}
|
|
function compress_block(s, ltree, dtree) {
|
|
var dist;
|
|
var lc;
|
|
var lx = 0;
|
|
var code;
|
|
var extra;
|
|
if (s.last_lit !== 0) {
|
|
do {
|
|
dist = s.pending_buf[s.d_buf + lx * 2] << 8 | s.pending_buf[s.d_buf + lx * 2 + 1];
|
|
lc = s.pending_buf[s.l_buf + lx];
|
|
lx++;
|
|
if (dist === 0) {
|
|
send_code(s, lc, ltree);
|
|
} else {
|
|
code = _length_code[lc];
|
|
send_code(s, code + LITERALS + 1, ltree);
|
|
extra = extra_lbits[code];
|
|
if (extra !== 0) {
|
|
lc -= base_length[code];
|
|
send_bits(s, lc, extra);
|
|
}
|
|
dist--;
|
|
code = d_code(dist);
|
|
send_code(s, code, dtree);
|
|
extra = extra_dbits[code];
|
|
if (extra !== 0) {
|
|
dist -= base_dist[code];
|
|
send_bits(s, dist, extra);
|
|
}
|
|
}
|
|
} while (lx < s.last_lit);
|
|
}
|
|
send_code(s, END_BLOCK, ltree);
|
|
}
|
|
function build_tree(s, desc) {
|
|
var tree = desc.dyn_tree;
|
|
var stree = desc.stat_desc.static_tree;
|
|
var has_stree = desc.stat_desc.has_stree;
|
|
var elems = desc.stat_desc.elems;
|
|
var n, m;
|
|
var max_code = -1;
|
|
var node;
|
|
s.heap_len = 0;
|
|
s.heap_max = HEAP_SIZE;
|
|
for (n = 0; n < elems; n++) {
|
|
if (tree[n * 2] !== 0) {
|
|
s.heap[++s.heap_len] = max_code = n;
|
|
s.depth[n] = 0;
|
|
} else {
|
|
tree[n * 2 + 1] = 0;
|
|
}
|
|
}
|
|
while (s.heap_len < 2) {
|
|
node = s.heap[++s.heap_len] = max_code < 2 ? ++max_code : 0;
|
|
tree[node * 2] = 1;
|
|
s.depth[node] = 0;
|
|
s.opt_len--;
|
|
if (has_stree) {
|
|
s.static_len -= stree[node * 2 + 1];
|
|
}
|
|
}
|
|
desc.max_code = max_code;
|
|
for (n = s.heap_len >> 1; n >= 1; n--) {
|
|
pqdownheap(s, tree, n);
|
|
}
|
|
node = elems;
|
|
do {
|
|
n = s.heap[
|
|
1
|
|
/*SMALLEST*/
|
|
];
|
|
s.heap[
|
|
1
|
|
/*SMALLEST*/
|
|
] = s.heap[s.heap_len--];
|
|
pqdownheap(
|
|
s,
|
|
tree,
|
|
1
|
|
/*SMALLEST*/
|
|
);
|
|
m = s.heap[
|
|
1
|
|
/*SMALLEST*/
|
|
];
|
|
s.heap[--s.heap_max] = n;
|
|
s.heap[--s.heap_max] = m;
|
|
tree[node * 2] = tree[n * 2] + tree[m * 2];
|
|
s.depth[node] = (s.depth[n] >= s.depth[m] ? s.depth[n] : s.depth[m]) + 1;
|
|
tree[n * 2 + 1] = tree[m * 2 + 1] = node;
|
|
s.heap[
|
|
1
|
|
/*SMALLEST*/
|
|
] = node++;
|
|
pqdownheap(
|
|
s,
|
|
tree,
|
|
1
|
|
/*SMALLEST*/
|
|
);
|
|
} while (s.heap_len >= 2);
|
|
s.heap[--s.heap_max] = s.heap[
|
|
1
|
|
/*SMALLEST*/
|
|
];
|
|
gen_bitlen(s, desc);
|
|
gen_codes(tree, max_code, s.bl_count);
|
|
}
|
|
function scan_tree(s, tree, max_code) {
|
|
var n;
|
|
var prevlen = -1;
|
|
var curlen;
|
|
var nextlen = tree[0 * 2 + 1];
|
|
var count = 0;
|
|
var max_count = 7;
|
|
var min_count = 4;
|
|
if (nextlen === 0) {
|
|
max_count = 138;
|
|
min_count = 3;
|
|
}
|
|
tree[(max_code + 1) * 2 + 1] = 65535;
|
|
for (n = 0; n <= max_code; n++) {
|
|
curlen = nextlen;
|
|
nextlen = tree[(n + 1) * 2 + 1];
|
|
if (++count < max_count && curlen === nextlen) {
|
|
continue;
|
|
} else if (count < min_count) {
|
|
s.bl_tree[curlen * 2] += count;
|
|
} else if (curlen !== 0) {
|
|
if (curlen !== prevlen) {
|
|
s.bl_tree[curlen * 2]++;
|
|
}
|
|
s.bl_tree[REP_3_6 * 2]++;
|
|
} else if (count <= 10) {
|
|
s.bl_tree[REPZ_3_10 * 2]++;
|
|
} else {
|
|
s.bl_tree[REPZ_11_138 * 2]++;
|
|
}
|
|
count = 0;
|
|
prevlen = curlen;
|
|
if (nextlen === 0) {
|
|
max_count = 138;
|
|
min_count = 3;
|
|
} else if (curlen === nextlen) {
|
|
max_count = 6;
|
|
min_count = 3;
|
|
} else {
|
|
max_count = 7;
|
|
min_count = 4;
|
|
}
|
|
}
|
|
}
|
|
function send_tree(s, tree, max_code) {
|
|
var n;
|
|
var prevlen = -1;
|
|
var curlen;
|
|
var nextlen = tree[0 * 2 + 1];
|
|
var count = 0;
|
|
var max_count = 7;
|
|
var min_count = 4;
|
|
if (nextlen === 0) {
|
|
max_count = 138;
|
|
min_count = 3;
|
|
}
|
|
for (n = 0; n <= max_code; n++) {
|
|
curlen = nextlen;
|
|
nextlen = tree[(n + 1) * 2 + 1];
|
|
if (++count < max_count && curlen === nextlen) {
|
|
continue;
|
|
} else if (count < min_count) {
|
|
do {
|
|
send_code(s, curlen, s.bl_tree);
|
|
} while (--count !== 0);
|
|
} else if (curlen !== 0) {
|
|
if (curlen !== prevlen) {
|
|
send_code(s, curlen, s.bl_tree);
|
|
count--;
|
|
}
|
|
send_code(s, REP_3_6, s.bl_tree);
|
|
send_bits(s, count - 3, 2);
|
|
} else if (count <= 10) {
|
|
send_code(s, REPZ_3_10, s.bl_tree);
|
|
send_bits(s, count - 3, 3);
|
|
} else {
|
|
send_code(s, REPZ_11_138, s.bl_tree);
|
|
send_bits(s, count - 11, 7);
|
|
}
|
|
count = 0;
|
|
prevlen = curlen;
|
|
if (nextlen === 0) {
|
|
max_count = 138;
|
|
min_count = 3;
|
|
} else if (curlen === nextlen) {
|
|
max_count = 6;
|
|
min_count = 3;
|
|
} else {
|
|
max_count = 7;
|
|
min_count = 4;
|
|
}
|
|
}
|
|
}
|
|
function build_bl_tree(s) {
|
|
var max_blindex;
|
|
scan_tree(s, s.dyn_ltree, s.l_desc.max_code);
|
|
scan_tree(s, s.dyn_dtree, s.d_desc.max_code);
|
|
build_tree(s, s.bl_desc);
|
|
for (max_blindex = BL_CODES - 1; max_blindex >= 3; max_blindex--) {
|
|
if (s.bl_tree[bl_order[max_blindex] * 2 + 1] !== 0) {
|
|
break;
|
|
}
|
|
}
|
|
s.opt_len += 3 * (max_blindex + 1) + 5 + 5 + 4;
|
|
return max_blindex;
|
|
}
|
|
function send_all_trees(s, lcodes, dcodes, blcodes) {
|
|
var rank2;
|
|
send_bits(s, lcodes - 257, 5);
|
|
send_bits(s, dcodes - 1, 5);
|
|
send_bits(s, blcodes - 4, 4);
|
|
for (rank2 = 0; rank2 < blcodes; rank2++) {
|
|
send_bits(s, s.bl_tree[bl_order[rank2] * 2 + 1], 3);
|
|
}
|
|
send_tree(s, s.dyn_ltree, lcodes - 1);
|
|
send_tree(s, s.dyn_dtree, dcodes - 1);
|
|
}
|
|
function detect_data_type(s) {
|
|
var black_mask = 4093624447;
|
|
var n;
|
|
for (n = 0; n <= 31; n++, black_mask >>>= 1) {
|
|
if (black_mask & 1 && s.dyn_ltree[n * 2] !== 0) {
|
|
return Z_BINARY;
|
|
}
|
|
}
|
|
if (s.dyn_ltree[9 * 2] !== 0 || s.dyn_ltree[10 * 2] !== 0 || s.dyn_ltree[13 * 2] !== 0) {
|
|
return Z_TEXT;
|
|
}
|
|
for (n = 32; n < LITERALS; n++) {
|
|
if (s.dyn_ltree[n * 2] !== 0) {
|
|
return Z_TEXT;
|
|
}
|
|
}
|
|
return Z_BINARY;
|
|
}
|
|
var static_init_done = false;
|
|
function _tr_init(s) {
|
|
if (!static_init_done) {
|
|
tr_static_init();
|
|
static_init_done = true;
|
|
}
|
|
s.l_desc = new TreeDesc(s.dyn_ltree, static_l_desc);
|
|
s.d_desc = new TreeDesc(s.dyn_dtree, static_d_desc);
|
|
s.bl_desc = new TreeDesc(s.bl_tree, static_bl_desc);
|
|
s.bi_buf = 0;
|
|
s.bi_valid = 0;
|
|
init_block(s);
|
|
}
|
|
function _tr_stored_block(s, buf, stored_len, last) {
|
|
send_bits(s, (STORED_BLOCK << 1) + (last ? 1 : 0), 3);
|
|
copy_block(s, buf, stored_len, true);
|
|
}
|
|
function _tr_align(s) {
|
|
send_bits(s, STATIC_TREES << 1, 3);
|
|
send_code(s, END_BLOCK, static_ltree);
|
|
bi_flush(s);
|
|
}
|
|
function _tr_flush_block(s, buf, stored_len, last) {
|
|
var opt_lenb, static_lenb;
|
|
var max_blindex = 0;
|
|
if (s.level > 0) {
|
|
if (s.strm.data_type === Z_UNKNOWN) {
|
|
s.strm.data_type = detect_data_type(s);
|
|
}
|
|
build_tree(s, s.l_desc);
|
|
build_tree(s, s.d_desc);
|
|
max_blindex = build_bl_tree(s);
|
|
opt_lenb = s.opt_len + 3 + 7 >>> 3;
|
|
static_lenb = s.static_len + 3 + 7 >>> 3;
|
|
if (static_lenb <= opt_lenb) {
|
|
opt_lenb = static_lenb;
|
|
}
|
|
} else {
|
|
opt_lenb = static_lenb = stored_len + 5;
|
|
}
|
|
if (stored_len + 4 <= opt_lenb && buf !== -1) {
|
|
_tr_stored_block(s, buf, stored_len, last);
|
|
} else if (s.strategy === Z_FIXED || static_lenb === opt_lenb) {
|
|
send_bits(s, (STATIC_TREES << 1) + (last ? 1 : 0), 3);
|
|
compress_block(s, static_ltree, static_dtree);
|
|
} else {
|
|
send_bits(s, (DYN_TREES << 1) + (last ? 1 : 0), 3);
|
|
send_all_trees(s, s.l_desc.max_code + 1, s.d_desc.max_code + 1, max_blindex + 1);
|
|
compress_block(s, s.dyn_ltree, s.dyn_dtree);
|
|
}
|
|
init_block(s);
|
|
if (last) {
|
|
bi_windup(s);
|
|
}
|
|
}
|
|
function _tr_tally(s, dist, lc) {
|
|
s.pending_buf[s.d_buf + s.last_lit * 2] = dist >>> 8 & 255;
|
|
s.pending_buf[s.d_buf + s.last_lit * 2 + 1] = dist & 255;
|
|
s.pending_buf[s.l_buf + s.last_lit] = lc & 255;
|
|
s.last_lit++;
|
|
if (dist === 0) {
|
|
s.dyn_ltree[lc * 2]++;
|
|
} else {
|
|
s.matches++;
|
|
dist--;
|
|
s.dyn_ltree[(_length_code[lc] + LITERALS + 1) * 2]++;
|
|
s.dyn_dtree[d_code(dist) * 2]++;
|
|
}
|
|
return s.last_lit === s.lit_bufsize - 1;
|
|
}
|
|
|
|
// vendor/pako/lib/zlib/messages.js
|
|
var messages_default = {
|
|
2: "need dictionary",
|
|
/* Z_NEED_DICT 2 */
|
|
1: "stream end",
|
|
/* Z_STREAM_END 1 */
|
|
0: "",
|
|
/* Z_OK 0 */
|
|
"-1": "file error",
|
|
/* Z_ERRNO (-1) */
|
|
"-2": "stream error",
|
|
/* Z_STREAM_ERROR (-2) */
|
|
"-3": "data error",
|
|
/* Z_DATA_ERROR (-3) */
|
|
"-4": "insufficient memory",
|
|
/* Z_MEM_ERROR (-4) */
|
|
"-5": "buffer error",
|
|
/* Z_BUF_ERROR (-5) */
|
|
"-6": "incompatible version"
|
|
/* Z_VERSION_ERROR (-6) */
|
|
};
|
|
|
|
// vendor/pako/lib/zlib/deflate.js
|
|
var Z_NO_FLUSH = 0;
|
|
var Z_PARTIAL_FLUSH = 1;
|
|
var Z_FULL_FLUSH = 3;
|
|
var Z_FINISH2 = 4;
|
|
var Z_BLOCK2 = 5;
|
|
var Z_OK2 = 0;
|
|
var Z_STREAM_END2 = 1;
|
|
var Z_STREAM_ERROR2 = -2;
|
|
var Z_BUF_ERROR2 = -5;
|
|
var Z_DEFAULT_COMPRESSION = -1;
|
|
var Z_FILTERED = 1;
|
|
var Z_HUFFMAN_ONLY = 2;
|
|
var Z_RLE = 3;
|
|
var Z_FIXED2 = 4;
|
|
var Z_DEFAULT_STRATEGY = 0;
|
|
var Z_UNKNOWN2 = 2;
|
|
var Z_DEFLATED2 = 8;
|
|
var MAX_MEM_LEVEL = 9;
|
|
var MAX_WBITS2 = 15;
|
|
var DEF_MEM_LEVEL = 8;
|
|
var LENGTH_CODES2 = 29;
|
|
var LITERALS2 = 256;
|
|
var L_CODES2 = LITERALS2 + 1 + LENGTH_CODES2;
|
|
var D_CODES2 = 30;
|
|
var BL_CODES2 = 19;
|
|
var HEAP_SIZE2 = 2 * L_CODES2 + 1;
|
|
var MAX_BITS2 = 15;
|
|
var MIN_MATCH2 = 3;
|
|
var MAX_MATCH2 = 258;
|
|
var MIN_LOOKAHEAD = MAX_MATCH2 + MIN_MATCH2 + 1;
|
|
var PRESET_DICT = 32;
|
|
var INIT_STATE = 42;
|
|
var EXTRA_STATE = 69;
|
|
var NAME_STATE = 73;
|
|
var COMMENT_STATE = 91;
|
|
var HCRC_STATE = 103;
|
|
var BUSY_STATE = 113;
|
|
var FINISH_STATE = 666;
|
|
var BS_NEED_MORE = 1;
|
|
var BS_BLOCK_DONE = 2;
|
|
var BS_FINISH_STARTED = 3;
|
|
var BS_FINISH_DONE = 4;
|
|
var OS_CODE = 3;
|
|
function err(strm, errorCode) {
|
|
strm.msg = messages_default[errorCode];
|
|
return errorCode;
|
|
}
|
|
function rank(f2) {
|
|
return (f2 << 1) - (f2 > 4 ? 9 : 0);
|
|
}
|
|
function zero2(buf) {
|
|
var len = buf.length;
|
|
while (--len >= 0) {
|
|
buf[len] = 0;
|
|
}
|
|
}
|
|
function flush_pending(strm) {
|
|
var s = strm.state;
|
|
var len = s.pending;
|
|
if (len > strm.avail_out) {
|
|
len = strm.avail_out;
|
|
}
|
|
if (len === 0) {
|
|
return;
|
|
}
|
|
arraySet(strm.output, s.pending_buf, s.pending_out, len, strm.next_out);
|
|
strm.next_out += len;
|
|
s.pending_out += len;
|
|
strm.total_out += len;
|
|
strm.avail_out -= len;
|
|
s.pending -= len;
|
|
if (s.pending === 0) {
|
|
s.pending_out = 0;
|
|
}
|
|
}
|
|
function flush_block_only(s, last) {
|
|
_tr_flush_block(s, s.block_start >= 0 ? s.block_start : -1, s.strstart - s.block_start, last);
|
|
s.block_start = s.strstart;
|
|
flush_pending(s.strm);
|
|
}
|
|
function put_byte(s, b2) {
|
|
s.pending_buf[s.pending++] = b2;
|
|
}
|
|
function putShortMSB(s, b2) {
|
|
s.pending_buf[s.pending++] = b2 >>> 8 & 255;
|
|
s.pending_buf[s.pending++] = b2 & 255;
|
|
}
|
|
function read_buf(strm, buf, start, size) {
|
|
var len = strm.avail_in;
|
|
if (len > size) {
|
|
len = size;
|
|
}
|
|
if (len === 0) {
|
|
return 0;
|
|
}
|
|
strm.avail_in -= len;
|
|
arraySet(buf, strm.input, strm.next_in, len, start);
|
|
if (strm.state.wrap === 1) {
|
|
strm.adler = adler32(strm.adler, buf, len, start);
|
|
} else if (strm.state.wrap === 2) {
|
|
strm.adler = makeTable(strm.adler, buf, len, start);
|
|
}
|
|
strm.next_in += len;
|
|
strm.total_in += len;
|
|
return len;
|
|
}
|
|
function longest_match(s, cur_match) {
|
|
var chain_length = s.max_chain_length;
|
|
var scan = s.strstart;
|
|
var match;
|
|
var len;
|
|
var best_len = s.prev_length;
|
|
var nice_match = s.nice_match;
|
|
var limit = s.strstart > s.w_size - MIN_LOOKAHEAD ? s.strstart - (s.w_size - MIN_LOOKAHEAD) : 0;
|
|
var _win = s.window;
|
|
var wmask = s.w_mask;
|
|
var prev = s.prev;
|
|
var strend = s.strstart + MAX_MATCH2;
|
|
var scan_end1 = _win[scan + best_len - 1];
|
|
var scan_end = _win[scan + best_len];
|
|
if (s.prev_length >= s.good_match) {
|
|
chain_length >>= 2;
|
|
}
|
|
if (nice_match > s.lookahead) {
|
|
nice_match = s.lookahead;
|
|
}
|
|
do {
|
|
match = cur_match;
|
|
if (_win[match + best_len] !== scan_end || _win[match + best_len - 1] !== scan_end1 || _win[match] !== _win[scan] || _win[++match] !== _win[scan + 1]) {
|
|
continue;
|
|
}
|
|
scan += 2;
|
|
match++;
|
|
do {
|
|
} while (_win[++scan] === _win[++match] && _win[++scan] === _win[++match] && _win[++scan] === _win[++match] && _win[++scan] === _win[++match] && _win[++scan] === _win[++match] && _win[++scan] === _win[++match] && _win[++scan] === _win[++match] && _win[++scan] === _win[++match] && scan < strend);
|
|
len = MAX_MATCH2 - (strend - scan);
|
|
scan = strend - MAX_MATCH2;
|
|
if (len > best_len) {
|
|
s.match_start = cur_match;
|
|
best_len = len;
|
|
if (len >= nice_match) {
|
|
break;
|
|
}
|
|
scan_end1 = _win[scan + best_len - 1];
|
|
scan_end = _win[scan + best_len];
|
|
}
|
|
} while ((cur_match = prev[cur_match & wmask]) > limit && --chain_length !== 0);
|
|
if (best_len <= s.lookahead) {
|
|
return best_len;
|
|
}
|
|
return s.lookahead;
|
|
}
|
|
function fill_window(s) {
|
|
var _w_size = s.w_size;
|
|
var p, n, m, more, str;
|
|
do {
|
|
more = s.window_size - s.lookahead - s.strstart;
|
|
if (s.strstart >= _w_size + (_w_size - MIN_LOOKAHEAD)) {
|
|
arraySet(s.window, s.window, _w_size, _w_size, 0);
|
|
s.match_start -= _w_size;
|
|
s.strstart -= _w_size;
|
|
s.block_start -= _w_size;
|
|
n = s.hash_size;
|
|
p = n;
|
|
do {
|
|
m = s.head[--p];
|
|
s.head[p] = m >= _w_size ? m - _w_size : 0;
|
|
} while (--n);
|
|
n = _w_size;
|
|
p = n;
|
|
do {
|
|
m = s.prev[--p];
|
|
s.prev[p] = m >= _w_size ? m - _w_size : 0;
|
|
} while (--n);
|
|
more += _w_size;
|
|
}
|
|
if (s.strm.avail_in === 0) {
|
|
break;
|
|
}
|
|
n = read_buf(s.strm, s.window, s.strstart + s.lookahead, more);
|
|
s.lookahead += n;
|
|
if (s.lookahead + s.insert >= MIN_MATCH2) {
|
|
str = s.strstart - s.insert;
|
|
s.ins_h = s.window[str];
|
|
s.ins_h = (s.ins_h << s.hash_shift ^ s.window[str + 1]) & s.hash_mask;
|
|
while (s.insert) {
|
|
s.ins_h = (s.ins_h << s.hash_shift ^ s.window[str + MIN_MATCH2 - 1]) & s.hash_mask;
|
|
s.prev[str & s.w_mask] = s.head[s.ins_h];
|
|
s.head[s.ins_h] = str;
|
|
str++;
|
|
s.insert--;
|
|
if (s.lookahead + s.insert < MIN_MATCH2) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
} while (s.lookahead < MIN_LOOKAHEAD && s.strm.avail_in !== 0);
|
|
}
|
|
function deflate_stored(s, flush) {
|
|
var max_block_size = 65535;
|
|
if (max_block_size > s.pending_buf_size - 5) {
|
|
max_block_size = s.pending_buf_size - 5;
|
|
}
|
|
for (; ; ) {
|
|
if (s.lookahead <= 1) {
|
|
fill_window(s);
|
|
if (s.lookahead === 0 && flush === Z_NO_FLUSH) {
|
|
return BS_NEED_MORE;
|
|
}
|
|
if (s.lookahead === 0) {
|
|
break;
|
|
}
|
|
}
|
|
s.strstart += s.lookahead;
|
|
s.lookahead = 0;
|
|
var max_start = s.block_start + max_block_size;
|
|
if (s.strstart === 0 || s.strstart >= max_start) {
|
|
s.lookahead = s.strstart - max_start;
|
|
s.strstart = max_start;
|
|
flush_block_only(s, false);
|
|
if (s.strm.avail_out === 0) {
|
|
return BS_NEED_MORE;
|
|
}
|
|
}
|
|
if (s.strstart - s.block_start >= s.w_size - MIN_LOOKAHEAD) {
|
|
flush_block_only(s, false);
|
|
if (s.strm.avail_out === 0) {
|
|
return BS_NEED_MORE;
|
|
}
|
|
}
|
|
}
|
|
s.insert = 0;
|
|
if (flush === Z_FINISH2) {
|
|
flush_block_only(s, true);
|
|
if (s.strm.avail_out === 0) {
|
|
return BS_FINISH_STARTED;
|
|
}
|
|
return BS_FINISH_DONE;
|
|
}
|
|
if (s.strstart > s.block_start) {
|
|
flush_block_only(s, false);
|
|
if (s.strm.avail_out === 0) {
|
|
return BS_NEED_MORE;
|
|
}
|
|
}
|
|
return BS_NEED_MORE;
|
|
}
|
|
function deflate_fast(s, flush) {
|
|
var hash_head;
|
|
var bflush;
|
|
for (; ; ) {
|
|
if (s.lookahead < MIN_LOOKAHEAD) {
|
|
fill_window(s);
|
|
if (s.lookahead < MIN_LOOKAHEAD && flush === Z_NO_FLUSH) {
|
|
return BS_NEED_MORE;
|
|
}
|
|
if (s.lookahead === 0) {
|
|
break;
|
|
}
|
|
}
|
|
hash_head = 0;
|
|
if (s.lookahead >= MIN_MATCH2) {
|
|
s.ins_h = (s.ins_h << s.hash_shift ^ s.window[s.strstart + MIN_MATCH2 - 1]) & s.hash_mask;
|
|
hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h];
|
|
s.head[s.ins_h] = s.strstart;
|
|
}
|
|
if (hash_head !== 0 && s.strstart - hash_head <= s.w_size - MIN_LOOKAHEAD) {
|
|
s.match_length = longest_match(s, hash_head);
|
|
}
|
|
if (s.match_length >= MIN_MATCH2) {
|
|
bflush = _tr_tally(s, s.strstart - s.match_start, s.match_length - MIN_MATCH2);
|
|
s.lookahead -= s.match_length;
|
|
if (s.match_length <= s.max_lazy_match && s.lookahead >= MIN_MATCH2) {
|
|
s.match_length--;
|
|
do {
|
|
s.strstart++;
|
|
s.ins_h = (s.ins_h << s.hash_shift ^ s.window[s.strstart + MIN_MATCH2 - 1]) & s.hash_mask;
|
|
hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h];
|
|
s.head[s.ins_h] = s.strstart;
|
|
} while (--s.match_length !== 0);
|
|
s.strstart++;
|
|
} else {
|
|
s.strstart += s.match_length;
|
|
s.match_length = 0;
|
|
s.ins_h = s.window[s.strstart];
|
|
s.ins_h = (s.ins_h << s.hash_shift ^ s.window[s.strstart + 1]) & s.hash_mask;
|
|
}
|
|
} else {
|
|
bflush = _tr_tally(s, 0, s.window[s.strstart]);
|
|
s.lookahead--;
|
|
s.strstart++;
|
|
}
|
|
if (bflush) {
|
|
flush_block_only(s, false);
|
|
if (s.strm.avail_out === 0) {
|
|
return BS_NEED_MORE;
|
|
}
|
|
}
|
|
}
|
|
s.insert = s.strstart < MIN_MATCH2 - 1 ? s.strstart : MIN_MATCH2 - 1;
|
|
if (flush === Z_FINISH2) {
|
|
flush_block_only(s, true);
|
|
if (s.strm.avail_out === 0) {
|
|
return BS_FINISH_STARTED;
|
|
}
|
|
return BS_FINISH_DONE;
|
|
}
|
|
if (s.last_lit) {
|
|
flush_block_only(s, false);
|
|
if (s.strm.avail_out === 0) {
|
|
return BS_NEED_MORE;
|
|
}
|
|
}
|
|
return BS_BLOCK_DONE;
|
|
}
|
|
function deflate_slow(s, flush) {
|
|
var hash_head;
|
|
var bflush;
|
|
var max_insert;
|
|
for (; ; ) {
|
|
if (s.lookahead < MIN_LOOKAHEAD) {
|
|
fill_window(s);
|
|
if (s.lookahead < MIN_LOOKAHEAD && flush === Z_NO_FLUSH) {
|
|
return BS_NEED_MORE;
|
|
}
|
|
if (s.lookahead === 0) {
|
|
break;
|
|
}
|
|
}
|
|
hash_head = 0;
|
|
if (s.lookahead >= MIN_MATCH2) {
|
|
s.ins_h = (s.ins_h << s.hash_shift ^ s.window[s.strstart + MIN_MATCH2 - 1]) & s.hash_mask;
|
|
hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h];
|
|
s.head[s.ins_h] = s.strstart;
|
|
}
|
|
s.prev_length = s.match_length;
|
|
s.prev_match = s.match_start;
|
|
s.match_length = MIN_MATCH2 - 1;
|
|
if (hash_head !== 0 && s.prev_length < s.max_lazy_match && s.strstart - hash_head <= s.w_size - MIN_LOOKAHEAD) {
|
|
s.match_length = longest_match(s, hash_head);
|
|
if (s.match_length <= 5 && (s.strategy === Z_FILTERED || s.match_length === MIN_MATCH2 && s.strstart - s.match_start > 4096)) {
|
|
s.match_length = MIN_MATCH2 - 1;
|
|
}
|
|
}
|
|
if (s.prev_length >= MIN_MATCH2 && s.match_length <= s.prev_length) {
|
|
max_insert = s.strstart + s.lookahead - MIN_MATCH2;
|
|
bflush = _tr_tally(s, s.strstart - 1 - s.prev_match, s.prev_length - MIN_MATCH2);
|
|
s.lookahead -= s.prev_length - 1;
|
|
s.prev_length -= 2;
|
|
do {
|
|
if (++s.strstart <= max_insert) {
|
|
s.ins_h = (s.ins_h << s.hash_shift ^ s.window[s.strstart + MIN_MATCH2 - 1]) & s.hash_mask;
|
|
hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h];
|
|
s.head[s.ins_h] = s.strstart;
|
|
}
|
|
} while (--s.prev_length !== 0);
|
|
s.match_available = 0;
|
|
s.match_length = MIN_MATCH2 - 1;
|
|
s.strstart++;
|
|
if (bflush) {
|
|
flush_block_only(s, false);
|
|
if (s.strm.avail_out === 0) {
|
|
return BS_NEED_MORE;
|
|
}
|
|
}
|
|
} else if (s.match_available) {
|
|
bflush = _tr_tally(s, 0, s.window[s.strstart - 1]);
|
|
if (bflush) {
|
|
flush_block_only(s, false);
|
|
}
|
|
s.strstart++;
|
|
s.lookahead--;
|
|
if (s.strm.avail_out === 0) {
|
|
return BS_NEED_MORE;
|
|
}
|
|
} else {
|
|
s.match_available = 1;
|
|
s.strstart++;
|
|
s.lookahead--;
|
|
}
|
|
}
|
|
if (s.match_available) {
|
|
bflush = _tr_tally(s, 0, s.window[s.strstart - 1]);
|
|
s.match_available = 0;
|
|
}
|
|
s.insert = s.strstart < MIN_MATCH2 - 1 ? s.strstart : MIN_MATCH2 - 1;
|
|
if (flush === Z_FINISH2) {
|
|
flush_block_only(s, true);
|
|
if (s.strm.avail_out === 0) {
|
|
return BS_FINISH_STARTED;
|
|
}
|
|
return BS_FINISH_DONE;
|
|
}
|
|
if (s.last_lit) {
|
|
flush_block_only(s, false);
|
|
if (s.strm.avail_out === 0) {
|
|
return BS_NEED_MORE;
|
|
}
|
|
}
|
|
return BS_BLOCK_DONE;
|
|
}
|
|
function deflate_rle(s, flush) {
|
|
var bflush;
|
|
var prev;
|
|
var scan, strend;
|
|
var _win = s.window;
|
|
for (; ; ) {
|
|
if (s.lookahead <= MAX_MATCH2) {
|
|
fill_window(s);
|
|
if (s.lookahead <= MAX_MATCH2 && flush === Z_NO_FLUSH) {
|
|
return BS_NEED_MORE;
|
|
}
|
|
if (s.lookahead === 0) {
|
|
break;
|
|
}
|
|
}
|
|
s.match_length = 0;
|
|
if (s.lookahead >= MIN_MATCH2 && s.strstart > 0) {
|
|
scan = s.strstart - 1;
|
|
prev = _win[scan];
|
|
if (prev === _win[++scan] && prev === _win[++scan] && prev === _win[++scan]) {
|
|
strend = s.strstart + MAX_MATCH2;
|
|
do {
|
|
} while (prev === _win[++scan] && prev === _win[++scan] && prev === _win[++scan] && prev === _win[++scan] && prev === _win[++scan] && prev === _win[++scan] && prev === _win[++scan] && prev === _win[++scan] && scan < strend);
|
|
s.match_length = MAX_MATCH2 - (strend - scan);
|
|
if (s.match_length > s.lookahead) {
|
|
s.match_length = s.lookahead;
|
|
}
|
|
}
|
|
}
|
|
if (s.match_length >= MIN_MATCH2) {
|
|
bflush = _tr_tally(s, 1, s.match_length - MIN_MATCH2);
|
|
s.lookahead -= s.match_length;
|
|
s.strstart += s.match_length;
|
|
s.match_length = 0;
|
|
} else {
|
|
bflush = _tr_tally(s, 0, s.window[s.strstart]);
|
|
s.lookahead--;
|
|
s.strstart++;
|
|
}
|
|
if (bflush) {
|
|
flush_block_only(s, false);
|
|
if (s.strm.avail_out === 0) {
|
|
return BS_NEED_MORE;
|
|
}
|
|
}
|
|
}
|
|
s.insert = 0;
|
|
if (flush === Z_FINISH2) {
|
|
flush_block_only(s, true);
|
|
if (s.strm.avail_out === 0) {
|
|
return BS_FINISH_STARTED;
|
|
}
|
|
return BS_FINISH_DONE;
|
|
}
|
|
if (s.last_lit) {
|
|
flush_block_only(s, false);
|
|
if (s.strm.avail_out === 0) {
|
|
return BS_NEED_MORE;
|
|
}
|
|
}
|
|
return BS_BLOCK_DONE;
|
|
}
|
|
function deflate_huff(s, flush) {
|
|
var bflush;
|
|
for (; ; ) {
|
|
if (s.lookahead === 0) {
|
|
fill_window(s);
|
|
if (s.lookahead === 0) {
|
|
if (flush === Z_NO_FLUSH) {
|
|
return BS_NEED_MORE;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
s.match_length = 0;
|
|
bflush = _tr_tally(s, 0, s.window[s.strstart]);
|
|
s.lookahead--;
|
|
s.strstart++;
|
|
if (bflush) {
|
|
flush_block_only(s, false);
|
|
if (s.strm.avail_out === 0) {
|
|
return BS_NEED_MORE;
|
|
}
|
|
}
|
|
}
|
|
s.insert = 0;
|
|
if (flush === Z_FINISH2) {
|
|
flush_block_only(s, true);
|
|
if (s.strm.avail_out === 0) {
|
|
return BS_FINISH_STARTED;
|
|
}
|
|
return BS_FINISH_DONE;
|
|
}
|
|
if (s.last_lit) {
|
|
flush_block_only(s, false);
|
|
if (s.strm.avail_out === 0) {
|
|
return BS_NEED_MORE;
|
|
}
|
|
}
|
|
return BS_BLOCK_DONE;
|
|
}
|
|
function Config(good_length, max_lazy, nice_length, max_chain, func) {
|
|
this.good_length = good_length;
|
|
this.max_lazy = max_lazy;
|
|
this.nice_length = nice_length;
|
|
this.max_chain = max_chain;
|
|
this.func = func;
|
|
}
|
|
var configuration_table;
|
|
configuration_table = [
|
|
/* good lazy nice chain */
|
|
new Config(0, 0, 0, 0, deflate_stored),
|
|
/* 0 store only */
|
|
new Config(4, 4, 8, 4, deflate_fast),
|
|
/* 1 max speed, no lazy matches */
|
|
new Config(4, 5, 16, 8, deflate_fast),
|
|
/* 2 */
|
|
new Config(4, 6, 32, 32, deflate_fast),
|
|
/* 3 */
|
|
new Config(4, 4, 16, 16, deflate_slow),
|
|
/* 4 lazy matches */
|
|
new Config(8, 16, 32, 32, deflate_slow),
|
|
/* 5 */
|
|
new Config(8, 16, 128, 128, deflate_slow),
|
|
/* 6 */
|
|
new Config(8, 32, 128, 256, deflate_slow),
|
|
/* 7 */
|
|
new Config(32, 128, 258, 1024, deflate_slow),
|
|
/* 8 */
|
|
new Config(32, 258, 258, 4096, deflate_slow)
|
|
/* 9 max compression */
|
|
];
|
|
function lm_init(s) {
|
|
s.window_size = 2 * s.w_size;
|
|
zero2(s.head);
|
|
s.max_lazy_match = configuration_table[s.level].max_lazy;
|
|
s.good_match = configuration_table[s.level].good_length;
|
|
s.nice_match = configuration_table[s.level].nice_length;
|
|
s.max_chain_length = configuration_table[s.level].max_chain;
|
|
s.strstart = 0;
|
|
s.block_start = 0;
|
|
s.lookahead = 0;
|
|
s.insert = 0;
|
|
s.match_length = s.prev_length = MIN_MATCH2 - 1;
|
|
s.match_available = 0;
|
|
s.ins_h = 0;
|
|
}
|
|
function DeflateState() {
|
|
this.strm = null;
|
|
this.status = 0;
|
|
this.pending_buf = null;
|
|
this.pending_buf_size = 0;
|
|
this.pending_out = 0;
|
|
this.pending = 0;
|
|
this.wrap = 0;
|
|
this.gzhead = null;
|
|
this.gzindex = 0;
|
|
this.method = Z_DEFLATED2;
|
|
this.last_flush = -1;
|
|
this.w_size = 0;
|
|
this.w_bits = 0;
|
|
this.w_mask = 0;
|
|
this.window = null;
|
|
this.window_size = 0;
|
|
this.prev = null;
|
|
this.head = null;
|
|
this.ins_h = 0;
|
|
this.hash_size = 0;
|
|
this.hash_bits = 0;
|
|
this.hash_mask = 0;
|
|
this.hash_shift = 0;
|
|
this.block_start = 0;
|
|
this.match_length = 0;
|
|
this.prev_match = 0;
|
|
this.match_available = 0;
|
|
this.strstart = 0;
|
|
this.match_start = 0;
|
|
this.lookahead = 0;
|
|
this.prev_length = 0;
|
|
this.max_chain_length = 0;
|
|
this.max_lazy_match = 0;
|
|
this.level = 0;
|
|
this.strategy = 0;
|
|
this.good_match = 0;
|
|
this.nice_match = 0;
|
|
this.dyn_ltree = new Buf16(HEAP_SIZE2 * 2);
|
|
this.dyn_dtree = new Buf16((2 * D_CODES2 + 1) * 2);
|
|
this.bl_tree = new Buf16((2 * BL_CODES2 + 1) * 2);
|
|
zero2(this.dyn_ltree);
|
|
zero2(this.dyn_dtree);
|
|
zero2(this.bl_tree);
|
|
this.l_desc = null;
|
|
this.d_desc = null;
|
|
this.bl_desc = null;
|
|
this.bl_count = new Buf16(MAX_BITS2 + 1);
|
|
this.heap = new Buf16(2 * L_CODES2 + 1);
|
|
zero2(this.heap);
|
|
this.heap_len = 0;
|
|
this.heap_max = 0;
|
|
this.depth = new Buf16(2 * L_CODES2 + 1);
|
|
zero2(this.depth);
|
|
this.l_buf = 0;
|
|
this.lit_bufsize = 0;
|
|
this.last_lit = 0;
|
|
this.d_buf = 0;
|
|
this.opt_len = 0;
|
|
this.static_len = 0;
|
|
this.matches = 0;
|
|
this.insert = 0;
|
|
this.bi_buf = 0;
|
|
this.bi_valid = 0;
|
|
}
|
|
function deflateResetKeep(strm) {
|
|
var s;
|
|
if (!strm || !strm.state) {
|
|
return err(strm, Z_STREAM_ERROR2);
|
|
}
|
|
strm.total_in = strm.total_out = 0;
|
|
strm.data_type = Z_UNKNOWN2;
|
|
s = strm.state;
|
|
s.pending = 0;
|
|
s.pending_out = 0;
|
|
if (s.wrap < 0) {
|
|
s.wrap = -s.wrap;
|
|
}
|
|
s.status = s.wrap ? INIT_STATE : BUSY_STATE;
|
|
strm.adler = s.wrap === 2 ? 0 : 1;
|
|
s.last_flush = Z_NO_FLUSH;
|
|
_tr_init(s);
|
|
return Z_OK2;
|
|
}
|
|
function deflateReset(strm) {
|
|
var ret = deflateResetKeep(strm);
|
|
if (ret === Z_OK2) {
|
|
lm_init(strm.state);
|
|
}
|
|
return ret;
|
|
}
|
|
function deflateInit2(strm, level, method, windowBits, memLevel, strategy) {
|
|
if (!strm) {
|
|
return Z_STREAM_ERROR2;
|
|
}
|
|
var wrap = 1;
|
|
if (level === Z_DEFAULT_COMPRESSION) {
|
|
level = 6;
|
|
}
|
|
if (windowBits < 0) {
|
|
wrap = 0;
|
|
windowBits = -windowBits;
|
|
} else if (windowBits > 15) {
|
|
wrap = 2;
|
|
windowBits -= 16;
|
|
}
|
|
if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method !== Z_DEFLATED2 || windowBits < 8 || windowBits > 15 || level < 0 || level > 9 || strategy < 0 || strategy > Z_FIXED2) {
|
|
return err(strm, Z_STREAM_ERROR2);
|
|
}
|
|
if (windowBits === 8) {
|
|
windowBits = 9;
|
|
}
|
|
var s = new DeflateState();
|
|
strm.state = s;
|
|
s.strm = strm;
|
|
s.wrap = wrap;
|
|
s.gzhead = null;
|
|
s.w_bits = windowBits;
|
|
s.w_size = 1 << s.w_bits;
|
|
s.w_mask = s.w_size - 1;
|
|
s.hash_bits = memLevel + 7;
|
|
s.hash_size = 1 << s.hash_bits;
|
|
s.hash_mask = s.hash_size - 1;
|
|
s.hash_shift = ~~((s.hash_bits + MIN_MATCH2 - 1) / MIN_MATCH2);
|
|
s.window = new Buf8(s.w_size * 2);
|
|
s.head = new Buf16(s.hash_size);
|
|
s.prev = new Buf16(s.w_size);
|
|
s.lit_bufsize = 1 << memLevel + 6;
|
|
s.pending_buf_size = s.lit_bufsize * 4;
|
|
s.pending_buf = new Buf8(s.pending_buf_size);
|
|
s.d_buf = 1 * s.lit_bufsize;
|
|
s.l_buf = (1 + 2) * s.lit_bufsize;
|
|
s.level = level;
|
|
s.strategy = strategy;
|
|
s.method = method;
|
|
return deflateReset(strm);
|
|
}
|
|
function deflateInit(strm, level) {
|
|
return deflateInit2(strm, level, Z_DEFLATED2, MAX_WBITS2, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY);
|
|
}
|
|
function deflate(strm, flush) {
|
|
var old_flush, s;
|
|
var beg, val;
|
|
if (!strm || !strm.state || flush > Z_BLOCK2 || flush < 0) {
|
|
return strm ? err(strm, Z_STREAM_ERROR2) : Z_STREAM_ERROR2;
|
|
}
|
|
s = strm.state;
|
|
if (!strm.output || !strm.input && strm.avail_in !== 0 || s.status === FINISH_STATE && flush !== Z_FINISH2) {
|
|
return err(strm, strm.avail_out === 0 ? Z_BUF_ERROR2 : Z_STREAM_ERROR2);
|
|
}
|
|
s.strm = strm;
|
|
old_flush = s.last_flush;
|
|
s.last_flush = flush;
|
|
if (s.status === INIT_STATE) {
|
|
if (s.wrap === 2) {
|
|
strm.adler = 0;
|
|
put_byte(s, 31);
|
|
put_byte(s, 139);
|
|
put_byte(s, 8);
|
|
if (!s.gzhead) {
|
|
put_byte(s, 0);
|
|
put_byte(s, 0);
|
|
put_byte(s, 0);
|
|
put_byte(s, 0);
|
|
put_byte(s, 0);
|
|
put_byte(s, s.level === 9 ? 2 : s.strategy >= Z_HUFFMAN_ONLY || s.level < 2 ? 4 : 0);
|
|
put_byte(s, OS_CODE);
|
|
s.status = BUSY_STATE;
|
|
} else {
|
|
put_byte(
|
|
s,
|
|
(s.gzhead.text ? 1 : 0) + (s.gzhead.hcrc ? 2 : 0) + (!s.gzhead.extra ? 0 : 4) + (!s.gzhead.name ? 0 : 8) + (!s.gzhead.comment ? 0 : 16)
|
|
);
|
|
put_byte(s, s.gzhead.time & 255);
|
|
put_byte(s, s.gzhead.time >> 8 & 255);
|
|
put_byte(s, s.gzhead.time >> 16 & 255);
|
|
put_byte(s, s.gzhead.time >> 24 & 255);
|
|
put_byte(s, s.level === 9 ? 2 : s.strategy >= Z_HUFFMAN_ONLY || s.level < 2 ? 4 : 0);
|
|
put_byte(s, s.gzhead.os & 255);
|
|
if (s.gzhead.extra && s.gzhead.extra.length) {
|
|
put_byte(s, s.gzhead.extra.length & 255);
|
|
put_byte(s, s.gzhead.extra.length >> 8 & 255);
|
|
}
|
|
if (s.gzhead.hcrc) {
|
|
strm.adler = makeTable(strm.adler, s.pending_buf, s.pending, 0);
|
|
}
|
|
s.gzindex = 0;
|
|
s.status = EXTRA_STATE;
|
|
}
|
|
} else {
|
|
var header = Z_DEFLATED2 + (s.w_bits - 8 << 4) << 8;
|
|
var level_flags = -1;
|
|
if (s.strategy >= Z_HUFFMAN_ONLY || s.level < 2) {
|
|
level_flags = 0;
|
|
} else if (s.level < 6) {
|
|
level_flags = 1;
|
|
} else if (s.level === 6) {
|
|
level_flags = 2;
|
|
} else {
|
|
level_flags = 3;
|
|
}
|
|
header |= level_flags << 6;
|
|
if (s.strstart !== 0) {
|
|
header |= PRESET_DICT;
|
|
}
|
|
header += 31 - header % 31;
|
|
s.status = BUSY_STATE;
|
|
putShortMSB(s, header);
|
|
if (s.strstart !== 0) {
|
|
putShortMSB(s, strm.adler >>> 16);
|
|
putShortMSB(s, strm.adler & 65535);
|
|
}
|
|
strm.adler = 1;
|
|
}
|
|
}
|
|
if (s.status === EXTRA_STATE) {
|
|
if (s.gzhead.extra) {
|
|
beg = s.pending;
|
|
while (s.gzindex < (s.gzhead.extra.length & 65535)) {
|
|
if (s.pending === s.pending_buf_size) {
|
|
if (s.gzhead.hcrc && s.pending > beg) {
|
|
strm.adler = makeTable(strm.adler, s.pending_buf, s.pending - beg, beg);
|
|
}
|
|
flush_pending(strm);
|
|
beg = s.pending;
|
|
if (s.pending === s.pending_buf_size) {
|
|
break;
|
|
}
|
|
}
|
|
put_byte(s, s.gzhead.extra[s.gzindex] & 255);
|
|
s.gzindex++;
|
|
}
|
|
if (s.gzhead.hcrc && s.pending > beg) {
|
|
strm.adler = makeTable(strm.adler, s.pending_buf, s.pending - beg, beg);
|
|
}
|
|
if (s.gzindex === s.gzhead.extra.length) {
|
|
s.gzindex = 0;
|
|
s.status = NAME_STATE;
|
|
}
|
|
} else {
|
|
s.status = NAME_STATE;
|
|
}
|
|
}
|
|
if (s.status === NAME_STATE) {
|
|
if (s.gzhead.name) {
|
|
beg = s.pending;
|
|
do {
|
|
if (s.pending === s.pending_buf_size) {
|
|
if (s.gzhead.hcrc && s.pending > beg) {
|
|
strm.adler = makeTable(strm.adler, s.pending_buf, s.pending - beg, beg);
|
|
}
|
|
flush_pending(strm);
|
|
beg = s.pending;
|
|
if (s.pending === s.pending_buf_size) {
|
|
val = 1;
|
|
break;
|
|
}
|
|
}
|
|
if (s.gzindex < s.gzhead.name.length) {
|
|
val = s.gzhead.name.charCodeAt(s.gzindex++) & 255;
|
|
} else {
|
|
val = 0;
|
|
}
|
|
put_byte(s, val);
|
|
} while (val !== 0);
|
|
if (s.gzhead.hcrc && s.pending > beg) {
|
|
strm.adler = makeTable(strm.adler, s.pending_buf, s.pending - beg, beg);
|
|
}
|
|
if (val === 0) {
|
|
s.gzindex = 0;
|
|
s.status = COMMENT_STATE;
|
|
}
|
|
} else {
|
|
s.status = COMMENT_STATE;
|
|
}
|
|
}
|
|
if (s.status === COMMENT_STATE) {
|
|
if (s.gzhead.comment) {
|
|
beg = s.pending;
|
|
do {
|
|
if (s.pending === s.pending_buf_size) {
|
|
if (s.gzhead.hcrc && s.pending > beg) {
|
|
strm.adler = makeTable(strm.adler, s.pending_buf, s.pending - beg, beg);
|
|
}
|
|
flush_pending(strm);
|
|
beg = s.pending;
|
|
if (s.pending === s.pending_buf_size) {
|
|
val = 1;
|
|
break;
|
|
}
|
|
}
|
|
if (s.gzindex < s.gzhead.comment.length) {
|
|
val = s.gzhead.comment.charCodeAt(s.gzindex++) & 255;
|
|
} else {
|
|
val = 0;
|
|
}
|
|
put_byte(s, val);
|
|
} while (val !== 0);
|
|
if (s.gzhead.hcrc && s.pending > beg) {
|
|
strm.adler = makeTable(strm.adler, s.pending_buf, s.pending - beg, beg);
|
|
}
|
|
if (val === 0) {
|
|
s.status = HCRC_STATE;
|
|
}
|
|
} else {
|
|
s.status = HCRC_STATE;
|
|
}
|
|
}
|
|
if (s.status === HCRC_STATE) {
|
|
if (s.gzhead.hcrc) {
|
|
if (s.pending + 2 > s.pending_buf_size) {
|
|
flush_pending(strm);
|
|
}
|
|
if (s.pending + 2 <= s.pending_buf_size) {
|
|
put_byte(s, strm.adler & 255);
|
|
put_byte(s, strm.adler >> 8 & 255);
|
|
strm.adler = 0;
|
|
s.status = BUSY_STATE;
|
|
}
|
|
} else {
|
|
s.status = BUSY_STATE;
|
|
}
|
|
}
|
|
if (s.pending !== 0) {
|
|
flush_pending(strm);
|
|
if (strm.avail_out === 0) {
|
|
s.last_flush = -1;
|
|
return Z_OK2;
|
|
}
|
|
} else if (strm.avail_in === 0 && rank(flush) <= rank(old_flush) && flush !== Z_FINISH2) {
|
|
return err(strm, Z_BUF_ERROR2);
|
|
}
|
|
if (s.status === FINISH_STATE && strm.avail_in !== 0) {
|
|
return err(strm, Z_BUF_ERROR2);
|
|
}
|
|
if (strm.avail_in !== 0 || s.lookahead !== 0 || flush !== Z_NO_FLUSH && s.status !== FINISH_STATE) {
|
|
var bstate = s.strategy === Z_HUFFMAN_ONLY ? deflate_huff(s, flush) : s.strategy === Z_RLE ? deflate_rle(s, flush) : configuration_table[s.level].func(s, flush);
|
|
if (bstate === BS_FINISH_STARTED || bstate === BS_FINISH_DONE) {
|
|
s.status = FINISH_STATE;
|
|
}
|
|
if (bstate === BS_NEED_MORE || bstate === BS_FINISH_STARTED) {
|
|
if (strm.avail_out === 0) {
|
|
s.last_flush = -1;
|
|
}
|
|
return Z_OK2;
|
|
}
|
|
if (bstate === BS_BLOCK_DONE) {
|
|
if (flush === Z_PARTIAL_FLUSH) {
|
|
_tr_align(s);
|
|
} else if (flush !== Z_BLOCK2) {
|
|
_tr_stored_block(s, 0, 0, false);
|
|
if (flush === Z_FULL_FLUSH) {
|
|
zero2(s.head);
|
|
if (s.lookahead === 0) {
|
|
s.strstart = 0;
|
|
s.block_start = 0;
|
|
s.insert = 0;
|
|
}
|
|
}
|
|
}
|
|
flush_pending(strm);
|
|
if (strm.avail_out === 0) {
|
|
s.last_flush = -1;
|
|
return Z_OK2;
|
|
}
|
|
}
|
|
}
|
|
if (flush !== Z_FINISH2) {
|
|
return Z_OK2;
|
|
}
|
|
if (s.wrap <= 0) {
|
|
return Z_STREAM_END2;
|
|
}
|
|
if (s.wrap === 2) {
|
|
put_byte(s, strm.adler & 255);
|
|
put_byte(s, strm.adler >> 8 & 255);
|
|
put_byte(s, strm.adler >> 16 & 255);
|
|
put_byte(s, strm.adler >> 24 & 255);
|
|
put_byte(s, strm.total_in & 255);
|
|
put_byte(s, strm.total_in >> 8 & 255);
|
|
put_byte(s, strm.total_in >> 16 & 255);
|
|
put_byte(s, strm.total_in >> 24 & 255);
|
|
} else {
|
|
putShortMSB(s, strm.adler >>> 16);
|
|
putShortMSB(s, strm.adler & 65535);
|
|
}
|
|
flush_pending(strm);
|
|
if (s.wrap > 0) {
|
|
s.wrap = -s.wrap;
|
|
}
|
|
return s.pending !== 0 ? Z_OK2 : Z_STREAM_END2;
|
|
}
|
|
|
|
// core/deflator.js
|
|
var Deflator = class {
|
|
constructor() {
|
|
this.strm = new ZStream();
|
|
this.chunkSize = 1024 * 10 * 10;
|
|
this.outputBuffer = new Uint8Array(this.chunkSize);
|
|
deflateInit(this.strm, Z_DEFAULT_COMPRESSION);
|
|
}
|
|
deflate(inData) {
|
|
this.strm.input = inData;
|
|
this.strm.avail_in = this.strm.input.length;
|
|
this.strm.next_in = 0;
|
|
this.strm.output = this.outputBuffer;
|
|
this.strm.avail_out = this.chunkSize;
|
|
this.strm.next_out = 0;
|
|
let lastRet = deflate(this.strm, Z_FULL_FLUSH);
|
|
let outData = new Uint8Array(this.strm.output.buffer, 0, this.strm.next_out);
|
|
if (lastRet < 0) {
|
|
throw new Error("zlib deflate failed");
|
|
}
|
|
if (this.strm.avail_in > 0) {
|
|
let chunks = [outData];
|
|
let totalLen = outData.length;
|
|
do {
|
|
this.strm.output = new Uint8Array(this.chunkSize);
|
|
this.strm.next_out = 0;
|
|
this.strm.avail_out = this.chunkSize;
|
|
lastRet = deflate(this.strm, Z_FULL_FLUSH);
|
|
if (lastRet < 0) {
|
|
throw new Error("zlib deflate failed");
|
|
}
|
|
let chunk = new Uint8Array(this.strm.output.buffer, 0, this.strm.next_out);
|
|
totalLen += chunk.length;
|
|
chunks.push(chunk);
|
|
} while (this.strm.avail_in > 0);
|
|
let newData = new Uint8Array(totalLen);
|
|
let offset = 0;
|
|
for (let i = 0; i < chunks.length; i++) {
|
|
newData.set(chunks[i], offset);
|
|
offset += chunks[i].length;
|
|
}
|
|
outData = newData;
|
|
}
|
|
this.strm.input = null;
|
|
this.strm.avail_in = 0;
|
|
this.strm.next_in = 0;
|
|
return outData;
|
|
}
|
|
};
|
|
|
|
// core/input/keysym.js
|
|
var keysym_default = {
|
|
XK_VoidSymbol: 16777215,
|
|
/* Void symbol */
|
|
XK_BackSpace: 65288,
|
|
/* Back space, back char */
|
|
XK_Tab: 65289,
|
|
XK_Linefeed: 65290,
|
|
/* Linefeed, LF */
|
|
XK_Clear: 65291,
|
|
XK_Return: 65293,
|
|
/* Return, enter */
|
|
XK_Pause: 65299,
|
|
/* Pause, hold */
|
|
XK_Scroll_Lock: 65300,
|
|
XK_Sys_Req: 65301,
|
|
XK_Escape: 65307,
|
|
XK_Delete: 65535,
|
|
/* Delete, rubout */
|
|
/* International & multi-key character composition */
|
|
XK_Multi_key: 65312,
|
|
/* Multi-key character compose */
|
|
XK_Codeinput: 65335,
|
|
XK_SingleCandidate: 65340,
|
|
XK_MultipleCandidate: 65341,
|
|
XK_PreviousCandidate: 65342,
|
|
/* Japanese keyboard support */
|
|
XK_Kanji: 65313,
|
|
/* Kanji, Kanji convert */
|
|
XK_Muhenkan: 65314,
|
|
/* Cancel Conversion */
|
|
XK_Henkan_Mode: 65315,
|
|
/* Start/Stop Conversion */
|
|
XK_Henkan: 65315,
|
|
/* Alias for Henkan_Mode */
|
|
XK_Romaji: 65316,
|
|
/* to Romaji */
|
|
XK_Hiragana: 65317,
|
|
/* to Hiragana */
|
|
XK_Katakana: 65318,
|
|
/* to Katakana */
|
|
XK_Hiragana_Katakana: 65319,
|
|
/* Hiragana/Katakana toggle */
|
|
XK_Zenkaku: 65320,
|
|
/* to Zenkaku */
|
|
XK_Hankaku: 65321,
|
|
/* to Hankaku */
|
|
XK_Zenkaku_Hankaku: 65322,
|
|
/* Zenkaku/Hankaku toggle */
|
|
XK_Touroku: 65323,
|
|
/* Add to Dictionary */
|
|
XK_Massyo: 65324,
|
|
/* Delete from Dictionary */
|
|
XK_Kana_Lock: 65325,
|
|
/* Kana Lock */
|
|
XK_Kana_Shift: 65326,
|
|
/* Kana Shift */
|
|
XK_Eisu_Shift: 65327,
|
|
/* Alphanumeric Shift */
|
|
XK_Eisu_toggle: 65328,
|
|
/* Alphanumeric toggle */
|
|
XK_Kanji_Bangou: 65335,
|
|
/* Codeinput */
|
|
XK_Zen_Koho: 65341,
|
|
/* Multiple/All Candidate(s) */
|
|
XK_Mae_Koho: 65342,
|
|
/* Previous Candidate */
|
|
/* Cursor control & motion */
|
|
XK_Home: 65360,
|
|
XK_Left: 65361,
|
|
/* Move left, left arrow */
|
|
XK_Up: 65362,
|
|
/* Move up, up arrow */
|
|
XK_Right: 65363,
|
|
/* Move right, right arrow */
|
|
XK_Down: 65364,
|
|
/* Move down, down arrow */
|
|
XK_Prior: 65365,
|
|
/* Prior, previous */
|
|
XK_Page_Up: 65365,
|
|
XK_Next: 65366,
|
|
/* Next */
|
|
XK_Page_Down: 65366,
|
|
XK_End: 65367,
|
|
/* EOL */
|
|
XK_Begin: 65368,
|
|
/* BOL */
|
|
/* Misc functions */
|
|
XK_Select: 65376,
|
|
/* Select, mark */
|
|
XK_Print: 65377,
|
|
XK_Execute: 65378,
|
|
/* Execute, run, do */
|
|
XK_Insert: 65379,
|
|
/* Insert, insert here */
|
|
XK_Undo: 65381,
|
|
XK_Redo: 65382,
|
|
/* Redo, again */
|
|
XK_Menu: 65383,
|
|
XK_Find: 65384,
|
|
/* Find, search */
|
|
XK_Cancel: 65385,
|
|
/* Cancel, stop, abort, exit */
|
|
XK_Help: 65386,
|
|
/* Help */
|
|
XK_Break: 65387,
|
|
XK_Mode_switch: 65406,
|
|
/* Character set switch */
|
|
XK_script_switch: 65406,
|
|
/* Alias for mode_switch */
|
|
XK_Num_Lock: 65407,
|
|
/* Keypad functions, keypad numbers cleverly chosen to map to ASCII */
|
|
XK_KP_Space: 65408,
|
|
/* Space */
|
|
XK_KP_Tab: 65417,
|
|
XK_KP_Enter: 65421,
|
|
/* Enter */
|
|
XK_KP_F1: 65425,
|
|
/* PF1, KP_A, ... */
|
|
XK_KP_F2: 65426,
|
|
XK_KP_F3: 65427,
|
|
XK_KP_F4: 65428,
|
|
XK_KP_Home: 65429,
|
|
XK_KP_Left: 65430,
|
|
XK_KP_Up: 65431,
|
|
XK_KP_Right: 65432,
|
|
XK_KP_Down: 65433,
|
|
XK_KP_Prior: 65434,
|
|
XK_KP_Page_Up: 65434,
|
|
XK_KP_Next: 65435,
|
|
XK_KP_Page_Down: 65435,
|
|
XK_KP_End: 65436,
|
|
XK_KP_Begin: 65437,
|
|
XK_KP_Insert: 65438,
|
|
XK_KP_Delete: 65439,
|
|
XK_KP_Equal: 65469,
|
|
/* Equals */
|
|
XK_KP_Multiply: 65450,
|
|
XK_KP_Add: 65451,
|
|
XK_KP_Separator: 65452,
|
|
/* Separator, often comma */
|
|
XK_KP_Subtract: 65453,
|
|
XK_KP_Decimal: 65454,
|
|
XK_KP_Divide: 65455,
|
|
XK_KP_0: 65456,
|
|
XK_KP_1: 65457,
|
|
XK_KP_2: 65458,
|
|
XK_KP_3: 65459,
|
|
XK_KP_4: 65460,
|
|
XK_KP_5: 65461,
|
|
XK_KP_6: 65462,
|
|
XK_KP_7: 65463,
|
|
XK_KP_8: 65464,
|
|
XK_KP_9: 65465,
|
|
/*
|
|
* Auxiliary functions; note the duplicate definitions for left and right
|
|
* function keys; Sun keyboards and a few other manufacturers have such
|
|
* function key groups on the left and/or right sides of the keyboard.
|
|
* We've not found a keyboard with more than 35 function keys total.
|
|
*/
|
|
XK_F1: 65470,
|
|
XK_F2: 65471,
|
|
XK_F3: 65472,
|
|
XK_F4: 65473,
|
|
XK_F5: 65474,
|
|
XK_F6: 65475,
|
|
XK_F7: 65476,
|
|
XK_F8: 65477,
|
|
XK_F9: 65478,
|
|
XK_F10: 65479,
|
|
XK_F11: 65480,
|
|
XK_L1: 65480,
|
|
XK_F12: 65481,
|
|
XK_L2: 65481,
|
|
XK_F13: 65482,
|
|
XK_L3: 65482,
|
|
XK_F14: 65483,
|
|
XK_L4: 65483,
|
|
XK_F15: 65484,
|
|
XK_L5: 65484,
|
|
XK_F16: 65485,
|
|
XK_L6: 65485,
|
|
XK_F17: 65486,
|
|
XK_L7: 65486,
|
|
XK_F18: 65487,
|
|
XK_L8: 65487,
|
|
XK_F19: 65488,
|
|
XK_L9: 65488,
|
|
XK_F20: 65489,
|
|
XK_L10: 65489,
|
|
XK_F21: 65490,
|
|
XK_R1: 65490,
|
|
XK_F22: 65491,
|
|
XK_R2: 65491,
|
|
XK_F23: 65492,
|
|
XK_R3: 65492,
|
|
XK_F24: 65493,
|
|
XK_R4: 65493,
|
|
XK_F25: 65494,
|
|
XK_R5: 65494,
|
|
XK_F26: 65495,
|
|
XK_R6: 65495,
|
|
XK_F27: 65496,
|
|
XK_R7: 65496,
|
|
XK_F28: 65497,
|
|
XK_R8: 65497,
|
|
XK_F29: 65498,
|
|
XK_R9: 65498,
|
|
XK_F30: 65499,
|
|
XK_R10: 65499,
|
|
XK_F31: 65500,
|
|
XK_R11: 65500,
|
|
XK_F32: 65501,
|
|
XK_R12: 65501,
|
|
XK_F33: 65502,
|
|
XK_R13: 65502,
|
|
XK_F34: 65503,
|
|
XK_R14: 65503,
|
|
XK_F35: 65504,
|
|
XK_R15: 65504,
|
|
/* Modifiers */
|
|
XK_Shift_L: 65505,
|
|
/* Left shift */
|
|
XK_Shift_R: 65506,
|
|
/* Right shift */
|
|
XK_Control_L: 65507,
|
|
/* Left control */
|
|
XK_Control_R: 65508,
|
|
/* Right control */
|
|
XK_Caps_Lock: 65509,
|
|
/* Caps lock */
|
|
XK_Shift_Lock: 65510,
|
|
/* Shift lock */
|
|
XK_Meta_L: 65511,
|
|
/* Left meta */
|
|
XK_Meta_R: 65512,
|
|
/* Right meta */
|
|
XK_Alt_L: 65513,
|
|
/* Left alt */
|
|
XK_Alt_R: 65514,
|
|
/* Right alt */
|
|
XK_Super_L: 65515,
|
|
/* Left super */
|
|
XK_Super_R: 65516,
|
|
/* Right super */
|
|
XK_Hyper_L: 65517,
|
|
/* Left hyper */
|
|
XK_Hyper_R: 65518,
|
|
/* Right hyper */
|
|
/*
|
|
* Keyboard (XKB) Extension function and modifier keys
|
|
* (from Appendix C of "The X Keyboard Extension: Protocol Specification")
|
|
* Byte 3 = 0xfe
|
|
*/
|
|
XK_ISO_Level3_Shift: 65027,
|
|
/* AltGr */
|
|
XK_ISO_Next_Group: 65032,
|
|
XK_ISO_Prev_Group: 65034,
|
|
XK_ISO_First_Group: 65036,
|
|
XK_ISO_Last_Group: 65038,
|
|
/*
|
|
* Latin 1
|
|
* (ISO/IEC 8859-1: Unicode U+0020..U+00FF)
|
|
* Byte 3: 0
|
|
*/
|
|
XK_space: 32,
|
|
/* U+0020 SPACE */
|
|
XK_exclam: 33,
|
|
/* U+0021 EXCLAMATION MARK */
|
|
XK_quotedbl: 34,
|
|
/* U+0022 QUOTATION MARK */
|
|
XK_numbersign: 35,
|
|
/* U+0023 NUMBER SIGN */
|
|
XK_dollar: 36,
|
|
/* U+0024 DOLLAR SIGN */
|
|
XK_percent: 37,
|
|
/* U+0025 PERCENT SIGN */
|
|
XK_ampersand: 38,
|
|
/* U+0026 AMPERSAND */
|
|
XK_apostrophe: 39,
|
|
/* U+0027 APOSTROPHE */
|
|
XK_quoteright: 39,
|
|
/* deprecated */
|
|
XK_parenleft: 40,
|
|
/* U+0028 LEFT PARENTHESIS */
|
|
XK_parenright: 41,
|
|
/* U+0029 RIGHT PARENTHESIS */
|
|
XK_asterisk: 42,
|
|
/* U+002A ASTERISK */
|
|
XK_plus: 43,
|
|
/* U+002B PLUS SIGN */
|
|
XK_comma: 44,
|
|
/* U+002C COMMA */
|
|
XK_minus: 45,
|
|
/* U+002D HYPHEN-MINUS */
|
|
XK_period: 46,
|
|
/* U+002E FULL STOP */
|
|
XK_slash: 47,
|
|
/* U+002F SOLIDUS */
|
|
XK_0: 48,
|
|
/* U+0030 DIGIT ZERO */
|
|
XK_1: 49,
|
|
/* U+0031 DIGIT ONE */
|
|
XK_2: 50,
|
|
/* U+0032 DIGIT TWO */
|
|
XK_3: 51,
|
|
/* U+0033 DIGIT THREE */
|
|
XK_4: 52,
|
|
/* U+0034 DIGIT FOUR */
|
|
XK_5: 53,
|
|
/* U+0035 DIGIT FIVE */
|
|
XK_6: 54,
|
|
/* U+0036 DIGIT SIX */
|
|
XK_7: 55,
|
|
/* U+0037 DIGIT SEVEN */
|
|
XK_8: 56,
|
|
/* U+0038 DIGIT EIGHT */
|
|
XK_9: 57,
|
|
/* U+0039 DIGIT NINE */
|
|
XK_colon: 58,
|
|
/* U+003A COLON */
|
|
XK_semicolon: 59,
|
|
/* U+003B SEMICOLON */
|
|
XK_less: 60,
|
|
/* U+003C LESS-THAN SIGN */
|
|
XK_equal: 61,
|
|
/* U+003D EQUALS SIGN */
|
|
XK_greater: 62,
|
|
/* U+003E GREATER-THAN SIGN */
|
|
XK_question: 63,
|
|
/* U+003F QUESTION MARK */
|
|
XK_at: 64,
|
|
/* U+0040 COMMERCIAL AT */
|
|
XK_A: 65,
|
|
/* U+0041 LATIN CAPITAL LETTER A */
|
|
XK_B: 66,
|
|
/* U+0042 LATIN CAPITAL LETTER B */
|
|
XK_C: 67,
|
|
/* U+0043 LATIN CAPITAL LETTER C */
|
|
XK_D: 68,
|
|
/* U+0044 LATIN CAPITAL LETTER D */
|
|
XK_E: 69,
|
|
/* U+0045 LATIN CAPITAL LETTER E */
|
|
XK_F: 70,
|
|
/* U+0046 LATIN CAPITAL LETTER F */
|
|
XK_G: 71,
|
|
/* U+0047 LATIN CAPITAL LETTER G */
|
|
XK_H: 72,
|
|
/* U+0048 LATIN CAPITAL LETTER H */
|
|
XK_I: 73,
|
|
/* U+0049 LATIN CAPITAL LETTER I */
|
|
XK_J: 74,
|
|
/* U+004A LATIN CAPITAL LETTER J */
|
|
XK_K: 75,
|
|
/* U+004B LATIN CAPITAL LETTER K */
|
|
XK_L: 76,
|
|
/* U+004C LATIN CAPITAL LETTER L */
|
|
XK_M: 77,
|
|
/* U+004D LATIN CAPITAL LETTER M */
|
|
XK_N: 78,
|
|
/* U+004E LATIN CAPITAL LETTER N */
|
|
XK_O: 79,
|
|
/* U+004F LATIN CAPITAL LETTER O */
|
|
XK_P: 80,
|
|
/* U+0050 LATIN CAPITAL LETTER P */
|
|
XK_Q: 81,
|
|
/* U+0051 LATIN CAPITAL LETTER Q */
|
|
XK_R: 82,
|
|
/* U+0052 LATIN CAPITAL LETTER R */
|
|
XK_S: 83,
|
|
/* U+0053 LATIN CAPITAL LETTER S */
|
|
XK_T: 84,
|
|
/* U+0054 LATIN CAPITAL LETTER T */
|
|
XK_U: 85,
|
|
/* U+0055 LATIN CAPITAL LETTER U */
|
|
XK_V: 86,
|
|
/* U+0056 LATIN CAPITAL LETTER V */
|
|
XK_W: 87,
|
|
/* U+0057 LATIN CAPITAL LETTER W */
|
|
XK_X: 88,
|
|
/* U+0058 LATIN CAPITAL LETTER X */
|
|
XK_Y: 89,
|
|
/* U+0059 LATIN CAPITAL LETTER Y */
|
|
XK_Z: 90,
|
|
/* U+005A LATIN CAPITAL LETTER Z */
|
|
XK_bracketleft: 91,
|
|
/* U+005B LEFT SQUARE BRACKET */
|
|
XK_backslash: 92,
|
|
/* U+005C REVERSE SOLIDUS */
|
|
XK_bracketright: 93,
|
|
/* U+005D RIGHT SQUARE BRACKET */
|
|
XK_asciicircum: 94,
|
|
/* U+005E CIRCUMFLEX ACCENT */
|
|
XK_underscore: 95,
|
|
/* U+005F LOW LINE */
|
|
XK_grave: 96,
|
|
/* U+0060 GRAVE ACCENT */
|
|
XK_quoteleft: 96,
|
|
/* deprecated */
|
|
XK_a: 97,
|
|
/* U+0061 LATIN SMALL LETTER A */
|
|
XK_b: 98,
|
|
/* U+0062 LATIN SMALL LETTER B */
|
|
XK_c: 99,
|
|
/* U+0063 LATIN SMALL LETTER C */
|
|
XK_d: 100,
|
|
/* U+0064 LATIN SMALL LETTER D */
|
|
XK_e: 101,
|
|
/* U+0065 LATIN SMALL LETTER E */
|
|
XK_f: 102,
|
|
/* U+0066 LATIN SMALL LETTER F */
|
|
XK_g: 103,
|
|
/* U+0067 LATIN SMALL LETTER G */
|
|
XK_h: 104,
|
|
/* U+0068 LATIN SMALL LETTER H */
|
|
XK_i: 105,
|
|
/* U+0069 LATIN SMALL LETTER I */
|
|
XK_j: 106,
|
|
/* U+006A LATIN SMALL LETTER J */
|
|
XK_k: 107,
|
|
/* U+006B LATIN SMALL LETTER K */
|
|
XK_l: 108,
|
|
/* U+006C LATIN SMALL LETTER L */
|
|
XK_m: 109,
|
|
/* U+006D LATIN SMALL LETTER M */
|
|
XK_n: 110,
|
|
/* U+006E LATIN SMALL LETTER N */
|
|
XK_o: 111,
|
|
/* U+006F LATIN SMALL LETTER O */
|
|
XK_p: 112,
|
|
/* U+0070 LATIN SMALL LETTER P */
|
|
XK_q: 113,
|
|
/* U+0071 LATIN SMALL LETTER Q */
|
|
XK_r: 114,
|
|
/* U+0072 LATIN SMALL LETTER R */
|
|
XK_s: 115,
|
|
/* U+0073 LATIN SMALL LETTER S */
|
|
XK_t: 116,
|
|
/* U+0074 LATIN SMALL LETTER T */
|
|
XK_u: 117,
|
|
/* U+0075 LATIN SMALL LETTER U */
|
|
XK_v: 118,
|
|
/* U+0076 LATIN SMALL LETTER V */
|
|
XK_w: 119,
|
|
/* U+0077 LATIN SMALL LETTER W */
|
|
XK_x: 120,
|
|
/* U+0078 LATIN SMALL LETTER X */
|
|
XK_y: 121,
|
|
/* U+0079 LATIN SMALL LETTER Y */
|
|
XK_z: 122,
|
|
/* U+007A LATIN SMALL LETTER Z */
|
|
XK_braceleft: 123,
|
|
/* U+007B LEFT CURLY BRACKET */
|
|
XK_bar: 124,
|
|
/* U+007C VERTICAL LINE */
|
|
XK_braceright: 125,
|
|
/* U+007D RIGHT CURLY BRACKET */
|
|
XK_asciitilde: 126,
|
|
/* U+007E TILDE */
|
|
XK_nobreakspace: 160,
|
|
/* U+00A0 NO-BREAK SPACE */
|
|
XK_exclamdown: 161,
|
|
/* U+00A1 INVERTED EXCLAMATION MARK */
|
|
XK_cent: 162,
|
|
/* U+00A2 CENT SIGN */
|
|
XK_sterling: 163,
|
|
/* U+00A3 POUND SIGN */
|
|
XK_currency: 164,
|
|
/* U+00A4 CURRENCY SIGN */
|
|
XK_yen: 165,
|
|
/* U+00A5 YEN SIGN */
|
|
XK_brokenbar: 166,
|
|
/* U+00A6 BROKEN BAR */
|
|
XK_section: 167,
|
|
/* U+00A7 SECTION SIGN */
|
|
XK_diaeresis: 168,
|
|
/* U+00A8 DIAERESIS */
|
|
XK_copyright: 169,
|
|
/* U+00A9 COPYRIGHT SIGN */
|
|
XK_ordfeminine: 170,
|
|
/* U+00AA FEMININE ORDINAL INDICATOR */
|
|
XK_guillemotleft: 171,
|
|
/* U+00AB LEFT-POINTING DOUBLE ANGLE QUOTATION MARK */
|
|
XK_notsign: 172,
|
|
/* U+00AC NOT SIGN */
|
|
XK_hyphen: 173,
|
|
/* U+00AD SOFT HYPHEN */
|
|
XK_registered: 174,
|
|
/* U+00AE REGISTERED SIGN */
|
|
XK_macron: 175,
|
|
/* U+00AF MACRON */
|
|
XK_degree: 176,
|
|
/* U+00B0 DEGREE SIGN */
|
|
XK_plusminus: 177,
|
|
/* U+00B1 PLUS-MINUS SIGN */
|
|
XK_twosuperior: 178,
|
|
/* U+00B2 SUPERSCRIPT TWO */
|
|
XK_threesuperior: 179,
|
|
/* U+00B3 SUPERSCRIPT THREE */
|
|
XK_acute: 180,
|
|
/* U+00B4 ACUTE ACCENT */
|
|
XK_mu: 181,
|
|
/* U+00B5 MICRO SIGN */
|
|
XK_paragraph: 182,
|
|
/* U+00B6 PILCROW SIGN */
|
|
XK_periodcentered: 183,
|
|
/* U+00B7 MIDDLE DOT */
|
|
XK_cedilla: 184,
|
|
/* U+00B8 CEDILLA */
|
|
XK_onesuperior: 185,
|
|
/* U+00B9 SUPERSCRIPT ONE */
|
|
XK_masculine: 186,
|
|
/* U+00BA MASCULINE ORDINAL INDICATOR */
|
|
XK_guillemotright: 187,
|
|
/* U+00BB RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK */
|
|
XK_onequarter: 188,
|
|
/* U+00BC VULGAR FRACTION ONE QUARTER */
|
|
XK_onehalf: 189,
|
|
/* U+00BD VULGAR FRACTION ONE HALF */
|
|
XK_threequarters: 190,
|
|
/* U+00BE VULGAR FRACTION THREE QUARTERS */
|
|
XK_questiondown: 191,
|
|
/* U+00BF INVERTED QUESTION MARK */
|
|
XK_Agrave: 192,
|
|
/* U+00C0 LATIN CAPITAL LETTER A WITH GRAVE */
|
|
XK_Aacute: 193,
|
|
/* U+00C1 LATIN CAPITAL LETTER A WITH ACUTE */
|
|
XK_Acircumflex: 194,
|
|
/* U+00C2 LATIN CAPITAL LETTER A WITH CIRCUMFLEX */
|
|
XK_Atilde: 195,
|
|
/* U+00C3 LATIN CAPITAL LETTER A WITH TILDE */
|
|
XK_Adiaeresis: 196,
|
|
/* U+00C4 LATIN CAPITAL LETTER A WITH DIAERESIS */
|
|
XK_Aring: 197,
|
|
/* U+00C5 LATIN CAPITAL LETTER A WITH RING ABOVE */
|
|
XK_AE: 198,
|
|
/* U+00C6 LATIN CAPITAL LETTER AE */
|
|
XK_Ccedilla: 199,
|
|
/* U+00C7 LATIN CAPITAL LETTER C WITH CEDILLA */
|
|
XK_Egrave: 200,
|
|
/* U+00C8 LATIN CAPITAL LETTER E WITH GRAVE */
|
|
XK_Eacute: 201,
|
|
/* U+00C9 LATIN CAPITAL LETTER E WITH ACUTE */
|
|
XK_Ecircumflex: 202,
|
|
/* U+00CA LATIN CAPITAL LETTER E WITH CIRCUMFLEX */
|
|
XK_Ediaeresis: 203,
|
|
/* U+00CB LATIN CAPITAL LETTER E WITH DIAERESIS */
|
|
XK_Igrave: 204,
|
|
/* U+00CC LATIN CAPITAL LETTER I WITH GRAVE */
|
|
XK_Iacute: 205,
|
|
/* U+00CD LATIN CAPITAL LETTER I WITH ACUTE */
|
|
XK_Icircumflex: 206,
|
|
/* U+00CE LATIN CAPITAL LETTER I WITH CIRCUMFLEX */
|
|
XK_Idiaeresis: 207,
|
|
/* U+00CF LATIN CAPITAL LETTER I WITH DIAERESIS */
|
|
XK_ETH: 208,
|
|
/* U+00D0 LATIN CAPITAL LETTER ETH */
|
|
XK_Eth: 208,
|
|
/* deprecated */
|
|
XK_Ntilde: 209,
|
|
/* U+00D1 LATIN CAPITAL LETTER N WITH TILDE */
|
|
XK_Ograve: 210,
|
|
/* U+00D2 LATIN CAPITAL LETTER O WITH GRAVE */
|
|
XK_Oacute: 211,
|
|
/* U+00D3 LATIN CAPITAL LETTER O WITH ACUTE */
|
|
XK_Ocircumflex: 212,
|
|
/* U+00D4 LATIN CAPITAL LETTER O WITH CIRCUMFLEX */
|
|
XK_Otilde: 213,
|
|
/* U+00D5 LATIN CAPITAL LETTER O WITH TILDE */
|
|
XK_Odiaeresis: 214,
|
|
/* U+00D6 LATIN CAPITAL LETTER O WITH DIAERESIS */
|
|
XK_multiply: 215,
|
|
/* U+00D7 MULTIPLICATION SIGN */
|
|
XK_Oslash: 216,
|
|
/* U+00D8 LATIN CAPITAL LETTER O WITH STROKE */
|
|
XK_Ooblique: 216,
|
|
/* U+00D8 LATIN CAPITAL LETTER O WITH STROKE */
|
|
XK_Ugrave: 217,
|
|
/* U+00D9 LATIN CAPITAL LETTER U WITH GRAVE */
|
|
XK_Uacute: 218,
|
|
/* U+00DA LATIN CAPITAL LETTER U WITH ACUTE */
|
|
XK_Ucircumflex: 219,
|
|
/* U+00DB LATIN CAPITAL LETTER U WITH CIRCUMFLEX */
|
|
XK_Udiaeresis: 220,
|
|
/* U+00DC LATIN CAPITAL LETTER U WITH DIAERESIS */
|
|
XK_Yacute: 221,
|
|
/* U+00DD LATIN CAPITAL LETTER Y WITH ACUTE */
|
|
XK_THORN: 222,
|
|
/* U+00DE LATIN CAPITAL LETTER THORN */
|
|
XK_Thorn: 222,
|
|
/* deprecated */
|
|
XK_ssharp: 223,
|
|
/* U+00DF LATIN SMALL LETTER SHARP S */
|
|
XK_agrave: 224,
|
|
/* U+00E0 LATIN SMALL LETTER A WITH GRAVE */
|
|
XK_aacute: 225,
|
|
/* U+00E1 LATIN SMALL LETTER A WITH ACUTE */
|
|
XK_acircumflex: 226,
|
|
/* U+00E2 LATIN SMALL LETTER A WITH CIRCUMFLEX */
|
|
XK_atilde: 227,
|
|
/* U+00E3 LATIN SMALL LETTER A WITH TILDE */
|
|
XK_adiaeresis: 228,
|
|
/* U+00E4 LATIN SMALL LETTER A WITH DIAERESIS */
|
|
XK_aring: 229,
|
|
/* U+00E5 LATIN SMALL LETTER A WITH RING ABOVE */
|
|
XK_ae: 230,
|
|
/* U+00E6 LATIN SMALL LETTER AE */
|
|
XK_ccedilla: 231,
|
|
/* U+00E7 LATIN SMALL LETTER C WITH CEDILLA */
|
|
XK_egrave: 232,
|
|
/* U+00E8 LATIN SMALL LETTER E WITH GRAVE */
|
|
XK_eacute: 233,
|
|
/* U+00E9 LATIN SMALL LETTER E WITH ACUTE */
|
|
XK_ecircumflex: 234,
|
|
/* U+00EA LATIN SMALL LETTER E WITH CIRCUMFLEX */
|
|
XK_ediaeresis: 235,
|
|
/* U+00EB LATIN SMALL LETTER E WITH DIAERESIS */
|
|
XK_igrave: 236,
|
|
/* U+00EC LATIN SMALL LETTER I WITH GRAVE */
|
|
XK_iacute: 237,
|
|
/* U+00ED LATIN SMALL LETTER I WITH ACUTE */
|
|
XK_icircumflex: 238,
|
|
/* U+00EE LATIN SMALL LETTER I WITH CIRCUMFLEX */
|
|
XK_idiaeresis: 239,
|
|
/* U+00EF LATIN SMALL LETTER I WITH DIAERESIS */
|
|
XK_eth: 240,
|
|
/* U+00F0 LATIN SMALL LETTER ETH */
|
|
XK_ntilde: 241,
|
|
/* U+00F1 LATIN SMALL LETTER N WITH TILDE */
|
|
XK_ograve: 242,
|
|
/* U+00F2 LATIN SMALL LETTER O WITH GRAVE */
|
|
XK_oacute: 243,
|
|
/* U+00F3 LATIN SMALL LETTER O WITH ACUTE */
|
|
XK_ocircumflex: 244,
|
|
/* U+00F4 LATIN SMALL LETTER O WITH CIRCUMFLEX */
|
|
XK_otilde: 245,
|
|
/* U+00F5 LATIN SMALL LETTER O WITH TILDE */
|
|
XK_odiaeresis: 246,
|
|
/* U+00F6 LATIN SMALL LETTER O WITH DIAERESIS */
|
|
XK_division: 247,
|
|
/* U+00F7 DIVISION SIGN */
|
|
XK_oslash: 248,
|
|
/* U+00F8 LATIN SMALL LETTER O WITH STROKE */
|
|
XK_ooblique: 248,
|
|
/* U+00F8 LATIN SMALL LETTER O WITH STROKE */
|
|
XK_ugrave: 249,
|
|
/* U+00F9 LATIN SMALL LETTER U WITH GRAVE */
|
|
XK_uacute: 250,
|
|
/* U+00FA LATIN SMALL LETTER U WITH ACUTE */
|
|
XK_ucircumflex: 251,
|
|
/* U+00FB LATIN SMALL LETTER U WITH CIRCUMFLEX */
|
|
XK_udiaeresis: 252,
|
|
/* U+00FC LATIN SMALL LETTER U WITH DIAERESIS */
|
|
XK_yacute: 253,
|
|
/* U+00FD LATIN SMALL LETTER Y WITH ACUTE */
|
|
XK_thorn: 254,
|
|
/* U+00FE LATIN SMALL LETTER THORN */
|
|
XK_ydiaeresis: 255,
|
|
/* U+00FF LATIN SMALL LETTER Y WITH DIAERESIS */
|
|
/*
|
|
* Korean
|
|
* Byte 3 = 0x0e
|
|
*/
|
|
XK_Hangul: 65329,
|
|
/* Hangul start/stop(toggle) */
|
|
XK_Hangul_Hanja: 65332,
|
|
/* Start Hangul->Hanja Conversion */
|
|
XK_Hangul_Jeonja: 65336,
|
|
/* Jeonja mode */
|
|
/*
|
|
* XFree86 vendor specific keysyms.
|
|
*
|
|
* The XFree86 keysym range is 0x10080001 - 0x1008FFFF.
|
|
*/
|
|
XF86XK_ModeLock: 269025025,
|
|
XF86XK_MonBrightnessUp: 269025026,
|
|
XF86XK_MonBrightnessDown: 269025027,
|
|
XF86XK_KbdLightOnOff: 269025028,
|
|
XF86XK_KbdBrightnessUp: 269025029,
|
|
XF86XK_KbdBrightnessDown: 269025030,
|
|
XF86XK_Standby: 269025040,
|
|
XF86XK_AudioLowerVolume: 269025041,
|
|
XF86XK_AudioMute: 269025042,
|
|
XF86XK_AudioRaiseVolume: 269025043,
|
|
XF86XK_AudioPlay: 269025044,
|
|
XF86XK_AudioStop: 269025045,
|
|
XF86XK_AudioPrev: 269025046,
|
|
XF86XK_AudioNext: 269025047,
|
|
XF86XK_HomePage: 269025048,
|
|
XF86XK_Mail: 269025049,
|
|
XF86XK_Start: 269025050,
|
|
XF86XK_Search: 269025051,
|
|
XF86XK_AudioRecord: 269025052,
|
|
XF86XK_Calculator: 269025053,
|
|
XF86XK_Memo: 269025054,
|
|
XF86XK_ToDoList: 269025055,
|
|
XF86XK_Calendar: 269025056,
|
|
XF86XK_PowerDown: 269025057,
|
|
XF86XK_ContrastAdjust: 269025058,
|
|
XF86XK_RockerUp: 269025059,
|
|
XF86XK_RockerDown: 269025060,
|
|
XF86XK_RockerEnter: 269025061,
|
|
XF86XK_Back: 269025062,
|
|
XF86XK_Forward: 269025063,
|
|
XF86XK_Stop: 269025064,
|
|
XF86XK_Refresh: 269025065,
|
|
XF86XK_PowerOff: 269025066,
|
|
XF86XK_WakeUp: 269025067,
|
|
XF86XK_Eject: 269025068,
|
|
XF86XK_ScreenSaver: 269025069,
|
|
XF86XK_WWW: 269025070,
|
|
XF86XK_Sleep: 269025071,
|
|
XF86XK_Favorites: 269025072,
|
|
XF86XK_AudioPause: 269025073,
|
|
XF86XK_AudioMedia: 269025074,
|
|
XF86XK_MyComputer: 269025075,
|
|
XF86XK_VendorHome: 269025076,
|
|
XF86XK_LightBulb: 269025077,
|
|
XF86XK_Shop: 269025078,
|
|
XF86XK_History: 269025079,
|
|
XF86XK_OpenURL: 269025080,
|
|
XF86XK_AddFavorite: 269025081,
|
|
XF86XK_HotLinks: 269025082,
|
|
XF86XK_BrightnessAdjust: 269025083,
|
|
XF86XK_Finance: 269025084,
|
|
XF86XK_Community: 269025085,
|
|
XF86XK_AudioRewind: 269025086,
|
|
XF86XK_BackForward: 269025087,
|
|
XF86XK_Launch0: 269025088,
|
|
XF86XK_Launch1: 269025089,
|
|
XF86XK_Launch2: 269025090,
|
|
XF86XK_Launch3: 269025091,
|
|
XF86XK_Launch4: 269025092,
|
|
XF86XK_Launch5: 269025093,
|
|
XF86XK_Launch6: 269025094,
|
|
XF86XK_Launch7: 269025095,
|
|
XF86XK_Launch8: 269025096,
|
|
XF86XK_Launch9: 269025097,
|
|
XF86XK_LaunchA: 269025098,
|
|
XF86XK_LaunchB: 269025099,
|
|
XF86XK_LaunchC: 269025100,
|
|
XF86XK_LaunchD: 269025101,
|
|
XF86XK_LaunchE: 269025102,
|
|
XF86XK_LaunchF: 269025103,
|
|
XF86XK_ApplicationLeft: 269025104,
|
|
XF86XK_ApplicationRight: 269025105,
|
|
XF86XK_Book: 269025106,
|
|
XF86XK_CD: 269025107,
|
|
XF86XK_Calculater: 269025108,
|
|
XF86XK_Clear: 269025109,
|
|
XF86XK_Close: 269025110,
|
|
XF86XK_Copy: 269025111,
|
|
XF86XK_Cut: 269025112,
|
|
XF86XK_Display: 269025113,
|
|
XF86XK_DOS: 269025114,
|
|
XF86XK_Documents: 269025115,
|
|
XF86XK_Excel: 269025116,
|
|
XF86XK_Explorer: 269025117,
|
|
XF86XK_Game: 269025118,
|
|
XF86XK_Go: 269025119,
|
|
XF86XK_iTouch: 269025120,
|
|
XF86XK_LogOff: 269025121,
|
|
XF86XK_Market: 269025122,
|
|
XF86XK_Meeting: 269025123,
|
|
XF86XK_MenuKB: 269025125,
|
|
XF86XK_MenuPB: 269025126,
|
|
XF86XK_MySites: 269025127,
|
|
XF86XK_New: 269025128,
|
|
XF86XK_News: 269025129,
|
|
XF86XK_OfficeHome: 269025130,
|
|
XF86XK_Open: 269025131,
|
|
XF86XK_Option: 269025132,
|
|
XF86XK_Paste: 269025133,
|
|
XF86XK_Phone: 269025134,
|
|
XF86XK_Q: 269025136,
|
|
XF86XK_Reply: 269025138,
|
|
XF86XK_Reload: 269025139,
|
|
XF86XK_RotateWindows: 269025140,
|
|
XF86XK_RotationPB: 269025141,
|
|
XF86XK_RotationKB: 269025142,
|
|
XF86XK_Save: 269025143,
|
|
XF86XK_ScrollUp: 269025144,
|
|
XF86XK_ScrollDown: 269025145,
|
|
XF86XK_ScrollClick: 269025146,
|
|
XF86XK_Send: 269025147,
|
|
XF86XK_Spell: 269025148,
|
|
XF86XK_SplitScreen: 269025149,
|
|
XF86XK_Support: 269025150,
|
|
XF86XK_TaskPane: 269025151,
|
|
XF86XK_Terminal: 269025152,
|
|
XF86XK_Tools: 269025153,
|
|
XF86XK_Travel: 269025154,
|
|
XF86XK_UserPB: 269025156,
|
|
XF86XK_User1KB: 269025157,
|
|
XF86XK_User2KB: 269025158,
|
|
XF86XK_Video: 269025159,
|
|
XF86XK_WheelButton: 269025160,
|
|
XF86XK_Word: 269025161,
|
|
XF86XK_Xfer: 269025162,
|
|
XF86XK_ZoomIn: 269025163,
|
|
XF86XK_ZoomOut: 269025164,
|
|
XF86XK_Away: 269025165,
|
|
XF86XK_Messenger: 269025166,
|
|
XF86XK_WebCam: 269025167,
|
|
XF86XK_MailForward: 269025168,
|
|
XF86XK_Pictures: 269025169,
|
|
XF86XK_Music: 269025170,
|
|
XF86XK_Battery: 269025171,
|
|
XF86XK_Bluetooth: 269025172,
|
|
XF86XK_WLAN: 269025173,
|
|
XF86XK_UWB: 269025174,
|
|
XF86XK_AudioForward: 269025175,
|
|
XF86XK_AudioRepeat: 269025176,
|
|
XF86XK_AudioRandomPlay: 269025177,
|
|
XF86XK_Subtitle: 269025178,
|
|
XF86XK_AudioCycleTrack: 269025179,
|
|
XF86XK_CycleAngle: 269025180,
|
|
XF86XK_FrameBack: 269025181,
|
|
XF86XK_FrameForward: 269025182,
|
|
XF86XK_Time: 269025183,
|
|
XF86XK_Select: 269025184,
|
|
XF86XK_View: 269025185,
|
|
XF86XK_TopMenu: 269025186,
|
|
XF86XK_Red: 269025187,
|
|
XF86XK_Green: 269025188,
|
|
XF86XK_Yellow: 269025189,
|
|
XF86XK_Blue: 269025190,
|
|
XF86XK_Suspend: 269025191,
|
|
XF86XK_Hibernate: 269025192,
|
|
XF86XK_TouchpadToggle: 269025193,
|
|
XF86XK_TouchpadOn: 269025200,
|
|
XF86XK_TouchpadOff: 269025201,
|
|
XF86XK_AudioMicMute: 269025202,
|
|
XF86XK_Switch_VT_1: 269024769,
|
|
XF86XK_Switch_VT_2: 269024770,
|
|
XF86XK_Switch_VT_3: 269024771,
|
|
XF86XK_Switch_VT_4: 269024772,
|
|
XF86XK_Switch_VT_5: 269024773,
|
|
XF86XK_Switch_VT_6: 269024774,
|
|
XF86XK_Switch_VT_7: 269024775,
|
|
XF86XK_Switch_VT_8: 269024776,
|
|
XF86XK_Switch_VT_9: 269024777,
|
|
XF86XK_Switch_VT_10: 269024778,
|
|
XF86XK_Switch_VT_11: 269024779,
|
|
XF86XK_Switch_VT_12: 269024780,
|
|
XF86XK_Ungrab: 269024800,
|
|
XF86XK_ClearGrab: 269024801,
|
|
XF86XK_Next_VMode: 269024802,
|
|
XF86XK_Prev_VMode: 269024803,
|
|
XF86XK_LogWindowTree: 269024804,
|
|
XF86XK_LogGrabInfo: 269024805
|
|
};
|
|
|
|
// core/input/keysymdef.js
|
|
var codepoints = {
|
|
256: 960,
|
|
// XK_Amacron
|
|
257: 992,
|
|
// XK_amacron
|
|
258: 451,
|
|
// XK_Abreve
|
|
259: 483,
|
|
// XK_abreve
|
|
260: 417,
|
|
// XK_Aogonek
|
|
261: 433,
|
|
// XK_aogonek
|
|
262: 454,
|
|
// XK_Cacute
|
|
263: 486,
|
|
// XK_cacute
|
|
264: 710,
|
|
// XK_Ccircumflex
|
|
265: 742,
|
|
// XK_ccircumflex
|
|
266: 709,
|
|
// XK_Cabovedot
|
|
267: 741,
|
|
// XK_cabovedot
|
|
268: 456,
|
|
// XK_Ccaron
|
|
269: 488,
|
|
// XK_ccaron
|
|
270: 463,
|
|
// XK_Dcaron
|
|
271: 495,
|
|
// XK_dcaron
|
|
272: 464,
|
|
// XK_Dstroke
|
|
273: 496,
|
|
// XK_dstroke
|
|
274: 938,
|
|
// XK_Emacron
|
|
275: 954,
|
|
// XK_emacron
|
|
278: 972,
|
|
// XK_Eabovedot
|
|
279: 1004,
|
|
// XK_eabovedot
|
|
280: 458,
|
|
// XK_Eogonek
|
|
281: 490,
|
|
// XK_eogonek
|
|
282: 460,
|
|
// XK_Ecaron
|
|
283: 492,
|
|
// XK_ecaron
|
|
284: 728,
|
|
// XK_Gcircumflex
|
|
285: 760,
|
|
// XK_gcircumflex
|
|
286: 683,
|
|
// XK_Gbreve
|
|
287: 699,
|
|
// XK_gbreve
|
|
288: 725,
|
|
// XK_Gabovedot
|
|
289: 757,
|
|
// XK_gabovedot
|
|
290: 939,
|
|
// XK_Gcedilla
|
|
291: 955,
|
|
// XK_gcedilla
|
|
292: 678,
|
|
// XK_Hcircumflex
|
|
293: 694,
|
|
// XK_hcircumflex
|
|
294: 673,
|
|
// XK_Hstroke
|
|
295: 689,
|
|
// XK_hstroke
|
|
296: 933,
|
|
// XK_Itilde
|
|
297: 949,
|
|
// XK_itilde
|
|
298: 975,
|
|
// XK_Imacron
|
|
299: 1007,
|
|
// XK_imacron
|
|
302: 967,
|
|
// XK_Iogonek
|
|
303: 999,
|
|
// XK_iogonek
|
|
304: 681,
|
|
// XK_Iabovedot
|
|
305: 697,
|
|
// XK_idotless
|
|
308: 684,
|
|
// XK_Jcircumflex
|
|
309: 700,
|
|
// XK_jcircumflex
|
|
310: 979,
|
|
// XK_Kcedilla
|
|
311: 1011,
|
|
// XK_kcedilla
|
|
312: 930,
|
|
// XK_kra
|
|
313: 453,
|
|
// XK_Lacute
|
|
314: 485,
|
|
// XK_lacute
|
|
315: 934,
|
|
// XK_Lcedilla
|
|
316: 950,
|
|
// XK_lcedilla
|
|
317: 421,
|
|
// XK_Lcaron
|
|
318: 437,
|
|
// XK_lcaron
|
|
321: 419,
|
|
// XK_Lstroke
|
|
322: 435,
|
|
// XK_lstroke
|
|
323: 465,
|
|
// XK_Nacute
|
|
324: 497,
|
|
// XK_nacute
|
|
325: 977,
|
|
// XK_Ncedilla
|
|
326: 1009,
|
|
// XK_ncedilla
|
|
327: 466,
|
|
// XK_Ncaron
|
|
328: 498,
|
|
// XK_ncaron
|
|
330: 957,
|
|
// XK_ENG
|
|
331: 959,
|
|
// XK_eng
|
|
332: 978,
|
|
// XK_Omacron
|
|
333: 1010,
|
|
// XK_omacron
|
|
336: 469,
|
|
// XK_Odoubleacute
|
|
337: 501,
|
|
// XK_odoubleacute
|
|
338: 5052,
|
|
// XK_OE
|
|
339: 5053,
|
|
// XK_oe
|
|
340: 448,
|
|
// XK_Racute
|
|
341: 480,
|
|
// XK_racute
|
|
342: 931,
|
|
// XK_Rcedilla
|
|
343: 947,
|
|
// XK_rcedilla
|
|
344: 472,
|
|
// XK_Rcaron
|
|
345: 504,
|
|
// XK_rcaron
|
|
346: 422,
|
|
// XK_Sacute
|
|
347: 438,
|
|
// XK_sacute
|
|
348: 734,
|
|
// XK_Scircumflex
|
|
349: 766,
|
|
// XK_scircumflex
|
|
350: 426,
|
|
// XK_Scedilla
|
|
351: 442,
|
|
// XK_scedilla
|
|
352: 425,
|
|
// XK_Scaron
|
|
353: 441,
|
|
// XK_scaron
|
|
354: 478,
|
|
// XK_Tcedilla
|
|
355: 510,
|
|
// XK_tcedilla
|
|
356: 427,
|
|
// XK_Tcaron
|
|
357: 443,
|
|
// XK_tcaron
|
|
358: 940,
|
|
// XK_Tslash
|
|
359: 956,
|
|
// XK_tslash
|
|
360: 989,
|
|
// XK_Utilde
|
|
361: 1021,
|
|
// XK_utilde
|
|
362: 990,
|
|
// XK_Umacron
|
|
363: 1022,
|
|
// XK_umacron
|
|
364: 733,
|
|
// XK_Ubreve
|
|
365: 765,
|
|
// XK_ubreve
|
|
366: 473,
|
|
// XK_Uring
|
|
367: 505,
|
|
// XK_uring
|
|
368: 475,
|
|
// XK_Udoubleacute
|
|
369: 507,
|
|
// XK_udoubleacute
|
|
370: 985,
|
|
// XK_Uogonek
|
|
371: 1017,
|
|
// XK_uogonek
|
|
376: 5054,
|
|
// XK_Ydiaeresis
|
|
377: 428,
|
|
// XK_Zacute
|
|
378: 444,
|
|
// XK_zacute
|
|
379: 431,
|
|
// XK_Zabovedot
|
|
380: 447,
|
|
// XK_zabovedot
|
|
381: 430,
|
|
// XK_Zcaron
|
|
382: 446,
|
|
// XK_zcaron
|
|
402: 2294,
|
|
// XK_function
|
|
466: 16777681,
|
|
// XK_Ocaron
|
|
711: 439,
|
|
// XK_caron
|
|
728: 418,
|
|
// XK_breve
|
|
729: 511,
|
|
// XK_abovedot
|
|
731: 434,
|
|
// XK_ogonek
|
|
733: 445,
|
|
// XK_doubleacute
|
|
901: 1966,
|
|
// XK_Greek_accentdieresis
|
|
902: 1953,
|
|
// XK_Greek_ALPHAaccent
|
|
904: 1954,
|
|
// XK_Greek_EPSILONaccent
|
|
905: 1955,
|
|
// XK_Greek_ETAaccent
|
|
906: 1956,
|
|
// XK_Greek_IOTAaccent
|
|
908: 1959,
|
|
// XK_Greek_OMICRONaccent
|
|
910: 1960,
|
|
// XK_Greek_UPSILONaccent
|
|
911: 1963,
|
|
// XK_Greek_OMEGAaccent
|
|
912: 1974,
|
|
// XK_Greek_iotaaccentdieresis
|
|
913: 1985,
|
|
// XK_Greek_ALPHA
|
|
914: 1986,
|
|
// XK_Greek_BETA
|
|
915: 1987,
|
|
// XK_Greek_GAMMA
|
|
916: 1988,
|
|
// XK_Greek_DELTA
|
|
917: 1989,
|
|
// XK_Greek_EPSILON
|
|
918: 1990,
|
|
// XK_Greek_ZETA
|
|
919: 1991,
|
|
// XK_Greek_ETA
|
|
920: 1992,
|
|
// XK_Greek_THETA
|
|
921: 1993,
|
|
// XK_Greek_IOTA
|
|
922: 1994,
|
|
// XK_Greek_KAPPA
|
|
923: 1995,
|
|
// XK_Greek_LAMDA
|
|
924: 1996,
|
|
// XK_Greek_MU
|
|
925: 1997,
|
|
// XK_Greek_NU
|
|
926: 1998,
|
|
// XK_Greek_XI
|
|
927: 1999,
|
|
// XK_Greek_OMICRON
|
|
928: 2e3,
|
|
// XK_Greek_PI
|
|
929: 2001,
|
|
// XK_Greek_RHO
|
|
931: 2002,
|
|
// XK_Greek_SIGMA
|
|
932: 2004,
|
|
// XK_Greek_TAU
|
|
933: 2005,
|
|
// XK_Greek_UPSILON
|
|
934: 2006,
|
|
// XK_Greek_PHI
|
|
935: 2007,
|
|
// XK_Greek_CHI
|
|
936: 2008,
|
|
// XK_Greek_PSI
|
|
937: 2009,
|
|
// XK_Greek_OMEGA
|
|
938: 1957,
|
|
// XK_Greek_IOTAdieresis
|
|
939: 1961,
|
|
// XK_Greek_UPSILONdieresis
|
|
940: 1969,
|
|
// XK_Greek_alphaaccent
|
|
941: 1970,
|
|
// XK_Greek_epsilonaccent
|
|
942: 1971,
|
|
// XK_Greek_etaaccent
|
|
943: 1972,
|
|
// XK_Greek_iotaaccent
|
|
944: 1978,
|
|
// XK_Greek_upsilonaccentdieresis
|
|
945: 2017,
|
|
// XK_Greek_alpha
|
|
946: 2018,
|
|
// XK_Greek_beta
|
|
947: 2019,
|
|
// XK_Greek_gamma
|
|
948: 2020,
|
|
// XK_Greek_delta
|
|
949: 2021,
|
|
// XK_Greek_epsilon
|
|
950: 2022,
|
|
// XK_Greek_zeta
|
|
951: 2023,
|
|
// XK_Greek_eta
|
|
952: 2024,
|
|
// XK_Greek_theta
|
|
953: 2025,
|
|
// XK_Greek_iota
|
|
954: 2026,
|
|
// XK_Greek_kappa
|
|
955: 2027,
|
|
// XK_Greek_lamda
|
|
956: 2028,
|
|
// XK_Greek_mu
|
|
957: 2029,
|
|
// XK_Greek_nu
|
|
958: 2030,
|
|
// XK_Greek_xi
|
|
959: 2031,
|
|
// XK_Greek_omicron
|
|
960: 2032,
|
|
// XK_Greek_pi
|
|
961: 2033,
|
|
// XK_Greek_rho
|
|
962: 2035,
|
|
// XK_Greek_finalsmallsigma
|
|
963: 2034,
|
|
// XK_Greek_sigma
|
|
964: 2036,
|
|
// XK_Greek_tau
|
|
965: 2037,
|
|
// XK_Greek_upsilon
|
|
966: 2038,
|
|
// XK_Greek_phi
|
|
967: 2039,
|
|
// XK_Greek_chi
|
|
968: 2040,
|
|
// XK_Greek_psi
|
|
969: 2041,
|
|
// XK_Greek_omega
|
|
970: 1973,
|
|
// XK_Greek_iotadieresis
|
|
971: 1977,
|
|
// XK_Greek_upsilondieresis
|
|
972: 1975,
|
|
// XK_Greek_omicronaccent
|
|
973: 1976,
|
|
// XK_Greek_upsilonaccent
|
|
974: 1979,
|
|
// XK_Greek_omegaaccent
|
|
1025: 1715,
|
|
// XK_Cyrillic_IO
|
|
1026: 1713,
|
|
// XK_Serbian_DJE
|
|
1027: 1714,
|
|
// XK_Macedonia_GJE
|
|
1028: 1716,
|
|
// XK_Ukrainian_IE
|
|
1029: 1717,
|
|
// XK_Macedonia_DSE
|
|
1030: 1718,
|
|
// XK_Ukrainian_I
|
|
1031: 1719,
|
|
// XK_Ukrainian_YI
|
|
1032: 1720,
|
|
// XK_Cyrillic_JE
|
|
1033: 1721,
|
|
// XK_Cyrillic_LJE
|
|
1034: 1722,
|
|
// XK_Cyrillic_NJE
|
|
1035: 1723,
|
|
// XK_Serbian_TSHE
|
|
1036: 1724,
|
|
// XK_Macedonia_KJE
|
|
1038: 1726,
|
|
// XK_Byelorussian_SHORTU
|
|
1039: 1727,
|
|
// XK_Cyrillic_DZHE
|
|
1040: 1761,
|
|
// XK_Cyrillic_A
|
|
1041: 1762,
|
|
// XK_Cyrillic_BE
|
|
1042: 1783,
|
|
// XK_Cyrillic_VE
|
|
1043: 1767,
|
|
// XK_Cyrillic_GHE
|
|
1044: 1764,
|
|
// XK_Cyrillic_DE
|
|
1045: 1765,
|
|
// XK_Cyrillic_IE
|
|
1046: 1782,
|
|
// XK_Cyrillic_ZHE
|
|
1047: 1786,
|
|
// XK_Cyrillic_ZE
|
|
1048: 1769,
|
|
// XK_Cyrillic_I
|
|
1049: 1770,
|
|
// XK_Cyrillic_SHORTI
|
|
1050: 1771,
|
|
// XK_Cyrillic_KA
|
|
1051: 1772,
|
|
// XK_Cyrillic_EL
|
|
1052: 1773,
|
|
// XK_Cyrillic_EM
|
|
1053: 1774,
|
|
// XK_Cyrillic_EN
|
|
1054: 1775,
|
|
// XK_Cyrillic_O
|
|
1055: 1776,
|
|
// XK_Cyrillic_PE
|
|
1056: 1778,
|
|
// XK_Cyrillic_ER
|
|
1057: 1779,
|
|
// XK_Cyrillic_ES
|
|
1058: 1780,
|
|
// XK_Cyrillic_TE
|
|
1059: 1781,
|
|
// XK_Cyrillic_U
|
|
1060: 1766,
|
|
// XK_Cyrillic_EF
|
|
1061: 1768,
|
|
// XK_Cyrillic_HA
|
|
1062: 1763,
|
|
// XK_Cyrillic_TSE
|
|
1063: 1790,
|
|
// XK_Cyrillic_CHE
|
|
1064: 1787,
|
|
// XK_Cyrillic_SHA
|
|
1065: 1789,
|
|
// XK_Cyrillic_SHCHA
|
|
1066: 1791,
|
|
// XK_Cyrillic_HARDSIGN
|
|
1067: 1785,
|
|
// XK_Cyrillic_YERU
|
|
1068: 1784,
|
|
// XK_Cyrillic_SOFTSIGN
|
|
1069: 1788,
|
|
// XK_Cyrillic_E
|
|
1070: 1760,
|
|
// XK_Cyrillic_YU
|
|
1071: 1777,
|
|
// XK_Cyrillic_YA
|
|
1072: 1729,
|
|
// XK_Cyrillic_a
|
|
1073: 1730,
|
|
// XK_Cyrillic_be
|
|
1074: 1751,
|
|
// XK_Cyrillic_ve
|
|
1075: 1735,
|
|
// XK_Cyrillic_ghe
|
|
1076: 1732,
|
|
// XK_Cyrillic_de
|
|
1077: 1733,
|
|
// XK_Cyrillic_ie
|
|
1078: 1750,
|
|
// XK_Cyrillic_zhe
|
|
1079: 1754,
|
|
// XK_Cyrillic_ze
|
|
1080: 1737,
|
|
// XK_Cyrillic_i
|
|
1081: 1738,
|
|
// XK_Cyrillic_shorti
|
|
1082: 1739,
|
|
// XK_Cyrillic_ka
|
|
1083: 1740,
|
|
// XK_Cyrillic_el
|
|
1084: 1741,
|
|
// XK_Cyrillic_em
|
|
1085: 1742,
|
|
// XK_Cyrillic_en
|
|
1086: 1743,
|
|
// XK_Cyrillic_o
|
|
1087: 1744,
|
|
// XK_Cyrillic_pe
|
|
1088: 1746,
|
|
// XK_Cyrillic_er
|
|
1089: 1747,
|
|
// XK_Cyrillic_es
|
|
1090: 1748,
|
|
// XK_Cyrillic_te
|
|
1091: 1749,
|
|
// XK_Cyrillic_u
|
|
1092: 1734,
|
|
// XK_Cyrillic_ef
|
|
1093: 1736,
|
|
// XK_Cyrillic_ha
|
|
1094: 1731,
|
|
// XK_Cyrillic_tse
|
|
1095: 1758,
|
|
// XK_Cyrillic_che
|
|
1096: 1755,
|
|
// XK_Cyrillic_sha
|
|
1097: 1757,
|
|
// XK_Cyrillic_shcha
|
|
1098: 1759,
|
|
// XK_Cyrillic_hardsign
|
|
1099: 1753,
|
|
// XK_Cyrillic_yeru
|
|
1100: 1752,
|
|
// XK_Cyrillic_softsign
|
|
1101: 1756,
|
|
// XK_Cyrillic_e
|
|
1102: 1728,
|
|
// XK_Cyrillic_yu
|
|
1103: 1745,
|
|
// XK_Cyrillic_ya
|
|
1105: 1699,
|
|
// XK_Cyrillic_io
|
|
1106: 1697,
|
|
// XK_Serbian_dje
|
|
1107: 1698,
|
|
// XK_Macedonia_gje
|
|
1108: 1700,
|
|
// XK_Ukrainian_ie
|
|
1109: 1701,
|
|
// XK_Macedonia_dse
|
|
1110: 1702,
|
|
// XK_Ukrainian_i
|
|
1111: 1703,
|
|
// XK_Ukrainian_yi
|
|
1112: 1704,
|
|
// XK_Cyrillic_je
|
|
1113: 1705,
|
|
// XK_Cyrillic_lje
|
|
1114: 1706,
|
|
// XK_Cyrillic_nje
|
|
1115: 1707,
|
|
// XK_Serbian_tshe
|
|
1116: 1708,
|
|
// XK_Macedonia_kje
|
|
1118: 1710,
|
|
// XK_Byelorussian_shortu
|
|
1119: 1711,
|
|
// XK_Cyrillic_dzhe
|
|
1168: 1725,
|
|
// XK_Ukrainian_GHE_WITH_UPTURN
|
|
1169: 1709,
|
|
// XK_Ukrainian_ghe_with_upturn
|
|
1488: 3296,
|
|
// XK_hebrew_aleph
|
|
1489: 3297,
|
|
// XK_hebrew_bet
|
|
1490: 3298,
|
|
// XK_hebrew_gimel
|
|
1491: 3299,
|
|
// XK_hebrew_dalet
|
|
1492: 3300,
|
|
// XK_hebrew_he
|
|
1493: 3301,
|
|
// XK_hebrew_waw
|
|
1494: 3302,
|
|
// XK_hebrew_zain
|
|
1495: 3303,
|
|
// XK_hebrew_chet
|
|
1496: 3304,
|
|
// XK_hebrew_tet
|
|
1497: 3305,
|
|
// XK_hebrew_yod
|
|
1498: 3306,
|
|
// XK_hebrew_finalkaph
|
|
1499: 3307,
|
|
// XK_hebrew_kaph
|
|
1500: 3308,
|
|
// XK_hebrew_lamed
|
|
1501: 3309,
|
|
// XK_hebrew_finalmem
|
|
1502: 3310,
|
|
// XK_hebrew_mem
|
|
1503: 3311,
|
|
// XK_hebrew_finalnun
|
|
1504: 3312,
|
|
// XK_hebrew_nun
|
|
1505: 3313,
|
|
// XK_hebrew_samech
|
|
1506: 3314,
|
|
// XK_hebrew_ayin
|
|
1507: 3315,
|
|
// XK_hebrew_finalpe
|
|
1508: 3316,
|
|
// XK_hebrew_pe
|
|
1509: 3317,
|
|
// XK_hebrew_finalzade
|
|
1510: 3318,
|
|
// XK_hebrew_zade
|
|
1511: 3319,
|
|
// XK_hebrew_qoph
|
|
1512: 3320,
|
|
// XK_hebrew_resh
|
|
1513: 3321,
|
|
// XK_hebrew_shin
|
|
1514: 3322,
|
|
// XK_hebrew_taw
|
|
1548: 1452,
|
|
// XK_Arabic_comma
|
|
1563: 1467,
|
|
// XK_Arabic_semicolon
|
|
1567: 1471,
|
|
// XK_Arabic_question_mark
|
|
1569: 1473,
|
|
// XK_Arabic_hamza
|
|
1570: 1474,
|
|
// XK_Arabic_maddaonalef
|
|
1571: 1475,
|
|
// XK_Arabic_hamzaonalef
|
|
1572: 1476,
|
|
// XK_Arabic_hamzaonwaw
|
|
1573: 1477,
|
|
// XK_Arabic_hamzaunderalef
|
|
1574: 1478,
|
|
// XK_Arabic_hamzaonyeh
|
|
1575: 1479,
|
|
// XK_Arabic_alef
|
|
1576: 1480,
|
|
// XK_Arabic_beh
|
|
1577: 1481,
|
|
// XK_Arabic_tehmarbuta
|
|
1578: 1482,
|
|
// XK_Arabic_teh
|
|
1579: 1483,
|
|
// XK_Arabic_theh
|
|
1580: 1484,
|
|
// XK_Arabic_jeem
|
|
1581: 1485,
|
|
// XK_Arabic_hah
|
|
1582: 1486,
|
|
// XK_Arabic_khah
|
|
1583: 1487,
|
|
// XK_Arabic_dal
|
|
1584: 1488,
|
|
// XK_Arabic_thal
|
|
1585: 1489,
|
|
// XK_Arabic_ra
|
|
1586: 1490,
|
|
// XK_Arabic_zain
|
|
1587: 1491,
|
|
// XK_Arabic_seen
|
|
1588: 1492,
|
|
// XK_Arabic_sheen
|
|
1589: 1493,
|
|
// XK_Arabic_sad
|
|
1590: 1494,
|
|
// XK_Arabic_dad
|
|
1591: 1495,
|
|
// XK_Arabic_tah
|
|
1592: 1496,
|
|
// XK_Arabic_zah
|
|
1593: 1497,
|
|
// XK_Arabic_ain
|
|
1594: 1498,
|
|
// XK_Arabic_ghain
|
|
1600: 1504,
|
|
// XK_Arabic_tatweel
|
|
1601: 1505,
|
|
// XK_Arabic_feh
|
|
1602: 1506,
|
|
// XK_Arabic_qaf
|
|
1603: 1507,
|
|
// XK_Arabic_kaf
|
|
1604: 1508,
|
|
// XK_Arabic_lam
|
|
1605: 1509,
|
|
// XK_Arabic_meem
|
|
1606: 1510,
|
|
// XK_Arabic_noon
|
|
1607: 1511,
|
|
// XK_Arabic_ha
|
|
1608: 1512,
|
|
// XK_Arabic_waw
|
|
1609: 1513,
|
|
// XK_Arabic_alefmaksura
|
|
1610: 1514,
|
|
// XK_Arabic_yeh
|
|
1611: 1515,
|
|
// XK_Arabic_fathatan
|
|
1612: 1516,
|
|
// XK_Arabic_dammatan
|
|
1613: 1517,
|
|
// XK_Arabic_kasratan
|
|
1614: 1518,
|
|
// XK_Arabic_fatha
|
|
1615: 1519,
|
|
// XK_Arabic_damma
|
|
1616: 1520,
|
|
// XK_Arabic_kasra
|
|
1617: 1521,
|
|
// XK_Arabic_shadda
|
|
1618: 1522,
|
|
// XK_Arabic_sukun
|
|
3585: 3489,
|
|
// XK_Thai_kokai
|
|
3586: 3490,
|
|
// XK_Thai_khokhai
|
|
3587: 3491,
|
|
// XK_Thai_khokhuat
|
|
3588: 3492,
|
|
// XK_Thai_khokhwai
|
|
3589: 3493,
|
|
// XK_Thai_khokhon
|
|
3590: 3494,
|
|
// XK_Thai_khorakhang
|
|
3591: 3495,
|
|
// XK_Thai_ngongu
|
|
3592: 3496,
|
|
// XK_Thai_chochan
|
|
3593: 3497,
|
|
// XK_Thai_choching
|
|
3594: 3498,
|
|
// XK_Thai_chochang
|
|
3595: 3499,
|
|
// XK_Thai_soso
|
|
3596: 3500,
|
|
// XK_Thai_chochoe
|
|
3597: 3501,
|
|
// XK_Thai_yoying
|
|
3598: 3502,
|
|
// XK_Thai_dochada
|
|
3599: 3503,
|
|
// XK_Thai_topatak
|
|
3600: 3504,
|
|
// XK_Thai_thothan
|
|
3601: 3505,
|
|
// XK_Thai_thonangmontho
|
|
3602: 3506,
|
|
// XK_Thai_thophuthao
|
|
3603: 3507,
|
|
// XK_Thai_nonen
|
|
3604: 3508,
|
|
// XK_Thai_dodek
|
|
3605: 3509,
|
|
// XK_Thai_totao
|
|
3606: 3510,
|
|
// XK_Thai_thothung
|
|
3607: 3511,
|
|
// XK_Thai_thothahan
|
|
3608: 3512,
|
|
// XK_Thai_thothong
|
|
3609: 3513,
|
|
// XK_Thai_nonu
|
|
3610: 3514,
|
|
// XK_Thai_bobaimai
|
|
3611: 3515,
|
|
// XK_Thai_popla
|
|
3612: 3516,
|
|
// XK_Thai_phophung
|
|
3613: 3517,
|
|
// XK_Thai_fofa
|
|
3614: 3518,
|
|
// XK_Thai_phophan
|
|
3615: 3519,
|
|
// XK_Thai_fofan
|
|
3616: 3520,
|
|
// XK_Thai_phosamphao
|
|
3617: 3521,
|
|
// XK_Thai_moma
|
|
3618: 3522,
|
|
// XK_Thai_yoyak
|
|
3619: 3523,
|
|
// XK_Thai_rorua
|
|
3620: 3524,
|
|
// XK_Thai_ru
|
|
3621: 3525,
|
|
// XK_Thai_loling
|
|
3622: 3526,
|
|
// XK_Thai_lu
|
|
3623: 3527,
|
|
// XK_Thai_wowaen
|
|
3624: 3528,
|
|
// XK_Thai_sosala
|
|
3625: 3529,
|
|
// XK_Thai_sorusi
|
|
3626: 3530,
|
|
// XK_Thai_sosua
|
|
3627: 3531,
|
|
// XK_Thai_hohip
|
|
3628: 3532,
|
|
// XK_Thai_lochula
|
|
3629: 3533,
|
|
// XK_Thai_oang
|
|
3630: 3534,
|
|
// XK_Thai_honokhuk
|
|
3631: 3535,
|
|
// XK_Thai_paiyannoi
|
|
3632: 3536,
|
|
// XK_Thai_saraa
|
|
3633: 3537,
|
|
// XK_Thai_maihanakat
|
|
3634: 3538,
|
|
// XK_Thai_saraaa
|
|
3635: 3539,
|
|
// XK_Thai_saraam
|
|
3636: 3540,
|
|
// XK_Thai_sarai
|
|
3637: 3541,
|
|
// XK_Thai_saraii
|
|
3638: 3542,
|
|
// XK_Thai_saraue
|
|
3639: 3543,
|
|
// XK_Thai_sarauee
|
|
3640: 3544,
|
|
// XK_Thai_sarau
|
|
3641: 3545,
|
|
// XK_Thai_sarauu
|
|
3642: 3546,
|
|
// XK_Thai_phinthu
|
|
3647: 3551,
|
|
// XK_Thai_baht
|
|
3648: 3552,
|
|
// XK_Thai_sarae
|
|
3649: 3553,
|
|
// XK_Thai_saraae
|
|
3650: 3554,
|
|
// XK_Thai_sarao
|
|
3651: 3555,
|
|
// XK_Thai_saraaimaimuan
|
|
3652: 3556,
|
|
// XK_Thai_saraaimaimalai
|
|
3653: 3557,
|
|
// XK_Thai_lakkhangyao
|
|
3654: 3558,
|
|
// XK_Thai_maiyamok
|
|
3655: 3559,
|
|
// XK_Thai_maitaikhu
|
|
3656: 3560,
|
|
// XK_Thai_maiek
|
|
3657: 3561,
|
|
// XK_Thai_maitho
|
|
3658: 3562,
|
|
// XK_Thai_maitri
|
|
3659: 3563,
|
|
// XK_Thai_maichattawa
|
|
3660: 3564,
|
|
// XK_Thai_thanthakhat
|
|
3661: 3565,
|
|
// XK_Thai_nikhahit
|
|
3664: 3568,
|
|
// XK_Thai_leksun
|
|
3665: 3569,
|
|
// XK_Thai_leknung
|
|
3666: 3570,
|
|
// XK_Thai_leksong
|
|
3667: 3571,
|
|
// XK_Thai_leksam
|
|
3668: 3572,
|
|
// XK_Thai_leksi
|
|
3669: 3573,
|
|
// XK_Thai_lekha
|
|
3670: 3574,
|
|
// XK_Thai_lekhok
|
|
3671: 3575,
|
|
// XK_Thai_lekchet
|
|
3672: 3576,
|
|
// XK_Thai_lekpaet
|
|
3673: 3577,
|
|
// XK_Thai_lekkao
|
|
8194: 2722,
|
|
// XK_enspace
|
|
8195: 2721,
|
|
// XK_emspace
|
|
8196: 2723,
|
|
// XK_em3space
|
|
8197: 2724,
|
|
// XK_em4space
|
|
8199: 2725,
|
|
// XK_digitspace
|
|
8200: 2726,
|
|
// XK_punctspace
|
|
8201: 2727,
|
|
// XK_thinspace
|
|
8202: 2728,
|
|
// XK_hairspace
|
|
8210: 2747,
|
|
// XK_figdash
|
|
8211: 2730,
|
|
// XK_endash
|
|
8212: 2729,
|
|
// XK_emdash
|
|
8213: 1967,
|
|
// XK_Greek_horizbar
|
|
8215: 3295,
|
|
// XK_hebrew_doublelowline
|
|
8216: 2768,
|
|
// XK_leftsinglequotemark
|
|
8217: 2769,
|
|
// XK_rightsinglequotemark
|
|
8218: 2813,
|
|
// XK_singlelowquotemark
|
|
8220: 2770,
|
|
// XK_leftdoublequotemark
|
|
8221: 2771,
|
|
// XK_rightdoublequotemark
|
|
8222: 2814,
|
|
// XK_doublelowquotemark
|
|
8224: 2801,
|
|
// XK_dagger
|
|
8225: 2802,
|
|
// XK_doubledagger
|
|
8226: 2790,
|
|
// XK_enfilledcircbullet
|
|
8229: 2735,
|
|
// XK_doubbaselinedot
|
|
8230: 2734,
|
|
// XK_ellipsis
|
|
8240: 2773,
|
|
// XK_permille
|
|
8242: 2774,
|
|
// XK_minutes
|
|
8243: 2775,
|
|
// XK_seconds
|
|
8248: 2812,
|
|
// XK_caret
|
|
8254: 1150,
|
|
// XK_overline
|
|
8361: 3839,
|
|
// XK_Korean_Won
|
|
8364: 8364,
|
|
// XK_EuroSign
|
|
8453: 2744,
|
|
// XK_careof
|
|
8470: 1712,
|
|
// XK_numerosign
|
|
8471: 2811,
|
|
// XK_phonographcopyright
|
|
8478: 2772,
|
|
// XK_prescription
|
|
8482: 2761,
|
|
// XK_trademark
|
|
8531: 2736,
|
|
// XK_onethird
|
|
8532: 2737,
|
|
// XK_twothirds
|
|
8533: 2738,
|
|
// XK_onefifth
|
|
8534: 2739,
|
|
// XK_twofifths
|
|
8535: 2740,
|
|
// XK_threefifths
|
|
8536: 2741,
|
|
// XK_fourfifths
|
|
8537: 2742,
|
|
// XK_onesixth
|
|
8538: 2743,
|
|
// XK_fivesixths
|
|
8539: 2755,
|
|
// XK_oneeighth
|
|
8540: 2756,
|
|
// XK_threeeighths
|
|
8541: 2757,
|
|
// XK_fiveeighths
|
|
8542: 2758,
|
|
// XK_seveneighths
|
|
8592: 2299,
|
|
// XK_leftarrow
|
|
8593: 2300,
|
|
// XK_uparrow
|
|
8594: 2301,
|
|
// XK_rightarrow
|
|
8595: 2302,
|
|
// XK_downarrow
|
|
8658: 2254,
|
|
// XK_implies
|
|
8660: 2253,
|
|
// XK_ifonlyif
|
|
8706: 2287,
|
|
// XK_partialderivative
|
|
8711: 2245,
|
|
// XK_nabla
|
|
8728: 3018,
|
|
// XK_jot
|
|
8730: 2262,
|
|
// XK_radical
|
|
8733: 2241,
|
|
// XK_variation
|
|
8734: 2242,
|
|
// XK_infinity
|
|
8743: 2270,
|
|
// XK_logicaland
|
|
8744: 2271,
|
|
// XK_logicalor
|
|
8745: 2268,
|
|
// XK_intersection
|
|
8746: 2269,
|
|
// XK_union
|
|
8747: 2239,
|
|
// XK_integral
|
|
8756: 2240,
|
|
// XK_therefore
|
|
8764: 2248,
|
|
// XK_approximate
|
|
8771: 2249,
|
|
// XK_similarequal
|
|
8773: 16785992,
|
|
// XK_approxeq
|
|
8800: 2237,
|
|
// XK_notequal
|
|
8801: 2255,
|
|
// XK_identical
|
|
8804: 2236,
|
|
// XK_lessthanequal
|
|
8805: 2238,
|
|
// XK_greaterthanequal
|
|
8834: 2266,
|
|
// XK_includedin
|
|
8835: 2267,
|
|
// XK_includes
|
|
8866: 3068,
|
|
// XK_righttack
|
|
8867: 3036,
|
|
// XK_lefttack
|
|
8868: 3010,
|
|
// XK_downtack
|
|
8869: 3022,
|
|
// XK_uptack
|
|
8968: 3027,
|
|
// XK_upstile
|
|
8970: 3012,
|
|
// XK_downstile
|
|
8981: 2810,
|
|
// XK_telephonerecorder
|
|
8992: 2212,
|
|
// XK_topintegral
|
|
8993: 2213,
|
|
// XK_botintegral
|
|
9109: 3020,
|
|
// XK_quad
|
|
9115: 2219,
|
|
// XK_topleftparens
|
|
9117: 2220,
|
|
// XK_botleftparens
|
|
9118: 2221,
|
|
// XK_toprightparens
|
|
9120: 2222,
|
|
// XK_botrightparens
|
|
9121: 2215,
|
|
// XK_topleftsqbracket
|
|
9123: 2216,
|
|
// XK_botleftsqbracket
|
|
9124: 2217,
|
|
// XK_toprightsqbracket
|
|
9126: 2218,
|
|
// XK_botrightsqbracket
|
|
9128: 2223,
|
|
// XK_leftmiddlecurlybrace
|
|
9132: 2224,
|
|
// XK_rightmiddlecurlybrace
|
|
9143: 2209,
|
|
// XK_leftradical
|
|
9146: 2543,
|
|
// XK_horizlinescan1
|
|
9147: 2544,
|
|
// XK_horizlinescan3
|
|
9148: 2546,
|
|
// XK_horizlinescan7
|
|
9149: 2547,
|
|
// XK_horizlinescan9
|
|
9225: 2530,
|
|
// XK_ht
|
|
9226: 2533,
|
|
// XK_lf
|
|
9227: 2537,
|
|
// XK_vt
|
|
9228: 2531,
|
|
// XK_ff
|
|
9229: 2532,
|
|
// XK_cr
|
|
9251: 2732,
|
|
// XK_signifblank
|
|
9252: 2536,
|
|
// XK_nl
|
|
9472: 2211,
|
|
// XK_horizconnector
|
|
9474: 2214,
|
|
// XK_vertconnector
|
|
9484: 2210,
|
|
// XK_topleftradical
|
|
9488: 2539,
|
|
// XK_uprightcorner
|
|
9492: 2541,
|
|
// XK_lowleftcorner
|
|
9496: 2538,
|
|
// XK_lowrightcorner
|
|
9500: 2548,
|
|
// XK_leftt
|
|
9508: 2549,
|
|
// XK_rightt
|
|
9516: 2551,
|
|
// XK_topt
|
|
9524: 2550,
|
|
// XK_bott
|
|
9532: 2542,
|
|
// XK_crossinglines
|
|
9618: 2529,
|
|
// XK_checkerboard
|
|
9642: 2791,
|
|
// XK_enfilledsqbullet
|
|
9643: 2785,
|
|
// XK_enopensquarebullet
|
|
9644: 2779,
|
|
// XK_filledrectbullet
|
|
9645: 2786,
|
|
// XK_openrectbullet
|
|
9646: 2783,
|
|
// XK_emfilledrect
|
|
9647: 2767,
|
|
// XK_emopenrectangle
|
|
9650: 2792,
|
|
// XK_filledtribulletup
|
|
9651: 2787,
|
|
// XK_opentribulletup
|
|
9654: 2781,
|
|
// XK_filledrighttribullet
|
|
9655: 2765,
|
|
// XK_rightopentriangle
|
|
9660: 2793,
|
|
// XK_filledtribulletdown
|
|
9661: 2788,
|
|
// XK_opentribulletdown
|
|
9664: 2780,
|
|
// XK_filledlefttribullet
|
|
9665: 2764,
|
|
// XK_leftopentriangle
|
|
9670: 2528,
|
|
// XK_soliddiamond
|
|
9675: 2766,
|
|
// XK_emopencircle
|
|
9679: 2782,
|
|
// XK_emfilledcircle
|
|
9702: 2784,
|
|
// XK_enopencircbullet
|
|
9734: 2789,
|
|
// XK_openstar
|
|
9742: 2809,
|
|
// XK_telephone
|
|
9747: 2762,
|
|
// XK_signaturemark
|
|
9756: 2794,
|
|
// XK_leftpointer
|
|
9758: 2795,
|
|
// XK_rightpointer
|
|
9792: 2808,
|
|
// XK_femalesymbol
|
|
9794: 2807,
|
|
// XK_malesymbol
|
|
9827: 2796,
|
|
// XK_club
|
|
9829: 2798,
|
|
// XK_heart
|
|
9830: 2797,
|
|
// XK_diamond
|
|
9837: 2806,
|
|
// XK_musicalflat
|
|
9839: 2805,
|
|
// XK_musicalsharp
|
|
10003: 2803,
|
|
// XK_checkmark
|
|
10007: 2804,
|
|
// XK_ballotcross
|
|
10013: 2777,
|
|
// XK_latincross
|
|
10016: 2800,
|
|
// XK_maltesecross
|
|
10216: 2748,
|
|
// XK_leftanglebracket
|
|
10217: 2750,
|
|
// XK_rightanglebracket
|
|
12289: 1188,
|
|
// XK_kana_comma
|
|
12290: 1185,
|
|
// XK_kana_fullstop
|
|
12300: 1186,
|
|
// XK_kana_openingbracket
|
|
12301: 1187,
|
|
// XK_kana_closingbracket
|
|
12443: 1246,
|
|
// XK_voicedsound
|
|
12444: 1247,
|
|
// XK_semivoicedsound
|
|
12449: 1191,
|
|
// XK_kana_a
|
|
12450: 1201,
|
|
// XK_kana_A
|
|
12451: 1192,
|
|
// XK_kana_i
|
|
12452: 1202,
|
|
// XK_kana_I
|
|
12453: 1193,
|
|
// XK_kana_u
|
|
12454: 1203,
|
|
// XK_kana_U
|
|
12455: 1194,
|
|
// XK_kana_e
|
|
12456: 1204,
|
|
// XK_kana_E
|
|
12457: 1195,
|
|
// XK_kana_o
|
|
12458: 1205,
|
|
// XK_kana_O
|
|
12459: 1206,
|
|
// XK_kana_KA
|
|
12461: 1207,
|
|
// XK_kana_KI
|
|
12463: 1208,
|
|
// XK_kana_KU
|
|
12465: 1209,
|
|
// XK_kana_KE
|
|
12467: 1210,
|
|
// XK_kana_KO
|
|
12469: 1211,
|
|
// XK_kana_SA
|
|
12471: 1212,
|
|
// XK_kana_SHI
|
|
12473: 1213,
|
|
// XK_kana_SU
|
|
12475: 1214,
|
|
// XK_kana_SE
|
|
12477: 1215,
|
|
// XK_kana_SO
|
|
12479: 1216,
|
|
// XK_kana_TA
|
|
12481: 1217,
|
|
// XK_kana_CHI
|
|
12483: 1199,
|
|
// XK_kana_tsu
|
|
12484: 1218,
|
|
// XK_kana_TSU
|
|
12486: 1219,
|
|
// XK_kana_TE
|
|
12488: 1220,
|
|
// XK_kana_TO
|
|
12490: 1221,
|
|
// XK_kana_NA
|
|
12491: 1222,
|
|
// XK_kana_NI
|
|
12492: 1223,
|
|
// XK_kana_NU
|
|
12493: 1224,
|
|
// XK_kana_NE
|
|
12494: 1225,
|
|
// XK_kana_NO
|
|
12495: 1226,
|
|
// XK_kana_HA
|
|
12498: 1227,
|
|
// XK_kana_HI
|
|
12501: 1228,
|
|
// XK_kana_FU
|
|
12504: 1229,
|
|
// XK_kana_HE
|
|
12507: 1230,
|
|
// XK_kana_HO
|
|
12510: 1231,
|
|
// XK_kana_MA
|
|
12511: 1232,
|
|
// XK_kana_MI
|
|
12512: 1233,
|
|
// XK_kana_MU
|
|
12513: 1234,
|
|
// XK_kana_ME
|
|
12514: 1235,
|
|
// XK_kana_MO
|
|
12515: 1196,
|
|
// XK_kana_ya
|
|
12516: 1236,
|
|
// XK_kana_YA
|
|
12517: 1197,
|
|
// XK_kana_yu
|
|
12518: 1237,
|
|
// XK_kana_YU
|
|
12519: 1198,
|
|
// XK_kana_yo
|
|
12520: 1238,
|
|
// XK_kana_YO
|
|
12521: 1239,
|
|
// XK_kana_RA
|
|
12522: 1240,
|
|
// XK_kana_RI
|
|
12523: 1241,
|
|
// XK_kana_RU
|
|
12524: 1242,
|
|
// XK_kana_RE
|
|
12525: 1243,
|
|
// XK_kana_RO
|
|
12527: 1244,
|
|
// XK_kana_WA
|
|
12530: 1190,
|
|
// XK_kana_WO
|
|
12531: 1245,
|
|
// XK_kana_N
|
|
12539: 1189,
|
|
// XK_kana_conjunctive
|
|
12540: 1200
|
|
// XK_prolongedsound
|
|
};
|
|
var keysymdef_default = {
|
|
lookup(u) {
|
|
if (u >= 32 && u <= 255) {
|
|
return u;
|
|
}
|
|
const keysym = codepoints[u];
|
|
if (keysym !== void 0) {
|
|
return keysym;
|
|
}
|
|
return 16777216 | u;
|
|
}
|
|
};
|
|
|
|
// core/input/vkeys.js
|
|
var vkeys_default = {
|
|
8: "Backspace",
|
|
9: "Tab",
|
|
10: "NumpadClear",
|
|
13: "Enter",
|
|
16: "ShiftLeft",
|
|
17: "ControlLeft",
|
|
18: "AltLeft",
|
|
19: "Pause",
|
|
20: "CapsLock",
|
|
21: "Lang1",
|
|
25: "Lang2",
|
|
27: "Escape",
|
|
28: "Convert",
|
|
29: "NonConvert",
|
|
32: "Space",
|
|
33: "PageUp",
|
|
34: "PageDown",
|
|
35: "End",
|
|
36: "Home",
|
|
37: "ArrowLeft",
|
|
38: "ArrowUp",
|
|
39: "ArrowRight",
|
|
40: "ArrowDown",
|
|
41: "Select",
|
|
44: "PrintScreen",
|
|
45: "Insert",
|
|
46: "Delete",
|
|
47: "Help",
|
|
48: "Digit0",
|
|
49: "Digit1",
|
|
50: "Digit2",
|
|
51: "Digit3",
|
|
52: "Digit4",
|
|
53: "Digit5",
|
|
54: "Digit6",
|
|
55: "Digit7",
|
|
56: "Digit8",
|
|
57: "Digit9",
|
|
91: "MetaLeft",
|
|
92: "MetaRight",
|
|
93: "ContextMenu",
|
|
95: "Sleep",
|
|
96: "Numpad0",
|
|
97: "Numpad1",
|
|
98: "Numpad2",
|
|
99: "Numpad3",
|
|
100: "Numpad4",
|
|
101: "Numpad5",
|
|
102: "Numpad6",
|
|
103: "Numpad7",
|
|
104: "Numpad8",
|
|
105: "Numpad9",
|
|
106: "NumpadMultiply",
|
|
107: "NumpadAdd",
|
|
108: "NumpadDecimal",
|
|
109: "NumpadSubtract",
|
|
110: "NumpadDecimal",
|
|
// Duplicate, because buggy on Windows
|
|
111: "NumpadDivide",
|
|
112: "F1",
|
|
113: "F2",
|
|
114: "F3",
|
|
115: "F4",
|
|
116: "F5",
|
|
117: "F6",
|
|
118: "F7",
|
|
119: "F8",
|
|
120: "F9",
|
|
121: "F10",
|
|
122: "F11",
|
|
123: "F12",
|
|
124: "F13",
|
|
125: "F14",
|
|
126: "F15",
|
|
127: "F16",
|
|
128: "F17",
|
|
129: "F18",
|
|
130: "F19",
|
|
131: "F20",
|
|
132: "F21",
|
|
133: "F22",
|
|
134: "F23",
|
|
135: "F24",
|
|
144: "NumLock",
|
|
145: "ScrollLock",
|
|
166: "BrowserBack",
|
|
167: "BrowserForward",
|
|
168: "BrowserRefresh",
|
|
169: "BrowserStop",
|
|
170: "BrowserSearch",
|
|
171: "BrowserFavorites",
|
|
172: "BrowserHome",
|
|
173: "AudioVolumeMute",
|
|
174: "AudioVolumeDown",
|
|
175: "AudioVolumeUp",
|
|
176: "MediaTrackNext",
|
|
177: "MediaTrackPrevious",
|
|
178: "MediaStop",
|
|
179: "MediaPlayPause",
|
|
180: "LaunchMail",
|
|
181: "MediaSelect",
|
|
182: "LaunchApp1",
|
|
183: "LaunchApp2",
|
|
225: "AltRight"
|
|
// Only when it is AltGraph
|
|
};
|
|
|
|
// core/input/fixedkeys.js
|
|
var fixedkeys_default = {
|
|
// 3.1.1.1. Writing System Keys
|
|
"Backspace": "Backspace",
|
|
// 3.1.1.2. Functional Keys
|
|
"AltLeft": "Alt",
|
|
"AltRight": "Alt",
|
|
// This could also be 'AltGraph'
|
|
"CapsLock": "CapsLock",
|
|
"ContextMenu": "ContextMenu",
|
|
"ControlLeft": "Control",
|
|
"ControlRight": "Control",
|
|
"Enter": "Enter",
|
|
"MetaLeft": "Meta",
|
|
"MetaRight": "Meta",
|
|
"ShiftLeft": "Shift",
|
|
"ShiftRight": "Shift",
|
|
"Tab": "Tab",
|
|
// FIXME: Japanese/Korean keys
|
|
// 3.1.2. Control Pad Section
|
|
"Delete": "Delete",
|
|
"End": "End",
|
|
"Help": "Help",
|
|
"Home": "Home",
|
|
"Insert": "Insert",
|
|
"PageDown": "PageDown",
|
|
"PageUp": "PageUp",
|
|
// 3.1.3. Arrow Pad Section
|
|
"ArrowDown": "ArrowDown",
|
|
"ArrowLeft": "ArrowLeft",
|
|
"ArrowRight": "ArrowRight",
|
|
"ArrowUp": "ArrowUp",
|
|
// 3.1.4. Numpad Section
|
|
"NumLock": "NumLock",
|
|
"NumpadBackspace": "Backspace",
|
|
"NumpadClear": "Clear",
|
|
// 3.1.5. Function Section
|
|
"Escape": "Escape",
|
|
"F1": "F1",
|
|
"F2": "F2",
|
|
"F3": "F3",
|
|
"F4": "F4",
|
|
"F5": "F5",
|
|
"F6": "F6",
|
|
"F7": "F7",
|
|
"F8": "F8",
|
|
"F9": "F9",
|
|
"F10": "F10",
|
|
"F11": "F11",
|
|
"F12": "F12",
|
|
"F13": "F13",
|
|
"F14": "F14",
|
|
"F15": "F15",
|
|
"F16": "F16",
|
|
"F17": "F17",
|
|
"F18": "F18",
|
|
"F19": "F19",
|
|
"F20": "F20",
|
|
"F21": "F21",
|
|
"F22": "F22",
|
|
"F23": "F23",
|
|
"F24": "F24",
|
|
"F25": "F25",
|
|
"F26": "F26",
|
|
"F27": "F27",
|
|
"F28": "F28",
|
|
"F29": "F29",
|
|
"F30": "F30",
|
|
"F31": "F31",
|
|
"F32": "F32",
|
|
"F33": "F33",
|
|
"F34": "F34",
|
|
"F35": "F35",
|
|
"PrintScreen": "PrintScreen",
|
|
"ScrollLock": "ScrollLock",
|
|
"Pause": "Pause",
|
|
// 3.1.6. Media Keys
|
|
"BrowserBack": "BrowserBack",
|
|
"BrowserFavorites": "BrowserFavorites",
|
|
"BrowserForward": "BrowserForward",
|
|
"BrowserHome": "BrowserHome",
|
|
"BrowserRefresh": "BrowserRefresh",
|
|
"BrowserSearch": "BrowserSearch",
|
|
"BrowserStop": "BrowserStop",
|
|
"Eject": "Eject",
|
|
"LaunchApp1": "LaunchMyComputer",
|
|
"LaunchApp2": "LaunchCalendar",
|
|
"LaunchMail": "LaunchMail",
|
|
"MediaPlayPause": "MediaPlay",
|
|
"MediaStop": "MediaStop",
|
|
"MediaTrackNext": "MediaTrackNext",
|
|
"MediaTrackPrevious": "MediaTrackPrevious",
|
|
"Power": "Power",
|
|
"Sleep": "Sleep",
|
|
"AudioVolumeDown": "AudioVolumeDown",
|
|
"AudioVolumeMute": "AudioVolumeMute",
|
|
"AudioVolumeUp": "AudioVolumeUp",
|
|
"WakeUp": "WakeUp"
|
|
};
|
|
|
|
// core/input/domkeytable.js
|
|
var DOMKeyTable = {};
|
|
function addStandard(key, standard) {
|
|
if (standard === void 0) throw new Error('Undefined keysym for key "' + key + '"');
|
|
if (key in DOMKeyTable) throw new Error('Duplicate entry for key "' + key + '"');
|
|
DOMKeyTable[key] = [standard, standard, standard, standard];
|
|
}
|
|
function addLeftRight(key, left, right) {
|
|
if (left === void 0) throw new Error('Undefined keysym for key "' + key + '"');
|
|
if (right === void 0) throw new Error('Undefined keysym for key "' + key + '"');
|
|
if (key in DOMKeyTable) throw new Error('Duplicate entry for key "' + key + '"');
|
|
DOMKeyTable[key] = [left, left, right, left];
|
|
}
|
|
function addNumpad(key, standard, numpad) {
|
|
if (standard === void 0) throw new Error('Undefined keysym for key "' + key + '"');
|
|
if (numpad === void 0) throw new Error('Undefined keysym for key "' + key + '"');
|
|
if (key in DOMKeyTable) throw new Error('Duplicate entry for key "' + key + '"');
|
|
DOMKeyTable[key] = [standard, standard, standard, numpad];
|
|
}
|
|
addLeftRight("Alt", keysym_default.XK_Alt_L, keysym_default.XK_Alt_R);
|
|
addStandard("AltGraph", keysym_default.XK_ISO_Level3_Shift);
|
|
addStandard("CapsLock", keysym_default.XK_Caps_Lock);
|
|
addLeftRight("Control", keysym_default.XK_Control_L, keysym_default.XK_Control_R);
|
|
addLeftRight("Meta", keysym_default.XK_Super_L, keysym_default.XK_Super_R);
|
|
addStandard("NumLock", keysym_default.XK_Num_Lock);
|
|
addStandard("ScrollLock", keysym_default.XK_Scroll_Lock);
|
|
addLeftRight("Shift", keysym_default.XK_Shift_L, keysym_default.XK_Shift_R);
|
|
addNumpad("Enter", keysym_default.XK_Return, keysym_default.XK_KP_Enter);
|
|
addStandard("Tab", keysym_default.XK_Tab);
|
|
addNumpad(" ", keysym_default.XK_space, keysym_default.XK_KP_Space);
|
|
addNumpad("ArrowDown", keysym_default.XK_Down, keysym_default.XK_KP_Down);
|
|
addNumpad("ArrowLeft", keysym_default.XK_Left, keysym_default.XK_KP_Left);
|
|
addNumpad("ArrowRight", keysym_default.XK_Right, keysym_default.XK_KP_Right);
|
|
addNumpad("ArrowUp", keysym_default.XK_Up, keysym_default.XK_KP_Up);
|
|
addNumpad("End", keysym_default.XK_End, keysym_default.XK_KP_End);
|
|
addNumpad("Home", keysym_default.XK_Home, keysym_default.XK_KP_Home);
|
|
addNumpad("PageDown", keysym_default.XK_Next, keysym_default.XK_KP_Next);
|
|
addNumpad("PageUp", keysym_default.XK_Prior, keysym_default.XK_KP_Prior);
|
|
addStandard("Backspace", keysym_default.XK_BackSpace);
|
|
addNumpad("Clear", keysym_default.XK_Clear, keysym_default.XK_KP_Begin);
|
|
addStandard("Copy", keysym_default.XF86XK_Copy);
|
|
addStandard("Cut", keysym_default.XF86XK_Cut);
|
|
addNumpad("Delete", keysym_default.XK_Delete, keysym_default.XK_KP_Delete);
|
|
addNumpad("Insert", keysym_default.XK_Insert, keysym_default.XK_KP_Insert);
|
|
addStandard("Paste", keysym_default.XF86XK_Paste);
|
|
addStandard("Redo", keysym_default.XK_Redo);
|
|
addStandard("Undo", keysym_default.XK_Undo);
|
|
addStandard("Cancel", keysym_default.XK_Cancel);
|
|
addStandard("ContextMenu", keysym_default.XK_Menu);
|
|
addStandard("Escape", keysym_default.XK_Escape);
|
|
addStandard("Execute", keysym_default.XK_Execute);
|
|
addStandard("Find", keysym_default.XK_Find);
|
|
addStandard("Help", keysym_default.XK_Help);
|
|
addStandard("Pause", keysym_default.XK_Pause);
|
|
addStandard("Select", keysym_default.XK_Select);
|
|
addStandard("ZoomIn", keysym_default.XF86XK_ZoomIn);
|
|
addStandard("ZoomOut", keysym_default.XF86XK_ZoomOut);
|
|
addStandard("BrightnessDown", keysym_default.XF86XK_MonBrightnessDown);
|
|
addStandard("BrightnessUp", keysym_default.XF86XK_MonBrightnessUp);
|
|
addStandard("Eject", keysym_default.XF86XK_Eject);
|
|
addStandard("LogOff", keysym_default.XF86XK_LogOff);
|
|
addStandard("Power", keysym_default.XF86XK_PowerOff);
|
|
addStandard("PowerOff", keysym_default.XF86XK_PowerDown);
|
|
addStandard("PrintScreen", keysym_default.XK_Print);
|
|
addStandard("Hibernate", keysym_default.XF86XK_Hibernate);
|
|
addStandard("Standby", keysym_default.XF86XK_Standby);
|
|
addStandard("WakeUp", keysym_default.XF86XK_WakeUp);
|
|
addStandard("AllCandidates", keysym_default.XK_MultipleCandidate);
|
|
addStandard("Alphanumeric", keysym_default.XK_Eisu_toggle);
|
|
addStandard("CodeInput", keysym_default.XK_Codeinput);
|
|
addStandard("Compose", keysym_default.XK_Multi_key);
|
|
addStandard("Convert", keysym_default.XK_Henkan);
|
|
addStandard("GroupFirst", keysym_default.XK_ISO_First_Group);
|
|
addStandard("GroupLast", keysym_default.XK_ISO_Last_Group);
|
|
addStandard("GroupNext", keysym_default.XK_ISO_Next_Group);
|
|
addStandard("GroupPrevious", keysym_default.XK_ISO_Prev_Group);
|
|
addStandard("NonConvert", keysym_default.XK_Muhenkan);
|
|
addStandard("PreviousCandidate", keysym_default.XK_PreviousCandidate);
|
|
addStandard("SingleCandidate", keysym_default.XK_SingleCandidate);
|
|
addStandard("HangulMode", keysym_default.XK_Hangul);
|
|
addStandard("HanjaMode", keysym_default.XK_Hangul_Hanja);
|
|
addStandard("JunjaMode", keysym_default.XK_Hangul_Jeonja);
|
|
addStandard("Eisu", keysym_default.XK_Eisu_toggle);
|
|
addStandard("Hankaku", keysym_default.XK_Hankaku);
|
|
addStandard("Hiragana", keysym_default.XK_Hiragana);
|
|
addStandard("HiraganaKatakana", keysym_default.XK_Hiragana_Katakana);
|
|
addStandard("KanaMode", keysym_default.XK_Kana_Shift);
|
|
addStandard("KanjiMode", keysym_default.XK_Kanji);
|
|
addStandard("Katakana", keysym_default.XK_Katakana);
|
|
addStandard("Romaji", keysym_default.XK_Romaji);
|
|
addStandard("Zenkaku", keysym_default.XK_Zenkaku);
|
|
addStandard("ZenkakuHankaku", keysym_default.XK_Zenkaku_Hankaku);
|
|
addStandard("F1", keysym_default.XK_F1);
|
|
addStandard("F2", keysym_default.XK_F2);
|
|
addStandard("F3", keysym_default.XK_F3);
|
|
addStandard("F4", keysym_default.XK_F4);
|
|
addStandard("F5", keysym_default.XK_F5);
|
|
addStandard("F6", keysym_default.XK_F6);
|
|
addStandard("F7", keysym_default.XK_F7);
|
|
addStandard("F8", keysym_default.XK_F8);
|
|
addStandard("F9", keysym_default.XK_F9);
|
|
addStandard("F10", keysym_default.XK_F10);
|
|
addStandard("F11", keysym_default.XK_F11);
|
|
addStandard("F12", keysym_default.XK_F12);
|
|
addStandard("F13", keysym_default.XK_F13);
|
|
addStandard("F14", keysym_default.XK_F14);
|
|
addStandard("F15", keysym_default.XK_F15);
|
|
addStandard("F16", keysym_default.XK_F16);
|
|
addStandard("F17", keysym_default.XK_F17);
|
|
addStandard("F18", keysym_default.XK_F18);
|
|
addStandard("F19", keysym_default.XK_F19);
|
|
addStandard("F20", keysym_default.XK_F20);
|
|
addStandard("F21", keysym_default.XK_F21);
|
|
addStandard("F22", keysym_default.XK_F22);
|
|
addStandard("F23", keysym_default.XK_F23);
|
|
addStandard("F24", keysym_default.XK_F24);
|
|
addStandard("F25", keysym_default.XK_F25);
|
|
addStandard("F26", keysym_default.XK_F26);
|
|
addStandard("F27", keysym_default.XK_F27);
|
|
addStandard("F28", keysym_default.XK_F28);
|
|
addStandard("F29", keysym_default.XK_F29);
|
|
addStandard("F30", keysym_default.XK_F30);
|
|
addStandard("F31", keysym_default.XK_F31);
|
|
addStandard("F32", keysym_default.XK_F32);
|
|
addStandard("F33", keysym_default.XK_F33);
|
|
addStandard("F34", keysym_default.XK_F34);
|
|
addStandard("F35", keysym_default.XK_F35);
|
|
addStandard("Close", keysym_default.XF86XK_Close);
|
|
addStandard("MailForward", keysym_default.XF86XK_MailForward);
|
|
addStandard("MailReply", keysym_default.XF86XK_Reply);
|
|
addStandard("MailSend", keysym_default.XF86XK_Send);
|
|
addStandard("MediaFastForward", keysym_default.XF86XK_AudioForward);
|
|
addStandard("MediaPause", keysym_default.XF86XK_AudioPause);
|
|
addStandard("MediaPlay", keysym_default.XF86XK_AudioPlay);
|
|
addStandard("MediaRecord", keysym_default.XF86XK_AudioRecord);
|
|
addStandard("MediaRewind", keysym_default.XF86XK_AudioRewind);
|
|
addStandard("MediaStop", keysym_default.XF86XK_AudioStop);
|
|
addStandard("MediaTrackNext", keysym_default.XF86XK_AudioNext);
|
|
addStandard("MediaTrackPrevious", keysym_default.XF86XK_AudioPrev);
|
|
addStandard("New", keysym_default.XF86XK_New);
|
|
addStandard("Open", keysym_default.XF86XK_Open);
|
|
addStandard("Print", keysym_default.XK_Print);
|
|
addStandard("Save", keysym_default.XF86XK_Save);
|
|
addStandard("SpellCheck", keysym_default.XF86XK_Spell);
|
|
addStandard("AudioVolumeDown", keysym_default.XF86XK_AudioLowerVolume);
|
|
addStandard("AudioVolumeUp", keysym_default.XF86XK_AudioRaiseVolume);
|
|
addStandard("AudioVolumeMute", keysym_default.XF86XK_AudioMute);
|
|
addStandard("MicrophoneVolumeMute", keysym_default.XF86XK_AudioMicMute);
|
|
addStandard("LaunchApplication1", keysym_default.XF86XK_MyComputer);
|
|
addStandard("LaunchApplication2", keysym_default.XF86XK_Calculator);
|
|
addStandard("LaunchCalendar", keysym_default.XF86XK_Calendar);
|
|
addStandard("LaunchMail", keysym_default.XF86XK_Mail);
|
|
addStandard("LaunchMediaPlayer", keysym_default.XF86XK_AudioMedia);
|
|
addStandard("LaunchMusicPlayer", keysym_default.XF86XK_Music);
|
|
addStandard("LaunchPhone", keysym_default.XF86XK_Phone);
|
|
addStandard("LaunchScreenSaver", keysym_default.XF86XK_ScreenSaver);
|
|
addStandard("LaunchSpreadsheet", keysym_default.XF86XK_Excel);
|
|
addStandard("LaunchWebBrowser", keysym_default.XF86XK_WWW);
|
|
addStandard("LaunchWebCam", keysym_default.XF86XK_WebCam);
|
|
addStandard("LaunchWordProcessor", keysym_default.XF86XK_Word);
|
|
addStandard("BrowserBack", keysym_default.XF86XK_Back);
|
|
addStandard("BrowserFavorites", keysym_default.XF86XK_Favorites);
|
|
addStandard("BrowserForward", keysym_default.XF86XK_Forward);
|
|
addStandard("BrowserHome", keysym_default.XF86XK_HomePage);
|
|
addStandard("BrowserRefresh", keysym_default.XF86XK_Refresh);
|
|
addStandard("BrowserSearch", keysym_default.XF86XK_Search);
|
|
addStandard("BrowserStop", keysym_default.XF86XK_Stop);
|
|
addStandard("Dimmer", keysym_default.XF86XK_BrightnessAdjust);
|
|
addStandard("MediaAudioTrack", keysym_default.XF86XK_AudioCycleTrack);
|
|
addStandard("RandomToggle", keysym_default.XF86XK_AudioRandomPlay);
|
|
addStandard("SplitScreenToggle", keysym_default.XF86XK_SplitScreen);
|
|
addStandard("Subtitle", keysym_default.XF86XK_Subtitle);
|
|
addStandard("VideoModeNext", keysym_default.XF86XK_Next_VMode);
|
|
addNumpad("=", keysym_default.XK_equal, keysym_default.XK_KP_Equal);
|
|
addNumpad("+", keysym_default.XK_plus, keysym_default.XK_KP_Add);
|
|
addNumpad("-", keysym_default.XK_minus, keysym_default.XK_KP_Subtract);
|
|
addNumpad("*", keysym_default.XK_asterisk, keysym_default.XK_KP_Multiply);
|
|
addNumpad("/", keysym_default.XK_slash, keysym_default.XK_KP_Divide);
|
|
addNumpad(".", keysym_default.XK_period, keysym_default.XK_KP_Decimal);
|
|
addNumpad(",", keysym_default.XK_comma, keysym_default.XK_KP_Separator);
|
|
addNumpad("0", keysym_default.XK_0, keysym_default.XK_KP_0);
|
|
addNumpad("1", keysym_default.XK_1, keysym_default.XK_KP_1);
|
|
addNumpad("2", keysym_default.XK_2, keysym_default.XK_KP_2);
|
|
addNumpad("3", keysym_default.XK_3, keysym_default.XK_KP_3);
|
|
addNumpad("4", keysym_default.XK_4, keysym_default.XK_KP_4);
|
|
addNumpad("5", keysym_default.XK_5, keysym_default.XK_KP_5);
|
|
addNumpad("6", keysym_default.XK_6, keysym_default.XK_KP_6);
|
|
addNumpad("7", keysym_default.XK_7, keysym_default.XK_KP_7);
|
|
addNumpad("8", keysym_default.XK_8, keysym_default.XK_KP_8);
|
|
addNumpad("9", keysym_default.XK_9, keysym_default.XK_KP_9);
|
|
var domkeytable_default = DOMKeyTable;
|
|
|
|
// core/input/util.js
|
|
function getKeycode(evt) {
|
|
if (evt.code) {
|
|
switch (evt.code) {
|
|
case "OSLeft":
|
|
return "MetaLeft";
|
|
case "OSRight":
|
|
return "MetaRight";
|
|
}
|
|
return evt.code;
|
|
}
|
|
if (evt.keyCode in vkeys_default) {
|
|
let code = vkeys_default[evt.keyCode];
|
|
if (isMac() && code === "ContextMenu") {
|
|
code = "MetaRight";
|
|
}
|
|
if (evt.location === 2) {
|
|
switch (code) {
|
|
case "ShiftLeft":
|
|
return "ShiftRight";
|
|
case "ControlLeft":
|
|
return "ControlRight";
|
|
case "AltLeft":
|
|
return "AltRight";
|
|
}
|
|
}
|
|
if (evt.location === 3) {
|
|
switch (code) {
|
|
case "Delete":
|
|
return "NumpadDecimal";
|
|
case "Insert":
|
|
return "Numpad0";
|
|
case "End":
|
|
return "Numpad1";
|
|
case "ArrowDown":
|
|
return "Numpad2";
|
|
case "PageDown":
|
|
return "Numpad3";
|
|
case "ArrowLeft":
|
|
return "Numpad4";
|
|
case "ArrowRight":
|
|
return "Numpad6";
|
|
case "Home":
|
|
return "Numpad7";
|
|
case "ArrowUp":
|
|
return "Numpad8";
|
|
case "PageUp":
|
|
return "Numpad9";
|
|
case "Enter":
|
|
return "NumpadEnter";
|
|
}
|
|
}
|
|
return code;
|
|
}
|
|
return "Unidentified";
|
|
}
|
|
function getKey(evt) {
|
|
if (evt.key !== void 0 && evt.key !== "Unidentified") {
|
|
switch (evt.key) {
|
|
case "OS":
|
|
return "Meta";
|
|
case "LaunchMyComputer":
|
|
return "LaunchApplication1";
|
|
case "LaunchCalculator":
|
|
return "LaunchApplication2";
|
|
}
|
|
switch (evt.key) {
|
|
case "UIKeyInputUpArrow":
|
|
return "ArrowUp";
|
|
case "UIKeyInputDownArrow":
|
|
return "ArrowDown";
|
|
case "UIKeyInputLeftArrow":
|
|
return "ArrowLeft";
|
|
case "UIKeyInputRightArrow":
|
|
return "ArrowRight";
|
|
case "UIKeyInputEscape":
|
|
return "Escape";
|
|
}
|
|
if (evt.key === "\0" && evt.code === "NumpadDecimal") {
|
|
return "Delete";
|
|
}
|
|
return evt.key;
|
|
}
|
|
const code = getKeycode(evt);
|
|
if (code in fixedkeys_default) {
|
|
return fixedkeys_default[code];
|
|
}
|
|
if (evt.charCode) {
|
|
return String.fromCharCode(evt.charCode);
|
|
}
|
|
return "Unidentified";
|
|
}
|
|
function getKeysym(evt) {
|
|
const key = getKey(evt);
|
|
if (key === "Unidentified") {
|
|
return null;
|
|
}
|
|
if (key in domkeytable_default) {
|
|
let location = evt.location;
|
|
if (key === "Meta" && location === 0) {
|
|
location = 2;
|
|
}
|
|
if (key === "Clear" && location === 3) {
|
|
let code = getKeycode(evt);
|
|
if (code === "NumLock") {
|
|
location = 0;
|
|
}
|
|
}
|
|
if (location === void 0 || location > 3) {
|
|
location = 0;
|
|
}
|
|
if (key === "Meta") {
|
|
let code = getKeycode(evt);
|
|
if (code === "AltLeft") {
|
|
return keysym_default.XK_Meta_L;
|
|
} else if (code === "AltRight") {
|
|
return keysym_default.XK_Meta_R;
|
|
}
|
|
}
|
|
if (key === "Clear") {
|
|
let code = getKeycode(evt);
|
|
if (code === "NumLock") {
|
|
return keysym_default.XK_Num_Lock;
|
|
}
|
|
}
|
|
if (isWindows()) {
|
|
switch (key) {
|
|
case "Zenkaku":
|
|
case "Hankaku":
|
|
return keysym_default.XK_Zenkaku_Hankaku;
|
|
case "Romaji":
|
|
case "KanaMode":
|
|
return keysym_default.XK_Romaji;
|
|
}
|
|
}
|
|
return domkeytable_default[key][location];
|
|
}
|
|
if (key.length !== 1) {
|
|
return null;
|
|
}
|
|
const codepoint = key.charCodeAt();
|
|
if (codepoint) {
|
|
return keysymdef_default.lookup(codepoint);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
// core/input/keyboard.js
|
|
var Keyboard = class {
|
|
constructor(target) {
|
|
this._target = target || null;
|
|
this._keyDownList = {};
|
|
this._altGrArmed = false;
|
|
this._eventHandlers = {
|
|
"keyup": this._handleKeyUp.bind(this),
|
|
"keydown": this._handleKeyDown.bind(this),
|
|
"blur": this._allKeysUp.bind(this)
|
|
};
|
|
this.onkeyevent = () => {
|
|
};
|
|
}
|
|
// ===== PRIVATE METHODS =====
|
|
_sendKeyEvent(keysym, code, down, numlock = null, capslock = null) {
|
|
if (down) {
|
|
this._keyDownList[code] = keysym;
|
|
} else {
|
|
if (!(code in this._keyDownList)) {
|
|
return;
|
|
}
|
|
delete this._keyDownList[code];
|
|
}
|
|
Debug("onkeyevent " + (down ? "down" : "up") + ", keysym: " + keysym, ", code: " + code + ", numlock: " + numlock + ", capslock: " + capslock);
|
|
this.onkeyevent(keysym, code, down, numlock, capslock);
|
|
}
|
|
_getKeyCode(e2) {
|
|
const code = getKeycode(e2);
|
|
if (code !== "Unidentified") {
|
|
return code;
|
|
}
|
|
if (e2.keyCode) {
|
|
if (e2.keyCode !== 229) {
|
|
return "Platform" + e2.keyCode;
|
|
}
|
|
}
|
|
if (e2.keyIdentifier) {
|
|
if (e2.keyIdentifier.substr(0, 2) !== "U+") {
|
|
return e2.keyIdentifier;
|
|
}
|
|
const codepoint = parseInt(e2.keyIdentifier.substr(2), 16);
|
|
const char = String.fromCharCode(codepoint).toUpperCase();
|
|
return "Platform" + char.charCodeAt();
|
|
}
|
|
return "Unidentified";
|
|
}
|
|
_handleKeyDown(e2) {
|
|
const code = this._getKeyCode(e2);
|
|
let keysym = getKeysym(e2);
|
|
let numlock = e2.getModifierState("NumLock");
|
|
let capslock = e2.getModifierState("CapsLock");
|
|
if (isMac() || isIOS()) {
|
|
numlock = null;
|
|
}
|
|
if (this._altGrArmed) {
|
|
this._altGrArmed = false;
|
|
clearTimeout(this._altGrTimeout);
|
|
if (code === "AltRight" && e2.timeStamp - this._altGrCtrlTime < 50) {
|
|
keysym = keysym_default.XK_ISO_Level3_Shift;
|
|
} else {
|
|
this._sendKeyEvent(keysym_default.XK_Control_L, "ControlLeft", true, numlock, capslock);
|
|
}
|
|
}
|
|
if (code === "Unidentified") {
|
|
if (keysym) {
|
|
this._sendKeyEvent(keysym, code, true, numlock, capslock);
|
|
this._sendKeyEvent(keysym, code, false, numlock, capslock);
|
|
}
|
|
stopEvent(e2);
|
|
return;
|
|
}
|
|
if (isMac() || isIOS()) {
|
|
switch (keysym) {
|
|
case keysym_default.XK_Super_L:
|
|
keysym = keysym_default.XK_Alt_L;
|
|
break;
|
|
case keysym_default.XK_Super_R:
|
|
keysym = keysym_default.XK_Super_L;
|
|
break;
|
|
case keysym_default.XK_Alt_L:
|
|
keysym = keysym_default.XK_Mode_switch;
|
|
break;
|
|
case keysym_default.XK_Alt_R:
|
|
keysym = keysym_default.XK_ISO_Level3_Shift;
|
|
break;
|
|
}
|
|
}
|
|
if (code in this._keyDownList) {
|
|
keysym = this._keyDownList[code];
|
|
}
|
|
if ((isMac() || isIOS()) && (e2.metaKey && code !== "MetaLeft" && code !== "MetaRight")) {
|
|
this._sendKeyEvent(keysym, code, true, numlock, capslock);
|
|
this._sendKeyEvent(keysym, code, false, numlock, capslock);
|
|
stopEvent(e2);
|
|
return;
|
|
}
|
|
if ((isMac() || isIOS()) && code === "CapsLock") {
|
|
this._sendKeyEvent(keysym_default.XK_Caps_Lock, "CapsLock", true, numlock, capslock);
|
|
this._sendKeyEvent(keysym_default.XK_Caps_Lock, "CapsLock", false, numlock, capslock);
|
|
stopEvent(e2);
|
|
return;
|
|
}
|
|
const jpBadKeys = [
|
|
keysym_default.XK_Zenkaku_Hankaku,
|
|
keysym_default.XK_Eisu_toggle,
|
|
keysym_default.XK_Katakana,
|
|
keysym_default.XK_Hiragana,
|
|
keysym_default.XK_Romaji
|
|
];
|
|
if (isWindows() && jpBadKeys.includes(keysym)) {
|
|
this._sendKeyEvent(keysym, code, true, numlock, capslock);
|
|
this._sendKeyEvent(keysym, code, false, numlock, capslock);
|
|
stopEvent(e2);
|
|
return;
|
|
}
|
|
stopEvent(e2);
|
|
if (code === "ControlLeft" && isWindows() && !("ControlLeft" in this._keyDownList)) {
|
|
this._altGrArmed = true;
|
|
this._altGrTimeout = setTimeout(this._interruptAltGrSequence.bind(this), 100);
|
|
this._altGrCtrlTime = e2.timeStamp;
|
|
return;
|
|
}
|
|
this._sendKeyEvent(keysym, code, true, numlock, capslock);
|
|
}
|
|
_handleKeyUp(e2) {
|
|
stopEvent(e2);
|
|
const code = this._getKeyCode(e2);
|
|
this._interruptAltGrSequence();
|
|
if ((isMac() || isIOS()) && code === "CapsLock") {
|
|
this._sendKeyEvent(keysym_default.XK_Caps_Lock, "CapsLock", true);
|
|
this._sendKeyEvent(keysym_default.XK_Caps_Lock, "CapsLock", false);
|
|
return;
|
|
}
|
|
this._sendKeyEvent(this._keyDownList[code], code, false);
|
|
if (isWindows() && (code === "ShiftLeft" || code === "ShiftRight")) {
|
|
if ("ShiftRight" in this._keyDownList) {
|
|
this._sendKeyEvent(
|
|
this._keyDownList["ShiftRight"],
|
|
"ShiftRight",
|
|
false
|
|
);
|
|
}
|
|
if ("ShiftLeft" in this._keyDownList) {
|
|
this._sendKeyEvent(
|
|
this._keyDownList["ShiftLeft"],
|
|
"ShiftLeft",
|
|
false
|
|
);
|
|
}
|
|
}
|
|
}
|
|
_interruptAltGrSequence() {
|
|
if (this._altGrArmed) {
|
|
this._altGrArmed = false;
|
|
clearTimeout(this._altGrTimeout);
|
|
this._sendKeyEvent(keysym_default.XK_Control_L, "ControlLeft", true);
|
|
}
|
|
}
|
|
_allKeysUp() {
|
|
Debug(">> Keyboard.allKeysUp");
|
|
this._interruptAltGrSequence();
|
|
for (let code in this._keyDownList) {
|
|
this._sendKeyEvent(this._keyDownList[code], code, false);
|
|
}
|
|
Debug("<< Keyboard.allKeysUp");
|
|
}
|
|
// ===== PUBLIC METHODS =====
|
|
grab() {
|
|
this._target.addEventListener("keydown", this._eventHandlers.keydown);
|
|
this._target.addEventListener("keyup", this._eventHandlers.keyup);
|
|
window.addEventListener("blur", this._eventHandlers.blur);
|
|
}
|
|
ungrab() {
|
|
this._target.removeEventListener("keydown", this._eventHandlers.keydown);
|
|
this._target.removeEventListener("keyup", this._eventHandlers.keyup);
|
|
window.removeEventListener("blur", this._eventHandlers.blur);
|
|
this._allKeysUp();
|
|
}
|
|
};
|
|
|
|
// core/input/gesturehandler.js
|
|
var GH_NOGESTURE = 0;
|
|
var GH_ONETAP = 1;
|
|
var GH_TWOTAP = 2;
|
|
var GH_THREETAP = 4;
|
|
var GH_DRAG = 8;
|
|
var GH_LONGPRESS = 16;
|
|
var GH_TWODRAG = 32;
|
|
var GH_PINCH = 64;
|
|
var GH_INITSTATE = 127;
|
|
var GH_MOVE_THRESHOLD = 50;
|
|
var GH_ANGLE_THRESHOLD = 90;
|
|
var GH_MULTITOUCH_TIMEOUT = 250;
|
|
var GH_TAP_TIMEOUT = 1e3;
|
|
var GH_LONGPRESS_TIMEOUT = 1e3;
|
|
var GH_TWOTOUCH_TIMEOUT = 50;
|
|
var GestureHandler = class {
|
|
constructor() {
|
|
this._target = null;
|
|
this._state = GH_INITSTATE;
|
|
this._tracked = [];
|
|
this._ignored = [];
|
|
this._waitingRelease = false;
|
|
this._releaseStart = 0;
|
|
this._longpressTimeoutId = null;
|
|
this._twoTouchTimeoutId = null;
|
|
this._boundEventHandler = this._eventHandler.bind(this);
|
|
}
|
|
attach(target) {
|
|
this.detach();
|
|
this._target = target;
|
|
this._target.addEventListener(
|
|
"touchstart",
|
|
this._boundEventHandler
|
|
);
|
|
this._target.addEventListener(
|
|
"touchmove",
|
|
this._boundEventHandler
|
|
);
|
|
this._target.addEventListener(
|
|
"touchend",
|
|
this._boundEventHandler
|
|
);
|
|
this._target.addEventListener(
|
|
"touchcancel",
|
|
this._boundEventHandler
|
|
);
|
|
}
|
|
detach() {
|
|
if (!this._target) {
|
|
return;
|
|
}
|
|
this._stopLongpressTimeout();
|
|
this._stopTwoTouchTimeout();
|
|
this._target.removeEventListener(
|
|
"touchstart",
|
|
this._boundEventHandler
|
|
);
|
|
this._target.removeEventListener(
|
|
"touchmove",
|
|
this._boundEventHandler
|
|
);
|
|
this._target.removeEventListener(
|
|
"touchend",
|
|
this._boundEventHandler
|
|
);
|
|
this._target.removeEventListener(
|
|
"touchcancel",
|
|
this._boundEventHandler
|
|
);
|
|
this._target = null;
|
|
}
|
|
_eventHandler(e2) {
|
|
let fn;
|
|
e2.stopPropagation();
|
|
e2.preventDefault();
|
|
switch (e2.type) {
|
|
case "touchstart":
|
|
fn = this._touchStart;
|
|
break;
|
|
case "touchmove":
|
|
fn = this._touchMove;
|
|
break;
|
|
case "touchend":
|
|
case "touchcancel":
|
|
fn = this._touchEnd;
|
|
break;
|
|
}
|
|
for (let i = 0; i < e2.changedTouches.length; i++) {
|
|
let touch = e2.changedTouches[i];
|
|
fn.call(this, touch.identifier, touch.clientX, touch.clientY);
|
|
}
|
|
}
|
|
_touchStart(id, x, y) {
|
|
if (this._hasDetectedGesture() || this._state === GH_NOGESTURE) {
|
|
this._ignored.push(id);
|
|
return;
|
|
}
|
|
if (this._tracked.length > 0 && Date.now() - this._tracked[0].started > GH_MULTITOUCH_TIMEOUT) {
|
|
this._state = GH_NOGESTURE;
|
|
this._ignored.push(id);
|
|
return;
|
|
}
|
|
if (this._waitingRelease) {
|
|
this._state = GH_NOGESTURE;
|
|
this._ignored.push(id);
|
|
return;
|
|
}
|
|
this._tracked.push({
|
|
id,
|
|
started: Date.now(),
|
|
active: true,
|
|
firstX: x,
|
|
firstY: y,
|
|
lastX: x,
|
|
lastY: y,
|
|
angle: 0
|
|
});
|
|
switch (this._tracked.length) {
|
|
case 1:
|
|
this._startLongpressTimeout();
|
|
break;
|
|
case 2:
|
|
this._state &= ~(GH_ONETAP | GH_DRAG | GH_LONGPRESS);
|
|
this._stopLongpressTimeout();
|
|
break;
|
|
case 3:
|
|
this._state &= ~(GH_TWOTAP | GH_TWODRAG | GH_PINCH);
|
|
break;
|
|
default:
|
|
this._state = GH_NOGESTURE;
|
|
}
|
|
}
|
|
_touchMove(id, x, y) {
|
|
let touch = this._tracked.find((t) => t.id === id);
|
|
if (touch === void 0) {
|
|
return;
|
|
}
|
|
touch.lastX = x;
|
|
touch.lastY = y;
|
|
let deltaX = x - touch.firstX;
|
|
let deltaY = y - touch.firstY;
|
|
if (touch.firstX !== touch.lastX || touch.firstY !== touch.lastY) {
|
|
touch.angle = Math.atan2(deltaY, deltaX) * 180 / Math.PI;
|
|
}
|
|
if (!this._hasDetectedGesture()) {
|
|
if (Math.hypot(deltaX, deltaY) < GH_MOVE_THRESHOLD) {
|
|
return;
|
|
}
|
|
this._state &= ~(GH_ONETAP | GH_TWOTAP | GH_THREETAP | GH_LONGPRESS);
|
|
this._stopLongpressTimeout();
|
|
if (this._tracked.length !== 1) {
|
|
this._state &= ~GH_DRAG;
|
|
}
|
|
if (this._tracked.length !== 2) {
|
|
this._state &= ~(GH_TWODRAG | GH_PINCH);
|
|
}
|
|
if (this._tracked.length === 2) {
|
|
let prevTouch = this._tracked.find((t) => t.id !== id);
|
|
let prevDeltaMove = Math.hypot(
|
|
prevTouch.firstX - prevTouch.lastX,
|
|
prevTouch.firstY - prevTouch.lastY
|
|
);
|
|
if (prevDeltaMove > GH_MOVE_THRESHOLD) {
|
|
let deltaAngle = Math.abs(touch.angle - prevTouch.angle);
|
|
deltaAngle = Math.abs((deltaAngle + 180) % 360 - 180);
|
|
if (deltaAngle > GH_ANGLE_THRESHOLD) {
|
|
this._state &= ~GH_TWODRAG;
|
|
} else {
|
|
this._state &= ~GH_PINCH;
|
|
}
|
|
if (this._isTwoTouchTimeoutRunning()) {
|
|
this._stopTwoTouchTimeout();
|
|
}
|
|
} else if (!this._isTwoTouchTimeoutRunning()) {
|
|
this._startTwoTouchTimeout();
|
|
}
|
|
}
|
|
if (!this._hasDetectedGesture()) {
|
|
return;
|
|
}
|
|
this._pushEvent("gesturestart");
|
|
}
|
|
this._pushEvent("gesturemove");
|
|
}
|
|
_touchEnd(id, x, y) {
|
|
if (this._ignored.indexOf(id) !== -1) {
|
|
this._ignored.splice(this._ignored.indexOf(id), 1);
|
|
if (this._ignored.length === 0 && this._tracked.length === 0) {
|
|
this._state = GH_INITSTATE;
|
|
this._waitingRelease = false;
|
|
}
|
|
return;
|
|
}
|
|
if (!this._hasDetectedGesture() && this._isTwoTouchTimeoutRunning()) {
|
|
this._stopTwoTouchTimeout();
|
|
this._state = GH_NOGESTURE;
|
|
}
|
|
if (!this._hasDetectedGesture()) {
|
|
this._state &= ~(GH_DRAG | GH_TWODRAG | GH_PINCH);
|
|
this._state &= ~GH_LONGPRESS;
|
|
this._stopLongpressTimeout();
|
|
if (!this._waitingRelease) {
|
|
this._releaseStart = Date.now();
|
|
this._waitingRelease = true;
|
|
switch (this._tracked.length) {
|
|
case 1:
|
|
this._state &= ~(GH_TWOTAP | GH_THREETAP);
|
|
break;
|
|
case 2:
|
|
this._state &= ~(GH_ONETAP | GH_THREETAP);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (this._waitingRelease) {
|
|
if (Date.now() - this._releaseStart > GH_MULTITOUCH_TIMEOUT) {
|
|
this._state = GH_NOGESTURE;
|
|
}
|
|
if (this._tracked.some((t) => Date.now() - t.started > GH_TAP_TIMEOUT)) {
|
|
this._state = GH_NOGESTURE;
|
|
}
|
|
let touch = this._tracked.find((t) => t.id === id);
|
|
touch.active = false;
|
|
if (this._hasDetectedGesture()) {
|
|
this._pushEvent("gesturestart");
|
|
} else {
|
|
if (this._state !== GH_NOGESTURE) {
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
if (this._hasDetectedGesture()) {
|
|
this._pushEvent("gestureend");
|
|
}
|
|
for (let i = 0; i < this._tracked.length; i++) {
|
|
if (this._tracked[i].active) {
|
|
this._ignored.push(this._tracked[i].id);
|
|
}
|
|
}
|
|
this._tracked = [];
|
|
this._state = GH_NOGESTURE;
|
|
if (this._ignored.indexOf(id) !== -1) {
|
|
this._ignored.splice(this._ignored.indexOf(id), 1);
|
|
}
|
|
if (this._ignored.length === 0) {
|
|
this._state = GH_INITSTATE;
|
|
this._waitingRelease = false;
|
|
}
|
|
}
|
|
_hasDetectedGesture() {
|
|
if (this._state === GH_NOGESTURE) {
|
|
return false;
|
|
}
|
|
if (this._state & this._state - 1) {
|
|
return false;
|
|
}
|
|
if (this._state & (GH_ONETAP | GH_TWOTAP | GH_THREETAP)) {
|
|
if (this._tracked.some((t) => t.active)) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
_startLongpressTimeout() {
|
|
this._stopLongpressTimeout();
|
|
this._longpressTimeoutId = setTimeout(
|
|
() => this._longpressTimeout(),
|
|
GH_LONGPRESS_TIMEOUT
|
|
);
|
|
}
|
|
_stopLongpressTimeout() {
|
|
clearTimeout(this._longpressTimeoutId);
|
|
this._longpressTimeoutId = null;
|
|
}
|
|
_longpressTimeout() {
|
|
if (this._hasDetectedGesture()) {
|
|
throw new Error("A longpress gesture failed, conflict with a different gesture");
|
|
}
|
|
this._state = GH_LONGPRESS;
|
|
this._pushEvent("gesturestart");
|
|
}
|
|
_startTwoTouchTimeout() {
|
|
this._stopTwoTouchTimeout();
|
|
this._twoTouchTimeoutId = setTimeout(
|
|
() => this._twoTouchTimeout(),
|
|
GH_TWOTOUCH_TIMEOUT
|
|
);
|
|
}
|
|
_stopTwoTouchTimeout() {
|
|
clearTimeout(this._twoTouchTimeoutId);
|
|
this._twoTouchTimeoutId = null;
|
|
}
|
|
_isTwoTouchTimeoutRunning() {
|
|
return this._twoTouchTimeoutId !== null;
|
|
}
|
|
_twoTouchTimeout() {
|
|
if (this._tracked.length === 0) {
|
|
throw new Error("A pinch or two drag gesture failed, no tracked touches");
|
|
}
|
|
let avgM = this._getAverageMovement();
|
|
let avgMoveH = Math.abs(avgM.x);
|
|
let avgMoveV = Math.abs(avgM.y);
|
|
let avgD = this._getAverageDistance();
|
|
let deltaTouchDistance = Math.abs(Math.hypot(avgD.first.x, avgD.first.y) - Math.hypot(avgD.last.x, avgD.last.y));
|
|
if (avgMoveV < deltaTouchDistance && avgMoveH < deltaTouchDistance) {
|
|
this._state = GH_PINCH;
|
|
} else {
|
|
this._state = GH_TWODRAG;
|
|
}
|
|
this._pushEvent("gesturestart");
|
|
this._pushEvent("gesturemove");
|
|
}
|
|
_pushEvent(type) {
|
|
let detail = { type: this._stateToGesture(this._state) };
|
|
let avg = this._getPosition();
|
|
let pos = avg.last;
|
|
if (type === "gesturestart") {
|
|
pos = avg.first;
|
|
}
|
|
switch (this._state) {
|
|
case GH_TWODRAG:
|
|
case GH_PINCH:
|
|
pos = avg.first;
|
|
break;
|
|
}
|
|
detail["clientX"] = pos.x;
|
|
detail["clientY"] = pos.y;
|
|
if (this._state === GH_PINCH) {
|
|
let distance = this._getAverageDistance();
|
|
if (type === "gesturestart") {
|
|
detail["magnitudeX"] = distance.first.x;
|
|
detail["magnitudeY"] = distance.first.y;
|
|
} else {
|
|
detail["magnitudeX"] = distance.last.x;
|
|
detail["magnitudeY"] = distance.last.y;
|
|
}
|
|
} else if (this._state === GH_TWODRAG) {
|
|
if (type === "gesturestart") {
|
|
detail["magnitudeX"] = 0;
|
|
detail["magnitudeY"] = 0;
|
|
} else {
|
|
let movement = this._getAverageMovement();
|
|
detail["magnitudeX"] = movement.x;
|
|
detail["magnitudeY"] = movement.y;
|
|
}
|
|
}
|
|
let gev = new CustomEvent(type, { detail });
|
|
this._target.dispatchEvent(gev);
|
|
}
|
|
_stateToGesture(state) {
|
|
switch (state) {
|
|
case GH_ONETAP:
|
|
return "onetap";
|
|
case GH_TWOTAP:
|
|
return "twotap";
|
|
case GH_THREETAP:
|
|
return "threetap";
|
|
case GH_DRAG:
|
|
return "drag";
|
|
case GH_LONGPRESS:
|
|
return "longpress";
|
|
case GH_TWODRAG:
|
|
return "twodrag";
|
|
case GH_PINCH:
|
|
return "pinch";
|
|
}
|
|
throw new Error("Unknown gesture state: " + state);
|
|
}
|
|
_getPosition() {
|
|
if (this._tracked.length === 0) {
|
|
throw new Error("Failed to get gesture position, no tracked touches");
|
|
}
|
|
let size = this._tracked.length;
|
|
let fx = 0, fy = 0, lx = 0, ly = 0;
|
|
for (let i = 0; i < this._tracked.length; i++) {
|
|
fx += this._tracked[i].firstX;
|
|
fy += this._tracked[i].firstY;
|
|
lx += this._tracked[i].lastX;
|
|
ly += this._tracked[i].lastY;
|
|
}
|
|
return {
|
|
first: {
|
|
x: fx / size,
|
|
y: fy / size
|
|
},
|
|
last: {
|
|
x: lx / size,
|
|
y: ly / size
|
|
}
|
|
};
|
|
}
|
|
_getAverageMovement() {
|
|
if (this._tracked.length === 0) {
|
|
throw new Error("Failed to get gesture movement, no tracked touches");
|
|
}
|
|
let totalH, totalV;
|
|
totalH = totalV = 0;
|
|
let size = this._tracked.length;
|
|
for (let i = 0; i < this._tracked.length; i++) {
|
|
totalH += this._tracked[i].lastX - this._tracked[i].firstX;
|
|
totalV += this._tracked[i].lastY - this._tracked[i].firstY;
|
|
}
|
|
return {
|
|
x: totalH / size,
|
|
y: totalV / size
|
|
};
|
|
}
|
|
_getAverageDistance() {
|
|
if (this._tracked.length === 0) {
|
|
throw new Error("Failed to get gesture distance, no tracked touches");
|
|
}
|
|
let first = this._tracked[0];
|
|
let last = this._tracked[this._tracked.length - 1];
|
|
let fdx = Math.abs(last.firstX - first.firstX);
|
|
let fdy = Math.abs(last.firstY - first.firstY);
|
|
let ldx = Math.abs(last.lastX - first.lastX);
|
|
let ldy = Math.abs(last.lastY - first.lastY);
|
|
return {
|
|
first: { x: fdx, y: fdy },
|
|
last: { x: ldx, y: ldy }
|
|
};
|
|
}
|
|
};
|
|
|
|
// core/util/cursor.js
|
|
var useFallback = !supportsCursorURIs || isTouchDevice;
|
|
var Cursor = class {
|
|
constructor() {
|
|
this._target = null;
|
|
this._canvas = document.createElement("canvas");
|
|
if (useFallback) {
|
|
this._canvas.style.position = "fixed";
|
|
this._canvas.style.zIndex = "65535";
|
|
this._canvas.style.pointerEvents = "none";
|
|
this._canvas.style.userSelect = "none";
|
|
this._canvas.style.WebkitUserSelect = "none";
|
|
this._canvas.style.visibility = "hidden";
|
|
}
|
|
this._position = { x: 0, y: 0 };
|
|
this._hotSpot = { x: 0, y: 0 };
|
|
this._eventHandlers = {
|
|
"mouseover": this._handleMouseOver.bind(this),
|
|
"mouseleave": this._handleMouseLeave.bind(this),
|
|
"mousemove": this._handleMouseMove.bind(this),
|
|
"mouseup": this._handleMouseUp.bind(this)
|
|
};
|
|
}
|
|
attach(target) {
|
|
if (this._target) {
|
|
this.detach();
|
|
}
|
|
this._target = target;
|
|
if (useFallback) {
|
|
document.body.appendChild(this._canvas);
|
|
const options = { capture: true, passive: true };
|
|
this._target.addEventListener("mouseover", this._eventHandlers.mouseover, options);
|
|
this._target.addEventListener("mouseleave", this._eventHandlers.mouseleave, options);
|
|
this._target.addEventListener("mousemove", this._eventHandlers.mousemove, options);
|
|
this._target.addEventListener("mouseup", this._eventHandlers.mouseup, options);
|
|
}
|
|
this.clear();
|
|
}
|
|
detach() {
|
|
if (!this._target) {
|
|
return;
|
|
}
|
|
if (useFallback) {
|
|
const options = { capture: true, passive: true };
|
|
this._target.removeEventListener("mouseover", this._eventHandlers.mouseover, options);
|
|
this._target.removeEventListener("mouseleave", this._eventHandlers.mouseleave, options);
|
|
this._target.removeEventListener("mousemove", this._eventHandlers.mousemove, options);
|
|
this._target.removeEventListener("mouseup", this._eventHandlers.mouseup, options);
|
|
if (document.contains(this._canvas)) {
|
|
document.body.removeChild(this._canvas);
|
|
}
|
|
}
|
|
this._target = null;
|
|
}
|
|
change(rgba, hotx, hoty, w, h) {
|
|
if (w === 0 || h === 0) {
|
|
this.clear();
|
|
return;
|
|
}
|
|
this._position.x = this._position.x + this._hotSpot.x - hotx;
|
|
this._position.y = this._position.y + this._hotSpot.y - hoty;
|
|
this._hotSpot.x = hotx;
|
|
this._hotSpot.y = hoty;
|
|
let ctx = this._canvas.getContext("2d");
|
|
this._canvas.width = w;
|
|
this._canvas.height = h;
|
|
let img = new ImageData(new Uint8ClampedArray(rgba), w, h);
|
|
ctx.clearRect(0, 0, w, h);
|
|
ctx.putImageData(img, 0, 0);
|
|
if (useFallback) {
|
|
this._updatePosition();
|
|
} else {
|
|
let url = this._canvas.toDataURL();
|
|
this._target.style.cursor = "url(" + url + ")" + hotx + " " + hoty + ", default";
|
|
}
|
|
}
|
|
clear() {
|
|
this._target.style.cursor = "none";
|
|
this._canvas.width = 0;
|
|
this._canvas.height = 0;
|
|
this._position.x = this._position.x + this._hotSpot.x;
|
|
this._position.y = this._position.y + this._hotSpot.y;
|
|
this._hotSpot.x = 0;
|
|
this._hotSpot.y = 0;
|
|
}
|
|
// Mouse events might be emulated, this allows
|
|
// moving the cursor in such cases
|
|
move(clientX, clientY) {
|
|
if (!useFallback) {
|
|
return;
|
|
}
|
|
if (window.visualViewport) {
|
|
this._position.x = clientX + window.visualViewport.offsetLeft;
|
|
this._position.y = clientY + window.visualViewport.offsetTop;
|
|
} else {
|
|
this._position.x = clientX;
|
|
this._position.y = clientY;
|
|
}
|
|
this._updatePosition();
|
|
let target = document.elementFromPoint(clientX, clientY);
|
|
this._updateVisibility(target);
|
|
}
|
|
_handleMouseOver(event) {
|
|
this._handleMouseMove(event);
|
|
}
|
|
_handleMouseLeave(event) {
|
|
this._updateVisibility(event.relatedTarget);
|
|
}
|
|
_handleMouseMove(event) {
|
|
this._updateVisibility(event.target);
|
|
this._position.x = event.clientX - this._hotSpot.x;
|
|
this._position.y = event.clientY - this._hotSpot.y;
|
|
this._updatePosition();
|
|
}
|
|
_handleMouseUp(event) {
|
|
let target = document.elementFromPoint(event.clientX, event.clientY);
|
|
this._updateVisibility(target);
|
|
if (this._captureIsActive()) {
|
|
window.setTimeout(() => {
|
|
if (!this._target) {
|
|
return;
|
|
}
|
|
target = document.elementFromPoint(
|
|
event.clientX,
|
|
event.clientY
|
|
);
|
|
this._updateVisibility(target);
|
|
}, 0);
|
|
}
|
|
}
|
|
_showCursor() {
|
|
if (this._canvas.style.visibility === "hidden") {
|
|
this._canvas.style.visibility = "";
|
|
}
|
|
}
|
|
_hideCursor() {
|
|
if (this._canvas.style.visibility !== "hidden") {
|
|
this._canvas.style.visibility = "hidden";
|
|
}
|
|
}
|
|
// Should we currently display the cursor?
|
|
// (i.e. are we over the target, or a child of the target without a
|
|
// different cursor set)
|
|
_shouldShowCursor(target) {
|
|
if (!target) {
|
|
return false;
|
|
}
|
|
if (target === this._target) {
|
|
return true;
|
|
}
|
|
if (!this._target.contains(target)) {
|
|
return false;
|
|
}
|
|
if (window.getComputedStyle(target).cursor !== "none") {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
_updateVisibility(target) {
|
|
if (this._captureIsActive()) {
|
|
target = document.captureElement;
|
|
}
|
|
if (this._shouldShowCursor(target)) {
|
|
this._showCursor();
|
|
} else {
|
|
this._hideCursor();
|
|
}
|
|
}
|
|
_updatePosition() {
|
|
this._canvas.style.left = this._position.x + "px";
|
|
this._canvas.style.top = this._position.y + "px";
|
|
}
|
|
_captureIsActive() {
|
|
return document.captureElement && document.documentElement.contains(document.captureElement);
|
|
}
|
|
};
|
|
|
|
// core/websock.js
|
|
var MAX_RQ_GROW_SIZE = 40 * 1024 * 1024;
|
|
var DataChannel = {
|
|
CONNECTING: "connecting",
|
|
OPEN: "open",
|
|
CLOSING: "closing",
|
|
CLOSED: "closed"
|
|
};
|
|
var ReadyStates = {
|
|
CONNECTING: [WebSocket.CONNECTING, DataChannel.CONNECTING],
|
|
OPEN: [WebSocket.OPEN, DataChannel.OPEN],
|
|
CLOSING: [WebSocket.CLOSING, DataChannel.CLOSING],
|
|
CLOSED: [WebSocket.CLOSED, DataChannel.CLOSED]
|
|
};
|
|
var rawChannelProps = [
|
|
"send",
|
|
"close",
|
|
"binaryType",
|
|
"onerror",
|
|
"onmessage",
|
|
"onopen",
|
|
"protocol",
|
|
"readyState"
|
|
];
|
|
var Websock = class {
|
|
constructor() {
|
|
this._websocket = null;
|
|
this._rQi = 0;
|
|
this._rQlen = 0;
|
|
this._rQbufferSize = 1024 * 1024 * 4;
|
|
this._rQ = null;
|
|
this._sQbufferSize = 1024 * 10;
|
|
this._sQlen = 0;
|
|
this._sQ = null;
|
|
this._eventHandlers = {
|
|
message: () => {
|
|
},
|
|
open: () => {
|
|
},
|
|
close: () => {
|
|
},
|
|
error: () => {
|
|
}
|
|
};
|
|
}
|
|
// Getters and setters
|
|
get readyState() {
|
|
let subState;
|
|
if (this._websocket === null) {
|
|
return "unused";
|
|
}
|
|
subState = this._websocket.readyState;
|
|
if (ReadyStates.CONNECTING.includes(subState)) {
|
|
return "connecting";
|
|
} else if (ReadyStates.OPEN.includes(subState)) {
|
|
return "open";
|
|
} else if (ReadyStates.CLOSING.includes(subState)) {
|
|
return "closing";
|
|
} else if (ReadyStates.CLOSED.includes(subState)) {
|
|
return "closed";
|
|
}
|
|
return "unknown";
|
|
}
|
|
// Receive queue
|
|
rQpeek8() {
|
|
return this._rQ[this._rQi];
|
|
}
|
|
rQskipBytes(bytes) {
|
|
this._rQi += bytes;
|
|
}
|
|
rQshift8() {
|
|
return this._rQshift(1);
|
|
}
|
|
rQshift16() {
|
|
return this._rQshift(2);
|
|
}
|
|
rQshift32() {
|
|
return this._rQshift(4);
|
|
}
|
|
// TODO(directxman12): test performance with these vs a DataView
|
|
_rQshift(bytes) {
|
|
let res = 0;
|
|
for (let byte = bytes - 1; byte >= 0; byte--) {
|
|
res += this._rQ[this._rQi++] << byte * 8;
|
|
}
|
|
return res >>> 0;
|
|
}
|
|
rQlen() {
|
|
return this._rQlen - this._rQi;
|
|
}
|
|
rQshiftStr(len) {
|
|
let str = "";
|
|
for (let i = 0; i < len; i += 4096) {
|
|
let part = this.rQshiftBytes(Math.min(4096, len - i), false);
|
|
str += String.fromCharCode.apply(null, part);
|
|
}
|
|
return str;
|
|
}
|
|
rQshiftBytes(len, copy = true) {
|
|
this._rQi += len;
|
|
if (copy) {
|
|
return this._rQ.slice(this._rQi - len, this._rQi);
|
|
} else {
|
|
return this._rQ.subarray(this._rQi - len, this._rQi);
|
|
}
|
|
}
|
|
rQshiftTo(target, len) {
|
|
target.set(new Uint8Array(this._rQ.buffer, this._rQi, len));
|
|
this._rQi += len;
|
|
}
|
|
rQpeekBytes(len, copy = true) {
|
|
if (copy) {
|
|
return this._rQ.slice(this._rQi, this._rQi + len);
|
|
} else {
|
|
return this._rQ.subarray(this._rQi, this._rQi + len);
|
|
}
|
|
}
|
|
// Check to see if we must wait for 'num' bytes (default to FBU.bytes)
|
|
// to be available in the receive queue. Return true if we need to
|
|
// wait (and possibly print a debug message), otherwise false.
|
|
rQwait(msg, num, goback) {
|
|
if (this._rQlen - this._rQi < num) {
|
|
if (goback) {
|
|
if (this._rQi < goback) {
|
|
throw new Error("rQwait cannot backup " + goback + " bytes");
|
|
}
|
|
this._rQi -= goback;
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
// Send queue
|
|
sQpush8(num) {
|
|
this._sQensureSpace(1);
|
|
this._sQ[this._sQlen++] = num;
|
|
}
|
|
sQpush16(num) {
|
|
this._sQensureSpace(2);
|
|
this._sQ[this._sQlen++] = num >> 8 & 255;
|
|
this._sQ[this._sQlen++] = num >> 0 & 255;
|
|
}
|
|
sQpush32(num) {
|
|
this._sQensureSpace(4);
|
|
this._sQ[this._sQlen++] = num >> 24 & 255;
|
|
this._sQ[this._sQlen++] = num >> 16 & 255;
|
|
this._sQ[this._sQlen++] = num >> 8 & 255;
|
|
this._sQ[this._sQlen++] = num >> 0 & 255;
|
|
}
|
|
sQpushString(str) {
|
|
let bytes = str.split("").map((chr) => chr.charCodeAt(0));
|
|
this.sQpushBytes(new Uint8Array(bytes));
|
|
}
|
|
sQpushBytes(bytes) {
|
|
for (let offset = 0; offset < bytes.length; ) {
|
|
this._sQensureSpace(1);
|
|
let chunkSize = this._sQbufferSize - this._sQlen;
|
|
if (chunkSize > bytes.length - offset) {
|
|
chunkSize = bytes.length - offset;
|
|
}
|
|
this._sQ.set(bytes.subarray(offset, offset + chunkSize), this._sQlen);
|
|
this._sQlen += chunkSize;
|
|
offset += chunkSize;
|
|
}
|
|
}
|
|
flush() {
|
|
if (this._sQlen > 0 && this.readyState === "open") {
|
|
this._websocket.send(new Uint8Array(this._sQ.buffer, 0, this._sQlen));
|
|
this._sQlen = 0;
|
|
}
|
|
}
|
|
_sQensureSpace(bytes) {
|
|
if (this._sQbufferSize - this._sQlen < bytes) {
|
|
this.flush();
|
|
}
|
|
}
|
|
// Event handlers
|
|
off(evt) {
|
|
this._eventHandlers[evt] = () => {
|
|
};
|
|
}
|
|
on(evt, handler) {
|
|
this._eventHandlers[evt] = handler;
|
|
}
|
|
_allocateBuffers() {
|
|
this._rQ = new Uint8Array(this._rQbufferSize);
|
|
this._sQ = new Uint8Array(this._sQbufferSize);
|
|
}
|
|
init() {
|
|
this._allocateBuffers();
|
|
this._rQi = 0;
|
|
this._websocket = null;
|
|
}
|
|
open(uri, protocols) {
|
|
this.attach(new WebSocket(uri, protocols));
|
|
}
|
|
attach(rawChannel) {
|
|
this.init();
|
|
const channelProps = [...Object.keys(rawChannel), ...Object.getOwnPropertyNames(Object.getPrototypeOf(rawChannel))];
|
|
for (let i = 0; i < rawChannelProps.length; i++) {
|
|
const prop = rawChannelProps[i];
|
|
if (channelProps.indexOf(prop) < 0) {
|
|
throw new Error("Raw channel missing property: " + prop);
|
|
}
|
|
}
|
|
this._websocket = rawChannel;
|
|
this._websocket.binaryType = "arraybuffer";
|
|
this._websocket.onmessage = this._recvMessage.bind(this);
|
|
this._websocket.onopen = () => {
|
|
Debug(">> WebSock.onopen");
|
|
if (this._websocket.protocol) {
|
|
Info("Server choose sub-protocol: " + this._websocket.protocol);
|
|
}
|
|
this._eventHandlers.open();
|
|
Debug("<< WebSock.onopen");
|
|
};
|
|
this._websocket.onclose = (e2) => {
|
|
Debug(">> WebSock.onclose");
|
|
this._eventHandlers.close(e2);
|
|
Debug("<< WebSock.onclose");
|
|
};
|
|
this._websocket.onerror = (e2) => {
|
|
Debug(">> WebSock.onerror: " + e2);
|
|
this._eventHandlers.error(e2);
|
|
Debug("<< WebSock.onerror: " + e2);
|
|
};
|
|
}
|
|
close() {
|
|
if (this._websocket) {
|
|
if (this.readyState === "connecting" || this.readyState === "open") {
|
|
Info("Closing WebSocket connection");
|
|
this._websocket.close();
|
|
}
|
|
this._websocket.onmessage = () => {
|
|
};
|
|
}
|
|
}
|
|
// private methods
|
|
// We want to move all the unread data to the start of the queue,
|
|
// e.g. compacting.
|
|
// The function also expands the receive que if needed, and for
|
|
// performance reasons we combine these two actions to avoid
|
|
// unnecessary copying.
|
|
_expandCompactRQ(minFit) {
|
|
const requiredBufferSize = (this._rQlen - this._rQi + minFit) * 8;
|
|
const resizeNeeded = this._rQbufferSize < requiredBufferSize;
|
|
if (resizeNeeded) {
|
|
this._rQbufferSize = Math.max(this._rQbufferSize * 2, requiredBufferSize);
|
|
}
|
|
if (this._rQbufferSize > MAX_RQ_GROW_SIZE) {
|
|
this._rQbufferSize = MAX_RQ_GROW_SIZE;
|
|
if (this._rQbufferSize - (this._rQlen - this._rQi) < minFit) {
|
|
throw new Error("Receive queue buffer exceeded " + MAX_RQ_GROW_SIZE + " bytes, and the new message could not fit");
|
|
}
|
|
}
|
|
if (resizeNeeded) {
|
|
const oldRQbuffer = this._rQ.buffer;
|
|
this._rQ = new Uint8Array(this._rQbufferSize);
|
|
this._rQ.set(new Uint8Array(oldRQbuffer, this._rQi, this._rQlen - this._rQi));
|
|
} else {
|
|
this._rQ.copyWithin(0, this._rQi, this._rQlen);
|
|
}
|
|
this._rQlen = this._rQlen - this._rQi;
|
|
this._rQi = 0;
|
|
}
|
|
// push arraybuffer values onto the end of the receive que
|
|
_recvMessage(e2) {
|
|
if (this._rQlen == this._rQi) {
|
|
this._rQlen = 0;
|
|
this._rQi = 0;
|
|
}
|
|
const u8 = new Uint8Array(e2.data);
|
|
if (u8.length > this._rQbufferSize - this._rQlen) {
|
|
this._expandCompactRQ(u8.length);
|
|
}
|
|
this._rQ.set(u8, this._rQlen);
|
|
this._rQlen += u8.length;
|
|
if (this._rQlen - this._rQi > 0) {
|
|
this._eventHandlers.message();
|
|
} else {
|
|
Debug("Ignoring empty message");
|
|
}
|
|
}
|
|
};
|
|
|
|
// core/input/xtscancodes.js
|
|
var xtscancodes_default = {
|
|
"Again": 57349,
|
|
/* html:Again (Again) -> linux:129 (KEY_AGAIN) -> atset1:57349 */
|
|
"AltLeft": 56,
|
|
/* html:AltLeft (AltLeft) -> linux:56 (KEY_LEFTALT) -> atset1:56 */
|
|
"AltRight": 57400,
|
|
/* html:AltRight (AltRight) -> linux:100 (KEY_RIGHTALT) -> atset1:57400 */
|
|
"ArrowDown": 57424,
|
|
/* html:ArrowDown (ArrowDown) -> linux:108 (KEY_DOWN) -> atset1:57424 */
|
|
"ArrowLeft": 57419,
|
|
/* html:ArrowLeft (ArrowLeft) -> linux:105 (KEY_LEFT) -> atset1:57419 */
|
|
"ArrowRight": 57421,
|
|
/* html:ArrowRight (ArrowRight) -> linux:106 (KEY_RIGHT) -> atset1:57421 */
|
|
"ArrowUp": 57416,
|
|
/* html:ArrowUp (ArrowUp) -> linux:103 (KEY_UP) -> atset1:57416 */
|
|
"AudioVolumeDown": 57390,
|
|
/* html:AudioVolumeDown (AudioVolumeDown) -> linux:114 (KEY_VOLUMEDOWN) -> atset1:57390 */
|
|
"AudioVolumeMute": 57376,
|
|
/* html:AudioVolumeMute (AudioVolumeMute) -> linux:113 (KEY_MUTE) -> atset1:57376 */
|
|
"AudioVolumeUp": 57392,
|
|
/* html:AudioVolumeUp (AudioVolumeUp) -> linux:115 (KEY_VOLUMEUP) -> atset1:57392 */
|
|
"Backquote": 41,
|
|
/* html:Backquote (Backquote) -> linux:41 (KEY_GRAVE) -> atset1:41 */
|
|
"Backslash": 43,
|
|
/* html:Backslash (Backslash) -> linux:43 (KEY_BACKSLASH) -> atset1:43 */
|
|
"Backspace": 14,
|
|
/* html:Backspace (Backspace) -> linux:14 (KEY_BACKSPACE) -> atset1:14 */
|
|
"BracketLeft": 26,
|
|
/* html:BracketLeft (BracketLeft) -> linux:26 (KEY_LEFTBRACE) -> atset1:26 */
|
|
"BracketRight": 27,
|
|
/* html:BracketRight (BracketRight) -> linux:27 (KEY_RIGHTBRACE) -> atset1:27 */
|
|
"BrowserBack": 57450,
|
|
/* html:BrowserBack (BrowserBack) -> linux:158 (KEY_BACK) -> atset1:57450 */
|
|
"BrowserFavorites": 57446,
|
|
/* html:BrowserFavorites (BrowserFavorites) -> linux:156 (KEY_BOOKMARKS) -> atset1:57446 */
|
|
"BrowserForward": 57449,
|
|
/* html:BrowserForward (BrowserForward) -> linux:159 (KEY_FORWARD) -> atset1:57449 */
|
|
"BrowserHome": 57394,
|
|
/* html:BrowserHome (BrowserHome) -> linux:172 (KEY_HOMEPAGE) -> atset1:57394 */
|
|
"BrowserRefresh": 57447,
|
|
/* html:BrowserRefresh (BrowserRefresh) -> linux:173 (KEY_REFRESH) -> atset1:57447 */
|
|
"BrowserSearch": 57445,
|
|
/* html:BrowserSearch (BrowserSearch) -> linux:217 (KEY_SEARCH) -> atset1:57445 */
|
|
"BrowserStop": 57448,
|
|
/* html:BrowserStop (BrowserStop) -> linux:128 (KEY_STOP) -> atset1:57448 */
|
|
"CapsLock": 58,
|
|
/* html:CapsLock (CapsLock) -> linux:58 (KEY_CAPSLOCK) -> atset1:58 */
|
|
"Comma": 51,
|
|
/* html:Comma (Comma) -> linux:51 (KEY_COMMA) -> atset1:51 */
|
|
"ContextMenu": 57437,
|
|
/* html:ContextMenu (ContextMenu) -> linux:127 (KEY_COMPOSE) -> atset1:57437 */
|
|
"ControlLeft": 29,
|
|
/* html:ControlLeft (ControlLeft) -> linux:29 (KEY_LEFTCTRL) -> atset1:29 */
|
|
"ControlRight": 57373,
|
|
/* html:ControlRight (ControlRight) -> linux:97 (KEY_RIGHTCTRL) -> atset1:57373 */
|
|
"Convert": 121,
|
|
/* html:Convert (Convert) -> linux:92 (KEY_HENKAN) -> atset1:121 */
|
|
"Copy": 57464,
|
|
/* html:Copy (Copy) -> linux:133 (KEY_COPY) -> atset1:57464 */
|
|
"Cut": 57404,
|
|
/* html:Cut (Cut) -> linux:137 (KEY_CUT) -> atset1:57404 */
|
|
"Delete": 57427,
|
|
/* html:Delete (Delete) -> linux:111 (KEY_DELETE) -> atset1:57427 */
|
|
"Digit0": 11,
|
|
/* html:Digit0 (Digit0) -> linux:11 (KEY_0) -> atset1:11 */
|
|
"Digit1": 2,
|
|
/* html:Digit1 (Digit1) -> linux:2 (KEY_1) -> atset1:2 */
|
|
"Digit2": 3,
|
|
/* html:Digit2 (Digit2) -> linux:3 (KEY_2) -> atset1:3 */
|
|
"Digit3": 4,
|
|
/* html:Digit3 (Digit3) -> linux:4 (KEY_3) -> atset1:4 */
|
|
"Digit4": 5,
|
|
/* html:Digit4 (Digit4) -> linux:5 (KEY_4) -> atset1:5 */
|
|
"Digit5": 6,
|
|
/* html:Digit5 (Digit5) -> linux:6 (KEY_5) -> atset1:6 */
|
|
"Digit6": 7,
|
|
/* html:Digit6 (Digit6) -> linux:7 (KEY_6) -> atset1:7 */
|
|
"Digit7": 8,
|
|
/* html:Digit7 (Digit7) -> linux:8 (KEY_7) -> atset1:8 */
|
|
"Digit8": 9,
|
|
/* html:Digit8 (Digit8) -> linux:9 (KEY_8) -> atset1:9 */
|
|
"Digit9": 10,
|
|
/* html:Digit9 (Digit9) -> linux:10 (KEY_9) -> atset1:10 */
|
|
"Eject": 57469,
|
|
/* html:Eject (Eject) -> linux:162 (KEY_EJECTCLOSECD) -> atset1:57469 */
|
|
"End": 57423,
|
|
/* html:End (End) -> linux:107 (KEY_END) -> atset1:57423 */
|
|
"Enter": 28,
|
|
/* html:Enter (Enter) -> linux:28 (KEY_ENTER) -> atset1:28 */
|
|
"Equal": 13,
|
|
/* html:Equal (Equal) -> linux:13 (KEY_EQUAL) -> atset1:13 */
|
|
"Escape": 1,
|
|
/* html:Escape (Escape) -> linux:1 (KEY_ESC) -> atset1:1 */
|
|
"F1": 59,
|
|
/* html:F1 (F1) -> linux:59 (KEY_F1) -> atset1:59 */
|
|
"F10": 68,
|
|
/* html:F10 (F10) -> linux:68 (KEY_F10) -> atset1:68 */
|
|
"F11": 87,
|
|
/* html:F11 (F11) -> linux:87 (KEY_F11) -> atset1:87 */
|
|
"F12": 88,
|
|
/* html:F12 (F12) -> linux:88 (KEY_F12) -> atset1:88 */
|
|
"F13": 93,
|
|
/* html:F13 (F13) -> linux:183 (KEY_F13) -> atset1:93 */
|
|
"F14": 94,
|
|
/* html:F14 (F14) -> linux:184 (KEY_F14) -> atset1:94 */
|
|
"F15": 95,
|
|
/* html:F15 (F15) -> linux:185 (KEY_F15) -> atset1:95 */
|
|
"F16": 85,
|
|
/* html:F16 (F16) -> linux:186 (KEY_F16) -> atset1:85 */
|
|
"F17": 57347,
|
|
/* html:F17 (F17) -> linux:187 (KEY_F17) -> atset1:57347 */
|
|
"F18": 57463,
|
|
/* html:F18 (F18) -> linux:188 (KEY_F18) -> atset1:57463 */
|
|
"F19": 57348,
|
|
/* html:F19 (F19) -> linux:189 (KEY_F19) -> atset1:57348 */
|
|
"F2": 60,
|
|
/* html:F2 (F2) -> linux:60 (KEY_F2) -> atset1:60 */
|
|
"F20": 90,
|
|
/* html:F20 (F20) -> linux:190 (KEY_F20) -> atset1:90 */
|
|
"F21": 116,
|
|
/* html:F21 (F21) -> linux:191 (KEY_F21) -> atset1:116 */
|
|
"F22": 57465,
|
|
/* html:F22 (F22) -> linux:192 (KEY_F22) -> atset1:57465 */
|
|
"F23": 109,
|
|
/* html:F23 (F23) -> linux:193 (KEY_F23) -> atset1:109 */
|
|
"F24": 111,
|
|
/* html:F24 (F24) -> linux:194 (KEY_F24) -> atset1:111 */
|
|
"F3": 61,
|
|
/* html:F3 (F3) -> linux:61 (KEY_F3) -> atset1:61 */
|
|
"F4": 62,
|
|
/* html:F4 (F4) -> linux:62 (KEY_F4) -> atset1:62 */
|
|
"F5": 63,
|
|
/* html:F5 (F5) -> linux:63 (KEY_F5) -> atset1:63 */
|
|
"F6": 64,
|
|
/* html:F6 (F6) -> linux:64 (KEY_F6) -> atset1:64 */
|
|
"F7": 65,
|
|
/* html:F7 (F7) -> linux:65 (KEY_F7) -> atset1:65 */
|
|
"F8": 66,
|
|
/* html:F8 (F8) -> linux:66 (KEY_F8) -> atset1:66 */
|
|
"F9": 67,
|
|
/* html:F9 (F9) -> linux:67 (KEY_F9) -> atset1:67 */
|
|
"Find": 57409,
|
|
/* html:Find (Find) -> linux:136 (KEY_FIND) -> atset1:57409 */
|
|
"Help": 57461,
|
|
/* html:Help (Help) -> linux:138 (KEY_HELP) -> atset1:57461 */
|
|
"Hiragana": 119,
|
|
/* html:Hiragana (Lang4) -> linux:91 (KEY_HIRAGANA) -> atset1:119 */
|
|
"Home": 57415,
|
|
/* html:Home (Home) -> linux:102 (KEY_HOME) -> atset1:57415 */
|
|
"Insert": 57426,
|
|
/* html:Insert (Insert) -> linux:110 (KEY_INSERT) -> atset1:57426 */
|
|
"IntlBackslash": 86,
|
|
/* html:IntlBackslash (IntlBackslash) -> linux:86 (KEY_102ND) -> atset1:86 */
|
|
"IntlRo": 115,
|
|
/* html:IntlRo (IntlRo) -> linux:89 (KEY_RO) -> atset1:115 */
|
|
"IntlYen": 125,
|
|
/* html:IntlYen (IntlYen) -> linux:124 (KEY_YEN) -> atset1:125 */
|
|
"KanaMode": 112,
|
|
/* html:KanaMode (KanaMode) -> linux:93 (KEY_KATAKANAHIRAGANA) -> atset1:112 */
|
|
"Katakana": 120,
|
|
/* html:Katakana (Lang3) -> linux:90 (KEY_KATAKANA) -> atset1:120 */
|
|
"KeyA": 30,
|
|
/* html:KeyA (KeyA) -> linux:30 (KEY_A) -> atset1:30 */
|
|
"KeyB": 48,
|
|
/* html:KeyB (KeyB) -> linux:48 (KEY_B) -> atset1:48 */
|
|
"KeyC": 46,
|
|
/* html:KeyC (KeyC) -> linux:46 (KEY_C) -> atset1:46 */
|
|
"KeyD": 32,
|
|
/* html:KeyD (KeyD) -> linux:32 (KEY_D) -> atset1:32 */
|
|
"KeyE": 18,
|
|
/* html:KeyE (KeyE) -> linux:18 (KEY_E) -> atset1:18 */
|
|
"KeyF": 33,
|
|
/* html:KeyF (KeyF) -> linux:33 (KEY_F) -> atset1:33 */
|
|
"KeyG": 34,
|
|
/* html:KeyG (KeyG) -> linux:34 (KEY_G) -> atset1:34 */
|
|
"KeyH": 35,
|
|
/* html:KeyH (KeyH) -> linux:35 (KEY_H) -> atset1:35 */
|
|
"KeyI": 23,
|
|
/* html:KeyI (KeyI) -> linux:23 (KEY_I) -> atset1:23 */
|
|
"KeyJ": 36,
|
|
/* html:KeyJ (KeyJ) -> linux:36 (KEY_J) -> atset1:36 */
|
|
"KeyK": 37,
|
|
/* html:KeyK (KeyK) -> linux:37 (KEY_K) -> atset1:37 */
|
|
"KeyL": 38,
|
|
/* html:KeyL (KeyL) -> linux:38 (KEY_L) -> atset1:38 */
|
|
"KeyM": 50,
|
|
/* html:KeyM (KeyM) -> linux:50 (KEY_M) -> atset1:50 */
|
|
"KeyN": 49,
|
|
/* html:KeyN (KeyN) -> linux:49 (KEY_N) -> atset1:49 */
|
|
"KeyO": 24,
|
|
/* html:KeyO (KeyO) -> linux:24 (KEY_O) -> atset1:24 */
|
|
"KeyP": 25,
|
|
/* html:KeyP (KeyP) -> linux:25 (KEY_P) -> atset1:25 */
|
|
"KeyQ": 16,
|
|
/* html:KeyQ (KeyQ) -> linux:16 (KEY_Q) -> atset1:16 */
|
|
"KeyR": 19,
|
|
/* html:KeyR (KeyR) -> linux:19 (KEY_R) -> atset1:19 */
|
|
"KeyS": 31,
|
|
/* html:KeyS (KeyS) -> linux:31 (KEY_S) -> atset1:31 */
|
|
"KeyT": 20,
|
|
/* html:KeyT (KeyT) -> linux:20 (KEY_T) -> atset1:20 */
|
|
"KeyU": 22,
|
|
/* html:KeyU (KeyU) -> linux:22 (KEY_U) -> atset1:22 */
|
|
"KeyV": 47,
|
|
/* html:KeyV (KeyV) -> linux:47 (KEY_V) -> atset1:47 */
|
|
"KeyW": 17,
|
|
/* html:KeyW (KeyW) -> linux:17 (KEY_W) -> atset1:17 */
|
|
"KeyX": 45,
|
|
/* html:KeyX (KeyX) -> linux:45 (KEY_X) -> atset1:45 */
|
|
"KeyY": 21,
|
|
/* html:KeyY (KeyY) -> linux:21 (KEY_Y) -> atset1:21 */
|
|
"KeyZ": 44,
|
|
/* html:KeyZ (KeyZ) -> linux:44 (KEY_Z) -> atset1:44 */
|
|
"Lang1": 114,
|
|
/* html:Lang1 (Lang1) -> linux:122 (KEY_HANGEUL) -> atset1:114 */
|
|
"Lang2": 113,
|
|
/* html:Lang2 (Lang2) -> linux:123 (KEY_HANJA) -> atset1:113 */
|
|
"Lang3": 120,
|
|
/* html:Lang3 (Lang3) -> linux:90 (KEY_KATAKANA) -> atset1:120 */
|
|
"Lang4": 119,
|
|
/* html:Lang4 (Lang4) -> linux:91 (KEY_HIRAGANA) -> atset1:119 */
|
|
"Lang5": 118,
|
|
/* html:Lang5 (Lang5) -> linux:85 (KEY_ZENKAKUHANKAKU) -> atset1:118 */
|
|
"LaunchApp1": 57451,
|
|
/* html:LaunchApp1 (LaunchApp1) -> linux:157 (KEY_COMPUTER) -> atset1:57451 */
|
|
"LaunchApp2": 57377,
|
|
/* html:LaunchApp2 (LaunchApp2) -> linux:140 (KEY_CALC) -> atset1:57377 */
|
|
"LaunchMail": 57452,
|
|
/* html:LaunchMail (LaunchMail) -> linux:155 (KEY_MAIL) -> atset1:57452 */
|
|
"MediaPlayPause": 57378,
|
|
/* html:MediaPlayPause (MediaPlayPause) -> linux:164 (KEY_PLAYPAUSE) -> atset1:57378 */
|
|
"MediaSelect": 57453,
|
|
/* html:MediaSelect (MediaSelect) -> linux:226 (KEY_MEDIA) -> atset1:57453 */
|
|
"MediaStop": 57380,
|
|
/* html:MediaStop (MediaStop) -> linux:166 (KEY_STOPCD) -> atset1:57380 */
|
|
"MediaTrackNext": 57369,
|
|
/* html:MediaTrackNext (MediaTrackNext) -> linux:163 (KEY_NEXTSONG) -> atset1:57369 */
|
|
"MediaTrackPrevious": 57360,
|
|
/* html:MediaTrackPrevious (MediaTrackPrevious) -> linux:165 (KEY_PREVIOUSSONG) -> atset1:57360 */
|
|
"MetaLeft": 57435,
|
|
/* html:MetaLeft (MetaLeft) -> linux:125 (KEY_LEFTMETA) -> atset1:57435 */
|
|
"MetaRight": 57436,
|
|
/* html:MetaRight (MetaRight) -> linux:126 (KEY_RIGHTMETA) -> atset1:57436 */
|
|
"Minus": 12,
|
|
/* html:Minus (Minus) -> linux:12 (KEY_MINUS) -> atset1:12 */
|
|
"NonConvert": 123,
|
|
/* html:NonConvert (NonConvert) -> linux:94 (KEY_MUHENKAN) -> atset1:123 */
|
|
"NumLock": 69,
|
|
/* html:NumLock (NumLock) -> linux:69 (KEY_NUMLOCK) -> atset1:69 */
|
|
"Numpad0": 82,
|
|
/* html:Numpad0 (Numpad0) -> linux:82 (KEY_KP0) -> atset1:82 */
|
|
"Numpad1": 79,
|
|
/* html:Numpad1 (Numpad1) -> linux:79 (KEY_KP1) -> atset1:79 */
|
|
"Numpad2": 80,
|
|
/* html:Numpad2 (Numpad2) -> linux:80 (KEY_KP2) -> atset1:80 */
|
|
"Numpad3": 81,
|
|
/* html:Numpad3 (Numpad3) -> linux:81 (KEY_KP3) -> atset1:81 */
|
|
"Numpad4": 75,
|
|
/* html:Numpad4 (Numpad4) -> linux:75 (KEY_KP4) -> atset1:75 */
|
|
"Numpad5": 76,
|
|
/* html:Numpad5 (Numpad5) -> linux:76 (KEY_KP5) -> atset1:76 */
|
|
"Numpad6": 77,
|
|
/* html:Numpad6 (Numpad6) -> linux:77 (KEY_KP6) -> atset1:77 */
|
|
"Numpad7": 71,
|
|
/* html:Numpad7 (Numpad7) -> linux:71 (KEY_KP7) -> atset1:71 */
|
|
"Numpad8": 72,
|
|
/* html:Numpad8 (Numpad8) -> linux:72 (KEY_KP8) -> atset1:72 */
|
|
"Numpad9": 73,
|
|
/* html:Numpad9 (Numpad9) -> linux:73 (KEY_KP9) -> atset1:73 */
|
|
"NumpadAdd": 78,
|
|
/* html:NumpadAdd (NumpadAdd) -> linux:78 (KEY_KPPLUS) -> atset1:78 */
|
|
"NumpadComma": 126,
|
|
/* html:NumpadComma (NumpadComma) -> linux:121 (KEY_KPCOMMA) -> atset1:126 */
|
|
"NumpadDecimal": 83,
|
|
/* html:NumpadDecimal (NumpadDecimal) -> linux:83 (KEY_KPDOT) -> atset1:83 */
|
|
"NumpadDivide": 57397,
|
|
/* html:NumpadDivide (NumpadDivide) -> linux:98 (KEY_KPSLASH) -> atset1:57397 */
|
|
"NumpadEnter": 57372,
|
|
/* html:NumpadEnter (NumpadEnter) -> linux:96 (KEY_KPENTER) -> atset1:57372 */
|
|
"NumpadEqual": 89,
|
|
/* html:NumpadEqual (NumpadEqual) -> linux:117 (KEY_KPEQUAL) -> atset1:89 */
|
|
"NumpadMultiply": 55,
|
|
/* html:NumpadMultiply (NumpadMultiply) -> linux:55 (KEY_KPASTERISK) -> atset1:55 */
|
|
"NumpadParenLeft": 57462,
|
|
/* html:NumpadParenLeft (NumpadParenLeft) -> linux:179 (KEY_KPLEFTPAREN) -> atset1:57462 */
|
|
"NumpadParenRight": 57467,
|
|
/* html:NumpadParenRight (NumpadParenRight) -> linux:180 (KEY_KPRIGHTPAREN) -> atset1:57467 */
|
|
"NumpadSubtract": 74,
|
|
/* html:NumpadSubtract (NumpadSubtract) -> linux:74 (KEY_KPMINUS) -> atset1:74 */
|
|
"Open": 100,
|
|
/* html:Open (Open) -> linux:134 (KEY_OPEN) -> atset1:100 */
|
|
"PageDown": 57425,
|
|
/* html:PageDown (PageDown) -> linux:109 (KEY_PAGEDOWN) -> atset1:57425 */
|
|
"PageUp": 57417,
|
|
/* html:PageUp (PageUp) -> linux:104 (KEY_PAGEUP) -> atset1:57417 */
|
|
"Paste": 101,
|
|
/* html:Paste (Paste) -> linux:135 (KEY_PASTE) -> atset1:101 */
|
|
"Pause": 57414,
|
|
/* html:Pause (Pause) -> linux:119 (KEY_PAUSE) -> atset1:57414 */
|
|
"Period": 52,
|
|
/* html:Period (Period) -> linux:52 (KEY_DOT) -> atset1:52 */
|
|
"Power": 57438,
|
|
/* html:Power (Power) -> linux:116 (KEY_POWER) -> atset1:57438 */
|
|
"PrintScreen": 84,
|
|
/* html:PrintScreen (PrintScreen) -> linux:99 (KEY_SYSRQ) -> atset1:84 */
|
|
"Props": 57350,
|
|
/* html:Props (Props) -> linux:130 (KEY_PROPS) -> atset1:57350 */
|
|
"Quote": 40,
|
|
/* html:Quote (Quote) -> linux:40 (KEY_APOSTROPHE) -> atset1:40 */
|
|
"ScrollLock": 70,
|
|
/* html:ScrollLock (ScrollLock) -> linux:70 (KEY_SCROLLLOCK) -> atset1:70 */
|
|
"Semicolon": 39,
|
|
/* html:Semicolon (Semicolon) -> linux:39 (KEY_SEMICOLON) -> atset1:39 */
|
|
"ShiftLeft": 42,
|
|
/* html:ShiftLeft (ShiftLeft) -> linux:42 (KEY_LEFTSHIFT) -> atset1:42 */
|
|
"ShiftRight": 54,
|
|
/* html:ShiftRight (ShiftRight) -> linux:54 (KEY_RIGHTSHIFT) -> atset1:54 */
|
|
"Slash": 53,
|
|
/* html:Slash (Slash) -> linux:53 (KEY_SLASH) -> atset1:53 */
|
|
"Sleep": 57439,
|
|
/* html:Sleep (Sleep) -> linux:142 (KEY_SLEEP) -> atset1:57439 */
|
|
"Space": 57,
|
|
/* html:Space (Space) -> linux:57 (KEY_SPACE) -> atset1:57 */
|
|
"Suspend": 57381,
|
|
/* html:Suspend (Suspend) -> linux:205 (KEY_SUSPEND) -> atset1:57381 */
|
|
"Tab": 15,
|
|
/* html:Tab (Tab) -> linux:15 (KEY_TAB) -> atset1:15 */
|
|
"Undo": 57351,
|
|
/* html:Undo (Undo) -> linux:131 (KEY_UNDO) -> atset1:57351 */
|
|
"WakeUp": 57443
|
|
/* html:WakeUp (WakeUp) -> linux:143 (KEY_WAKEUP) -> atset1:57443 */
|
|
};
|
|
|
|
// core/encodings.js
|
|
var encodings = {
|
|
encodingRaw: 0,
|
|
encodingCopyRect: 1,
|
|
encodingRRE: 2,
|
|
encodingHextile: 5,
|
|
encodingZlib: 6,
|
|
encodingTight: 7,
|
|
encodingZRLE: 16,
|
|
encodingTightPNG: -260,
|
|
encodingJPEG: 21,
|
|
encodingH264: 50,
|
|
pseudoEncodingQualityLevel9: -23,
|
|
pseudoEncodingQualityLevel0: -32,
|
|
pseudoEncodingDesktopSize: -223,
|
|
pseudoEncodingLastRect: -224,
|
|
pseudoEncodingCursor: -239,
|
|
pseudoEncodingQEMUExtendedKeyEvent: -258,
|
|
pseudoEncodingQEMULedEvent: -261,
|
|
pseudoEncodingDesktopName: -307,
|
|
pseudoEncodingExtendedDesktopSize: -308,
|
|
pseudoEncodingXvp: -309,
|
|
pseudoEncodingFence: -312,
|
|
pseudoEncodingContinuousUpdates: -313,
|
|
pseudoEncodingExtendedMouseButtons: -316,
|
|
pseudoEncodingCompressLevel9: -247,
|
|
pseudoEncodingCompressLevel0: -256,
|
|
pseudoEncodingVMwareCursor: 1464686180,
|
|
pseudoEncodingExtendedClipboard: 3231835598
|
|
};
|
|
|
|
// core/crypto/aes.js
|
|
var AESECBCipher = class _AESECBCipher {
|
|
constructor() {
|
|
this._key = null;
|
|
}
|
|
get algorithm() {
|
|
return { name: "AES-ECB" };
|
|
}
|
|
static async importKey(key, _algorithm, extractable, keyUsages) {
|
|
const cipher = new _AESECBCipher();
|
|
await cipher._importKey(key, extractable, keyUsages);
|
|
return cipher;
|
|
}
|
|
async _importKey(key, extractable, keyUsages) {
|
|
this._key = await window.crypto.subtle.importKey(
|
|
"raw",
|
|
key,
|
|
{ name: "AES-CBC" },
|
|
extractable,
|
|
keyUsages
|
|
);
|
|
}
|
|
async encrypt(_algorithm, plaintext) {
|
|
const x = new Uint8Array(plaintext);
|
|
if (x.length % 16 !== 0 || this._key === null) {
|
|
return null;
|
|
}
|
|
const n = x.length / 16;
|
|
for (let i = 0; i < n; i++) {
|
|
const y = new Uint8Array(await window.crypto.subtle.encrypt({
|
|
name: "AES-CBC",
|
|
iv: new Uint8Array(16)
|
|
}, this._key, x.slice(i * 16, i * 16 + 16))).slice(0, 16);
|
|
x.set(y, i * 16);
|
|
}
|
|
return x;
|
|
}
|
|
};
|
|
var AESEAXCipher = class _AESEAXCipher {
|
|
constructor() {
|
|
this._rawKey = null;
|
|
this._ctrKey = null;
|
|
this._cbcKey = null;
|
|
this._zeroBlock = new Uint8Array(16);
|
|
this._prefixBlock0 = this._zeroBlock;
|
|
this._prefixBlock1 = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]);
|
|
this._prefixBlock2 = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2]);
|
|
}
|
|
get algorithm() {
|
|
return { name: "AES-EAX" };
|
|
}
|
|
async _encryptBlock(block) {
|
|
const encrypted = await window.crypto.subtle.encrypt({
|
|
name: "AES-CBC",
|
|
iv: this._zeroBlock
|
|
}, this._cbcKey, block);
|
|
return new Uint8Array(encrypted).slice(0, 16);
|
|
}
|
|
async _initCMAC() {
|
|
const k1 = await this._encryptBlock(this._zeroBlock);
|
|
const k2 = new Uint8Array(16);
|
|
const v = k1[0] >>> 6;
|
|
for (let i = 0; i < 15; i++) {
|
|
k2[i] = k1[i + 1] >> 6 | k1[i] << 2;
|
|
k1[i] = k1[i + 1] >> 7 | k1[i] << 1;
|
|
}
|
|
const lut = [0, 135, 14, 137];
|
|
k2[14] ^= v >>> 1;
|
|
k2[15] = k1[15] << 2 ^ lut[v];
|
|
k1[15] = k1[15] << 1 ^ lut[v >> 1];
|
|
this._k1 = k1;
|
|
this._k2 = k2;
|
|
}
|
|
async _encryptCTR(data, counter) {
|
|
const encrypted = await window.crypto.subtle.encrypt({
|
|
name: "AES-CTR",
|
|
counter,
|
|
length: 128
|
|
}, this._ctrKey, data);
|
|
return new Uint8Array(encrypted);
|
|
}
|
|
async _decryptCTR(data, counter) {
|
|
const decrypted = await window.crypto.subtle.decrypt({
|
|
name: "AES-CTR",
|
|
counter,
|
|
length: 128
|
|
}, this._ctrKey, data);
|
|
return new Uint8Array(decrypted);
|
|
}
|
|
async _computeCMAC(data, prefixBlock) {
|
|
if (prefixBlock.length !== 16) {
|
|
return null;
|
|
}
|
|
const n = Math.floor(data.length / 16);
|
|
const m = Math.ceil(data.length / 16);
|
|
const r = data.length - n * 16;
|
|
const cbcData = new Uint8Array((m + 1) * 16);
|
|
cbcData.set(prefixBlock);
|
|
cbcData.set(data, 16);
|
|
if (r === 0) {
|
|
for (let i = 0; i < 16; i++) {
|
|
cbcData[n * 16 + i] ^= this._k1[i];
|
|
}
|
|
} else {
|
|
cbcData[(n + 1) * 16 + r] = 128;
|
|
for (let i = 0; i < 16; i++) {
|
|
cbcData[(n + 1) * 16 + i] ^= this._k2[i];
|
|
}
|
|
}
|
|
let cbcEncrypted = await window.crypto.subtle.encrypt({
|
|
name: "AES-CBC",
|
|
iv: this._zeroBlock
|
|
}, this._cbcKey, cbcData);
|
|
cbcEncrypted = new Uint8Array(cbcEncrypted);
|
|
const mac = cbcEncrypted.slice(cbcEncrypted.length - 32, cbcEncrypted.length - 16);
|
|
return mac;
|
|
}
|
|
static async importKey(key, _algorithm, _extractable, _keyUsages) {
|
|
const cipher = new _AESEAXCipher();
|
|
await cipher._importKey(key);
|
|
return cipher;
|
|
}
|
|
async _importKey(key) {
|
|
this._rawKey = key;
|
|
this._ctrKey = await window.crypto.subtle.importKey(
|
|
"raw",
|
|
key,
|
|
{ name: "AES-CTR" },
|
|
false,
|
|
["encrypt", "decrypt"]
|
|
);
|
|
this._cbcKey = await window.crypto.subtle.importKey(
|
|
"raw",
|
|
key,
|
|
{ name: "AES-CBC" },
|
|
false,
|
|
["encrypt"]
|
|
);
|
|
await this._initCMAC();
|
|
}
|
|
async encrypt(algorithm, message) {
|
|
const ad = algorithm.additionalData;
|
|
const nonce = algorithm.iv;
|
|
const nCMAC = await this._computeCMAC(nonce, this._prefixBlock0);
|
|
const encrypted = await this._encryptCTR(message, nCMAC);
|
|
const adCMAC = await this._computeCMAC(ad, this._prefixBlock1);
|
|
const mac = await this._computeCMAC(encrypted, this._prefixBlock2);
|
|
for (let i = 0; i < 16; i++) {
|
|
mac[i] ^= nCMAC[i] ^ adCMAC[i];
|
|
}
|
|
const res = new Uint8Array(16 + encrypted.length);
|
|
res.set(encrypted);
|
|
res.set(mac, encrypted.length);
|
|
return res;
|
|
}
|
|
async decrypt(algorithm, data) {
|
|
const encrypted = data.slice(0, data.length - 16);
|
|
const ad = algorithm.additionalData;
|
|
const nonce = algorithm.iv;
|
|
const mac = data.slice(data.length - 16);
|
|
const nCMAC = await this._computeCMAC(nonce, this._prefixBlock0);
|
|
const adCMAC = await this._computeCMAC(ad, this._prefixBlock1);
|
|
const computedMac = await this._computeCMAC(encrypted, this._prefixBlock2);
|
|
for (let i = 0; i < 16; i++) {
|
|
computedMac[i] ^= nCMAC[i] ^ adCMAC[i];
|
|
}
|
|
if (computedMac.length !== mac.length) {
|
|
return null;
|
|
}
|
|
for (let i = 0; i < mac.length; i++) {
|
|
if (computedMac[i] !== mac[i]) {
|
|
return null;
|
|
}
|
|
}
|
|
const res = await this._decryptCTR(encrypted, nCMAC);
|
|
return res;
|
|
}
|
|
};
|
|
|
|
// core/crypto/des.js
|
|
var PC2 = [
|
|
13,
|
|
16,
|
|
10,
|
|
23,
|
|
0,
|
|
4,
|
|
2,
|
|
27,
|
|
14,
|
|
5,
|
|
20,
|
|
9,
|
|
22,
|
|
18,
|
|
11,
|
|
3,
|
|
25,
|
|
7,
|
|
15,
|
|
6,
|
|
26,
|
|
19,
|
|
12,
|
|
1,
|
|
40,
|
|
51,
|
|
30,
|
|
36,
|
|
46,
|
|
54,
|
|
29,
|
|
39,
|
|
50,
|
|
44,
|
|
32,
|
|
47,
|
|
43,
|
|
48,
|
|
38,
|
|
55,
|
|
33,
|
|
52,
|
|
45,
|
|
41,
|
|
49,
|
|
35,
|
|
28,
|
|
31
|
|
];
|
|
var totrot = [1, 2, 4, 6, 8, 10, 12, 14, 15, 17, 19, 21, 23, 25, 27, 28];
|
|
var z = 0;
|
|
var a;
|
|
var b;
|
|
var c;
|
|
var d;
|
|
var e;
|
|
var f;
|
|
a = 1 << 16;
|
|
b = 1 << 24;
|
|
c = a | b;
|
|
d = 1 << 2;
|
|
e = 1 << 10;
|
|
f = d | e;
|
|
var SP1 = [
|
|
c | e,
|
|
z | z,
|
|
a | z,
|
|
c | f,
|
|
c | d,
|
|
a | f,
|
|
z | d,
|
|
a | z,
|
|
z | e,
|
|
c | e,
|
|
c | f,
|
|
z | e,
|
|
b | f,
|
|
c | d,
|
|
b | z,
|
|
z | d,
|
|
z | f,
|
|
b | e,
|
|
b | e,
|
|
a | e,
|
|
a | e,
|
|
c | z,
|
|
c | z,
|
|
b | f,
|
|
a | d,
|
|
b | d,
|
|
b | d,
|
|
a | d,
|
|
z | z,
|
|
z | f,
|
|
a | f,
|
|
b | z,
|
|
a | z,
|
|
c | f,
|
|
z | d,
|
|
c | z,
|
|
c | e,
|
|
b | z,
|
|
b | z,
|
|
z | e,
|
|
c | d,
|
|
a | z,
|
|
a | e,
|
|
b | d,
|
|
z | e,
|
|
z | d,
|
|
b | f,
|
|
a | f,
|
|
c | f,
|
|
a | d,
|
|
c | z,
|
|
b | f,
|
|
b | d,
|
|
z | f,
|
|
a | f,
|
|
c | e,
|
|
z | f,
|
|
b | e,
|
|
b | e,
|
|
z | z,
|
|
a | d,
|
|
a | e,
|
|
z | z,
|
|
c | d
|
|
];
|
|
a = 1 << 20;
|
|
b = 1 << 31;
|
|
c = a | b;
|
|
d = 1 << 5;
|
|
e = 1 << 15;
|
|
f = d | e;
|
|
var SP2 = [
|
|
c | f,
|
|
b | e,
|
|
z | e,
|
|
a | f,
|
|
a | z,
|
|
z | d,
|
|
c | d,
|
|
b | f,
|
|
b | d,
|
|
c | f,
|
|
c | e,
|
|
b | z,
|
|
b | e,
|
|
a | z,
|
|
z | d,
|
|
c | d,
|
|
a | e,
|
|
a | d,
|
|
b | f,
|
|
z | z,
|
|
b | z,
|
|
z | e,
|
|
a | f,
|
|
c | z,
|
|
a | d,
|
|
b | d,
|
|
z | z,
|
|
a | e,
|
|
z | f,
|
|
c | e,
|
|
c | z,
|
|
z | f,
|
|
z | z,
|
|
a | f,
|
|
c | d,
|
|
a | z,
|
|
b | f,
|
|
c | z,
|
|
c | e,
|
|
z | e,
|
|
c | z,
|
|
b | e,
|
|
z | d,
|
|
c | f,
|
|
a | f,
|
|
z | d,
|
|
z | e,
|
|
b | z,
|
|
z | f,
|
|
c | e,
|
|
a | z,
|
|
b | d,
|
|
a | d,
|
|
b | f,
|
|
b | d,
|
|
a | d,
|
|
a | e,
|
|
z | z,
|
|
b | e,
|
|
z | f,
|
|
b | z,
|
|
c | d,
|
|
c | f,
|
|
a | e
|
|
];
|
|
a = 1 << 17;
|
|
b = 1 << 27;
|
|
c = a | b;
|
|
d = 1 << 3;
|
|
e = 1 << 9;
|
|
f = d | e;
|
|
var SP3 = [
|
|
z | f,
|
|
c | e,
|
|
z | z,
|
|
c | d,
|
|
b | e,
|
|
z | z,
|
|
a | f,
|
|
b | e,
|
|
a | d,
|
|
b | d,
|
|
b | d,
|
|
a | z,
|
|
c | f,
|
|
a | d,
|
|
c | z,
|
|
z | f,
|
|
b | z,
|
|
z | d,
|
|
c | e,
|
|
z | e,
|
|
a | e,
|
|
c | z,
|
|
c | d,
|
|
a | f,
|
|
b | f,
|
|
a | e,
|
|
a | z,
|
|
b | f,
|
|
z | d,
|
|
c | f,
|
|
z | e,
|
|
b | z,
|
|
c | e,
|
|
b | z,
|
|
a | d,
|
|
z | f,
|
|
a | z,
|
|
c | e,
|
|
b | e,
|
|
z | z,
|
|
z | e,
|
|
a | d,
|
|
c | f,
|
|
b | e,
|
|
b | d,
|
|
z | e,
|
|
z | z,
|
|
c | d,
|
|
b | f,
|
|
a | z,
|
|
b | z,
|
|
c | f,
|
|
z | d,
|
|
a | f,
|
|
a | e,
|
|
b | d,
|
|
c | z,
|
|
b | f,
|
|
z | f,
|
|
c | z,
|
|
a | f,
|
|
z | d,
|
|
c | d,
|
|
a | e
|
|
];
|
|
a = 1 << 13;
|
|
b = 1 << 23;
|
|
c = a | b;
|
|
d = 1 << 0;
|
|
e = 1 << 7;
|
|
f = d | e;
|
|
var SP4 = [
|
|
c | d,
|
|
a | f,
|
|
a | f,
|
|
z | e,
|
|
c | e,
|
|
b | f,
|
|
b | d,
|
|
a | d,
|
|
z | z,
|
|
c | z,
|
|
c | z,
|
|
c | f,
|
|
z | f,
|
|
z | z,
|
|
b | e,
|
|
b | d,
|
|
z | d,
|
|
a | z,
|
|
b | z,
|
|
c | d,
|
|
z | e,
|
|
b | z,
|
|
a | d,
|
|
a | e,
|
|
b | f,
|
|
z | d,
|
|
a | e,
|
|
b | e,
|
|
a | z,
|
|
c | e,
|
|
c | f,
|
|
z | f,
|
|
b | e,
|
|
b | d,
|
|
c | z,
|
|
c | f,
|
|
z | f,
|
|
z | z,
|
|
z | z,
|
|
c | z,
|
|
a | e,
|
|
b | e,
|
|
b | f,
|
|
z | d,
|
|
c | d,
|
|
a | f,
|
|
a | f,
|
|
z | e,
|
|
c | f,
|
|
z | f,
|
|
z | d,
|
|
a | z,
|
|
b | d,
|
|
a | d,
|
|
c | e,
|
|
b | f,
|
|
a | d,
|
|
a | e,
|
|
b | z,
|
|
c | d,
|
|
z | e,
|
|
b | z,
|
|
a | z,
|
|
c | e
|
|
];
|
|
a = 1 << 25;
|
|
b = 1 << 30;
|
|
c = a | b;
|
|
d = 1 << 8;
|
|
e = 1 << 19;
|
|
f = d | e;
|
|
var SP5 = [
|
|
z | d,
|
|
a | f,
|
|
a | e,
|
|
c | d,
|
|
z | e,
|
|
z | d,
|
|
b | z,
|
|
a | e,
|
|
b | f,
|
|
z | e,
|
|
a | d,
|
|
b | f,
|
|
c | d,
|
|
c | e,
|
|
z | f,
|
|
b | z,
|
|
a | z,
|
|
b | e,
|
|
b | e,
|
|
z | z,
|
|
b | d,
|
|
c | f,
|
|
c | f,
|
|
a | d,
|
|
c | e,
|
|
b | d,
|
|
z | z,
|
|
c | z,
|
|
a | f,
|
|
a | z,
|
|
c | z,
|
|
z | f,
|
|
z | e,
|
|
c | d,
|
|
z | d,
|
|
a | z,
|
|
b | z,
|
|
a | e,
|
|
c | d,
|
|
b | f,
|
|
a | d,
|
|
b | z,
|
|
c | e,
|
|
a | f,
|
|
b | f,
|
|
z | d,
|
|
a | z,
|
|
c | e,
|
|
c | f,
|
|
z | f,
|
|
c | z,
|
|
c | f,
|
|
a | e,
|
|
z | z,
|
|
b | e,
|
|
c | z,
|
|
z | f,
|
|
a | d,
|
|
b | d,
|
|
z | e,
|
|
z | z,
|
|
b | e,
|
|
a | f,
|
|
b | d
|
|
];
|
|
a = 1 << 22;
|
|
b = 1 << 29;
|
|
c = a | b;
|
|
d = 1 << 4;
|
|
e = 1 << 14;
|
|
f = d | e;
|
|
var SP6 = [
|
|
b | d,
|
|
c | z,
|
|
z | e,
|
|
c | f,
|
|
c | z,
|
|
z | d,
|
|
c | f,
|
|
a | z,
|
|
b | e,
|
|
a | f,
|
|
a | z,
|
|
b | d,
|
|
a | d,
|
|
b | e,
|
|
b | z,
|
|
z | f,
|
|
z | z,
|
|
a | d,
|
|
b | f,
|
|
z | e,
|
|
a | e,
|
|
b | f,
|
|
z | d,
|
|
c | d,
|
|
c | d,
|
|
z | z,
|
|
a | f,
|
|
c | e,
|
|
z | f,
|
|
a | e,
|
|
c | e,
|
|
b | z,
|
|
b | e,
|
|
z | d,
|
|
c | d,
|
|
a | e,
|
|
c | f,
|
|
a | z,
|
|
z | f,
|
|
b | d,
|
|
a | z,
|
|
b | e,
|
|
b | z,
|
|
z | f,
|
|
b | d,
|
|
c | f,
|
|
a | e,
|
|
c | z,
|
|
a | f,
|
|
c | e,
|
|
z | z,
|
|
c | d,
|
|
z | d,
|
|
z | e,
|
|
c | z,
|
|
a | f,
|
|
z | e,
|
|
a | d,
|
|
b | f,
|
|
z | z,
|
|
c | e,
|
|
b | z,
|
|
a | d,
|
|
b | f
|
|
];
|
|
a = 1 << 21;
|
|
b = 1 << 26;
|
|
c = a | b;
|
|
d = 1 << 1;
|
|
e = 1 << 11;
|
|
f = d | e;
|
|
var SP7 = [
|
|
a | z,
|
|
c | d,
|
|
b | f,
|
|
z | z,
|
|
z | e,
|
|
b | f,
|
|
a | f,
|
|
c | e,
|
|
c | f,
|
|
a | z,
|
|
z | z,
|
|
b | d,
|
|
z | d,
|
|
b | z,
|
|
c | d,
|
|
z | f,
|
|
b | e,
|
|
a | f,
|
|
a | d,
|
|
b | e,
|
|
b | d,
|
|
c | z,
|
|
c | e,
|
|
a | d,
|
|
c | z,
|
|
z | e,
|
|
z | f,
|
|
c | f,
|
|
a | e,
|
|
z | d,
|
|
b | z,
|
|
a | e,
|
|
b | z,
|
|
a | e,
|
|
a | z,
|
|
b | f,
|
|
b | f,
|
|
c | d,
|
|
c | d,
|
|
z | d,
|
|
a | d,
|
|
b | z,
|
|
b | e,
|
|
a | z,
|
|
c | e,
|
|
z | f,
|
|
a | f,
|
|
c | e,
|
|
z | f,
|
|
b | d,
|
|
c | f,
|
|
c | z,
|
|
a | e,
|
|
z | z,
|
|
z | d,
|
|
c | f,
|
|
z | z,
|
|
a | f,
|
|
c | z,
|
|
z | e,
|
|
b | d,
|
|
b | e,
|
|
z | e,
|
|
a | d
|
|
];
|
|
a = 1 << 18;
|
|
b = 1 << 28;
|
|
c = a | b;
|
|
d = 1 << 6;
|
|
e = 1 << 12;
|
|
f = d | e;
|
|
var SP8 = [
|
|
b | f,
|
|
z | e,
|
|
a | z,
|
|
c | f,
|
|
b | z,
|
|
b | f,
|
|
z | d,
|
|
b | z,
|
|
a | d,
|
|
c | z,
|
|
c | f,
|
|
a | e,
|
|
c | e,
|
|
a | f,
|
|
z | e,
|
|
z | d,
|
|
c | z,
|
|
b | d,
|
|
b | e,
|
|
z | f,
|
|
a | e,
|
|
a | d,
|
|
c | d,
|
|
c | e,
|
|
z | f,
|
|
z | z,
|
|
z | z,
|
|
c | d,
|
|
b | d,
|
|
b | e,
|
|
a | f,
|
|
a | z,
|
|
a | f,
|
|
a | z,
|
|
c | e,
|
|
z | e,
|
|
z | d,
|
|
c | d,
|
|
z | e,
|
|
a | f,
|
|
b | e,
|
|
z | d,
|
|
b | d,
|
|
c | z,
|
|
c | d,
|
|
b | z,
|
|
a | z,
|
|
b | f,
|
|
z | z,
|
|
c | f,
|
|
a | d,
|
|
b | d,
|
|
c | z,
|
|
b | e,
|
|
b | f,
|
|
z | z,
|
|
c | f,
|
|
a | e,
|
|
a | e,
|
|
z | f,
|
|
z | f,
|
|
a | d,
|
|
b | z,
|
|
c | e
|
|
];
|
|
var DES = class {
|
|
constructor(password) {
|
|
this.keys = [];
|
|
const pc1m = [], pcr = [], kn = [];
|
|
for (let j = 0, l = 56; j < 56; ++j, l -= 8) {
|
|
l += l < -5 ? 65 : l < -3 ? 31 : l < -1 ? 63 : l === 27 ? 35 : 0;
|
|
const m = l & 7;
|
|
pc1m[j] = (password[l >>> 3] & 1 << m) !== 0 ? 1 : 0;
|
|
}
|
|
for (let i = 0; i < 16; ++i) {
|
|
const m = i << 1;
|
|
const n = m + 1;
|
|
kn[m] = kn[n] = 0;
|
|
for (let o = 28; o < 59; o += 28) {
|
|
for (let j = o - 28; j < o; ++j) {
|
|
const l = j + totrot[i];
|
|
pcr[j] = l < o ? pc1m[l] : pc1m[l - 28];
|
|
}
|
|
}
|
|
for (let j = 0; j < 24; ++j) {
|
|
if (pcr[PC2[j]] !== 0) {
|
|
kn[m] |= 1 << 23 - j;
|
|
}
|
|
if (pcr[PC2[j + 24]] !== 0) {
|
|
kn[n] |= 1 << 23 - j;
|
|
}
|
|
}
|
|
}
|
|
for (let i = 0, rawi = 0, KnLi = 0; i < 16; ++i) {
|
|
const raw0 = kn[rawi++];
|
|
const raw1 = kn[rawi++];
|
|
this.keys[KnLi] = (raw0 & 16515072) << 6;
|
|
this.keys[KnLi] |= (raw0 & 4032) << 10;
|
|
this.keys[KnLi] |= (raw1 & 16515072) >>> 10;
|
|
this.keys[KnLi] |= (raw1 & 4032) >>> 6;
|
|
++KnLi;
|
|
this.keys[KnLi] = (raw0 & 258048) << 12;
|
|
this.keys[KnLi] |= (raw0 & 63) << 16;
|
|
this.keys[KnLi] |= (raw1 & 258048) >>> 4;
|
|
this.keys[KnLi] |= raw1 & 63;
|
|
++KnLi;
|
|
}
|
|
}
|
|
// Encrypt 8 bytes of text
|
|
enc8(text) {
|
|
const b2 = text.slice();
|
|
let l, r, x;
|
|
l = b2[0] << 24 | b2[1] << 16 | b2[2] << 8 | b2[3];
|
|
r = b2[4] << 24 | b2[5] << 16 | b2[6] << 8 | b2[7];
|
|
x = (l >>> 4 ^ r) & 252645135;
|
|
r ^= x;
|
|
l ^= x << 4;
|
|
x = (l >>> 16 ^ r) & 65535;
|
|
r ^= x;
|
|
l ^= x << 16;
|
|
x = (r >>> 2 ^ l) & 858993459;
|
|
l ^= x;
|
|
r ^= x << 2;
|
|
x = (r >>> 8 ^ l) & 16711935;
|
|
l ^= x;
|
|
r ^= x << 8;
|
|
r = r << 1 | r >>> 31 & 1;
|
|
x = (l ^ r) & 2863311530;
|
|
l ^= x;
|
|
r ^= x;
|
|
l = l << 1 | l >>> 31 & 1;
|
|
for (let i = 0, keysi = 0; i < 8; ++i) {
|
|
x = r << 28 | r >>> 4;
|
|
x ^= this.keys[keysi++];
|
|
let fval = SP7[x & 63];
|
|
fval |= SP5[x >>> 8 & 63];
|
|
fval |= SP3[x >>> 16 & 63];
|
|
fval |= SP1[x >>> 24 & 63];
|
|
x = r ^ this.keys[keysi++];
|
|
fval |= SP8[x & 63];
|
|
fval |= SP6[x >>> 8 & 63];
|
|
fval |= SP4[x >>> 16 & 63];
|
|
fval |= SP2[x >>> 24 & 63];
|
|
l ^= fval;
|
|
x = l << 28 | l >>> 4;
|
|
x ^= this.keys[keysi++];
|
|
fval = SP7[x & 63];
|
|
fval |= SP5[x >>> 8 & 63];
|
|
fval |= SP3[x >>> 16 & 63];
|
|
fval |= SP1[x >>> 24 & 63];
|
|
x = l ^ this.keys[keysi++];
|
|
fval |= SP8[x & 63];
|
|
fval |= SP6[x >>> 8 & 63];
|
|
fval |= SP4[x >>> 16 & 63];
|
|
fval |= SP2[x >>> 24 & 63];
|
|
r ^= fval;
|
|
}
|
|
r = r << 31 | r >>> 1;
|
|
x = (l ^ r) & 2863311530;
|
|
l ^= x;
|
|
r ^= x;
|
|
l = l << 31 | l >>> 1;
|
|
x = (l >>> 8 ^ r) & 16711935;
|
|
r ^= x;
|
|
l ^= x << 8;
|
|
x = (l >>> 2 ^ r) & 858993459;
|
|
r ^= x;
|
|
l ^= x << 2;
|
|
x = (r >>> 16 ^ l) & 65535;
|
|
l ^= x;
|
|
r ^= x << 16;
|
|
x = (r >>> 4 ^ l) & 252645135;
|
|
l ^= x;
|
|
r ^= x << 4;
|
|
x = [r, l];
|
|
for (let i = 0; i < 8; i++) {
|
|
b2[i] = (x[i >>> 2] >>> 8 * (3 - i % 4)) % 256;
|
|
if (b2[i] < 0) {
|
|
b2[i] += 256;
|
|
}
|
|
}
|
|
return b2;
|
|
}
|
|
};
|
|
var DESECBCipher = class _DESECBCipher {
|
|
constructor() {
|
|
this._cipher = null;
|
|
}
|
|
get algorithm() {
|
|
return { name: "DES-ECB" };
|
|
}
|
|
static importKey(key, _algorithm, _extractable, _keyUsages) {
|
|
const cipher = new _DESECBCipher();
|
|
cipher._importKey(key);
|
|
return cipher;
|
|
}
|
|
_importKey(key, _extractable, _keyUsages) {
|
|
this._cipher = new DES(key);
|
|
}
|
|
encrypt(_algorithm, plaintext) {
|
|
const x = new Uint8Array(plaintext);
|
|
if (x.length % 8 !== 0 || this._cipher === null) {
|
|
return null;
|
|
}
|
|
const n = x.length / 8;
|
|
for (let i = 0; i < n; i++) {
|
|
x.set(this._cipher.enc8(x.slice(i * 8, i * 8 + 8)), i * 8);
|
|
}
|
|
return x;
|
|
}
|
|
};
|
|
var DESCBCCipher = class _DESCBCCipher {
|
|
constructor() {
|
|
this._cipher = null;
|
|
}
|
|
get algorithm() {
|
|
return { name: "DES-CBC" };
|
|
}
|
|
static importKey(key, _algorithm, _extractable, _keyUsages) {
|
|
const cipher = new _DESCBCCipher();
|
|
cipher._importKey(key);
|
|
return cipher;
|
|
}
|
|
_importKey(key) {
|
|
this._cipher = new DES(key);
|
|
}
|
|
encrypt(algorithm, plaintext) {
|
|
const x = new Uint8Array(plaintext);
|
|
let y = new Uint8Array(algorithm.iv);
|
|
if (x.length % 8 !== 0 || this._cipher === null) {
|
|
return null;
|
|
}
|
|
const n = x.length / 8;
|
|
for (let i = 0; i < n; i++) {
|
|
for (let j = 0; j < 8; j++) {
|
|
y[j] ^= plaintext[i * 8 + j];
|
|
}
|
|
y = this._cipher.enc8(y);
|
|
x.set(y, i * 8);
|
|
}
|
|
return x;
|
|
}
|
|
};
|
|
|
|
// core/crypto/bigint.js
|
|
function modPow(b2, e2, m) {
|
|
let r = 1n;
|
|
b2 = b2 % m;
|
|
while (e2 > 0n) {
|
|
if ((e2 & 1n) === 1n) {
|
|
r = r * b2 % m;
|
|
}
|
|
e2 = e2 >> 1n;
|
|
b2 = b2 * b2 % m;
|
|
}
|
|
return r;
|
|
}
|
|
function bigIntToU8Array(bigint, padLength = 0) {
|
|
let hex = bigint.toString(16);
|
|
if (padLength === 0) {
|
|
padLength = Math.ceil(hex.length / 2);
|
|
}
|
|
hex = hex.padStart(padLength * 2, "0");
|
|
const length = hex.length / 2;
|
|
const arr = new Uint8Array(length);
|
|
for (let i = 0; i < length; i++) {
|
|
arr[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16);
|
|
}
|
|
return arr;
|
|
}
|
|
function u8ArrayToBigInt(arr) {
|
|
let hex = "0x";
|
|
for (let i = 0; i < arr.length; i++) {
|
|
hex += arr[i].toString(16).padStart(2, "0");
|
|
}
|
|
return BigInt(hex);
|
|
}
|
|
|
|
// core/crypto/rsa.js
|
|
var RSACipher = class _RSACipher {
|
|
constructor() {
|
|
this._keyLength = 0;
|
|
this._keyBytes = 0;
|
|
this._n = null;
|
|
this._e = null;
|
|
this._d = null;
|
|
this._nBigInt = null;
|
|
this._eBigInt = null;
|
|
this._dBigInt = null;
|
|
this._extractable = false;
|
|
}
|
|
get algorithm() {
|
|
return { name: "RSA-PKCS1-v1_5" };
|
|
}
|
|
_base64urlDecode(data) {
|
|
data = data.replace(/-/g, "+").replace(/_/g, "/");
|
|
data = data.padEnd(Math.ceil(data.length / 4) * 4, "=");
|
|
return base64_default.decode(data);
|
|
}
|
|
_padArray(arr, length) {
|
|
const res = new Uint8Array(length);
|
|
res.set(arr, length - arr.length);
|
|
return res;
|
|
}
|
|
static async generateKey(algorithm, extractable, _keyUsages) {
|
|
const cipher = new _RSACipher();
|
|
await cipher._generateKey(algorithm, extractable);
|
|
return { privateKey: cipher };
|
|
}
|
|
async _generateKey(algorithm, extractable) {
|
|
this._keyLength = algorithm.modulusLength;
|
|
this._keyBytes = Math.ceil(this._keyLength / 8);
|
|
const key = await window.crypto.subtle.generateKey(
|
|
{
|
|
name: "RSA-OAEP",
|
|
modulusLength: algorithm.modulusLength,
|
|
publicExponent: algorithm.publicExponent,
|
|
hash: { name: "SHA-256" }
|
|
},
|
|
true,
|
|
["encrypt", "decrypt"]
|
|
);
|
|
const privateKey = await window.crypto.subtle.exportKey("jwk", key.privateKey);
|
|
this._n = this._padArray(this._base64urlDecode(privateKey.n), this._keyBytes);
|
|
this._nBigInt = u8ArrayToBigInt(this._n);
|
|
this._e = this._padArray(this._base64urlDecode(privateKey.e), this._keyBytes);
|
|
this._eBigInt = u8ArrayToBigInt(this._e);
|
|
this._d = this._padArray(this._base64urlDecode(privateKey.d), this._keyBytes);
|
|
this._dBigInt = u8ArrayToBigInt(this._d);
|
|
this._extractable = extractable;
|
|
}
|
|
static async importKey(key, _algorithm, extractable, keyUsages) {
|
|
if (keyUsages.length !== 1 || keyUsages[0] !== "encrypt") {
|
|
throw new Error("only support importing RSA public key");
|
|
}
|
|
const cipher = new _RSACipher();
|
|
await cipher._importKey(key, extractable);
|
|
return cipher;
|
|
}
|
|
async _importKey(key, extractable) {
|
|
const n = key.n;
|
|
const e2 = key.e;
|
|
if (n.length !== e2.length) {
|
|
throw new Error("the sizes of modulus and public exponent do not match");
|
|
}
|
|
this._keyBytes = n.length;
|
|
this._keyLength = this._keyBytes * 8;
|
|
this._n = new Uint8Array(this._keyBytes);
|
|
this._e = new Uint8Array(this._keyBytes);
|
|
this._n.set(n);
|
|
this._e.set(e2);
|
|
this._nBigInt = u8ArrayToBigInt(this._n);
|
|
this._eBigInt = u8ArrayToBigInt(this._e);
|
|
this._extractable = extractable;
|
|
}
|
|
async encrypt(_algorithm, message) {
|
|
if (message.length > this._keyBytes - 11) {
|
|
return null;
|
|
}
|
|
const ps = new Uint8Array(this._keyBytes - message.length - 3);
|
|
window.crypto.getRandomValues(ps);
|
|
for (let i = 0; i < ps.length; i++) {
|
|
ps[i] = Math.floor(ps[i] * 254 / 255 + 1);
|
|
}
|
|
const em = new Uint8Array(this._keyBytes);
|
|
em[1] = 2;
|
|
em.set(ps, 2);
|
|
em.set(message, ps.length + 3);
|
|
const emBigInt = u8ArrayToBigInt(em);
|
|
const c2 = modPow(emBigInt, this._eBigInt, this._nBigInt);
|
|
return bigIntToU8Array(c2, this._keyBytes);
|
|
}
|
|
async decrypt(_algorithm, message) {
|
|
if (message.length !== this._keyBytes) {
|
|
return null;
|
|
}
|
|
const msgBigInt = u8ArrayToBigInt(message);
|
|
const emBigInt = modPow(msgBigInt, this._dBigInt, this._nBigInt);
|
|
const em = bigIntToU8Array(emBigInt, this._keyBytes);
|
|
if (em[0] !== 0 || em[1] !== 2) {
|
|
return null;
|
|
}
|
|
let i = 2;
|
|
for (; i < em.length; i++) {
|
|
if (em[i] === 0) {
|
|
break;
|
|
}
|
|
}
|
|
if (i === em.length) {
|
|
return null;
|
|
}
|
|
return em.slice(i + 1, em.length);
|
|
}
|
|
async exportKey() {
|
|
if (!this._extractable) {
|
|
throw new Error("key is not extractable");
|
|
}
|
|
return { n: this._n, e: this._e, d: this._d };
|
|
}
|
|
};
|
|
|
|
// core/crypto/dh.js
|
|
var DHPublicKey = class {
|
|
constructor(key) {
|
|
this._key = key;
|
|
}
|
|
get algorithm() {
|
|
return { name: "DH" };
|
|
}
|
|
exportKey() {
|
|
return this._key;
|
|
}
|
|
};
|
|
var DHCipher = class _DHCipher {
|
|
constructor() {
|
|
this._g = null;
|
|
this._p = null;
|
|
this._gBigInt = null;
|
|
this._pBigInt = null;
|
|
this._privateKey = null;
|
|
}
|
|
get algorithm() {
|
|
return { name: "DH" };
|
|
}
|
|
static generateKey(algorithm, _extractable) {
|
|
const cipher = new _DHCipher();
|
|
cipher._generateKey(algorithm);
|
|
return { privateKey: cipher, publicKey: new DHPublicKey(cipher._publicKey) };
|
|
}
|
|
_generateKey(algorithm) {
|
|
const g = algorithm.g;
|
|
const p = algorithm.p;
|
|
this._keyBytes = p.length;
|
|
this._gBigInt = u8ArrayToBigInt(g);
|
|
this._pBigInt = u8ArrayToBigInt(p);
|
|
this._privateKey = window.crypto.getRandomValues(new Uint8Array(this._keyBytes));
|
|
this._privateKeyBigInt = u8ArrayToBigInt(this._privateKey);
|
|
this._publicKey = bigIntToU8Array(modPow(
|
|
this._gBigInt,
|
|
this._privateKeyBigInt,
|
|
this._pBigInt
|
|
), this._keyBytes);
|
|
}
|
|
deriveBits(algorithm, length) {
|
|
const bytes = Math.ceil(length / 8);
|
|
const pkey = new Uint8Array(algorithm.public);
|
|
const len = bytes > this._keyBytes ? bytes : this._keyBytes;
|
|
const secret = modPow(u8ArrayToBigInt(pkey), this._privateKeyBigInt, this._pBigInt);
|
|
return bigIntToU8Array(secret, len).slice(0, len);
|
|
}
|
|
};
|
|
|
|
// core/crypto/md5.js
|
|
async function MD5(d2) {
|
|
let s = "";
|
|
for (let i = 0; i < d2.length; i++) {
|
|
s += String.fromCharCode(d2[i]);
|
|
}
|
|
return M(V(Y(X(s), 8 * s.length)));
|
|
}
|
|
function M(d2) {
|
|
let f2 = new Uint8Array(d2.length);
|
|
for (let i = 0; i < d2.length; i++) {
|
|
f2[i] = d2.charCodeAt(i);
|
|
}
|
|
return f2;
|
|
}
|
|
function X(d2) {
|
|
let r = Array(d2.length >> 2);
|
|
for (let m = 0; m < r.length; m++) r[m] = 0;
|
|
for (let m = 0; m < 8 * d2.length; m += 8) r[m >> 5] |= (255 & d2.charCodeAt(m / 8)) << m % 32;
|
|
return r;
|
|
}
|
|
function V(d2) {
|
|
let r = "";
|
|
for (let m = 0; m < 32 * d2.length; m += 8) r += String.fromCharCode(d2[m >> 5] >>> m % 32 & 255);
|
|
return r;
|
|
}
|
|
function Y(d2, g) {
|
|
d2[g >> 5] |= 128 << g % 32, d2[14 + (g + 64 >>> 9 << 4)] = g;
|
|
let m = 1732584193, f2 = -271733879, r = -1732584194, i = 271733878;
|
|
for (let n = 0; n < d2.length; n += 16) {
|
|
let h = m, t = f2, g2 = r, e2 = i;
|
|
f2 = ii(f2 = ii(f2 = ii(f2 = ii(f2 = hh(f2 = hh(f2 = hh(f2 = hh(f2 = gg(f2 = gg(f2 = gg(f2 = gg(f2 = ff(f2 = ff(f2 = ff(f2 = ff(f2, r = ff(r, i = ff(i, m = ff(m, f2, r, i, d2[n + 0], 7, -680876936), f2, r, d2[n + 1], 12, -389564586), m, f2, d2[n + 2], 17, 606105819), i, m, d2[n + 3], 22, -1044525330), r = ff(r, i = ff(i, m = ff(m, f2, r, i, d2[n + 4], 7, -176418897), f2, r, d2[n + 5], 12, 1200080426), m, f2, d2[n + 6], 17, -1473231341), i, m, d2[n + 7], 22, -45705983), r = ff(r, i = ff(i, m = ff(m, f2, r, i, d2[n + 8], 7, 1770035416), f2, r, d2[n + 9], 12, -1958414417), m, f2, d2[n + 10], 17, -42063), i, m, d2[n + 11], 22, -1990404162), r = ff(r, i = ff(i, m = ff(m, f2, r, i, d2[n + 12], 7, 1804603682), f2, r, d2[n + 13], 12, -40341101), m, f2, d2[n + 14], 17, -1502002290), i, m, d2[n + 15], 22, 1236535329), r = gg(r, i = gg(i, m = gg(m, f2, r, i, d2[n + 1], 5, -165796510), f2, r, d2[n + 6], 9, -1069501632), m, f2, d2[n + 11], 14, 643717713), i, m, d2[n + 0], 20, -373897302), r = gg(r, i = gg(i, m = gg(m, f2, r, i, d2[n + 5], 5, -701558691), f2, r, d2[n + 10], 9, 38016083), m, f2, d2[n + 15], 14, -660478335), i, m, d2[n + 4], 20, -405537848), r = gg(r, i = gg(i, m = gg(m, f2, r, i, d2[n + 9], 5, 568446438), f2, r, d2[n + 14], 9, -1019803690), m, f2, d2[n + 3], 14, -187363961), i, m, d2[n + 8], 20, 1163531501), r = gg(r, i = gg(i, m = gg(m, f2, r, i, d2[n + 13], 5, -1444681467), f2, r, d2[n + 2], 9, -51403784), m, f2, d2[n + 7], 14, 1735328473), i, m, d2[n + 12], 20, -1926607734), r = hh(r, i = hh(i, m = hh(m, f2, r, i, d2[n + 5], 4, -378558), f2, r, d2[n + 8], 11, -2022574463), m, f2, d2[n + 11], 16, 1839030562), i, m, d2[n + 14], 23, -35309556), r = hh(r, i = hh(i, m = hh(m, f2, r, i, d2[n + 1], 4, -1530992060), f2, r, d2[n + 4], 11, 1272893353), m, f2, d2[n + 7], 16, -155497632), i, m, d2[n + 10], 23, -1094730640), r = hh(r, i = hh(i, m = hh(m, f2, r, i, d2[n + 13], 4, 681279174), f2, r, d2[n + 0], 11, -358537222), m, f2, d2[n + 3], 16, -722521979), i, m, d2[n + 6], 23, 76029189), r = hh(r, i = hh(i, m = hh(m, f2, r, i, d2[n + 9], 4, -640364487), f2, r, d2[n + 12], 11, -421815835), m, f2, d2[n + 15], 16, 530742520), i, m, d2[n + 2], 23, -995338651), r = ii(r, i = ii(i, m = ii(m, f2, r, i, d2[n + 0], 6, -198630844), f2, r, d2[n + 7], 10, 1126891415), m, f2, d2[n + 14], 15, -1416354905), i, m, d2[n + 5], 21, -57434055), r = ii(r, i = ii(i, m = ii(m, f2, r, i, d2[n + 12], 6, 1700485571), f2, r, d2[n + 3], 10, -1894986606), m, f2, d2[n + 10], 15, -1051523), i, m, d2[n + 1], 21, -2054922799), r = ii(r, i = ii(i, m = ii(m, f2, r, i, d2[n + 8], 6, 1873313359), f2, r, d2[n + 15], 10, -30611744), m, f2, d2[n + 6], 15, -1560198380), i, m, d2[n + 13], 21, 1309151649), r = ii(r, i = ii(i, m = ii(m, f2, r, i, d2[n + 4], 6, -145523070), f2, r, d2[n + 11], 10, -1120210379), m, f2, d2[n + 2], 15, 718787259), i, m, d2[n + 9], 21, -343485551), m = add(m, h), f2 = add(f2, t), r = add(r, g2), i = add(i, e2);
|
|
}
|
|
return Array(m, f2, r, i);
|
|
}
|
|
function cmn(d2, g, m, f2, r, i) {
|
|
return add(rol(add(add(g, d2), add(f2, i)), r), m);
|
|
}
|
|
function ff(d2, g, m, f2, r, i, n) {
|
|
return cmn(g & m | ~g & f2, d2, g, r, i, n);
|
|
}
|
|
function gg(d2, g, m, f2, r, i, n) {
|
|
return cmn(g & f2 | m & ~f2, d2, g, r, i, n);
|
|
}
|
|
function hh(d2, g, m, f2, r, i, n) {
|
|
return cmn(g ^ m ^ f2, d2, g, r, i, n);
|
|
}
|
|
function ii(d2, g, m, f2, r, i, n) {
|
|
return cmn(m ^ (g | ~f2), d2, g, r, i, n);
|
|
}
|
|
function add(d2, g) {
|
|
let m = (65535 & d2) + (65535 & g);
|
|
return (d2 >> 16) + (g >> 16) + (m >> 16) << 16 | 65535 & m;
|
|
}
|
|
function rol(d2, g) {
|
|
return d2 << g | d2 >>> 32 - g;
|
|
}
|
|
|
|
// core/crypto/crypto.js
|
|
var LegacyCrypto = class {
|
|
constructor() {
|
|
this._algorithms = {
|
|
"AES-ECB": AESECBCipher,
|
|
"AES-EAX": AESEAXCipher,
|
|
"DES-ECB": DESECBCipher,
|
|
"DES-CBC": DESCBCCipher,
|
|
"RSA-PKCS1-v1_5": RSACipher,
|
|
"DH": DHCipher,
|
|
"MD5": MD5
|
|
};
|
|
}
|
|
encrypt(algorithm, key, data) {
|
|
if (key.algorithm.name !== algorithm.name) {
|
|
throw new Error("algorithm does not match");
|
|
}
|
|
if (typeof key.encrypt !== "function") {
|
|
throw new Error("key does not support encryption");
|
|
}
|
|
return key.encrypt(algorithm, data);
|
|
}
|
|
decrypt(algorithm, key, data) {
|
|
if (key.algorithm.name !== algorithm.name) {
|
|
throw new Error("algorithm does not match");
|
|
}
|
|
if (typeof key.decrypt !== "function") {
|
|
throw new Error("key does not support encryption");
|
|
}
|
|
return key.decrypt(algorithm, data);
|
|
}
|
|
importKey(format, keyData, algorithm, extractable, keyUsages) {
|
|
if (format !== "raw") {
|
|
throw new Error("key format is not supported");
|
|
}
|
|
const alg = this._algorithms[algorithm.name];
|
|
if (typeof alg === "undefined" || typeof alg.importKey !== "function") {
|
|
throw new Error("algorithm is not supported");
|
|
}
|
|
return alg.importKey(keyData, algorithm, extractable, keyUsages);
|
|
}
|
|
generateKey(algorithm, extractable, keyUsages) {
|
|
const alg = this._algorithms[algorithm.name];
|
|
if (typeof alg === "undefined" || typeof alg.generateKey !== "function") {
|
|
throw new Error("algorithm is not supported");
|
|
}
|
|
return alg.generateKey(algorithm, extractable, keyUsages);
|
|
}
|
|
exportKey(format, key) {
|
|
if (format !== "raw") {
|
|
throw new Error("key format is not supported");
|
|
}
|
|
if (typeof key.exportKey !== "function") {
|
|
throw new Error("key does not support exportKey");
|
|
}
|
|
return key.exportKey();
|
|
}
|
|
digest(algorithm, data) {
|
|
const alg = this._algorithms[algorithm];
|
|
if (typeof alg !== "function") {
|
|
throw new Error("algorithm is not supported");
|
|
}
|
|
return alg(data);
|
|
}
|
|
deriveBits(algorithm, key, length) {
|
|
if (key.algorithm.name !== algorithm.name) {
|
|
throw new Error("algorithm does not match");
|
|
}
|
|
if (typeof key.deriveBits !== "function") {
|
|
throw new Error("key does not support deriveBits");
|
|
}
|
|
return key.deriveBits(algorithm, length);
|
|
}
|
|
};
|
|
var crypto_default = new LegacyCrypto();
|
|
|
|
// core/ra2.js
|
|
var RA2Cipher = class {
|
|
constructor() {
|
|
this._cipher = null;
|
|
this._counter = new Uint8Array(16);
|
|
}
|
|
async setKey(key) {
|
|
this._cipher = await crypto_default.importKey(
|
|
"raw",
|
|
key,
|
|
{ name: "AES-EAX" },
|
|
false,
|
|
["encrypt, decrypt"]
|
|
);
|
|
}
|
|
async makeMessage(message) {
|
|
const ad = new Uint8Array([(message.length & 65280) >>> 8, message.length & 255]);
|
|
const encrypted = await crypto_default.encrypt({
|
|
name: "AES-EAX",
|
|
iv: this._counter,
|
|
additionalData: ad
|
|
}, this._cipher, message);
|
|
for (let i = 0; i < 16 && this._counter[i]++ === 255; i++) ;
|
|
const res = new Uint8Array(message.length + 2 + 16);
|
|
res.set(ad);
|
|
res.set(encrypted, 2);
|
|
return res;
|
|
}
|
|
async receiveMessage(length, encrypted) {
|
|
const ad = new Uint8Array([(length & 65280) >>> 8, length & 255]);
|
|
const res = await crypto_default.decrypt({
|
|
name: "AES-EAX",
|
|
iv: this._counter,
|
|
additionalData: ad
|
|
}, this._cipher, encrypted);
|
|
for (let i = 0; i < 16 && this._counter[i]++ === 255; i++) ;
|
|
return res;
|
|
}
|
|
};
|
|
var RSAAESAuthenticationState = class extends EventTargetMixin {
|
|
constructor(sock, getCredentials) {
|
|
super();
|
|
this._hasStarted = false;
|
|
this._checkSock = null;
|
|
this._checkCredentials = null;
|
|
this._approveServerResolve = null;
|
|
this._sockReject = null;
|
|
this._credentialsReject = null;
|
|
this._approveServerReject = null;
|
|
this._sock = sock;
|
|
this._getCredentials = getCredentials;
|
|
}
|
|
_waitSockAsync(len) {
|
|
return new Promise((resolve, reject) => {
|
|
const hasData = () => !this._sock.rQwait("RA2", len);
|
|
if (hasData()) {
|
|
resolve();
|
|
} else {
|
|
this._checkSock = () => {
|
|
if (hasData()) {
|
|
resolve();
|
|
this._checkSock = null;
|
|
this._sockReject = null;
|
|
}
|
|
};
|
|
this._sockReject = reject;
|
|
}
|
|
});
|
|
}
|
|
_waitApproveKeyAsync() {
|
|
return new Promise((resolve, reject) => {
|
|
this._approveServerResolve = resolve;
|
|
this._approveServerReject = reject;
|
|
});
|
|
}
|
|
_waitCredentialsAsync(subtype) {
|
|
const hasCredentials = () => {
|
|
if (subtype === 1 && this._getCredentials().username !== void 0 && this._getCredentials().password !== void 0) {
|
|
return true;
|
|
} else if (subtype === 2 && this._getCredentials().password !== void 0) {
|
|
return true;
|
|
}
|
|
return false;
|
|
};
|
|
return new Promise((resolve, reject) => {
|
|
if (hasCredentials()) {
|
|
resolve();
|
|
} else {
|
|
this._checkCredentials = () => {
|
|
if (hasCredentials()) {
|
|
resolve();
|
|
this._checkCredentials = null;
|
|
this._credentialsReject = null;
|
|
}
|
|
};
|
|
this._credentialsReject = reject;
|
|
}
|
|
});
|
|
}
|
|
checkInternalEvents() {
|
|
if (this._checkSock !== null) {
|
|
this._checkSock();
|
|
}
|
|
if (this._checkCredentials !== null) {
|
|
this._checkCredentials();
|
|
}
|
|
}
|
|
approveServer() {
|
|
if (this._approveServerResolve !== null) {
|
|
this._approveServerResolve();
|
|
this._approveServerResolve = null;
|
|
}
|
|
}
|
|
disconnect() {
|
|
if (this._sockReject !== null) {
|
|
this._sockReject(new Error("disconnect normally"));
|
|
this._sockReject = null;
|
|
}
|
|
if (this._credentialsReject !== null) {
|
|
this._credentialsReject(new Error("disconnect normally"));
|
|
this._credentialsReject = null;
|
|
}
|
|
if (this._approveServerReject !== null) {
|
|
this._approveServerReject(new Error("disconnect normally"));
|
|
this._approveServerReject = null;
|
|
}
|
|
}
|
|
async negotiateRA2neAuthAsync() {
|
|
this._hasStarted = true;
|
|
await this._waitSockAsync(4);
|
|
const serverKeyLengthBuffer = this._sock.rQpeekBytes(4);
|
|
const serverKeyLength = this._sock.rQshift32();
|
|
if (serverKeyLength < 1024) {
|
|
throw new Error("RA2: server public key is too short: " + serverKeyLength);
|
|
} else if (serverKeyLength > 8192) {
|
|
throw new Error("RA2: server public key is too long: " + serverKeyLength);
|
|
}
|
|
const serverKeyBytes = Math.ceil(serverKeyLength / 8);
|
|
await this._waitSockAsync(serverKeyBytes * 2);
|
|
const serverN = this._sock.rQshiftBytes(serverKeyBytes);
|
|
const serverE = this._sock.rQshiftBytes(serverKeyBytes);
|
|
const serverRSACipher = await crypto_default.importKey(
|
|
"raw",
|
|
{ n: serverN, e: serverE },
|
|
{ name: "RSA-PKCS1-v1_5" },
|
|
false,
|
|
["encrypt"]
|
|
);
|
|
const serverPublickey = new Uint8Array(4 + serverKeyBytes * 2);
|
|
serverPublickey.set(serverKeyLengthBuffer);
|
|
serverPublickey.set(serverN, 4);
|
|
serverPublickey.set(serverE, 4 + serverKeyBytes);
|
|
let approveKey = this._waitApproveKeyAsync();
|
|
this.dispatchEvent(new CustomEvent("serververification", {
|
|
detail: { type: "RSA", publickey: serverPublickey }
|
|
}));
|
|
await approveKey;
|
|
const clientKeyLength = 2048;
|
|
const clientKeyBytes = Math.ceil(clientKeyLength / 8);
|
|
const clientRSACipher = (await crypto_default.generateKey({
|
|
name: "RSA-PKCS1-v1_5",
|
|
modulusLength: clientKeyLength,
|
|
publicExponent: new Uint8Array([1, 0, 1])
|
|
}, true, ["encrypt"])).privateKey;
|
|
const clientExportedRSAKey = await crypto_default.exportKey("raw", clientRSACipher);
|
|
const clientN = clientExportedRSAKey.n;
|
|
const clientE = clientExportedRSAKey.e;
|
|
const clientPublicKey = new Uint8Array(4 + clientKeyBytes * 2);
|
|
clientPublicKey[0] = (clientKeyLength & 4278190080) >>> 24;
|
|
clientPublicKey[1] = (clientKeyLength & 16711680) >>> 16;
|
|
clientPublicKey[2] = (clientKeyLength & 65280) >>> 8;
|
|
clientPublicKey[3] = clientKeyLength & 255;
|
|
clientPublicKey.set(clientN, 4);
|
|
clientPublicKey.set(clientE, 4 + clientKeyBytes);
|
|
this._sock.sQpushBytes(clientPublicKey);
|
|
this._sock.flush();
|
|
const clientRandom = new Uint8Array(16);
|
|
window.crypto.getRandomValues(clientRandom);
|
|
const clientEncryptedRandom = await crypto_default.encrypt(
|
|
{ name: "RSA-PKCS1-v1_5" },
|
|
serverRSACipher,
|
|
clientRandom
|
|
);
|
|
const clientRandomMessage = new Uint8Array(2 + serverKeyBytes);
|
|
clientRandomMessage[0] = (serverKeyBytes & 65280) >>> 8;
|
|
clientRandomMessage[1] = serverKeyBytes & 255;
|
|
clientRandomMessage.set(clientEncryptedRandom, 2);
|
|
this._sock.sQpushBytes(clientRandomMessage);
|
|
this._sock.flush();
|
|
await this._waitSockAsync(2);
|
|
if (this._sock.rQshift16() !== clientKeyBytes) {
|
|
throw new Error("RA2: wrong encrypted message length");
|
|
}
|
|
const serverEncryptedRandom = this._sock.rQshiftBytes(clientKeyBytes);
|
|
const serverRandom = await crypto_default.decrypt(
|
|
{ name: "RSA-PKCS1-v1_5" },
|
|
clientRSACipher,
|
|
serverEncryptedRandom
|
|
);
|
|
if (serverRandom === null || serverRandom.length !== 16) {
|
|
throw new Error("RA2: corrupted server encrypted random");
|
|
}
|
|
let clientSessionKey = new Uint8Array(32);
|
|
let serverSessionKey = new Uint8Array(32);
|
|
clientSessionKey.set(serverRandom);
|
|
clientSessionKey.set(clientRandom, 16);
|
|
serverSessionKey.set(clientRandom);
|
|
serverSessionKey.set(serverRandom, 16);
|
|
clientSessionKey = await window.crypto.subtle.digest("SHA-1", clientSessionKey);
|
|
clientSessionKey = new Uint8Array(clientSessionKey).slice(0, 16);
|
|
serverSessionKey = await window.crypto.subtle.digest("SHA-1", serverSessionKey);
|
|
serverSessionKey = new Uint8Array(serverSessionKey).slice(0, 16);
|
|
const clientCipher = new RA2Cipher();
|
|
await clientCipher.setKey(clientSessionKey);
|
|
const serverCipher = new RA2Cipher();
|
|
await serverCipher.setKey(serverSessionKey);
|
|
let serverHash = new Uint8Array(8 + serverKeyBytes * 2 + clientKeyBytes * 2);
|
|
let clientHash = new Uint8Array(8 + serverKeyBytes * 2 + clientKeyBytes * 2);
|
|
serverHash.set(serverPublickey);
|
|
serverHash.set(clientPublicKey, 4 + serverKeyBytes * 2);
|
|
clientHash.set(clientPublicKey);
|
|
clientHash.set(serverPublickey, 4 + clientKeyBytes * 2);
|
|
serverHash = await window.crypto.subtle.digest("SHA-1", serverHash);
|
|
clientHash = await window.crypto.subtle.digest("SHA-1", clientHash);
|
|
serverHash = new Uint8Array(serverHash);
|
|
clientHash = new Uint8Array(clientHash);
|
|
this._sock.sQpushBytes(await clientCipher.makeMessage(clientHash));
|
|
this._sock.flush();
|
|
await this._waitSockAsync(2 + 20 + 16);
|
|
if (this._sock.rQshift16() !== 20) {
|
|
throw new Error("RA2: wrong server hash");
|
|
}
|
|
const serverHashReceived = await serverCipher.receiveMessage(
|
|
20,
|
|
this._sock.rQshiftBytes(20 + 16)
|
|
);
|
|
if (serverHashReceived === null) {
|
|
throw new Error("RA2: failed to authenticate the message");
|
|
}
|
|
for (let i = 0; i < 20; i++) {
|
|
if (serverHashReceived[i] !== serverHash[i]) {
|
|
throw new Error("RA2: wrong server hash");
|
|
}
|
|
}
|
|
await this._waitSockAsync(2 + 1 + 16);
|
|
if (this._sock.rQshift16() !== 1) {
|
|
throw new Error("RA2: wrong subtype");
|
|
}
|
|
let subtype = await serverCipher.receiveMessage(
|
|
1,
|
|
this._sock.rQshiftBytes(1 + 16)
|
|
);
|
|
if (subtype === null) {
|
|
throw new Error("RA2: failed to authenticate the message");
|
|
}
|
|
subtype = subtype[0];
|
|
let waitCredentials = this._waitCredentialsAsync(subtype);
|
|
if (subtype === 1) {
|
|
if (this._getCredentials().username === void 0 || this._getCredentials().password === void 0) {
|
|
this.dispatchEvent(new CustomEvent(
|
|
"credentialsrequired",
|
|
{ detail: { types: ["username", "password"] } }
|
|
));
|
|
}
|
|
} else if (subtype === 2) {
|
|
if (this._getCredentials().password === void 0) {
|
|
this.dispatchEvent(new CustomEvent(
|
|
"credentialsrequired",
|
|
{ detail: { types: ["password"] } }
|
|
));
|
|
}
|
|
} else {
|
|
throw new Error("RA2: wrong subtype");
|
|
}
|
|
await waitCredentials;
|
|
let username;
|
|
if (subtype === 1) {
|
|
username = encodeUTF8(this._getCredentials().username).slice(0, 255);
|
|
} else {
|
|
username = "";
|
|
}
|
|
const password = encodeUTF8(this._getCredentials().password).slice(0, 255);
|
|
const credentials = new Uint8Array(username.length + password.length + 2);
|
|
credentials[0] = username.length;
|
|
credentials[username.length + 1] = password.length;
|
|
for (let i = 0; i < username.length; i++) {
|
|
credentials[i + 1] = username.charCodeAt(i);
|
|
}
|
|
for (let i = 0; i < password.length; i++) {
|
|
credentials[username.length + 2 + i] = password.charCodeAt(i);
|
|
}
|
|
this._sock.sQpushBytes(await clientCipher.makeMessage(credentials));
|
|
this._sock.flush();
|
|
}
|
|
get hasStarted() {
|
|
return this._hasStarted;
|
|
}
|
|
set hasStarted(s) {
|
|
this._hasStarted = s;
|
|
}
|
|
};
|
|
|
|
// core/decoders/raw.js
|
|
var RawDecoder = class {
|
|
constructor() {
|
|
this._lines = 0;
|
|
}
|
|
decodeRect(x, y, width, height, sock, display, depth) {
|
|
if (width === 0 || height === 0) {
|
|
return true;
|
|
}
|
|
if (this._lines === 0) {
|
|
this._lines = height;
|
|
}
|
|
const pixelSize = depth == 8 ? 1 : 4;
|
|
const bytesPerLine = width * pixelSize;
|
|
while (this._lines > 0) {
|
|
if (sock.rQwait("RAW", bytesPerLine)) {
|
|
return false;
|
|
}
|
|
const curY = y + (height - this._lines);
|
|
let data = sock.rQshiftBytes(bytesPerLine, false);
|
|
if (depth == 8) {
|
|
const newdata = new Uint8Array(width * 4);
|
|
for (let i = 0; i < width; i++) {
|
|
newdata[i * 4 + 0] = (data[i] >> 0 & 3) * 255 / 3;
|
|
newdata[i * 4 + 1] = (data[i] >> 2 & 3) * 255 / 3;
|
|
newdata[i * 4 + 2] = (data[i] >> 4 & 3) * 255 / 3;
|
|
newdata[i * 4 + 3] = 255;
|
|
}
|
|
data = newdata;
|
|
}
|
|
for (let i = 0; i < width; i++) {
|
|
data[i * 4 + 3] = 255;
|
|
}
|
|
display.blitImage(x, curY, width, 1, data, 0);
|
|
this._lines--;
|
|
}
|
|
return true;
|
|
}
|
|
};
|
|
|
|
// core/decoders/copyrect.js
|
|
var CopyRectDecoder = class {
|
|
decodeRect(x, y, width, height, sock, display, depth) {
|
|
if (sock.rQwait("COPYRECT", 4)) {
|
|
return false;
|
|
}
|
|
let deltaX = sock.rQshift16();
|
|
let deltaY = sock.rQshift16();
|
|
if (width === 0 || height === 0) {
|
|
return true;
|
|
}
|
|
display.copyImage(deltaX, deltaY, x, y, width, height);
|
|
return true;
|
|
}
|
|
};
|
|
|
|
// core/decoders/rre.js
|
|
var RREDecoder = class {
|
|
constructor() {
|
|
this._subrects = 0;
|
|
}
|
|
decodeRect(x, y, width, height, sock, display, depth) {
|
|
if (this._subrects === 0) {
|
|
if (sock.rQwait("RRE", 4 + 4)) {
|
|
return false;
|
|
}
|
|
this._subrects = sock.rQshift32();
|
|
let color = sock.rQshiftBytes(4);
|
|
display.fillRect(x, y, width, height, color);
|
|
}
|
|
while (this._subrects > 0) {
|
|
if (sock.rQwait("RRE", 4 + 8)) {
|
|
return false;
|
|
}
|
|
let color = sock.rQshiftBytes(4);
|
|
let sx = sock.rQshift16();
|
|
let sy = sock.rQshift16();
|
|
let swidth = sock.rQshift16();
|
|
let sheight = sock.rQshift16();
|
|
display.fillRect(x + sx, y + sy, swidth, sheight, color);
|
|
this._subrects--;
|
|
}
|
|
return true;
|
|
}
|
|
};
|
|
|
|
// core/decoders/hextile.js
|
|
var HextileDecoder = class {
|
|
constructor() {
|
|
this._tiles = 0;
|
|
this._lastsubencoding = 0;
|
|
this._tileBuffer = new Uint8Array(16 * 16 * 4);
|
|
}
|
|
decodeRect(x, y, width, height, sock, display, depth) {
|
|
if (this._tiles === 0) {
|
|
this._tilesX = Math.ceil(width / 16);
|
|
this._tilesY = Math.ceil(height / 16);
|
|
this._totalTiles = this._tilesX * this._tilesY;
|
|
this._tiles = this._totalTiles;
|
|
}
|
|
while (this._tiles > 0) {
|
|
let bytes = 1;
|
|
if (sock.rQwait("HEXTILE", bytes)) {
|
|
return false;
|
|
}
|
|
let subencoding = sock.rQpeek8();
|
|
if (subencoding > 30) {
|
|
throw new Error("Illegal hextile subencoding (subencoding: " + subencoding + ")");
|
|
}
|
|
const currTile = this._totalTiles - this._tiles;
|
|
const tileX = currTile % this._tilesX;
|
|
const tileY = Math.floor(currTile / this._tilesX);
|
|
const tx = x + tileX * 16;
|
|
const ty = y + tileY * 16;
|
|
const tw = Math.min(16, x + width - tx);
|
|
const th = Math.min(16, y + height - ty);
|
|
if (subencoding & 1) {
|
|
bytes += tw * th * 4;
|
|
} else {
|
|
if (subencoding & 2) {
|
|
bytes += 4;
|
|
}
|
|
if (subencoding & 4) {
|
|
bytes += 4;
|
|
}
|
|
if (subencoding & 8) {
|
|
bytes++;
|
|
if (sock.rQwait("HEXTILE", bytes)) {
|
|
return false;
|
|
}
|
|
let subrects = sock.rQpeekBytes(bytes).at(-1);
|
|
if (subencoding & 16) {
|
|
bytes += subrects * (4 + 2);
|
|
} else {
|
|
bytes += subrects * 2;
|
|
}
|
|
}
|
|
}
|
|
if (sock.rQwait("HEXTILE", bytes)) {
|
|
return false;
|
|
}
|
|
sock.rQshift8();
|
|
if (subencoding === 0) {
|
|
if (this._lastsubencoding & 1) {
|
|
Debug(" Ignoring blank after RAW");
|
|
} else {
|
|
display.fillRect(tx, ty, tw, th, this._background);
|
|
}
|
|
} else if (subencoding & 1) {
|
|
let pixels = tw * th;
|
|
let data = sock.rQshiftBytes(pixels * 4, false);
|
|
for (let i = 0; i < pixels; i++) {
|
|
data[i * 4 + 3] = 255;
|
|
}
|
|
display.blitImage(tx, ty, tw, th, data, 0);
|
|
} else {
|
|
if (subencoding & 2) {
|
|
this._background = new Uint8Array(sock.rQshiftBytes(4));
|
|
}
|
|
if (subencoding & 4) {
|
|
this._foreground = new Uint8Array(sock.rQshiftBytes(4));
|
|
}
|
|
this._startTile(tx, ty, tw, th, this._background);
|
|
if (subencoding & 8) {
|
|
let subrects = sock.rQshift8();
|
|
for (let s = 0; s < subrects; s++) {
|
|
let color;
|
|
if (subencoding & 16) {
|
|
color = sock.rQshiftBytes(4);
|
|
} else {
|
|
color = this._foreground;
|
|
}
|
|
const xy = sock.rQshift8();
|
|
const sx = xy >> 4;
|
|
const sy = xy & 15;
|
|
const wh = sock.rQshift8();
|
|
const sw = (wh >> 4) + 1;
|
|
const sh = (wh & 15) + 1;
|
|
this._subTile(sx, sy, sw, sh, color);
|
|
}
|
|
}
|
|
this._finishTile(display);
|
|
}
|
|
this._lastsubencoding = subencoding;
|
|
this._tiles--;
|
|
}
|
|
return true;
|
|
}
|
|
// start updating a tile
|
|
_startTile(x, y, width, height, color) {
|
|
this._tileX = x;
|
|
this._tileY = y;
|
|
this._tileW = width;
|
|
this._tileH = height;
|
|
const red = color[0];
|
|
const green = color[1];
|
|
const blue = color[2];
|
|
const data = this._tileBuffer;
|
|
for (let i = 0; i < width * height * 4; i += 4) {
|
|
data[i] = red;
|
|
data[i + 1] = green;
|
|
data[i + 2] = blue;
|
|
data[i + 3] = 255;
|
|
}
|
|
}
|
|
// update sub-rectangle of the current tile
|
|
_subTile(x, y, w, h, color) {
|
|
const red = color[0];
|
|
const green = color[1];
|
|
const blue = color[2];
|
|
const xend = x + w;
|
|
const yend = y + h;
|
|
const data = this._tileBuffer;
|
|
const width = this._tileW;
|
|
for (let j = y; j < yend; j++) {
|
|
for (let i = x; i < xend; i++) {
|
|
const p = (i + j * width) * 4;
|
|
data[p] = red;
|
|
data[p + 1] = green;
|
|
data[p + 2] = blue;
|
|
data[p + 3] = 255;
|
|
}
|
|
}
|
|
}
|
|
// draw the current tile to the screen
|
|
_finishTile(display) {
|
|
display.blitImage(
|
|
this._tileX,
|
|
this._tileY,
|
|
this._tileW,
|
|
this._tileH,
|
|
this._tileBuffer,
|
|
0
|
|
);
|
|
}
|
|
};
|
|
|
|
// core/decoders/zlib.js
|
|
var ZlibDecoder = class {
|
|
constructor() {
|
|
this._zlib = new Inflate();
|
|
this._length = 0;
|
|
}
|
|
decodeRect(x, y, width, height, sock, display, depth) {
|
|
if (width === 0 || height === 0) {
|
|
return true;
|
|
}
|
|
if (this._length === 0) {
|
|
if (sock.rQwait("ZLIB", 4)) {
|
|
return false;
|
|
}
|
|
this._length = sock.rQshift32();
|
|
}
|
|
if (sock.rQwait("ZLIB", this._length)) {
|
|
return false;
|
|
}
|
|
let data = new Uint8Array(sock.rQshiftBytes(this._length, false));
|
|
this._length = 0;
|
|
this._zlib.setInput(data);
|
|
data = this._zlib.inflate(width * height * 4);
|
|
this._zlib.setInput(null);
|
|
for (let i = 0; i < width * height; i++) {
|
|
data[i * 4 + 3] = 255;
|
|
}
|
|
display.blitImage(x, y, width, height, data, 0);
|
|
return true;
|
|
}
|
|
};
|
|
|
|
// core/decoders/tight.js
|
|
var TightDecoder = class {
|
|
constructor() {
|
|
this._ctl = null;
|
|
this._filter = null;
|
|
this._numColors = 0;
|
|
this._palette = new Uint8Array(1024);
|
|
this._len = 0;
|
|
this._zlibs = [];
|
|
for (let i = 0; i < 4; i++) {
|
|
this._zlibs[i] = new Inflate();
|
|
}
|
|
}
|
|
decodeRect(x, y, width, height, sock, display, depth) {
|
|
if (this._ctl === null) {
|
|
if (sock.rQwait("TIGHT compression-control", 1)) {
|
|
return false;
|
|
}
|
|
this._ctl = sock.rQshift8();
|
|
for (let i = 0; i < 4; i++) {
|
|
if (this._ctl >> i & 1) {
|
|
this._zlibs[i].reset();
|
|
Info("Reset zlib stream " + i);
|
|
}
|
|
}
|
|
this._ctl = this._ctl >> 4;
|
|
}
|
|
let ret;
|
|
if (this._ctl === 8) {
|
|
ret = this._fillRect(
|
|
x,
|
|
y,
|
|
width,
|
|
height,
|
|
sock,
|
|
display,
|
|
depth
|
|
);
|
|
} else if (this._ctl === 9) {
|
|
ret = this._jpegRect(
|
|
x,
|
|
y,
|
|
width,
|
|
height,
|
|
sock,
|
|
display,
|
|
depth
|
|
);
|
|
} else if (this._ctl === 10) {
|
|
ret = this._pngRect(
|
|
x,
|
|
y,
|
|
width,
|
|
height,
|
|
sock,
|
|
display,
|
|
depth
|
|
);
|
|
} else if ((this._ctl & 8) == 0) {
|
|
ret = this._basicRect(
|
|
this._ctl,
|
|
x,
|
|
y,
|
|
width,
|
|
height,
|
|
sock,
|
|
display,
|
|
depth
|
|
);
|
|
} else {
|
|
throw new Error("Illegal tight compression received (ctl: " + this._ctl + ")");
|
|
}
|
|
if (ret) {
|
|
this._ctl = null;
|
|
}
|
|
return ret;
|
|
}
|
|
_fillRect(x, y, width, height, sock, display, depth) {
|
|
if (sock.rQwait("TIGHT", 3)) {
|
|
return false;
|
|
}
|
|
let pixel = sock.rQshiftBytes(3);
|
|
display.fillRect(x, y, width, height, pixel, false);
|
|
return true;
|
|
}
|
|
_jpegRect(x, y, width, height, sock, display, depth) {
|
|
let data = this._readData(sock);
|
|
if (data === null) {
|
|
return false;
|
|
}
|
|
display.imageRect(x, y, width, height, "image/jpeg", data);
|
|
return true;
|
|
}
|
|
_pngRect(x, y, width, height, sock, display, depth) {
|
|
throw new Error("PNG received in standard Tight rect");
|
|
}
|
|
_basicRect(ctl, x, y, width, height, sock, display, depth) {
|
|
if (this._filter === null) {
|
|
if (ctl & 4) {
|
|
if (sock.rQwait("TIGHT", 1)) {
|
|
return false;
|
|
}
|
|
this._filter = sock.rQshift8();
|
|
} else {
|
|
this._filter = 0;
|
|
}
|
|
}
|
|
let streamId = ctl & 3;
|
|
let ret;
|
|
switch (this._filter) {
|
|
case 0:
|
|
ret = this._copyFilter(
|
|
streamId,
|
|
x,
|
|
y,
|
|
width,
|
|
height,
|
|
sock,
|
|
display,
|
|
depth
|
|
);
|
|
break;
|
|
case 1:
|
|
ret = this._paletteFilter(
|
|
streamId,
|
|
x,
|
|
y,
|
|
width,
|
|
height,
|
|
sock,
|
|
display,
|
|
depth
|
|
);
|
|
break;
|
|
case 2:
|
|
ret = this._gradientFilter(
|
|
streamId,
|
|
x,
|
|
y,
|
|
width,
|
|
height,
|
|
sock,
|
|
display,
|
|
depth
|
|
);
|
|
break;
|
|
default:
|
|
throw new Error("Illegal tight filter received (ctl: " + this._filter + ")");
|
|
}
|
|
if (ret) {
|
|
this._filter = null;
|
|
}
|
|
return ret;
|
|
}
|
|
_copyFilter(streamId, x, y, width, height, sock, display, depth) {
|
|
const uncompressedSize = width * height * 3;
|
|
let data;
|
|
if (uncompressedSize === 0) {
|
|
return true;
|
|
}
|
|
if (uncompressedSize < 12) {
|
|
if (sock.rQwait("TIGHT", uncompressedSize)) {
|
|
return false;
|
|
}
|
|
data = sock.rQshiftBytes(uncompressedSize);
|
|
} else {
|
|
data = this._readData(sock);
|
|
if (data === null) {
|
|
return false;
|
|
}
|
|
this._zlibs[streamId].setInput(data);
|
|
data = this._zlibs[streamId].inflate(uncompressedSize);
|
|
this._zlibs[streamId].setInput(null);
|
|
}
|
|
let rgbx = new Uint8Array(width * height * 4);
|
|
for (let i = 0, j = 0; i < width * height * 4; i += 4, j += 3) {
|
|
rgbx[i] = data[j];
|
|
rgbx[i + 1] = data[j + 1];
|
|
rgbx[i + 2] = data[j + 2];
|
|
rgbx[i + 3] = 255;
|
|
}
|
|
display.blitImage(x, y, width, height, rgbx, 0, false);
|
|
return true;
|
|
}
|
|
_paletteFilter(streamId, x, y, width, height, sock, display, depth) {
|
|
if (this._numColors === 0) {
|
|
if (sock.rQwait("TIGHT palette", 1)) {
|
|
return false;
|
|
}
|
|
const numColors = sock.rQpeek8() + 1;
|
|
const paletteSize = numColors * 3;
|
|
if (sock.rQwait("TIGHT palette", 1 + paletteSize)) {
|
|
return false;
|
|
}
|
|
this._numColors = numColors;
|
|
sock.rQskipBytes(1);
|
|
sock.rQshiftTo(this._palette, paletteSize);
|
|
}
|
|
const bpp = this._numColors <= 2 ? 1 : 8;
|
|
const rowSize = Math.floor((width * bpp + 7) / 8);
|
|
const uncompressedSize = rowSize * height;
|
|
let data;
|
|
if (uncompressedSize === 0) {
|
|
return true;
|
|
}
|
|
if (uncompressedSize < 12) {
|
|
if (sock.rQwait("TIGHT", uncompressedSize)) {
|
|
return false;
|
|
}
|
|
data = sock.rQshiftBytes(uncompressedSize);
|
|
} else {
|
|
data = this._readData(sock);
|
|
if (data === null) {
|
|
return false;
|
|
}
|
|
this._zlibs[streamId].setInput(data);
|
|
data = this._zlibs[streamId].inflate(uncompressedSize);
|
|
this._zlibs[streamId].setInput(null);
|
|
}
|
|
if (this._numColors == 2) {
|
|
this._monoRect(x, y, width, height, data, this._palette, display);
|
|
} else {
|
|
this._paletteRect(x, y, width, height, data, this._palette, display);
|
|
}
|
|
this._numColors = 0;
|
|
return true;
|
|
}
|
|
_monoRect(x, y, width, height, data, palette, display) {
|
|
const dest = this._getScratchBuffer(width * height * 4);
|
|
const w = Math.floor((width + 7) / 8);
|
|
const w1 = Math.floor(width / 8);
|
|
for (let y2 = 0; y2 < height; y2++) {
|
|
let dp, sp, x2;
|
|
for (x2 = 0; x2 < w1; x2++) {
|
|
for (let b2 = 7; b2 >= 0; b2--) {
|
|
dp = (y2 * width + x2 * 8 + 7 - b2) * 4;
|
|
sp = (data[y2 * w + x2] >> b2 & 1) * 3;
|
|
dest[dp] = palette[sp];
|
|
dest[dp + 1] = palette[sp + 1];
|
|
dest[dp + 2] = palette[sp + 2];
|
|
dest[dp + 3] = 255;
|
|
}
|
|
}
|
|
for (let b2 = 7; b2 >= 8 - width % 8; b2--) {
|
|
dp = (y2 * width + x2 * 8 + 7 - b2) * 4;
|
|
sp = (data[y2 * w + x2] >> b2 & 1) * 3;
|
|
dest[dp] = palette[sp];
|
|
dest[dp + 1] = palette[sp + 1];
|
|
dest[dp + 2] = palette[sp + 2];
|
|
dest[dp + 3] = 255;
|
|
}
|
|
}
|
|
display.blitImage(x, y, width, height, dest, 0, false);
|
|
}
|
|
_paletteRect(x, y, width, height, data, palette, display) {
|
|
const dest = this._getScratchBuffer(width * height * 4);
|
|
const total = width * height * 4;
|
|
for (let i = 0, j = 0; i < total; i += 4, j++) {
|
|
const sp = data[j] * 3;
|
|
dest[i] = palette[sp];
|
|
dest[i + 1] = palette[sp + 1];
|
|
dest[i + 2] = palette[sp + 2];
|
|
dest[i + 3] = 255;
|
|
}
|
|
display.blitImage(x, y, width, height, dest, 0, false);
|
|
}
|
|
_gradientFilter(streamId, x, y, width, height, sock, display, depth) {
|
|
const uncompressedSize = width * height * 3;
|
|
let data;
|
|
if (uncompressedSize === 0) {
|
|
return true;
|
|
}
|
|
if (uncompressedSize < 12) {
|
|
if (sock.rQwait("TIGHT", uncompressedSize)) {
|
|
return false;
|
|
}
|
|
data = sock.rQshiftBytes(uncompressedSize);
|
|
} else {
|
|
data = this._readData(sock);
|
|
if (data === null) {
|
|
return false;
|
|
}
|
|
this._zlibs[streamId].setInput(data);
|
|
data = this._zlibs[streamId].inflate(uncompressedSize);
|
|
this._zlibs[streamId].setInput(null);
|
|
}
|
|
let rgbx = new Uint8Array(4 * width * height);
|
|
let rgbxIndex = 0, dataIndex = 0;
|
|
let left = new Uint8Array(3);
|
|
for (let x2 = 0; x2 < width; x2++) {
|
|
for (let c2 = 0; c2 < 3; c2++) {
|
|
const prediction = left[c2];
|
|
const value = data[dataIndex++] + prediction;
|
|
rgbx[rgbxIndex++] = value;
|
|
left[c2] = value;
|
|
}
|
|
rgbx[rgbxIndex++] = 255;
|
|
}
|
|
let upperIndex = 0;
|
|
let upper = new Uint8Array(3), upperleft = new Uint8Array(3);
|
|
for (let y2 = 1; y2 < height; y2++) {
|
|
left.fill(0);
|
|
upperleft.fill(0);
|
|
for (let x2 = 0; x2 < width; x2++) {
|
|
for (let c2 = 0; c2 < 3; c2++) {
|
|
upper[c2] = rgbx[upperIndex++];
|
|
let prediction = left[c2] + upper[c2] - upperleft[c2];
|
|
if (prediction < 0) {
|
|
prediction = 0;
|
|
} else if (prediction > 255) {
|
|
prediction = 255;
|
|
}
|
|
const value = data[dataIndex++] + prediction;
|
|
rgbx[rgbxIndex++] = value;
|
|
upperleft[c2] = upper[c2];
|
|
left[c2] = value;
|
|
}
|
|
rgbx[rgbxIndex++] = 255;
|
|
upperIndex++;
|
|
}
|
|
}
|
|
display.blitImage(x, y, width, height, rgbx, 0, false);
|
|
return true;
|
|
}
|
|
_readData(sock) {
|
|
if (this._len === 0) {
|
|
if (sock.rQwait("TIGHT", 3)) {
|
|
return null;
|
|
}
|
|
let byte;
|
|
byte = sock.rQshift8();
|
|
this._len = byte & 127;
|
|
if (byte & 128) {
|
|
byte = sock.rQshift8();
|
|
this._len |= (byte & 127) << 7;
|
|
if (byte & 128) {
|
|
byte = sock.rQshift8();
|
|
this._len |= byte << 14;
|
|
}
|
|
}
|
|
}
|
|
if (sock.rQwait("TIGHT", this._len)) {
|
|
return null;
|
|
}
|
|
let data = sock.rQshiftBytes(this._len, false);
|
|
this._len = 0;
|
|
return data;
|
|
}
|
|
_getScratchBuffer(size) {
|
|
if (!this._scratchBuffer || this._scratchBuffer.length < size) {
|
|
this._scratchBuffer = new Uint8Array(size);
|
|
}
|
|
return this._scratchBuffer;
|
|
}
|
|
};
|
|
|
|
// core/decoders/tightpng.js
|
|
var TightPNGDecoder = class extends TightDecoder {
|
|
_pngRect(x, y, width, height, sock, display, depth) {
|
|
let data = this._readData(sock);
|
|
if (data === null) {
|
|
return false;
|
|
}
|
|
display.imageRect(x, y, width, height, "image/png", data);
|
|
return true;
|
|
}
|
|
_basicRect(ctl, x, y, width, height, sock, display, depth) {
|
|
throw new Error("BasicCompression received in TightPNG rect");
|
|
}
|
|
};
|
|
|
|
// core/decoders/zrle.js
|
|
var ZRLE_TILE_WIDTH = 64;
|
|
var ZRLE_TILE_HEIGHT = 64;
|
|
var ZRLEDecoder = class {
|
|
constructor() {
|
|
this._length = 0;
|
|
this._inflator = new Inflate();
|
|
this._pixelBuffer = new Uint8Array(ZRLE_TILE_WIDTH * ZRLE_TILE_HEIGHT * 4);
|
|
this._tileBuffer = new Uint8Array(ZRLE_TILE_WIDTH * ZRLE_TILE_HEIGHT * 4);
|
|
}
|
|
decodeRect(x, y, width, height, sock, display, depth) {
|
|
if (this._length === 0) {
|
|
if (sock.rQwait("ZLib data length", 4)) {
|
|
return false;
|
|
}
|
|
this._length = sock.rQshift32();
|
|
}
|
|
if (sock.rQwait("Zlib data", this._length)) {
|
|
return false;
|
|
}
|
|
const data = sock.rQshiftBytes(this._length, false);
|
|
this._inflator.setInput(data);
|
|
for (let ty = y; ty < y + height; ty += ZRLE_TILE_HEIGHT) {
|
|
let th = Math.min(ZRLE_TILE_HEIGHT, y + height - ty);
|
|
for (let tx = x; tx < x + width; tx += ZRLE_TILE_WIDTH) {
|
|
let tw = Math.min(ZRLE_TILE_WIDTH, x + width - tx);
|
|
const tileSize = tw * th;
|
|
const subencoding = this._inflator.inflate(1)[0];
|
|
if (subencoding === 0) {
|
|
const data2 = this._readPixels(tileSize);
|
|
display.blitImage(tx, ty, tw, th, data2, 0, false);
|
|
} else if (subencoding === 1) {
|
|
const background = this._readPixels(1);
|
|
display.fillRect(tx, ty, tw, th, [background[0], background[1], background[2]]);
|
|
} else if (subencoding >= 2 && subencoding <= 16) {
|
|
const data2 = this._decodePaletteTile(subencoding, tileSize, tw, th);
|
|
display.blitImage(tx, ty, tw, th, data2, 0, false);
|
|
} else if (subencoding === 128) {
|
|
const data2 = this._decodeRLETile(tileSize);
|
|
display.blitImage(tx, ty, tw, th, data2, 0, false);
|
|
} else if (subencoding >= 130 && subencoding <= 255) {
|
|
const data2 = this._decodeRLEPaletteTile(subencoding - 128, tileSize);
|
|
display.blitImage(tx, ty, tw, th, data2, 0, false);
|
|
} else {
|
|
throw new Error("Unknown subencoding: " + subencoding);
|
|
}
|
|
}
|
|
}
|
|
this._length = 0;
|
|
return true;
|
|
}
|
|
_getBitsPerPixelInPalette(paletteSize) {
|
|
if (paletteSize <= 2) {
|
|
return 1;
|
|
} else if (paletteSize <= 4) {
|
|
return 2;
|
|
} else if (paletteSize <= 16) {
|
|
return 4;
|
|
}
|
|
}
|
|
_readPixels(pixels) {
|
|
let data = this._pixelBuffer;
|
|
const buffer = this._inflator.inflate(3 * pixels);
|
|
for (let i = 0, j = 0; i < pixels * 4; i += 4, j += 3) {
|
|
data[i] = buffer[j];
|
|
data[i + 1] = buffer[j + 1];
|
|
data[i + 2] = buffer[j + 2];
|
|
data[i + 3] = 255;
|
|
}
|
|
return data;
|
|
}
|
|
_decodePaletteTile(paletteSize, tileSize, tilew, tileh) {
|
|
const data = this._tileBuffer;
|
|
const palette = this._readPixels(paletteSize);
|
|
const bitsPerPixel = this._getBitsPerPixelInPalette(paletteSize);
|
|
const mask = (1 << bitsPerPixel) - 1;
|
|
let offset = 0;
|
|
let encoded = this._inflator.inflate(1)[0];
|
|
for (let y = 0; y < tileh; y++) {
|
|
let shift = 8 - bitsPerPixel;
|
|
for (let x = 0; x < tilew; x++) {
|
|
if (shift < 0) {
|
|
shift = 8 - bitsPerPixel;
|
|
encoded = this._inflator.inflate(1)[0];
|
|
}
|
|
let indexInPalette = encoded >> shift & mask;
|
|
data[offset] = palette[indexInPalette * 4];
|
|
data[offset + 1] = palette[indexInPalette * 4 + 1];
|
|
data[offset + 2] = palette[indexInPalette * 4 + 2];
|
|
data[offset + 3] = palette[indexInPalette * 4 + 3];
|
|
offset += 4;
|
|
shift -= bitsPerPixel;
|
|
}
|
|
if (shift < 8 - bitsPerPixel && y < tileh - 1) {
|
|
encoded = this._inflator.inflate(1)[0];
|
|
}
|
|
}
|
|
return data;
|
|
}
|
|
_decodeRLETile(tileSize) {
|
|
const data = this._tileBuffer;
|
|
let i = 0;
|
|
while (i < tileSize) {
|
|
const pixel = this._readPixels(1);
|
|
const length = this._readRLELength();
|
|
for (let j = 0; j < length; j++) {
|
|
data[i * 4] = pixel[0];
|
|
data[i * 4 + 1] = pixel[1];
|
|
data[i * 4 + 2] = pixel[2];
|
|
data[i * 4 + 3] = pixel[3];
|
|
i++;
|
|
}
|
|
}
|
|
return data;
|
|
}
|
|
_decodeRLEPaletteTile(paletteSize, tileSize) {
|
|
const data = this._tileBuffer;
|
|
const palette = this._readPixels(paletteSize);
|
|
let offset = 0;
|
|
while (offset < tileSize) {
|
|
let indexInPalette = this._inflator.inflate(1)[0];
|
|
let length = 1;
|
|
if (indexInPalette >= 128) {
|
|
indexInPalette -= 128;
|
|
length = this._readRLELength();
|
|
}
|
|
if (indexInPalette > paletteSize) {
|
|
throw new Error("Too big index in palette: " + indexInPalette + ", palette size: " + paletteSize);
|
|
}
|
|
if (offset + length > tileSize) {
|
|
throw new Error("Too big rle length in palette mode: " + length + ", allowed length is: " + (tileSize - offset));
|
|
}
|
|
for (let j = 0; j < length; j++) {
|
|
data[offset * 4] = palette[indexInPalette * 4];
|
|
data[offset * 4 + 1] = palette[indexInPalette * 4 + 1];
|
|
data[offset * 4 + 2] = palette[indexInPalette * 4 + 2];
|
|
data[offset * 4 + 3] = palette[indexInPalette * 4 + 3];
|
|
offset++;
|
|
}
|
|
}
|
|
return data;
|
|
}
|
|
_readRLELength() {
|
|
let length = 0;
|
|
let current;
|
|
do {
|
|
current = this._inflator.inflate(1)[0];
|
|
length += current;
|
|
} while (current === 255);
|
|
return length + 1;
|
|
}
|
|
};
|
|
|
|
// core/decoders/jpeg.js
|
|
var JPEGDecoder = class {
|
|
constructor() {
|
|
this._cachedQuantTables = [];
|
|
this._cachedHuffmanTables = [];
|
|
this._segments = [];
|
|
}
|
|
decodeRect(x, y, width, height, sock, display, depth) {
|
|
while (true) {
|
|
let segment = this._readSegment(sock);
|
|
if (segment === null) {
|
|
return false;
|
|
}
|
|
this._segments.push(segment);
|
|
if (segment[1] === 217) {
|
|
break;
|
|
}
|
|
}
|
|
let huffmanTables = [];
|
|
let quantTables = [];
|
|
for (let segment of this._segments) {
|
|
let type = segment[1];
|
|
if (type === 196) {
|
|
huffmanTables.push(segment);
|
|
} else if (type === 219) {
|
|
quantTables.push(segment);
|
|
}
|
|
}
|
|
const sofIndex = this._segments.findIndex(
|
|
(x2) => x2[1] == 192 || x2[1] == 194
|
|
);
|
|
if (sofIndex == -1) {
|
|
throw new Error("Illegal JPEG image without SOF");
|
|
}
|
|
if (quantTables.length === 0) {
|
|
this._segments.splice(
|
|
sofIndex + 1,
|
|
0,
|
|
...this._cachedQuantTables
|
|
);
|
|
}
|
|
if (huffmanTables.length === 0) {
|
|
this._segments.splice(
|
|
sofIndex + 1,
|
|
0,
|
|
...this._cachedHuffmanTables
|
|
);
|
|
}
|
|
let length = 0;
|
|
for (let segment of this._segments) {
|
|
length += segment.length;
|
|
}
|
|
let data = new Uint8Array(length);
|
|
length = 0;
|
|
for (let segment of this._segments) {
|
|
data.set(segment, length);
|
|
length += segment.length;
|
|
}
|
|
display.imageRect(x, y, width, height, "image/jpeg", data);
|
|
if (huffmanTables.length !== 0) {
|
|
this._cachedHuffmanTables = huffmanTables;
|
|
}
|
|
if (quantTables.length !== 0) {
|
|
this._cachedQuantTables = quantTables;
|
|
}
|
|
this._segments = [];
|
|
return true;
|
|
}
|
|
_readSegment(sock) {
|
|
if (sock.rQwait("JPEG", 2)) {
|
|
return null;
|
|
}
|
|
let marker = sock.rQshift8();
|
|
if (marker != 255) {
|
|
throw new Error("Illegal JPEG marker received (byte: " + marker + ")");
|
|
}
|
|
let type = sock.rQshift8();
|
|
if (type >= 208 && type <= 217 || type == 1) {
|
|
return new Uint8Array([marker, type]);
|
|
}
|
|
if (sock.rQwait("JPEG", 2, 2)) {
|
|
return null;
|
|
}
|
|
let length = sock.rQshift16();
|
|
if (length < 2) {
|
|
throw new Error("Illegal JPEG length received (length: " + length + ")");
|
|
}
|
|
if (sock.rQwait("JPEG", length - 2, 4)) {
|
|
return null;
|
|
}
|
|
let extra = 0;
|
|
if (type === 218) {
|
|
if (sock.rQwait("JPEG", length - 2 + 2, 4)) {
|
|
return null;
|
|
}
|
|
let len = sock.rQlen();
|
|
let data = sock.rQpeekBytes(len, false);
|
|
while (true) {
|
|
let idx = data.indexOf(255, length - 2 + extra);
|
|
if (idx === -1) {
|
|
sock.rQwait("JPEG", Infinity, 4);
|
|
return null;
|
|
}
|
|
if (idx === len - 1) {
|
|
sock.rQwait("JPEG", Infinity, 4);
|
|
return null;
|
|
}
|
|
if (data.at(idx + 1) === 0 || data.at(idx + 1) >= 208 && data.at(idx + 1) <= 215) {
|
|
extra = idx + 2 - (length - 2);
|
|
continue;
|
|
}
|
|
extra = idx - (length - 2);
|
|
break;
|
|
}
|
|
}
|
|
let segment = new Uint8Array(2 + length + extra);
|
|
segment[0] = marker;
|
|
segment[1] = type;
|
|
segment[2] = length >> 8;
|
|
segment[3] = length;
|
|
segment.set(sock.rQshiftBytes(length - 2 + extra, false), 4);
|
|
return segment;
|
|
}
|
|
};
|
|
|
|
// core/decoders/h264.js
|
|
var H264Parser = class {
|
|
constructor(data) {
|
|
this._data = data;
|
|
this._index = 0;
|
|
this.profileIdc = null;
|
|
this.constraintSet = null;
|
|
this.levelIdc = null;
|
|
}
|
|
_getStartSequenceLen(index) {
|
|
let data = this._data;
|
|
if (data[index + 0] == 0 && data[index + 1] == 0 && data[index + 2] == 0 && data[index + 3] == 1) {
|
|
return 4;
|
|
}
|
|
if (data[index + 0] == 0 && data[index + 1] == 0 && data[index + 2] == 1) {
|
|
return 3;
|
|
}
|
|
return 0;
|
|
}
|
|
_indexOfNextNalUnit(index) {
|
|
let data = this._data;
|
|
for (let i = index; i < data.length; ++i) {
|
|
if (this._getStartSequenceLen(i) != 0) {
|
|
return i;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
_parseSps(index) {
|
|
this.profileIdc = this._data[index];
|
|
this.constraintSet = this._data[index + 1];
|
|
this.levelIdc = this._data[index + 2];
|
|
}
|
|
_parseNalUnit(index) {
|
|
const firstByte = this._data[index];
|
|
if (firstByte & 128) {
|
|
throw new Error("H264 parsing sanity check failed, forbidden zero bit is set");
|
|
}
|
|
const unitType = firstByte & 31;
|
|
switch (unitType) {
|
|
case 1:
|
|
return { slice: true };
|
|
case 5:
|
|
return { slice: true, key: true };
|
|
case 6:
|
|
return {};
|
|
case 7:
|
|
this._parseSps(index + 1);
|
|
return {};
|
|
case 8:
|
|
return {};
|
|
default:
|
|
Warn("Unhandled unit type: ", unitType);
|
|
break;
|
|
}
|
|
return {};
|
|
}
|
|
parse() {
|
|
const startIndex = this._index;
|
|
let isKey = false;
|
|
while (this._index < this._data.length) {
|
|
const startSequenceLen = this._getStartSequenceLen(this._index);
|
|
if (startSequenceLen == 0) {
|
|
throw new Error("Invalid start sequence in bit stream");
|
|
}
|
|
const { slice, key } = this._parseNalUnit(this._index + startSequenceLen);
|
|
let nextIndex = this._indexOfNextNalUnit(this._index + startSequenceLen);
|
|
if (nextIndex == -1) {
|
|
this._index = this._data.length;
|
|
} else {
|
|
this._index = nextIndex;
|
|
}
|
|
if (key) {
|
|
isKey = true;
|
|
}
|
|
if (slice) {
|
|
break;
|
|
}
|
|
}
|
|
if (startIndex === this._index) {
|
|
return null;
|
|
}
|
|
return {
|
|
frame: this._data.subarray(startIndex, this._index),
|
|
key: isKey
|
|
};
|
|
}
|
|
};
|
|
var H264Context = class {
|
|
constructor(width, height) {
|
|
this.lastUsed = 0;
|
|
this._width = width;
|
|
this._height = height;
|
|
this._profileIdc = null;
|
|
this._constraintSet = null;
|
|
this._levelIdc = null;
|
|
this._decoder = null;
|
|
this._pendingFrames = [];
|
|
}
|
|
_handleFrame(frame) {
|
|
let pending = this._pendingFrames.shift();
|
|
if (pending === void 0) {
|
|
throw new Error("Pending frame queue empty when receiving frame from decoder");
|
|
}
|
|
if (pending.timestamp != frame.timestamp) {
|
|
throw new Error("Video frame timestamp mismatch. Expected " + frame.timestamp + " but but got " + pending.timestamp);
|
|
}
|
|
pending.frame = frame;
|
|
pending.ready = true;
|
|
pending.resolve();
|
|
if (!pending.keep) {
|
|
frame.close();
|
|
}
|
|
}
|
|
_handleError(e2) {
|
|
throw new Error("Failed to decode frame: " + e2.message);
|
|
}
|
|
_configureDecoder(profileIdc, constraintSet, levelIdc) {
|
|
if (this._decoder === null || this._decoder.state === "closed") {
|
|
this._decoder = new VideoDecoder({
|
|
output: (frame) => this._handleFrame(frame),
|
|
error: (e2) => this._handleError(e2)
|
|
});
|
|
}
|
|
const codec = "avc1." + profileIdc.toString(16).padStart(2, "0") + constraintSet.toString(16).padStart(2, "0") + levelIdc.toString(16).padStart(2, "0");
|
|
this._decoder.configure({
|
|
codec,
|
|
codedWidth: this._width,
|
|
codedHeight: this._height,
|
|
optimizeForLatency: true
|
|
});
|
|
}
|
|
_preparePendingFrame(timestamp) {
|
|
let pending = {
|
|
timestamp,
|
|
promise: null,
|
|
resolve: null,
|
|
frame: null,
|
|
ready: false,
|
|
keep: false
|
|
};
|
|
pending.promise = new Promise((resolve) => {
|
|
pending.resolve = resolve;
|
|
});
|
|
this._pendingFrames.push(pending);
|
|
return pending;
|
|
}
|
|
decode(payload) {
|
|
let parser = new H264Parser(payload);
|
|
let result = null;
|
|
let timestamp = Math.round(window.performance.now() * 1e3);
|
|
while (true) {
|
|
let encodedFrame = parser.parse();
|
|
if (encodedFrame === null) {
|
|
break;
|
|
}
|
|
if (parser.profileIdc !== null) {
|
|
self._profileIdc = parser.profileIdc;
|
|
self._constraintSet = parser.constraintSet;
|
|
self._levelIdc = parser.levelIdc;
|
|
}
|
|
if (this._decoder === null || this._decoder.state !== "configured") {
|
|
if (!encodedFrame.key) {
|
|
Warn("Missing key frame. Can't decode until one arrives");
|
|
continue;
|
|
}
|
|
if (self._profileIdc === null) {
|
|
Warn("Cannot config decoder. Have not received SPS and PPS yet.");
|
|
continue;
|
|
}
|
|
this._configureDecoder(
|
|
self._profileIdc,
|
|
self._constraintSet,
|
|
self._levelIdc
|
|
);
|
|
}
|
|
result = this._preparePendingFrame(timestamp);
|
|
const chunk = new EncodedVideoChunk({
|
|
timestamp,
|
|
type: encodedFrame.key ? "key" : "delta",
|
|
data: encodedFrame.frame
|
|
});
|
|
try {
|
|
this._decoder.decode(chunk);
|
|
} catch (e2) {
|
|
Warn("Failed to decode:", e2);
|
|
}
|
|
}
|
|
if (result !== null) {
|
|
result.keep = true;
|
|
}
|
|
return result;
|
|
}
|
|
};
|
|
var H264Decoder = class {
|
|
constructor() {
|
|
this._tick = 0;
|
|
this._contexts = {};
|
|
}
|
|
_contextId(x, y, width, height) {
|
|
return [x, y, width, height].join(",");
|
|
}
|
|
_findOldestContextId() {
|
|
let oldestTick = Number.MAX_VALUE;
|
|
let oldestKey = void 0;
|
|
for (const [key, value] of Object.entries(this._contexts)) {
|
|
if (value.lastUsed < oldestTick) {
|
|
oldestTick = value.lastUsed;
|
|
oldestKey = key;
|
|
}
|
|
}
|
|
return oldestKey;
|
|
}
|
|
_createContext(x, y, width, height) {
|
|
const maxContexts = 64;
|
|
if (Object.keys(this._contexts).length >= maxContexts) {
|
|
let oldestContextId = this._findOldestContextId();
|
|
delete this._contexts[oldestContextId];
|
|
}
|
|
let context = new H264Context(width, height);
|
|
this._contexts[this._contextId(x, y, width, height)] = context;
|
|
return context;
|
|
}
|
|
_getContext(x, y, width, height) {
|
|
let context = this._contexts[this._contextId(x, y, width, height)];
|
|
return context !== void 0 ? context : this._createContext(x, y, width, height);
|
|
}
|
|
_resetContext(x, y, width, height) {
|
|
delete this._contexts[this._contextId(x, y, width, height)];
|
|
}
|
|
_resetAllContexts() {
|
|
this._contexts = {};
|
|
}
|
|
decodeRect(x, y, width, height, sock, display, depth) {
|
|
const resetContextFlag = 1;
|
|
const resetAllContextsFlag = 2;
|
|
if (sock.rQwait("h264 header", 8)) {
|
|
return false;
|
|
}
|
|
const length = sock.rQshift32();
|
|
const flags = sock.rQshift32();
|
|
if (sock.rQwait("h264 payload", length, 8)) {
|
|
return false;
|
|
}
|
|
if (flags & resetAllContextsFlag) {
|
|
this._resetAllContexts();
|
|
} else if (flags & resetContextFlag) {
|
|
this._resetContext(x, y, width, height);
|
|
}
|
|
let context = this._getContext(x, y, width, height);
|
|
context.lastUsed = this._tick++;
|
|
if (length !== 0) {
|
|
let payload = sock.rQshiftBytes(length, false);
|
|
let frame = context.decode(payload);
|
|
if (frame !== null) {
|
|
display.videoFrame(x, y, width, height, frame);
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
};
|
|
|
|
// core/rfb.js
|
|
var DISCONNECT_TIMEOUT = 3;
|
|
var DEFAULT_BACKGROUND = "rgb(40, 40, 40)";
|
|
var MOUSE_MOVE_DELAY = 17;
|
|
var WHEEL_STEP = 50;
|
|
var WHEEL_LINE_HEIGHT = 19;
|
|
var GESTURE_ZOOMSENS = 75;
|
|
var GESTURE_SCRLSENS = 50;
|
|
var DOUBLE_TAP_TIMEOUT = 1e3;
|
|
var DOUBLE_TAP_THRESHOLD = 50;
|
|
var securityTypeNone = 1;
|
|
var securityTypeVNCAuth = 2;
|
|
var securityTypeRA2ne = 6;
|
|
var securityTypeTight = 16;
|
|
var securityTypeVeNCrypt = 19;
|
|
var securityTypeXVP = 22;
|
|
var securityTypeARD = 30;
|
|
var securityTypeMSLogonII = 113;
|
|
var securityTypeUnixLogon = 129;
|
|
var securityTypePlain = 256;
|
|
var extendedClipboardFormatText = 1;
|
|
var extendedClipboardFormatRtf = 1 << 1;
|
|
var extendedClipboardFormatHtml = 1 << 2;
|
|
var extendedClipboardFormatDib = 1 << 3;
|
|
var extendedClipboardFormatFiles = 1 << 4;
|
|
var extendedClipboardActionCaps = 1 << 24;
|
|
var extendedClipboardActionRequest = 1 << 25;
|
|
var extendedClipboardActionPeek = 1 << 26;
|
|
var extendedClipboardActionNotify = 1 << 27;
|
|
var extendedClipboardActionProvide = 1 << 28;
|
|
var RFB = class _RFB extends EventTargetMixin {
|
|
constructor(target, urlOrChannel, options) {
|
|
if (!target) {
|
|
throw new Error("Must specify target");
|
|
}
|
|
if (!urlOrChannel) {
|
|
throw new Error("Must specify URL, WebSocket or RTCDataChannel");
|
|
}
|
|
if (!window.isSecureContext) {
|
|
Error2("noVNC requires a secure context (TLS). Expect crashes!");
|
|
}
|
|
super();
|
|
this._target = target;
|
|
if (typeof urlOrChannel === "string") {
|
|
this._url = urlOrChannel;
|
|
} else {
|
|
this._url = null;
|
|
this._rawChannel = urlOrChannel;
|
|
}
|
|
options = options || {};
|
|
this._rfbCredentials = options.credentials || {};
|
|
this._shared = "shared" in options ? !!options.shared : true;
|
|
this._repeaterID = options.repeaterID || "";
|
|
this._wsProtocols = options.wsProtocols || [];
|
|
this._rfbConnectionState = "";
|
|
this._rfbInitState = "";
|
|
this._rfbAuthScheme = -1;
|
|
this._rfbCleanDisconnect = true;
|
|
this._rfbRSAAESAuthenticationState = null;
|
|
this._rfbVersion = 0;
|
|
this._rfbMaxVersion = 3.8;
|
|
this._rfbTightVNC = false;
|
|
this._rfbVeNCryptState = 0;
|
|
this._rfbXvpVer = 0;
|
|
this._fbWidth = 0;
|
|
this._fbHeight = 0;
|
|
this._fbName = "";
|
|
this._capabilities = { power: false };
|
|
this._supportsFence = false;
|
|
this._supportsContinuousUpdates = false;
|
|
this._enabledContinuousUpdates = false;
|
|
this._supportsSetDesktopSize = false;
|
|
this._screenID = 0;
|
|
this._screenFlags = 0;
|
|
this._pendingRemoteResize = false;
|
|
this._lastResize = 0;
|
|
this._qemuExtKeyEventSupported = false;
|
|
this._extendedPointerEventSupported = false;
|
|
this._clipboardText = null;
|
|
this._clipboardServerCapabilitiesActions = {};
|
|
this._clipboardServerCapabilitiesFormats = {};
|
|
this._sock = null;
|
|
this._display = null;
|
|
this._flushing = false;
|
|
this._asyncClipboard = null;
|
|
this._keyboard = null;
|
|
this._gestures = null;
|
|
this._resizeObserver = null;
|
|
this._disconnTimer = null;
|
|
this._resizeTimeout = null;
|
|
this._mouseMoveTimer = null;
|
|
this._decoders = {};
|
|
this._FBU = {
|
|
rects: 0,
|
|
x: 0,
|
|
y: 0,
|
|
width: 0,
|
|
height: 0,
|
|
encoding: null
|
|
};
|
|
this._mousePos = {};
|
|
this._mouseButtonMask = 0;
|
|
this._mouseLastMoveTime = 0;
|
|
this._viewportDragging = false;
|
|
this._viewportDragPos = {};
|
|
this._viewportHasMoved = false;
|
|
this._accumulatedWheelDeltaX = 0;
|
|
this._accumulatedWheelDeltaY = 0;
|
|
this._gestureLastTapTime = null;
|
|
this._gestureFirstDoubleTapEv = null;
|
|
this._gestureLastMagnitudeX = 0;
|
|
this._gestureLastMagnitudeY = 0;
|
|
this._eventHandlers = {
|
|
focusCanvas: this._focusCanvas.bind(this),
|
|
handleResize: this._handleResize.bind(this),
|
|
handleMouse: this._handleMouse.bind(this),
|
|
handleWheel: this._handleWheel.bind(this),
|
|
handleGesture: this._handleGesture.bind(this),
|
|
handleRSAAESCredentialsRequired: this._handleRSAAESCredentialsRequired.bind(this),
|
|
handleRSAAESServerVerification: this._handleRSAAESServerVerification.bind(this)
|
|
};
|
|
Debug(">> RFB.constructor");
|
|
this._screen = document.createElement("div");
|
|
this._screen.style.display = "flex";
|
|
this._screen.style.width = "100%";
|
|
this._screen.style.height = "100%";
|
|
this._screen.style.overflow = "auto";
|
|
this._screen.style.background = DEFAULT_BACKGROUND;
|
|
this._canvas = document.createElement("canvas");
|
|
this._canvas.style.margin = "auto";
|
|
this._canvas.style.outline = "none";
|
|
this._canvas.width = 0;
|
|
this._canvas.height = 0;
|
|
this._canvas.tabIndex = -1;
|
|
this._screen.appendChild(this._canvas);
|
|
this._cursor = new Cursor();
|
|
this._cursorImage = _RFB.cursors.none;
|
|
this._decoders[encodings.encodingRaw] = new RawDecoder();
|
|
this._decoders[encodings.encodingCopyRect] = new CopyRectDecoder();
|
|
this._decoders[encodings.encodingRRE] = new RREDecoder();
|
|
this._decoders[encodings.encodingHextile] = new HextileDecoder();
|
|
this._decoders[encodings.encodingZlib] = new ZlibDecoder();
|
|
this._decoders[encodings.encodingTight] = new TightDecoder();
|
|
this._decoders[encodings.encodingTightPNG] = new TightPNGDecoder();
|
|
this._decoders[encodings.encodingZRLE] = new ZRLEDecoder();
|
|
this._decoders[encodings.encodingJPEG] = new JPEGDecoder();
|
|
this._decoders[encodings.encodingH264] = new H264Decoder();
|
|
try {
|
|
this._display = new Display(this._canvas);
|
|
} catch (exc) {
|
|
Error2("Display exception: " + exc);
|
|
throw exc;
|
|
}
|
|
this._asyncClipboard = new AsyncClipboard(this._canvas);
|
|
this._asyncClipboard.onpaste = this.clipboardPasteFrom.bind(this);
|
|
this._keyboard = new Keyboard(this._canvas);
|
|
this._keyboard.onkeyevent = this._handleKeyEvent.bind(this);
|
|
this._remoteCapsLock = null;
|
|
this._remoteNumLock = null;
|
|
this._gestures = new GestureHandler();
|
|
this._sock = new Websock();
|
|
this._sock.on("open", this._socketOpen.bind(this));
|
|
this._sock.on("close", this._socketClose.bind(this));
|
|
this._sock.on("message", this._handleMessage.bind(this));
|
|
this._sock.on("error", this._socketError.bind(this));
|
|
this._expectedClientWidth = null;
|
|
this._expectedClientHeight = null;
|
|
this._resizeObserver = new ResizeObserver(this._eventHandlers.handleResize);
|
|
this._updateConnectionState("connecting");
|
|
Debug("<< RFB.constructor");
|
|
this.dragViewport = false;
|
|
this.focusOnClick = true;
|
|
this._viewOnly = false;
|
|
this._clipViewport = false;
|
|
this._clippingViewport = false;
|
|
this._scaleViewport = false;
|
|
this._resizeSession = false;
|
|
this._showDotCursor = false;
|
|
this._qualityLevel = 6;
|
|
this._compressionLevel = 2;
|
|
}
|
|
// ===== PROPERTIES =====
|
|
get viewOnly() {
|
|
return this._viewOnly;
|
|
}
|
|
set viewOnly(viewOnly) {
|
|
this._viewOnly = viewOnly;
|
|
if (this._rfbConnectionState === "connecting" || this._rfbConnectionState === "connected") {
|
|
if (viewOnly) {
|
|
this._keyboard.ungrab();
|
|
this._asyncClipboard.ungrab();
|
|
} else {
|
|
this._keyboard.grab();
|
|
this._asyncClipboard.grab();
|
|
}
|
|
}
|
|
}
|
|
get capabilities() {
|
|
return this._capabilities;
|
|
}
|
|
get clippingViewport() {
|
|
return this._clippingViewport;
|
|
}
|
|
_setClippingViewport(on) {
|
|
if (on === this._clippingViewport) {
|
|
return;
|
|
}
|
|
this._clippingViewport = on;
|
|
this.dispatchEvent(new CustomEvent(
|
|
"clippingviewport",
|
|
{ detail: this._clippingViewport }
|
|
));
|
|
}
|
|
get touchButton() {
|
|
return 0;
|
|
}
|
|
set touchButton(button) {
|
|
Warn("Using old API!");
|
|
}
|
|
get clipViewport() {
|
|
return this._clipViewport;
|
|
}
|
|
set clipViewport(viewport) {
|
|
this._clipViewport = viewport;
|
|
this._updateClip();
|
|
}
|
|
get scaleViewport() {
|
|
return this._scaleViewport;
|
|
}
|
|
set scaleViewport(scale) {
|
|
this._scaleViewport = scale;
|
|
if (scale && this._clipViewport) {
|
|
this._updateClip();
|
|
}
|
|
this._updateScale();
|
|
if (!scale && this._clipViewport) {
|
|
this._updateClip();
|
|
}
|
|
}
|
|
get resizeSession() {
|
|
return this._resizeSession;
|
|
}
|
|
set resizeSession(resize) {
|
|
this._resizeSession = resize;
|
|
if (resize) {
|
|
this._requestRemoteResize();
|
|
}
|
|
}
|
|
get showDotCursor() {
|
|
return this._showDotCursor;
|
|
}
|
|
set showDotCursor(show) {
|
|
this._showDotCursor = show;
|
|
this._refreshCursor();
|
|
}
|
|
get background() {
|
|
return this._screen.style.background;
|
|
}
|
|
set background(cssValue) {
|
|
this._screen.style.background = cssValue;
|
|
}
|
|
get qualityLevel() {
|
|
return this._qualityLevel;
|
|
}
|
|
set qualityLevel(qualityLevel) {
|
|
if (!Number.isInteger(qualityLevel) || qualityLevel < 0 || qualityLevel > 9) {
|
|
Error2("qualityLevel must be an integer between 0 and 9");
|
|
return;
|
|
}
|
|
if (this._qualityLevel === qualityLevel) {
|
|
return;
|
|
}
|
|
this._qualityLevel = qualityLevel;
|
|
if (this._rfbConnectionState === "connected") {
|
|
this._sendEncodings();
|
|
}
|
|
}
|
|
get compressionLevel() {
|
|
return this._compressionLevel;
|
|
}
|
|
set compressionLevel(compressionLevel) {
|
|
if (!Number.isInteger(compressionLevel) || compressionLevel < 0 || compressionLevel > 9) {
|
|
Error2("compressionLevel must be an integer between 0 and 9");
|
|
return;
|
|
}
|
|
if (this._compressionLevel === compressionLevel) {
|
|
return;
|
|
}
|
|
this._compressionLevel = compressionLevel;
|
|
if (this._rfbConnectionState === "connected") {
|
|
this._sendEncodings();
|
|
}
|
|
}
|
|
// ===== PUBLIC METHODS =====
|
|
disconnect() {
|
|
this._updateConnectionState("disconnecting");
|
|
this._sock.off("error");
|
|
this._sock.off("message");
|
|
this._sock.off("open");
|
|
if (this._rfbRSAAESAuthenticationState !== null) {
|
|
this._rfbRSAAESAuthenticationState.disconnect();
|
|
}
|
|
}
|
|
approveServer() {
|
|
if (this._rfbRSAAESAuthenticationState !== null) {
|
|
this._rfbRSAAESAuthenticationState.approveServer();
|
|
}
|
|
}
|
|
sendCredentials(creds) {
|
|
this._rfbCredentials = creds;
|
|
this._resumeAuthentication();
|
|
}
|
|
sendCtrlAltDel() {
|
|
if (this._rfbConnectionState !== "connected" || this._viewOnly) {
|
|
return;
|
|
}
|
|
Info("Sending Ctrl-Alt-Del");
|
|
this.sendKey(keysym_default.XK_Control_L, "ControlLeft", true);
|
|
this.sendKey(keysym_default.XK_Alt_L, "AltLeft", true);
|
|
this.sendKey(keysym_default.XK_Delete, "Delete", true);
|
|
this.sendKey(keysym_default.XK_Delete, "Delete", false);
|
|
this.sendKey(keysym_default.XK_Alt_L, "AltLeft", false);
|
|
this.sendKey(keysym_default.XK_Control_L, "ControlLeft", false);
|
|
}
|
|
machineShutdown() {
|
|
this._xvpOp(1, 2);
|
|
}
|
|
machineReboot() {
|
|
this._xvpOp(1, 3);
|
|
}
|
|
machineReset() {
|
|
this._xvpOp(1, 4);
|
|
}
|
|
// Send a key press. If 'down' is not specified then send a down key
|
|
// followed by an up key.
|
|
sendKey(keysym, code, down) {
|
|
if (this._rfbConnectionState !== "connected" || this._viewOnly) {
|
|
return;
|
|
}
|
|
if (down === void 0) {
|
|
this.sendKey(keysym, code, true);
|
|
this.sendKey(keysym, code, false);
|
|
return;
|
|
}
|
|
const scancode = xtscancodes_default[code];
|
|
if (this._qemuExtKeyEventSupported && scancode) {
|
|
keysym = keysym || 0;
|
|
Info("Sending key (" + (down ? "down" : "up") + "): keysym " + keysym + ", scancode " + scancode);
|
|
_RFB.messages.QEMUExtendedKeyEvent(this._sock, keysym, down, scancode);
|
|
} else {
|
|
if (!keysym) {
|
|
return;
|
|
}
|
|
Info("Sending keysym (" + (down ? "down" : "up") + "): " + keysym);
|
|
_RFB.messages.keyEvent(this._sock, keysym, down ? 1 : 0);
|
|
}
|
|
}
|
|
focus(options) {
|
|
this._canvas.focus(options);
|
|
}
|
|
blur() {
|
|
this._canvas.blur();
|
|
}
|
|
clipboardPasteFrom(text) {
|
|
if (this._rfbConnectionState !== "connected" || this._viewOnly) {
|
|
return;
|
|
}
|
|
if (this._clipboardServerCapabilitiesFormats[extendedClipboardFormatText] && this._clipboardServerCapabilitiesActions[extendedClipboardActionNotify]) {
|
|
this._clipboardText = text;
|
|
_RFB.messages.extendedClipboardNotify(this._sock, [extendedClipboardFormatText]);
|
|
} else {
|
|
let length, i;
|
|
let data;
|
|
length = 0;
|
|
for (let codePoint of text) {
|
|
length++;
|
|
}
|
|
data = new Uint8Array(length);
|
|
i = 0;
|
|
for (let codePoint of text) {
|
|
let code = codePoint.codePointAt(0);
|
|
if (code > 255) {
|
|
code = 63;
|
|
}
|
|
data[i++] = code;
|
|
}
|
|
_RFB.messages.clientCutText(this._sock, data);
|
|
}
|
|
}
|
|
getImageData() {
|
|
return this._display.getImageData();
|
|
}
|
|
toDataURL(type, encoderOptions) {
|
|
return this._display.toDataURL(type, encoderOptions);
|
|
}
|
|
toBlob(callback, type, quality) {
|
|
return this._display.toBlob(callback, type, quality);
|
|
}
|
|
// ===== PRIVATE METHODS =====
|
|
_connect() {
|
|
Debug(">> RFB.connect");
|
|
if (this._url) {
|
|
Info(`connecting to ${this._url}`);
|
|
this._sock.open(this._url, this._wsProtocols);
|
|
} else {
|
|
Info(`attaching ${this._rawChannel} to Websock`);
|
|
this._sock.attach(this._rawChannel);
|
|
if (this._sock.readyState === "closed") {
|
|
throw Error("Cannot use already closed WebSocket/RTCDataChannel");
|
|
}
|
|
if (this._sock.readyState === "open") {
|
|
this._socketOpen();
|
|
}
|
|
}
|
|
this._target.appendChild(this._screen);
|
|
this._gestures.attach(this._canvas);
|
|
this._cursor.attach(this._canvas);
|
|
this._refreshCursor();
|
|
this._resizeObserver.observe(this._screen);
|
|
this._canvas.addEventListener("mousedown", this._eventHandlers.focusCanvas);
|
|
this._canvas.addEventListener("touchstart", this._eventHandlers.focusCanvas);
|
|
this._canvas.addEventListener("mousedown", this._eventHandlers.handleMouse);
|
|
this._canvas.addEventListener("mouseup", this._eventHandlers.handleMouse);
|
|
this._canvas.addEventListener("mousemove", this._eventHandlers.handleMouse);
|
|
this._canvas.addEventListener("click", this._eventHandlers.handleMouse);
|
|
this._canvas.addEventListener("contextmenu", this._eventHandlers.handleMouse);
|
|
this._canvas.addEventListener("wheel", this._eventHandlers.handleWheel);
|
|
this._canvas.addEventListener("gesturestart", this._eventHandlers.handleGesture);
|
|
this._canvas.addEventListener("gesturemove", this._eventHandlers.handleGesture);
|
|
this._canvas.addEventListener("gestureend", this._eventHandlers.handleGesture);
|
|
Debug("<< RFB.connect");
|
|
}
|
|
_disconnect() {
|
|
Debug(">> RFB.disconnect");
|
|
this._cursor.detach();
|
|
this._canvas.removeEventListener("gesturestart", this._eventHandlers.handleGesture);
|
|
this._canvas.removeEventListener("gesturemove", this._eventHandlers.handleGesture);
|
|
this._canvas.removeEventListener("gestureend", this._eventHandlers.handleGesture);
|
|
this._canvas.removeEventListener("wheel", this._eventHandlers.handleWheel);
|
|
this._canvas.removeEventListener("mousedown", this._eventHandlers.handleMouse);
|
|
this._canvas.removeEventListener("mouseup", this._eventHandlers.handleMouse);
|
|
this._canvas.removeEventListener("mousemove", this._eventHandlers.handleMouse);
|
|
this._canvas.removeEventListener("click", this._eventHandlers.handleMouse);
|
|
this._canvas.removeEventListener("contextmenu", this._eventHandlers.handleMouse);
|
|
this._canvas.removeEventListener("mousedown", this._eventHandlers.focusCanvas);
|
|
this._canvas.removeEventListener("touchstart", this._eventHandlers.focusCanvas);
|
|
this._resizeObserver.disconnect();
|
|
this._keyboard.ungrab();
|
|
this._gestures.detach();
|
|
this._sock.close();
|
|
try {
|
|
this._target.removeChild(this._screen);
|
|
} catch (e2) {
|
|
if (e2.name === "NotFoundError") {
|
|
} else {
|
|
throw e2;
|
|
}
|
|
}
|
|
clearTimeout(this._resizeTimeout);
|
|
clearTimeout(this._mouseMoveTimer);
|
|
Debug("<< RFB.disconnect");
|
|
}
|
|
_socketOpen() {
|
|
if (this._rfbConnectionState === "connecting" && this._rfbInitState === "") {
|
|
this._rfbInitState = "ProtocolVersion";
|
|
Debug("Starting VNC handshake");
|
|
} else {
|
|
this._fail("Unexpected server connection while " + this._rfbConnectionState);
|
|
}
|
|
}
|
|
_socketClose(e2) {
|
|
Debug("WebSocket on-close event");
|
|
let msg = "";
|
|
if (e2.code) {
|
|
msg = "(code: " + e2.code;
|
|
if (e2.reason) {
|
|
msg += ", reason: " + e2.reason;
|
|
}
|
|
msg += ")";
|
|
}
|
|
switch (this._rfbConnectionState) {
|
|
case "connecting":
|
|
this._fail("Connection closed " + msg);
|
|
break;
|
|
case "connected":
|
|
this._updateConnectionState("disconnecting");
|
|
this._updateConnectionState("disconnected");
|
|
break;
|
|
case "disconnecting":
|
|
this._updateConnectionState("disconnected");
|
|
break;
|
|
case "disconnected":
|
|
this._fail("Unexpected server disconnect when already disconnected " + msg);
|
|
break;
|
|
default:
|
|
this._fail("Unexpected server disconnect before connecting " + msg);
|
|
break;
|
|
}
|
|
this._sock.off("close");
|
|
this._rawChannel = null;
|
|
}
|
|
_socketError(e2) {
|
|
Warn("WebSocket on-error event");
|
|
}
|
|
_focusCanvas(event) {
|
|
if (!this.focusOnClick) {
|
|
return;
|
|
}
|
|
this.focus({ preventScroll: true });
|
|
}
|
|
_setDesktopName(name) {
|
|
this._fbName = name;
|
|
this.dispatchEvent(new CustomEvent(
|
|
"desktopname",
|
|
{ detail: { name: this._fbName } }
|
|
));
|
|
}
|
|
_saveExpectedClientSize() {
|
|
this._expectedClientWidth = this._screen.clientWidth;
|
|
this._expectedClientHeight = this._screen.clientHeight;
|
|
}
|
|
_currentClientSize() {
|
|
return [this._screen.clientWidth, this._screen.clientHeight];
|
|
}
|
|
_clientHasExpectedSize() {
|
|
const [currentWidth, currentHeight] = this._currentClientSize();
|
|
return currentWidth == this._expectedClientWidth && currentHeight == this._expectedClientHeight;
|
|
}
|
|
// Handle browser window resizes
|
|
_handleResize() {
|
|
if (this._clientHasExpectedSize()) {
|
|
return;
|
|
}
|
|
window.requestAnimationFrame(() => {
|
|
this._updateClip();
|
|
this._updateScale();
|
|
this._saveExpectedClientSize();
|
|
});
|
|
this._requestRemoteResize();
|
|
}
|
|
// Update state of clipping in Display object, and make sure the
|
|
// configured viewport matches the current screen size
|
|
_updateClip() {
|
|
const curClip = this._display.clipViewport;
|
|
let newClip = this._clipViewport;
|
|
if (this._scaleViewport) {
|
|
newClip = false;
|
|
}
|
|
if (curClip !== newClip) {
|
|
this._display.clipViewport = newClip;
|
|
}
|
|
if (newClip) {
|
|
const size = this._screenSize();
|
|
this._display.viewportChangeSize(size.w, size.h);
|
|
this._fixScrollbars();
|
|
this._setClippingViewport(size.w < this._display.width || size.h < this._display.height);
|
|
} else {
|
|
this._setClippingViewport(false);
|
|
}
|
|
if (curClip !== newClip) {
|
|
this._saveExpectedClientSize();
|
|
}
|
|
}
|
|
_updateScale() {
|
|
if (!this._scaleViewport) {
|
|
this._display.scale = 1;
|
|
} else {
|
|
const size = this._screenSize();
|
|
this._display.autoscale(size.w, size.h);
|
|
}
|
|
this._fixScrollbars();
|
|
}
|
|
// Requests a change of remote desktop size. This message is an extension
|
|
// and may only be sent if we have received an ExtendedDesktopSize message
|
|
_requestRemoteResize() {
|
|
if (!this._resizeSession) {
|
|
return;
|
|
}
|
|
if (this._viewOnly) {
|
|
return;
|
|
}
|
|
if (!this._supportsSetDesktopSize) {
|
|
return;
|
|
}
|
|
if (this._pendingRemoteResize) {
|
|
return;
|
|
}
|
|
if (Date.now() - this._lastResize < 100) {
|
|
clearTimeout(this._resizeTimeout);
|
|
this._resizeTimeout = setTimeout(
|
|
this._requestRemoteResize.bind(this),
|
|
100 - (Date.now() - this._lastResize)
|
|
);
|
|
return;
|
|
}
|
|
this._resizeTimeout = null;
|
|
const size = this._screenSize();
|
|
if (size.w === this._fbWidth && size.h === this._fbHeight) {
|
|
return;
|
|
}
|
|
this._pendingRemoteResize = true;
|
|
this._lastResize = Date.now();
|
|
_RFB.messages.setDesktopSize(
|
|
this._sock,
|
|
Math.floor(size.w),
|
|
Math.floor(size.h),
|
|
this._screenID,
|
|
this._screenFlags
|
|
);
|
|
Debug("Requested new desktop size: " + size.w + "x" + size.h);
|
|
}
|
|
// Gets the the size of the available screen
|
|
_screenSize() {
|
|
let r = this._screen.getBoundingClientRect();
|
|
return { w: r.width, h: r.height };
|
|
}
|
|
_fixScrollbars() {
|
|
const orig = this._screen.style.overflow;
|
|
this._screen.style.overflow = "hidden";
|
|
this._screen.getBoundingClientRect();
|
|
this._screen.style.overflow = orig;
|
|
}
|
|
/*
|
|
* Connection states:
|
|
* connecting
|
|
* connected
|
|
* disconnecting
|
|
* disconnected - permanent state
|
|
*/
|
|
_updateConnectionState(state) {
|
|
const oldstate = this._rfbConnectionState;
|
|
if (state === oldstate) {
|
|
Debug("Already in state '" + state + "', ignoring");
|
|
return;
|
|
}
|
|
if (oldstate === "disconnected") {
|
|
Error2("Tried changing state of a disconnected RFB object");
|
|
return;
|
|
}
|
|
switch (state) {
|
|
case "connected":
|
|
if (oldstate !== "connecting") {
|
|
Error2("Bad transition to connected state, previous connection state: " + oldstate);
|
|
return;
|
|
}
|
|
break;
|
|
case "disconnected":
|
|
if (oldstate !== "disconnecting") {
|
|
Error2("Bad transition to disconnected state, previous connection state: " + oldstate);
|
|
return;
|
|
}
|
|
break;
|
|
case "connecting":
|
|
if (oldstate !== "") {
|
|
Error2("Bad transition to connecting state, previous connection state: " + oldstate);
|
|
return;
|
|
}
|
|
break;
|
|
case "disconnecting":
|
|
if (oldstate !== "connected" && oldstate !== "connecting") {
|
|
Error2("Bad transition to disconnecting state, previous connection state: " + oldstate);
|
|
return;
|
|
}
|
|
break;
|
|
default:
|
|
Error2("Unknown connection state: " + state);
|
|
return;
|
|
}
|
|
this._rfbConnectionState = state;
|
|
Debug("New state '" + state + "', was '" + oldstate + "'.");
|
|
if (this._disconnTimer && state !== "disconnecting") {
|
|
Debug("Clearing disconnect timer");
|
|
clearTimeout(this._disconnTimer);
|
|
this._disconnTimer = null;
|
|
this._sock.off("close");
|
|
}
|
|
switch (state) {
|
|
case "connecting":
|
|
this._connect();
|
|
break;
|
|
case "connected":
|
|
this.dispatchEvent(new CustomEvent("connect", { detail: {} }));
|
|
break;
|
|
case "disconnecting":
|
|
this._disconnect();
|
|
this._disconnTimer = setTimeout(() => {
|
|
Error2("Disconnection timed out.");
|
|
this._updateConnectionState("disconnected");
|
|
}, DISCONNECT_TIMEOUT * 1e3);
|
|
break;
|
|
case "disconnected":
|
|
this.dispatchEvent(new CustomEvent(
|
|
"disconnect",
|
|
{ detail: { clean: this._rfbCleanDisconnect } }
|
|
));
|
|
break;
|
|
}
|
|
}
|
|
/* Print errors and disconnect
|
|
*
|
|
* The parameter 'details' is used for information that
|
|
* should be logged but not sent to the user interface.
|
|
*/
|
|
_fail(details) {
|
|
switch (this._rfbConnectionState) {
|
|
case "disconnecting":
|
|
Error2("Failed when disconnecting: " + details);
|
|
break;
|
|
case "connected":
|
|
Error2("Failed while connected: " + details);
|
|
break;
|
|
case "connecting":
|
|
Error2("Failed when connecting: " + details);
|
|
break;
|
|
default:
|
|
Error2("RFB failure: " + details);
|
|
break;
|
|
}
|
|
this._rfbCleanDisconnect = false;
|
|
this._updateConnectionState("disconnecting");
|
|
this._updateConnectionState("disconnected");
|
|
return false;
|
|
}
|
|
_setCapability(cap, val) {
|
|
this._capabilities[cap] = val;
|
|
this.dispatchEvent(new CustomEvent(
|
|
"capabilities",
|
|
{ detail: { capabilities: this._capabilities } }
|
|
));
|
|
}
|
|
_handleMessage() {
|
|
if (this._sock.rQwait("message", 1)) {
|
|
Warn("handleMessage called on an empty receive queue");
|
|
return;
|
|
}
|
|
switch (this._rfbConnectionState) {
|
|
case "disconnected":
|
|
Error2("Got data while disconnected");
|
|
break;
|
|
case "connected":
|
|
while (true) {
|
|
if (this._flushing) {
|
|
break;
|
|
}
|
|
if (!this._normalMsg()) {
|
|
break;
|
|
}
|
|
if (this._sock.rQwait("message", 1)) {
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
case "connecting":
|
|
while (this._rfbConnectionState === "connecting") {
|
|
if (!this._initMsg()) {
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
Error2("Got data while in an invalid state");
|
|
break;
|
|
}
|
|
}
|
|
_handleKeyEvent(keysym, code, down, numlock, capslock) {
|
|
if (code == "CapsLock" && down) {
|
|
this._remoteCapsLock = null;
|
|
}
|
|
if (this._remoteCapsLock !== null && capslock !== null && this._remoteCapsLock !== capslock && down) {
|
|
Debug("Fixing remote caps lock");
|
|
this.sendKey(keysym_default.XK_Caps_Lock, "CapsLock", true);
|
|
this.sendKey(keysym_default.XK_Caps_Lock, "CapsLock", false);
|
|
this._remoteCapsLock = null;
|
|
}
|
|
if (code == "NumLock" && down) {
|
|
this._remoteNumLock = null;
|
|
}
|
|
if (this._remoteNumLock !== null && numlock !== null && this._remoteNumLock !== numlock && down) {
|
|
Debug("Fixing remote num lock");
|
|
this.sendKey(keysym_default.XK_Num_Lock, "NumLock", true);
|
|
this.sendKey(keysym_default.XK_Num_Lock, "NumLock", false);
|
|
this._remoteNumLock = null;
|
|
}
|
|
this.sendKey(keysym, code, down);
|
|
}
|
|
static _convertButtonMask(buttons) {
|
|
const buttonMaskMap = {
|
|
0: 1 << 0,
|
|
// Left
|
|
1: 1 << 2,
|
|
// Right
|
|
2: 1 << 1,
|
|
// Middle
|
|
3: 1 << 7,
|
|
// Back
|
|
4: 1 << 8
|
|
// Forward
|
|
};
|
|
let bmask = 0;
|
|
for (let i = 0; i < 5; i++) {
|
|
if (buttons & 1 << i) {
|
|
bmask |= buttonMaskMap[i];
|
|
}
|
|
}
|
|
return bmask;
|
|
}
|
|
_handleMouse(ev) {
|
|
if (ev.type === "click") {
|
|
if (ev.target !== this._canvas) {
|
|
return;
|
|
}
|
|
}
|
|
ev.stopPropagation();
|
|
ev.preventDefault();
|
|
if (ev.type === "click" || ev.type === "contextmenu") {
|
|
return;
|
|
}
|
|
let pos = clientToElement(
|
|
ev.clientX,
|
|
ev.clientY,
|
|
this._canvas
|
|
);
|
|
let bmask = _RFB._convertButtonMask(ev.buttons);
|
|
let down = ev.type == "mousedown";
|
|
switch (ev.type) {
|
|
case "mousedown":
|
|
case "mouseup":
|
|
if (this.dragViewport) {
|
|
if (down && !this._viewportDragging) {
|
|
this._viewportDragging = true;
|
|
this._viewportDragPos = { "x": pos.x, "y": pos.y };
|
|
this._viewportHasMoved = false;
|
|
this._flushMouseMoveTimer(pos.x, pos.y);
|
|
this._mouseButtonMask = bmask;
|
|
break;
|
|
} else {
|
|
this._viewportDragging = false;
|
|
if (this._viewportHasMoved) {
|
|
this._mouseButtonMask = bmask;
|
|
break;
|
|
}
|
|
this._sendMouse(pos.x, pos.y, this._mouseButtonMask);
|
|
}
|
|
}
|
|
if (down) {
|
|
setCapture(this._canvas);
|
|
}
|
|
this._handleMouseButton(pos.x, pos.y, bmask);
|
|
break;
|
|
case "mousemove":
|
|
if (this._viewportDragging) {
|
|
const deltaX = this._viewportDragPos.x - pos.x;
|
|
const deltaY = this._viewportDragPos.y - pos.y;
|
|
if (this._viewportHasMoved || (Math.abs(deltaX) > dragThreshold || Math.abs(deltaY) > dragThreshold)) {
|
|
this._viewportHasMoved = true;
|
|
this._viewportDragPos = { "x": pos.x, "y": pos.y };
|
|
this._display.viewportChangePos(deltaX, deltaY);
|
|
}
|
|
break;
|
|
}
|
|
this._handleMouseMove(pos.x, pos.y);
|
|
break;
|
|
}
|
|
}
|
|
_handleMouseButton(x, y, bmask) {
|
|
this._flushMouseMoveTimer(x, y);
|
|
this._mouseButtonMask = bmask;
|
|
this._sendMouse(x, y, this._mouseButtonMask);
|
|
}
|
|
_handleMouseMove(x, y) {
|
|
this._mousePos = { "x": x, "y": y };
|
|
if (this._mouseMoveTimer == null) {
|
|
const timeSinceLastMove = Date.now() - this._mouseLastMoveTime;
|
|
if (timeSinceLastMove > MOUSE_MOVE_DELAY) {
|
|
this._sendMouse(x, y, this._mouseButtonMask);
|
|
this._mouseLastMoveTime = Date.now();
|
|
} else {
|
|
this._mouseMoveTimer = setTimeout(() => {
|
|
this._handleDelayedMouseMove();
|
|
}, MOUSE_MOVE_DELAY - timeSinceLastMove);
|
|
}
|
|
}
|
|
}
|
|
_handleDelayedMouseMove() {
|
|
this._mouseMoveTimer = null;
|
|
this._sendMouse(
|
|
this._mousePos.x,
|
|
this._mousePos.y,
|
|
this._mouseButtonMask
|
|
);
|
|
this._mouseLastMoveTime = Date.now();
|
|
}
|
|
_sendMouse(x, y, mask) {
|
|
if (this._rfbConnectionState !== "connected") {
|
|
return;
|
|
}
|
|
if (this._viewOnly) {
|
|
return;
|
|
}
|
|
if (mask & 32768) {
|
|
throw new Error("Illegal mouse button mask (mask: " + mask + ")");
|
|
}
|
|
let extendedMouseButtons = mask & 32640;
|
|
if (this._extendedPointerEventSupported && extendedMouseButtons) {
|
|
_RFB.messages.extendedPointerEvent(
|
|
this._sock,
|
|
this._display.absX(x),
|
|
this._display.absY(y),
|
|
mask
|
|
);
|
|
} else {
|
|
_RFB.messages.pointerEvent(
|
|
this._sock,
|
|
this._display.absX(x),
|
|
this._display.absY(y),
|
|
mask
|
|
);
|
|
}
|
|
}
|
|
_handleWheel(ev) {
|
|
if (this._rfbConnectionState !== "connected") {
|
|
return;
|
|
}
|
|
if (this._viewOnly) {
|
|
return;
|
|
}
|
|
ev.stopPropagation();
|
|
ev.preventDefault();
|
|
let pos = clientToElement(
|
|
ev.clientX,
|
|
ev.clientY,
|
|
this._canvas
|
|
);
|
|
let bmask = _RFB._convertButtonMask(ev.buttons);
|
|
let dX = ev.deltaX;
|
|
let dY = ev.deltaY;
|
|
if (ev.deltaMode !== 0) {
|
|
dX *= WHEEL_LINE_HEIGHT;
|
|
dY *= WHEEL_LINE_HEIGHT;
|
|
}
|
|
this._accumulatedWheelDeltaX += dX;
|
|
this._accumulatedWheelDeltaY += dY;
|
|
if (Math.abs(this._accumulatedWheelDeltaX) >= WHEEL_STEP) {
|
|
if (this._accumulatedWheelDeltaX < 0) {
|
|
this._handleMouseButton(pos.x, pos.y, bmask | 1 << 5);
|
|
this._handleMouseButton(pos.x, pos.y, bmask);
|
|
} else if (this._accumulatedWheelDeltaX > 0) {
|
|
this._handleMouseButton(pos.x, pos.y, bmask | 1 << 6);
|
|
this._handleMouseButton(pos.x, pos.y, bmask);
|
|
}
|
|
this._accumulatedWheelDeltaX = 0;
|
|
}
|
|
if (Math.abs(this._accumulatedWheelDeltaY) >= WHEEL_STEP) {
|
|
if (this._accumulatedWheelDeltaY < 0) {
|
|
this._handleMouseButton(pos.x, pos.y, bmask | 1 << 3);
|
|
this._handleMouseButton(pos.x, pos.y, bmask);
|
|
} else if (this._accumulatedWheelDeltaY > 0) {
|
|
this._handleMouseButton(pos.x, pos.y, bmask | 1 << 4);
|
|
this._handleMouseButton(pos.x, pos.y, bmask);
|
|
}
|
|
this._accumulatedWheelDeltaY = 0;
|
|
}
|
|
}
|
|
_fakeMouseMove(ev, elementX, elementY) {
|
|
this._handleMouseMove(elementX, elementY);
|
|
this._cursor.move(ev.detail.clientX, ev.detail.clientY);
|
|
}
|
|
_handleTapEvent(ev, bmask) {
|
|
let pos = clientToElement(
|
|
ev.detail.clientX,
|
|
ev.detail.clientY,
|
|
this._canvas
|
|
);
|
|
if (this._gestureLastTapTime !== null && Date.now() - this._gestureLastTapTime < DOUBLE_TAP_TIMEOUT && this._gestureFirstDoubleTapEv.detail.type === ev.detail.type) {
|
|
let dx = this._gestureFirstDoubleTapEv.detail.clientX - ev.detail.clientX;
|
|
let dy = this._gestureFirstDoubleTapEv.detail.clientY - ev.detail.clientY;
|
|
let distance = Math.hypot(dx, dy);
|
|
if (distance < DOUBLE_TAP_THRESHOLD) {
|
|
pos = clientToElement(
|
|
this._gestureFirstDoubleTapEv.detail.clientX,
|
|
this._gestureFirstDoubleTapEv.detail.clientY,
|
|
this._canvas
|
|
);
|
|
} else {
|
|
this._gestureFirstDoubleTapEv = ev;
|
|
}
|
|
} else {
|
|
this._gestureFirstDoubleTapEv = ev;
|
|
}
|
|
this._gestureLastTapTime = Date.now();
|
|
this._fakeMouseMove(this._gestureFirstDoubleTapEv, pos.x, pos.y);
|
|
this._handleMouseButton(pos.x, pos.y, bmask);
|
|
this._handleMouseButton(pos.x, pos.y, 0);
|
|
}
|
|
_handleGesture(ev) {
|
|
let magnitude;
|
|
let pos = clientToElement(
|
|
ev.detail.clientX,
|
|
ev.detail.clientY,
|
|
this._canvas
|
|
);
|
|
switch (ev.type) {
|
|
case "gesturestart":
|
|
switch (ev.detail.type) {
|
|
case "onetap":
|
|
this._handleTapEvent(ev, 1);
|
|
break;
|
|
case "twotap":
|
|
this._handleTapEvent(ev, 4);
|
|
break;
|
|
case "threetap":
|
|
this._handleTapEvent(ev, 2);
|
|
break;
|
|
case "drag":
|
|
if (this.dragViewport) {
|
|
this._viewportHasMoved = false;
|
|
this._viewportDragging = true;
|
|
this._viewportDragPos = { "x": pos.x, "y": pos.y };
|
|
} else {
|
|
this._fakeMouseMove(ev, pos.x, pos.y);
|
|
this._handleMouseButton(pos.x, pos.y, 1);
|
|
}
|
|
break;
|
|
case "longpress":
|
|
if (this.dragViewport) {
|
|
this._viewportHasMoved = false;
|
|
this._viewportDragPos = { "x": pos.x, "y": pos.y };
|
|
} else {
|
|
this._fakeMouseMove(ev, pos.x, pos.y);
|
|
this._handleMouseButton(pos.x, pos.y, 4);
|
|
}
|
|
break;
|
|
case "twodrag":
|
|
this._gestureLastMagnitudeX = ev.detail.magnitudeX;
|
|
this._gestureLastMagnitudeY = ev.detail.magnitudeY;
|
|
this._fakeMouseMove(ev, pos.x, pos.y);
|
|
break;
|
|
case "pinch":
|
|
this._gestureLastMagnitudeX = Math.hypot(
|
|
ev.detail.magnitudeX,
|
|
ev.detail.magnitudeY
|
|
);
|
|
this._fakeMouseMove(ev, pos.x, pos.y);
|
|
break;
|
|
}
|
|
break;
|
|
case "gesturemove":
|
|
switch (ev.detail.type) {
|
|
case "onetap":
|
|
case "twotap":
|
|
case "threetap":
|
|
break;
|
|
case "drag":
|
|
case "longpress":
|
|
if (this.dragViewport) {
|
|
this._viewportDragging = true;
|
|
const deltaX = this._viewportDragPos.x - pos.x;
|
|
const deltaY = this._viewportDragPos.y - pos.y;
|
|
if (this._viewportHasMoved || (Math.abs(deltaX) > dragThreshold || Math.abs(deltaY) > dragThreshold)) {
|
|
this._viewportHasMoved = true;
|
|
this._viewportDragPos = { "x": pos.x, "y": pos.y };
|
|
this._display.viewportChangePos(deltaX, deltaY);
|
|
}
|
|
} else {
|
|
this._fakeMouseMove(ev, pos.x, pos.y);
|
|
}
|
|
break;
|
|
case "twodrag":
|
|
this._fakeMouseMove(ev, pos.x, pos.y);
|
|
while (ev.detail.magnitudeY - this._gestureLastMagnitudeY > GESTURE_SCRLSENS) {
|
|
this._handleMouseButton(pos.x, pos.y, 8);
|
|
this._handleMouseButton(pos.x, pos.y, 0);
|
|
this._gestureLastMagnitudeY += GESTURE_SCRLSENS;
|
|
}
|
|
while (ev.detail.magnitudeY - this._gestureLastMagnitudeY < -GESTURE_SCRLSENS) {
|
|
this._handleMouseButton(pos.x, pos.y, 16);
|
|
this._handleMouseButton(pos.x, pos.y, 0);
|
|
this._gestureLastMagnitudeY -= GESTURE_SCRLSENS;
|
|
}
|
|
while (ev.detail.magnitudeX - this._gestureLastMagnitudeX > GESTURE_SCRLSENS) {
|
|
this._handleMouseButton(pos.x, pos.y, 32);
|
|
this._handleMouseButton(pos.x, pos.y, 0);
|
|
this._gestureLastMagnitudeX += GESTURE_SCRLSENS;
|
|
}
|
|
while (ev.detail.magnitudeX - this._gestureLastMagnitudeX < -GESTURE_SCRLSENS) {
|
|
this._handleMouseButton(pos.x, pos.y, 64);
|
|
this._handleMouseButton(pos.x, pos.y, 0);
|
|
this._gestureLastMagnitudeX -= GESTURE_SCRLSENS;
|
|
}
|
|
break;
|
|
case "pinch":
|
|
this._fakeMouseMove(ev, pos.x, pos.y);
|
|
magnitude = Math.hypot(ev.detail.magnitudeX, ev.detail.magnitudeY);
|
|
if (Math.abs(magnitude - this._gestureLastMagnitudeX) > GESTURE_ZOOMSENS) {
|
|
this._handleKeyEvent(keysym_default.XK_Control_L, "ControlLeft", true);
|
|
while (magnitude - this._gestureLastMagnitudeX > GESTURE_ZOOMSENS) {
|
|
this._handleMouseButton(pos.x, pos.y, 8);
|
|
this._handleMouseButton(pos.x, pos.y, 0);
|
|
this._gestureLastMagnitudeX += GESTURE_ZOOMSENS;
|
|
}
|
|
while (magnitude - this._gestureLastMagnitudeX < -GESTURE_ZOOMSENS) {
|
|
this._handleMouseButton(pos.x, pos.y, 16);
|
|
this._handleMouseButton(pos.x, pos.y, 0);
|
|
this._gestureLastMagnitudeX -= GESTURE_ZOOMSENS;
|
|
}
|
|
}
|
|
this._handleKeyEvent(keysym_default.XK_Control_L, "ControlLeft", false);
|
|
break;
|
|
}
|
|
break;
|
|
case "gestureend":
|
|
switch (ev.detail.type) {
|
|
case "onetap":
|
|
case "twotap":
|
|
case "threetap":
|
|
case "pinch":
|
|
case "twodrag":
|
|
break;
|
|
case "drag":
|
|
if (this.dragViewport) {
|
|
this._viewportDragging = false;
|
|
} else {
|
|
this._fakeMouseMove(ev, pos.x, pos.y);
|
|
this._handleMouseButton(pos.x, pos.y, 0);
|
|
}
|
|
break;
|
|
case "longpress":
|
|
if (this._viewportHasMoved) {
|
|
break;
|
|
}
|
|
if (this.dragViewport && !this._viewportHasMoved) {
|
|
this._fakeMouseMove(ev, pos.x, pos.y);
|
|
this._handleMouseButton(pos.x, pos.y, 4);
|
|
this._handleMouseButton(pos.x, pos.y, 0);
|
|
this._viewportDragging = false;
|
|
} else {
|
|
this._fakeMouseMove(ev, pos.x, pos.y);
|
|
this._handleMouseButton(pos.x, pos.y, 0);
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
_flushMouseMoveTimer(x, y) {
|
|
if (this._mouseMoveTimer !== null) {
|
|
clearTimeout(this._mouseMoveTimer);
|
|
this._mouseMoveTimer = null;
|
|
this._sendMouse(x, y, this._mouseButtonMask);
|
|
}
|
|
}
|
|
// Message handlers
|
|
_negotiateProtocolVersion() {
|
|
if (this._sock.rQwait("version", 12)) {
|
|
return false;
|
|
}
|
|
const sversion = this._sock.rQshiftStr(12).substr(4, 7);
|
|
Info("Server ProtocolVersion: " + sversion);
|
|
let isRepeater = 0;
|
|
switch (sversion) {
|
|
case "000.000":
|
|
isRepeater = 1;
|
|
break;
|
|
case "003.003":
|
|
case "003.006":
|
|
this._rfbVersion = 3.3;
|
|
break;
|
|
case "003.007":
|
|
this._rfbVersion = 3.7;
|
|
break;
|
|
case "003.008":
|
|
case "003.889":
|
|
// Apple Remote Desktop
|
|
case "004.000":
|
|
// Intel AMT KVM
|
|
case "004.001":
|
|
// RealVNC 4.6
|
|
case "005.000":
|
|
this._rfbVersion = 3.8;
|
|
break;
|
|
default:
|
|
return this._fail("Invalid server version " + sversion);
|
|
}
|
|
if (isRepeater) {
|
|
let repeaterID = "ID:" + this._repeaterID;
|
|
while (repeaterID.length < 250) {
|
|
repeaterID += "\0";
|
|
}
|
|
this._sock.sQpushString(repeaterID);
|
|
this._sock.flush();
|
|
return true;
|
|
}
|
|
if (this._rfbVersion > this._rfbMaxVersion) {
|
|
this._rfbVersion = this._rfbMaxVersion;
|
|
}
|
|
const cversion = "00" + parseInt(this._rfbVersion, 10) + ".00" + this._rfbVersion * 10 % 10;
|
|
this._sock.sQpushString("RFB " + cversion + "\n");
|
|
this._sock.flush();
|
|
Debug("Sent ProtocolVersion: " + cversion);
|
|
this._rfbInitState = "Security";
|
|
}
|
|
_isSupportedSecurityType(type) {
|
|
const clientTypes = [
|
|
securityTypeNone,
|
|
securityTypeVNCAuth,
|
|
securityTypeRA2ne,
|
|
securityTypeTight,
|
|
securityTypeVeNCrypt,
|
|
securityTypeXVP,
|
|
securityTypeARD,
|
|
securityTypeMSLogonII,
|
|
securityTypePlain
|
|
];
|
|
return clientTypes.includes(type);
|
|
}
|
|
_negotiateSecurity() {
|
|
if (this._rfbVersion >= 3.7) {
|
|
const numTypes = this._sock.rQshift8();
|
|
if (this._sock.rQwait("security type", numTypes, 1)) {
|
|
return false;
|
|
}
|
|
if (numTypes === 0) {
|
|
this._rfbInitState = "SecurityReason";
|
|
this._securityContext = "no security types";
|
|
this._securityStatus = 1;
|
|
return true;
|
|
}
|
|
const types = this._sock.rQshiftBytes(numTypes);
|
|
Debug("Server security types: " + types);
|
|
this._rfbAuthScheme = -1;
|
|
for (let type of types) {
|
|
if (this._isSupportedSecurityType(type)) {
|
|
this._rfbAuthScheme = type;
|
|
break;
|
|
}
|
|
}
|
|
if (this._rfbAuthScheme === -1) {
|
|
return this._fail("Unsupported security types (types: " + types + ")");
|
|
}
|
|
this._sock.sQpush8(this._rfbAuthScheme);
|
|
this._sock.flush();
|
|
} else {
|
|
if (this._sock.rQwait("security scheme", 4)) {
|
|
return false;
|
|
}
|
|
this._rfbAuthScheme = this._sock.rQshift32();
|
|
if (this._rfbAuthScheme == 0) {
|
|
this._rfbInitState = "SecurityReason";
|
|
this._securityContext = "authentication scheme";
|
|
this._securityStatus = 1;
|
|
return true;
|
|
}
|
|
}
|
|
this._rfbInitState = "Authentication";
|
|
Debug("Authenticating using scheme: " + this._rfbAuthScheme);
|
|
return true;
|
|
}
|
|
_handleSecurityReason() {
|
|
if (this._sock.rQwait("reason length", 4)) {
|
|
return false;
|
|
}
|
|
const strlen = this._sock.rQshift32();
|
|
let reason = "";
|
|
if (strlen > 0) {
|
|
if (this._sock.rQwait("reason", strlen, 4)) {
|
|
return false;
|
|
}
|
|
reason = this._sock.rQshiftStr(strlen);
|
|
}
|
|
if (reason !== "") {
|
|
this.dispatchEvent(new CustomEvent(
|
|
"securityfailure",
|
|
{ detail: {
|
|
status: this._securityStatus,
|
|
reason
|
|
} }
|
|
));
|
|
return this._fail("Security negotiation failed on " + this._securityContext + " (reason: " + reason + ")");
|
|
} else {
|
|
this.dispatchEvent(new CustomEvent(
|
|
"securityfailure",
|
|
{ detail: { status: this._securityStatus } }
|
|
));
|
|
return this._fail("Security negotiation failed on " + this._securityContext);
|
|
}
|
|
}
|
|
// authentication
|
|
_negotiateXvpAuth() {
|
|
if (this._rfbCredentials.username === void 0 || this._rfbCredentials.password === void 0 || this._rfbCredentials.target === void 0) {
|
|
this.dispatchEvent(new CustomEvent(
|
|
"credentialsrequired",
|
|
{ detail: { types: ["username", "password", "target"] } }
|
|
));
|
|
return false;
|
|
}
|
|
this._sock.sQpush8(this._rfbCredentials.username.length);
|
|
this._sock.sQpush8(this._rfbCredentials.target.length);
|
|
this._sock.sQpushString(this._rfbCredentials.username);
|
|
this._sock.sQpushString(this._rfbCredentials.target);
|
|
this._sock.flush();
|
|
this._rfbAuthScheme = securityTypeVNCAuth;
|
|
return this._negotiateAuthentication();
|
|
}
|
|
// VeNCrypt authentication, currently only supports version 0.2 and only Plain subtype
|
|
_negotiateVeNCryptAuth() {
|
|
if (this._rfbVeNCryptState == 0) {
|
|
if (this._sock.rQwait("vencrypt version", 2)) {
|
|
return false;
|
|
}
|
|
const major = this._sock.rQshift8();
|
|
const minor = this._sock.rQshift8();
|
|
if (!(major == 0 && minor == 2)) {
|
|
return this._fail("Unsupported VeNCrypt version " + major + "." + minor);
|
|
}
|
|
this._sock.sQpush8(0);
|
|
this._sock.sQpush8(2);
|
|
this._sock.flush();
|
|
this._rfbVeNCryptState = 1;
|
|
}
|
|
if (this._rfbVeNCryptState == 1) {
|
|
if (this._sock.rQwait("vencrypt ack", 1)) {
|
|
return false;
|
|
}
|
|
const res = this._sock.rQshift8();
|
|
if (res != 0) {
|
|
return this._fail("VeNCrypt failure " + res);
|
|
}
|
|
this._rfbVeNCryptState = 2;
|
|
}
|
|
if (this._rfbVeNCryptState == 2) {
|
|
if (this._sock.rQwait("vencrypt subtypes length", 1)) {
|
|
return false;
|
|
}
|
|
const subtypesLength = this._sock.rQshift8();
|
|
if (subtypesLength < 1) {
|
|
return this._fail("VeNCrypt subtypes empty");
|
|
}
|
|
this._rfbVeNCryptSubtypesLength = subtypesLength;
|
|
this._rfbVeNCryptState = 3;
|
|
}
|
|
if (this._rfbVeNCryptState == 3) {
|
|
if (this._sock.rQwait("vencrypt subtypes", 4 * this._rfbVeNCryptSubtypesLength)) {
|
|
return false;
|
|
}
|
|
const subtypes = [];
|
|
for (let i = 0; i < this._rfbVeNCryptSubtypesLength; i++) {
|
|
subtypes.push(this._sock.rQshift32());
|
|
}
|
|
this._rfbAuthScheme = -1;
|
|
for (let type of subtypes) {
|
|
if (type === securityTypeVeNCrypt) {
|
|
continue;
|
|
}
|
|
if (this._isSupportedSecurityType(type)) {
|
|
this._rfbAuthScheme = type;
|
|
break;
|
|
}
|
|
}
|
|
if (this._rfbAuthScheme === -1) {
|
|
return this._fail("Unsupported security types (types: " + subtypes + ")");
|
|
}
|
|
this._sock.sQpush32(this._rfbAuthScheme);
|
|
this._sock.flush();
|
|
this._rfbVeNCryptState = 4;
|
|
return true;
|
|
}
|
|
}
|
|
_negotiatePlainAuth() {
|
|
if (this._rfbCredentials.username === void 0 || this._rfbCredentials.password === void 0) {
|
|
this.dispatchEvent(new CustomEvent(
|
|
"credentialsrequired",
|
|
{ detail: { types: ["username", "password"] } }
|
|
));
|
|
return false;
|
|
}
|
|
const user = encodeUTF8(this._rfbCredentials.username);
|
|
const pass = encodeUTF8(this._rfbCredentials.password);
|
|
this._sock.sQpush32(user.length);
|
|
this._sock.sQpush32(pass.length);
|
|
this._sock.sQpushString(user);
|
|
this._sock.sQpushString(pass);
|
|
this._sock.flush();
|
|
this._rfbInitState = "SecurityResult";
|
|
return true;
|
|
}
|
|
_negotiateStdVNCAuth() {
|
|
if (this._sock.rQwait("auth challenge", 16)) {
|
|
return false;
|
|
}
|
|
if (this._rfbCredentials.password === void 0) {
|
|
this.dispatchEvent(new CustomEvent(
|
|
"credentialsrequired",
|
|
{ detail: { types: ["password"] } }
|
|
));
|
|
return false;
|
|
}
|
|
const challenge = Array.prototype.slice.call(this._sock.rQshiftBytes(16));
|
|
const response = _RFB.genDES(this._rfbCredentials.password, challenge);
|
|
this._sock.sQpushBytes(response);
|
|
this._sock.flush();
|
|
this._rfbInitState = "SecurityResult";
|
|
return true;
|
|
}
|
|
_negotiateARDAuth() {
|
|
if (this._rfbCredentials.username === void 0 || this._rfbCredentials.password === void 0) {
|
|
this.dispatchEvent(new CustomEvent(
|
|
"credentialsrequired",
|
|
{ detail: { types: ["username", "password"] } }
|
|
));
|
|
return false;
|
|
}
|
|
if (this._rfbCredentials.ardPublicKey != void 0 && this._rfbCredentials.ardCredentials != void 0) {
|
|
this._sock.sQpushBytes(this._rfbCredentials.ardCredentials);
|
|
this._sock.sQpushBytes(this._rfbCredentials.ardPublicKey);
|
|
this._sock.flush();
|
|
this._rfbCredentials.ardCredentials = null;
|
|
this._rfbCredentials.ardPublicKey = null;
|
|
this._rfbInitState = "SecurityResult";
|
|
return true;
|
|
}
|
|
if (this._sock.rQwait("read ard", 4)) {
|
|
return false;
|
|
}
|
|
let generator = this._sock.rQshiftBytes(2);
|
|
let keyLength = this._sock.rQshift16();
|
|
if (this._sock.rQwait("read ard keylength", keyLength * 2, 4)) {
|
|
return false;
|
|
}
|
|
let prime = this._sock.rQshiftBytes(keyLength);
|
|
let serverPublicKey = this._sock.rQshiftBytes(keyLength);
|
|
let clientKey = crypto_default.generateKey(
|
|
{ name: "DH", g: generator, p: prime },
|
|
false,
|
|
["deriveBits"]
|
|
);
|
|
this._negotiateARDAuthAsync(keyLength, serverPublicKey, clientKey);
|
|
return false;
|
|
}
|
|
async _negotiateARDAuthAsync(keyLength, serverPublicKey, clientKey) {
|
|
const clientPublicKey = crypto_default.exportKey("raw", clientKey.publicKey);
|
|
const sharedKey = crypto_default.deriveBits(
|
|
{ name: "DH", public: serverPublicKey },
|
|
clientKey.privateKey,
|
|
keyLength * 8
|
|
);
|
|
const username = encodeUTF8(this._rfbCredentials.username).substring(0, 63);
|
|
const password = encodeUTF8(this._rfbCredentials.password).substring(0, 63);
|
|
const credentials = window.crypto.getRandomValues(new Uint8Array(128));
|
|
for (let i = 0; i < username.length; i++) {
|
|
credentials[i] = username.charCodeAt(i);
|
|
}
|
|
credentials[username.length] = 0;
|
|
for (let i = 0; i < password.length; i++) {
|
|
credentials[64 + i] = password.charCodeAt(i);
|
|
}
|
|
credentials[64 + password.length] = 0;
|
|
const key = await crypto_default.digest("MD5", sharedKey);
|
|
const cipher = await crypto_default.importKey(
|
|
"raw",
|
|
key,
|
|
{ name: "AES-ECB" },
|
|
false,
|
|
["encrypt"]
|
|
);
|
|
const encrypted = await crypto_default.encrypt({ name: "AES-ECB" }, cipher, credentials);
|
|
this._rfbCredentials.ardCredentials = encrypted;
|
|
this._rfbCredentials.ardPublicKey = clientPublicKey;
|
|
this._resumeAuthentication();
|
|
}
|
|
_negotiateTightUnixAuth() {
|
|
if (this._rfbCredentials.username === void 0 || this._rfbCredentials.password === void 0) {
|
|
this.dispatchEvent(new CustomEvent(
|
|
"credentialsrequired",
|
|
{ detail: { types: ["username", "password"] } }
|
|
));
|
|
return false;
|
|
}
|
|
this._sock.sQpush32(this._rfbCredentials.username.length);
|
|
this._sock.sQpush32(this._rfbCredentials.password.length);
|
|
this._sock.sQpushString(this._rfbCredentials.username);
|
|
this._sock.sQpushString(this._rfbCredentials.password);
|
|
this._sock.flush();
|
|
this._rfbInitState = "SecurityResult";
|
|
return true;
|
|
}
|
|
_negotiateTightTunnels(numTunnels) {
|
|
const clientSupportedTunnelTypes = {
|
|
0: { vendor: "TGHT", signature: "NOTUNNEL" }
|
|
};
|
|
const serverSupportedTunnelTypes = {};
|
|
for (let i = 0; i < numTunnels; i++) {
|
|
const capCode = this._sock.rQshift32();
|
|
const capVendor = this._sock.rQshiftStr(4);
|
|
const capSignature = this._sock.rQshiftStr(8);
|
|
serverSupportedTunnelTypes[capCode] = { vendor: capVendor, signature: capSignature };
|
|
}
|
|
Debug("Server Tight tunnel types: " + serverSupportedTunnelTypes);
|
|
if (serverSupportedTunnelTypes[1] && serverSupportedTunnelTypes[1].vendor === "SICR" && serverSupportedTunnelTypes[1].signature === "SCHANNEL") {
|
|
Debug("Detected Siemens server. Assuming NOTUNNEL support.");
|
|
serverSupportedTunnelTypes[0] = { vendor: "TGHT", signature: "NOTUNNEL" };
|
|
}
|
|
if (serverSupportedTunnelTypes[0]) {
|
|
if (serverSupportedTunnelTypes[0].vendor != clientSupportedTunnelTypes[0].vendor || serverSupportedTunnelTypes[0].signature != clientSupportedTunnelTypes[0].signature) {
|
|
return this._fail("Client's tunnel type had the incorrect vendor or signature");
|
|
}
|
|
Debug("Selected tunnel type: " + clientSupportedTunnelTypes[0]);
|
|
this._sock.sQpush32(0);
|
|
this._sock.flush();
|
|
return false;
|
|
} else {
|
|
return this._fail("Server wanted tunnels, but doesn't support the notunnel type");
|
|
}
|
|
}
|
|
_negotiateTightAuth() {
|
|
if (!this._rfbTightVNC) {
|
|
if (this._sock.rQwait("num tunnels", 4)) {
|
|
return false;
|
|
}
|
|
const numTunnels = this._sock.rQshift32();
|
|
if (numTunnels > 0 && this._sock.rQwait("tunnel capabilities", 16 * numTunnels, 4)) {
|
|
return false;
|
|
}
|
|
this._rfbTightVNC = true;
|
|
if (numTunnels > 0) {
|
|
this._negotiateTightTunnels(numTunnels);
|
|
return false;
|
|
}
|
|
}
|
|
if (this._sock.rQwait("sub auth count", 4)) {
|
|
return false;
|
|
}
|
|
const subAuthCount = this._sock.rQshift32();
|
|
if (subAuthCount === 0) {
|
|
this._rfbInitState = "SecurityResult";
|
|
return true;
|
|
}
|
|
if (this._sock.rQwait("sub auth capabilities", 16 * subAuthCount, 4)) {
|
|
return false;
|
|
}
|
|
const clientSupportedTypes = {
|
|
"STDVNOAUTH__": 1,
|
|
"STDVVNCAUTH_": 2,
|
|
"TGHTULGNAUTH": 129
|
|
};
|
|
const serverSupportedTypes = [];
|
|
for (let i = 0; i < subAuthCount; i++) {
|
|
this._sock.rQshift32();
|
|
const capabilities = this._sock.rQshiftStr(12);
|
|
serverSupportedTypes.push(capabilities);
|
|
}
|
|
Debug("Server Tight authentication types: " + serverSupportedTypes);
|
|
for (let authType in clientSupportedTypes) {
|
|
if (serverSupportedTypes.indexOf(authType) != -1) {
|
|
this._sock.sQpush32(clientSupportedTypes[authType]);
|
|
this._sock.flush();
|
|
Debug("Selected authentication type: " + authType);
|
|
switch (authType) {
|
|
case "STDVNOAUTH__":
|
|
this._rfbInitState = "SecurityResult";
|
|
return true;
|
|
case "STDVVNCAUTH_":
|
|
this._rfbAuthScheme = securityTypeVNCAuth;
|
|
return true;
|
|
case "TGHTULGNAUTH":
|
|
this._rfbAuthScheme = securityTypeUnixLogon;
|
|
return true;
|
|
default:
|
|
return this._fail("Unsupported tiny auth scheme (scheme: " + authType + ")");
|
|
}
|
|
}
|
|
}
|
|
return this._fail("No supported sub-auth types!");
|
|
}
|
|
_handleRSAAESCredentialsRequired(event) {
|
|
this.dispatchEvent(event);
|
|
}
|
|
_handleRSAAESServerVerification(event) {
|
|
this.dispatchEvent(event);
|
|
}
|
|
_negotiateRA2neAuth() {
|
|
if (this._rfbRSAAESAuthenticationState === null) {
|
|
this._rfbRSAAESAuthenticationState = new RSAAESAuthenticationState(this._sock, () => this._rfbCredentials);
|
|
this._rfbRSAAESAuthenticationState.addEventListener(
|
|
"serververification",
|
|
this._eventHandlers.handleRSAAESServerVerification
|
|
);
|
|
this._rfbRSAAESAuthenticationState.addEventListener(
|
|
"credentialsrequired",
|
|
this._eventHandlers.handleRSAAESCredentialsRequired
|
|
);
|
|
}
|
|
this._rfbRSAAESAuthenticationState.checkInternalEvents();
|
|
if (!this._rfbRSAAESAuthenticationState.hasStarted) {
|
|
this._rfbRSAAESAuthenticationState.negotiateRA2neAuthAsync().catch((e2) => {
|
|
if (e2.message !== "disconnect normally") {
|
|
this._fail(e2.message);
|
|
}
|
|
}).then(() => {
|
|
this._rfbInitState = "SecurityResult";
|
|
return true;
|
|
}).finally(() => {
|
|
this._rfbRSAAESAuthenticationState.removeEventListener(
|
|
"serververification",
|
|
this._eventHandlers.handleRSAAESServerVerification
|
|
);
|
|
this._rfbRSAAESAuthenticationState.removeEventListener(
|
|
"credentialsrequired",
|
|
this._eventHandlers.handleRSAAESCredentialsRequired
|
|
);
|
|
this._rfbRSAAESAuthenticationState = null;
|
|
});
|
|
}
|
|
return false;
|
|
}
|
|
_negotiateMSLogonIIAuth() {
|
|
if (this._sock.rQwait("mslogonii dh param", 24)) {
|
|
return false;
|
|
}
|
|
if (this._rfbCredentials.username === void 0 || this._rfbCredentials.password === void 0) {
|
|
this.dispatchEvent(new CustomEvent(
|
|
"credentialsrequired",
|
|
{ detail: { types: ["username", "password"] } }
|
|
));
|
|
return false;
|
|
}
|
|
const g = this._sock.rQshiftBytes(8);
|
|
const p = this._sock.rQshiftBytes(8);
|
|
const A = this._sock.rQshiftBytes(8);
|
|
const dhKey = crypto_default.generateKey({ name: "DH", g, p }, true, ["deriveBits"]);
|
|
const B = crypto_default.exportKey("raw", dhKey.publicKey);
|
|
const secret = crypto_default.deriveBits({ name: "DH", public: A }, dhKey.privateKey, 64);
|
|
const key = crypto_default.importKey("raw", secret, { name: "DES-CBC" }, false, ["encrypt"]);
|
|
const username = encodeUTF8(this._rfbCredentials.username).substring(0, 255);
|
|
const password = encodeUTF8(this._rfbCredentials.password).substring(0, 63);
|
|
let usernameBytes = new Uint8Array(256);
|
|
let passwordBytes = new Uint8Array(64);
|
|
window.crypto.getRandomValues(usernameBytes);
|
|
window.crypto.getRandomValues(passwordBytes);
|
|
for (let i = 0; i < username.length; i++) {
|
|
usernameBytes[i] = username.charCodeAt(i);
|
|
}
|
|
usernameBytes[username.length] = 0;
|
|
for (let i = 0; i < password.length; i++) {
|
|
passwordBytes[i] = password.charCodeAt(i);
|
|
}
|
|
passwordBytes[password.length] = 0;
|
|
usernameBytes = crypto_default.encrypt({ name: "DES-CBC", iv: secret }, key, usernameBytes);
|
|
passwordBytes = crypto_default.encrypt({ name: "DES-CBC", iv: secret }, key, passwordBytes);
|
|
this._sock.sQpushBytes(B);
|
|
this._sock.sQpushBytes(usernameBytes);
|
|
this._sock.sQpushBytes(passwordBytes);
|
|
this._sock.flush();
|
|
this._rfbInitState = "SecurityResult";
|
|
return true;
|
|
}
|
|
_negotiateAuthentication() {
|
|
switch (this._rfbAuthScheme) {
|
|
case securityTypeNone:
|
|
if (this._rfbVersion >= 3.8) {
|
|
this._rfbInitState = "SecurityResult";
|
|
} else {
|
|
this._rfbInitState = "ClientInitialisation";
|
|
}
|
|
return true;
|
|
case securityTypeXVP:
|
|
return this._negotiateXvpAuth();
|
|
case securityTypeARD:
|
|
return this._negotiateARDAuth();
|
|
case securityTypeVNCAuth:
|
|
return this._negotiateStdVNCAuth();
|
|
case securityTypeTight:
|
|
return this._negotiateTightAuth();
|
|
case securityTypeVeNCrypt:
|
|
return this._negotiateVeNCryptAuth();
|
|
case securityTypePlain:
|
|
return this._negotiatePlainAuth();
|
|
case securityTypeUnixLogon:
|
|
return this._negotiateTightUnixAuth();
|
|
case securityTypeRA2ne:
|
|
return this._negotiateRA2neAuth();
|
|
case securityTypeMSLogonII:
|
|
return this._negotiateMSLogonIIAuth();
|
|
default:
|
|
return this._fail("Unsupported auth scheme (scheme: " + this._rfbAuthScheme + ")");
|
|
}
|
|
}
|
|
_handleSecurityResult() {
|
|
if (this._sock.rQwait("VNC auth response ", 4)) {
|
|
return false;
|
|
}
|
|
const status = this._sock.rQshift32();
|
|
if (status === 0) {
|
|
this._rfbInitState = "ClientInitialisation";
|
|
Debug("Authentication OK");
|
|
return true;
|
|
} else {
|
|
if (this._rfbVersion >= 3.8) {
|
|
this._rfbInitState = "SecurityReason";
|
|
this._securityContext = "security result";
|
|
this._securityStatus = status;
|
|
return true;
|
|
} else {
|
|
this.dispatchEvent(new CustomEvent(
|
|
"securityfailure",
|
|
{ detail: { status } }
|
|
));
|
|
return this._fail("Security handshake failed");
|
|
}
|
|
}
|
|
}
|
|
_negotiateServerInit() {
|
|
if (this._sock.rQwait("server initialization", 24)) {
|
|
return false;
|
|
}
|
|
const width = this._sock.rQshift16();
|
|
const height = this._sock.rQshift16();
|
|
const bpp = this._sock.rQshift8();
|
|
const depth = this._sock.rQshift8();
|
|
const bigEndian = this._sock.rQshift8();
|
|
const trueColor = this._sock.rQshift8();
|
|
const redMax = this._sock.rQshift16();
|
|
const greenMax = this._sock.rQshift16();
|
|
const blueMax = this._sock.rQshift16();
|
|
const redShift = this._sock.rQshift8();
|
|
const greenShift = this._sock.rQshift8();
|
|
const blueShift = this._sock.rQshift8();
|
|
this._sock.rQskipBytes(3);
|
|
const nameLength = this._sock.rQshift32();
|
|
if (this._sock.rQwait("server init name", nameLength, 24)) {
|
|
return false;
|
|
}
|
|
let name = this._sock.rQshiftStr(nameLength);
|
|
name = decodeUTF8(name, true);
|
|
if (this._rfbTightVNC) {
|
|
if (this._sock.rQwait("TightVNC extended server init header", 8, 24 + nameLength)) {
|
|
return false;
|
|
}
|
|
const numServerMessages = this._sock.rQshift16();
|
|
const numClientMessages = this._sock.rQshift16();
|
|
const numEncodings = this._sock.rQshift16();
|
|
this._sock.rQskipBytes(2);
|
|
const totalMessagesLength = (numServerMessages + numClientMessages + numEncodings) * 16;
|
|
if (this._sock.rQwait("TightVNC extended server init header", totalMessagesLength, 32 + nameLength)) {
|
|
return false;
|
|
}
|
|
this._sock.rQskipBytes(16 * numServerMessages);
|
|
this._sock.rQskipBytes(16 * numClientMessages);
|
|
this._sock.rQskipBytes(16 * numEncodings);
|
|
}
|
|
Info("Screen: " + width + "x" + height + ", bpp: " + bpp + ", depth: " + depth + ", bigEndian: " + bigEndian + ", trueColor: " + trueColor + ", redMax: " + redMax + ", greenMax: " + greenMax + ", blueMax: " + blueMax + ", redShift: " + redShift + ", greenShift: " + greenShift + ", blueShift: " + blueShift);
|
|
this._setDesktopName(name);
|
|
this._resize(width, height);
|
|
if (!this._viewOnly) {
|
|
this._keyboard.grab();
|
|
this._asyncClipboard.grab();
|
|
}
|
|
this._fbDepth = 24;
|
|
if (this._fbName === "Intel(r) AMT KVM") {
|
|
Warn("Intel AMT KVM only supports 8/16 bit depths. Using low color mode.");
|
|
this._fbDepth = 8;
|
|
}
|
|
_RFB.messages.pixelFormat(this._sock, this._fbDepth, true);
|
|
this._sendEncodings();
|
|
_RFB.messages.fbUpdateRequest(this._sock, false, 0, 0, this._fbWidth, this._fbHeight);
|
|
this._updateConnectionState("connected");
|
|
return true;
|
|
}
|
|
_sendEncodings() {
|
|
const encs = [];
|
|
encs.push(encodings.encodingCopyRect);
|
|
if (this._fbDepth == 24) {
|
|
if (supportsWebCodecsH264Decode) {
|
|
encs.push(encodings.encodingH264);
|
|
}
|
|
encs.push(encodings.encodingTight);
|
|
encs.push(encodings.encodingTightPNG);
|
|
encs.push(encodings.encodingZRLE);
|
|
encs.push(encodings.encodingJPEG);
|
|
encs.push(encodings.encodingHextile);
|
|
encs.push(encodings.encodingRRE);
|
|
encs.push(encodings.encodingZlib);
|
|
}
|
|
encs.push(encodings.encodingRaw);
|
|
encs.push(encodings.pseudoEncodingQualityLevel0 + this._qualityLevel);
|
|
encs.push(encodings.pseudoEncodingCompressLevel0 + this._compressionLevel);
|
|
encs.push(encodings.pseudoEncodingDesktopSize);
|
|
encs.push(encodings.pseudoEncodingLastRect);
|
|
encs.push(encodings.pseudoEncodingQEMUExtendedKeyEvent);
|
|
encs.push(encodings.pseudoEncodingQEMULedEvent);
|
|
encs.push(encodings.pseudoEncodingExtendedDesktopSize);
|
|
encs.push(encodings.pseudoEncodingXvp);
|
|
encs.push(encodings.pseudoEncodingFence);
|
|
encs.push(encodings.pseudoEncodingContinuousUpdates);
|
|
encs.push(encodings.pseudoEncodingDesktopName);
|
|
encs.push(encodings.pseudoEncodingExtendedClipboard);
|
|
encs.push(encodings.pseudoEncodingExtendedMouseButtons);
|
|
if (this._fbDepth == 24) {
|
|
encs.push(encodings.pseudoEncodingVMwareCursor);
|
|
encs.push(encodings.pseudoEncodingCursor);
|
|
}
|
|
_RFB.messages.clientEncodings(this._sock, encs);
|
|
}
|
|
/* RFB protocol initialization states:
|
|
* ProtocolVersion
|
|
* Security
|
|
* Authentication
|
|
* SecurityResult
|
|
* ClientInitialization - not triggered by server message
|
|
* ServerInitialization
|
|
*/
|
|
_initMsg() {
|
|
switch (this._rfbInitState) {
|
|
case "ProtocolVersion":
|
|
return this._negotiateProtocolVersion();
|
|
case "Security":
|
|
return this._negotiateSecurity();
|
|
case "Authentication":
|
|
return this._negotiateAuthentication();
|
|
case "SecurityResult":
|
|
return this._handleSecurityResult();
|
|
case "SecurityReason":
|
|
return this._handleSecurityReason();
|
|
case "ClientInitialisation":
|
|
this._sock.sQpush8(this._shared ? 1 : 0);
|
|
this._sock.flush();
|
|
this._rfbInitState = "ServerInitialisation";
|
|
return true;
|
|
case "ServerInitialisation":
|
|
return this._negotiateServerInit();
|
|
default:
|
|
return this._fail("Unknown init state (state: " + this._rfbInitState + ")");
|
|
}
|
|
}
|
|
// Resume authentication handshake after it was paused for some
|
|
// reason, e.g. waiting for a password from the user
|
|
_resumeAuthentication() {
|
|
setTimeout(this._initMsg.bind(this), 0);
|
|
}
|
|
_handleSetColourMapMsg() {
|
|
Debug("SetColorMapEntries");
|
|
return this._fail("Unexpected SetColorMapEntries message");
|
|
}
|
|
_writeClipboard(text) {
|
|
if (this._viewOnly) return;
|
|
if (this._asyncClipboard.writeClipboard(text)) return;
|
|
this.dispatchEvent(
|
|
new CustomEvent("clipboard", { detail: { text } })
|
|
);
|
|
}
|
|
_handleServerCutText() {
|
|
Debug("ServerCutText");
|
|
if (this._sock.rQwait("ServerCutText header", 7, 1)) {
|
|
return false;
|
|
}
|
|
this._sock.rQskipBytes(3);
|
|
let length = this._sock.rQshift32();
|
|
length = toSigned32bit(length);
|
|
if (this._sock.rQwait("ServerCutText content", Math.abs(length), 8)) {
|
|
return false;
|
|
}
|
|
if (length >= 0) {
|
|
const text = this._sock.rQshiftStr(length);
|
|
if (this._viewOnly) {
|
|
return true;
|
|
}
|
|
this._writeClipboard(text);
|
|
} else {
|
|
length = Math.abs(length);
|
|
const flags = this._sock.rQshift32();
|
|
let formats = flags & 65535;
|
|
let actions = flags & 4278190080;
|
|
let isCaps = !!(actions & extendedClipboardActionCaps);
|
|
if (isCaps) {
|
|
this._clipboardServerCapabilitiesFormats = {};
|
|
this._clipboardServerCapabilitiesActions = {};
|
|
for (let i = 0; i <= 15; i++) {
|
|
let index = 1 << i;
|
|
if (formats & index) {
|
|
this._clipboardServerCapabilitiesFormats[index] = true;
|
|
this._sock.rQshift32();
|
|
}
|
|
}
|
|
for (let i = 24; i <= 31; i++) {
|
|
let index = 1 << i;
|
|
this._clipboardServerCapabilitiesActions[index] = !!(actions & index);
|
|
}
|
|
let clientActions = [
|
|
extendedClipboardActionCaps,
|
|
extendedClipboardActionRequest,
|
|
extendedClipboardActionPeek,
|
|
extendedClipboardActionNotify,
|
|
extendedClipboardActionProvide
|
|
];
|
|
_RFB.messages.extendedClipboardCaps(this._sock, clientActions, { extendedClipboardFormatText: 0 });
|
|
} else if (actions === extendedClipboardActionRequest) {
|
|
if (this._viewOnly) {
|
|
return true;
|
|
}
|
|
if (this._clipboardText != null && this._clipboardServerCapabilitiesActions[extendedClipboardActionProvide]) {
|
|
if (formats & extendedClipboardFormatText) {
|
|
_RFB.messages.extendedClipboardProvide(this._sock, [extendedClipboardFormatText], [this._clipboardText]);
|
|
}
|
|
}
|
|
} else if (actions === extendedClipboardActionPeek) {
|
|
if (this._viewOnly) {
|
|
return true;
|
|
}
|
|
if (this._clipboardServerCapabilitiesActions[extendedClipboardActionNotify]) {
|
|
if (this._clipboardText != null) {
|
|
_RFB.messages.extendedClipboardNotify(this._sock, [extendedClipboardFormatText]);
|
|
} else {
|
|
_RFB.messages.extendedClipboardNotify(this._sock, []);
|
|
}
|
|
}
|
|
} else if (actions === extendedClipboardActionNotify) {
|
|
if (this._viewOnly) {
|
|
return true;
|
|
}
|
|
if (this._clipboardServerCapabilitiesActions[extendedClipboardActionRequest]) {
|
|
if (formats & extendedClipboardFormatText) {
|
|
_RFB.messages.extendedClipboardRequest(this._sock, [extendedClipboardFormatText]);
|
|
}
|
|
}
|
|
} else if (actions === extendedClipboardActionProvide) {
|
|
if (this._viewOnly) {
|
|
return true;
|
|
}
|
|
if (!(formats & extendedClipboardFormatText)) {
|
|
return true;
|
|
}
|
|
this._clipboardText = null;
|
|
let zlibStream = this._sock.rQshiftBytes(length - 4);
|
|
let streamInflator = new Inflate();
|
|
let textData = null;
|
|
streamInflator.setInput(zlibStream);
|
|
for (let i = 0; i <= 15; i++) {
|
|
let format = 1 << i;
|
|
if (formats & format) {
|
|
let size = 0;
|
|
let sizeArray = streamInflator.inflate(4);
|
|
size |= sizeArray[0] << 24;
|
|
size |= sizeArray[1] << 16;
|
|
size |= sizeArray[2] << 8;
|
|
size |= sizeArray[3];
|
|
let chunk = streamInflator.inflate(size);
|
|
if (format === extendedClipboardFormatText) {
|
|
textData = chunk;
|
|
}
|
|
}
|
|
}
|
|
streamInflator.setInput(null);
|
|
if (textData !== null) {
|
|
let tmpText = "";
|
|
for (let i = 0; i < textData.length; i++) {
|
|
tmpText += String.fromCharCode(textData[i]);
|
|
}
|
|
textData = tmpText;
|
|
textData = decodeUTF8(textData);
|
|
if (textData.length > 0 && "\0" === textData.charAt(textData.length - 1)) {
|
|
textData = textData.slice(0, -1);
|
|
}
|
|
textData = textData.replaceAll("\r\n", "\n");
|
|
this._writeClipboard(textData);
|
|
}
|
|
} else {
|
|
return this._fail("Unexpected action in extended clipboard message: " + actions);
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
_handleServerFenceMsg() {
|
|
if (this._sock.rQwait("ServerFence header", 8, 1)) {
|
|
return false;
|
|
}
|
|
this._sock.rQskipBytes(3);
|
|
let flags = this._sock.rQshift32();
|
|
let length = this._sock.rQshift8();
|
|
if (this._sock.rQwait("ServerFence payload", length, 9)) {
|
|
return false;
|
|
}
|
|
if (length > 64) {
|
|
Warn("Bad payload length (" + length + ") in fence response");
|
|
length = 64;
|
|
}
|
|
const payload = this._sock.rQshiftStr(length);
|
|
this._supportsFence = true;
|
|
if (!(flags & 1 << 31)) {
|
|
return this._fail("Unexpected fence response");
|
|
}
|
|
flags &= 1 << 0 | 1 << 1;
|
|
_RFB.messages.clientFence(this._sock, flags, payload);
|
|
return true;
|
|
}
|
|
_handleXvpMsg() {
|
|
if (this._sock.rQwait("XVP version and message", 3, 1)) {
|
|
return false;
|
|
}
|
|
this._sock.rQskipBytes(1);
|
|
const xvpVer = this._sock.rQshift8();
|
|
const xvpMsg = this._sock.rQshift8();
|
|
switch (xvpMsg) {
|
|
case 0:
|
|
Error2("XVP operation failed");
|
|
break;
|
|
case 1:
|
|
this._rfbXvpVer = xvpVer;
|
|
Info("XVP extensions enabled (version " + this._rfbXvpVer + ")");
|
|
this._setCapability("power", true);
|
|
break;
|
|
default:
|
|
this._fail("Illegal server XVP message (msg: " + xvpMsg + ")");
|
|
break;
|
|
}
|
|
return true;
|
|
}
|
|
_normalMsg() {
|
|
let msgType;
|
|
if (this._FBU.rects > 0) {
|
|
msgType = 0;
|
|
} else {
|
|
msgType = this._sock.rQshift8();
|
|
}
|
|
let first, ret;
|
|
switch (msgType) {
|
|
case 0:
|
|
ret = this._framebufferUpdate();
|
|
if (ret && !this._enabledContinuousUpdates) {
|
|
_RFB.messages.fbUpdateRequest(
|
|
this._sock,
|
|
true,
|
|
0,
|
|
0,
|
|
this._fbWidth,
|
|
this._fbHeight
|
|
);
|
|
}
|
|
return ret;
|
|
case 1:
|
|
return this._handleSetColourMapMsg();
|
|
case 2:
|
|
Debug("Bell");
|
|
this.dispatchEvent(new CustomEvent(
|
|
"bell",
|
|
{ detail: {} }
|
|
));
|
|
return true;
|
|
case 3:
|
|
return this._handleServerCutText();
|
|
case 150:
|
|
first = !this._supportsContinuousUpdates;
|
|
this._supportsContinuousUpdates = true;
|
|
this._enabledContinuousUpdates = false;
|
|
if (first) {
|
|
this._enabledContinuousUpdates = true;
|
|
this._updateContinuousUpdates();
|
|
Info("Enabling continuous updates.");
|
|
} else {
|
|
}
|
|
return true;
|
|
case 248:
|
|
return this._handleServerFenceMsg();
|
|
case 250:
|
|
return this._handleXvpMsg();
|
|
default:
|
|
this._fail("Unexpected server message (type " + msgType + ")");
|
|
Debug("sock.rQpeekBytes(30): " + this._sock.rQpeekBytes(30));
|
|
return true;
|
|
}
|
|
}
|
|
_framebufferUpdate() {
|
|
if (this._FBU.rects === 0) {
|
|
if (this._sock.rQwait("FBU header", 3, 1)) {
|
|
return false;
|
|
}
|
|
this._sock.rQskipBytes(1);
|
|
this._FBU.rects = this._sock.rQshift16();
|
|
if (this._display.pending()) {
|
|
this._flushing = true;
|
|
this._display.flush().then(() => {
|
|
this._flushing = false;
|
|
if (!this._sock.rQwait("message", 1)) {
|
|
this._handleMessage();
|
|
}
|
|
});
|
|
return false;
|
|
}
|
|
}
|
|
while (this._FBU.rects > 0) {
|
|
if (this._FBU.encoding === null) {
|
|
if (this._sock.rQwait("rect header", 12)) {
|
|
return false;
|
|
}
|
|
this._FBU.x = this._sock.rQshift16();
|
|
this._FBU.y = this._sock.rQshift16();
|
|
this._FBU.width = this._sock.rQshift16();
|
|
this._FBU.height = this._sock.rQshift16();
|
|
this._FBU.encoding = this._sock.rQshift32();
|
|
this._FBU.encoding >>= 0;
|
|
}
|
|
if (!this._handleRect()) {
|
|
return false;
|
|
}
|
|
this._FBU.rects--;
|
|
this._FBU.encoding = null;
|
|
}
|
|
this._display.flip();
|
|
return true;
|
|
}
|
|
_handleRect() {
|
|
switch (this._FBU.encoding) {
|
|
case encodings.pseudoEncodingLastRect:
|
|
this._FBU.rects = 1;
|
|
return true;
|
|
case encodings.pseudoEncodingVMwareCursor:
|
|
return this._handleVMwareCursor();
|
|
case encodings.pseudoEncodingCursor:
|
|
return this._handleCursor();
|
|
case encodings.pseudoEncodingQEMUExtendedKeyEvent:
|
|
this._qemuExtKeyEventSupported = true;
|
|
return true;
|
|
case encodings.pseudoEncodingDesktopName:
|
|
return this._handleDesktopName();
|
|
case encodings.pseudoEncodingDesktopSize:
|
|
this._resize(this._FBU.width, this._FBU.height);
|
|
return true;
|
|
case encodings.pseudoEncodingExtendedDesktopSize:
|
|
return this._handleExtendedDesktopSize();
|
|
case encodings.pseudoEncodingExtendedMouseButtons:
|
|
this._extendedPointerEventSupported = true;
|
|
return true;
|
|
case encodings.pseudoEncodingQEMULedEvent:
|
|
return this._handleLedEvent();
|
|
default:
|
|
return this._handleDataRect();
|
|
}
|
|
}
|
|
_handleVMwareCursor() {
|
|
const hotx = this._FBU.x;
|
|
const hoty = this._FBU.y;
|
|
const w = this._FBU.width;
|
|
const h = this._FBU.height;
|
|
if (this._sock.rQwait("VMware cursor encoding", 1)) {
|
|
return false;
|
|
}
|
|
const cursorType = this._sock.rQshift8();
|
|
this._sock.rQshift8();
|
|
let rgba;
|
|
const bytesPerPixel = 4;
|
|
if (cursorType == 0) {
|
|
const PIXEL_MASK = 4294967040 | 0;
|
|
rgba = new Array(w * h * bytesPerPixel);
|
|
if (this._sock.rQwait(
|
|
"VMware cursor classic encoding",
|
|
w * h * bytesPerPixel * 2,
|
|
2
|
|
)) {
|
|
return false;
|
|
}
|
|
let andMask = new Array(w * h);
|
|
for (let pixel = 0; pixel < w * h; pixel++) {
|
|
andMask[pixel] = this._sock.rQshift32();
|
|
}
|
|
let xorMask = new Array(w * h);
|
|
for (let pixel = 0; pixel < w * h; pixel++) {
|
|
xorMask[pixel] = this._sock.rQshift32();
|
|
}
|
|
for (let pixel = 0; pixel < w * h; pixel++) {
|
|
if (andMask[pixel] == 0) {
|
|
let bgr = xorMask[pixel];
|
|
let r = bgr >> 8 & 255;
|
|
let g = bgr >> 16 & 255;
|
|
let b2 = bgr >> 24 & 255;
|
|
rgba[pixel * bytesPerPixel] = r;
|
|
rgba[pixel * bytesPerPixel + 1] = g;
|
|
rgba[pixel * bytesPerPixel + 2] = b2;
|
|
rgba[pixel * bytesPerPixel + 3] = 255;
|
|
} else if ((andMask[pixel] & PIXEL_MASK) == PIXEL_MASK) {
|
|
if (xorMask[pixel] == 0) {
|
|
rgba[pixel * bytesPerPixel] = 0;
|
|
rgba[pixel * bytesPerPixel + 1] = 0;
|
|
rgba[pixel * bytesPerPixel + 2] = 0;
|
|
rgba[pixel * bytesPerPixel + 3] = 0;
|
|
} else if ((xorMask[pixel] & PIXEL_MASK) == PIXEL_MASK) {
|
|
rgba[pixel * bytesPerPixel] = 0;
|
|
rgba[pixel * bytesPerPixel + 1] = 0;
|
|
rgba[pixel * bytesPerPixel + 2] = 0;
|
|
rgba[pixel * bytesPerPixel + 3] = 255;
|
|
} else {
|
|
rgba[pixel * bytesPerPixel] = 0;
|
|
rgba[pixel * bytesPerPixel + 1] = 0;
|
|
rgba[pixel * bytesPerPixel + 2] = 0;
|
|
rgba[pixel * bytesPerPixel + 3] = 255;
|
|
}
|
|
} else {
|
|
rgba[pixel * bytesPerPixel] = 0;
|
|
rgba[pixel * bytesPerPixel + 1] = 0;
|
|
rgba[pixel * bytesPerPixel + 2] = 0;
|
|
rgba[pixel * bytesPerPixel + 3] = 255;
|
|
}
|
|
}
|
|
} else if (cursorType == 1) {
|
|
if (this._sock.rQwait(
|
|
"VMware cursor alpha encoding",
|
|
w * h * 4,
|
|
2
|
|
)) {
|
|
return false;
|
|
}
|
|
rgba = new Array(w * h * bytesPerPixel);
|
|
for (let pixel = 0; pixel < w * h; pixel++) {
|
|
let data = this._sock.rQshift32();
|
|
rgba[pixel * 4] = data >> 24 & 255;
|
|
rgba[pixel * 4 + 1] = data >> 16 & 255;
|
|
rgba[pixel * 4 + 2] = data >> 8 & 255;
|
|
rgba[pixel * 4 + 3] = data & 255;
|
|
}
|
|
} else {
|
|
Warn("The given cursor type is not supported: " + cursorType + " given.");
|
|
return false;
|
|
}
|
|
this._updateCursor(rgba, hotx, hoty, w, h);
|
|
return true;
|
|
}
|
|
_handleCursor() {
|
|
const hotx = this._FBU.x;
|
|
const hoty = this._FBU.y;
|
|
const w = this._FBU.width;
|
|
const h = this._FBU.height;
|
|
const pixelslength = w * h * 4;
|
|
const masklength = Math.ceil(w / 8) * h;
|
|
let bytes = pixelslength + masklength;
|
|
if (this._sock.rQwait("cursor encoding", bytes)) {
|
|
return false;
|
|
}
|
|
const pixels = this._sock.rQshiftBytes(pixelslength);
|
|
const mask = this._sock.rQshiftBytes(masklength);
|
|
let rgba = new Uint8Array(w * h * 4);
|
|
let pixIdx = 0;
|
|
for (let y = 0; y < h; y++) {
|
|
for (let x = 0; x < w; x++) {
|
|
let maskIdx = y * Math.ceil(w / 8) + Math.floor(x / 8);
|
|
let alpha = mask[maskIdx] << x % 8 & 128 ? 255 : 0;
|
|
rgba[pixIdx] = pixels[pixIdx + 2];
|
|
rgba[pixIdx + 1] = pixels[pixIdx + 1];
|
|
rgba[pixIdx + 2] = pixels[pixIdx];
|
|
rgba[pixIdx + 3] = alpha;
|
|
pixIdx += 4;
|
|
}
|
|
}
|
|
this._updateCursor(rgba, hotx, hoty, w, h);
|
|
return true;
|
|
}
|
|
_handleDesktopName() {
|
|
if (this._sock.rQwait("DesktopName", 4)) {
|
|
return false;
|
|
}
|
|
let length = this._sock.rQshift32();
|
|
if (this._sock.rQwait("DesktopName", length, 4)) {
|
|
return false;
|
|
}
|
|
let name = this._sock.rQshiftStr(length);
|
|
name = decodeUTF8(name, true);
|
|
this._setDesktopName(name);
|
|
return true;
|
|
}
|
|
_handleLedEvent() {
|
|
if (this._sock.rQwait("LED status", 1)) {
|
|
return false;
|
|
}
|
|
let data = this._sock.rQshift8();
|
|
let numLock = data & 2 ? true : false;
|
|
let capsLock = data & 4 ? true : false;
|
|
this._remoteCapsLock = capsLock;
|
|
this._remoteNumLock = numLock;
|
|
return true;
|
|
}
|
|
_handleExtendedDesktopSize() {
|
|
if (this._sock.rQwait("ExtendedDesktopSize", 4)) {
|
|
return false;
|
|
}
|
|
const numberOfScreens = this._sock.rQpeek8();
|
|
let bytes = 4 + numberOfScreens * 16;
|
|
if (this._sock.rQwait("ExtendedDesktopSize", bytes)) {
|
|
return false;
|
|
}
|
|
const firstUpdate = !this._supportsSetDesktopSize;
|
|
this._supportsSetDesktopSize = true;
|
|
this._sock.rQskipBytes(1);
|
|
this._sock.rQskipBytes(3);
|
|
for (let i = 0; i < numberOfScreens; i += 1) {
|
|
if (i === 0) {
|
|
this._screenID = this._sock.rQshift32();
|
|
this._sock.rQskipBytes(2);
|
|
this._sock.rQskipBytes(2);
|
|
this._sock.rQskipBytes(2);
|
|
this._sock.rQskipBytes(2);
|
|
this._screenFlags = this._sock.rQshift32();
|
|
} else {
|
|
this._sock.rQskipBytes(16);
|
|
}
|
|
}
|
|
if (this._FBU.x === 1) {
|
|
this._pendingRemoteResize = false;
|
|
}
|
|
if (this._FBU.x === 1 && this._FBU.y !== 0) {
|
|
let msg;
|
|
switch (this._FBU.y) {
|
|
case 1:
|
|
msg = "Resize is administratively prohibited";
|
|
break;
|
|
case 2:
|
|
msg = "Out of resources";
|
|
break;
|
|
case 3:
|
|
msg = "Invalid screen layout";
|
|
break;
|
|
default:
|
|
msg = "Unknown reason";
|
|
break;
|
|
}
|
|
Warn("Server did not accept the resize request: " + msg);
|
|
} else {
|
|
this._resize(this._FBU.width, this._FBU.height);
|
|
}
|
|
if (firstUpdate) {
|
|
this._requestRemoteResize();
|
|
}
|
|
if (this._FBU.x === 1 && this._FBU.y === 0) {
|
|
this._requestRemoteResize();
|
|
}
|
|
return true;
|
|
}
|
|
_handleDataRect() {
|
|
let decoder = this._decoders[this._FBU.encoding];
|
|
if (!decoder) {
|
|
this._fail("Unsupported encoding (encoding: " + this._FBU.encoding + ")");
|
|
return false;
|
|
}
|
|
try {
|
|
return decoder.decodeRect(
|
|
this._FBU.x,
|
|
this._FBU.y,
|
|
this._FBU.width,
|
|
this._FBU.height,
|
|
this._sock,
|
|
this._display,
|
|
this._fbDepth
|
|
);
|
|
} catch (err2) {
|
|
this._fail("Error decoding rect: " + err2);
|
|
return false;
|
|
}
|
|
}
|
|
_updateContinuousUpdates() {
|
|
if (!this._enabledContinuousUpdates) {
|
|
return;
|
|
}
|
|
_RFB.messages.enableContinuousUpdates(
|
|
this._sock,
|
|
true,
|
|
0,
|
|
0,
|
|
this._fbWidth,
|
|
this._fbHeight
|
|
);
|
|
}
|
|
// Handle resize-messages from the server
|
|
_resize(width, height) {
|
|
this._fbWidth = width;
|
|
this._fbHeight = height;
|
|
this._display.resize(this._fbWidth, this._fbHeight);
|
|
this._updateClip();
|
|
this._updateScale();
|
|
this._updateContinuousUpdates();
|
|
this._saveExpectedClientSize();
|
|
}
|
|
_xvpOp(ver, op) {
|
|
if (this._rfbXvpVer < ver) {
|
|
return;
|
|
}
|
|
Info("Sending XVP operation " + op + " (version " + ver + ")");
|
|
_RFB.messages.xvpOp(this._sock, ver, op);
|
|
}
|
|
_updateCursor(rgba, hotx, hoty, w, h) {
|
|
this._cursorImage = {
|
|
rgbaPixels: rgba,
|
|
hotx,
|
|
hoty,
|
|
w,
|
|
h
|
|
};
|
|
this._refreshCursor();
|
|
}
|
|
_shouldShowDotCursor() {
|
|
if (!this._showDotCursor) {
|
|
return false;
|
|
}
|
|
for (let i = 3; i < this._cursorImage.rgbaPixels.length; i += 4) {
|
|
if (this._cursorImage.rgbaPixels[i]) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
_refreshCursor() {
|
|
if (this._rfbConnectionState !== "connecting" && this._rfbConnectionState !== "connected") {
|
|
return;
|
|
}
|
|
const image = this._shouldShowDotCursor() ? _RFB.cursors.dot : this._cursorImage;
|
|
this._cursor.change(
|
|
image.rgbaPixels,
|
|
image.hotx,
|
|
image.hoty,
|
|
image.w,
|
|
image.h
|
|
);
|
|
}
|
|
static genDES(password, challenge) {
|
|
const passwordChars = password.split("").map((c2) => c2.charCodeAt(0));
|
|
const key = crypto_default.importKey(
|
|
"raw",
|
|
passwordChars,
|
|
{ name: "DES-ECB" },
|
|
false,
|
|
["encrypt"]
|
|
);
|
|
return crypto_default.encrypt({ name: "DES-ECB" }, key, challenge);
|
|
}
|
|
};
|
|
RFB.messages = {
|
|
keyEvent(sock, keysym, down) {
|
|
sock.sQpush8(4);
|
|
sock.sQpush8(down);
|
|
sock.sQpush16(0);
|
|
sock.sQpush32(keysym);
|
|
sock.flush();
|
|
},
|
|
QEMUExtendedKeyEvent(sock, keysym, down, keycode) {
|
|
function getRFBkeycode(xtScanCode) {
|
|
const upperByte = keycode >> 8;
|
|
const lowerByte = keycode & 255;
|
|
if (upperByte === 224 && lowerByte < 127) {
|
|
return lowerByte | 128;
|
|
}
|
|
return xtScanCode;
|
|
}
|
|
sock.sQpush8(255);
|
|
sock.sQpush8(0);
|
|
sock.sQpush16(down);
|
|
sock.sQpush32(keysym);
|
|
const RFBkeycode = getRFBkeycode(keycode);
|
|
sock.sQpush32(RFBkeycode);
|
|
sock.flush();
|
|
},
|
|
pointerEvent(sock, x, y, mask) {
|
|
sock.sQpush8(5);
|
|
mask = mask & 127;
|
|
sock.sQpush8(mask);
|
|
sock.sQpush16(x);
|
|
sock.sQpush16(y);
|
|
sock.flush();
|
|
},
|
|
extendedPointerEvent(sock, x, y, mask) {
|
|
sock.sQpush8(5);
|
|
let higherBits = mask >> 7 & 255;
|
|
if (higherBits & 252) {
|
|
throw new Error("Invalid mouse button mask: " + mask);
|
|
}
|
|
let lowerBits = mask & 127;
|
|
lowerBits |= 128;
|
|
sock.sQpush8(lowerBits);
|
|
sock.sQpush16(x);
|
|
sock.sQpush16(y);
|
|
sock.sQpush8(higherBits);
|
|
sock.flush();
|
|
},
|
|
// Used to build Notify and Request data.
|
|
_buildExtendedClipboardFlags(actions, formats) {
|
|
let data = new Uint8Array(4);
|
|
let formatFlag = 0;
|
|
let actionFlag = 0;
|
|
for (let i = 0; i < actions.length; i++) {
|
|
actionFlag |= actions[i];
|
|
}
|
|
for (let i = 0; i < formats.length; i++) {
|
|
formatFlag |= formats[i];
|
|
}
|
|
data[0] = actionFlag >> 24;
|
|
data[1] = 0;
|
|
data[2] = 0;
|
|
data[3] = formatFlag;
|
|
return data;
|
|
},
|
|
extendedClipboardProvide(sock, formats, inData) {
|
|
let deflator = new Deflator();
|
|
let dataToDeflate = [];
|
|
for (let i = 0; i < formats.length; i++) {
|
|
if (formats[i] != extendedClipboardFormatText) {
|
|
throw new Error("Unsupported extended clipboard format for Provide message.");
|
|
}
|
|
inData[i] = inData[i].replace(/\r\n|\r|\n/gm, "\r\n");
|
|
let text = encodeUTF8(inData[i] + "\0");
|
|
dataToDeflate.push(
|
|
text.length >> 24 & 255,
|
|
text.length >> 16 & 255,
|
|
text.length >> 8 & 255,
|
|
text.length & 255
|
|
);
|
|
for (let j = 0; j < text.length; j++) {
|
|
dataToDeflate.push(text.charCodeAt(j));
|
|
}
|
|
}
|
|
let deflatedData = deflator.deflate(new Uint8Array(dataToDeflate));
|
|
let data = new Uint8Array(4 + deflatedData.length);
|
|
data.set(RFB.messages._buildExtendedClipboardFlags(
|
|
[extendedClipboardActionProvide],
|
|
formats
|
|
));
|
|
data.set(deflatedData, 4);
|
|
RFB.messages.clientCutText(sock, data, true);
|
|
},
|
|
extendedClipboardNotify(sock, formats) {
|
|
let flags = RFB.messages._buildExtendedClipboardFlags(
|
|
[extendedClipboardActionNotify],
|
|
formats
|
|
);
|
|
RFB.messages.clientCutText(sock, flags, true);
|
|
},
|
|
extendedClipboardRequest(sock, formats) {
|
|
let flags = RFB.messages._buildExtendedClipboardFlags(
|
|
[extendedClipboardActionRequest],
|
|
formats
|
|
);
|
|
RFB.messages.clientCutText(sock, flags, true);
|
|
},
|
|
extendedClipboardCaps(sock, actions, formats) {
|
|
let formatKeys = Object.keys(formats);
|
|
let data = new Uint8Array(4 + 4 * formatKeys.length);
|
|
formatKeys.map((x) => parseInt(x));
|
|
formatKeys.sort((a2, b2) => a2 - b2);
|
|
data.set(RFB.messages._buildExtendedClipboardFlags(actions, []));
|
|
let loopOffset = 4;
|
|
for (let i = 0; i < formatKeys.length; i++) {
|
|
data[loopOffset] = formats[formatKeys[i]] >> 24;
|
|
data[loopOffset + 1] = formats[formatKeys[i]] >> 16;
|
|
data[loopOffset + 2] = formats[formatKeys[i]] >> 8;
|
|
data[loopOffset + 3] = formats[formatKeys[i]] >> 0;
|
|
loopOffset += 4;
|
|
data[3] |= 1 << formatKeys[i];
|
|
}
|
|
RFB.messages.clientCutText(sock, data, true);
|
|
},
|
|
clientCutText(sock, data, extended = false) {
|
|
sock.sQpush8(6);
|
|
sock.sQpush8(0);
|
|
sock.sQpush8(0);
|
|
sock.sQpush8(0);
|
|
let length;
|
|
if (extended) {
|
|
length = toUnsigned32bit(-data.length);
|
|
} else {
|
|
length = data.length;
|
|
}
|
|
sock.sQpush32(length);
|
|
sock.sQpushBytes(data);
|
|
sock.flush();
|
|
},
|
|
setDesktopSize(sock, width, height, id, flags) {
|
|
sock.sQpush8(251);
|
|
sock.sQpush8(0);
|
|
sock.sQpush16(width);
|
|
sock.sQpush16(height);
|
|
sock.sQpush8(1);
|
|
sock.sQpush8(0);
|
|
sock.sQpush32(id);
|
|
sock.sQpush16(0);
|
|
sock.sQpush16(0);
|
|
sock.sQpush16(width);
|
|
sock.sQpush16(height);
|
|
sock.sQpush32(flags);
|
|
sock.flush();
|
|
},
|
|
clientFence(sock, flags, payload) {
|
|
sock.sQpush8(248);
|
|
sock.sQpush8(0);
|
|
sock.sQpush8(0);
|
|
sock.sQpush8(0);
|
|
sock.sQpush32(flags);
|
|
sock.sQpush8(payload.length);
|
|
sock.sQpushString(payload);
|
|
sock.flush();
|
|
},
|
|
enableContinuousUpdates(sock, enable, x, y, width, height) {
|
|
sock.sQpush8(150);
|
|
sock.sQpush8(enable);
|
|
sock.sQpush16(x);
|
|
sock.sQpush16(y);
|
|
sock.sQpush16(width);
|
|
sock.sQpush16(height);
|
|
sock.flush();
|
|
},
|
|
pixelFormat(sock, depth, trueColor) {
|
|
let bpp;
|
|
if (depth > 16) {
|
|
bpp = 32;
|
|
} else if (depth > 8) {
|
|
bpp = 16;
|
|
} else {
|
|
bpp = 8;
|
|
}
|
|
const bits = Math.floor(depth / 3);
|
|
sock.sQpush8(0);
|
|
sock.sQpush8(0);
|
|
sock.sQpush8(0);
|
|
sock.sQpush8(0);
|
|
sock.sQpush8(bpp);
|
|
sock.sQpush8(depth);
|
|
sock.sQpush8(0);
|
|
sock.sQpush8(trueColor ? 1 : 0);
|
|
sock.sQpush16((1 << bits) - 1);
|
|
sock.sQpush16((1 << bits) - 1);
|
|
sock.sQpush16((1 << bits) - 1);
|
|
sock.sQpush8(bits * 0);
|
|
sock.sQpush8(bits * 1);
|
|
sock.sQpush8(bits * 2);
|
|
sock.sQpush8(0);
|
|
sock.sQpush8(0);
|
|
sock.sQpush8(0);
|
|
sock.flush();
|
|
},
|
|
clientEncodings(sock, encodings2) {
|
|
sock.sQpush8(2);
|
|
sock.sQpush8(0);
|
|
sock.sQpush16(encodings2.length);
|
|
for (let i = 0; i < encodings2.length; i++) {
|
|
sock.sQpush32(encodings2[i]);
|
|
}
|
|
sock.flush();
|
|
},
|
|
fbUpdateRequest(sock, incremental, x, y, w, h) {
|
|
if (typeof x === "undefined") {
|
|
x = 0;
|
|
}
|
|
if (typeof y === "undefined") {
|
|
y = 0;
|
|
}
|
|
sock.sQpush8(3);
|
|
sock.sQpush8(incremental ? 1 : 0);
|
|
sock.sQpush16(x);
|
|
sock.sQpush16(y);
|
|
sock.sQpush16(w);
|
|
sock.sQpush16(h);
|
|
sock.flush();
|
|
},
|
|
xvpOp(sock, ver, op) {
|
|
sock.sQpush8(250);
|
|
sock.sQpush8(0);
|
|
sock.sQpush8(ver);
|
|
sock.sQpush8(op);
|
|
sock.flush();
|
|
}
|
|
};
|
|
RFB.cursors = {
|
|
none: {
|
|
rgbaPixels: new Uint8Array(),
|
|
w: 0,
|
|
h: 0,
|
|
hotx: 0,
|
|
hoty: 0
|
|
},
|
|
dot: {
|
|
/* eslint-disable indent */
|
|
rgbaPixels: new Uint8Array([
|
|
255,
|
|
255,
|
|
255,
|
|
255,
|
|
0,
|
|
0,
|
|
0,
|
|
255,
|
|
255,
|
|
255,
|
|
255,
|
|
255,
|
|
0,
|
|
0,
|
|
0,
|
|
255,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
255,
|
|
255,
|
|
255,
|
|
255,
|
|
255,
|
|
0,
|
|
0,
|
|
0,
|
|
255,
|
|
255,
|
|
255,
|
|
255,
|
|
255
|
|
]),
|
|
/* eslint-enable indent */
|
|
w: 3,
|
|
h: 3,
|
|
hotx: 1,
|
|
hoty: 1
|
|
}
|
|
};
|
|
export {
|
|
RFB as default
|
|
};
|
|
|
|
// Expose RFB globally for non-module scripts
|
|
if (typeof window !== 'undefined') window.RFB = RFB;
|