@@ -5,8 +5,12 @@ import {
5
5
DialogActions ,
6
6
DialogContent ,
7
7
DialogTitle ,
8
+ IconButton ,
9
+ Tooltip ,
8
10
Typography ,
9
11
} from "@mui/material" ;
12
+ import ContentPasteGoIcon from "@mui/icons-material/ContentPasteGo" ;
13
+ import ContentCopyIcon from "@mui/icons-material/ContentCopy" ;
10
14
import RFB from "@novnc/novnc/core/rfb" ;
11
15
import React from "react" ;
12
16
import { isMobileState } from "../../data/atoms" ;
@@ -16,10 +20,35 @@ import { useCallback, useEffect, useRef, useState } from "react";
16
20
export function RemoteBrowser ( { wsUrl, timeout, onClose } ) {
17
21
const screenRef = useRef ( null ) ;
18
22
const rfbRef = useRef ( null ) ;
23
+ const [ selectedText , setSelectedText ] = useState ( "" ) ;
19
24
const [ connected , setConnected ] = useState ( false ) ;
20
25
const [ open , setOpen ] = useState ( false ) ;
21
26
const [ timeLeft , setTimeLeft ] = useState ( timeout ) ;
22
27
28
+ const onPaste = useCallback ( ( ) => {
29
+ if ( ! rfbRef . current ) {
30
+ return ;
31
+ }
32
+
33
+ navigator . permissions . query ( { name : "clipboard-read" } ) . then ( ( status ) => {
34
+ if ( status . state === "granted" || status . state === "prompt" ) {
35
+ navigator . clipboard . readText ( ) . then ( ( text ) => {
36
+ for ( const char of text ) {
37
+ rfbRef . current . sendKey ( char . charCodeAt ( 0 ) , char ) ;
38
+ }
39
+ } ) ;
40
+ }
41
+ } ) ;
42
+ } , [ rfbRef ] ) ;
43
+
44
+ const onCopy = useCallback ( ( ) => {
45
+ if ( ! selectedText ) {
46
+ return ;
47
+ }
48
+
49
+ navigator . clipboard . writeText ( selectedText ) ;
50
+ } , [ selectedText ] ) ;
51
+
23
52
const setupRFB = useCallback ( ( ) => {
24
53
if ( screenRef . current && ! rfbRef . current ) {
25
54
const credentials = wsUrl . split ( "@" ) [ 0 ] . split ( "://" ) [ 1 ] ;
@@ -57,7 +86,7 @@ export function RemoteBrowser({ wsUrl, timeout, onClose }) {
57
86
58
87
rfbRef . current . addEventListener ( "clipboard" , ( e ) => {
59
88
if ( e . detail . text ) {
60
- navigator . clipboard . writeText ( e . detail . text ) ;
89
+ setSelectedText ( e . detail . text ) ;
61
90
}
62
91
} ) ;
63
92
@@ -147,6 +176,16 @@ export function RemoteBrowser({ wsUrl, timeout, onClose }) {
147
176
{ ! connected && "Connecting..." }
148
177
</ DialogContent >
149
178
< DialogActions >
179
+ < Tooltip title = "Copy selected text to clipboard" >
180
+ < IconButton onClick = { onCopy } sx = { { pr : 0 } } >
181
+ < ContentCopyIcon />
182
+ </ IconButton >
183
+ </ Tooltip >
184
+ < Tooltip title = "Paste text from clipboard" >
185
+ < IconButton onClick = { onPaste } >
186
+ < ContentPasteGoIcon />
187
+ </ IconButton >
188
+ </ Tooltip >
150
189
< Button onClick = { ( ) => onClose ( ) } variant = "contained" >
151
190
Done
152
191
</ Button >
0 commit comments