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:
parent
b8a99e6e9e
commit
af073e77ec
5 changed files with 134 additions and 19 deletions
|
|
@ -24,6 +24,13 @@ WEB_PORT=8080
|
||||||
# Optionales VNC-Passwort. Leer = ohne Passwort (nur für lokales Netz gedacht).
|
# Optionales VNC-Passwort. Leer = ohne Passwort (nur für lokales Netz gedacht).
|
||||||
VNC_PASSWORD=
|
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.
|
# noVNC-Pfad. Leer = Dashboard startet direkt im VNC-Viewer.
|
||||||
# Z.B. "vnc.html" für die standalone noVNC-Seite ohne Dashboard-Frame.
|
# Z.B. "vnc.html" für die standalone noVNC-Seite ohne Dashboard-Frame.
|
||||||
NOVNC_PATH=
|
NOVNC_PATH=
|
||||||
|
|
|
||||||
47
README.md
47
README.md
|
|
@ -111,6 +111,53 @@ Die konkrete Einrichtung hängt von deiner Farm ab. Typische Schritte:
|
||||||
| `DISPLAY_REFRESH` | `60` | Bildwiederholrate des virtuellen Displays. |
|
| `DISPLAY_REFRESH` | `60` | Bildwiederholrate des virtuellen Displays. |
|
||||||
| `WEB_PORT` | `8080` | Browser-Port. |
|
| `WEB_PORT` | `8080` | Browser-Port. |
|
||||||
| `VNC_PASSWORD` | *(leer)* | Optional. Leer = ohne Auth (nur lokales Netz!). |
|
| `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
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ services:
|
||||||
DISPLAY_REFRESH: ${DISPLAY_REFRESH:-60}
|
DISPLAY_REFRESH: ${DISPLAY_REFRESH:-60}
|
||||||
DISPLAY_DEPTH: ${DISPLAY_DEPTH:-24}
|
DISPLAY_DEPTH: ${DISPLAY_DEPTH:-24}
|
||||||
VNC_PASSWORD: ${VNC_PASSWORD:-}
|
VNC_PASSWORD: ${VNC_PASSWORD:-}
|
||||||
|
X11VNC_EXTRA: ${X11VNC_EXTRA:--threads -pointer_mode 4 -norepeat -nodpms -nofbpm -nowf -nowcr}
|
||||||
NOVNC_PATH: ${NOVNC_PATH:-}
|
NOVNC_PATH: ${NOVNC_PATH:-}
|
||||||
|
|
||||||
ports:
|
ports:
|
||||||
|
|
|
||||||
|
|
@ -65,9 +65,22 @@ else
|
||||||
VNC_PWFLAG="-nopw"
|
VNC_PWFLAG="-nopw"
|
||||||
fi
|
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
|
cat > /tmp/x11vnc.conf <<EOF
|
||||||
[program:x11vnc]
|
[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
|
priority=20
|
||||||
autostart=true
|
autostart=true
|
||||||
autorestart=true
|
autorestart=true
|
||||||
|
|
|
||||||
|
|
@ -16,18 +16,28 @@ const errorMsg = ref<string | null>(null)
|
||||||
const iframeEl = ref<HTMLIFrameElement | null>(null)
|
const iframeEl = ref<HTMLIFrameElement | null>(null)
|
||||||
const iframeKey = ref(0)
|
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 novncUrl = computed(() => {
|
||||||
const host = window.location.hostname
|
const host = window.location.hostname
|
||||||
const port = window.location.port || String(window.location.port)
|
const port = window.location.port
|
||||||
const params = new URLSearchParams({
|
const params = new URLSearchParams({
|
||||||
autoconnect: '1',
|
autoconnect: '1',
|
||||||
resize: 'scaling',
|
reconnect: '1',
|
||||||
// noVNC spricht relativ 'websockify' an → nginx mappt /websockify.
|
resize: 'remote',
|
||||||
path: 'websockify',
|
path: 'websockify',
|
||||||
// show_dot_cursor hilft beim Zielen im VNC-Fenster.
|
|
||||||
show_dot: '1',
|
show_dot: '1',
|
||||||
// host/port für die Anzeige im noVNC-eigenen UI; iframe nutzt aber path.
|
view_only: '0',
|
||||||
|
clipboard: '1',
|
||||||
host,
|
host,
|
||||||
port,
|
port,
|
||||||
})
|
})
|
||||||
|
|
@ -47,6 +57,20 @@ function onIframeLoad() {
|
||||||
state.value = 'connected'
|
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(() => {
|
onMounted(() => {
|
||||||
state.value = 'connecting'
|
state.value = 'connecting'
|
||||||
})
|
})
|
||||||
|
|
@ -54,6 +78,7 @@ onMounted(() => {
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="vnc">
|
<div class="vnc">
|
||||||
|
<div class="vnc__stage" @click="focusFrame">
|
||||||
<iframe
|
<iframe
|
||||||
ref="iframeEl"
|
ref="iframeEl"
|
||||||
:key="iframeKey"
|
:key="iframeKey"
|
||||||
|
|
@ -63,6 +88,7 @@ onMounted(() => {
|
||||||
allow="clipboard-read; clipboard-write; fullscreen"
|
allow="clipboard-read; clipboard-write; fullscreen"
|
||||||
@load="onIframeLoad"
|
@load="onIframeLoad"
|
||||||
></iframe>
|
></iframe>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div v-if="state !== 'connected'" class="vnc__overlay">
|
<div v-if="state !== 'connected'" class="vnc__overlay">
|
||||||
<div class="vnc__overlay-inner">
|
<div class="vnc__overlay-inner">
|
||||||
|
|
@ -91,9 +117,11 @@ onMounted(() => {
|
||||||
}}
|
}}
|
||||||
</span>
|
</span>
|
||||||
<span class="vnc__hint">
|
<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>
|
</span>
|
||||||
<button @click="reload">Aktualisieren</button>
|
<button @click="focusFrame" :disabled="state !== 'connected'">Fokus</button>
|
||||||
|
<button @click="reload" :disabled="state === 'connecting'">Aktualisieren</button>
|
||||||
<button
|
<button
|
||||||
@click="iframeEl?.requestFullscreen()"
|
@click="iframeEl?.requestFullscreen()"
|
||||||
:disabled="state !== 'connected'"
|
:disabled="state !== 'connected'"
|
||||||
|
|
@ -113,10 +141,18 @@ onMounted(() => {
|
||||||
background: #000;
|
background: #000;
|
||||||
}
|
}
|
||||||
|
|
||||||
.vnc__frame {
|
.vnc__stage {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
|
position: relative;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vnc__frame {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
border: 0;
|
border: 0;
|
||||||
background: #000;
|
background: #000;
|
||||||
}
|
}
|
||||||
|
|
@ -165,6 +201,17 @@ onMounted(() => {
|
||||||
color: var(--text-dim);
|
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 {
|
.vnc__badge.connected {
|
||||||
background: var(--accent);
|
background: var(--accent);
|
||||||
color: #0f1115;
|
color: #0f1115;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue