Files
FocusFix/README.md
T
2026-04-18 16:10:59 +02:00

16 KiB

FocusFix - Game Foreground Fix for Windows

Windows-Hilfsprogramm, das ein Spielfenster automatisch in den Vordergrund bringt. Gedacht für Spiele, die nach dem Start im Hintergrund landen oder von Steam, Taskleiste, Splashscreens oder Overlay-Fenstern verdeckt werden. Funktioniert mit Steam (direkt über %command%) und Sunshine/Moonlight (manueller Prozessname).


Inhaltsverzeichnis


Problembeschreibung

Beim Start eines Spiels über Steam oder Sunshine/Moonlight öffnet sich das Spielfenster im Hintergrund. Die Steam-Oberfläche, die Windows-Taskleiste oder andere Fenster verdecken es, und der Spieler muss manuell per Alt+Tab wechseln.

Ursache: Windows vergibt den Vordergrundfokus nur eingeschränkt an Prozesse, die das System als berechtigt ansieht. Zusätzlich erzeugen manche Spiele beim Start mehrere Fenster wie Splashscreens, Launcher oder titellose Overlay-Fenster, die den Fokus stören können.

Lösungsansatz

focusfix.py kann in zwei Modi arbeiten:

  1. Steam-Wrapper-Modus: Das Script erhält %command%, leitet daraus den Prozessnamen ab, startet das Spiel selbst und überwacht anschließend den Fensterfokus.
  2. Direktmodus: Das Script wird mit --process Name gestartet und überwacht einen bekannten Spielprozess.

Das Tool ist nicht auf ein bestimmtes Spiel festgelegt, sondern für viele ähnliche Fokus-Probleme mit vergleichbarem Fensterverhalten gedacht.

Architektur

Steam Launch Options / Sunshine Befehlsvorbereitung
        │
        ▼
   ┌────────────────────┐
   │ pythonw.exe        │
   │ focusfix.py        │
   │                    │
   │ Steam: %command%   │
   │ Sunshine:          │
   │ --process Name     │
   └────────┬───────────┘
            │
   Steam-Modus:
   startet das Spiel selbst
            │
   Prozess/Fenster gefunden
            │
   ┌────────▼───────────┐
   │ 1. Prozess finden  │
   │ 2. Fenster erkennen│
   │ 3. Größe abwarten  │
   │ 4. Spiel fokussieren│
   │ 5. Wechsel beobachten│
   │ 6. Script beendet  │
   └────────────────────┘

Zwei Dateien, davon eine nur noch optional:

Datei Sprache Aufgabe
focusfix.py Python 3 Steam-Wrapper-Modus, Direktmodus per --process, Prozess-Monitoring, Fenstererkennung, Fensterwechsel-Erkennung, Fokus-Erzwingung, Logging
launch.vbs VBScript Legacy-Wrapper für ältere Steam-Konfigurationen; für den aktuellen Ablauf nicht mehr erforderlich

Voraussetzungen

Komponente Version Hinweis
Windows 10 / 11 Benötigt Win32 API (user32.dll)
Python 3.10+ py Launcher muss verfügbar sein
pip-Pakete psutil, pywin32 Werden im .venv installiert
Steam Beliebig Startoptionen müssen konfigurierbar sein

Installation

cd C:\Path\To\FocusFix

# Virtual Environment erstellen
py -m venv .venv

# Aktivieren
.venv\Scripts\activate

# Abhängigkeiten installieren
pip install psutil pywin32

Dateistruktur nach Installation

C:\Path\To\FocusFix\
├── .venv\                  # Python Virtual Environment
├── focusfix.py             # Hauptscript
├── focusfix.log            # Logdatei (wird automatisch erstellt)
├── launch.vbs              # Legacy-Wrapper, optional
├── CLAUDE.md               # Kontext für Claude Code
└── README.md               # Diese Dokumentation

Konfiguration

Steam

  1. Steam öffnen → Bibliothek
  2. Rechtsklick auf das Spiel → Eigenschaften
  3. Unter Allgemein → Startoptionen eine der folgenden Varianten eintragen:

Variante A — Empfohlen: direkt mit focusfix.py

"C:\Path\To\FocusFix\.venv\Scripts\pythonw.exe" "C:\Path\To\FocusFix\focusfix.py" %command%

focusfix.py extrahiert den Prozessnamen automatisch aus %command%, startet das eigentliche Spiel und überwacht danach den Fensterfokus. Die gleiche Startoption kann für beliebige Steam-Spiele mit vergleichbarem Fokus-Problem verwendet werden. Die Pfade im Beispiel sind Platzhalter und müssen durch deinen tatsächlichen Installationspfad ersetzt werden.

Erklärung:

  • pythonw.exe — startet Python ohne Konsolenfenster
  • "...\focusfix.py" — Python-Script im Steam-Wrapper-Modus
  • %command% — Steam-Platzhalter, wird zur Laufzeit durch den vollständigen Pfad zur Spiel-Executable ersetzt, z.B. "C:\SteamLibrary\...\Game.exe"

Variante B — Legacy: über launch.vbs

Wenn du den alten VBScript-Wrapper weiterhin verwenden willst, kannst du in Steam Folgendes eintragen:

wscript "C:\Path\To\FocusFix\launch.vbs" %command%

launch.vbs extrahiert den Prozessnamen aus %command%, startet focusfix.py unsichtbar mit --process und startet danach das eigentliche Spiel. Diese Variante funktioniert weiterhin, ist aber nur noch als Legacy-/Fallback-Weg gedacht, weil focusfix.py den Wrapper-Job inzwischen selbst übernehmen kann. Die Pfade im Beispiel sind Platzhalter und müssen durch deinen tatsächlichen Installationspfad ersetzt werden.

Erklärung:

  • wscript — startet VBScript ohne sichtbares Konsolenfenster
  • "...\launch.vbs" — Legacy-Wrapper, der focusfix.py indirekt startet
  • %command% — Steam-Platzhalter mit dem ursprünglichen Spielstartbefehl

Variante C — Release-Exe

Wenn du eine gebaute Release-Datei verwenden willst, kannst du statt Python direkt die .exe in Steam eintragen. In diesem Repository liegt aktuell eine Build-Datei unter dist\nuinstall\FocusFix.exe:

"C:\Path\To\FocusFix\dist\nuinstall\FocusFix.exe" %command%

Die .exe übernimmt denselben Wrapper-Modus wie focusfix.py: Sie erhält %command%, startet das Spiel und überwacht danach den Fokus. Diese Variante ist praktisch, wenn du keine sichtbare Python-Installation oder kein venv in den Steam-Startoptionen referenzieren willst.

Wichtig: Der Dateiname der Release-Exe hängt vom Build ab. Wenn du später eine neu benannte Exe wie FocusFix.exe baust, muss genau dieser Pfad in Steam eingetragen werden. Auch hier sind die Pfade im Beispiel Platzhalter und müssen durch deinen tatsächlichen Installationspfad ersetzt werden.

Sunshine / Moonlight

In Sunshine als Befehlsvorbereitung (Command Preparation) pro Spiel eintragen:

"C:\Path\To\FocusFix\.venv\Scripts\pythonw.exe" "C:\Path\To\FocusFix\focusfix.py" --process "Prozessname"

Den Prozessnamen im Task-Manager ablesen, ohne .exe. Beispiele:

Spiel Prozessname
Crimson Desert CrimsonDesert
Wuthering Waves Client-Win64-Shipping

Wichtig: Der vollständige Pfad zu pythonw.exe im .venv ist nötig, damit die Abhängigkeiten (psutil, pywin32) gefunden werden. py oder python nutzt sonst möglicherweise eine andere Python-Installation.

Ablauf zur Laufzeit

Zeitachse
─────────────────────────────────────────────────────────────────────
t=0s    Steam startet das Script mit %command%
        oder Sunshine mit --process "GameName"

t=0.1s  focusfix.py beginnt zu arbeiten
        → Steam-Modus: startet zuerst das Spiel und leitet den Prozessnamen ab
        → Danach: sucht nach Prozess "GameName"

t=~3s   Spielprozess gestartet, ggf. Splashscreen erscheint
        → Script findet den Prozess (PID)
        → Sucht nach Fenster mit Breite >= 800px
        → Kleine Splashscreens werden ignoriert

t=~10s  Hauptfenster des Spiels erscheint
        → Script findet das Fenster
        → Bevorzugt Fenster mit Titel
        → Wartet 3 Sekunden
        → Wartet bis Fenstergröße stabil ist

t=~13s  Phase 3: Fokus-Erzwingung
        → Spielfenster wird in den Vordergrund gebracht
        → Bei Misserfolg: bis zu 15 Wiederholungen mit je 2s Pause
        → Beobachtet Fensterwechsel (z.B. Splash → Hauptfenster)
        → Ignoriert problematische titellose Overlay-Fenster

