@@ -5,8 +5,12 @@ import {
55 DialogActions ,
66 DialogContent ,
77 DialogTitle ,
8+ IconButton ,
9+ Tooltip ,
810 Typography ,
911} from "@mui/material" ;
12+ import ContentPasteGoIcon from "@mui/icons-material/ContentPasteGo" ;
13+ import ContentCopyIcon from "@mui/icons-material/ContentCopy" ;
1014import RFB from "@novnc/novnc/core/rfb" ;
1115import React from "react" ;
1216import { isMobileState } from "../../data/atoms" ;
@@ -16,10 +20,35 @@ import { useCallback, useEffect, useRef, useState } from "react";
1620export function RemoteBrowser ( { wsUrl, timeout, onClose } ) {
1721 const screenRef = useRef ( null ) ;
1822 const rfbRef = useRef ( null ) ;
23+ const [ selectedText , setSelectedText ] = useState ( "" ) ;
1924 const [ connected , setConnected ] = useState ( false ) ;
2025 const [ open , setOpen ] = useState ( false ) ;
2126 const [ timeLeft , setTimeLeft ] = useState ( timeout ) ;
2227
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+
2352 const setupRFB = useCallback ( ( ) => {
2453 if ( screenRef . current && ! rfbRef . current ) {
2554 const credentials = wsUrl . split ( "@" ) [ 0 ] . split ( "://" ) [ 1 ] ;
@@ -57,7 +86,7 @@ export function RemoteBrowser({ wsUrl, timeout, onClose }) {
5786
5887 rfbRef . current . addEventListener ( "clipboard" , ( e ) => {
5988 if ( e . detail . text ) {
60- navigator . clipboard . writeText ( e . detail . text ) ;
89+ setSelectedText ( e . detail . text ) ;
6190 }
6291 } ) ;
6392
@@ -147,6 +176,16 @@ export function RemoteBrowser({ wsUrl, timeout, onClose }) {
147176 { ! connected && "Connecting..." }
148177 </ DialogContent >
149178 < 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 >
150189 < Button onClick = { ( ) => onClose ( ) } variant = "contained" >
151190 Done
152191 </ Button >
0 commit comments