Repository navigation
feat: custom app mode, any .exe as the console launcher - #161
Conversation
Adds a fourth launch mode, "customApp": launches a chosen exe (optional arguments, working directory = its folder), moves its window to the game screen and ends the session once the watched process (the exe, or a process name for launcher stubs) has appeared and stayed gone for a grace period. A process that never appears keeps the session until it's ended by hand. A missing or invalid path blocks starting. Co-Authored-By: Claude Opus 5.5 <[email protected]>
cd231c4 to
20e860b
Compare
There was a problem hiding this comment.
Important
The watcher can miss a short-lived launched process and then leave the console session active indefinitely; process-name matching also conflates distinct instances.
Reviewed changes This review covers the custom-app launch mode and its process/window lifecycle, configuration, UI, localization, tests, and documentation.
- Custom app launch and validation Adds executable selection, arguments, pre-start validation, and launch from the executable's directory.
- Session monitoring and window placement Watches a selected process name, moves its window to the game display, and restores after an observed process exits.
- User-facing surfaces and tests Adds localized settings and console controls, guide/manual test updates, changelog entries, and pure-logic tests.
gpt-6-luna | 𝕏
| if (running) | ||
| { | ||
| State.CustomAppGoneSince = null; | ||
| if (!State.HasAppeared) AppLog.Write($"Loop: processo {name} apareceu"); |
There was a problem hiding this comment.
If the launched app exits before a poll observes it, HasAppeared stays false and the 90-second timeout only logs; the session then remains active indefinitely even though the app did run and exit. This is especially plausible for a short-lived launcher when no separate watch process is configured.
Technical details
# Do not lose exits between polls
## Affected sites
- `src/ConsoleMode/Services/ConsoleEngine.cs:495-515` — `HasAppeared` is set only by a positive `IsProcessRunning` poll, and the never-seen timeout does not exit.
- `src/ConsoleMode/Services/ConsoleEngine.cs:297` — before appearance, polling is delayed by 1.5 seconds.
## Required outcome
- Detect completion of the launched process even if it starts and exits between polling ticks, and allow the normal grace-period restoration path to run.| { | ||
| var name = State.CustomAppWatchName; | ||
| var now = DateTime.Now; | ||
| var running = LaunchService.IsProcessRunning(name); |
There was a problem hiding this comment.
GetProcessesByName treats every same-name process as the watched app, including one that was already running before this session or belongs to another install. That process can mark the app as appeared, keep the session alive after the launched instance exits, and cause PlaceCustomAppWindow to activate the wrong instance.
Technical details
# Associate the watcher with the intended process
## Affected sites
- `src/ConsoleMode/Services/ConsoleEngine.cs:495-501` — any matching process satisfies the watch and triggers window placement.
- `src/ConsoleMode/Services/ConsoleEngine.cs:503-515` — another same-name process prevents the exit grace period from completing.
- `src/ConsoleMode/Services/ConsoleEngine.cs:522-540` — the first enumerated same-name window is moved/activated.
- `src/ConsoleMode/Services/LaunchService.cs:51-70` — process checks and window enumeration are name-wide.
## Required outcome
- Ensure the session watch and window placement refer to the intended app instance rather than an unrelated process that shares its executable name.# Conflicts: # CHANGELOG.en-US.md # CHANGELOG.md

What
A fourth launch mode, Custom app ("Aplicativo personalizado"): any
.exebecomes the console launcher (RetroArch, another frontend, a game launcher…).FileOpenPickerfiltered to.exe, initialized with the main window handle like the Playnite picker), Arguments (optional) and Process to watch (optional). The Console interface gets an App to open row (opens the picker) when this mode is selected.CustomAppPath,CustomAppArguments,CustomAppWatchProcess, saved like the other settings.Monitors.MoveProcessWindows, up to 8 tries like the others) and brought to the front (WindowSwitcher.Activate, no topmost).CustomAppWatchProcessif set, otherwise the launched exe's name) has appeared and then stayed gone for an 8 s grace period. If it never appears within 90 s, that's logged in Portuguese and the session stays until the user ends it (Start + Select hold, session menu, tray)..exe, or a file that no longer exists blocks starting with a clear message, both in the view model (warning InfoBar) and inConsoleEngine.Start(before anything changes on screen, which covers the tray/--start/protocol paths).FileDescription, falling back to the file name.Pure logic (validation, process name normalization, watched process choice, display name fallback, exit/timeout decisions) is in
src/ConsoleMode/Services/CustomApp.cs, linked in the test project and covered byCustomAppTests.Strings in all six catalogs (translated). Guide row in all six guides plus a short paragraph in
GUIDE.md/GUIDE.pt-BR.md; manual checks indocs/TESTING.md; changelog in both files.Why
Requested in #111 (Reddit): use any app as the trigger, so Console Mode applies the TV setup, watches that process, and restores the desk when it exits.
Part of #111: the keyboard hotkey to end console mode mentioned there is not included in this PR.
How tested
dotnet test tests/ConsoleMode.Tests/ConsoleMode.Tests.csprojon Linux: all tests pass, including the newCustomAppTestsand the localization checks.docs/TESTING.md.🤖 Generated with Claude Code