- Debug-Logging optional gemacht, den Legacy-Wrapper portabler aufgebaut (relative Pfade, Debug-Weitergabe, Python-Fallback) und die README für Endanwender und Entwickler klarer neu strukturiert.
FocusFix - Game Foreground Fix for Windows
Windows-Hilfsprogramm, das ein Spielfenster automatisch in den Vordergrund bringt. Gedacht für Spiele (z.b. Crimson Desert), 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
- Schnellstart
- Problembeschreibung
- Lösungsansatz
- Architektur
- Voraussetzungen
- Direkte Verwendung
- Aus Quellcode ausführen
- Konfiguration
- Ablauf zur Laufzeit
- Dateireferenz
- Konfigurationsparameter
- Windows API — Technischer Hintergrund
- Manuelles Testen
- Debugging
- Bekannte Einschränkungen
Schnellstart
Für Nutzer
Wenn du FocusFix direkt verwenden willst, ist eine fertige FocusFix.exe der empfohlene Weg. Du brauchst dann weder ein Virtual Environment noch ein manuelles pip install.
Steam-Beispiel:
"C:\Path\To\FocusFix\FocusFix.exe" %command%
Mit Debug-Logging:
"C:\Path\To\FocusFix\FocusFix.exe" -debug %command%
Für Entwickler
Wenn du FocusFix aus dem Repository starten oder weiterentwickeln willst:
cd C:\Path\To\FocusFix
py -m pip install -r requirements.txt
Danach kannst du focusfix.py direkt mit deinem Python-Interpreter oder über pythonw.exe verwenden.
Steam-Beispiel für die Quellcode-Nutzung mit lokalem .venv:
"C:\Projekte\FocusFix\.venv\Scripts\pythonw.exe" "C:\Projekte\FocusFix\focusfix.py" %command%
Ohne lokales .venv und mit globalem Python im PATH:
"pythonw.exe" "C:\Projekte\FocusFix\focusfix.py" %command%
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:
- Steam-Wrapper-Modus: Das Script erhält
%command%, leitet daraus den Prozessnamen ab, startet das Spiel selbst und überwacht anschließend den Fensterfokus. - Direktmodus: Das Script wird mit
--process Namegestartet 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) |
| Steam | Beliebig | Startoptionen müssen konfigurierbar sein |
| Python | 3.10+ | Nur für Quellcode-Nutzung erforderlich |
| pip-Pakete | psutil, pywin32 |
Nur für Quellcode-Nutzung erforderlich |
Direkte Verwendung
Für normale Nutzer ist eine fertige .exe der einfachste Weg.
Aus Quellcode ausführen
cd C:\Path\To\FocusFix
py -m pip install -r requirements.txt
Optional kannst du dafür auch ein Virtual Environment verwenden. Für Entwickler ist das sinnvoll, für Endanwender aber nicht der Standardweg.
Dateistruktur im Repository
C:\Path\To\FocusFix\
├── focusfix.py # Hauptscript
├── focusfix.log # Logdatei (nur bei --debug / -debug)
├── launch.vbs # Legacy-Wrapper, optional
├── requirements.txt # Python-Abhängigkeiten für Quellcode-Nutzung
├── CLAUDE.md # Kontext für Claude Code
└── README.md # Diese Dokumentation
Konfiguration
Steam
- Steam öffnen → Bibliothek
- Rechtsklick auf das Spiel → Eigenschaften
- Unter Allgemein → Startoptionen eine der folgenden Varianten eintragen:
Variante A — Empfohlen für Nutzer: FocusFix.exe
"C:\Path\To\FocusFix\FocusFix.exe" %command%
Mit Debug-Logging:
"C:\Path\To\FocusFix\FocusFix.exe" -debug %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 für Endanwender gedacht.
Die Pfade im Beispiel sind Platzhalter und müssen durch deinen tatsächlichen Installationspfad ersetzt werden.
Variante B — Quellcode direkt mit focusfix.py
"C:\Path\To\Python\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 C — 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%
Beispiel: "C:\Projekte\FocusFix\launch.vbs" %command%
Mit Debug-Logging:
wscript "C:\Path\To\FocusFix\launch.vbs" -debug %command%
wscript "C:\Projekte\FocusFix\launch.vbs" -debug %command%
launch.vbs extrahiert den Prozessnamen aus %command%, startet focusfix.py unsichtbar mit --process und startet danach das eigentliche Spiel. -d, -debug und --debug werden an focusfix.py weitergereicht und nicht an das Spiel übergeben. Diese Variante funktioniert weiterhin, ist aber nur noch als Legacy-/Fallback-Weg gedacht, weil focusfix.py den Wrapper-Job inzwischen selbst übernehmen kann.
Der Wrapper erwartet focusfix.py relativ zu seinem eigenen Speicherort. Für Python nutzt er zuerst .venv\Scripts\pythonw.exe im selben Ordner und fällt, falls nicht vorhanden, auf pythonw.exe aus der globalen Installation beziehungsweise dem PATH zurück.
Erklärung:
wscript— startet VBScript ohne sichtbares Konsolenfenster"...\launch.vbs"— Legacy-Wrapper, derfocusfix.pyindirekt startet-debug— optional, aktiviertfocusfix.logfürfocusfix.py%command%— Steam-Platzhalter mit dem ursprünglichen Spielstartbefehl
Sunshine / Moonlight
Für Nutzer mit .exe:
"C:\Path\To\FocusFix\FocusFix.exe" --process "Prozessname"
Mit Debug-Logging:
"C:\Path\To\FocusFix\FocusFix.exe" --debug --process "Prozessname"
Für Quellcode-Nutzung in Sunshine als Befehlsvorbereitung (Command Preparation) pro Spiel:
"C:\Path\To\Python\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: Wenn du den Quellcode-Weg nutzt, muss der verwendete Python-Interpreter Zugriff auf die installierten Abhängigkeiten aus requirements.txt haben. pythonw.exe ist für unsichtbare Hintergrundausführung sinnvoller als python.exe.
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
- Startphase: Entweder wird der Prozessname direkt über
--processübergeben oder im Steam-Modus aus dem Spielbefehl abgeleitet. - Steam-Wrapper-Modus: Falls ein Spielbefehl übergeben wurde, startet das Script das Spiel selbst.
- Phase 1 — Prozess-Suche: Pollt alle 0,5 Sekunden nach dem Prozessnamen. Bricht nach
--timeoutSekunden ab. - 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.
- 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 Nutzung für Endanwender erfolgt über FocusFix.exe. Die Datei kann als Fallback im Repository bleiben, wird für den normalen Ablauf aber nicht mehr benötigt. Der Wrapper löst focusfix.py relativ zu seinem eigenen Ordner auf, verwendet bevorzugt .venv\Scripts\pythonw.exe daneben und fällt sonst auf pythonw.exe aus der globalen Python-Installation beziehungsweise dem PATH zurück. -d/-debug/--debug kann er an focusfix.py weitergeben.
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\FocusFix.exe |
Empfohlener Pfad für Endanwender |
C:\Path\To\Python\pythonw.exe |
Beispielpfad zum Python-Interpreter ohne Konsolenfenster, für Quellcode-Nutzung |
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
python focusfix.py --process "CrimsonDesert" --timeout 5
Steam-Wrapper-Modus testen
python focusfix.py "C:\Path\To\Game\TestGame.exe"
Standardmäßig erzeugt FocusFix keine Logdatei. Mit --debug oder -debug landen die Laufzeit-Logs in focusfix.log; bei jedem neuen Scriptstart wird die Datei dabei überschrieben. 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
- Steam-Startoptionen wie oben konfigurieren.
- Spiel über Steam starten.
- Erwartung: Spielfenster erscheint nach dem Ladescreen im Vordergrund, ohne zusätzliches Konsolenfenster.
- Falls mit
--debuggestartet wurde,focusfix.logprüfen.
Debugging
Für die Fehlersuche FocusFix mit --debug oder -debug starten. Dann werden alle Informationen in focusfix.log protokolliert; ein vorhandenes Logfile aus einem früheren Lauf wird dabei ersetzt:
- 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 .exe oder pythonw.exe/focusfix.py korrekt referenziert werden |
ModuleNotFoundError: psutil |
Falsche Python-Installation | py -m pip install -r requirements.txt ausführen oder den richtigen Python-Interpreter 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 oder .exe verwenden |
| 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_windowwä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.