xiongzhu há 2 anos atrás
pai
commit
d116813153
6 ficheiros alterados com 395 adições e 22 exclusões
  1. 11 9
      app.js
  2. 1 0
      keyboard.html
  3. 80 0
      lib/index.html
  4. 70 0
      lib/keyboard.css
  5. 218 0
      lib/keyboard.js
  6. 15 13
      routes/index.js

+ 11 - 9
app.js

@@ -9,6 +9,17 @@ module.exports.options = {};
 
 module.exports = async function (fastify, opts) {
     // Place here your custom code!
+    fastify.register(fstatic, {
+        root: path.join(__dirname, "lib"),
+        prefix: "/lib/",
+        setHeaders: (res, path, stat) => {
+            res.setHeader("Cross-Origin-Embedder-Policy", "require-corp");
+        },
+    });
+
+    fastify.register(cors, {
+        // put your options here
+    });
 
     // Do not touch the following lines
 
@@ -26,13 +37,4 @@ module.exports = async function (fastify, opts) {
         dir: path.join(__dirname, "routes"),
         options: Object.assign({}, opts),
     });
-
-    fastify.register(fstatic, {
-        root: path.join(__dirname, "lib"),
-        prefix: "/lib/"
-    });
-
-    fastify.register(cors, {
-        // put your options here
-    });
 };

+ 1 - 0
keyboard.html

