From c3c58581ccca69296048d8e0e5a7ba4cc48cc723 Mon Sep 17 00:00:00 2001 From: mrhid6 Date: Mon, 20 Jul 2026 09:49:20 +0100 Subject: [PATCH] fix: Fixed scale and mouse handler --- web/app/servers/[id]/console/page.tsx | 21 +++++++++++++++++---- web/lib/guacConsole.ts | 10 +++++++++- 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/web/app/servers/[id]/console/page.tsx b/web/app/servers/[id]/console/page.tsx index 845ed9c..20ad962 100644 --- a/web/app/servers/[id]/console/page.tsx +++ b/web/app/servers/[id]/console/page.tsx @@ -15,7 +15,11 @@ export default function ServerConsolePage() { const serverId = params.id as string; const containerRef = useRef(null); - const connectionRef = useRef<{ disconnect: () => void; setScale: (scale: number) => void } | null>(null); + const connectionRef = useRef<{ + disconnect: () => void; + setScale: (scale: number) => void; + resize: (width: number, height: number) => void; + } | null>(null); const [protocol, setProtocol] = useState(searchParams.get("protocol") || ""); const [keyId, setKeyId] = useState(""); @@ -121,9 +125,18 @@ export default function ServerConsolePage() { setPending(null); }, [connected, pending]); - // Apply zoom changes live without reconnecting. + // Apply zoom live without reconnecting: resize the remote to a resolution + // that, once scaled to fit the container, yields the requested zoom. Higher + // zoom = fewer remote pixels rendered larger. Display always fits the + // container exactly, so no scrollbars appear. useEffect(() => { - connectionRef.current?.setScale(zoom / dprRef.current); + if (!connectionRef.current || !containerRef.current) return; + const rect = containerRef.current.getBoundingClientRect(); + const dpr = dprRef.current; + const remoteW = Math.floor((rect.width * dpr) / zoom); + const remoteH = Math.floor((rect.height * dpr) / zoom); + connectionRef.current.resize(remoteW, remoteH); + connectionRef.current.setScale(zoom / dpr); }, [zoom]); function handleDisconnect() { @@ -276,7 +289,7 @@ export default function ServerConsolePage() {
); diff --git a/web/lib/guacConsole.ts b/web/lib/guacConsole.ts index 66af968..ea66b95 100644 --- a/web/lib/guacConsole.ts +++ b/web/lib/guacConsole.ts @@ -6,7 +6,7 @@ export function openConsole( container: HTMLElement, wsUrl: string, connectData = "" -): { disconnect: () => void; setScale: (scale: number) => void } { +): { disconnect: () => void; setScale: (scale: number) => void; resize: (width: number, height: number) => void } { // Guacamole's WebSocketTunnel builds the socket URL as `wsUrl + "?" + data`, // so wsUrl must NOT already contain a query string — pass params via connectData. const tunnel = new Guacamole.WebSocketTunnel(wsUrl); @@ -46,10 +46,15 @@ export function openConsole( const keyboard = new Guacamole.Keyboard(container); keyboard.onkeydown = (k: number) => client.sendKeyEvent(1, k); keyboard.onkeyup = (k: number) => client.sendKeyEvent(0, k); + // Guacamole.Mouse consumes the native mousedown, so clicking the console never + // moves DOM focus back to it. Refocus explicitly so keyboard capture resumes. + const refocus = () => container.focus(); + container.addEventListener("mousedown", refocus); container.focus(); return { disconnect() { + container.removeEventListener("mousedown", refocus); keyboard.onkeydown = null; keyboard.onkeyup = null; if (typeof keyboard.reset === "function") keyboard.reset(); @@ -59,5 +64,8 @@ export function openConsole( scale = s; display.scale(s); }, + resize(width: number, height: number) { + client.sendSize(width, height); + }, }; }