fix: Fixed mouse position on console
Server Deploy / deploy (push) Successful in 39s

This commit is contained in:
2026-07-20 09:36:57 +01:00
parent a02747d02e
commit 963fa9c877
2 changed files with 46 additions and 10 deletions
+23 -4
View File
@@ -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
View File
@@ -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);
},
};
}