Make your monitors' inputs follow a dumb USB switch, on Windows.
If you share one keyboard and mouse between two PCs with a cheap USB switch (Benfei and friends), pressing its button moves the peripherals but leaves both monitors showing the wrong machine. This watcher fixes that: press the button, and the monitors follow.
It also documents, with measurements, exactly which parts of this are impossible — because a lot of monitors lie about what they support, and working that out took far longer than writing the script. See docs/FINDINGS.md.
The USB switch has no software interface — nothing can ask it which PC it points at. So the shared peripherals themselves are used as the signal: if your mouse and keyboard are present on this PC, the switch points here; if they vanish, it points at the other machine. On each transition the watcher writes the monitors' input-select register over DDC/CI.
One press of the button, ~190 ms later the picture follows.
Measured on an AOC Q27G2G4 and an LG UltraGear 27GN800-B:
| Situation | Standard monitor (AOC) | LG with the 0xF4 quirk |
|---|---|---|
| Button press → other PC | automatic | automatic |
| Button press → back to this PC | automatic | not possible |
| Other PC sleeps/disconnects | automatic | automatic (panel's own auto-input) |
The one hole is reclaiming an LG-style panel on a button press while the other machine is still driving it. That is not a missing feature in this tool — such panels stop answering DDC entirely on any input they are not currently displaying, so there is nothing to send a command to. Even a brightness read fails. Eleven input codes, the raw NVAPI sidechannel, and a DisplayPort hot-plug with Auto Input Switch enabled were all tried; the full evidence is in docs/FINDINGS.md.
If you need that last case automated, it takes hardware that interrupts the other machine's video cable — options and costs in docs/HARDWARE.md.
- Windows 10/11 x64
- Both PCs cabled to each monitor on different inputs (e.g. DisplayPort from one, HDMI from the other)
- Monitors supporting DDC/CI (enable it in the OSD if there is a toggle)
- ControlMyMonitor
- Only for LG panels that ignore
VCP 0x60: deskmux and an NVIDIA GPU driving the monitor - No admin rights needed
See tools/README.md for downloads and checksums. The tools are not vendored here.
Download ControlMyMonitor (and deskmux if you have an affected LG) and note the
paths. The shipped config assumes D:\Monitor\controlmymonitor\ and
D:\Monitor\deskmux\.
cd scripts
.\discover.ps1This prints each monitor's Short Monitor ID (use that, not \\.\DISPLAYn —
the numbering shifts) and its Input Select register with the input codes the
panel admits to having. Common codes: 15 = DisplayPort1, 16 = DisplayPort2,
17 = HDMI1, 18 = HDMI2.
Verify which code is which physical port rather than assuming. Switch a
monitor by hand and read the value back, or set a value and look at the screen.
Guessing here cost real time: a monitor reported 17 while still displaying
DisplayPort, because 17 was an empty port it had silently refused to select.
.\discover.ps1 -WatchDevicesPress the switch button during the countdown, wait a few seconds, press it again. The script reports the VID/PID pairs that appeared and disappeared — those are your shared peripherals.
Edit the CONFIG block at the top of scripts/watch-usb-switch.ps1:
$watchedDevices = @('VID_1038&PID_185A', 'VID_1E7D&PID_2FEE')
$stdMonitor = "AOC2702" # Short Monitor ID
$stdHere = 15 # this PC's input
$stdAway = 18 # the other PC's input
$lgModel = "GN800" # "" to disable LG handling entirely
$lgAway = "hdmi1" # the other PC's input on the LGIf your monitors all switch fine with ControlMyMonitor, set $lgModel = "" and
ignore deskmux completely.
powershell -NoProfile -ExecutionPolicy Bypass -File .\watch-usb-switch.ps1Press the button both ways and watch scripts/switch.log:
2026-10-10 12:52:50 -> other PC: AOC2702 to 18, LG to hdmi1 (186ms)
2026-10-10 12:53:02 -> this PC: AOC2702 to 15 (5ms)
Edit the script path inside scripts/launch-watcher.vbs, then drop a copy into
your Startup folder:
Copy-Item .\launch-watcher.vbs "$([Environment]::GetFolderPath('Startup'))\"Run it once to start without logging out:
wscript.exe .\launch-watcher.vbsIt runs hidden. Task Scheduler works too, but registering a task needs elevation; the Startup folder does not.
This is what makes a panel come back on its own when the other machine sleeps or is unplugged — the one case the software cannot cover for LG-style panels.
| Setting | Meaning |
|---|---|
$cmm, $deskmux |
Tool paths |
$watchedDevices |
VID/PID fragments matched against InstanceId |
$stdMonitor |
Short Monitor ID of the DDC-standard monitor |
$stdHere / $stdAway |
VCP 0x60 values for this PC / the other PC |
$lgModel |
deskmux capability model string; "" disables LG handling |
$lgAway |
deskmux input name for the other PC |
$lgFast |
-fast (~214 ms vs ~1200 ms); verify per machine |
$pollMs |
Poll interval; detection itself costs ~260 ms |
Nothing happens at all. Check switch.log exists and shows
watcher started. If there is no log, the script is not running — start it in a
visible console to see the error.
The log shows switches but the picture doesn't change. The monitor is accepting writes and ignoring them. Confirm DDC works at all by changing brightness over DDC; if brightness moves but input doesn't, you have the LG problem — see docs/FINDINGS.md.
It switches to a black screen. The configured code points at an input with nothing on it. Re-check step 2.
The LG switches away but never comes back. Expected. See the table above.
It switches the wrong monitor. deskmux indices are renumbered whenever a display is enabled or disabled. The watcher resolves by model string at startup to avoid this; restart it after changing your display layout.
Writing values by hand from Git Bash does nothing. Git Bash mangles /flag
arguments and \\.\DISPLAYn\Monitor0 strings. Use MSYS_NO_PATHCONV=1 or a
.bat file. This one produced a completely wrong conclusion during development.
- ControlMyMonitor and MultiMonitorTool by Nir Sofer
- deskmux by klaidliadon — the LG sidechannel implementation this depends on
- ddcutil's
LG input source wiki
for the
0xF4value table - display-switch — a maintained, cross-platform tool for the same use case, if you want something less hand-rolled (standard DDC only, so it cannot drive the LG sidechannel)
MIT — see LICENSE.