[MOD] Add paste clipboard to noVNC

platix

New Member
Mar 29, 2018
3
1
3
37
Hi guys!
Here I bring you a very useful mod that adds a button to noVNC that sends the text entered in an input (clipboard or anything).

In file /usr/share/novnc-pve/index.html.tpl

Add:
HTML:
                    <input type="image" alt="Input" src="/novnc/app/images/clipboard.svg"
                        id="noVNC_send_paste" class="noVNC_button"
                        title="Send user input" />

on line 118 after:
HTML:
                    <input type="image" alt="Ctrl+Alt+Del" src="/novnc/app/images/ctrlaltdel.svg"
                        id="noVNC_send_ctrl_alt_del_button" class="noVNC_button"
                        title="Send Ctrl-Alt-Del" />


In file /usr/share/novnc-pve/app.js

Add:
HTML:
       sendPaste: function () {
            if (this._rfb_connection_state !== 'connected' || this._view_only) { return false; }

            var t = prompt("Enter text to be sent to console, (This wont send the enter keystroke)");

            if (t){
                t = t.split("");
                while(t.length){
                    var character = t.shift();
                    var i=[];
                    var code = character.charCodeAt();
                    var needs_shift = character.match(/[A-Zª!\"·$%&/()=?¿*Ç_:;>]/);
                    if (needs_shift) {
                        this.sendKey($$$core$input$keysym$$default.XK_Shift_L, character,1);
                    }
                    this.sendKey(code, character, 1);
                    this.sendKey(code, character,0);
                    if (needs_shift) {
                        this.sendKey($$$core$input$keysym$$default.XK_Shift_L, character,0);
                    }
                }

                $$$core$util$logging$$.Info("Sending user input");

                return true;
            } else {
                return false;
            }
        },

on line 7751 after:
HTML:
        sendCtrlAltDel: function () {
            if (this._rfb_connection_state !== 'connected' || this._view_only) { return false; }
            $$$core$util$logging$$.Info("Sending Ctrl-Alt-Del");

            this.sendKey($$$core$input$keysym$$default.XK_Control_L, "ControlLeft", true);
            this.sendKey($$$core$input$keysym$$default.XK_Alt_L, "AltLeft", true);
            this.sendKey($$$core$input$keysym$$default.XK_Delete, "Delete", true);
            this.sendKey($$$core$input$keysym$$default.XK_Delete, "Delete", false);
            this.sendKey($$$core$input$keysym$$default.XK_Alt_L, "AltLeft", false);
            this.sendKey($$$core$input$keysym$$default.XK_Control_L, "ControlLeft", false);

            return true;
        },

Add:
HTML:
            document.getElementById("noVNC_send_paste")
                .addEventListener('click', app$ui$$UI.sendPaste);

on line 10829 after:
HTML:
            document.getElementById("noVNC_send_ctrl_alt_del_button")
                .addEventListener('click', app$ui$$UI.sendCtrlAltDel);

and finally, add:
HTML:
        sendPaste: function() {
            app$ui$$UI.rfb.sendPaste();
        },

on line 12131 after:
HTML:
        sendCtrlAltDel: function() {
            app$ui$$UI.rfb.sendCtrlAltDel();
        },

It's working well with my spanish keyboard, if you use US keyboard try to change the line:
HTML:
                    var needs_shift = character.match(/[A-Zª!\"·$%&/()=?¿*Ç_:;>]/);

with:
HTML:
            var needs_shift = character.match(/[A-Z!@#$%^&*()_+{}:\"<>?~|]/);

or adapt to your keyboard.

Do not forget to clean the browser cache. I hope you find it useful.

Regards.
 
This is gold, will try tonight.

Am fearing it dissapears when doing an update to PVE but will find a way... :)
 
will be nice that this code was incorporated in proxmox, but I didn't find any channel to make the request
 
I know that this not the perfect solution, but it works in the most of my cases. Some characters are not sended well, but it's a beginning.

I coded it in 15min based in a github code and my needs.

I think that would be a good option to add the possibility to include plugins in proxmox made by the community. Looking the forums, many people needs it.
 
  • Like
Reactions: AlexLup
I find the lack of c&p irritating, using the console in Proxmox when its most critical, during setup of a new vhost. This means that I copy&paste the most and the functionality is not there..
 
I find the lack of c&p irritating, using the console in Proxmox when its most critical, during setup of a new vhost. This means that I copy&paste the most and the functionality is not there..
the problem with vms is that the vnc server comes from qemu (outside the vm) which has no notion of a cliboard inside the vm,
so we cannot really copy/paste via novnc on qemu vms

what would work, if you really need this, is to add a serial port to the vm (with 'qm set ID -serial0 socket) and set the display to the serial socket
then you do not have a 'real' graphical interface anymore, but are able to use either novnc or xterm.js which both support copy/paste under those circumstances,
alternatively, we now support cloud init, so you could add an ip/hostname/ssh-key there and simply setup the vm with ssh

I know that this not the perfect solution, but it works in the most of my cases. Some characters are not sended well, but it's a beginning.
i agree that something like this could work (see https://bugzilla.proxmox.com/show_bug.cgi?id=1406), we would have to limit it to basic ascii characters, since with everything else (even brackets, commas, etc.)
it is impossble to know which comibination of shift/alt-gr etc. has to be pressed
(and honestly i do not think we want to maintain a big list of language/keypress maps)

I think that would be a good option to add the possibility to include plugins in proxmox made by the community. Looking the forums, many people needs it.
we already support plugins for storages, what else would you have in mind? what kind of api? for what parts?
although it would be better to discuss this on the developer mailing list (which is linked in the developer documentation)
 
thx platix.I modified my PVE according to your tips.
my version
Code:
# pveversion -v
proxmox-ve: 5.3-1 (running kernel: 4.15.18-11-pve)
pve-manager: 5.3-11 (running version: 5.3-11/d4907f84)
pve-kernel-4.15: 5.3-2
pve-kernel-4.15.18-11-pve: 4.15.18-34
pve-kernel-4.15.18-9-pve: 4.15.18-30
ceph: 12.2.11-pve1
corosync: 2.4.4-pve1
criu: 2.11.1-1~bpo90
glusterfs-client: 3.8.8-1
ksm-control-daemon: 1.2-2
libjs-extjs: 6.0.1-2
libpve-access-control: 5.1-3
libpve-apiclient-perl: 2.0-5
libpve-common-perl: 5.0-47
libpve-guest-common-perl: 2.0-20
libpve-http-server-perl: 2.0-12
libpve-storage-perl: 5.0-38
libqb0: 1.0.3-1~bpo9
lvm2: 2.02.168-pve6
lxc-pve: 3.1.0-3
lxcfs: 3.0.3-pve1
novnc-pve: 1.0.0-3
openvswitch-switch: 2.7.0-3
proxmox-widget-toolkit: 1.0-23
pve-cluster: 5.0-33
pve-container: 2.0-34
pve-edk2-firmware: 1.20181023-1
pve-firewall: 3.0-18
pve-firmware: 2.0-6
pve-ha-manager: 2.0-6
pve-i18n: 1.0-9
pve-libspice-server1: 0.14.1-2
pve-qemu-kvm: 2.12.1-2
pve-xtermjs: 3.10.1-2
qemu-server: 5.0-47
smartmontools: 6.5+svn4324-1
spiceterm: 3.0-5
vncterm: 1.5-3
zfsutils-linux: 0.7.12-pve1~bpo1

In file /usr/share/novnc-pve/index.html.tpl
I add line 142-146
Code:
138             <!-- Clipboard -->
139             <input type="image" alt="Clipboard" src="/novnc/app/images/clipboard.svg"
140                 id="noVNC_clipboard_button" class="noVNC_button"
141                 title="Clipboard" />
142 <!--by Michael.Tong start -->
143                         <input type="image" alt="Input" src="/novnc/app/images/clipboard.svg"
144                                 id="noVNC_send_paste" class="noVNC_button"
145                                 title="Send user input" />
146 <!--by Michael.Tong end -->
In file /usr/share/novnc-pve/app.js
I made 3 changes
1.add line 8405-8435
Code:
 8401         sendCredentials(creds) {
 8402             this._rfb_credentials = creds;
 8403             setTimeout(this._init_msg.bind(this), 0);
 8404         }
 8405  /*by Michael.Tong start*/
 8406        sendPaste () {
 8407             if (this._rfb_connection_state !== 'connected' || this._view_only) { return false; }
 8408
 8409             var t = prompt("Enter text to be sent to console, (This wont send the enter keystroke)");
 8410
 8411             if (t){
 8412                 t = t.split("");
 8413                 while(t.length){
 8414                     var character = t.shift();
 8415                     var i=[];
 8416                     var code = character.charCodeAt();
 8417                     var needs_shift = character.match(/[A-Z!@#$%^&*()_+{}:\"<>?~|]/);
 8418                     if (needs_shift) {
 8419                         this.sendKey($$$core$input$keysym$$default.XK_Shift_L, character,1);
 8420                     }
 8421                     this.sendKey(code, character, 1);
 8422                     this.sendKey(code, character,0);
 8423                     if (needs_shift) {
 8424                         this.sendKey($$$core$input$keysym$$default.XK_Shift_L, character,0);
 8425                     }
 8426                 }
 8427
 8428                 $$$core$util$logging$$.Info("Sending user input");
 8429
 8430                 return true;
 8431             } else {
 8432                 return false;
 8433             }
 8434         }
 8435  /*by Michael.Tong end*/
 8436         sendCtrlAltDel() {
 8437             if (this._rfb_connection_state !== 'connected' || this._viewOnly) { return; }
 8438             $$$core$util$logging$$.Info("Sending Ctrl-Alt-Del");
2.add line 11667-11670
Code:
11664         addFullscreenHandlers() {
11665             document.getElementById("noVNC_fullscreen_button")
11666                 .addEventListener('click', app$ui$$UI.toggleFullscreen);
11667 /*by Michael.Tong start*/
11668                         document.getElementById("noVNC_send_paste")
11669                                 .addEventListener('click', app$ui$$UI.sendPaste);
11670 /*by Michael.Tong end*/
11671             window.addEventListener('fullscreenchange', app$ui$$UI.updateFullscreenButton);
11672             window.addEventListener('mozfullscreenchange', app$ui$$UI.updateFullscreenButton);
11673             window.addEventListener('webkitfullscreenchange', app$ui$$UI.updateFullscreenButton);
11674             window.addEventListener('msfullscreenchange', app$ui$$UI.updateFullscreenButton);

3.add line 12901-12905
Code:
12898         sendCtrlAltDel() {
12899             app$ui$$UI.rfb.sendCtrlAltDel();
12900                 },
12901 /*by Michael.Tong start*/
12902         sendPaste: function() {
12903             app$ui$$UI.rfb.sendPaste();
12904         },
12905 /*by Michael.Tong end*/
12906     /* ------^-------
12907      *   /EXTRA KEYS
12908      * ==============
12909      *     PVE
12910      * ------v------*/
tips:
1.this is US keyboard
2.I installed ceph, so the lines number may not be correct in your PVE, you can refer to the context function.
3.this version(proxmox-ve: 5.3-1 (running kernel: 4.15.18-11-pve)) include Ctrl+ALT+DEL,so I didn't add it.
This greatly improves my work efficiency,thank you platix.
 
  • Like
Reactions: bhatmag1ck
Thank you very much tcicy for this simple but yet great addition. It resolves the pain from having to type long secure passwords into the terminal during setup or login when no network is available and no spice is running.
I really don't understand why this hasn't been picked up by the Devs.
This is great even if it's limited to basic ASCII characters!

Edit:
Interestingly there seems to be a clipboard implementation based on Websockets which is hidden by the css class "noVNC_hidden".
Unfortunately it's not working (yet?). At least not for me.
Is this WIP or could someone give some insights about this hidden functionality?

Edit 2:
Forget my previous edit. I didn't check the noVNC Sourcecode before.
It seems to be a functionality of noVNC which has been hidden because it doesn't work (?).
 
Last edited:
I have made a newer version with enter key enabled:
just replace /usr/share/novnc-pve/app.js first part in @tcicy answer with this:
JavaScript:
sendPaste () {
navigator.clipboard.readText()
    .then(t => {
        if (t) {
            t = t.split("");
            while (t.length) {
                var character = t.shift();
                var i = [];
                var code = character.charCodeAt();
                var needs_shift = character.match(/[A-Z!@#$%^&*()_+{}:\"<>?~|]/);
                if (needs_shift) {
                    this.sendKey($$$core$input$keysym$$default.XK_Shift_L, character, 1);
                }
                if (code === 10) {
                    this.sendKey($$$core$input$keysym$$default.XK_Return, character, 1);
                    this.sendKey($$$core$input$keysym$$default.XK_Return, character, 0);
                } else {
                    this.sendKey(code, character, 1);
                    this.sendKey(code, character, 0);
                }
                if (needs_shift) {
                    this.sendKey($$$core$input$keysym$$default.XK_Shift_L, character, 0);
                }
            }
            $$$core$util$logging$$.Info("Sending user input");
            return true;
        } else {
            return false;
        }
    })
    .catch(err => {
        console.error('Failed to read clipboard contents: ', err);
    });
}

proxmox version:
Code:
proxmox-ve: 7.0-2 (running kernel: 5.11.22-1-pve)
pve-manager: 7.0-8 (running version: 7.0-8/b1dbf562)
pve-kernel-5.11: 7.0-3
pve-kernel-helper: 7.0-3
pve-kernel-5.11.22-1-pve: 5.11.22-2
ceph: 16.2.7
ceph-fuse: 16.2.7
corosync: 3.1.2-pve2
criu: 3.15-1+pve-1
glusterfs-client: 9.2-1
ifupdown2: 3.0.0-1+pve5
ksm-control-daemon: 1.4-1
libjs-extjs: 7.0.0-1
libknet1: 1.21-pve1
libproxmox-acme-perl: 1.1.1
libproxmox-backup-qemu0: 1.2.0-1
libpve-access-control: 7.0-4
libpve-apiclient-perl: 3.2-1
libpve-common-perl: 7.0-4
libpve-guest-common-perl: 4.0-2
libpve-http-server-perl: 4.0-2
libpve-storage-perl: 7.0-7
libspice-server1: 0.14.3-2.1
lvm2: 2.03.11-2.1
lxc-pve: 4.0.9-2
lxcfs: 4.0.8-pve1
novnc-pve: 1.2.0-3
proxmox-backup-client: 2.0.1-1
proxmox-backup-file-restore: 2.0.1-1
proxmox-mini-journalreader: 1.2-1
proxmox-widget-toolkit: 3.2-4
pve-cluster: 7.0-3
pve-container: 4.0-5
pve-docs: 7.0-5
pve-edk2-firmware: 3.20200531-1
pve-firewall: 4.2-2
pve-firmware: 3.2-4
pve-ha-manager: 3.3-1
pve-i18n: 2.4-1
pve-qemu-kvm: 6.0.0-2
pve-xtermjs: 4.12.0-1
qemu-server: 7.0-7
smartmontools: 7.2-1
spiceterm: 3.2-2
vncterm: 1.7-1
zfsutils-linux: 2.0.4-pve1
 
  • Like
Reactions: bhatmag1ck
Please integrate this great solution into proxmox standard, dear dev team. It is a pain to paste passwords or URLs into VMs otherwise.
 
  • Like
Reactions: werter and Darkk

About

The Proxmox community has been around for many years and offers help and support for Proxmox VE, Proxmox Backup Server, and Proxmox Mail Gateway.
We think our community is one of the best thanks to people like you!

Get your subscription!

The Proxmox team works very hard to make sure you are running the best software and getting stable updates and security enhancements, as well as quick enterprise support. Tens of thousands of happy customers have a Proxmox subscription. Get yours easily in our online shop.

Buy now!