Remove auto-start: launcher owns the app lifecycle
The TeslaConsole launcher starts and stops RIOJoy, so the app no longer registers any auto-start entry: - install-rio.ps1: drop the HKLM ...\Run registration and the post-install launch (and the -NoLaunch param). - Tray: remove the "Start with Windows" menu item and delete AutoStartManager (HKCU ...\Run writer). - AppConfig: drop the now-inert AutoStart field (+ test). - Docs (PLAN.md, README-DEPLOY.txt) updated to reflect launcher-managed start/stop. uninstall-rio.ps1 still clears any leftover Run entry from older auto-starting builds. Solution builds; 241 tests pass. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -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
|
||||
|
||||
+7
-17
@@ -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:
|
||||
|
||||
<root>\app\RioJoy.Tray.exe the published tray app (self-contained)
|
||||
<root>\app\RioJoy.Tray.exe the published tray app (net48)
|
||||
<root>\vendor\ViGEmBus_*.exe the signed ViGEmBus installer
|
||||
<root>\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'
|
||||
|
||||
# --- 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
|
||||
|
||||
+6
-5
@@ -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.
|
||||
|
||||
@@ -29,9 +29,6 @@ public sealed class AppConfig
|
||||
/// </summary>
|
||||
public string? NeutralProfileName { get; set; }
|
||||
|
||||
/// <summary>Start RIOJoy with Windows.</summary>
|
||||
public bool AutoStart { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Path to the cockpit overlay template (<c>regions.json</c>) used to generate
|
||||
/// per-profile wallpapers (Phase 7). Null disables wallpaper generation. The
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
using Microsoft.Win32;
|
||||
|
||||
namespace RioJoy.Tray.Os;
|
||||
|
||||
/// <summary>
|
||||
/// Manages the Windows "run at login" registration via the per-user
|
||||
/// <c>Run</c> registry key. Per-user (HKCU) needs no elevation and matches the
|
||||
/// tray app running in the interactive session.
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -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";
|
||||
|
||||
|
||||
@@ -9,7 +9,8 @@ namespace RioJoy.Tray;
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user