Skip to content

Instantly share code, notes, and snippets.

@larkinwc
Forked from amunchet/noVNCCopyPasteProxmox.user.js
Last active September 12, 2025 20:43
Show Gist options
  • Save larkinwc/ca542dabebefe7866f903dc51a9a4553 to your computer and use it in GitHub Desktop.
Save larkinwc/ca542dabebefe7866f903dc51a9a4553 to your computer and use it in GitHub Desktop.
Copy/Paste for noVNC Proxmox
// ==UserScript==
// @name noVNC Paste for Proxmox (Ctrl+Shift+V)
// @namespace http://tampermonkey.net/
// @version 0.3
// @description Pastes text into a noVNC window using Ctrl+Shift+V
// @author Chester Enright (modified by user request)
// @match https://*/*
// @include /^.*novnc.*/
// @require http://code.jquery.com/jquery-3.3.1.min.js
// @grant none
// ==/UserScript==
(function () {
'use strict';
const delay = 1; // Delay between keystrokes in milliseconds
/**
* Sends a string to the canvas by simulating individual key presses.
* @param {string} text The text to send.
*/
window.sendString = function(text) {
var el = document.getElementById("canvas-id");
if (!el) {
console.error("noVNC canvas with ID 'canvas-id' not found.");
return;
}
text.split("").forEach((char, index) => {
setTimeout(() => {
const needs_shift = char.match(/[A-Z!@#$%^&*()_+{}:"<>?~|]/);
let evt;
if (needs_shift) {
// Press Shift
el.dispatchEvent(new KeyboardEvent("keydown", { keyCode: 16, code: 'ShiftLeft', key: 'Shift', bubbles: true }));
// Press the character key with shift modifier
el.dispatchEvent(new KeyboardEvent("keydown", { key: char, shiftKey: true, bubbles: true }));
// Release the character key
el.dispatchEvent(new KeyboardEvent("keyup", { key: char, shiftKey: true, bubbles: true }));
// Release Shift
el.dispatchEvent(new KeyboardEvent("keyup", { keyCode: 16, code: 'ShiftLeft', key: 'Shift', bubbles: true }));
} else {
// Press the character key
el.dispatchEvent(new KeyboardEvent("keydown", { key: char, bubbles: true }));
// Release the character key
el.dispatchEvent(new KeyboardEvent("keyup", { key: char, bubbles: true }));
}
}, index * delay);
});
};
$(document).ready(function() {
// Wait a moment for the noVNC canvas to be available.
setTimeout(() => {
console.log("Starting up noVNC Copy/Paste (for Proxmox)");
// Find the canvas and assign it an ID for easy selection.
const canvas = $("canvas").first();
if (canvas.length) {
canvas.attr("id", "canvas-id");
console.log("Canvas found and ID assigned.");
} else {
console.error("Could not find the noVNC canvas element.");
return;
}
// Listen for keydown events on the document.
$(document).on("keydown", function(e) {
// Check for the Ctrl + Shift + V combination
if (e.ctrlKey && e.shiftKey && (e.key === 'V' || e.key === 'v')) {
// Prevent the default browser action for this shortcut.
e.preventDefault();
console.log("Ctrl+Shift+V detected. Attempting to paste from clipboard.");
// Read text from the clipboard and send it.
navigator.clipboard.readText().then(text => {
window.sendString(text);
}).catch(err => {
console.error('Failed to read clipboard contents: ', err);
});
}
});
}, 1000); // 1-second delay
});
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment