VNC-Steuerung verbessern: Low-Latency, Maus, Tastatur, Resize

Die Steuerung ist jetzt auf Minecraft (Menü, Chat, Inventar, AFK-Farmen)
optimiert. Für Mouselook/PVP bleibt VNC ungeeignet (Protokollgrenze,
dokumentiert).

x11vnc (serverseitig, entrypoint.sh):
- -threads: parallele I/O-Threads → weniger Eingabe-Lag
- -pointer_mode 4: flüssigere Mausübertragung (Default 1 ist träge)
- -norepeat: verhindert doppelte Tastaturwiederholungen im Spiel
- -nodpms -nofbpm -nowf -nowcr: Energiesparen/Rate-Limiting aus
- Über X11VNC_EXTRA env var frei konfigurierbar

noVNC-Client (VncViewer.vue):
- resize=remote statt scaling: Xvfb folgt Fenstergröße (1:1-Maus-Mapung)
- reconnect=1: auto-Reconnect bei Abbruch
- clipboard=1: Zwischenablage Browser <-> Container
- view_only=0: Eingabe explizit freigeschaltet
- Klick ins Bild setzt Tastaturfokus ins iframe
- Hinweis auf Mausfreigabe (Strg+Alt+Umschalt), Fokus-Button

README: neuer Abschnitt "Steuerung über VNC" mit Grenzerklärung.
.env.example + docker-compose.yml: X11VNC_EXTRA durchgereicht.
This commit is contained in:
Tronax 2026-08-09 11:09:35 +02:00
parent b8a99e6e9e
commit af073e77ec
Signed by: Tronax
SSH key fingerprint: SHA256:2pKKXDZucWvaF/GzXNz0FY53EAO1YDLN80bqS+TTz/o
5 changed files with 134 additions and 19 deletions

View file

@ -24,6 +24,13 @@ WEB_PORT=8080
# Optionales VNC-Passwort. Leer = ohne Passwort (nur für lokales Netz gedacht).
VNC_PASSWORD=
# Zusätzliche x11vnc-Flags für die Low-Latency-/Eingabe-Optimierung.
# Defaults sind auf Minecraft (Menü, Chat, Inventar, AFK-Farmen) abgestimmt:
# -threads -pointer_mode 4 -norepeat -nodpms -nofbpm -nowf -nowcr
# Für langsames Netz z.B. Kompression dazuschalten:
# -threads -pointer_mode 4 -norepeat -tight -compresslevel 6 -quality 7
X11VNC_EXTRA=
# noVNC-Pfad. Leer = Dashboard startet direkt im VNC-Viewer.
# Z.B. "vnc.html" für die standalone noVNC-Seite ohne Dashboard-Frame.
NOVNC_PATH=

View file

@ -111,6 +111,53 @@ Die konkrete Einrichtung hängt von deiner Farm ab. Typische Schritte:
| `DISPLAY_REFRESH` | `60` | Bildwiederholrate des virtuellen Displays. |
| `WEB_PORT` | `8080` | Browser-Port. |
| `VNC_PASSWORD` | *(leer)* | Optional. Leer = ohne Auth (nur lokales Netz!). |
| `X11VNC_EXTRA` | siehe `.env` | Low-Latency-/Eingabe-Flags für x11vnc. |
---
## Steuerung über VNC
Die Steuerung ist auf **Minecraft-Menü, Chat, Inventar und AFK-Farmen**
optimiert. Sie ist **nicht** für aktives PVP/Mouselook gedacht — das ist eine
grundsätzliche Grenze von VNC (siehe unten).
**Bedienung im Browser:**
- **Klick ins Bild** → setzt den Tastaturfokus ins Spielfenster (Tasten gehen
ans Spiel, nicht an den Browser).
- **Maus freigeben**`Strg + Alt + Umschalt` (noVNC-Standard).
- **Vollbild** → Button in der Toolbar; für Minecraft flächendeckend.
- **Zwischenablage** → automatisch verknüpft (Login-Codes / Server-IPs kopieren
geht direkt zwischen Browser und Container).
**Was automatisch eingestellt ist:**
- `resize=remote`: die Xvfb-Auflösung folgt der Fenstergröße (1:1-Maus-Mapung,
keine Skalierungs-Unschärfe).
- `reconnect=1`: bei Abbruch verbindet noVNC selbstständig neu.
- x11vnc mit `-threads -pointer_mode 4 -norepeat`:
- `-threads` → parallele I/O-Threads, weniger Eingabe-Lag.
- `-pointer_mode 4` → flüssigere Mausübertragung als der Default (1).
- `-norepeat` → verhindert doppelte Tastaturwiederholungen im Spiel.
- `-nodpms -nofbpm -nowf -nowcr` → Energiesparen und Rate-Limiting aus, damit
nichts nach Leerlauf ruckelt.
**Für langsames Netz** (z. B. Remote über Internet statt LAN) in der `.env`
Kompression aktivieren:
```
X11VNC_EXTRA=-threads -pointer_mode 4 -norepeat -tight -compresslevel 6 -quality 7
```
### Warum Mouselook nicht richtig geht
VNC überträgt **absolute** Mauskoordinaten („Cursor an Position X/Y"). Minecraft
wie jedes FPS-artige Spiel braucht aber **relative** Mausbewegung und setzt den
Cursor dafür jeden Frame auf die Bildmitte zurück ([noVNC Issue #1493][novnc1493]).
Darum lässt sich die Kamera per VNC nicht sinnfrei drehen.
Für Menü, Buttons, Chat, Inventar und reines AFK auf einer Farm ist das ohne
Bedeutung. Wer wirklich remote *spielen* will, braucht ein anderes Protokoll
(Sunshine/Moonlight statt VNC) — das ist mit dieser Architektur nicht abgedeckt.
[novnc1493]: https://github.com/novnc/noVNC/issues/1493
---

View file

@ -20,6 +20,7 @@ services:
DISPLAY_REFRESH: ${DISPLAY_REFRESH:-60}
DISPLAY_DEPTH: ${DISPLAY_DEPTH:-24}
VNC_PASSWORD: ${VNC_PASSWORD:-}
X11VNC_EXTRA: ${X11VNC_EXTRA:--threads -pointer_mode 4 -norepeat -nodpms -nofbpm -nowf -nowcr}
NOVNC_PATH: ${NOVNC_PATH:-}
ports:

View file

@ -65,9 +65,22 @@ else
VNC_PWFLAG="-nopw"
fi
# Low-Latency-x11vnc-Optionen. Für Minecraft sind vor allem wichtig:
# -threads parallele Eingabe-/Ausgabe-Threads → weniger Lag
# -pointer_mode 4 flüssigere Mausübertragung (Default 1 ist träge)
# -norepeat Server-seite Tastaturwiederholung unterdrücken (sonst
# doppelte Auto-Repeat-Tasten im Spiel)
# -nocursorshape / -cursor none kein Cursor-Shape-Traffic (Cursor ist eh
# vom Spiel übermalt); -cursorX aber als sichtbarer Fallback
# -nodpms -nofbpm Energiesparen aus (sonst ruckelt es nach Leerlauf)
# -nowf -nowcr kein Wireframe/Rate-Limit beim Fensterziehen
# -noxdamage-suffix stabilereDamage-Erfassung
# Encoding/Qualität werden vom Client (noVNC) ausgehandelt, nicht hier erzwungen.
X11VNC_EXTRA="${X11VNC_EXTRA:--threads -pointer_mode 4 -norepeat -nodpms -nofbpm -nowf -nowcr}"
cat > /tmp/x11vnc.conf <<EOF
[program:x11vnc]
command=/usr/bin/x11vnc -display :0 -forever -shared ${VNC_PWFLAG} -rfbport 5900
command=/usr/bin/x11vnc -display :0 -forever -shared ${VNC_PWFLAG} -rfbport 5900 ${X11VNC_EXTRA}
priority=20
autostart=true
autorestart=true

View file

@ -16,18 +16,28 @@ const errorMsg = ref<string | null>(null)
const iframeEl = ref<HTMLIFrameElement | null>(null)
const iframeKey = ref(0)
// noVNC-URL: autoconnect=1, resize=scaling, Pfad zum websockify.
// noVNC-URL mit auf Steuerung/Spiele optimierten Parametern:
// resize=remote passt die Xvfb-Auflösung an die Fenstergröße an
// (statt nur zu skalieren). Korrekte 1:1-Maus-Mapung,
// keine Unschärfe. Fällt auf 'scale' zurück, falls der
// Server kein Resize unterstützt.
// reconnect=1 bei Verbindungsabbruch automatisch neu verbinden.
// path=websockify noVNC spricht den WS-Endpunkt relativ an.
// show_dot=1 lokalen Punkt-Cursor zeigen (Zielhilfe).
// view_only=0 Eingabe explizit freischalten.
// clipboard=1 Zwischenablage zwischen Browser und VM verknüpfen
// (wichtig für Login-Codes / Server-IPs kopieren).
const novncUrl = computed(() => {
const host = window.location.hostname
const port = window.location.port || String(window.location.port)
const port = window.location.port
const params = new URLSearchParams({
autoconnect: '1',
resize: 'scaling',
// noVNC spricht relativ 'websockify' an nginx mappt /websockify.
reconnect: '1',
resize: 'remote',
path: 'websockify',
// show_dot_cursor hilft beim Zielen im VNC-Fenster.
show_dot: '1',
// host/port für die Anzeige im noVNC-eigenen UI; iframe nutzt aber path.
view_only: '0',
clipboard: '1',
host,
port,
})
@ -47,6 +57,20 @@ function onIframeLoad() {
state.value = 'connected'
}
// Fokus in den iframe setzen, damit Tastatureingaben ans Spiel gehen.
// noVNC selbst fängt die Keys im iframe ab; wir müssen nur dorthin fokussieren.
function focusFrame() {
const el = iframeEl.value
if (!el) return
// Versuch, das innere Dokument zu fokussieren (gleiche Origin erlaubt).
try {
el.contentWindow?.focus()
} catch {
/* Cross-Origin → iframe focus als Fallback */
el.focus()
}
}
onMounted(() => {
state.value = 'connecting'
})
@ -54,15 +78,17 @@ onMounted(() => {
<template>
<div class="vnc">
<iframe
ref="iframeEl"
:key="iframeKey"
class="vnc__frame"
:src="novncUrl"
title="Minecraft via noVNC"
allow="clipboard-read; clipboard-write; fullscreen"
@load="onIframeLoad"
></iframe>
<div class="vnc__stage" @click="focusFrame">
<iframe
ref="iframeEl"
:key="iframeKey"
class="vnc__frame"
:src="novncUrl"
title="Minecraft via noVNC"
allow="clipboard-read; clipboard-write; fullscreen"
@load="onIframeLoad"
></iframe>
</div>
<div v-if="state !== 'connected'" class="vnc__overlay">
<div class="vnc__overlay-inner">
@ -91,9 +117,11 @@ onMounted(() => {
}}
</span>
<span class="vnc__hint">
Maus im Fenster festhalten? Im noVNC-Seitenmenge Clip to Window.
Klick ins Bild für Tastatur-Fokus. Maus freigeben:
<kbd>Strg</kbd>+<kbd>Alt</kbd>+<kbd>Umschalt</kbd>
</span>
<button @click="reload">Aktualisieren</button>
<button @click="focusFrame" :disabled="state !== 'connected'">Fokus</button>
<button @click="reload" :disabled="state === 'connecting'">Aktualisieren</button>
<button
@click="iframeEl?.requestFullscreen()"
:disabled="state !== 'connected'"
@ -113,10 +141,18 @@ onMounted(() => {
background: #000;
}
.vnc__frame {
.vnc__stage {
flex: 1;
min-height: 0;
position: relative;
cursor: pointer;
}
.vnc__frame {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
border: 0;
background: #000;
}
@ -165,6 +201,17 @@ onMounted(() => {
color: var(--text-dim);
}
.vnc__hint kbd {
font-family: var(--mono);
background: var(--bg-elev-2);
border: 1px solid var(--border);
border-bottom-width: 2px;
border-radius: 4px;
padding: 1px 5px;
font-size: 10px;
color: var(--text);
}
.vnc__badge.connected {
background: var(--accent);
color: #0f1115;