Created
December 27, 2025 04:54
-
-
Save kiranwayne/f264fd3408ca5087692852fa16554b6a to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # ================================================================================= | |
| # KvmWatcher_v4.1.ps1 - Native In-Memory DDC/CI (Targeted) | |
| # | |
| # Description: Embeds C# code to access the Windows DXVA2 API directly. | |
| # Filters commands to ONLY affect the specified monitor name. | |
| # Reacts instantly to USB events. | |
| # ================================================================================= | |
| # --- Configuration --- | |
| $dp_value = 15 | |
| $hdmi_value = 17 | |
| # The name to match (Case-insensitive partial match) | |
| # Based on your previous logs, this is "DELL S2721DGF" | |
| $target_monitor_name = "DELL S2721DGF" | |
| $kvm_device_ids = @( | |
| 'HID\VID_413C&PID_2010&MI_00\9&5D7FD22&0&0000', | |
| 'HID\VID_046D&PID_C539&MI_00\8&279BBDB6&0&0000', | |
| 'HID\VID_046D&PID_C539&MI_01&COL01\8&1BCA673&0&0000' | |
| ) | |
| # --- Embedded C# Code for Native Monitor Control --- | |
| $MonitorControlSource = @" | |
| using System; | |
| using System.Runtime.InteropServices; | |
| using System.Collections.Generic; | |
| public class MonitorControl | |
| { | |
| [DllImport("user32.dll")] | |
| private static extern bool EnumDisplayMonitors(IntPtr hdc, IntPtr lprcClip, MonitorEnumDelegate lpfnEnum, IntPtr dwData); | |
| [DllImport("dxva2.dll", SetLastError = true)] | |
| private static extern bool GetPhysicalMonitorsFromHMONITOR(IntPtr hMonitor, uint dwPhysicalMonitorArraySize, [Out] PHYSICAL_MONITOR[] pPhysicalMonitorArray); | |
| [DllImport("dxva2.dll", SetLastError = true)] | |
| private static extern bool GetNumberOfPhysicalMonitorsFromHMONITOR(IntPtr hMonitor, out uint pdwNumberOfPhysicalMonitors); | |
| [DllImport("dxva2.dll", SetLastError = true)] | |
| private static extern bool DestroyPhysicalMonitors(uint dwPhysicalMonitorArraySize, [In] PHYSICAL_MONITOR[] pPhysicalMonitorArray); | |
| [DllImport("dxva2.dll", SetLastError = true)] | |
| private static extern bool SetVCPFeature(IntPtr hMonitor, byte bVCPCode, uint dwNewValue); | |
| private delegate bool MonitorEnumDelegate(IntPtr hMonitor, IntPtr hdcMonitor, ref Rect lprcMonitor, IntPtr dwData); | |
| [StructLayout(LayoutKind.Sequential)] | |
| public struct Rect { | |
| public int left; | |
| public int top; | |
| public int right; | |
| public int bottom; | |
| } | |
| [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] | |
| public struct PHYSICAL_MONITOR { | |
| public IntPtr hPhysicalMonitor; | |
| [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] | |
| public string szPhysicalMonitorDescription; | |
| } | |
| // Updated signature to accept a target name | |
| public static void SetInputSource(uint inputValue, string targetName) | |
| { | |
| EnumDisplayMonitors(IntPtr.Zero, IntPtr.Zero, | |
| delegate(IntPtr hMonitor, IntPtr hdcMonitor, ref Rect lprcMonitor, IntPtr dwData) | |
| { | |
| uint count; | |
| if (!GetNumberOfPhysicalMonitorsFromHMONITOR(hMonitor, out count)) return true; | |
| PHYSICAL_MONITOR[] physicalMonitors = new PHYSICAL_MONITOR[count]; | |
| if (!GetPhysicalMonitorsFromHMONITOR(hMonitor, count, physicalMonitors)) return true; | |
| foreach (var physMonitor in physicalMonitors) | |
| { | |
| // Only proceed if the monitor description contains our target name | |
| if (physMonitor.szPhysicalMonitorDescription.IndexOf(targetName, StringComparison.OrdinalIgnoreCase) >= 0) | |
| { | |
| // VCP Code 60 is Input Select | |
| SetVCPFeature(physMonitor.hPhysicalMonitor, 0x60, inputValue); | |
| // Optional: We could return false here to stop enumerating if we only expect one monitor, | |
| // but continuing is safer in case you have two of the same monitor. | |
| } | |
| } | |
| DestroyPhysicalMonitors(count, physicalMonitors); | |
| return true; | |
| }, IntPtr.Zero); | |
| } | |
| } | |
| "@ | |
| # Compile the C# code into memory | |
| try { | |
| Add-Type -TypeDefinition $MonitorControlSource -Language CSharp | |
| } catch { | |
| # Ignore error if type already exists | |
| } | |
| # --- Functions --- | |
| function Is-KvmOnPc { | |
| $devices_on_pc = Get-PnpDevice -InstanceId $kvm_device_ids -Status 'OK' -ErrorAction SilentlyContinue | |
| return [bool]$devices_on_pc | |
| } | |
| function Sync-MonitorState { | |
| Write-Host "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss'): KVM Event detected. Syncing..." | |
| $is_kvm_on_pc = Is-KvmOnPc | |
| # We now pass the $target_monitor_name to the C# function | |
| if ($is_kvm_on_pc) { | |
| Write-Host " -> KVM found on PC. Forcing DisplayPort ($dp_value) on '$target_monitor_name'..." | |
| [MonitorControl]::SetInputSource($dp_value, $target_monitor_name) | |
| } | |
| else { | |
| Write-Host " -> KVM is AWAY. Forcing HDMI ($hdmi_value) on '$target_monitor_name'..." | |
| [MonitorControl]::SetInputSource($hdmi_value, $target_monitor_name) | |
| } | |
| } | |
| # --- Main -------------------------------------------------------------------- | |
| Write-Host "Starting KVM 'Native Speed' Watcher (Targeted). Press Ctrl+C to exit." | |
| $script:lastKvmState = Is-KvmOnPc | |
| Write-Host "Initial KVM state: $(if($script:lastKvmState){'ON PC'} else {'AWAY'}) (No action taken)" | |
| $query = "SELECT * FROM Win32_DeviceChangeEvent WHERE EventType = 2 OR EventType = 3" | |
| try { | |
| Register-CimIndicationEvent -Query $query -SourceIdentifier 'KvmUsbChangeWatcher' | |
| Write-Host "Watcher is active (Native Mode)..." | |
| while ($true) { | |
| $event = Wait-Event -SourceIdentifier 'KvmUsbChangeWatcher' | |
| $current = Is-KvmOnPc | |
| if ($current -ne $script:lastKvmState) { | |
| $script:lastKvmState = $current | |
| Sync-MonitorState | |
| } | |
| Remove-Event -EventIdentifier $event.EventIdentifier | |
| } | |
| } | |
| finally { | |
| Write-Host "Stopping..." | |
| Unregister-Event -SourceIdentifier 'KvmUsbChangeWatcher' -ErrorAction SilentlyContinue | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment