Skip to content

Instantly share code, notes, and snippets.

@amunchet
Last active August 7, 2025 19:55
Show Gist options
  • Save amunchet/4cfaf0274f3d238946f9f8f94fa9ee02 to your computer and use it in GitHub Desktop.
Save amunchet/4cfaf0274f3d238946f9f8f94fa9ee02 to your computer and use it in GitHub Desktop.
Copy/Paste for noVNC Proxmox
// ==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'
window.sendString = function(text) {
var el = document.getElementById("canvas-id")
text.split("").forEach(x=>{
setTimeout(()=>{
var needs_shift = x.match(/[A-Z!@#$%^&*()_+{}:\"<>?~|]/)
let evt
if (needs_shift) {
evt = new KeyboardEvent("keydown", {keyCode: 16})
el.dispatchEvent(evt)
evt = new KeyboardEvent("keydown", {key: x, shiftKey: true})
el.dispatchEvent(evt)
evt = new KeyboardEvent("keyup", {keyCode: 16})
el.dispatchEvent(evt)
}else{
evt = new KeyboardEvent("keydown", {key: x})
}
el.dispatchEvent(evt)
}, delay)
})
}
$(document).ready(function() {
setTimeout(()=>{
console.log("Starting up noVNC Copy/Paste (for Proxmox)")
$("canvas").attr("id", "canvas-id")
$("canvas").on("mousedown", (e)=>{
if(e.button == 2){ // Right Click
navigator.clipboard.readText().then(text =>{
window.sendString(text)
})
}
})
}, 1000);
})
})()
@eerison
Copy link

eerison commented Nov 14, 2024

it worked, thank you <3

@Laz2047
Copy link

Laz2047 commented Nov 21, 2024

Is anyone else having a problem with carriage returns? I have a multi-line copy that is pasted into one line on Proxmox. Sometimes, the leading character of the next line is omitted, too.

@amunchet
Copy link
Author

@Laz2047 I would try the version above by @zakhar-kogan - it might handle carriage returns a bit better (I haven't actually tried it myself). The original version was just meant to paste in long passwords or single line items, so I didn't really consider multi-lines.

@Laz2047
Copy link

Laz2047 commented Nov 21, 2024

Thank you. I'll check it out.

@PhotographybyAlex
Copy link

@amunchet Just came here to say I love you for making this script. It's such a massive quality of life improvement!

@Mohamed-Ali-Nakouri
Copy link

Mohamed-Ali-Nakouri commented Aug 5, 2025

used this in console to paste ssh key using right mouse click.


(function () {
    const delay = 50; // Slow down typing to avoid missed characters


    function loadjQuery(callback) {
        if (typeof window.jQuery !== 'undefined') {
            callback(window.jQuery);
        } else {
            const script = document.createElement('script');
            script.src = "https://code.jquery.com/jquery-3.3.1.min.js";
            script.onload = () => callback(window.jQuery);
            document.head.appendChild(script);
        }
    }

    function sendChar(el, char) {
        if (char === '\n' || char === '\r') {
            // Handle Enter
            el.dispatchEvent(new KeyboardEvent("keydown", { key: "Enter", code: "Enter", which: 13, keyCode: 13 }));
            el.dispatchEvent(new KeyboardEvent("keyup", { key: "Enter", code: "Enter", which: 13, keyCode: 13 }));
            return;
        }

        const needsShift = char.match(/[A-Z!@#$%^&*()_+{}:"<>?~|]/);

        if (needsShift) {
            el.dispatchEvent(new KeyboardEvent("keydown", { key: "Shift", code: "ShiftLeft", shiftKey: true }));
        }

        el.dispatchEvent(new KeyboardEvent("keydown", { key: char, code: undefined, shiftKey: !!needsShift }));
        el.dispatchEvent(new KeyboardEvent("keyup", { key: char, code: undefined, shiftKey: !!needsShift }));

        if (needsShift) {
            el.dispatchEvent(new KeyboardEvent("keyup", { key: "Shift", code: "ShiftLeft", shiftKey: false }));
        }
    }

    function sendString(text) {
        const el = document.getElementById("canvas-id");
        if (!el) {
            console.warn("Canvas not found");
            return;
        }

        text.split("").forEach((char, i) => {
            setTimeout(() => sendChar(el, char), delay * i);
        });
    }

    loadjQuery(($) => {
        setTimeout(() => {
            console.log("noVNC Paste active");
            $("canvas").attr("id", "canvas-id");

            $("canvas").on("mousedown", (e) => {
                if (e.button === 2) { // Right-click
                    navigator.clipboard.readText().then(text => {
                        sendString(text);
                    });
                }
            });
        }, 1000);
    });
})();

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment