Files
psxrecomp/tools/click_launcher.ps1
T
Matthew Stanley 5f0654f188 launcher: Phase 5 — controller device picker + DualShock toggle
Per-player input routing with a real device dropdown (None / Keyboard /
each plugged-in SDL controller) and a digital-vs-DualShock pad-type toggle,
wired end-to-end through the runtime.

- sio.c/.h: per-slot pad state (pad_buttons[2]) + per-slot pad type. Analog
  poll emulation (id 0x73 + 4 stick axes) when a slot is in DualShock mode;
  digital (0x41) stays the default so existing games are unaffected. New
  setters: sio_set_pad_state_slot / sio_set_pad_analog / sio_set_pad_connected,
  getters sio_get_pad_{buttons,connected,analog}_slot.
- config_loader: settings.toml [controller] p1_device/p2_device (none/keyboard/
  <SDL GUID>) + p1_analog/p2_analog; load + save round-trip.
- main.cpp: replaced the single auto-opened controller with a two-slot
  PlayerInput model. Devices opened by GUID (with a first-free fallback so a
  re-paired pad still works), keyboard or controller feeds each PSX port, and
  analog stick axes drive the DualShock poll. Hot-plug re-resolves both slots.
  Defaults: P1 keyboard/digital, P2 none.
- launcher: enumerates SDL controllers (name+GUID); each player card has a
  custom click-to-open dropdown (option list injected via data-rml, the
  data-for path being unreliable in this RmlUi build) and a DualShock switch
  that drives the pad art (digital/analog) + status line. Zero-config default
  selects the first plugged-in pad. A saved-but-unplugged controller is kept
  as an "(offline)" option so the selection survives. Choices persist on launch.
- debug_server: pad_status now reports both slots' buttons + connected + analog.

UI polish from review:
- Removed the redundant disc-verdict widget (the green checks already convey it);
  Change ISO now anchors to the disc panel instead of floating at the page top.
- Added a prominent "Settings" button in the top bar (renderer/SS/AA/etc. were
  only reachable via the easily-missed footer link).
- Fixed the player-card asymmetry on toggle: status text no longer wraps and the
  player card body is a fixed height, so the pad art renders at a consistent size
  (measured 216x110 analog vs 219x110 digital) regardless of pad type.

Verified: device dropdown enumerates a real DualSense; selection + DualShock
toggle update the card; pad_status confirms per-slot connect + analog routing
(slot0 analog / slot1 digital and the reverse); default keyboard P1 unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-12 15:15:08 -07:00

50 lines
2.4 KiB
PowerShell

# Synthetic left-click at client coords (X,Y) inside the psx-runtime launcher
# window, then (optionally) screenshot the window client area to -Out.
# Coords are in the same space as shot_launcher.ps1's screenshot (client px).
param([int]$X = 0, [int]$Y = 0, [string]$Out = "")
$p = Get-Process psx-runtime -ErrorAction SilentlyContinue | Where-Object { $_.MainWindowHandle -ne 0 } | Select-Object -First 1
if (-not $p) { Write-Output "no window"; exit 1 }
$sig = @'
using System;
using System.Runtime.InteropServices;
public class C {
[DllImport("user32.dll")] public static extern bool SetWindowPos(IntPtr h, IntPtr after, int x, int y, int cx, int cy, uint flags);
[DllImport("user32.dll")] public static extern bool SetForegroundWindow(IntPtr h);
[DllImport("user32.dll")] public static extern bool GetClientRect(IntPtr h, out RECT r);
[DllImport("user32.dll")] public static extern bool ClientToScreen(IntPtr h, ref POINT p);
[DllImport("user32.dll")] public static extern bool SetCursorPos(int x, int y);
[DllImport("user32.dll")] public static extern void mouse_event(uint f, uint dx, uint dy, uint d, IntPtr e);
public struct RECT { public int left, top, right, bottom; }
public struct POINT { public int x, y; }
}
'@
Add-Type -TypeDefinition $sig 2>$null
$h = $p.MainWindowHandle
[C]::SetWindowPos($h, [IntPtr](-1), 0,0,0,0, 0x40 -bor 0x1 -bor 0x2) | Out-Null
[C]::SetForegroundWindow($h) | Out-Null
Start-Sleep -Milliseconds 300
$tl = New-Object C+POINT
[C]::ClientToScreen($h, [ref]$tl) | Out-Null
$sx = $tl.x + $X; $sy = $tl.y + $Y
[C]::SetCursorPos($sx, $sy) | Out-Null
Start-Sleep -Milliseconds 80
[C]::mouse_event(0x0002, 0,0,0,[IntPtr]::Zero) # LEFTDOWN
Start-Sleep -Milliseconds 50
[C]::mouse_event(0x0004, 0,0,0,[IntPtr]::Zero) # LEFTUP
Write-Output ("clicked client (" + $X + "," + $Y + ") -> screen (" + $sx + "," + $sy + ")")
Start-Sleep -Milliseconds 250
if ($Out -ne "") {
$r = New-Object C+RECT
[C]::GetClientRect($h, [ref]$r) | Out-Null
$tl2 = New-Object C+POINT
[C]::ClientToScreen($h, [ref]$tl2) | Out-Null
$w = $r.right - $r.left; $ht = $r.bottom - $r.top
Add-Type -AssemblyName System.Drawing
$bmp = New-Object System.Drawing.Bitmap($w, $ht)
$g = [System.Drawing.Graphics]::FromImage($bmp)
$g.CopyFromScreen($tl2.x, $tl2.y, 0, 0, (New-Object System.Drawing.Size($w, $ht)))
$bmp.Save($Out, [System.Drawing.Imaging.ImageFormat]::Png)
$g.Dispose(); $bmp.Dispose()
Write-Output ("saved " + $Out)
}