Skip to content

Commit a63794c

Browse files
hifihedgehogclaude
andcommitted
Add all testing/diagnostic PowerShell scripts, remove log files
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 71ed6d2 commit a63794c

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

63 files changed

+7573
-5
lines changed

tools/add_vjoy_test.ps1

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
# Add vJoy controller via UI automation and check HID state
2+
param(
3+
[int]$Count = 1,
4+
[switch]$CheckOnly
5+
)
6+
7+
Add-Type -AssemblyName UIAutomationClient
8+
Add-Type -AssemblyName UIAutomationTypes
9+
Add-Type -AssemblyName System.Windows.Forms
10+
11+
$auto = [System.Windows.Automation.AutomationElement]
12+
$cond = [System.Windows.Automation.PropertyCondition]
13+
$tree = [System.Windows.Automation.TreeScope]
14+
$invoke = [System.Windows.Automation.InvokePattern]::Pattern
15+
16+
function Find-Element($parent, $name, $controlType) {
17+
$nameCond = New-Object $cond([System.Windows.Automation.AutomationElement]::NameProperty, $name)
18+
if ($controlType) {
19+
$typeCond = New-Object $cond([System.Windows.Automation.AutomationElement]::ControlTypeProperty, $controlType)
20+
$andCond = New-Object System.Windows.Automation.AndCondition($nameCond, $typeCond)
21+
return $parent.FindFirst([System.Windows.Automation.TreeScope]::Descendants, $andCond)
22+
}
23+
return $parent.FindFirst([System.Windows.Automation.TreeScope]::Descendants, $nameCond)
24+
}
25+
26+
function Click-Element($element) {
27+
$pattern = $element.GetCurrentPattern($invoke)
28+
$pattern.Invoke()
29+
}
30+
31+
# Find PadForge window
32+
$proc = Get-Process PadForge -ErrorAction SilentlyContinue | Select-Object -First 1
33+
if (-not $proc) { Write-Host "PadForge not running!"; exit 1 }
34+
$root = $auto::FromHandle($proc.MainWindowHandle)
35+
if (-not $root) { Write-Host "Cannot find PadForge window!"; exit 1 }
36+
Write-Host "Found PadForge window"
37+
38+
if (-not $CheckOnly) {
39+
for ($i = 0; $i -lt $Count; $i++) {
40+
Write-Host "`nAdding vJoy controller #$($i+1)..."
41+
42+
# Click "Add Controller" button
43+
$addBtn = Find-Element $root "Add Controller"
44+
if (-not $addBtn) { Write-Host "Cannot find 'Add Controller' button!"; exit 1 }
45+
Click-Element $addBtn
46+
Start-Sleep -Milliseconds 500
47+
48+
# Click "vJoy" button in popup
49+
$vjoyBtn = Find-Element $root "vJoy"
50+
if (-not $vjoyBtn) { Write-Host "Cannot find 'vJoy' button in popup!"; exit 1 }
51+
Click-Element $vjoyBtn
52+
Write-Host "Clicked vJoy button"
53+
54+
# Wait for device to be created
55+
Start-Sleep -Seconds 8
56+
}
57+
}
58+
59+
# Now run the HID check
60+
Write-Host "`n=== Post-add HID Check ==="
61+
62+
# VJOYRAWPDO count
63+
$rawPdo = Get-CimInstance Win32_PnPEntity | Where-Object { $_.DeviceID -like '*VJOYRAWPDO*' }
64+
Write-Host "VJOYRAWPDO devices: $($rawPdo.Count)"
65+
$rawPdo | ForEach-Object { Write-Host " $($_.DeviceID) [$($_.Status)] err=$($_.ConfigManagerErrorCode)" }
66+
67+
# HID devices with vJoy VID/PID
68+
$hidDevices = Get-CimInstance Win32_PnPEntity | Where-Object { $_.DeviceID -like 'HID\VID_1234&PID_BEAD*' }
69+
Write-Host "HID vJoy collection devices: $($hidDevices.Count)"
70+
$hidDevices | ForEach-Object { Write-Host " $($_.DeviceID) [$($_.Status)] err=$($_.ConfigManagerErrorCode) name=$($_.Name)" }
71+
72+
# ROOT\HIDCLASS nodes
73+
$rootNodes = Get-CimInstance Win32_PnPEntity | Where-Object { $_.DeviceID -like 'ROOT\HIDCLASS\*' -and $_.Name -like '*vJoy*' }
74+
Write-Host "ROOT\HIDCLASS vJoy nodes: $($rootNodes.Count)"
75+
$rootNodes | ForEach-Object { Write-Host " $($_.DeviceID) [$($_.Status)] err=$($_.ConfigManagerErrorCode)" }
76+
77+
# Registry
78+
$base = 'HKLM:\SYSTEM\CurrentControlSet\services\vjoy\Parameters'
79+
if (Test-Path $base) {
80+
$devKeys = Get-ChildItem $base | Where-Object { $_.PSChildName -match '^Device\d+$' }
81+
Write-Host "Registry DeviceNN keys: $($devKeys.Count)"
82+
$devKeys | ForEach-Object { Write-Host " $($_.PSChildName)" }
83+
}
84+
85+
# WinMM
86+
Add-Type @'
87+
using System;
88+
using System.Runtime.InteropServices;
89+
public static class WinMM2 {
90+
[DllImport("winmm.dll")]
91+
public static extern int joyGetNumDevs();
92+
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
93+
public struct JOYCAPSW {
94+
public ushort wMid; public ushort wPid;
95+
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] public string szPname;
96+
public uint wXmin, wXmax, wYmin, wYmax, wZmin, wZmax;
97+
public uint wNumButtons, wPeriodMin, wPeriodMax;
98+
public uint wRmin, wRmax, wUmin, wUmax, wVmin, wVmax;
99+
public uint wCaps, wMaxAxes, wNumAxes, wMaxButtons;
100+
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] public string szRegKey;
101+
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] public string szOEMVxD;
102+
}
103+
[DllImport("winmm.dll", CharSet = CharSet.Unicode)]
104+
public static extern int joyGetDevCapsW(uint uJoyID, ref JOYCAPSW pjc, int cbjc);
105+
}
106+
'@
107+
$numDevs = [WinMM2]::joyGetNumDevs()
108+
$vjoyCount = 0
109+
for ($i = 0; $i -lt $numDevs; $i++) {
110+
$caps = New-Object WinMM2+JOYCAPSW
111+
$res = [WinMM2]::joyGetDevCapsW($i, [ref]$caps, [Runtime.InteropServices.Marshal]::SizeOf($caps))
112+
if ($res -eq 0 -and $caps.wMid -eq 0x1234 -and $caps.wPid -eq 0xBEAD) {
113+
$vjoyCount++
114+
Write-Host " WinMM ID=$i name='$($caps.szPname)' axes=$($caps.wNumAxes) btns=$($caps.wNumButtons)"
115+
}
116+
}
117+
Write-Host "vJoy joysticks in WinMM: $vjoyCount"

