Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ guacd (C, from guacamole-server)
- **Connections** with folder-based organisation and OIDC group access control
- **Active Sessions** section with live thumbnail previews
- **Session ended overlay** with Reconnect/Close buttons
- **Clipboard panel controls** (Home + Fullscreen)
- **8 built-in themes** with CSS gradient backgrounds, or configure your own
- **Reports page** with session analytics, history, and CSV export

Expand Down
16 changes: 16 additions & 0 deletions docs/web-sessions.md
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,22 @@ Clipboard copy and paste can be independently disabled per connections entry. Th

These work for all session types (SSH, RDP, VNC, Web), not just web sessions. See [Security: Clipboard control](security.md#clipboard-control) for details.

## In-session keyboard shortcuts

The session page supports a small set of browser-side shortcuts:

| Shortcut | Action | Notes |
|----------|--------|-------|
| `Ctrl+Alt+Shift` | Toggle the clipboard side panel | Works globally on the session page (capture phase), including when the remote display is focused. |
| `Ctrl+V` (Windows/Linux) or `Cmd+V` (macOS) | Sync browser clipboard text to the remote session, then send paste | If clipboard API access is available, rustguac reads local clipboard text and sends it to the remote before forwarding the paste key event. |
| `Esc` (browser fullscreen) | Exit fullscreen | Browser-native fullscreen key. rustguac may request keyboard lock while in fullscreen; if lock is unavailable, an on-screen notice reminds users to press Esc. |

Additional behavior:

- No dedicated keyboard combo is currently assigned for entering fullscreen. Users can use entry-level fullscreen-on-connect, or open the `Ctrl+Alt+Shift` clipboard panel and click its **Fullscreen** button (next to **Home**).
- All other key presses are passed through to the remote host by Guacamole keyboard handling.
- Clipboard policy flags still apply: `disable_copy` and `disable_paste` can block corresponding clipboard flows regardless of local shortcuts.

## URL placeholders

The entry URL supports credential placeholders that are URL-encoded and substituted before Chromium navigates:
Expand Down
36 changes: 8 additions & 28 deletions static/client.html
Original file line number Diff line number Diff line change
Expand Up @@ -118,24 +118,6 @@
border: 1px solid var(--border) !important;
}
#btn-reconnect:hover { background: var(--border); }
#fs-toggle {
display: none;
position: fixed;
top: 10px;
right: 10px;
z-index: 1500;
background: rgba(0,0,0,0.55);
color: var(--text-muted);
border: 1px solid var(--border);
border-radius: 4px;
padding: 4px 10px;
font-family: monospace;
font-size: 14px;
cursor: pointer;
opacity: 0.45;
transition: opacity 0.2s;
}
#fs-toggle:hover { opacity: 1; color: var(--accent); }
#fs-bar {
display: none;
position: fixed;
Expand Down Expand Up @@ -247,7 +229,6 @@ <h2 id="disconnected-title">Session Ended</h2>
</div>
</div>
<div id="status">Loading...</div>
<button id="fs-toggle" title="Enter fullscreen">&#9974; Fullscreen</button>
<div id="fs-bar">
<div id="fs-bar-title"></div>
<div id="fs-bar-buttons">
Expand Down Expand Up @@ -528,6 +509,7 @@ <h2 id="disconnected-title">Session Ended</h2>
'<div style="display:flex;align-items:center;gap:0.6em;padding:0.8em 1em;border-bottom:1px solid var(--border);background:var(--surface);">' +
'<h3 style="margin:0;flex:1;color:var(--primary);font-size:1.1em;">Session</h3>' +
'<button id="cp-home" style="background:var(--input);border:1px solid var(--border);color:var(--accent);font-family:monospace;font-size:0.9em;padding:0.35em 0.8em;border-radius:3px;cursor:pointer;" title="Return to the Connections page">&#127968; Home</button>' +
'<button id="cp-fullscreen" style="background:var(--input);border:1px solid var(--border);color:var(--accent);font-family:monospace;font-size:0.9em;padding:0.35em 0.8em;border-radius:3px;cursor:pointer;" title="Enter fullscreen">&#9974; Fullscreen</button>' +
'<button id="cp-close" style="background:none;border:none;color:var(--text-dim);font-size:1.6em;cursor:pointer;font-family:monospace;padding:0 0.3em;">&times;</button>' +
'</div>' +
'<div style="flex:1;display:flex;flex-direction:column;padding:1em;gap:0.8em;overflow-y:auto;min-height:0;">' +
Expand Down Expand Up @@ -557,6 +539,10 @@ <h2 id="disconnected-title">Session Ended</h2>
// Connections' active-session card.
window.location.href = '/connections.html';
});
document.getElementById('cp-fullscreen').addEventListener('click', function() {
rgEnterFullscreen();
if (panelOpen) toggleClipboardPanel();
});
document.getElementById('cp-send').addEventListener('click', function() {
if (clipboardTextarea.value) sendClipboardToRemote(clipboardTextarea.value);
});
Expand Down Expand Up @@ -1043,9 +1029,9 @@ <h2 id="disconnected-title">Session Ended</h2>
// the prior gesture. So when the entry is marked
// fullscreen-on-connect we don't try to fire on page load.
// Instead we arm a one-shot listener for the next mousedown
// or keydown after CONNECTED. The manual gear-toggle button
// in the corner uses its own click gesture and works at any
// time once shown.
// or keydown after CONNECTED. The Ctrl+Alt+Shift menu's
// fullscreen button uses its own click gesture and works at
// any time once shown.
function rgFullscreenEl() {
return document.fullscreenElement
|| document.webkitFullscreenElement
Expand Down Expand Up @@ -1138,9 +1124,7 @@ <h2 id="disconnected-title">Session Ended</h2>
}
function rgOnFullscreenChange() {
var inFs = !!rgFullscreenEl();
var tg = document.getElementById('fs-toggle');
var bar = document.getElementById('fs-bar');
if (tg) tg.style.display = inFs ? 'none' : 'block';
if (bar) {
if (inFs) {
bar.classList.add('visible');
Expand All @@ -1159,7 +1143,6 @@ <h2 id="disconnected-title">Session Ended</h2>
}
['fullscreenchange','webkitfullscreenchange','mozfullscreenchange','MSFullscreenChange']
.forEach(function(ev){ document.addEventListener(ev, rgOnFullscreenChange); });
document.getElementById('fs-toggle').addEventListener('click', rgEnterFullscreen);
document.getElementById('fs-exit').addEventListener('click', rgExitFullscreen);
document.getElementById('fs-disconnect').addEventListener('click', function() {
rgExitFullscreen();
Expand All @@ -1179,7 +1162,6 @@ <h2 id="disconnected-title">Session Ended</h2>
// First capture after 3s (let display render)
setTimeout(captureAndUploadThumbnail, 3000);
}
document.getElementById('fs-toggle').style.display = 'block';
document.getElementById('fs-bar-title').textContent =
entryDisplayName || ('Session ' + sessionId.substring(0,8));
if (wantFullscreen) rgArmFullscreenGesture();
Expand All @@ -1197,7 +1179,6 @@ <h2 id="disconnected-title">Session Ended</h2>
statusEl.textContent = 'Disconnected'; statusEl.className = '';
if (_thumbInterval) { clearInterval(_thumbInterval); _thumbInterval = null; }
document.getElementById('disconnected-overlay').className = 'visible';
document.getElementById('fs-toggle').style.display = 'none';
if (rgFullscreenEl()) rgExitFullscreen();
break;
}
Expand All @@ -1212,7 +1193,6 @@ <h2 id="disconnected-title">Session Ended</h2>
document.getElementById('disconnected-title').textContent = 'Connection Error';
document.getElementById('disconnected-message').textContent = status.message || 'An error occurred.';
document.getElementById('disconnected-overlay').className = 'visible';
document.getElementById('fs-toggle').style.display = 'none';
if (rgFullscreenEl()) rgExitFullscreen();
};

Expand Down