Skip to content

Instantly share code, notes, and snippets.

@amunchet
Last active July 16, 2026 17:04
Show Gist options
  • Select an option

  • Save amunchet/4cfaf0274f3d238946f9f8f94fa9ee02 to your computer and use it in GitHub Desktop.

Select an option

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);
})
})()
@bakatz

bakatz commented Oct 17, 2025

Copy link
Copy Markdown

The canvas finding logic is broken, use this for sendString() if you're using novnc and it'll work:

function sendString(text) {

        var el = document.querySelector("#noVNC_container canvas")
        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)
            }, 100)
        })

    }

@cjpjxjx

cjpjxjx commented Nov 27, 2025

Copy link
Copy Markdown

感谢作者的代码!

受此启发,我在 Claude Code 的帮助下基于原代码开发了一个增强版的 PVE 粘贴输入工具(现已更新至 2.0)。主要改进包括:

  1. 核心机制:优先直接调用 noVNC 客户端自身的按键发送接口(RFB.sendKey),传入 keysym 与物理按键 code,无需再逆向猜测事件映射;无法获取该接口时才回退到合成键盘事件。对 Shift 组合键和特殊符号的处理更稳定。
  2. 交互优化:图形化模态框,支持实时字符统计、可调节并记忆的字符输入间隔,以及输入过程中的进度浮层(可随时取消)。
  3. 智能适配:实时检测不支持的非 ASCII 字符(中文、Emoji 等)并提示;根据 PVE 界面语言自动切换中英文;虚拟机关机或仅查看模式时自动隐藏按钮。
  4. 部署方式:除油猴脚本外,还支持 Nginx 注入方式,适合反向代理场景。

📖 项目文档与界面均已支持中英双语。

项目地址:https://github.com/cjpjxjx/pve-paste-input


Thanks for the code!

Inspired by this, I built an enhanced PVE paste input tool with the help of Claude Code (now updated to 2.0). Key improvements include:

  1. Core Mechanism: Prefers calling noVNC's own key-send API directly (RFB.sendKey) with the keysym and physical key code, instead of reverse-engineering event mappings; falls back to synthetic keyboard events only when that API isn't reachable. More reliable handling of Shift combinations and special symbols.
  2. Better UX: A graphical modal dialog with real-time character counting, an adjustable-and-remembered typing interval, and a progress panel during input (cancelable anytime).
  3. Smart Adaptation: Detects unsupported non-ASCII characters (Chinese, Emoji, etc.) in real time; auto-switches between Chinese and English based on the PVE UI language; auto-hides the button when the VM is off or in view-only mode.
  4. Deployment: Supports both a Tampermonkey userscript and Nginx injection (suitable for reverse-proxy setups).

📖 Both the documentation and the interface are now available in Chinese and English.

Repo: https://github.com/cjpjxjx/pve-paste-input

@SisypheOvO

SisypheOvO commented Apr 13, 2026

Copy link
Copy Markdown

@amunchet this script will run on all sites becuase

// @match        https://*
// @include      /^.*novnc.*/

matches all https websites. Changing the two lines above to the single line below will easily fix this I think:

// @match        *://*/*novnc*

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