tools/capture_macros.ps1

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
Add-Type -AssemblyName UIAutomationClient
2+
Add-Type -AssemblyName UIAutomationTypes
3+
Add-Type -AssemblyName System.Drawing
4+
Add-Type -AssemblyName System.Windows.Forms
5+
Add-Type @"
6+
using System;
7+
using System.Runtime.InteropServices;
8+
public class W32 {
9+
[DllImport("user32.dll")] public static extern bool SetForegroundWindow(IntPtr hWnd);
10+
[DllImport("user32.dll")] public static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);
11+
[DllImport("user32.dll")] public static extern bool SetProcessDPIAware();
12+
[DllImport("user32.dll")] public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
13+
[DllImport("user32.dll")] public static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);
14+
[DllImport("user32.dll")] public static extern bool SetCursorPos(int X, int Y);
15+
[DllImport("user32.dll")] public static extern void mouse_event(uint dwFlags, int dx, int dy, uint dwData, IntPtr dwExtraInfo);
16+
[DllImport("kernel32.dll")] public static extern IntPtr GetConsoleWindow();
17+
[StructLayout(LayoutKind.Sequential)]
18+
public struct RECT { public int Left, Top, Right, Bottom; }
19+
public static void Click(int x, int y) {
20+
SetCursorPos(x, y);
21+
System.Threading.Thread.Sleep(100);
22+
mouse_event(0x0002, 0, 0, 0, IntPtr.Zero);
23+
mouse_event(0x0004, 0, 0, 0, IntPtr.Zero);
24+
}
25+
}
26+
"@
27+
[W32]::SetProcessDPIAware()
28+
29+
$ch = [W32]::GetConsoleWindow()
30+
if ($ch -ne [IntPtr]::Zero) { [W32]::ShowWindow($ch, 6) }
31+
32+
$log = "C:\Users\sonic\GitHub\PadForge\tools\capture_macros_log.txt"
33+
"Starting..." | Out-File $log -Encoding ascii
34+
35+
try {
36+
$proc = Get-Process PadForge -ErrorAction Stop
37+
$hwnd = $proc.MainWindowHandle
38+
39+
[W32]::ShowWindow($hwnd, 9)
40+
Start-Sleep -Milliseconds 300
41+
[W32]::MoveWindow($hwnd, 50, 30, 1280, 800, $true)
42+
Start-Sleep -Milliseconds 500
43+
[W32]::SetForegroundWindow($hwnd)
44+
Start-Sleep -Milliseconds 500
45+
46+
$root = [System.Windows.Automation.AutomationElement]::FromHandle($hwnd)
47+
48+
# Click Pad1 in sidebar
49+
$pad1 = $root.FindFirst([System.Windows.Automation.TreeScope]::Descendants,
50+
(New-Object System.Windows.Automation.PropertyCondition(
51+
[System.Windows.Automation.AutomationElement]::NameProperty, "Pad1")))
52+
if ($pad1) {
53+
$selPat = $pad1.GetCurrentPattern([System.Windows.Automation.SelectionItemPattern]::Pattern)
54+
$selPat.Select()
55+
$rect = $pad1.Current.BoundingRectangle
56+
[W32]::Click([int]($rect.Left + $rect.Width / 2), [int]($rect.Top + $rect.Height / 2))
57+
Start-Sleep -Milliseconds 1000
58+
"Selected+Clicked Pad1" | Out-File $log -Append -Encoding ascii
59+
}
60+
61+
# Click Macros tab
62+
[W32]::SetForegroundWindow($hwnd)
63+
Start-Sleep -Milliseconds 300
64+
$root = [System.Windows.Automation.AutomationElement]::FromHandle($hwnd)
65+
$macros = $root.FindFirst([System.Windows.Automation.TreeScope]::Descendants,
66+
(New-Object System.Windows.Automation.PropertyCondition(
67+
[System.Windows.Automation.AutomationElement]::NameProperty, "Macros")))
68+
if ($macros) {
69+
$rect = $macros.Current.BoundingRectangle
70+
[W32]::Click([int]($rect.Left + $rect.Width / 2), [int]($rect.Top + $rect.Height / 2))
71+
Start-Sleep -Milliseconds 1000
72+
"Clicked Macros tab" | Out-File $log -Append -Encoding ascii
73+
}
74+
75+
# Now click "Volume Control" in the macro list
76+
# From the screenshot we can see the list. Volume Control is the 2nd item.
77+
# The list area starts around X=320..680 (physical), items at Y~250(Quick Melee), Y~308(Volume Control), Y~367(Rapid Fire A)
78+
# Window is at (50,30), 1800x1200 physical (1280x800 logical at 150% DPI)
79+
# From screenshot: "Volume Control" text is roughly at row 2 of the list
80+
# List left edge ~320px from window left, item height ~60px physical
81+
# First item Y center ~ 250 from window top, second ~ 310
82+
83+
$wr = New-Object W32+RECT
84+
[W32]::GetWindowRect($hwnd, [ref]$wr)
85+
86+
# Click Volume Control - second list item
87+
# From the screenshot proportions: list starts at ~22% from left, items at ~26%, 33%, 40% from top
88+
$clickX = $wr.Left + [int](0.37 * ($wr.Right - $wr.Left)) # center of list area
89+
$clickY = $wr.Top + [int](0.35 * ($wr.Bottom - $wr.Top)) # second item
90+
[W32]::Click($clickX, $clickY)
91+
Start-Sleep -Milliseconds 500
92+
"Clicked Volume Control area at ($clickX, $clickY)" | Out-File $log -Append -Encoding ascii
93+
94+
# Bring to front and capture
95+
[W32]::SetForegroundWindow($hwnd)
96+
Start-Sleep -Milliseconds 500
97+
98+
[W32]::GetWindowRect($hwnd, [ref]$wr)
99+
$w = $wr.Right - $wr.Left
100+
$h = $wr.Bottom - $wr.Top
101+
102+
$bmp = New-Object System.Drawing.Bitmap($w, $h)
103+
$g = [System.Drawing.Graphics]::FromImage($bmp)
104+
$g.CopyFromScreen($wr.Left, $wr.Top, 0, 0, (New-Object System.Drawing.Size($w, $h)))
105+
$g.Dispose()
106+
107+
$pngPath = "C:\Users\sonic\GitHub\PadForge\screenshots\macros.png"
108+
$bmp.Save($pngPath, [System.Drawing.Imaging.ImageFormat]::Png)
109+
$bmp.Dispose()
110+
"Screenshot saved" | Out-File $log -Append -Encoding ascii
111+
"DONE" | Out-File $log -Append -Encoding ascii
112+
113+
} catch {
114+
"ERROR: $_" | Out-File $log -Append -Encoding ascii
115+
}