t=~15s  Erfolg → focusfix.py beendet sich
        → Logdatei enthält den vollständigen Ablauf

Dateireferenz

focusfix.py

Funktionsübersicht

Funktion Beschreibung
derive_process_name(command) Leitet den Prozessnamen aus dem ersten Element eines Spielbefehls ab
launch_game(command) Startet das eigentliche Spiel im Steam-Wrapper-Modus
find_process_pids(name) Sucht laufende Prozesse nach Name (Teilstring, case-insensitiv), gibt PIDs zurück
find_game_window(pids) Findet das Hauptfenster der gegebenen PIDs, bevorzugt Fenster mit Titel und dann nach Größe
wait_for_stable_size(hwnd) Wartet bis die Fenstergröße sich stabilisiert hat
is_foreground(hwnd) Prüft ob ein Fenster aktuell im Vordergrund ist
bring_to_front(hwnd) Erzwingt den Vordergrundfokus für ein Fenster
main() Orchestriert Startmodus, Prozesssuche, Fenstersuche und Fokus-Erzwingung

main() — Ablauf

  1. Startphase: Entweder wird der Prozessname direkt über --process übergeben oder im Steam-Modus aus dem Spielbefehl abgeleitet.
  2. Steam-Wrapper-Modus: Falls ein Spielbefehl übergeben wurde, startet das Script das Spiel selbst.
  3. Phase 1 — Prozess-Suche: Pollt alle 0,5 Sekunden nach dem Prozessnamen. Bricht nach --timeout Sekunden ab.
  4. Phase 2 — Fenster-Suche: Pollt alle 0,5 Sekunden nach einem sichtbaren Fenster mit ausreichender Größe. Nach Fund: 3 Sekunden Wartezeit für die vollständige Initialisierung.
  5. Phase 3 — Fokus mit Fensterwechsel-Erkennung: Bis zu 15 Versuche den Spielfokus zu erzwingen, mit je 2 Sekunden Pause. Beobachtet dabei, ob sich das Fenster ändert und fokussiert das neue Fenster erneut.

launch.vbs

launch.vbs ist nur noch ein Legacy-Wrapper. Die aktuelle empfohlene Steam-Konfiguration nutzt focusfix.py direkt. Die Datei kann als Fallback im Repository bleiben, wird für den normalen Ablauf aber nicht mehr benötigt.

Konfigurationsparameter

Kommandozeilenargumente

Argument Pflicht Standard Beschreibung
--process Nein — Teilstring des Prozessnamens (case-insensitiv, ohne .exe)
--timeout Nein 120 Maximale Wartezeit in Sekunden für Prozess- und Fensterfund
command Nein — Steam-Spielbefehl, z.B. %command%; startet das Spiel und leitet den Prozessnamen automatisch ab

Es muss entweder --process oder ein Spielbefehl übergeben werden.

Konstanten in focusfix.py

Konstante Wert Beschreibung
MIN_WINDOW_WIDTH 800 Mindestbreite in Pixeln, um Splashscreens auszufiltern
FOCUS_RETRIES 15 Maximale Anzahl der Fokus-Versuche
FOCUS_RETRY_DELAY 2.0 Sekunden zwischen Fokus-Versuchen

Relevante Pfade

Pfad Zweck
C:\Path\To\FocusFix\.venv\Scripts\pythonw.exe Beispielpfad zum Python-Interpreter ohne Konsolenfenster, für Steam empfohlen
C:\Path\To\FocusFix\focusfix.py Beispielpfad zum Hauptscript

Bei einer Änderung des Installationsverzeichnisses müssen diese Pfade in den Steam-Startoptionen oder in Sunshine angepasst werden.

Windows API — Technischer Hintergrund

Das SetForegroundWindow-Problem

Seit Windows 2000 verhindert das Betriebssystem, dass beliebige Prozesse den Vordergrundfokus "stehlen" können. SetForegroundWindow(hwnd) funktioniert nur eingeschränkt. Andernfalls blinkt das Fenster lediglich in der Taskleiste.

Da focusfix.py als eigenständiger Prozess läuft und nicht Teil der normalen Spiel-UI ist, erfüllt es diese Bedingungen oft nicht direkt.

Workaround-Strategie

