From 990ad525632c37c99f5e439228edb4ccca32c48a Mon Sep 17 00:00:00 2001 From: Joe DiPrima Date: Sat, 8 Aug 2026 15:58:12 -0500 Subject: [PATCH] podprobe: emit boot-STABLE panel identities + ready-to-paste monitor:id: lines Adds a section resolving each screen's panel identity via the SAME Win32 API the game uses (EnumDisplayDevices on the display's MONITOR child) rather than the WmiMonitorID query above -- if probe and engine read different sources the printed fragments could fail to match what the engine tests. Verified on the dev box: probe and engine emit byte-identical identities. Answers the open [T3] multi-panel question WITHOUT deploying a build (pure OS data). When one EDID code appears on SEVERAL panels (identical MFD models) it detects the collision and emits the per-connector UID form instead. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_018SgmXGNMXavXiafKXf9MDC --- tools/podprobe.ps1 | 88 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) diff --git a/tools/podprobe.ps1 b/tools/podprobe.ps1 index 7cbec03..31ed012 100644 --- a/tools/podprobe.ps1 +++ b/tools/podprobe.ps1 @@ -82,6 +82,94 @@ try { } catch { W " (EDID query failed -- normal over some remote sessions: $_)" } W "" +# --------------------------------------------------------------------------- +# BOOT-STABLE panel identity. Windows renumbers \\.\DISPLAYn and reorders the +# enumeration when a panel is power-cycled or re-cabled, so binding the pod by +# index or device name is fragile (Nick, 2026-08-07: "the order changed ... even +# if the visual desktop tool looks the same"). Bind by the panel's own EDID +# identity instead: glass_layout.cfg accepts `monitor:id:`. +# +# This deliberately calls the SAME Win32 API the game does (EnumDisplayDevices +# on the display's MONITOR child) rather than the WmiMonitorID above -- if the +# probe and the engine read different sources, the fragments printed here might +# not be what the engine actually matches against. +# --------------------------------------------------------------------------- +W "---- BOOT-STABLE panel identity (paste these into glass_layout.cfg) ----" +try { + if (-not ("BTDisp" -as [type])) { + Add-Type -TypeDefinition @' +using System; +using System.Runtime.InteropServices; +public class BTDisp { + [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)] + public struct DISPLAY_DEVICE { + public int cb; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=32)] public string DeviceName; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=128)] public string DeviceString; + public int StateFlags; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=128)] public string DeviceID; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=128)] public string DeviceKey; + } + [DllImport("user32.dll", CharSet=CharSet.Ansi)] + public static extern bool EnumDisplayDevicesA(string dev, uint num, ref DISPLAY_DEVICE dd, uint flags); + public static string MonitorId(string display) { + DISPLAY_DEVICE dd = new DISPLAY_DEVICE(); + dd.cb = Marshal.SizeOf(typeof(DISPLAY_DEVICE)); + // 0x1 = EDD_GET_DEVICE_INTERFACE_NAME (richer path, includes connector UID) + if (!EnumDisplayDevicesA(display, 0, ref dd, 0x1)) { + dd = new DISPLAY_DEVICE(); + dd.cb = Marshal.SizeOf(typeof(DISPLAY_DEVICE)); + if (!EnumDisplayDevicesA(display, 0, ref dd, 0)) return ""; + } + return dd.DeviceID; + } +} +'@ + } + $codes = @{} + $rows = @() + foreach ($s in [System.Windows.Forms.Screen]::AllScreens) { + $sid = [BTDisp]::MonitorId($s.DeviceName) + # EDID PnP code = 3 letters + 4 hex digits (AUO10ED, DEL4231) + $code = "" + if ($sid -match '[\\#\?]([A-Za-z]{3}[0-9A-Fa-f]{4})[\\#\?]') { $code = $Matches[1] } + elseif ($sid -match '([A-Za-z]{3}[0-9A-Fa-f]{4})') { $code = $Matches[1] } + $rows += [pscustomobject]@{ Dev=$s.DeviceName; Prim=$s.Primary; Sid=$sid; Code=$code + X=$s.Bounds.X; Y=$s.Bounds.Y; W=$s.Bounds.Width; H=$s.Bounds.Height } + if ($code -ne "") { $codes[$code] = 1 + $(if ($codes.ContainsKey($code)) { $codes[$code] } else { 0 }) } + } + foreach ($r in $rows) { + W (" {0}{1} {2},{3} {4}x{5}" -f $r.Dev, $(if ($r.Prim) { " *PRIMARY*" } else { "" }), $r.X, $r.Y, $r.W, $r.H) + W (" stable-id : {0}" -f $(if ($r.Sid) { $r.Sid } else { "(unavailable)" })) + if ($r.Code -ne "" -and $codes[$r.Code] -gt 1) { + # Same model on more than one output: the EDID code alone is ambiguous. + # The connector UID in the tail is what separates them. + $uid = "" + if ($r.Sid -match '(UID[0-9]+)') { $uid = $Matches[1] } + if ($uid -ne "") { + W (" cfg form : monitor:id:{0} <-- code '{1}' is on {2} panels, so use the UID" -f $uid, $r.Code, $codes[$r.Code]) + } else { + W (" cfg form : (AMBIGUOUS -- '{0}' appears on {1} panels and no UID found;" -f $r.Code, $codes[$r.Code]) + W " use a longer unique substring of stable-id above)" + } + } elseif ($r.Code -ne "") { + W (" cfg form : monitor:id:{0}" -f $r.Code) + } else { + W " cfg form : (no EDID code parsed -- use a substring of stable-id)" + } + } + $dupes = ($codes.GetEnumerator() | Where-Object { $_.Value -gt 1 } | Measure-Object).Count + if ($dupes -gt 0) { + W "" + W (" NOTE: {0} EDID code(s) appear on more than one panel (identical models)." -f $dupes) + W " Those lines use the connector UID instead, which is per-output." + } + W "" + W " Run this again AFTER a reboot or a panel power-cycle: the device names" + W " and ordering above may move, but stable-id / cfg form must NOT." +} catch { W " (stable-identity probe failed: $_)" } +W "" + W "---- SERIAL PORTS (the RIO board lives on one of these) ----" try { $sp = Get-CimInstance Win32_SerialPort