tools/check_created.ps1

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
[xml]$x = Get-Content 'C:\PadForge\PadForge.xml'
2+
$nodes = $x.PadForgeSettings.AppSettings.SlotCreated.ChildNodes
3+
for ($i=0; $i -lt 4; $i++) {
4+
Write-Host "SlotCreated[$i] = $($nodes[$i].InnerText)"
5+
}

tools/check_node_status.ps1

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
Add-Type -TypeDefinition @"
2+
using System;
3+
using System.Runtime.InteropServices;
4+
public class CfgMgr {
5+
[DllImport("cfgmgr32.dll", CharSet = CharSet.Unicode)]
6+
public static extern int CM_Locate_DevNodeW(out int pdnDevInst, string pDeviceID, int ulFlags);
7+
[DllImport("cfgmgr32.dll")]
8+
public static extern int CM_Get_DevNode_Status(out int pulStatus, out int pulProblemNumber, int dnDevInst, int ulFlags);
9+
[DllImport("cfgmgr32.dll")]
10+
public static extern int CM_Disable_DevNode(int dnDevInst, int ulFlags);
11+
[DllImport("cfgmgr32.dll")]
12+
public static extern int CM_Enable_DevNode(int dnDevInst, int ulFlags);
13+
public const int CM_DISABLE_HARDWARE = 0x4;
14+
}
15+
"@ -ErrorAction SilentlyContinue
16+
17+
$devInst = 0
18+
$cr = [CfgMgr]::CM_Locate_DevNodeW([ref]$devInst, 'ROOT\HIDCLASS\0000', 0)
19+
Write-Host "Locate: cr=$cr devInst=$devInst"
20+
if ($cr -eq 0 -and $devInst -ne 0) {
21+
$s = 0; $p = 0
22+
[CfgMgr]::CM_Get_DevNode_Status([ref]$s, [ref]$p, $devInst, 0) | Out-Null
23+
$needRestart = ($s -band 0x01000000) -ne 0
24+
Write-Host ("Status=0x{0:X8} DN_NEED_RESTART={1} Problem={2}" -f $s, $needRestart, $p)
25+
26+
# Count joy.cpl vJoy entries
27+
$jc = (Get-CimInstance Win32_PnPEntity -ErrorAction SilentlyContinue | Where-Object { $_.DeviceID -like '*VJOYRAWPDO*' } | Measure-Object).Count
28+
Write-Host "joyCpl vJoy count: $jc"
29+
30+
# Check registry
31+
$baseKey = 'HKLM:\SYSTEM\CurrentControlSet\services\vjoy\Parameters'
32+
if (Test-Path $baseKey) {
33+
$devKeys = Get-ChildItem $baseKey -ErrorAction SilentlyContinue | Where-Object { $_.PSChildName -match '^Device\d+$' }
34+
Write-Host ("Registry DeviceNN keys: " + ($devKeys | Measure-Object).Count)
35+
}
36+
}