Das Script kombiniert drei Techniken:

1. Alt-Key-Simulation (keybd_event)

Simuliert einen Tastendruck der Alt-Taste. Windows behandelt den aufrufenden Prozess danach eher wie einen Prozess mit Benutzerinteraktion.

2. Thread-Input-Verbindung (AttachThreadInput)

Verbindet die Eingabewarteschlangen zweier Threads. Dadurch kann das Ziel-Fenster zuverlässiger in den Vordergrund gebracht werden.

3. Mehrfache Fokus-Befehle

ShowWindow, BringWindowToTop, SetForegroundWindow, SetFocus und SetActiveWindow adressieren jeweils einen leicht anderen Aspekt des Fenster-Fokus unter Windows.

Splashscreen-Erkennung

Viele Spiele zeigen beim Start einen Splashscreen, bevor das Hauptfenster erscheint. Beide gehören zum selben Prozess.

Das wichtigste Unterscheidungsmerkmal ist hier die Fenstergröße. Kleine Startfenster werden über MIN_WINDOW_WIDTH = 800 aussortiert. Zusätzlich werden Fenster mit Titel bevorzugt, um titellose Overlay-Fenster nicht fälschlich als Hauptfenster zu wählen.

Manuelles Testen

Direktmodus testen

cd C:\Path\To\FocusFix
.venv\Scripts\python focusfix.py --process "CrimsonDesert" --timeout 5

Steam-Wrapper-Modus testen

.venv\Scripts\python focusfix.py "C:\Path\To\Game\TestGame.exe"

Die Laufzeit-Logs landen in focusfix.log. Bei Ausführung über pythonw.exe gibt es keine sichtbare Ausgabe. Bei manuellen Starts mit python.exe können Argument- oder Interpreter-Fehler weiterhin in der Konsole erscheinen.

Gesamtablauf testen

  1. Steam-Startoptionen wie oben konfigurieren.
  2. Spiel über Steam starten.
  3. Erwartung: Spielfenster erscheint nach dem Ladescreen im Vordergrund, ohne zusätzliches Konsolenfenster.
  4. focusfix.log prüfen.

Debugging

Alle Informationen werden in focusfix.log protokolliert:

  • Gefundene Kandidaten-Fenster mit Handle, Titel, Größe und PID
  • Fensterwechsel und ignorierte titellose Fenster
  • Fokus-Versuche mit Ergebnis
  • Fehler mit Traceback

Häufige Probleme

Symptom Ursache Lösung
Spiel startet nicht Steam-Startoptionen fehlerhaft Prüfen ob %command% am Ende steht und pythonw.exe/focusfix.py korrekt referenziert werden
ModuleNotFoundError: psutil Falsche Python-Installation Vollständigen Pfad zu .venv\Scripts\pythonw.exe verwenden
Script findet Prozess nicht Prozessname stimmt nicht oder Launcher-Kette ist ungewöhnlich Mit --process testen oder Log prüfen
Fenster wird nicht fokussiert Windows-Restriktion zu streng Retry-Anzahl/Delay in Konstanten erhöhen
Alt-Taste bleibt hängen Spiel mit Admin-Rechten, Script ohne Script ebenfalls als Admin starten
CMD-Fenster sichtbar python.exe statt pythonw.exe Steam-/Sunshine-Konfiguration prüfen
Verdunkeltes/blockiertes Spiel Titelloses Overlay-Fenster Log prüfen; sollte meist durch Fenster-mit-Titel-Bevorzugung abgefangen werden

Fenster-Inspektion per PowerShell

Get-Process -Name GameName | Select-Object Id, Name, MainWindowTitle, MainWindowHandle

Bekannte Einschränkungen

  • Kein Admin erforderlich, aber manche Spiele starten mit erhöhten Rechten. Dann muss das Script ebenfalls als Admin laufen.
  • Exklusiver Vollbildmodus: Spiele im exklusiven Vollbild können sich anders verhalten.
  • Anti-Cheat: Manche Anti-Cheat-Systeme könnten Eingabesimulation oder Fokus-Workarounds blockieren.
  • Mehrere Monitore: find_game_window wählt das Fenster unabhängig vom Monitor.
  • Nicht universell für jedes Spiel: Das Tool ist generisch für viele ähnliche Fälle, aber nicht garantiert für jeden Launcher, jedes Anti-Cheat-System oder jedes ungewöhnliche Fenster-/Startverhalten.