@aiti-ai/grdpwasm 0.0.0-stage → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +674 -0
- package/README.md +161 -2
- package/README.zh-CN.md +145 -0
- package/package.json +27 -4
- package/scripts/postinstall.mjs +28 -0
- package/scripts/sync-version.mjs +23 -0
- package/static/index.html +894 -0
- package/static/main.wasm +0 -0
- package/static/remote-keys.js +59 -0
- package/static/shortcut-bar.js +95 -0
- package/static/system-keyboard.js +59 -0
- package/static/type-text.js +91 -0
- package/static/vendor/justget.browser.js +1 -0
- package/static/vendor/simple-keyboard.css +11 -0
- package/static/vendor/simple-keyboard.js +12 -0
- package/static/virtual-keyboard.css +77 -0
- package/static/virtual-keyboard.js +199 -0
- package/static/wasm_exec.js +575 -0
package/static/main.wasm
ADDED
|
Binary file
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* remote-keys.js — remote key helpers (X11/RFB keysym domain; host-agnostic shared component)
|
|
3
|
+
*
|
|
4
|
+
* Used by VNC (noVNC sendKey wants keysyms); RDP (scancode domain) doesn't need this module.
|
|
5
|
+
* codeToKeysym(code) — DOM `code` (KeyA/ArrowUp/F5…) -> keysym, 0 when unknown
|
|
6
|
+
* charToKeysym(ch) — char -> keysym (direct Latin-1 mapping; otherwise the Unicode extension convention 0x01000000|cp)
|
|
7
|
+
*/
|
|
8
|
+
(function (global, factory) {
|
|
9
|
+
const mod = factory();
|
|
10
|
+
if (typeof module === "object" && module.exports) module.exports = mod;
|
|
11
|
+
else if (typeof define === "function" && define.amd) define([], () => mod);
|
|
12
|
+
else global.RemoteKeys = mod;
|
|
13
|
+
})(typeof self !== "undefined" ? self : this, function () {
|
|
14
|
+
"use strict";
|
|
15
|
+
|
|
16
|
+
/* modifier keys */
|
|
17
|
+
const MODS = {
|
|
18
|
+
ShiftLeft: 0xffe1, ShiftRight: 0xffe2,
|
|
19
|
+
ControlLeft: 0xffe3, ControlRight: 0xffe4,
|
|
20
|
+
AltLeft: 0xffe9, AltRight: 0xffea,
|
|
21
|
+
MetaLeft: 0xffeb, MetaRight: 0xffec,
|
|
22
|
+
CapsLock: 0xffe5, NumLock: 0xff7f
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
/* special keys */
|
|
26
|
+
const SPECIAL = {
|
|
27
|
+
Escape: 0xff1b, Tab: 0xff09, Backspace: 0xff08, Delete: 0xffff,
|
|
28
|
+
Enter: 0xff0d, Space: 0x20,
|
|
29
|
+
ArrowUp: 0xff52, ArrowDown: 0xff54, ArrowLeft: 0xff51, ArrowRight: 0xff53,
|
|
30
|
+
Home: 0xff50, End: 0xff57, PageUp: 0xff55, PageDown: 0xff56,
|
|
31
|
+
Insert: 0xff63, PrintScreen: 0xff61, ScrollLock: 0xff14, Pause: 0xff13, Menu: 0xff67
|
|
32
|
+
};
|
|
33
|
+
for (let i = 1; i <= 12; i++) SPECIAL["F" + i] = 0xffbe + i - 1; // XK_F1..F12
|
|
34
|
+
|
|
35
|
+
/* symbol keys (unshifted chars of the main layout) */
|
|
36
|
+
const SYM = {
|
|
37
|
+
Backquote: 0x60, Minus: 0x2d, Equal: 0x3d,
|
|
38
|
+
BracketLeft: 0x5b, BracketRight: 0x5d, Backslash: 0x5c,
|
|
39
|
+
Semicolon: 0x3b, Quote: 0x27, Comma: 0x2c, Period: 0x2e, Slash: 0x2f
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
function codeToKeysym(code) {
|
|
43
|
+
if (MODS[code] !== undefined) return MODS[code];
|
|
44
|
+
if (SPECIAL[code] !== undefined) return SPECIAL[code];
|
|
45
|
+
let m;
|
|
46
|
+
if ((m = /^Key([A-Z])$/.exec(code))) return m[1].charCodeAt(0) + 32; // lowercase a-z
|
|
47
|
+
if ((m = /^Digit([0-9])$/.exec(code))) return m[1].charCodeAt(0);
|
|
48
|
+
if (SYM[code] !== undefined) return SYM[code];
|
|
49
|
+
return 0;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function charToKeysym(ch) {
|
|
53
|
+
const u = ch.codePointAt(0);
|
|
54
|
+
if (u >= 0x20 && u <= 0xff) return u;
|
|
55
|
+
return 0x01000000 | u;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return { codeToKeysym, charToKeysym };
|
|
59
|
+
});
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* shortcut-bar.js — remote-desktop shortcut bar (host-agnostic shared component; canonical source lives in aiti-ui-env)
|
|
3
|
+
*
|
|
4
|
+
* Usage:
|
|
5
|
+
* <script src=".../shortcut-bar.js"></script>
|
|
6
|
+
* ShortcutBar.mount({ root: "#shortcuts", onPress(code), onRelease(code), combos? });
|
|
7
|
+
*
|
|
8
|
+
* Semantics: holding a chip presses every key in the combo in order; release /
|
|
9
|
+
* pointer-out releases them in reverse. ("Hold Alt+Tab then tap Tab"-style flows
|
|
10
|
+
* can be layered on top by callers; this component stays minimal.)
|
|
11
|
+
* `combos` overrides the defaults: [{ label, codes: ["ControlLeft", ...] }] with DOM codes.
|
|
12
|
+
*/
|
|
13
|
+
(function (global, factory) {
|
|
14
|
+
const mod = factory();
|
|
15
|
+
if (typeof module === "object" && module.exports) module.exports = mod;
|
|
16
|
+
else if (typeof define === "function" && define.amd) define([], () => mod);
|
|
17
|
+
else global.ShortcutBar = mod;
|
|
18
|
+
})(typeof self !== "undefined" ? self : this, function () {
|
|
19
|
+
"use strict";
|
|
20
|
+
|
|
21
|
+
const DEFAULT_COMBOS = [
|
|
22
|
+
{ label: "Ctrl+Alt+T", codes: ["ControlLeft", "AltLeft", "KeyT"] },
|
|
23
|
+
{ label: "Alt+Tab", codes: ["AltLeft", "Tab"] },
|
|
24
|
+
{ label: "Ctrl+Alt+Del", codes: ["ControlLeft", "AltLeft", "Delete"] },
|
|
25
|
+
{ label: "⊞ Win", codes: ["MetaLeft"] },
|
|
26
|
+
{ label: "Ctrl+C", codes: ["ControlLeft", "KeyC"] },
|
|
27
|
+
{ label: "Ctrl+V", codes: ["ControlLeft", "KeyV"] },
|
|
28
|
+
{ label: "Ctrl+Z", codes: ["ControlLeft", "KeyZ"] },
|
|
29
|
+
{ label: "Ctrl+S", codes: ["ControlLeft", "KeyS"] },
|
|
30
|
+
{ label: "F5", codes: ["F5"] },
|
|
31
|
+
{ label: "F1", codes: ["F1"] },
|
|
32
|
+
{ label: "F2", codes: ["F2"] },
|
|
33
|
+
{ label: "F3", codes: ["F3"] },
|
|
34
|
+
{ label: "F4", codes: ["F4"] },
|
|
35
|
+
{ label: "F6", codes: ["F6"] },
|
|
36
|
+
{ label: "F7", codes: ["F7"] },
|
|
37
|
+
{ label: "F8", codes: ["F8"] },
|
|
38
|
+
{ label: "F9", codes: ["F9"] },
|
|
39
|
+
{ label: "F10", codes: ["F10"] },
|
|
40
|
+
{ label: "F11", codes: ["F11"] },
|
|
41
|
+
{ label: "F12", codes: ["F12"] },
|
|
42
|
+
{ label: "⇧+F10", codes: ["ShiftLeft", "F10"] }, // Windows/Linux context menu (Shift+F10)
|
|
43
|
+
{ label: "Esc", codes: ["Escape"] },
|
|
44
|
+
{ label: "PrtSc", codes: ["PrintScreen"] }
|
|
45
|
+
];
|
|
46
|
+
|
|
47
|
+
function mount(opts) {
|
|
48
|
+
const root = typeof opts.root === "string" ? document.querySelector(opts.root) : opts.root;
|
|
49
|
+
if (!root) throw new Error("ShortcutBar: root not found");
|
|
50
|
+
const onPress = opts.onPress || function () {};
|
|
51
|
+
const onRelease = opts.onRelease || function () {};
|
|
52
|
+
const combos = opts.combos || DEFAULT_COMBOS;
|
|
53
|
+
|
|
54
|
+
root.classList.add("scb-root");
|
|
55
|
+
let held = null; // { btn, codes }
|
|
56
|
+
|
|
57
|
+
function release() {
|
|
58
|
+
if (!held) return;
|
|
59
|
+
for (let i = held.codes.length - 1; i >= 0; i--) onRelease(held.codes[i]);
|
|
60
|
+
held.btn.classList.remove("scb-on");
|
|
61
|
+
held = null;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
combos.forEach((c) => {
|
|
65
|
+
const b = document.createElement("button");
|
|
66
|
+
b.type = "button";
|
|
67
|
+
b.className = "scb-chip";
|
|
68
|
+
b.textContent = c.label;
|
|
69
|
+
const down = (e) => {
|
|
70
|
+
e.preventDefault();
|
|
71
|
+
e.stopPropagation();
|
|
72
|
+
if (held && held.btn !== b) release();
|
|
73
|
+
if (held) return; // same chip already held; ignore repeated presses
|
|
74
|
+
held = { btn: b, codes: c.codes };
|
|
75
|
+
b.classList.add("scb-on");
|
|
76
|
+
for (const code of c.codes) onPress(code);
|
|
77
|
+
};
|
|
78
|
+
const up = () => {
|
|
79
|
+
if (held && held.btn === b) release();
|
|
80
|
+
};
|
|
81
|
+
b.addEventListener("pointerdown", down);
|
|
82
|
+
b.addEventListener("pointerup", up);
|
|
83
|
+
b.addEventListener("pointercancel", up);
|
|
84
|
+
b.addEventListener("pointerleave", up);
|
|
85
|
+
root.appendChild(b);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
return {
|
|
89
|
+
release,
|
|
90
|
+
isOpen() { return true; }
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return { mount, DEFAULT_COMBOS };
|
|
95
|
+
});
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* system-keyboard.js — system (device-native) soft-keyboard proxy (host-agnostic shared component)
|
|
3
|
+
*
|
|
4
|
+
* Purpose: a remote-desktop canvas (canvas / tabindex=-1) usually fails to summon
|
|
5
|
+
* the IME on mobile; this component uses one hidden <input> to recall the system
|
|
6
|
+
* keyboard and forwards typed characters/backspace/enter to the host via callbacks.
|
|
7
|
+
*
|
|
8
|
+
* const kb = SystemKeyboard.mount({ onChange(ev) }); // ev = {type:"char",ch} | {type:"special",name}
|
|
9
|
+
* kb.open()/close()/toggle(); kb.isOpen;
|
|
10
|
+
*
|
|
11
|
+
* Notes:
|
|
12
|
+
* - the input must not be display:none (some browsers won't pop the IME); hosts style it as a near-transparent fixed bar
|
|
13
|
+
* - during IME composition the input fires repeatedly; forward each segment (the remote receives Unicode keysyms)
|
|
14
|
+
*/
|
|
15
|
+
(function (global, factory) {
|
|
16
|
+
const mod = factory();
|
|
17
|
+
if (typeof module === "object" && module.exports) module.exports = mod;
|
|
18
|
+
else if (typeof define === "function" && define.amd) define([], () => mod);
|
|
19
|
+
else global.SystemKeyboard = mod;
|
|
20
|
+
})(typeof self !== "undefined" ? self : this, function () {
|
|
21
|
+
"use strict";
|
|
22
|
+
|
|
23
|
+
function mount(opts) {
|
|
24
|
+
const onChange = opts.onChange || function () {};
|
|
25
|
+
|
|
26
|
+
const input = document.createElement("input");
|
|
27
|
+
input.type = "text";
|
|
28
|
+
input.className = "syskb-input";
|
|
29
|
+
input.name = "syskb";
|
|
30
|
+
input.setAttribute("autocomplete", "off");
|
|
31
|
+
input.setAttribute("autocapitalize", "off");
|
|
32
|
+
input.setAttribute("autocorrect", "off");
|
|
33
|
+
input.spellcheck = false;
|
|
34
|
+
document.body.appendChild(input);
|
|
35
|
+
|
|
36
|
+
function flush() {
|
|
37
|
+
const v = input.value;
|
|
38
|
+
if (!v) return;
|
|
39
|
+
input.value = "";
|
|
40
|
+
for (const ch of v) onChange({ type: "char", ch: ch });
|
|
41
|
+
}
|
|
42
|
+
input.addEventListener("input", flush);
|
|
43
|
+
input.addEventListener("keydown", (e) => {
|
|
44
|
+
// special keys from physical keyboards never show up in value
|
|
45
|
+
if (e.key === "Backspace") { e.preventDefault(); onChange({ type: "special", name: "Backspace" }); }
|
|
46
|
+
else if (e.key === "Enter") { flush(); onChange({ type: "special", name: "Enter" }); }
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
return {
|
|
50
|
+
el: input,
|
|
51
|
+
open() { input.focus(); },
|
|
52
|
+
close() { input.blur(); },
|
|
53
|
+
toggle() { if (document.activeElement === input) input.blur(); else input.focus(); },
|
|
54
|
+
get isOpen() { return document.activeElement === input; }
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return { mount };
|
|
59
|
+
});
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* aiti-ui-env shared viewer component: text -> RFB keyboard event sequence (for VNC "type into remote")
|
|
3
|
+
*
|
|
4
|
+
* Why: the VNC clipboard is not reliable on every target —
|
|
5
|
+
* - a QEMU VM's VNC clipboard needs a guest agent (spice-vdagent etc.) to reach the guest; without one,
|
|
6
|
+
* ClientCutText data dangles inside QEMU (noVNC sends successfully but the guest never receives it);
|
|
7
|
+
* - x11vnc drops ClientCutText silently for roughly the first 8s of a connection, before selwin exists;
|
|
8
|
+
* - the legacy extension clipboard protocol is Latin-1 only; non-ASCII turns into '?'.
|
|
9
|
+
* Fallback = split the text into keyboard events sent one by one (equivalent to a human typing on the
|
|
10
|
+
* remote); every VNC server supports that.
|
|
11
|
+
*
|
|
12
|
+
* Mapping convention (US layout, matching the official noVNC Keyboard): each char provides
|
|
13
|
+
* - keysym: the char's X11 keysym (used by the legacy KeyEvent protocol; x11vnc/libvncserver reverse-map keysym -> key+Shift)
|
|
14
|
+
* - code : DOM code name (used by the QEMU extended key event to look up the Xt scancode table for the AT scancode)
|
|
15
|
+
* - shift : whether the char needs Shift (the QEMU extended key event only understands scancode + modifier state, so Shift down/up must be sent along)
|
|
16
|
+
* Non-ASCII (CJK/emoji...) cannot map to a single key -> skipped and counted (an IME is needed on the remote); the caller surfaces this to the user.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
/** XK_Shift_L: modifier keysym (DOM code = "ShiftLeft") */
|
|
20
|
+
export const SHIFT_KEYSYM = 0xffe1;
|
|
21
|
+
|
|
22
|
+
const LETTERS = (() => {
|
|
23
|
+
const m = {};
|
|
24
|
+
for (let i = 0; i < 26; i++) {
|
|
25
|
+
const lower = String.fromCharCode(97 + i);
|
|
26
|
+
const upper = String.fromCharCode(65 + i);
|
|
27
|
+
const code = "Key" + upper;
|
|
28
|
+
m[lower] = { keysym: lower.codePointAt(0), code, shift: false };
|
|
29
|
+
m[upper] = { keysym: upper.codePointAt(0), code, shift: true };
|
|
30
|
+
}
|
|
31
|
+
return m;
|
|
32
|
+
})();
|
|
33
|
+
|
|
34
|
+
const DIGITS = (() => {
|
|
35
|
+
const m = {};
|
|
36
|
+
for (let d = 0; d <= 9; d++) m[String(d)] = { keysym: 0x30 + d, code: "Digit" + d, shift: false };
|
|
37
|
+
return m;
|
|
38
|
+
})();
|
|
39
|
+
|
|
40
|
+
/** [char, DOM code]; shifted chars not listed here live in SHIFTED */
|
|
41
|
+
const PLAIN_PUNCT = [
|
|
42
|
+
[" ", "Space"], ["`", "Backquote"], ["-", "Minus"], ["=", "Equal"],
|
|
43
|
+
["[", "BracketLeft"], ["]", "BracketRight"], ["\\", "Backslash"], [";", "Semicolon"],
|
|
44
|
+
["'", "Quote"], [",", "Comma"], [".", "Period"], ["/", "Slash"],
|
|
45
|
+
];
|
|
46
|
+
const SHIFTED_PUNCT = [
|
|
47
|
+
["!", "Digit1"], ["@", "Digit2"], ["#", "Digit3"], ["$", "Digit4"], ["%", "Digit5"],
|
|
48
|
+
["^", "Digit6"], ["&", "Digit7"], ["*", "Digit8"], ["(", "Digit9"], [")", "Digit0"],
|
|
49
|
+
["_", "Minus"], ["+", "Equal"], ["{", "BracketLeft"], ["}", "BracketRight"], ["|", "Backslash"],
|
|
50
|
+
[":", "Semicolon"], ['"', "Quote"], ["<", "Comma"], [">", "Period"], ["?", "Slash"], ["~", "Backquote"],
|
|
51
|
+
];
|
|
52
|
+
|
|
53
|
+
/** Control chars: keysyms use the X11 function-key keysyms */
|
|
54
|
+
const CONTROL = {
|
|
55
|
+
"\n": { keysym: 0xff0d, code: "Enter", shift: false },
|
|
56
|
+
"\t": { keysym: 0xff09, code: "Tab", shift: false },
|
|
57
|
+
"\b": { keysym: 0xff08, code: "Backspace", shift: false },
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
const TABLE = (() => {
|
|
61
|
+
const m = Object.assign({}, LETTERS, DIGITS, CONTROL);
|
|
62
|
+
for (const [ch, code] of PLAIN_PUNCT) m[ch] = { keysym: ch.codePointAt(0), code, shift: false };
|
|
63
|
+
for (const [ch, code] of SHIFTED_PUNCT) m[ch] = { keysym: ch.codePointAt(0), code, shift: true };
|
|
64
|
+
return m;
|
|
65
|
+
})();
|
|
66
|
+
|
|
67
|
+
/** One char -> key spec; returns null when unmappable (non-ASCII / unknown control char) */
|
|
68
|
+
export function charToKey(ch) {
|
|
69
|
+
if (typeof ch !== "string" || ch.length === 0) return null;
|
|
70
|
+
return TABLE[ch] || null;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Text -> key event sequence.
|
|
75
|
+
* @param {string} text
|
|
76
|
+
* @returns {{keys: {keysym:number, code:string, shift:boolean}[], skipped: number}}
|
|
77
|
+
* skipped = number of unmappable chars (non-ASCII, \r, ...); the \r of \r\n is not counted (the newline is sent as \n).
|
|
78
|
+
*/
|
|
79
|
+
export function textToKeys(text) {
|
|
80
|
+
const keys = [];
|
|
81
|
+
let skipped = 0;
|
|
82
|
+
for (const ch of String(text == null ? "" : text)) {
|
|
83
|
+
if (ch === "\r") continue; // CRLF: drop \r, send Enter for \n (avoids double newline)
|
|
84
|
+
const spec = charToKey(ch);
|
|
85
|
+
if (spec) keys.push(spec);
|
|
86
|
+
else skipped++;
|
|
87
|
+
}
|
|
88
|
+
return { keys, skipped };
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export default { textToKeys, charToKey, SHIFT_KEYSYM };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var justget=(()=>{var G=Object.defineProperty;var ie=Object.getOwnPropertyDescriptor;var ce=Object.getOwnPropertyNames;var le=Object.prototype.hasOwnProperty;var ue=(e,t)=>{for(var r in t)G(e,r,{get:t[r],enumerable:!0})},de=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of ce(t))!le.call(e,o)&&o!==r&&G(e,o,{get:()=>t[o],enumerable:!(n=ie(t,o))||n.enumerable});return e};var me=e=>de(G({},"__esModule",{value:!0}),e);var Se={};ue(Se,{ChecksumMismatchError:()=>D,DEFAULT_CONFIG:()=>M,Downloader:()=>B,EWMA:()=>k,SpeedMonitor:()=>A,cacheKey:()=>H,calculateAverageSpeed:()=>$,calculateInstantSpeed:()=>I,concatBuffers:()=>U,digest:()=>P,download:()=>V,generateShortHash:()=>ee,getSpeedStats:()=>L,hexToUint8Array:()=>Y,isImmediateFailure:()=>R,loadBestSource:()=>J,mergeConfig:()=>_,prioritizeMirrors:()=>W,recordSuccess:()=>O,saveBestSource:()=>K,uint8ArrayToHex:()=>Q,validateConfig:()=>N});var M={primaryWarmupTime:5e3,speedThreshold:512e3,fastPrimaryThreshold:2048e3,sizeThreshold:52428800,minReplaceTime:3e4,replaceCheckInterval:1e4,chunks:"auto",chunkSize:"auto",minChunkSize:1048576,retries:3,retryDelay:2e3,timeout:3e5,connectTimeout:1e4,checksumAlgorithm:"sha256",responseType:"blob"},v={ewmaAlpha:.3,sampleInterval:1e3,windowSize:10};var F={minTimeBeforeReplace:3e4,checkInterval:1e4,slowThresholdRatio:.33,maxSlowChecks:3,bufferSize:1048576,immediateFailureCodes:["ECONNREFUSED","ENETUNREACH","EHOSTUNREACH","ETIMEDOUT","ENOTFOUND","EAI_AGAIN"],immediateFailureHttp:[404,401,403,410,500,502,503,504]};function R(e,t){if(t!==void 0&&(t>=500||F.immediateFailureHttp.includes(t)))return!0;let r=e.code;if(r&&F.immediateFailureCodes.includes(r))return!0;let n=e.message.toLowerCase();return n.includes("connection refused")||n.includes("network unreachable")||n.includes("host unreachable")||n.includes("aborted")||n.includes("cancelled")||n.includes("timeout")&&!n.includes("download timeout")}function _(e){return e?{...M,...e}:{...M}}function N(e){if(e.primaryWarmupTime!==void 0&&e.primaryWarmupTime<0)throw new Error("primaryWarmupTime must be non-negative");if(e.speedThreshold!==void 0&&e.speedThreshold<0)throw new Error("speedThreshold must be non-negative");if(e.fastPrimaryThreshold!==void 0&&e.fastPrimaryThreshold<0)throw new Error("fastPrimaryThreshold must be non-negative");if(e.sizeThreshold!==void 0&&e.sizeThreshold<0)throw new Error("sizeThreshold must be non-negative");if(e.minReplaceTime!==void 0&&e.minReplaceTime<0)throw new Error("minReplaceTime must be non-negative");if(e.replaceCheckInterval!==void 0&&e.replaceCheckInterval<0)throw new Error("replaceCheckInterval must be non-negative");if(e.connectTimeout!==void 0&&e.connectTimeout<0)throw new Error("connectTimeout must be non-negative");if(e.chunks!==void 0&&typeof e.chunks=="number"&&e.chunks<1)throw new Error("chunks must be at least 1");if(e.chunkSize!==void 0&&typeof e.chunkSize=="number"&&e.chunkSize<1)throw new Error("chunkSize must be at least 1");if(e.minChunkSize!==void 0&&e.minChunkSize<1)throw new Error("minChunkSize must be at least 1");if(e.retries!==void 0&&e.retries<0)throw new Error("retries must be non-negative");if(e.timeout!==void 0&&e.timeout<0)throw new Error("timeout must be non-negative");if(e.checksumAlgorithm!==void 0&&!["md5","sha1","sha256","sha512"].includes(e.checksumAlgorithm))throw new Error(`Unsupported checksumAlgorithm: ${e.checksumAlgorithm}`)}var k=class{alpha;value=0;initialized=!1;constructor(t=v.ewmaAlpha){if(t<=0||t>=1)throw new Error("Alpha must be between 0 and 1");this.alpha=t}update(t){return this.initialized?this.value=this.alpha*t+(1-this.alpha)*this.value:(this.value=t,this.initialized=!0),this.value}getValue(){return this.value}reset(){this.value=0,this.initialized=!1}};function I(e){if(e.length<2)return 0;let t=e[e.length-1],r=e[0],n=t.timestamp-r.timestamp;return n<=0?0:(t.bytes-r.bytes)/(n/1e3)}function $(e,t){if(e.length===0)return 0;let r=e[e.length-1],n=r.timestamp-t;return n<=0?0:r.bytes/n*1e3}function L(e,t,r){let n=I(e),o=$(e,t);return{current:n,ewma:r.getValue(),peak:Math.max(n,...e.map((h,u)=>u>0?I(e.slice(0,u+1)):0)),average:o}}var A=class{samples=[];ewma;startTime;options;interval;constructor(t={}){this.options={alpha:t.alpha??v.ewmaAlpha,sampleInterval:t.sampleInterval??v.sampleInterval,windowSize:t.windowSize??v.windowSize},this.ewma=new k(this.options.alpha),this.startTime=Date.now()}record(t){let r=Date.now(),n={bytes:t,timestamp:r};for(this.samples.push(n);this.samples.length>this.options.windowSize;)this.samples.shift();if(this.samples.length>=2){let o=I(this.samples);this.ewma.update(o)}return L(this.samples,this.startTime,this.ewma)}getStats(){return L(this.samples,this.startTime,this.ewma)}getCurrentSpeed(){return this.ewma.getValue()}isBelowThreshold(t){return this.getCurrentSpeed()<t}startSampling(t,r){this.interval=setInterval(()=>{let n=t(),o=this.record(n);r?.(o)},this.options.sampleInterval)}stopSampling(){this.interval&&(clearInterval(this.interval),this.interval=void 0)}reset(){this.samples=[],this.ewma.reset(),this.startTime=Date.now()}getElapsedTime(){return Date.now()-this.startTime}};async function q(e,t={}){let r=t.connectTimeout??1e4,n=t.timeout??3e5,o=new AbortController,h=setTimeout(()=>o.abort(),r);try{let u=await fetch(e,{redirect:"follow",signal:o.signal});if(u.status>=400)throw u.body?.getReader().cancel(),new j(u.status,e);let p=new AbortController,i=setTimeout(()=>p.abort(),n),a=fe(p.signal,t.signal),w=()=>u.body?.getReader().cancel();a.addEventListener("abort",w,{once:!0});let x=()=>{clearTimeout(i),a.removeEventListener("abort",w)};return{status:u.status,contentLength:he(u.headers.get("content-length")),body:u.body,cancel:()=>{x(),u.body?.getReader().cancel()},cleanup:x}}finally{clearTimeout(h)}}async function X(e,t,r){let n=e.getReader();try{for(;;){if(r?.aborted)throw new Error("Aborted");let{done:o,value:h}=await n.read();if(o)break;await t(h)}}finally{n.releaseLock()}}var j=class extends Error{status;constructor(t,r){super(`HTTP ${t}: ${r}`),this.status=t,this.name="HttpError"}};function he(e){if(!e)return;let t=Number.parseInt(e,10);return Number.isFinite(t)&&t>=0?t:void 0}function fe(...e){let t=new AbortController;for(let r of e)if(r){if(r.aborted)return t.abort(r.reason),t.signal;r.addEventListener("abort",()=>t.abort(r.reason),{once:!0})}return t.signal}function U(e){if(e.length===0)return new Uint8Array(0);if(e.length===1)return e[0];let t=e.reduce((o,h)=>o+h.byteLength,0),r=new Uint8Array(t),n=0;for(let o of e)r.set(o,n),n+=o.byteLength;return r}function Y(e){let t=e.replace(/^0x/i,""),r=new Uint8Array(t.length/2);for(let n=0;n<t.length;n+=2)r[n/2]=parseInt(t.substring(n,n+2),16);return r}function Q(e){return Array.from(e).map(t=>t.toString(16).padStart(2,"0")).join("")}async function P(e,t="sha256"){if(t==="md5")throw new Error("MD5 \u4E0D\u88AB Web Crypto API \u652F\u6301\uFF0C\u8BF7\u7528 SHA-256 \u66FF\u4EE3");try{if(typeof crypto>"u"||!crypto.subtle||!crypto.subtle.digest)throw new Error("WebCrypto unavailable");let r=t==="sha1"?"SHA-1":t==="sha256"?"SHA-256":"SHA-512",n=await crypto.subtle.digest(r,e),o=new Uint8Array(n);return Z(o)}catch{if(t==="sha256")return pe(e);throw new Error("\u975E\u5B89\u5168\u4E0A\u4E0B\u6587\uFF1AWebCrypto \u4E0D\u53EF\u7528\uFF0C\u7EAF JS fallback \u4EC5\u652F\u6301 sha256\uFF1B\u8BF7\u6539\u7528 sha256")}}function Z(e){return Array.from(e).map(t=>t.toString(16).padStart(2,"0")).join("")}function pe(e){let t=new Uint32Array([1116352408,1899447441,3049323471,3921009573,961987163,1508970993,2453635748,2870763221,3624381080,310598401,607225278,1426881987,1925078388,2162078206,2614888103,3248222580,3835390401,4022224774,264347078,604807628,770255983,1249150122,1555081692,1996064986,2554220882,2821834349,2952996808,3210313671,3336571891,3584528711,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,2177026350,2456956037,2730485921,2820302411,3259730800,3345764771,3516065817,3600352804,4094571909,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,2227730452,2361852424,2428436474,2756734187,3204031479,3329325298]),r=e.length,n=((r+8>>6)+1)*64,o=new Uint8Array(n);o.set(e),o[r]=128;let h=r*8,u=Math.floor(h/4294967296),p=h%4294967296,i=(m,b)=>{o[b]=m>>>24&255,o[b+1]=m>>>16&255,o[b+2]=m>>>8&255,o[b+3]=m&255};i(u,n-8),i(p,n-4);let a=new Uint32Array([1779033703,3144134277,1013904242,2773480762,1359893119,2600822924,528734635,1541459225]),w=new Uint32Array(64),x=(m,b)=>m>>>b|m<<32-b;for(let m=0;m<n;m+=64){for(let c=0;c<16;c++){let y=m+c*4;w[c]=o[y]<<24|o[y+1]<<16|o[y+2]<<8|o[y+3]}for(let c=16;c<64;c++){let y=x(w[c-15],7)^x(w[c-15],18)^w[c-15]>>>3,g=x(w[c-2],17)^x(w[c-2],19)^w[c-2]>>>10;w[c]=w[c-16]+y+w[c-7]+g|0}let b=a[0],C=a[1],E=a[2],z=a[3],s=a[4],l=a[5],f=a[6],d=a[7];for(let c=0;c<64;c++){let y=x(s,6)^x(s,11)^x(s,25),g=s&l^~s&f,T=d+y+g+t[c]+w[c]|0,oe=x(b,2)^x(b,13)^x(b,22),se=b&C^b&E^C&E,ae=oe+se|0;d=f,f=l,l=s,s=z+T|0,z=E,E=C,C=b,b=T+ae|0}a[0]=a[0]+b|0,a[1]=a[1]+C|0,a[2]=a[2]+E|0,a[3]=a[3]+z|0,a[4]=a[4]+s|0,a[5]=a[5]+l|0,a[6]=a[6]+f|0,a[7]=a[7]+d|0}let S=new Uint8Array(32);for(let m=0;m<8;m++)S[m*4]=a[m]>>>24&255,S[m*4+1]=a[m]>>>16&255,S[m*4+2]=a[m]>>>8&255,S[m*4+3]=a[m]&255;return Z(S)}function ee(e,t=8){let r=2166136261;for(let n=0;n<e.length;n++)r^=e.charCodeAt(n),r=Math.imul(r,16777619);return(r>>>0).toString(16).padStart(8,"0").slice(0,t)}var te="justget:cache:";function H(e){try{let t=new URL(e);return te+re(t.hostname+t.pathname)}catch{return te+re(e)}}function K(e,t){try{let r=H(e),n=ne(r),o={bestUrl:t,timestamp:Date.now(),successCount:(n?.successCount??0)+1};localStorage.setItem(r,JSON.stringify(o))}catch{}}function J(e){try{let t=H(e),r=ne(t);return r?Date.now()-r.timestamp>6048e5?(localStorage.removeItem(t),null):r.bestUrl:null}catch{return null}}function W(e,t,r){let n=J(r);if(!n)return{primaryUrl:e,mirrors:t};if(n===e)return{primaryUrl:e,mirrors:t};let o=t.indexOf(n);if(o!==-1){let h=[...t];return h.splice(o,1,e),{primaryUrl:n,mirrors:h}}return{primaryUrl:e,mirrors:t}}function O(e,t){K(e,t)}function ne(e){let t=localStorage.getItem(e);if(!t)return null;try{let r=JSON.parse(t);return!r.bestUrl||!r.timestamp?null:r}catch{return null}}function re(e){let t=2166136261;for(let r=0;r<e.length;r++)t^=e.charCodeAt(r),t=Math.imul(t,16777619);return(t>>>0).toString(16).padStart(8,"0")}function we(e){return new Promise(t=>setTimeout(t,e))}var D=class extends Error{expected;actual;badUrl;constructor(t,r,n){super(`Checksum mismatch: expected ${t}, got ${r}`),this.expected=t,this.actual=r,this.badUrl=n,this.name="ChecksumMismatchError"}};async function V(e){let t=Date.now(),{url:r,mirrors:n=[]}=e;if(!r)throw new Error("url is required");let o=_(e.options);N(o);let h=[r,...n],u,p;for(;;){if(h.length===0)throw u??new Error("Download failed: no source could complete");try{p=await be(h[0],h.slice(1),o,e.url);break}catch(a){if(a instanceof D){h=h.filter(w=>w!==a.badUrl),u=a;continue}throw a}}let i={...p,duration:Date.now()-t};return o.onComplete&&o.onComplete(i),i}async function be(e,t,r,n){let o=Date.now(),h=W(e,t,n);e=h.primaryUrl,t=h.mirrors;let u,p="application/octet-stream";try{let s=await fetch(e,{method:"HEAD",redirect:"follow"});if(s.ok){let l=s.headers.get("content-length");l&&(u=Number(l));let f=s.headers.get("content-type");f&&(p=f.split(";")[0].trim())}}catch{}let i={contentLength:u,workers:[],cfg:r,done:!1,mirrorsStartedCount:0,primaryFailedImmediately:!1,winner:null,overallStartedAt:o},a=()=>{if(!r.onProgress)return;let s=i.workers.map(g=>({id:g.id,url:g.url,downloadedBytes:g.bytesWritten,speed:g.monitor.getCurrentSpeed(),status:g.status})),l=i.winner?i.winner.chunks.reduce((g,T)=>g+T.byteLength,0):i.workers.reduce((g,T)=>g+T.bytesWritten,0),f=u??l,d=i.workers.reduce((g,T)=>g+T.monitor.getCurrentSpeed(),0),c=Math.max(1,Date.now()-o),y=d>0?d:l>0?l/c*1e3:0;r.onProgress({downloadedBytes:l,totalBytes:f,percentage:f>0?l/f*100:0,speed:y,eta:y>0?(f-l)/y*1e3:0,sources:s})},w=()=>{if(t.length===0||i.mirrorsStartedCount>=t.length)return!1;let s=i.workers.filter(c=>c.status==="active"&&!c.aborted);if(s.length===0)return!0;let f=s.reduce((c,y)=>c.monitor.getCurrentSpeed()>y.monitor.getCurrentSpeed()?c:y).monitor.getCurrentSpeed();return f>=(r.fastPrimaryThreshold??2048e3)||(u??0)<(r.sizeThreshold??50*1024*1024)?!1:f<(r.speedThreshold??512e3)},x=()=>{let s=i.mirrorsStartedCount++;if(s>=t.length)return;let l={id:`mirror-${s}`,url:t[s],isPrimary:!1,monitor:new A,controller:new AbortController,aborted:!1,slowChecks:0,bytesWritten:0,startedAt:Date.now(),status:"active",chunks:[]};m(l)},S=()=>{if(!(i.done||t.length===0)){if(i.primaryFailedImmediately){for(;i.mirrorsStartedCount<t.length&&!i.done;)x();return}w()&&x()}},m=s=>{i.workers.push(s),s.monitor.startSampling(()=>s.bytesWritten),ye(s,i,a).catch(l=>{s.error=l,s.status="failed",i.lastError=i.lastError??l,s.isPrimary&&R(l,l.status)&&(i.primaryFailedImmediately=!0,S())})},b={id:"primary",url:e,isPrimary:!0,monitor:new A,controller:new AbortController,aborted:!1,slowChecks:0,bytesWritten:0,startedAt:Date.now(),status:"active",chunks:[]};m(b);let C=setTimeout(()=>S(),r.primaryWarmupTime??5e3),E=setInterval(()=>{if(i.done)return;S();let s=i.workers.filter(d=>d.status==="active"&&!d.aborted);if(s.length<2||Date.now()-o<(r.minReplaceTime??3e4))return;let l=s.reduce((d,c)=>d.monitor.getCurrentSpeed()>c.monitor.getCurrentSpeed()?d:c),f=l.monitor.getCurrentSpeed();if(!(f<=0))for(let d of s){if(d===l)continue;d.monitor.getCurrentSpeed()/f<F.slowThresholdRatio?++d.slowChecks>=F.maxSlowChecks&&(d.aborted=!0,d.status="failed",d.controller.abort(),a()):d.slowChecks=0}},r.replaceCheckInterval??1e4),z=setInterval(a,200);try{if(await xe(i,r),!i.done||!i.winner)throw i.lastError??new Error("Download failed: no source could complete");for(let d of i.workers)d.status==="active"&&(d.status="completed");let s=U(i.winner.chunks);if(r.checksum){let d=r.checksumAlgorithm??"sha256",c=await P(s,d);if(c!==r.checksum.toLowerCase())throw new D(r.checksum.toLowerCase(),c,i.winner.url)}i.winner.url!==n&&O(n,i.winner.url);let l=r.responseType==="uint8array"?s:new Blob([s],{type:p}),f=u??s.byteLength;return ge(l,f,p,i.workers,o)}finally{clearTimeout(C),clearInterval(E),clearInterval(z);for(let s of i.workers)s.controller.abort(),s.monitor.stopSampling()}}async function xe(e,t){let r=(t.timeout??3e5)*3,n=Date.now()+r;for(;Date.now()<n;){if(e.done)return;if(!e.workers.some(o=>o.status==="active"&&!o.aborted)&&e.workers.length>0)throw e.lastError??new Error("All sources failed");await we(100)}throw new Error(`Download timeout (${r}ms = timeout\xD73)`)}async function ye(e,t,r){let n=await q(e.url,{connectTimeout:t.cfg.connectTimeout,timeout:t.cfg.timeout,signal:e.controller.signal});try{await X(n.body,o=>{if(e.aborted)throw new Error("Aborted");e.chunks.push(o),e.bytesWritten+=o.byteLength},e.controller.signal)}finally{n.cleanup()}if(!t.done){t.done=!0,t.winner={chunks:e.chunks,mimeType:"",url:e.url},e.status="completed";for(let o of t.workers)o!==e&&!o.aborted&&(o.aborted=!0,o.status="failed",o.controller.abort());r()}}function ge(e,t,r,n,o){let h=n.map(p=>({id:p.id,url:p.url,bytes:p.bytesWritten,duration:Date.now()-p.startedAt,averageSpeed:p.bytesWritten/Math.max(1,Date.now()-p.startedAt)*1e3,status:p.status})),u=Date.now()-o;return{data:e,bytes:t,duration:u,averageSpeed:u>0?t/u*1e3:0,sources:h,mimeType:r}}var B=class{options;constructor(t){this.options=t}start(){return V(this.options)}};return me(Se);})();
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
*
|
|
3
|
+
* simple-keyboard v3.8.177
|
|
4
|
+
* https://github.com/hodgef/simple-keyboard
|
|
5
|
+
*
|
|
6
|
+
* Copyright (c) Francisco Hodge (https://github.com/hodgef) and project contributors.
|
|
7
|
+
*
|
|
8
|
+
* This source code is licensed under the MIT license found in the
|
|
9
|
+
* LICENSE file in the root directory of this source tree.
|
|
10
|
+
*
|
|
11
|
+
*/.hg-theme-default{background-color:#ececec;border-radius:5px;box-sizing:border-box;font-family:HelveticaNeue-Light,Helvetica Neue Light,Helvetica Neue,Helvetica,Arial,Lucida Grande,sans-serif;overflow:hidden;padding:5px;touch-action:manipulation;-webkit-user-select:none;-moz-user-select:none;user-select:none;width:100%}.hg-theme-default .hg-button span,.hg-theme-default .hg-button span svg{pointer-events:none}.hg-theme-default button.hg-button{border-width:0;font-size:inherit}.hg-theme-default .hg-button{display:inline-block;flex-grow:1}.hg-theme-default .hg-row{display:flex}.hg-theme-default .hg-row:not(:last-child){margin-bottom:5px}.hg-theme-default .hg-row .hg-button-container,.hg-theme-default .hg-row .hg-button:not(:last-child){margin-right:5px}.hg-theme-default .hg-row>div:last-child{margin-right:0}.hg-theme-default .hg-row .hg-button-container{display:flex}.hg-theme-default .hg-button{align-items:center;background:#fff;border-bottom:1px solid #b5b5b5;border-radius:5px;box-shadow:0 0 3px -1px rgba(0,0,0,.3);box-sizing:border-box;cursor:pointer;display:flex;height:40px;justify-content:center;padding:5px;-webkit-tap-highlight-color:rgba(0,0,0,0)}.hg-theme-default .hg-button.hg-standardBtn{width:20px}.hg-theme-default .hg-button.hg-activeButton{background:#efefef}.hg-theme-default.hg-layout-numeric .hg-button{align-items:center;display:flex;height:60px;justify-content:center;width:33.3%}.hg-theme-default .hg-button.hg-button-numpadadd,.hg-theme-default .hg-button.hg-button-numpadenter{height:85px}.hg-theme-default .hg-button.hg-button-numpad0{width:105px}.hg-theme-default .hg-button.hg-button-com{max-width:85px}.hg-theme-default .hg-button.hg-standardBtn.hg-button-at{max-width:45px}.hg-theme-default .hg-button.hg-selectedButton{background:rgba(5,25,70,.53);color:#fff}.hg-theme-default .hg-button.hg-standardBtn[data-skbtn=".com"]{max-width:82px}.hg-theme-default .hg-button.hg-standardBtn[data-skbtn="@"]{max-width:60px}.hg-candidate-box{background:#ececec;border-bottom:2px solid #b5b5b5;border-radius:5px;display:inline-flex;margin-top:-10px;position:absolute;transform:translateY(-100%);-webkit-user-select:none;-moz-user-select:none;user-select:none}ul.hg-candidate-box-list{display:flex;flex:1;list-style:none;margin:0;padding:0}li.hg-candidate-box-list-item{align-items:center;display:flex;height:40px;justify-content:center;width:40px}li.hg-candidate-box-list-item:hover{background:rgba(0,0,0,.03);cursor:pointer}li.hg-candidate-box-list-item:active{background:rgba(0,0,0,.1)}.hg-candidate-box-prev:before{content:"◄"}.hg-candidate-box-next:before{content:"►"}.hg-candidate-box-next,.hg-candidate-box-prev{align-items:center;color:#969696;cursor:pointer;display:flex;padding:0 10px}.hg-candidate-box-next{border-bottom-right-radius:5px;border-top-right-radius:5px}.hg-candidate-box-prev{border-bottom-left-radius:5px;border-top-left-radius:5px}.hg-candidate-box-btn-active{color:#444}
|