From 44f7d8428fc54ea4f0bce81becace7762fe445a2 Mon Sep 17 00:00:00 2001 From: Dave Kempe Date: Wed, 21 Oct 2026 14:02:28 +1100 Subject: [PATCH] client: lock all keys from the Controls panel, remembered per browser Follows #319. The option moves out of the Session panel header into the Controls panel's new Keyboard section, beside View, and is remembered in the browser like the View choice. The lock follows the setting whenever fullscreen is entered, and switching it while fullscreen applies at once. Browsers without the Keyboard Lock API show it disabled with a note. --- static/client.html | 92 +++++++++++++++++++++------------------------- 1 file changed, 42 insertions(+), 50 deletions(-) diff --git a/static/client.html b/static/client.html index 422e85a..199db4b 100644 --- a/static/client.html +++ b/static/client.html @@ -674,7 +674,6 @@ var clipboardPanel = null; var clipboardTextarea = null; var clipboardStatusEl = null; - var lockKeyboardCheckbox = null; function setClipboardStatus(msg) { if (!clipboardStatusEl) return; @@ -692,16 +691,11 @@ clipboardPanel.style.cssText = 'display:none;position:fixed;top:0;left:0;bottom:0;width:380px;background:var(--bg);border-right:2px solid var(--primary);z-index:3000;font-family:monospace;color:var(--text);flex-direction:column;'; clipboardPanel.innerHTML = - '
' + - '
' + - '

Session

' + - '' + - '
' + - '
' + - '' + - '' + - '' + - '
' + + '
' + + '

Session

' + + '' + + '' + + '' + '
' + '
' + '
Shared clipboard. Paste text below and click Send, or copy text received from the remote session.
' + @@ -718,14 +712,6 @@ document.body.appendChild(clipboardPanel); clipboardTextarea = document.getElementById('cp-text'); clipboardStatusEl = document.getElementById('cp-status'); - lockKeyboardCheckbox = document.getElementById('cp-lock-keyboard'); - if (!navigator.keyboard || !navigator.keyboard.lock) { - lockKeyboardCheckbox.disabled = true; - lockKeyboardCheckbox.title = 'Keyboard Lock is not supported by this browser.'; - } - lockKeyboardCheckbox.addEventListener('change', function() { - rgRequestKeyboardLock(lockKeyboardCheckbox.checked); - }); document.getElementById('cp-close').addEventListener('click', function() { toggleClipboardPanel(); @@ -959,6 +945,11 @@ '
SEND KEYS
' + '
' + '
' + + '
' + + '
KEYBOARD
' + + '' + + '
In fullscreen, Win, Alt+Tab and other shortcuts go to the remote desktop instead of this computer. Hold Esc to leave fullscreen.
' + + '
' + '
' + '
VIEW
' + '' + @@ -979,6 +970,14 @@ b.addEventListener('click', function() { sendKeyCombo(k.keys); }); keysEl.appendChild(b); }); + var lockKeys = document.getElementById('ctrl-lock-keys'); + lockKeys.checked = lockAllKeys; + if (!rgKeyboardLockSupported()) { + lockKeys.checked = false; + lockKeys.disabled = true; + document.getElementById('ctrl-lock-keys-hint').textContent = 'This browser can\'t capture system shortcuts. Chrome and Edge can.'; + } + lockKeys.addEventListener('change', function() { rgSetLockAllKeys(lockKeys.checked); }); document.getElementById('ctrl-view-' + viewMode).checked = true; ['fit', 'actual'].forEach(function(m) { document.getElementById('ctrl-view-' + m).addEventListener('change', function(e) { @@ -1626,47 +1625,40 @@ // (e.g. no user activation on load): the caller decides whether to // wait for a gesture or give up and show the windowed session. var fsKeyboardLocked = false; - function rgRequestKeyboardLock(lockAll) { - if (!navigator.keyboard || !navigator.keyboard.lock) { - if (lockKeyboardCheckbox) lockKeyboardCheckbox.checked = false; - setClipboardStatus('Keyboard Lock is not supported by this browser.'); - return; - } - if (!rgFullscreenEl()) { - setClipboardStatus(lockAll - ? 'Keyboard lock will apply when fullscreen is entered.' - : 'Keyboard lock applies only in fullscreen.'); - return; - } + // Lock all keys (#319): in fullscreen, send Win, Alt+Tab and the + // like to the remote desktop instead of this computer. Off, only + // Escape is locked, so a single press doesn't leave fullscreen. + // Remembered per browser; set from the Controls panel. + var lockAllKeys = false; + try { lockAllKeys = localStorage.getItem('rustguac_lock_all_keys') === '1'; } catch (e) {} + function rgKeyboardLockSupported() { + return !!(navigator.keyboard && navigator.keyboard.lock); + } + function rgSetLockAllKeys(on) { + lockAllKeys = !!on; + try { + if (lockAllKeys) localStorage.setItem('rustguac_lock_all_keys', '1'); + else localStorage.removeItem('rustguac_lock_all_keys'); + } catch (e) {} + if (rgFullscreenEl()) rgRequestKeyboardLock(); + } + function rgRequestKeyboardLock() { + if (!rgKeyboardLockSupported()) { rgShowEscNoticeOnce(); return; } + var lockAll = lockAllKeys; var request; try { - request = lockAll - ? navigator.keyboard.lock() - : navigator.keyboard.lock(['Escape']); + request = lockAll ? navigator.keyboard.lock() : navigator.keyboard.lock(['Escape']); } catch (e) { - if (lockAll && lockKeyboardCheckbox) lockKeyboardCheckbox.checked = false; - setClipboardStatus('Could not lock the keyboard.'); - if (!lockAll) rgShowEscNoticeOnce(); - return; + request = Promise.reject(e); } - request.then(function() { - if (lockKeyboardCheckbox) { - setClipboardStatus(lockAll ? 'Keyboard locked.' : 'Additional keyboard lock disabled.'); - } - }).catch(function() { - if (lockAll && lockKeyboardCheckbox) lockKeyboardCheckbox.checked = false; - setClipboardStatus('Could not lock the keyboard.'); + request.catch(function() { if (!lockAll) rgShowEscNoticeOnce(); }); } function rgOnFullscreenEntered() { if (fsKeyboardLocked) return; fsKeyboardLocked = true; - if (navigator.keyboard && navigator.keyboard.lock) { - rgRequestKeyboardLock(!!(lockKeyboardCheckbox && lockKeyboardCheckbox.checked)); - } else { - rgShowEscNoticeOnce(); - } + rgRequestKeyboardLock(); } function rgEnterFullscreen(onReject) { var el = document.documentElement;