mirror of
https://github.com/Andre-Bzk/FocusFix.git
synced 2026-11-15 15:43:12 +01:00
Feature: Wrapper, Logging und Doku überarbeitet
- 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.
This commit is contained in:
@@ -8,42 +8,78 @@ FocusFix is a Windows utility that forces a game window into the foreground afte
|
|||||||
|
|
||||||
## Architecture
|
## Architecture
|
||||||
|
|
||||||
- **`focusfix.py`** — Python script that supports two modes: `--process Name` for monitoring an already-known process, or direct Steam wrapper mode where `%command%` is passed as positional arguments. In wrapper mode it derives the process name from the target executable, launches the game itself, then polls for the game process, waits for its main window (filtered by size to skip splash screens, preferring windows with titles over titleless overlays), waits for the window size to stabilize, then brings the game window to foreground using Win32 API workarounds (`AttachThreadInput` + `Alt` key simulation to bypass `SetForegroundWindow` restrictions). Monitors for window changes (splash → main window) and re-focuses automatically. Retries up to 15 times. Runtime logging goes to `focusfix.log`.
|
- **`focusfix.py`** — Python script that supports two modes: `--process Name` for monitoring an already-known process, or direct Steam wrapper mode where `%command%` is passed as positional arguments. In wrapper mode it derives the process name from the target executable, launches the game itself, then polls for the game process, waits for its main window (filtered by size to skip splash screens, preferring windows with titles over titleless overlays), waits for the window size to stabilize, then brings the game window to foreground using Win32 API workarounds (`AttachThreadInput` + `Alt` key simulation to bypass `SetForegroundWindow` restrictions). Monitors for window changes (splash → main window) and re-focuses automatically. Retries up to 15 times. Debug logging is only enabled explicitly with `--debug`/`-debug`, writes to `focusfix.log`, and overwrites the file on each new script start.
|
||||||
- **`launch.vbs`** — Legacy Steam wrapper. No longer required for normal usage, but still present in the repository.
|
- **`launch.vbs`** — Legacy Steam wrapper. Still supported as a fallback, but not the primary user path anymore. It resolves `focusfix.py` relative to its own location, prefers a sibling `.venv\Scripts\pythonw.exe`, falls back to `pythonw.exe` from `PATH`, and forwards `-d`/`-debug`/`--debug` to `focusfix.py` without passing those flags to the game.
|
||||||
|
- **`requirements.txt`** — Source-install dependencies for `focusfix.py` (`psutil`, `pywin32`).
|
||||||
|
|
||||||
## Setup
|
## Setup
|
||||||
|
|
||||||
|
```
|
||||||
|
py -m pip install -r requirements.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
Optional for development:
|
||||||
|
|
||||||
```
|
```
|
||||||
py -m venv .venv
|
py -m venv .venv
|
||||||
.venv\Scripts\activate
|
.venv\Scripts\activate
|
||||||
pip install psutil pywin32
|
pip install -r requirements.txt
|
||||||
```
|
```
|
||||||
|
|
||||||
## Steam Launch Options
|
## Steam Launch Options
|
||||||
|
|
||||||
|
Preferred for end users:
|
||||||
|
|
||||||
```
|
```
|
||||||
"C:\Projekte\Steam_backgroud_fix\.venv\Scripts\pythonw.exe" "C:\Projekte\Steam_backgroud_fix\focusfix.py" %command%
|
"C:\Path\To\FocusFix\FocusFix.exe" %command%
|
||||||
```
|
```
|
||||||
|
|
||||||
Same launch option works for all Steam games with similar foreground/focus issues — the process name is extracted automatically.
|
Direct Python/script usage:
|
||||||
|
|
||||||
|
```
|
||||||
|
"C:\Path\To\Python\pythonw.exe" "C:\Path\To\FocusFix\focusfix.py" %command%
|
||||||
|
```
|
||||||
|
|
||||||
|
Legacy wrapper fallback:
|
||||||
|
|
||||||
|
```
|
||||||
|
wscript "C:\Path\To\FocusFix\launch.vbs" %command%
|
||||||
|
wscript "C:\Path\To\FocusFix\launch.vbs" -debug %command%
|
||||||
|
```
|
||||||
|
|
||||||
|
All Steam variants above work generically across games with similar foreground/focus issues because the process name is derived from the target executable.
|
||||||
|
|
||||||
## Sunshine / Moonlight
|
## Sunshine / Moonlight
|
||||||
|
|
||||||
Use as command preparation in Sunshine (full venv path required):
|
Preferred for end users:
|
||||||
|
|
||||||
```
|
```
|
||||||
"C:\Projekte\Steam_backgroud_fix\.venv\Scripts\pythonw.exe" "C:\Projekte\Steam_backgroud_fix\focusfix.py" --process "ProcessName"
|
"C:\Path\To\FocusFix\FocusFix.exe" --process "ProcessName"
|
||||||
|
```
|
||||||
|
|
||||||
|
Direct Python/script usage:
|
||||||
|
|
||||||
|
```
|
||||||
|
"C:\Path\To\Python\pythonw.exe" "C:\Path\To\FocusFix\focusfix.py" --process "ProcessName"
|
||||||
```
|
```
|
||||||
|
|
||||||
## Running Manually (for testing)
|
## Running Manually (for testing)
|
||||||
|
|
||||||
```
|
```
|
||||||
.venv\Scripts\python focusfix.py --process CrimsonDesert
|
python focusfix.py --process CrimsonDesert
|
||||||
.venv\Scripts\python focusfix.py --process CrimsonDesert --timeout 180
|
python focusfix.py --process CrimsonDesert --timeout 180
|
||||||
.venv\Scripts\python focusfix.py "C:\Games\CrimsonDesert.exe"
|
python focusfix.py "C:\Games\CrimsonDesert.exe"
|
||||||
|
python focusfix.py -debug "C:\Games\CrimsonDesert.exe"
|
||||||
```
|
```
|
||||||
|
|
||||||
Use either `--process` or a game command. Runtime logging goes to `focusfix.log`. When started with `pythonw.exe`, no console window is shown; manual runs with `python.exe` can still print argument or interpreter errors to the console.
|
Use either `--process` or a game command. By default no log file is created. When started with `--debug` or `-debug`, runtime logging goes to `focusfix.log` and overwrites any existing file from a previous run. When started with `pythonw.exe`, no console window is shown; manual runs with `python.exe` can still print argument or interpreter errors to the console.
|
||||||
|
|
||||||
|
## Working Assumptions
|
||||||
|
|
||||||
|
- End-user docs and defaults should prefer `FocusFix.exe` over Python or `.venv`-based usage.
|
||||||
|
- Source-based usage is still supported for developers and power users through `requirements.txt`.
|
||||||
|
- `launch.vbs` is legacy/fallback behavior, not the primary integration path.
|
||||||
|
- Do not assume `.venv` exists; wrapper behavior explicitly supports a fallback to global `pythonw.exe`.
|
||||||
|
|
||||||
## Key Constants in focusfix.py
|
## Key Constants in focusfix.py
|
||||||
|
|
||||||
@@ -54,6 +90,6 @@ Use either `--process` or a game command. Runtime logging goes to `focusfix.log`
|
|||||||
|
|
||||||
- `SetForegroundWindow` is restricted by Windows unless the calling process owns the foreground. Workaround: simulate an `Alt` keypress + `AttachThreadInput` to the foreground thread.
|
- `SetForegroundWindow` is restricted by Windows unless the calling process owns the foreground. Workaround: simulate an `Alt` keypress + `AttachThreadInput` to the foreground thread.
|
||||||
- Alt key release is in a `finally` block to prevent it from staying pressed on errors.
|
- Alt key release is in a `finally` block to prevent it from staying pressed on errors.
|
||||||
- `pythonw.exe` (not `python.exe`) is required for invisible background execution.
|
- `pythonw.exe` (not `python.exe`) is required for invisible background execution when using the Python/script path.
|
||||||
- `launch.vbs` is legacy-only; normal Steam usage now calls `focusfix.py` directly.
|
- Normal user-facing guidance should point to `FocusFix.exe`; direct `focusfix.py` usage is the source/developer path.
|
||||||
- Window selection prefers titled windows over titleless ones (prevents overlay issues like in Wuthering Waves).
|
- Window selection prefers titled windows over titleless ones (prevents overlay issues like in Wuthering Waves).
|
||||||
|
|||||||
@@ -1,16 +1,20 @@
|
|||||||
# FocusFix - Game Foreground Fix for Windows
|
# 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).
|
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
|
## Inhaltsverzeichnis
|
||||||
|
|
||||||
|
- [Schnellstart](#schnellstart)
|
||||||
|
- [Für Nutzer](#fur-nutzer)
|
||||||
|
- [Für Entwickler](#fur-entwickler)
|
||||||
- [Problembeschreibung](#problembeschreibung)
|
- [Problembeschreibung](#problembeschreibung)
|
||||||
- [Lösungsansatz](#lösungsansatz)
|
- [Lösungsansatz](#lösungsansatz)
|
||||||
- [Architektur](#architektur)
|
- [Architektur](#architektur)
|
||||||
- [Voraussetzungen](#voraussetzungen)
|
- [Voraussetzungen](#voraussetzungen)
|
||||||
- [Installation](#installation)
|
- [Direkte Verwendung](#direkte-verwendung)
|
||||||
|
- [Aus Quellcode ausführen](#aus-quellcode-ausfuhren)
|
||||||
- [Konfiguration](#konfiguration)
|
- [Konfiguration](#konfiguration)
|
||||||
- [Steam](#steam)
|
- [Steam](#steam)
|
||||||
- [Sunshine / Moonlight](#sunshine--moonlight)
|
- [Sunshine / Moonlight](#sunshine--moonlight)
|
||||||
@@ -29,6 +33,47 @@ Windows-Hilfsprogramm, das ein Spielfenster automatisch in den Vordergrund bring
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## 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:
|
||||||
|
|
||||||
|
```text
|
||||||
|
"C:\Path\To\FocusFix\FocusFix.exe" %command%
|
||||||
|
```
|
||||||
|
|
||||||
|
Mit Debug-Logging:
|
||||||
|
|
||||||
|
```text
|
||||||
|
"C:\Path\To\FocusFix\FocusFix.exe" -debug %command%
|
||||||
|
```
|
||||||
|
|
||||||
|
### Für Entwickler
|
||||||
|
|
||||||
|
Wenn du FocusFix aus dem Repository starten oder weiterentwickeln willst:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
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`:
|
||||||
|
|
||||||
|
```text
|
||||||
|
"C:\Projekte\FocusFix\.venv\Scripts\pythonw.exe" "C:\Projekte\FocusFix\focusfix.py" %command%
|
||||||
|
```
|
||||||
|
|
||||||
|
Ohne lokales `.venv` und mit globalem Python im `PATH`:
|
||||||
|
|
||||||
|
```text
|
||||||
|
"pythonw.exe" "C:\Projekte\FocusFix\focusfix.py" %command%
|
||||||
|
```
|
||||||
|
|
||||||
## Problembeschreibung
|
## 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.
|
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.
|
||||||
@@ -86,33 +131,31 @@ Steam Launch Options / Sunshine Befehlsvorbereitung
|
|||||||
| Komponente | Version | Hinweis |
|
| Komponente | Version | Hinweis |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| Windows | 10 / 11 | Benötigt Win32 API (user32.dll) |
|
| 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 |
|
| 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 |
|
||||||
|
|
||||||
## Installation
|
## Direkte Verwendung
|
||||||
|
|
||||||
|
Für normale Nutzer ist eine fertige `.exe` der einfachste Weg.
|
||||||
|
|
||||||
|
## Aus Quellcode ausführen
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd C:\Path\To\FocusFix
|
cd C:\Path\To\FocusFix
|
||||||
|
py -m pip install -r requirements.txt
|
||||||
# Virtual Environment erstellen
|
|
||||||
py -m venv .venv
|
|
||||||
|
|
||||||
# Aktivieren
|
|
||||||
.venv\Scripts\activate
|
|
||||||
|
|
||||||
# Abhängigkeiten installieren
|
|
||||||
pip install psutil pywin32
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Dateistruktur nach Installation
|
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\
|
C:\Path\To\FocusFix\
|
||||||
├── .venv\ # Python Virtual Environment
|
|
||||||
├── focusfix.py # Hauptscript
|
├── focusfix.py # Hauptscript
|
||||||
├── focusfix.log # Logdatei (wird automatisch erstellt)
|
├── focusfix.log # Logdatei (nur bei --debug / -debug)
|
||||||
├── launch.vbs # Legacy-Wrapper, optional
|
├── launch.vbs # Legacy-Wrapper, optional
|
||||||
|
├── requirements.txt # Python-Abhängigkeiten für Quellcode-Nutzung
|
||||||
├── CLAUDE.md # Kontext für Claude Code
|
├── CLAUDE.md # Kontext für Claude Code
|
||||||
└── README.md # Diese Dokumentation
|
└── README.md # Diese Dokumentation
|
||||||
```
|
```
|
||||||
@@ -125,10 +168,25 @@ C:\Path\To\FocusFix\
|
|||||||
2. Rechtsklick auf das Spiel → **Eigenschaften**
|
2. Rechtsklick auf das Spiel → **Eigenschaften**
|
||||||
3. Unter **Allgemein → Startoptionen** eine der folgenden Varianten eintragen:
|
3. Unter **Allgemein → Startoptionen** eine der folgenden Varianten eintragen:
|
||||||
|
|
||||||
#### Variante A — Empfohlen: direkt mit `focusfix.py`
|
#### Variante A — Empfohlen für Nutzer: `FocusFix.exe`
|
||||||
|
|
||||||
```text
|
```text
|
||||||
"C:\Path\To\FocusFix\.venv\Scripts\pythonw.exe" "C:\Path\To\FocusFix\focusfix.py" %command%
|
"C:\Path\To\FocusFix\FocusFix.exe" %command%
|
||||||
|
```
|
||||||
|
|
||||||
|
Mit Debug-Logging:
|
||||||
|
|
||||||
|
```text
|
||||||
|
"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`
|
||||||
|
|
||||||
|
```text
|
||||||
|
"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.
|
`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.
|
||||||
@@ -139,41 +197,49 @@ Die Pfade im Beispiel sind Platzhalter und müssen durch deinen tatsächlichen I
|
|||||||
- `"...\focusfix.py"` — Python-Script im Steam-Wrapper-Modus
|
- `"...\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"`
|
- `%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`
|
#### Variante C — Legacy: über `launch.vbs`
|
||||||
|
|
||||||
Wenn du den alten VBScript-Wrapper weiterhin verwenden willst, kannst du in Steam Folgendes eintragen:
|
Wenn du den alten VBScript-Wrapper weiterhin verwenden willst, kannst du in Steam Folgendes eintragen:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
wscript "C:\Path\To\FocusFix\launch.vbs" %command%
|
wscript "C:\Path\To\FocusFix\launch.vbs" %command%
|
||||||
|
Beispiel: "C:\Projekte\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.
|
Mit Debug-Logging:
|
||||||
Die Pfade im Beispiel sind Platzhalter und müssen durch deinen tatsächlichen Installationspfad ersetzt werden.
|
|
||||||
|
```text
|
||||||
|
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:**
|
**Erklärung:**
|
||||||
- `wscript` — startet VBScript ohne sichtbares Konsolenfenster
|
- `wscript` — startet VBScript ohne sichtbares Konsolenfenster
|
||||||
- `"...\launch.vbs"` — Legacy-Wrapper, der `focusfix.py` indirekt startet
|
- `"...\launch.vbs"` — Legacy-Wrapper, der `focusfix.py` indirekt startet
|
||||||
|
- `-debug` — optional, aktiviert `focusfix.log` für `focusfix.py`
|
||||||
- `%command%` — Steam-Platzhalter mit dem ursprünglichen Spielstartbefehl
|
- `%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`:
|
|
||||||
|
|
||||||
```text
|
|
||||||
"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
|
### Sunshine / Moonlight
|
||||||
|
|
||||||
In Sunshine als **Befehlsvorbereitung** (Command Preparation) pro Spiel eintragen:
|
Für Nutzer mit `.exe`:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
"C:\Path\To\FocusFix\.venv\Scripts\pythonw.exe" "C:\Path\To\FocusFix\focusfix.py" --process "Prozessname"
|
"C:\Path\To\FocusFix\FocusFix.exe" --process "Prozessname"
|
||||||
|
```
|
||||||
|
|
||||||
|
Mit Debug-Logging:
|
||||||
|
|
||||||
|
```text
|
||||||
|
"C:\Path\To\FocusFix\FocusFix.exe" --debug --process "Prozessname"
|
||||||
|
```
|
||||||
|
|
||||||
|
Für Quellcode-Nutzung in Sunshine als **Befehlsvorbereitung** (Command Preparation) pro Spiel:
|
||||||
|
|
||||||
|
```text
|
||||||
|
"C:\Path\To\Python\pythonw.exe" "C:\Path\To\FocusFix\focusfix.py" --process "Prozessname"
|
||||||
```
|
```
|
||||||
|
|
||||||
Den Prozessnamen im Task-Manager ablesen, ohne `.exe`. Beispiele:
|
Den Prozessnamen im Task-Manager ablesen, ohne `.exe`. Beispiele:
|
||||||
@@ -183,7 +249,7 @@ Den Prozessnamen im Task-Manager ablesen, ohne `.exe`. Beispiele:
|
|||||||
| Crimson Desert | `CrimsonDesert` |
|
| Crimson Desert | `CrimsonDesert` |
|
||||||
| Wuthering Waves | `Client-Win64-Shipping` |
|
| 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.
|
**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
|
## Ablauf zur Laufzeit
|
||||||
|
|
||||||
@@ -245,7 +311,7 @@ t=~15s Erfolg → focusfix.py beendet sich
|
|||||||
|
|
||||||
### launch.vbs
|
### 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.
|
`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
|
## Konfigurationsparameter
|
||||||
|
|
||||||
@@ -271,7 +337,8 @@ Es muss entweder `--process` oder ein Spielbefehl übergeben werden.
|
|||||||
|
|
||||||
| Pfad | Zweck |
|
| 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.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 |
|
| `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.
|
Bei einer Änderung des Installationsverzeichnisses müssen diese Pfade in den Steam-Startoptionen oder in Sunshine angepasst werden.
|
||||||
@@ -312,27 +379,27 @@ Das wichtigste Unterscheidungsmerkmal ist hier die Fenstergröße. Kleine Startf
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd C:\Path\To\FocusFix
|
cd C:\Path\To\FocusFix
|
||||||
.venv\Scripts\python focusfix.py --process "CrimsonDesert" --timeout 5
|
python focusfix.py --process "CrimsonDesert" --timeout 5
|
||||||
```
|
```
|
||||||
|
|
||||||
### Steam-Wrapper-Modus testen
|
### Steam-Wrapper-Modus testen
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
.venv\Scripts\python focusfix.py "C:\Path\To\Game\TestGame.exe"
|
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.
|
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
|
### Gesamtablauf testen
|
||||||
|
|
||||||
1. Steam-Startoptionen wie oben konfigurieren.
|
1. Steam-Startoptionen wie oben konfigurieren.
|
||||||
2. Spiel über Steam starten.
|
2. Spiel über Steam starten.
|
||||||
3. Erwartung: Spielfenster erscheint nach dem Ladescreen im Vordergrund, ohne zusätzliches Konsolenfenster.
|
3. Erwartung: Spielfenster erscheint nach dem Ladescreen im Vordergrund, ohne zusätzliches Konsolenfenster.
|
||||||
4. `focusfix.log` prüfen.
|
4. Falls mit `--debug` gestartet wurde, `focusfix.log` prüfen.
|
||||||
|
|
||||||
## Debugging
|
## Debugging
|
||||||
|
|
||||||
Alle Informationen werden in `focusfix.log` protokolliert:
|
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
|
- Gefundene Kandidaten-Fenster mit Handle, Titel, Größe und PID
|
||||||
- Fensterwechsel und ignorierte titellose Fenster
|
- Fensterwechsel und ignorierte titellose Fenster
|
||||||
@@ -343,12 +410,12 @@ Alle Informationen werden in `focusfix.log` protokolliert:
|
|||||||
|
|
||||||
| Symptom | Ursache | Lösung |
|
| 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 |
|
| 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 | Vollständigen Pfad zu `.venv\Scripts\pythonw.exe` verwenden |
|
| `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 |
|
| 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 |
|
| 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 |
|
| 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 |
|
| 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 |
|
| Verdunkeltes/blockiertes Spiel | Titelloses Overlay-Fenster | Log prüfen; sollte meist durch Fenster-mit-Titel-Bevorzugung abgefangen werden |
|
||||||
|
|
||||||
### Fenster-Inspektion per PowerShell
|
### Fenster-Inspektion per PowerShell
|
||||||
|
|||||||
+35
-21
@@ -26,11 +26,9 @@ import win32process
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
_LOG_PATH = Path(__file__).resolve().parent / "focusfix.log"
|
_LOG_PATH = Path(__file__).resolve().parent / "focusfix.log"
|
||||||
logging.basicConfig(
|
_LOGGER = logging.getLogger("focusfix")
|
||||||
filename=str(_LOG_PATH),
|
_LOGGER.addHandler(logging.NullHandler())
|
||||||
level=logging.DEBUG,
|
_LOGGER.propagate = False
|
||||||
format="%(asctime)s %(levelname)s %(message)s",
|
|
||||||
)
|
|
||||||
|
|
||||||
# Minimale Fensterbreite in Pixeln, um den Splashscreen auszuschließen.
|
# Minimale Fensterbreite in Pixeln, um den Splashscreen auszuschließen.
|
||||||
MIN_WINDOW_WIDTH = 800
|
MIN_WINDOW_WIDTH = 800
|
||||||
@@ -46,8 +44,21 @@ def derive_process_name(command: list[str]) -> str:
|
|||||||
return Path(command[0]).stem
|
return Path(command[0]).stem
|
||||||
|
|
||||||
|
|
||||||
|
def configure_logging(enabled: bool, log_path: Path = _LOG_PATH) -> None:
|
||||||
|
_LOGGER.handlers.clear()
|
||||||
|
if not enabled:
|
||||||
|
_LOGGER.addHandler(logging.NullHandler())
|
||||||
|
_LOGGER.setLevel(logging.CRITICAL + 1)
|
||||||
|
return
|
||||||
|
|
||||||
|
file_handler = logging.FileHandler(log_path, mode="w", encoding="utf-8")
|
||||||
|
file_handler.setFormatter(logging.Formatter("%(asctime)s %(levelname)s %(message)s"))
|
||||||
|
_LOGGER.addHandler(file_handler)
|
||||||
|
_LOGGER.setLevel(logging.DEBUG)
|
||||||
|
|
||||||
|
|
||||||
def launch_game(command: list[str]) -> subprocess.Popen:
|
def launch_game(command: list[str]) -> subprocess.Popen:
|
||||||
logging.info("Launching game command: %r", command)
|
_LOGGER.info("Launching game command: %r", command)
|
||||||
return subprocess.Popen(command)
|
return subprocess.Popen(command)
|
||||||
|
|
||||||
|
|
||||||
@@ -82,7 +93,7 @@ def find_game_window(pids: set[int]) -> int | None:
|
|||||||
height = rect[3] - rect[1]
|
height = rect[3] - rect[1]
|
||||||
if width >= MIN_WINDOW_WIDTH:
|
if width >= MIN_WINDOW_WIDTH:
|
||||||
title = win32gui.GetWindowText(hwnd)
|
title = win32gui.GetWindowText(hwnd)
|
||||||
logging.debug("Candidate window: hwnd=%s title=%r size=%dx%d pid=%d", hwnd, title, width, height, pid)
|
_LOGGER.debug("Candidate window: hwnd=%s title=%r size=%dx%d pid=%d", hwnd, title, width, height, pid)
|
||||||
found.append((hwnd, title, width, height))
|
found.append((hwnd, title, width, height))
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@@ -115,7 +126,7 @@ def wait_for_stable_size(hwnd: int, polls: int = 3, interval: float = 0.5,
|
|||||||
stable_count = 0
|
stable_count = 0
|
||||||
last_size = size
|
last_size = size
|
||||||
time.sleep(interval)
|
time.sleep(interval)
|
||||||
logging.debug("Stable size for hwnd=%s: %dx%d (after %d stable polls)",
|
_LOGGER.debug("Stable size for hwnd=%s: %dx%d (after %d stable polls)",
|
||||||
hwnd, last_size[0], last_size[1], stable_count)
|
hwnd, last_size[0], last_size[1], stable_count)
|
||||||
return last_size
|
return last_size
|
||||||
|
|
||||||
@@ -154,11 +165,11 @@ def bring_to_front(hwnd: int) -> bool:
|
|||||||
ctypes.windll.user32.AttachThreadInput(tgt_tid, fg_tid, False)
|
ctypes.windll.user32.AttachThreadInput(tgt_tid, fg_tid, False)
|
||||||
|
|
||||||
result = is_foreground(hwnd)
|
result = is_foreground(hwnd)
|
||||||
logging.debug("bring_to_front result: %s (foreground hwnd=%s, target hwnd=%s)",
|
_LOGGER.debug("bring_to_front result: %s (foreground hwnd=%s, target hwnd=%s)",
|
||||||
result, win32gui.GetForegroundWindow(), hwnd)
|
result, win32gui.GetForegroundWindow(), hwnd)
|
||||||
return result
|
return result
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.exception("bring_to_front failed: %s", e)
|
_LOGGER.exception("bring_to_front failed: %s", e)
|
||||||
return False
|
return False
|
||||||
finally:
|
finally:
|
||||||
win32api.keybd_event(win32con.VK_MENU, 0, win32con.KEYEVENTF_KEYUP, 0)
|
win32api.keybd_event(win32con.VK_MENU, 0, win32con.KEYEVENTF_KEYUP, 0)
|
||||||
@@ -167,12 +178,15 @@ def bring_to_front(hwnd: int) -> bool:
|
|||||||
|
|
||||||
def main() -> None:
|
def main() -> None:
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument("-d", "--debug", "-debug", action="store_true",
|
||||||
|
help="Debug-Logging nach focusfix.log aktivieren")
|
||||||
parser.add_argument("--timeout", type=int, default=120)
|
parser.add_argument("--timeout", type=int, default=120)
|
||||||
parser.add_argument("--process", type=str,
|
parser.add_argument("--process", type=str,
|
||||||
help="Prozessname des Spiels (ohne .exe)")
|
help="Prozessname des Spiels (ohne .exe)")
|
||||||
parser.add_argument("command", nargs="*",
|
parser.add_argument("command", nargs="*",
|
||||||
help="Steam-Spielbefehl, z.B. %%command%%")
|
help="Steam-Spielbefehl, z.B. %%command%%")
|
||||||
args, extra_command_args = parser.parse_known_args()
|
args, extra_command_args = parser.parse_known_args()
|
||||||
|
configure_logging(args.debug)
|
||||||
|
|
||||||
process_name = args.process
|
process_name = args.process
|
||||||
command = args.command + extra_command_args
|
command = args.command + extra_command_args
|
||||||
@@ -187,13 +201,13 @@ def main() -> None:
|
|||||||
try:
|
try:
|
||||||
launch_game(command)
|
launch_game(command)
|
||||||
except OSError as exc:
|
except OSError as exc:
|
||||||
logging.exception("Failed to launch game command: %s", exc)
|
_LOGGER.exception("Failed to launch game command: %s", exc)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
elif not process_name:
|
elif not process_name:
|
||||||
parser.error("Either --process or a game command is required.")
|
parser.error("Either --process or a game command is required.")
|
||||||
|
|
||||||
deadline = time.time() + args.timeout
|
deadline = time.time() + args.timeout
|
||||||
logging.info("Monitoring process name: %s", process_name)
|
_LOGGER.info("Monitoring process name: %s", process_name)
|
||||||
|
|
||||||
# --- Phase 1: Warten auf den Prozess ---
|
# --- Phase 1: Warten auf den Prozess ---
|
||||||
pids: set[int] = set()
|
pids: set[int] = set()
|
||||||
@@ -211,13 +225,13 @@ def main() -> None:
|
|||||||
pids = find_process_pids(process_name)
|
pids = find_process_pids(process_name)
|
||||||
hwnd = find_game_window(pids)
|
hwnd = find_game_window(pids)
|
||||||
if hwnd:
|
if hwnd:
|
||||||
logging.info("Initial window found: hwnd=%s title=%r", hwnd, win32gui.GetWindowText(hwnd))
|
_LOGGER.info("Initial window found: hwnd=%s title=%r", hwnd, win32gui.GetWindowText(hwnd))
|
||||||
# Warten bis das Spiel sein Fenster vollständig aufgebaut hat
|
# Warten bis das Spiel sein Fenster vollständig aufgebaut hat
|
||||||
time.sleep(3)
|
time.sleep(3)
|
||||||
break
|
break
|
||||||
time.sleep(0.5)
|
time.sleep(0.5)
|
||||||
else:
|
else:
|
||||||
logging.error("Timeout waiting for game window")
|
_LOGGER.error("Timeout waiting for game window")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
# --- Phase 3: Spielfenster fokussieren und auf Fensterwechsel reagieren ---
|
# --- Phase 3: Spielfenster fokussieren und auf Fensterwechsel reagieren ---
|
||||||
@@ -227,7 +241,7 @@ def main() -> None:
|
|||||||
for attempt in range(FOCUS_RETRIES):
|
for attempt in range(FOCUS_RETRIES):
|
||||||
pids = find_process_pids(process_name)
|
pids = find_process_pids(process_name)
|
||||||
if not pids:
|
if not pids:
|
||||||
logging.warning("Game process gone, stopping")
|
_LOGGER.warning("Game process gone, stopping")
|
||||||
break
|
break
|
||||||
|
|
||||||
current_hwnd = find_game_window(pids)
|
current_hwnd = find_game_window(pids)
|
||||||
@@ -237,10 +251,10 @@ def main() -> None:
|
|||||||
old_title = win32gui.GetWindowText(hwnd) if hwnd else ""
|
old_title = win32gui.GetWindowText(hwnd) if hwnd else ""
|
||||||
# Nicht von einem Fenster mit Titel auf ein titelloses wechseln
|
# Nicht von einem Fenster mit Titel auf ein titelloses wechseln
|
||||||
if not new_title and old_title:
|
if not new_title and old_title:
|
||||||
logging.debug("Ignoring titleless window hwnd=%s (keeping %s title=%r)",
|
_LOGGER.debug("Ignoring titleless window hwnd=%s (keeping %s title=%r)",
|
||||||
current_hwnd, hwnd, old_title)
|
current_hwnd, hwnd, old_title)
|
||||||
else:
|
else:
|
||||||
logging.info("Window changed: old=%s new=%s title=%r",
|
_LOGGER.info("Window changed: old=%s new=%s title=%r",
|
||||||
hwnd, current_hwnd, new_title)
|
hwnd, current_hwnd, new_title)
|
||||||
hwnd = current_hwnd
|
hwnd = current_hwnd
|
||||||
focused_hwnd = None # neues Fenster muss neu fokussiert werden
|
focused_hwnd = None # neues Fenster muss neu fokussiert werden
|
||||||
@@ -258,15 +272,15 @@ def main() -> None:
|
|||||||
# Warten bis Fenstergröße stabil ist (Resize abgeschlossen)
|
# Warten bis Fenstergröße stabil ist (Resize abgeschlossen)
|
||||||
wait_for_stable_size(hwnd)
|
wait_for_stable_size(hwnd)
|
||||||
|
|
||||||
logging.info("Focus attempt %d/%d for hwnd=%s title=%r",
|
_LOGGER.info("Focus attempt %d/%d for hwnd=%s title=%r",
|
||||||
attempt + 1, FOCUS_RETRIES, hwnd, win32gui.GetWindowText(hwnd))
|
attempt + 1, FOCUS_RETRIES, hwnd, win32gui.GetWindowText(hwnd))
|
||||||
success = bring_to_front(hwnd)
|
success = bring_to_front(hwnd)
|
||||||
if success:
|
if success:
|
||||||
logging.info("Focus succeeded on attempt %d", attempt + 1)
|
_LOGGER.info("Focus succeeded on attempt %d", attempt + 1)
|
||||||
focused_hwnd = hwnd
|
focused_hwnd = hwnd
|
||||||
time.sleep(FOCUS_RETRY_DELAY)
|
time.sleep(FOCUS_RETRY_DELAY)
|
||||||
|
|
||||||
logging.info("Done. Final focused hwnd=%s", focused_hwnd)
|
_LOGGER.info("Done. Final focused hwnd=%s", focused_hwnd)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|||||||
+42
-13
@@ -1,21 +1,50 @@
|
|||||||
Set WshShell = CreateObject("WScript.Shell")
|
Set WshShell = CreateObject("WScript.Shell")
|
||||||
|
|
||||||
' Prozessname aus dem ersten Argument (Steam %command%) extrahieren
|
|
||||||
Dim exePath, fso, exeName
|
|
||||||
Set fso = CreateObject("Scripting.FileSystemObject")
|
Set fso = CreateObject("Scripting.FileSystemObject")
|
||||||
exePath = WScript.Arguments(0)
|
|
||||||
|
Dim baseDir, pythonwPath, focusfixPath
|
||||||
|
baseDir = fso.GetParentFolderName(WScript.ScriptFullName)
|
||||||
|
pythonwPath = fso.BuildPath(baseDir, ".venv\Scripts\pythonw.exe")
|
||||||
|
focusfixPath = fso.BuildPath(baseDir, "focusfix.py")
|
||||||
|
|
||||||
|
If Not fso.FileExists(pythonwPath) Then
|
||||||
|
pythonwPath = "pythonw.exe"
|
||||||
|
End If
|
||||||
|
|
||||||
|
Dim debugEnabled, exePath, exeName, gameCmd, arg, i
|
||||||
|
debugEnabled = False
|
||||||
|
exePath = ""
|
||||||
|
gameCmd = ""
|
||||||
|
|
||||||
|
For i = 0 To WScript.Arguments.Count - 1
|
||||||
|
arg = WScript.Arguments(i)
|
||||||
|
|
||||||
|
If arg = "-d" Or arg = "-debug" Or arg = "--debug" Then
|
||||||
|
debugEnabled = True
|
||||||
|
Else
|
||||||
|
If exePath = "" Then
|
||||||
|
exePath = arg
|
||||||
|
End If
|
||||||
|
gameCmd = gameCmd & """" & arg & """ "
|
||||||
|
End If
|
||||||
|
Next
|
||||||
|
|
||||||
|
If exePath = "" Then
|
||||||
|
WScript.Quit 1
|
||||||
|
End If
|
||||||
|
|
||||||
|
' Prozessname aus dem ersten nicht-Wrapper-Argument (Steam %command%) extrahieren
|
||||||
exeName = fso.GetBaseName(exePath)
|
exeName = fso.GetBaseName(exePath)
|
||||||
|
|
||||||
' FocusFix Script unsichtbar starten (pythonw = kein Konsolenfenster)
|
' FocusFix Script unsichtbar starten (pythonw = kein Konsolenfenster)
|
||||||
WshShell.Run """C:\Projekte\Steam_backgroud_fix\.venv\Scripts\pythonw.exe"" ""C:\Projekte\Steam_backgroud_fix\focusfix.py"" --process """ & exeName & """", 0, False
|
Dim focusfixCmd
|
||||||
|
focusfixCmd = """" & pythonwPath & """ """ & focusfixPath & """"
|
||||||
|
If debugEnabled Then
|
||||||
|
focusfixCmd = focusfixCmd & " -debug"
|
||||||
|
End If
|
||||||
|
focusfixCmd = focusfixCmd & " --process """ & exeName & """"
|
||||||
|
WshShell.Run focusfixCmd, 0, False
|
||||||
|
|
||||||
' Spiel starten: alle Argumente (= Steam %command%) zusammensetzen und ausführen
|
' Spiel starten: alle übrigen Argumente (= Steam %command%) zusammensetzen und ausführen
|
||||||
Dim gameCmd, i
|
If Trim(gameCmd) <> "" Then
|
||||||
gameCmd = ""
|
|
||||||
For i = 0 To WScript.Arguments.Count - 1
|
|
||||||
gameCmd = gameCmd & """" & WScript.Arguments(i) & """ "
|
|
||||||
Next
|
|
||||||
|
|
||||||
If gameCmd <> "" Then
|
|
||||||
WshShell.Run gameCmd, 1, False
|
WshShell.Run gameCmd, 1, False
|
||||||
End If
|
End If
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
psutil
|
||||||
|
pywin32
|
||||||
Reference in New Issue
Block a user