fix(web): run navigator.clipboard.write only when window has focus (#858)

When we receive clipboard update from the server and the browser window
is not in focus (for example, when the user copies some text directly on
the machine, not via the browser's VNC viewer), we got an error that
`navigator.clipboard.write` is not allowed when window is not in focus.
This PR adds a window check that the window has focus, and now
`clipboard.write` runs only when the window is in focus.
This commit is contained in:
Alex Yusiuk
2025-07-04 11:21:52 +00:00
committed by GitHub
parent a84a5c0571
commit 4dc5945019
@@ -72,6 +72,7 @@
let lastClipboardMonitorLoopError: Error | null = null;
let componentDestroyed = false;
let runWhenFocusedQueue: (() => void)[] = [];
/* Firefox-specific BEGIN */
@@ -173,13 +174,23 @@
}
}
function runWhenWindowFocused(fn: () => void) {
if (document.hasFocus()) {
fn();
} else {
runWhenFocusedQueue.push(fn);
}
}
// This callback is required to update client clipboard state when remote side has changed.
function onRemoteClipboardChanged(data: ClipboardData) {
try {
const mime_formats = clipboardDataToRecord(data);
const clipboard_item = new ClipboardItem(mime_formats);
lastReceivedClipboardData = clipboardDataToClipboardItemsRecord(data);
navigator.clipboard.write([clipboard_item]);
runWhenWindowFocused(() => {
lastReceivedClipboardData = clipboardDataToClipboardItemsRecord(data);
navigator.clipboard.write([clipboard_item]);
});
} catch (err) {
console.error('Failed to set client clipboard: ' + err);
}
@@ -445,6 +456,8 @@
window.addEventListener('keydown', captureKeys, false);
window.addEventListener('keyup', captureKeys, false);
window.addEventListener('focus', focusEventHandler);
}
function resetHostStyle() {
@@ -717,6 +730,13 @@
inner.dispatchEvent(new CustomEvent('ready', { detail: result, bubbles: true, composed: true }));
}
function focusEventHandler() {
while (runWhenFocusedQueue.length > 0) {
const fn = runWhenFocusedQueue.shift();
fn?.();
}
}
onMount(async () => {
loggingService.verbose = verbose === 'true';
loggingService.info('Dom ready');
@@ -726,6 +746,7 @@
onDestroy(() => {
window.removeEventListener('resize', resizeHandler);
window.removeEventListener('focus', focusEventHandler);
componentDestroyed = true;
});
</script>