This commit is contained in:
@@ -27,6 +27,8 @@ export default function ServerConsolePage() {
|
||||
const [connected, setConnected] = useState(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [pending, setPending] = useState<{ token: string; wsPath: string } | null>(null);
|
||||
const [zoom, setZoom] = useState(1);
|
||||
const dprRef = useRef(1);
|
||||
|
||||
// Inject the vendored Guacamole client script once.
|
||||
useEffect(() => {
|
||||
@@ -104,6 +106,7 @@ export default function ServerConsolePage() {
|
||||
const wsUrl = `${wsProto}://${location.host}${pending.wsPath}`;
|
||||
const rect = containerRef.current.getBoundingClientRect();
|
||||
const dpr = window.devicePixelRatio || 1;
|
||||
dprRef.current = dpr;
|
||||
// Request the remote at device-pixel resolution with a fixed 96 dpi, then
|
||||
// scale the display back down by dpr. Folding dpr into `dpi` instead makes
|
||||
// the remote enlarge everything, which reads as a zoomed-in view.
|
||||
@@ -114,12 +117,15 @@ export default function ServerConsolePage() {
|
||||
`&dpi=96`;
|
||||
|
||||
connectionRef.current = openConsole(containerRef.current, wsUrl, connectData);
|
||||
if (dpr !== 1) {
|
||||
connectionRef.current.setScale(1 / dpr);
|
||||
}
|
||||
connectionRef.current.setScale(zoom / dpr);
|
||||
setPending(null);
|
||||
}, [connected, pending]);
|
||||
|
||||
// Apply zoom changes live without reconnecting.
|
||||
useEffect(() => {
|
||||
connectionRef.current?.setScale(zoom / dprRef.current);
|
||||
}, [zoom]);
|
||||
|
||||
function handleDisconnect() {
|
||||
connectionRef.current?.disconnect();
|
||||
connectionRef.current = null;
|
||||
@@ -252,12 +258,25 @@ export default function ServerConsolePage() {
|
||||
<Button variant="danger" onClick={handleDisconnect}>
|
||||
Disconnect
|
||||
</Button>
|
||||
<label className="text-sm text-text-secondary">Scale</label>
|
||||
<select
|
||||
value={zoom}
|
||||
onChange={(e) => setZoom(Number(e.target.value))}
|
||||
className="rounded-lg border border-border bg-surface-2 px-3 py-2 text-sm text-text-primary focus:border-accent/50 focus:outline-none focus:ring-1 focus:ring-accent/30"
|
||||
>
|
||||
<option value={0.5}>50%</option>
|
||||
<option value={0.75}>75%</option>
|
||||
<option value={1}>100%</option>
|
||||
<option value={1.25}>125%</option>
|
||||
<option value={1.5}>150%</option>
|
||||
<option value={2}>200%</option>
|
||||
</select>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div
|
||||
ref={containerRef}
|
||||
className="min-h-[500px] flex-1 rounded-lg border border-border bg-black"
|
||||
className="min-h-[500px] flex-1 overflow-auto rounded-lg border border-border bg-black"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
+23
-6
@@ -17,10 +17,26 @@ export function openConsole(
|
||||
|
||||
client.connect(connectData);
|
||||
|
||||
// Wire keyboard + mouse.
|
||||
const mouse = new Guacamole.Mouse(client.getDisplay().getElement());
|
||||
mouse.onmousedown = mouse.onmouseup = mouse.onmousemove = (state: any) =>
|
||||
client.sendMouseState(state);
|
||||
const display = client.getDisplay();
|
||||
let scale = 1;
|
||||
|
||||
// Wire keyboard + mouse. The display element is rendered at `scale` of the
|
||||
// remote's native resolution, but Guacamole.Mouse reports coordinates in
|
||||
// element (on-screen) pixels. Divide by scale to map back to remote
|
||||
// coordinates, otherwise the cursor is offset.
|
||||
const mouse = new Guacamole.Mouse(display.getElement());
|
||||
mouse.onmousedown = mouse.onmouseup = mouse.onmousemove = (state: any) => {
|
||||
const s = new Guacamole.Mouse.State(
|
||||
state.x / scale,
|
||||
state.y / scale,
|
||||
state.left,
|
||||
state.middle,
|
||||
state.right,
|
||||
state.up,
|
||||
state.down
|
||||
);
|
||||
client.sendMouseState(s);
|
||||
};
|
||||
const keyboard = new Guacamole.Keyboard(document);
|
||||
keyboard.onkeydown = (k: number) => client.sendKeyEvent(1, k);
|
||||
keyboard.onkeyup = (k: number) => client.sendKeyEvent(0, k);
|
||||
@@ -29,8 +45,9 @@ export function openConsole(
|
||||
disconnect() {
|
||||
client.disconnect();
|
||||
},
|
||||
setScale(scale: number) {
|
||||
client.getDisplay().scale(scale);
|
||||
setScale(s: number) {
|
||||
scale = s;
|
||||
display.scale(s);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user