diff --git a/deploy/README-DEPLOY.txt b/deploy/README-DEPLOY.txt index 8fa9bc1..0e9bfff 100644 --- a/deploy/README-DEPLOY.txt +++ b/deploy/README-DEPLOY.txt @@ -25,8 +25,9 @@ What postinstall.bat does ------------------------- 1. Elevates to administrator (UAC) if not already elevated. 2. Installs ViGEmBus silently if its driver service is not already present. - 3. Registers RIOJoy to start at logon (HKLM ...\Run, machine-wide). - 4. Launches RIOJoy. + + RIOJoy is NOT registered to auto-start and is NOT launched by the installer — + the TeslaConsole launcher starts and stops the app. Deploying with TeslaConsole --------------------------- @@ -40,7 +41,8 @@ Deploying with TeslaConsole Uninstalling with TeslaConsole ------------------------------ Before deleting the RIOJoy folder, run RIOJoy\pre-uninstall.bat ELEVATED. It - stops the tray app (releasing file locks), removes the logon entry, uninstalls + stops the tray app (releasing file locks), removes any leftover logon entry + (from older builds that auto-started), uninstalls ViGEmBus, and clears per-user config (%APPDATA%\RIOJoy) for every profile. It is idempotent and non-fatal — safe even if RIOJoy was never fully installed. The console can then delete the folder cleanly. Use -KeepDriver to leave ViGEmBus in @@ -48,8 +50,10 @@ Uninstalling with TeslaConsole After install ------------- - * RIOJoy runs in the system tray. Right-click it to pick/edit profiles, set the - auto-switch executables, and toggle output to the PC. + * RIOJoy is started and stopped by the TeslaConsole launcher (it is not + registered to auto-start at logon). + * When running, RIOJoy lives in the system tray. Right-click it to pick/edit + profiles, set the auto-switch executables, and toggle output to the PC. * The RIO's joystick output appears to games as a standard "Xbox 360 Controller" (verify in joy.cpl). Note the XInput layout limits joystick BUTTONS to 11 (A, B, X, Y, LB, RB, Back, Start, L3, R3, Guide); bind everything else to the diff --git a/deploy/install-rio.ps1 b/deploy/install-rio.ps1 index 7cb29a4..87ac09c 100644 --- a/deploy/install-rio.ps1 +++ b/deploy/install-rio.ps1 @@ -1,14 +1,15 @@ <# .SYNOPSIS RIOJoy cockpit post-install. Installs the signed ViGEmBus virtual-controller - driver (if absent) and sets RIOJoy to start at logon. Must run elevated - (postinstall.bat elevates for you). Idempotent — safe to re-run. + driver (if absent). Must run elevated (postinstall.bat elevates for you). + Idempotent — safe to re-run. RIOJoy is NOT registered to auto-start: the + TeslaConsole launcher owns the app's start/stop lifecycle. .DESCRIPTION Run from inside the deployed package directory (e.g. C:\games\RIOJOY). Paths are resolved relative to this script, so the layout is: - \app\RioJoy.Tray.exe the published tray app (self-contained) + \app\RioJoy.Tray.exe the published tray app (net48) \vendor\ViGEmBus_*.exe the signed ViGEmBus installer \install-rio.ps1 (this file) @@ -16,17 +17,13 @@ Secure Boot change, and NO reboot. The RIO appears to games as a standard Xbox 360 controller. -.PARAMETER NoLaunch - Do not start the app after install (it still starts at the next logon). #> -param([switch]$NoLaunch) $ErrorActionPreference = 'Stop' -$root = $PSScriptRoot -$appExe = Join-Path $root 'app\RioJoy.Tray.exe' -$vendorDir = Join-Path $root 'vendor' -$runValueName = 'RIOJoy' +$root = $PSScriptRoot +$appExe = Join-Path $root 'app\RioJoy.Tray.exe' +$vendorDir = Join-Path $root 'vendor' # --- guards --------------------------------------------------------------- $principal = [Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent() @@ -58,18 +55,11 @@ if ($svc) { } } -# 2. Start RIOJoy at logon (machine-wide Run key -> runs in each user's session). -Write-Host 'Registering RIOJoy to start at logon...' -$runKey = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run' -New-ItemProperty -Path $runKey -Name $runValueName -Value "`"$appExe`"" -PropertyType String -Force | Out-Null +# RIOJoy itself is deliberately NOT registered to auto-start and NOT launched +# here: the TeslaConsole launcher starts and stops the app. # --- summary -------------------------------------------------------------- Write-Host '' Write-Host "RIOJoy installed to $root" -ForegroundColor Green -Write-Host 'RIOJoy starts automatically at logon.' -if (-not $NoLaunch) { - Write-Host 'Launching RIOJoy...' - # Launch via explorer so the tray app runs de-elevated in the user session. - Start-Process -FilePath (Join-Path $env:WINDIR 'explorer.exe') -ArgumentList $appExe -} +Write-Host 'RIOJoy is not auto-started; the TeslaConsole launcher starts and stops it.' exit 0 diff --git a/docs/PLAN.md b/docs/PLAN.md index d2e47cb..d0fe8db 100644 --- a/docs/PLAN.md +++ b/docs/PLAN.md @@ -51,7 +51,8 @@ cockpit's outputs on their behalf. language features that net48 lacks are supplied by the PolySharp source generator + a few NuGet shims; see `src/RioJoy.Core/Compat/`.) Driver is C (WDK), separate toolchain. -- **Form:** background **tray app** (NotifyIcon), auto-start with Windows. +- **Form:** background **tray app** (NotifyIcon); start/stop managed by the + TeslaConsole launcher (no logon auto-start). - **Targets:** Windows 10/11 **x64 only**. The legacy x86 / WinXP targets are dropped. @@ -198,10 +199,10 @@ Core logic in `src/RioJoy.Core/Profiles` + `RioRuntime`; UI/OS in `src/RioJoy.Tr commands → calibration resets + serial requests + lamp re-init. End-to-end tested over the fake transport. - Tray: `NotifyIcon` menu mirroring the legacy console menu (axis resets, - version/status, diagnostic toggles, quit) + profile selection (auto vs. manual) - + "start with Windows"; `RioCoordinator` owns the serial acquire/release tied to - the watcher (native-game COM-port yield); OS adapters - (`ForegroundProcessProvider`, `AutoStartManager`). + version/status, diagnostic toggles, quit) + profile selection (auto vs. manual); + `RioCoordinator` owns the serial acquire/release tied to the watcher (native-game + COM-port yield); OS adapters (`ForegroundProcessProvider`). The app's start/stop + lifecycle is owned by the TeslaConsole launcher (no logon auto-start). - Joystick output now uses the real `HidFeederJoystickSink` when the driver is present (verified end-to-end); `NullJoystickSink` remains only as the no-driver fallback. diff --git a/src/RioJoy.Core/Profiles/AppConfig.cs b/src/RioJoy.Core/Profiles/AppConfig.cs index bad2029..7ba2c72 100644 --- a/src/RioJoy.Core/Profiles/AppConfig.cs +++ b/src/RioJoy.Core/Profiles/AppConfig.cs @@ -29,9 +29,6 @@ public sealed class AppConfig /// public string? NeutralProfileName { get; set; } - /// Start RIOJoy with Windows. - public bool AutoStart { get; set; } - /// /// Path to the cockpit overlay template (regions.json) used to generate /// per-profile wallpapers (Phase 7). Null disables wallpaper generation. The diff --git a/src/RioJoy.Tray/Os/AutoStartManager.cs b/src/RioJoy.Tray/Os/AutoStartManager.cs deleted file mode 100644 index 7289698..0000000 --- a/src/RioJoy.Tray/Os/AutoStartManager.cs +++ /dev/null @@ -1,29 +0,0 @@ -using Microsoft.Win32; - -namespace RioJoy.Tray.Os; - -/// -/// Manages the Windows "run at login" registration via the per-user -/// Run registry key. Per-user (HKCU) needs no elevation and matches the -/// tray app running in the interactive session. -/// -public static class AutoStartManager -{ - private const string RunKey = @"Software\Microsoft\Windows\CurrentVersion\Run"; - private const string ValueName = "RIOJoy"; - - public static bool IsEnabled() - { - using RegistryKey? key = Registry.CurrentUser.OpenSubKey(RunKey); - return key?.GetValue(ValueName) is not null; - } - - public static void SetEnabled(bool enabled) - { - using RegistryKey key = Registry.CurrentUser.CreateSubKey(RunKey); - if (enabled) - key.SetValue(ValueName, $"\"{Application.ExecutablePath}\""); - else - key.DeleteValue(ValueName, throwOnMissingValue: false); - } -} diff --git a/src/RioJoy.Tray/Program.cs b/src/RioJoy.Tray/Program.cs index eb34f5e..9079431 100644 --- a/src/RioJoy.Tray/Program.cs +++ b/src/RioJoy.Tray/Program.cs @@ -3,8 +3,8 @@ namespace RioJoy.Tray; internal static class Program { // Per-session single-instance guard. Two instances would both grab the RIO COM - // port, so a second launch (e.g. machine-wide + per-user autostart both firing) - // must exit immediately. A named mutex is released by the OS if the owner dies, + // port, so a second launch (e.g. the launcher starting it while an instance is + // already running) must exit immediately. A named mutex is released by the OS if the owner dies, // so a crash never leaves a stale lock. private const string SingleInstanceMutex = "RIOJoy.Tray.SingleInstance"; diff --git a/src/RioJoy.Tray/TrayApplicationContext.cs b/src/RioJoy.Tray/TrayApplicationContext.cs index ac9204b..869a452 100644 --- a/src/RioJoy.Tray/TrayApplicationContext.cs +++ b/src/RioJoy.Tray/TrayApplicationContext.cs @@ -9,7 +9,8 @@ namespace RioJoy.Tray; /// /// Owns the tray icon, menu, and the RIOJoy runtime. The menu mirrors the legacy /// console menu (axis resets, version/status, diagnostic toggles, quit) and adds -/// profile selection (auto vs. manual) and a "start with Windows" toggle. The +/// profile selection (auto vs. manual). The app's start/stop lifecycle is owned by +/// the TeslaConsole launcher, so there is no "start with Windows" toggle. The /// auto-switch watcher is polled on a UI timer so menu/status updates stay on the /// UI thread. /// @@ -91,14 +92,8 @@ internal sealed class TrayApplicationContext : ApplicationContext menu.Items.Add(new ToolStripSeparator()); - var autoStart = new ToolStripMenuItem("Start with Windows") - { - CheckOnClick = true, - Checked = AutoStartManager.IsEnabled(), - }; - autoStart.Click += (_, _) => AutoStartManager.SetEnabled(autoStart.Checked); - menu.Items.Add(autoStart); - + // No "start with Windows" toggle: the TeslaConsole launcher owns the app's + // start/stop lifecycle, so RIOJoy deliberately registers no auto-start entry. menu.Items.Add("Exit", null, (_, _) => Quit()); return menu; diff --git a/tests/RioJoy.Core.Tests/Profiles/ConfigStoreTests.cs b/tests/RioJoy.Core.Tests/Profiles/ConfigStoreTests.cs index 8ce2782..fc67814 100644 --- a/tests/RioJoy.Core.Tests/Profiles/ConfigStoreTests.cs +++ b/tests/RioJoy.Core.Tests/Profiles/ConfigStoreTests.cs @@ -15,7 +15,6 @@ public class ConfigStoreTests DefaultPlasmaComPort = "COM4", NativeGameExecutables = { "firestorm.exe", "redplanet.exe" }, NeutralProfileName = "Desktop", - AutoStart = true, Profiles = { new RioProfile @@ -35,7 +34,6 @@ public class ConfigStoreTests Assert.Equal("COM3", back.DefaultRioComPort); Assert.Equal(new[] { "firestorm.exe", "redplanet.exe" }, back.NativeGameExecutables); - Assert.True(back.AutoStart); RioProfile p = Assert.Single(back.Profiles); Assert.Equal("Doom", p.Name);