From 2ecb617c09d8dadf3c39a5e790056fe12b472a8f Mon Sep 17 00:00:00 2001 From: Cyd Date: Sat, 11 Jul 2026 20:53:43 -0500 Subject: [PATCH] Phase 8D: universal deployment package (XP + Win10/11, two entry points) One RIOJoy-.zip now deploys on both OS generations (~75 MB with the offline XP prerequisites): - Layout: RIOJoy\app (net48 x64) + RIOJoy\app-xp (net40 x86) + RIOJoy\vendor (ViGEmBus; vendor\xp: .NET 4.0 offline installer + KB2468871, both signature-verified; RioGamepadXP driver slots in when 8B lands - build warns/skips until then). - RIOJoy\install-core.bat: shared OS-detecting install logic (ver -> 5.1 = XP); pure cmd.exe on the XP path, delegates to install-rio.ps1 on 10/11. Exports RIOJOY_APPDIR for shortcut creation. - postinstall.bat (TeslaConsole, unattended): elevates, runs the core, then deletes install.bat + README.txt so C:\games stays clean. - install.bat (standalone computers): same core + Start Menu/desktop shortcuts via make-shortcut.vbs (XP-safe); keeps the README. - README.txt at the zip root explains which entry point to run. - deploy *.ps1 re-encoded UTF-8-with-BOM: Windows PowerShell read the BOM-less files as ANSI, where an em-dash byte parses as a curly quote and breaks string parsing (bit install-rio.ps1 in dry-run testing). Verified: zip layout correct; extracted package dispatch-tested on Win10 non-elevated (OS detect -> modern route -> admin guard, system untouched). Co-Authored-By: Claude Fable 5 --- deploy/README.txt | 59 ++++++++++++++++++++++++++++++++++ deploy/build-package.ps1 | 68 +++++++++++++++++++++++++++++++++------- deploy/install-core.bat | 68 ++++++++++++++++++++++++++++++++++++++++ deploy/install-rio.ps1 | 2 +- deploy/install.bat | 54 +++++++++++++++++++++++++++++++ deploy/make-shortcut.vbs | 27 ++++++++++++++++ deploy/postinstall.bat | 21 ++++++++++--- deploy/uninstall-rio.ps1 | 2 +- docs/PLAN.md | 17 ++++++---- 9 files changed, 294 insertions(+), 24 deletions(-) create mode 100644 deploy/README.txt create mode 100644 deploy/install-core.bat create mode 100644 deploy/install.bat create mode 100644 deploy/make-shortcut.vbs diff --git a/deploy/README.txt b/deploy/README.txt new file mode 100644 index 0000000..307e510 --- /dev/null +++ b/deploy/README.txt @@ -0,0 +1,59 @@ +RIOJoy - cockpit interface for the VWE pods +============================================ + +This package installs RIOJoy, the program that connects the cockpit's RIO +hardware (joystick, throttle, pedals, 96 lighted buttons, plasma display) +to games that don't know about the cockpit. It works on two kinds of +Windows: + + * Windows 10 / 11 (64-bit) - full app, appears to games as an Xbox 360 + controller (ViGEmBus driver, included) + * Windows XP SP3 (32-bit) - full runtime + mapping editor; all + prerequisites are included for offline + install (.NET 4.0 + its async update) + +The installer detects which Windows it is running on and installs the +right pieces automatically. Everything needed is inside this package - +no internet connection is required. + + +WHICH FILE DO I RUN? +-------------------- + + install.bat <-- RUN THIS on a normal, standalone computer. + Right-click -> "Run as administrator" (on XP, log + in as an Administrator user first). It installs + the prerequisites and puts RIOJoy shortcuts in the + Start Menu and on the desktop. RIOJoy does NOT + auto-start with Windows - launch it from the + shortcut when you want the cockpit active. + + postinstall.bat -- Used by the arcade cabinet's launcher software + (TeslaConsole). It runs automatically after the + cabinet extracts this package; you do not need to + run it by hand. (It also deletes install.bat and + this README so the cabinet's games folder stays + clean.) + + +WHAT GETS INSTALLED +------------------- + + RIOJoy\app\ the program for Windows 10/11 + RIOJoy\app-xp\ the program for Windows XP + RIOJoy\vendor\ third-party prerequisites (ViGEmBus for 10/11; + .NET 4.0 + KB2468871 + the RioGamepadXP joystick + driver for XP) + +After installing, start RIOJoy and look for its icon in the system tray +(near the clock). Right-click the icon to pick a profile, edit button +mappings, or send commands to the cockpit hardware. Full deployment +notes for cabinet operators are in RIOJoy\README-DEPLOY.txt. + + +REMOVING RIOJOY +--------------- + +Run RIOJoy\pre-uninstall.bat as administrator, then delete the folder +you extracted. On a standalone computer also delete the RIOJoy shortcuts +from the Start Menu and desktop. diff --git a/deploy/build-package.ps1 b/deploy/build-package.ps1 index 14273c6..2285af7 100644 --- a/deploy/build-package.ps1 +++ b/deploy/build-package.ps1 @@ -1,8 +1,11 @@ -<# +<# .SYNOPSIS - Build the RIOJoy cockpit deployment zip: publish the tray app self-contained, - bundle the signed ViGEmBus installer + the post-install scripts, and zip it for - TeslaConsole. The zip extracts directly into a single directory (C:\games\RIOJOY). + Build the UNIVERSAL RIOJoy deployment zip (PLAN.md §8D): one archive that + deploys on Windows 10/11 (net48 x64, ViGEmBus) AND Windows XP SP3 (net40 + x86, offline prerequisites). Two install entry points sit at the zip root: + postinstall.bat (TeslaConsole, unattended, cleans the root after itself) + and install.bat (standalone computers, adds shortcuts). README.txt at the + root explains it to a human installer. .PARAMETER VigemInstaller Path to the signed ViGEmBus installer to bundle. If omitted, looks in @@ -11,6 +14,12 @@ Where to write the zip (default: dist, relative to the repo root). .PARAMETER Configuration Build configuration (default: Release). + +.NOTES + XP offline prerequisites are picked up from deploy\vendor\xp\ when present + (dotNetFx40_Full_x86_x64.exe, NDP40-KB2468871-v2-x86.exe, and the + RioGamepadXP driver once Phase 8B lands); missing ones produce warnings, + not failures, so modern-only builds still work. #> param( [string]$VigemInstaller, @@ -47,14 +56,23 @@ try { $pkgDir = Join-Path $staging 'RIOJoy' New-Item -ItemType Directory -Force -Path $pkgDir | Out-Null - # 1. Publish the tray app into riojoy\app (net48, framework-dependent — relies on - # the in-box .NET Framework 4.8 present on every Windows 10/11 machine). + # 1. Publish the tray app into RIOJoy\app (net48 x64, framework-dependent — relies + # on the in-box .NET Framework 4.8 present on every Windows 10/11 machine). $appOut = Join-Path $pkgDir 'app' - Write-Host "Publishing RioJoy.Tray ($Configuration, net48 framework-dependent)..." + Write-Host "Publishing RioJoy.Tray ($Configuration, net48 x64 framework-dependent)..." & dotnet publish (Join-Path $repo 'src\RioJoy.Tray\RioJoy.Tray.csproj') ` - -c $Configuration -p:DebugType=none ` + -c $Configuration -f net48 -p:DebugType=none ` -o $appOut | Out-Null - if ($LASTEXITCODE -ne 0) { throw 'dotnet publish failed.' } + if ($LASTEXITCODE -ne 0) { throw 'dotnet publish (net48) failed.' } + + # 1a. Publish the Windows XP flavor into RIOJoy\app-xp (net40 x86, + # framework-dependent on the bundled .NET 4.0). + $appXpOut = Join-Path $pkgDir 'app-xp' + Write-Host "Publishing RioJoy.Tray ($Configuration, net40 x86 for Windows XP)..." + & dotnet publish (Join-Path $repo 'src\RioJoy.Tray\RioJoy.Tray.csproj') ` + -c $Configuration -f net40 -p:DebugType=none ` + -o $appXpOut | Out-Null + if ($LASTEXITCODE -ne 0) { throw 'dotnet publish (net40) failed.' } # 1b. Trim native SkiaSharp variants the x64 pod never uses. SkiaSharp's net48 # loader finds the native in either the app root or an arch subfolder (both @@ -71,19 +89,45 @@ try { Get-ChildItem $appOut -Filter '*.dylib' -ErrorAction SilentlyContinue | Remove-Item -Force Get-ChildItem $appOut -Filter '*.so' -ErrorAction SilentlyContinue | Remove-Item -Force - # 2. Bundle the signed ViGEmBus installer into riojoy\vendor. + # 2. Bundle the signed ViGEmBus installer into RIOJoy\vendor, and the XP + # offline prerequisites into RIOJoy\vendor\xp (warn if absent). $vendorOut = Join-Path $pkgDir 'vendor' New-Item -ItemType Directory -Force -Path $vendorOut | Out-Null Copy-Item $VigemInstaller $vendorOut - # 3. Install/uninstall scripts + readme + version stamp inside RIOJoy\; - # postinstall.bat at root, pre-uninstall.bat inside the payload folder. + $vendorXpSrc = Join-Path $PSScriptRoot 'vendor\xp' + $vendorXpOut = Join-Path $vendorOut 'xp' + New-Item -ItemType Directory -Force -Path $vendorXpOut | Out-Null + $xpWanted = @( + @{ Name = 'dotNetFx40_Full_x86_x64.exe'; What = '.NET Framework 4.0 offline installer' }, + @{ Name = 'NDP40-KB2468871-v2-x86.exe'; What = '.NET 4.0 update KB2468871 (required by Bcl.Async)' }, + @{ Name = 'RioGamepadXP.inf'; What = 'RioGamepadXP driver INF (Phase 8B)' }, + @{ Name = 'RioGamepadXP.sys'; What = 'RioGamepadXP driver binary (Phase 8B)' } + ) + foreach ($item in $xpWanted) { + $src = Join-Path $vendorXpSrc $item.Name + if (Test-Path $src) { + Copy-Item $src $vendorXpOut + Write-Host "XP vendor: $($item.Name)" + } else { + Write-Warning "XP vendor missing: $($item.Name) - $($item.What). XP installs will warn/skip." + } + } + + # 3. Install/uninstall scripts + readmes + version stamp. Payload scripts in + # RIOJoy\; the two entry points (postinstall.bat, install.bat) and the + # human README at the zip root (postinstall.bat deletes install.bat + + # README.txt after a cabinet deploy to keep C:\games clean). Copy-Item (Join-Path $PSScriptRoot 'install-rio.ps1') $pkgDir Copy-Item (Join-Path $PSScriptRoot 'uninstall-rio.ps1') $pkgDir Copy-Item (Join-Path $PSScriptRoot 'pre-uninstall.bat') $pkgDir + Copy-Item (Join-Path $PSScriptRoot 'install-core.bat') $pkgDir + Copy-Item (Join-Path $PSScriptRoot 'make-shortcut.vbs') $pkgDir Copy-Item (Join-Path $PSScriptRoot 'README-DEPLOY.txt') $pkgDir Set-Content -Path (Join-Path $pkgDir 'VERSION.txt') -Value "RIOJoy $version" -Encoding utf8 Copy-Item (Join-Path $PSScriptRoot 'postinstall.bat') $staging + Copy-Item (Join-Path $PSScriptRoot 'install.bat') $staging + Copy-Item (Join-Path $PSScriptRoot 'README.txt') $staging # 4. Zip the package contents (so it extracts straight into C:\games\RIOJOY). $outDirFull = if ([IO.Path]::IsPathRooted($OutDir)) { $OutDir } else { Join-Path $repo $OutDir } diff --git a/deploy/install-core.bat b/deploy/install-core.bat new file mode 100644 index 0000000..76b1dad --- /dev/null +++ b/deploy/install-core.bat @@ -0,0 +1,68 @@ +@echo off +rem =========================================================================== +rem RIOJoy shared install core - called by postinstall.bat (cabinet / +rem TeslaConsole) and install.bat (freestanding). NOT run directly. +rem Detects the OS and installs the matching flavor's prerequisites: +rem Windows XP (5.1) -> .NET 4.0 + KB2468871 from RIOJoy\vendor\xp, +rem RioGamepadXP driver INF when bundled; +rem app = RIOJoy\app-xp (net40 x86) +rem Windows 10/11 -> RIOJoy\install-rio.ps1 (ViGEmBus etc.); +rem app = RIOJoy\app (net48 x64) +rem Pure cmd.exe on the XP path (XP has no in-box PowerShell). Idempotent. +rem Sets RIOJOY_APPDIR for the caller (shortcut creation). +rem =========================================================================== +setlocal EnableExtensions +set CORE_RC=0 +set PKGROOT=%~dp0 +rem PKGROOT = ...\RIOJoy\ (this file lives inside the payload folder) + +ver | findstr /C:"Version 5.1" >nul +if %errorlevel% equ 0 goto xp + +rem --- Windows 10/11 --------------------------------------------------------- +echo Detected modern Windows - installing the net48 x64 flavor prerequisites. +powershell -NoProfile -ExecutionPolicy Bypass -File "%PKGROOT%install-rio.ps1" +set CORE_RC=%errorlevel% +endlocal & set "RIOJOY_APPDIR=%~dp0app" & exit /b %CORE_RC% + +:xp +rem --- Windows XP SP3 --------------------------------------------------------- +echo Detected Windows XP - installing the net40 x86 flavor prerequisites. + +rem .NET Framework 4.0 (XP's ceiling; required by the app). +reg query "HKLM\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full" /v Install 2>nul | findstr /C:"0x1" >nul +if %errorlevel% equ 0 ( + echo .NET Framework 4.0 already installed. +) else ( + if exist "%PKGROOT%vendor\xp\dotNetFx40_Full_x86_x64.exe" ( + echo Installing .NET Framework 4.0 - this takes several minutes... + "%PKGROOT%vendor\xp\dotNetFx40_Full_x86_x64.exe" /q /norestart + if errorlevel 3011 echo .NET install requests a reboot - reboot before first use. + ) else ( + echo ERROR: vendor\xp\dotNetFx40_Full_x86_x64.exe is missing from the package. + set CORE_RC=1 + goto xpdone + ) +) + +rem KB2468871 - required by the async runtime (Microsoft.Bcl.Async). +rem The update no-ops quickly when already applied, so run unconditionally. +if exist "%PKGROOT%vendor\xp\NDP40-KB2468871-v2-x86.exe" ( + echo Applying .NET 4.0 update KB2468871... + "%PKGROOT%vendor\xp\NDP40-KB2468871-v2-x86.exe" /q /norestart +) else ( + echo WARNING: vendor\xp\NDP40-KB2468871-v2-x86.exe not bundled - the app + echo will not run without KB2468871. Install it before first use. +) + +rem RioGamepadXP virtual-joystick driver (bundled from Phase 8B onward). +if exist "%PKGROOT%vendor\xp\RioGamepadXP.inf" ( + echo Installing the RioGamepadXP virtual joystick driver... + rundll32 setupapi.dll,InstallHinfSection DefaultInstall 132 %PKGROOT%vendor\xp\RioGamepadXP.inf +) else ( + echo Note: RioGamepadXP driver not bundled yet - joystick output is + echo unavailable on XP; keyboard/mouse, lamps and plasma still work. +) + +:xpdone +endlocal & set "RIOJOY_APPDIR=%~dp0app-xp" & exit /b %CORE_RC% diff --git a/deploy/install-rio.ps1 b/deploy/install-rio.ps1 index 87ac09c..a7ddcc7 100644 --- a/deploy/install-rio.ps1 +++ b/deploy/install-rio.ps1 @@ -1,4 +1,4 @@ -<# +<# .SYNOPSIS RIOJoy cockpit post-install. Installs the signed ViGEmBus virtual-controller driver (if absent). Must run elevated (postinstall.bat elevates for you). diff --git a/deploy/install.bat b/deploy/install.bat new file mode 100644 index 0000000..1e65d4f --- /dev/null +++ b/deploy/install.bat @@ -0,0 +1,54 @@ +@echo off +rem =========================================================================== +rem RIOJoy standalone install entry point - for a computer WITHOUT the +rem TeslaConsole launcher. Extract the whole zip somewhere permanent (e.g. +rem C:\games), then run this as administrator. Installs the prerequisites +rem for this Windows version (XP or 10/11) via the shared install core and +rem creates Start Menu + desktop shortcuts to the right flavor of the app. +rem Nothing auto-starts: launch RIOJoy from the shortcut when you want it. +rem See README.txt for details. +rem =========================================================================== +setlocal +title RIOJoy install + +rem --- elevate if we are not already administrator -------------------------- +net session >nul 2>&1 +if %errorlevel% neq 0 ( + rem "if errorlevel" evaluates at run time (a %var% here would be stale). + ver | findstr /C:"Version 5.1" >nul + if not errorlevel 1 ( + echo This installer must run as an Administrator user. + pause + exit /b 1 + ) + echo Requesting administrator privileges... + powershell -NoProfile -Command "Start-Process -FilePath '%~f0' -Verb RunAs" + exit /b 0 +) + +cd /d "%~dp0" + +call "%~dp0RIOJoy\install-core.bat" +set RC=%errorlevel% +if %RC% neq 0 goto done + +rem --- shortcuts (Start Menu + desktop) -------------------------------------- +rem RIOJOY_APPDIR is set by install-core.bat to app (modern) or app-xp (XP). +set EXE=%RIOJOY_APPDIR%\RioJoy.Tray.exe +if not exist "%EXE%" ( + echo ERROR: app executable not found: %EXE% + set RC=1 + goto done +) +echo Creating shortcuts... +cscript //nologo "%~dp0RIOJoy\make-shortcut.vbs" "%EXE%" "RIOJoy" "%RIOJOY_APPDIR%" + +:done +echo. +if %RC% neq 0 ( + echo install FAILED with exit code %RC%. +) else ( + echo install completed. Launch RIOJoy from the Start Menu or desktop shortcut. +) +pause +exit /b %RC% diff --git a/deploy/make-shortcut.vbs b/deploy/make-shortcut.vbs new file mode 100644 index 0000000..d871f25 --- /dev/null +++ b/deploy/make-shortcut.vbs @@ -0,0 +1,27 @@ +' make-shortcut.vbs +' Creates Start Menu (all users) and desktop shortcuts. VBScript so the same +' helper works on Windows XP (no PowerShell) and Windows 10/11. +Option Explicit +Dim shell, fso, target, name, workdir, places, place, lnk +If WScript.Arguments.Count < 3 Then + WScript.Echo "usage: make-shortcut.vbs " + WScript.Quit 1 +End If +target = WScript.Arguments(0) +name = WScript.Arguments(1) +workdir = WScript.Arguments(2) + +Set shell = CreateObject("WScript.Shell") +Set fso = CreateObject("Scripting.FileSystemObject") + +places = Array(shell.SpecialFolders("AllUsersPrograms"), shell.SpecialFolders("Desktop")) +For Each place In places + If fso.FolderExists(place) Then + Set lnk = shell.CreateShortcut(fso.BuildPath(place, name & ".lnk")) + lnk.TargetPath = target + lnk.WorkingDirectory = workdir + lnk.Description = "RIOJoy cockpit interface" + lnk.Save + WScript.Echo " shortcut: " & fso.BuildPath(place, name & ".lnk") + End If +Next diff --git a/deploy/postinstall.bat b/deploy/postinstall.bat index 32b9d7f..5a61da1 100644 --- a/deploy/postinstall.bat +++ b/deploy/postinstall.bat @@ -1,8 +1,10 @@ @echo off rem =========================================================================== -rem RIOJoy cockpit post-install entry point (run by TeslaConsole). -rem Sits beside the 'RIOJoy' payload folder; elevates, then runs -rem RIOJoy\install-rio.ps1. +rem RIOJoy cockpit post-install entry point (run by TeslaConsole after the +rem package is extracted into C:\games). Sits beside the 'RIOJoy' payload +rem folder; elevates, runs the shared install core (which picks the XP or +rem modern flavor), then removes the standalone-install files so only +rem launcher-managed files stay at the C:\games root. rem =========================================================================== setlocal title RIOJoy post-install @@ -10,6 +12,12 @@ title RIOJoy post-install rem --- elevate if we are not already administrator -------------------------- net session >nul 2>&1 if %errorlevel% neq 0 ( + rem "if errorlevel" evaluates at run time (a %var% here would be stale). + ver | findstr /C:"Version 5.1" >nul + if not errorlevel 1 ( + echo This installer must run as an Administrator user. + exit /b 1 + ) echo Requesting administrator privileges... powershell -NoProfile -Command "Start-Process -FilePath '%~f0' -Verb RunAs" exit /b 0 @@ -17,9 +25,14 @@ if %errorlevel% neq 0 ( cd /d "%~dp0" -powershell -NoProfile -ExecutionPolicy Bypass -File "%~dp0RIOJoy\install-rio.ps1" +call "%~dp0RIOJoy\install-core.bat" set RC=%errorlevel% +rem --- cleanup: cabinet deploys keep the C:\games root clean ---------------- +rem (del tolerates already-missing files, so re-runs stay idempotent) +if exist "%~dp0install.bat" del /q "%~dp0install.bat" +if exist "%~dp0README.txt" del /q "%~dp0README.txt" + echo. if %RC% neq 0 ( echo postinstall FAILED with exit code %RC%. diff --git a/deploy/uninstall-rio.ps1 b/deploy/uninstall-rio.ps1 index d5c6760..3c8423e 100644 --- a/deploy/uninstall-rio.ps1 +++ b/deploy/uninstall-rio.ps1 @@ -1,4 +1,4 @@ -<# +<# .SYNOPSIS RIOJoy cockpit pre-uninstall cleanup. Reverses install-rio.ps1: stops the running tray app, removes the logon entry, optionally uninstalls ViGEmBus, diff --git a/docs/PLAN.md b/docs/PLAN.md index bac5e75..2719f41 100644 --- a/docs/PLAN.md +++ b/docs/PLAN.md @@ -294,7 +294,8 @@ Replaces the legacy Google-Sheet → `.data` → GIMP → Script-Fu pipeline - To confirm at Phase 7: target wallpaper resolution(s); static wallpaper vs. live overlay (e.g. lit-button highlighting mirroring lamp state). -### Phase 8 — Windows XP compatibility (dual-target) — planned +### Phase 8 — Windows XP compatibility (dual-target) — in progress +(8A/8C/8D done ✅; remaining: 8B driver + 8E XP-VM/cabinet verification) Bring RIOJoy back to the original XP-era cabinets (x86, XP SP3) **without regressing Windows 10/11**. Strategy: one codebase, two flavors, **one universal deployment archive**. The mapping editor ships everywhere @@ -310,7 +311,7 @@ XP consumes pre-rendered wallpapers. | JSON | System.Text.Json → **Newtonsoft 13** | Newtonsoft 13 (STJ needs net461+; one serializer for both flavors) | | Install scripts | PowerShell | **.bat only** (XP has no in-box PowerShell) | -- **8A — Core retarget** (`net48;net40` multi-target): de-Span the +- **8A — Core retarget — done ✅** (`net48;net40` multi-target): de-Span the protocol/serial layer (≈20 uses / 11 files → `byte[]`/`ArraySegment`; System.Memory doesn't go below net45, and at 9600 baud Span buys nothing); swap System.Text.Json → Newtonsoft in `ConfigStore`/`OverlayTemplateStore` @@ -341,16 +342,20 @@ XP consumes pre-rendered wallpapers. *Staging:* the XP app is useful before the driver lands — milestone 1 ships keyboard/mouse + lamps + plasma (joystick = Null sink), the driver follows as milestone 2. -- **8C — Tray on net40/x86:** multi-target `RioJoy.Tray` (net40 drops the +- **8C — Tray on net40/x86 — done ✅:** multi-target `RioJoy.Tray` (net40 drops the ViGEm + RioJoy.Overlay references); gate `WallpaperMakerForm` + overlay generation; `WallpaperApplier` converts PNG→BMP via GDI+ before `SystemParametersInfo` (harmless on 10/11, required on XP); profile editor stays (Segoe UI falls back to Tahoma). XP cabinets consume wallpapers pre-rendered on a modern machine (`RioProfile.WallpaperPath` travels with the config). -- **8D — Packaging (decided: one universal archive, two install entry - points).** `build-package.ps1` produces a single `RIOJoy-.zip` that - deploys on **both** XP and 10/11: +- **8D — Packaging — done ✅ (one universal archive, two install entry + points).** `build-package.ps1` produces a single `RIOJoy-.zip` (~75 MB + with the offline XP redistributables) that deploys on **both** XP and 10/11; + the RioGamepadXP driver files bundle automatically once 8B lands + (warn/skip until then). The shared OS-detecting install logic lives in + `RIOJoy\install-core.bat` (pure cmd on the XP path); shortcuts via + `make-shortcut.vbs` (works on XP and 10/11 alike): - Layout: `RIOJoy\app\` (net48 x64) + `RIOJoy\app-xp\` (net40 x86) + `RIOJoy\vendor\` (ViGEmBus installer for 10/11; RioGamepadXP.sys + INF for XP; **.NET 4.0 Full + KB2468871 redistributables** so an offline XP