tools/check_slot_config.ps1

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
[xml]$x = Get-Content 'C:\PadForge\PadForge.xml'
2+
$types = $x.PadForgeSettings.AppSettings.SlotControllerTypes
3+
$created = $x.PadForgeSettings.AppSettings.SlotCreated
4+
for ($i=0; $i -lt 4; $i++) {
5+
$t = $types.ChildNodes[$i].InnerText
6+
$c = $created.ChildNodes[$i].InnerText
7+
Write-Host "Slot $i : type=$t created=$c"
8+
}

tools/check_vjoy_state.ps1

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# Check vJoy device state: registry keys, device nodes, and PnP entities
2+
Write-Host "=== vJoy Registry Descriptors ==="
3+
$baseKey = 'HKLM:\SYSTEM\CurrentControlSet\services\vjoy\Parameters'
4+
if (Test-Path $baseKey) {
5+
$subkeys = Get-ChildItem $baseKey -ErrorAction SilentlyContinue | Where-Object { $_.PSChildName -match '^Device\d+$' }
6+
Write-Host "DeviceNN keys: $($subkeys.Count)"
7+
foreach ($k in $subkeys) {
8+
$desc = $k.GetValue('HidReportDescriptor')
9+
$size = if ($desc) { $desc.Length } else { 0 }
10+
Write-Host " $($k.PSChildName) - descriptor $size bytes"
11+
}
12+
} else {
13+
Write-Host "vjoy Parameters key not found"
14+
}
15+
16+
Write-Host ""
17+
Write-Host "=== vJoy Device Nodes (pnputil) ==="
18+
$pnpOutput = & pnputil /enum-devices /class HIDClass 2>&1 | Out-String
19+
$lines = $pnpOutput -split "`n"
20+
$inVjoy = $false
21+
foreach ($line in $lines) {
22+
if ($line -match 'Instance ID') { $currentId = $line }
23+
if ($line -match 'vJoy' -or $line -match 'vjoy') {
24+
$inVjoy = $true
25+
Write-Host $currentId.Trim()
26+
Write-Host $line.Trim()
27+
}
28+
if ($inVjoy -and $line -match 'Status') {
29+
Write-Host $line.Trim()
30+
$inVjoy = $false
31+
Write-Host ""
32+
}
33+
}
34+
35+
Write-Host "=== vJoy PnP Entities ==="
36+
Get-CimInstance Win32_PnPEntity | Where-Object { $_.Name -like '*vJoy*' } | ForEach-Object {
37+
Write-Host " $($_.Name) | Status=$($_.Status) | Error=$($_.ConfigManagerErrorCode)"
38+
}
39+
40+
Write-Host ""
41+
Write-Host "Done."

