@@ -189,6 +189,12 @@ type KVMConfig struct {
189
189
// socket at the path provided
190
190
TpmSocketPath string
191
191
192
+ // Enables bidirectional copy paste instead of basic pasting into VM.
193
+ // Requires QEMU 6.1+ compiled with qemu-vdagent chardev and for spice-vdagent to be installed on VM.
194
+ //
195
+ // Default: false
196
+ BidirectionalCopyPaste bool
197
+
192
198
// Add additional arguments to be passed to the QEMU instance. For example:
193
199
//
194
200
// vm config qemu-append -serial tcp:localhost:4001
@@ -546,6 +552,7 @@ func (vm *KVMConfig) String() string {
546
552
fmt .Fprintf (w , "Sockets:\t %v\n " , vm .Sockets )
547
553
fmt .Fprintf (w , "VGA:\t %v\n " , vm .Vga )
548
554
fmt .Fprintf (w , "Usb Use XHCI:\t %v\n " , vm .UsbUseXHCI )
555
+ fmt .Fprintf (w , "Bidirectional Copy Paste:\t %v\n " , vm .BidirectionalCopyPaste )
549
556
fmt .Fprintf (w , "TPM Socket: \t %v\n " , vm .TpmSocketPath )
550
557
w .Flush ()
551
558
fmt .Fprintln (& o )
@@ -772,6 +779,14 @@ func (vm *KvmVM) connectVNC() error {
772
779
for {
773
780
msg , err := vnc .ReadClientMessage (tee )
774
781
if err == nil {
782
+ // for cut text, send text immediately as string if not bi-directional
783
+ if cut , ok := msg .(* vnc.ClientCutText ); ok && ! vm .BidirectionalCopyPaste {
784
+ log .Info ("sending text for ClientCutText: %s" , cut .Text )
785
+ err = ns .Player .PlaybackString (vm .Name , vm .vncShim .Addr ().String (), string (cut .Text ))
786
+ if err != nil {
787
+ log .Warnln (err )
788
+ }
789
+ }
775
790
ns .Recorder .Route (vm .GetName (), msg )
776
791
continue
777
792
}
@@ -926,6 +941,17 @@ func (vm *KvmVM) launch() error {
926
941
var sErr bytes.Buffer
927
942
928
943
vmConfig := VMConfig {BaseConfig : vm .BaseConfig , KVMConfig : vm .KVMConfig }
944
+
945
+ // if using bidirectionalCopyPaste, error out if dependencies aren't met
946
+ if vmConfig .BidirectionalCopyPaste {
947
+ if err := checkVersion ("qemu" , MIN_QEMU_COPY_PASTE , qemuVersion ); err != nil {
948
+ return fmt .Errorf ("bidirectional-copy-paste not supported. Please disable: %v" , err )
949
+ }
950
+ if err := checkQemuChardev ("qemu-vdagent" ); err != nil {
951
+ return fmt .Errorf ("bidirectional-copy-paste not supported. Please disable: %v" , err )
952
+ }
953
+ }
954
+
929
955
args := vmConfig .qemuArgs (vm .ID , vm .instancePath )
930
956
args = vmConfig .applyQemuOverrides (args )
931
957
log .Debug ("final qemu args: %#v" , args )
@@ -1475,6 +1501,15 @@ func (vm VMConfig) qemuArgs(id int, vmPath string) []string {
1475
1501
args = append (args , fmt .Sprintf ("virtserialport,bus=virtio-serial%v.0,chardev=charvserialCC,id=charvserialCC,name=cc" , virtioPort ))
1476
1502
}
1477
1503
1504
+ if vm .BidirectionalCopyPaste {
1505
+ addVirtioDevice ()
1506
+
1507
+ args = append (args , "-chardev" )
1508
+ args = append (args , "qemu-vdagent,id=vdagent,clipboard=on" )
1509
+ args = append (args , "-device" )
1510
+ args = append (args , fmt .Sprintf ("virtserialport,bus=virtio-serial%v.0,chardev=vdagent,name=com.redhat.spice.0" , virtioPort ))
1511
+ }
1512
+
1478
1513
if vm .VirtioPorts != "" {
1479
1514
names := []string {}
1480
1515
0 commit comments