// ==UserScript== // @name noVNC Paste for Proxmox // @namespace http://tampermonkey.net/ // @version 0.2a // @description Pastes text into a noVNC window (for use with Proxmox specifically) // @author Chester Enright // @match https://* // @include /^.*novnc.*/ // @require http://code.jquery.com/jquery-3.3.1.min.js // @grant none // ==/UserScript== const delay = 1 ; (function () { 'use strict'; let capsLockOn = false; const KEY_DELAY = 50; const SHIFT_NEEDED = /[A-Z!@#$%^&*()_+{}:"<>?~|]/; function simulateKeyEvent(el, eventType, key, options = {}) { const evt = new KeyboardEvent(eventType, { key, ...options }); el.dispatchEvent(evt); } window.sendString = function(text) { const el = document.getElementById("novnc-canvas"); if (!el) { console.error("Canvas element not found"); return; } text.split('').forEach((char, index) => { setTimeout(() => { if (char === '\n') { // Simulate "Enter" key press for line breaks simulateKeyEvent(el, "keydown", "Enter"); simulateKeyEvent(el, "keyup", "Enter"); } else { const needsShift = SHIFT_NEEDED.test(char); const isUpperCase = char >= 'A' && char <= 'Z'; if (needsShift) { simulateKeyEvent(el, "keydown", "Shift", { keyCode: 16 }); } if (isUpperCase && capsLockOn) { simulateKeyEvent(el, "keydown", char.toLowerCase()); simulateKeyEvent(el, "keyup", char.toLowerCase()); } else { simulateKeyEvent(el, "keydown", char); simulateKeyEvent(el, "keyup", char); } if (needsShift) { simulateKeyEvent(el, "keyup", "Shift", { keyCode: 16 }); } if (char === "CapsLock") { capsLockOn = !capsLockOn; console.log("Caps Lock state changed:", capsLockOn); } } }, index * KEY_DELAY); }); }; function waitForCanvas() { return new Promise((resolve) => { const checkCanvas = () => { const canvas = $("canvas"); if (canvas.length > 0) { canvas.attr("id", "novnc-canvas"); resolve(canvas); } else { setTimeout(checkCanvas, 500); } }; checkCanvas(); }); } async function setupNoVNCPaste() { try { console.log("Starting up noVNC Copy/Paste (for Proxmox) - Improved Version with Line Breaks"); const canvas = await waitForCanvas(); canvas.on("mousedown", (e) => { if (e.button == 2) { // Right Click navigator.clipboard.readText() .then(text => { window.sendString(text); }) .catch(err => { console.error("Failed to read clipboard:", err); }); } }); console.log("noVNC Copy/Paste setup completed"); } catch (error) { console.error("Error setting up noVNC Copy/Paste:", error); } } $(document).ready(setupNoVNCPaste); })();