tools/convert_and_restore.ps1

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
Add-Type -AssemblyName System.Drawing
2+
$png = [System.Drawing.Image]::FromFile('C:\Users\sonic\GitHub\PadForge\screenshots\macros.png')
3+
$jpgEncoder = [System.Drawing.Imaging.ImageCodecInfo]::GetImageEncoders() | Where-Object { $_.MimeType -eq 'image/jpeg' }
4+
$encoderParams = New-Object System.Drawing.Imaging.EncoderParameters(1)
5+
$encoderParams.Param[0] = New-Object System.Drawing.Imaging.EncoderParameter([System.Drawing.Imaging.Encoder]::Quality, 90L)
6+
$png.Save('C:\Users\sonic\GitHub\PadForge\docs\images\macros.jpg', $jpgEncoder, $encoderParams)
7+
$png.Dispose()
8+
Write-Host 'JPG saved'
9+
10+
Copy-Item 'C:\PadForge\PadForge.xml.bak' 'C:\PadForge\PadForge.xml' -Force
11+
Write-Host 'XML backup restored'

tools/deploy.ps1

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Deploy PadForge.exe to C:\PadForge\
2+
$src = 'C:\Users\sonic\GitHub\PadForge\publish\PadForge.exe'
3+
$dst = 'C:\PadForge\PadForge.exe'
4+
5+
# Kill any running PadForge
6+
$procs = Get-Process -Name PadForge -ErrorAction SilentlyContinue
7+
if ($procs) {
8+
$procs | Stop-Process -Force
9+
for ($i = 0; $i -lt 15; $i++) {
10+
Start-Sleep -Seconds 1
11+
if (-not (Get-Process -Name PadForge -ErrorAction SilentlyContinue)) { break }
12+
}
13+
}
14+
15+
# Extra wait for file handle release
16+
Start-Sleep -Seconds 2
17+
18+
Copy-Item $src $dst -Force
19+
if ($?) {
20+
Write-Host "Deployed successfully"
21+
Start-Process $dst
22+
Write-Host "PadForge launched"
23+
} else {
24+
Write-Host "FAILED to copy"
25+
}

tools/dump_addctrl.ps1

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
Add-Type -AssemblyName UIAutomationClient
2+
Add-Type -AssemblyName UIAutomationTypes
3+
$ae = [System.Windows.Automation.AutomationElement]
4+
$ct = [System.Windows.Automation.ControlType]
5+
$tree = [System.Windows.Automation.TreeScope]
6+
$out = "C:\Users\sonic\GitHub\PadForge\tools\addctrl_dump.txt"
7+
$cond = New-Object System.Windows.Automation.PropertyCondition($ae::NameProperty, "PadForge")
8+
$win = $ae::RootElement.FindFirst($tree::Children, $cond)
9+
$lines = @()
10+
if (-not $win) { "No window" | Out-File $out -Encoding utf8; exit }
11+
$navCond = New-Object System.Windows.Automation.PropertyCondition($ae::NameProperty, "Add Controller")
12+
$items = $win.FindAll($tree::Descendants, $navCond)
13+
$lines += "Found $($items.Count) 'Add Controller' elements"
14+
foreach ($item in $items) {
15+
$lines += " Type=$($item.Current.ControlType.ProgrammaticName) AutoId=$($item.Current.AutomationId) Class=$($item.Current.ClassName)"
16+
$patterns = $item.GetSupportedPatterns()
17+
foreach ($p in $patterns) {
18+
$lines += " Pattern: $($p.ProgrammaticName)"
19+
}
20+
}
21+
$lines | Out-File $out -Encoding utf8 -Force

0 commit comments

Comments
 (0)