@@ -43,6 +43,7 @@
 </style>
 <style>
     .virtual-keyboard-window {
+        user-select: none;
         position: fixed;
         top: 0;
         width: 800px;

+ 80 - 0
lib/index.html

@@ -0,0 +1,80 @@
+<!doctype html>
+<html lang='en-us'>
+
+<head>
+	<meta charset='utf-8'/>
+	<meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
+    <link rel="stylesheet" href="/lib/simple-keyboard-3.7.2.css" />
+    <link rel="stylesheet" href="/lib/keyboard.css" />
+	<script src='lib/matoya.js'></script>
+	<script src='lib/weblib.js'></script>
+	<script src='lib/parsec.js'></script>
+</head>
+
+<body>
+<script>
+	(async function () {
+		const wasm = 'parsecd';
+		const userEnv = PARSEC_ENV;
+
+		const html = document.querySelector('html');
+		html.style.width = '100%';
+		html.style.height = '100%';
+		html.style.margin = 0;
+
+		const body = document.querySelector('body');
+		body.style.width = '100%';
+		body.style.height = '100%';
+		body.style.background = 'black';
+		body.style.overflow = 'hidden';
+		body.style.margin = 0;
+
+		if (!await MTY_Start(wasm, body, userEnv)) {
+			body.style.fontFamily = 'sans-serif';
+			body.style.fontSize = '30px';
+			body.style.background = 'black';
+			body.style.color = 'white';
+			body.style.textAlign = 'center';
+			body.style.padding = '10% 30px 0 30px';
+
+			document.body.innerHTML =
+				'<div>Your browser does not support the Parsec web app. The web app requires WebGL and WebAssembly 64-bit support.</div>' +
+				'<div style="margin-top:30px">Check the <a href="https://parsec.app/downloads">Downloads</a> page for our native app.</div>';
+		}
+
+		window.history.replaceState(null, document.title, '/');
+	})();
+
+	console.log('%cSTOP! ✋ This area is intended for developers. Pasting something here could give strangers access to your Parsec account.', 'font-size: 18px; font-weight: 700;');
+</script>
+<div class="virtual-keyboard-window">
+    <div class="window-top">Virtual Keyboard
+        <button class="btn-close">
+            <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 32 32">
+                <path
+                    d="M24 9.4L22.6 8L16 14.6L9.4 8L8 9.4l6.6 6.6L8 22.6L9.4 24l6.6-6.6l6.6 6.6l1.4-1.4l-6.6-6.6L24 9.4z"
+                    fill="currentColor"></path>
+            </svg>
+        </button>
+    </div>
+    <div class="window-content">
+        <div class="simple-keyboard"></div>
+    </div>
+</div>
+<div class="keyboard-toggle">
+    <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24">
+        <g fill="none">
+            <path
+                d="M19.745 5a2.25 2.25 0 0 1 2.25 2.25v9.505a2.25 2.25 0 0 1-2.25 2.25H4.25A2.25 2.25 0 0 1 2 16.755V7.25A2.25 2.25 0 0 1 4.25 5h15.495zm-2.495 9.5H6.75l-.102.007a.75.75 0 0 0 0 1.486L6.75 16h10.5l.102-.007a.75.75 0 0 0 0-1.486l-.102-.007zM16.5 11a1 1 0 1 0 0 2a1 1 0 0 0 0-2zm-2.995 0a1 1 0 1 0 0 2a1 1 0 0 0 0-2zm-3 0a1 1 0 1 0 0 2a1 1 0 0 0 0-2zm-3 0a1 1 0 1 0 0 2a1 1 0 0 0 0-2zM6 8a1 1 0 1 0 0 2a1 1 0 0 0 0-2zm2.995 0a1 1 0 1 0 0 2a1 1 0 0 0 0-2zm3 0a1 1 0 1 0 0 2a1 1 0 0 0 0-2zm3 0a1 1 0 1 0 0 2a1 1 0 0 0 0-2zm3 0a1 1 0 1 0 0 2a1 1 0 0 0 0-2z"
+                fill="currentColor"></path>
+        </g>
+    </svg>
+</div>
+<script src="/lib/jquery-3.7.0.min.js"></script>
+<script src="/lib/jquery-ui.min.js"></script>
+<script src="/lib/jquery.ui.touch-punch.min.js"></script>
+<script src="/lib/simple-keyboard-3.7.2.js"></script>
+<script src="/lib/keycode.js"></script>
+<script src="/lib/keyboard.js"></script>
+</body>
+</html>

+ 70 - 0
lib/keyboard.css

@@ -0,0 +1,70 @@
+* {
+    touch-action: none;
+}
+.virtual-keyboard-window {
+    user-select: none;
+    position: fixed;
+    top: 0;
+    width: 800px;
+    border-radius: 10px;
+    box-shadow: 0 1px 5px 2px rgba(0, 0, 0, 0.1);
+    border: 1px solid #ddd;
+    background: #ececec;
+    z-index: 999;
+    overflow: hidden;
+}
+
+.virtual-keyboard-window .window-content {
+    height: 100%;
+}
+
+.hg-theme-default .hg-button {
+    height: 45px;
+}
+
+.virtual-keyboard-window .window-top {
+    cursor: move;
+    text-align: center;
+    height: 20px;
+    border-top-right-radius: 5px;
+    border-top-left-radius: 5px;
+    padding: 5px;
+    background-color: #ddd;
+    color: #333;
+}
+
+.virtual-keyboard-window .btn-close {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    position: absolute;
+    right: 0;
+    top: 0;
+    width: 50px;
+    height: 30px;
+    box-sizing: border-box;
+    padding: 5px 15px;
+    border: none;
+    background: none;
+    cursor: pointer;
+}
+
+.keyboard-toggle {
+    width: 20px;
+    height: 20px;
+    padding: 5px;
+    position: absolute;
+    top: 0;
+    left: 0;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    background: #fff;
+    opacity: 0.5;
+    box-shadow: 0 1px 5px 2px rgba(0, 0, 0, 0.1);
+    color: #333;
+    border-radius: 4px;
+    border: 1px solid #ddd;
+    z-index: 999;
+    cursor: pointer;
+}

+ 218 - 0
lib/keyboard.js

@@ -0,0 +1,218 @@
+function touchHandler(event) {
+    var touches = event.changedTouches,
+        first = touches[0],
+        type = "";
+    switch (event.type) {
+        case "touchstart":
+            type = "mousedown";
+            break;
+        case "touchmove":
+            type = "mousemove";
+            break;
+        case "touchend":
+            type = "mouseup";
+            break;
+        default:
+            return;
+    }
+
+    // initMouseEvent(type, canBubble, cancelable, view, clickCount,
+    //                screenX, screenY, clientX, clientY, ctrlKey,
+    //                altKey, shiftKey, metaKey, button, relatedTarget);
+
+    var simulatedEvent = document.createEvent("MouseEvent");
+    simulatedEvent.initMouseEvent(
+        type,
+        true,
+        true,
+        window,
+        1,
+        first.screenX,
+        first.screenY,
+        first.clientX,
+        first.clientY,
+        false,
+        false,
+        false,
+        false,
+        0 /*left*/,
+        null
+    );
+
+    first.target.dispatchEvent(simulatedEvent);
+    event.preventDefault();
+}
+
+(function init() {
+    document.addEventListener("touchstart", touchHandler, true);
+    document.addEventListener("touchmove", touchHandler, true);
+    document.addEventListener("touchend", touchHandler, true);
+    document.addEventListener("touchcancel", touchHandler, true);
+})();
+
+let dragging = false;
+$(".virtual-keyboard-window").draggable({
+    containment: "parent",
+    handle: ".window-top",
+    drag: function (event, ui) {
+        localStorage.setItem("keyboard-position", JSON.stringify(ui.position));
+    },
+    start: function (event, ui) {
+        dragging = true;
+    },
+    stop: function (event, ui) {
+        setTimeout(() => {
+            dragging = false;
+        }, 300);
+    },
+});
+$(".keyboard-toggle").draggable({
+    containment: "parent",
+    drag: function (event, ui) {
+        localStorage.setItem(
+            "keyboard-toggle-position",
+            JSON.stringify(ui.position)
+        );
+    },
+    start: function (event, ui) {
+        dragging = true;
+    },
+    stop: function (event, ui) {
+        setTimeout(() => {
+            dragging = false;
+        }, 300);
+    },
+});
+function showKeyboard() {
+    if (dragging) return;
+    $(".virtual-keyboard-window").show();
+    $(".keyboard-toggle").hide();
+    localStorage.setItem("virtual-keyboard-visible", "true");
+}
+function hideKeyboard() {
+    if (dragging) return;
+    $(".virtual-keyboard-window").hide();
+    $(".keyboard-toggle").show();
+    localStorage.setItem("virtual-keyboard-visible", "false");
+}
+$(".btn-close").click(hideKeyboard);
+$(".keyboard-toggle").click(showKeyboard);
+if (
+    localStorage.getItem("virtual-keyboard-visible") === "true" ||
+    localStorage.getItem("virtual-keyboard-visible") === null
+) {
+    showKeyboard();
+} else {
+    hideKeyboard();
+}
+let keyboardPosition = {
+    left: (window.innerWidth - 800) / 2,
+    top: window.innerHeight - 300,
+};
+if (localStorage.getItem("keyboard-position")) {
+    keyboardPosition = JSON.parse(localStorage.getItem("keyboard-position"));
+    keyboardPosition.left = Math.min(
+        keyboardPosition.left,
+        window.innerWidth - 800
+    );
+    keyboardPosition.top = Math.min(
+        keyboardPosition.top,
+        window.innerHeight - 300
+    );
+}
+$(".virtual-keyboard-window").css("left", keyboardPosition.left);
+$(".virtual-keyboard-window").css("top", keyboardPosition.top);
+let togglePosition = {
+    left: window.innerWidth - 100,
+    top: window.innerHeight - 100,
+};
+if (localStorage.getItem("keyboard-toggle-position")) {
+    togglePosition = JSON.parse(
+        localStorage.getItem("keyboard-toggle-position")
+    );
+    togglePosition.left = Math.min(togglePosition.left, window.innerWidth - 50);
+    togglePosition.top = Math.min(togglePosition.top, window.innerHeight - 50);
+}
+$(".keyboard-toggle").css("left", togglePosition.left);
+$(".keyboard-toggle").css("top", togglePosition.top);
+
+const Keyboard = window.SimpleKeyboard.default;
+const keyboard = new Keyboard({
+    onChange: (input) => onChange(input),
+    onKeyPress: (button) => onKeyPress(button),
+});
+
+function onChange(input) {
+    // document.querySelector(".input").value = input;
+    console.log("Input changed", input);
+}
+
+function onKeyPress(button) {
+    console.log("Button pressed", button);
+    if (button === "{shift}" || button === "{lock}") {
+        handleShift();
+        return;
+    }
+    keyboard.clearInput();
+    let key = button;
+    if (key === ".com") {
+        for (let char of ".com".split("")) {
+            sendKey(char);
+        }
+        return;
+    }
+    switch (key) {
+        case "{bksp}":
+            key = "Backspace";
+            break;
+        case "{enter}":
+            key = "Enter";
+            break;
+        case "{space}":
+            key = " ";
+            break;
+        case "{tab}":
+            key = "Tab";
+            break;
+        case "{esc}":
+            key = "Escape";
+            break;
+        case "{lock}":
+            key = "CapsLock";
+            break;
+        case "{shift}":
+            key = "Shift";
+            break;
+        case "{alt}":
+            key = "Alt";
+            break;
+        case "{ctrl}":
+            key = "Control";
+            break;
+    }
+    sendKey(key);
+}
+
+function sendKey(key) {
+    let ev = new KeyboardEvent("keydown", {
+        key,
+        code: keyCode[key],
+    });
+    window.dispatchEvent(ev);
+}
+
+function handleShift() {
+    let currentLayout = keyboard.options.layoutName;
+    let shiftToggle = currentLayout === "default" ? "shift" : "default";
+
+    keyboard.setOptions({
+        layoutName: shiftToggle,
+    });
+}
+
+$(".virtual-keyboard-window,.keyboard-toggle").bind(
+    "touchstart mousedown",
+    function (event) {
+        event.stopPropagation();
+    }
+);

+ 15 - 13
routes/index.js

@@ -9,13 +9,21 @@ http.defaults.baseURL = "https://web.parsec.app";
 
 module.exports = async function (fastify, opts) {
     fastify.get("/", async function (request, reply) {
-        let { data: html, headers } = await http.get(`/`);
-        // let html = fs.readFileSync("./test.html").toString();
-        let append = fs.readFileSync("./keyboard.html").toString();
-        html = html.replace("</body>", append + "</body>");
-        reply.headers(headers);
-        reply.type("text/html");
-        return html;
+        // let { data: html, headers } = await http.get(`/`);
+        // // let html = fs.readFileSync("./test.html").toString();
+        // let append = fs.readFileSync("./keyboard.html").toString();
+        // html = html.replace("</body>", append + "</body>");
+        // headers['Cross-Origin-Embedder-Policy'] = 'require-corp';
+        // reply.headers(headers);
+        // reply.type("text/html");
+        // return html;
+        reply.headers({
+            "Cross-Origin-Embedder-Policy": "require-corp",
+            "Referrer-Policy": "no-referrer",
+            "Content-Security-Policy": "frame-ancestors 'self'",
+            "Cross-Origin-Opener-Policy": "same-origin",
+        });
+        return reply.sendFile("index.html");
     });
 
     fastify.get("/parsecd", async function (request, reply) {
@@ -24,10 +32,4 @@ module.exports = async function (fastify, opts) {
         return;
     });
 
-    fastify.get("*", async function (request, reply) {
-        let { data, headers } = await http.get(request.url);
-        reply.headers(headers);
-        reply.type(headers["content-type"]);
-        return data;
-    });
 };