Skip to content

Proposal: Set-MonitorInput / Get-MonitorInput cmdlets for VCP 0x60 (Input Select) #5

@yotsuda

Description

@yotsuda

Thanks for MonitorConfig — I've been using it as a base for some 2-PC monitor sharing scripting and noticed that VCP 0x60 (Input Select) is documented in VCPFeatures.csv and reachable via Set-MonitorVCPValue, but doesn't have a typed wrapper the way Brightness / Contrast / Color do. Wanted to gauge interest in contributing one before writing a PR — this would be the first external contribution to MonitorConfig, so happy to align on shape (or defer entirely) before investing the work.

Use case

Multi-input displays where a script wants to flip between HDMI / DP / USB-C without going through the OSD. Two common patterns:

  • KVM-style switching: two PCs each connected via a different input; a script on PC A flips both displays over to the input PC B is using.
  • Dock toggle: workstation runs internal HDMI for one task, eGPU on DP for another.

Today this works fine via:

$mon | Set-MonitorVCPValue -VCPCode 0x60 -Value 17

…but the values are MCCS-defined constants and could be exposed as a typed surface, the way Brightness already is.

Proposed shape

# Named (MCCS-standard) values
$mon | Set-MonitorInput -Source HDMI1
$mon | Set-MonitorInput -Source DisplayPort1

# Raw value for vendor-specific inputs (e.g. Dell USB-C = 0x1B)
$mon | Set-MonitorInput -Value 0x1B

# Read current input + capability
$mon | Get-MonitorInput
# Monitor       CurrentSource   CurrentValue  PossibleValues
# \\.\DISPLAY1  HDMI1           17            15 (DisplayPort1), 17 (HDMI1), 27 (Custom)

Source would accept names mirroring the MCCS section "Input Select / VCP code 0x60":

Vga1 = 0x01, Vga2 = 0x02
Dvi1 = 0x03, Dvi2 = 0x04
DisplayPort1 = 0x0F, DisplayPort2 = 0x10
Hdmi1 = 0x11, Hdmi2 = 0x12
... etc.

Tab-completion would be monitor-aware: when -Monitor is bound, suggestions are filtered to the values that monitor advertises in its DDC/CI capability string. On a P2725QE that reports 60(0F 11 1B), -Source <TAB> would show just DisplayPort1 and Hdmi1, and -Value <TAB> would also surface the vendor-specific 0x1B (USB-C, not in the MCCS list) with a description. Falls back to the full MCCS list when no monitor is bound or its capability string can't be read.

Implementation notes

Fits the existing pattern of typed wrapper over Set-MonitorVCPValue:

  • Add KnownVcpCodes.InputSelect = 0x60
  • New MonitorInputSource enum under API/
  • Add VCPMonitor.GetInputSource() / SetInputSource(uint) next to the existing GetBrightnessLevel / SetBrightnessLevel etc.
  • New GetMonitorInputCommand.cs / SetMonitorInputCommand.cs mirroring SetMonitorBrightnessCommand (Monitor pipeline arg at position 0, single Source / Value param at position 1, parameter sets to choose named vs raw)
  • New MonitorInputCompleter.cs with IArgumentCompleter classes for -Source and -Value, sharing one resolver that turns the bound -Monitor value (object or device-name string) into a VCPMonitor and reads VCP 0x60 valid values from ParsedCapabilityString
  • WMIMonitor doesn't apply (internal panels can't change input), so this would be VCP-only and error gracefully on WMIMonitor like WMIOptionsSetOnVCPDisplay does today

One small documentation nuance worth flagging: some monitors report a different EDID Product Code per active input (e.g. Dell P2725QE shows DELF168 over HDMI but DELF169 over DP — same physical panel). Doesn't affect this cmdlet, but it can surprise users who try to identify monitors by InstanceName across hosts. A README note seems sufficient.

Questions

Are PRs along these lines welcome? If yes, three design choices I'd like your opinion on:

  1. Naming: stick to MCCS spec literal (Hdmi1, Vga1, DisplayPort1) for fidelity, or use friendlier forms (HDMI, VGA, DP) with 1/2 suffixes only when needed?

  2. -Source parameter type — string vs enum. This one has a real tradeoff and I'd like your call before I send a PR:

    I started with MonitorInputSource as a public enum and -Source typed to it. PowerShell's binder, however, uses its own enum-name completion for enum-typed parameters and bypasses both [ArgumentCompleter] and Register-ArgumentCompleter for them — verified on PS 7 with a sentinel scriptblock that was silently dropped. To get the monitor-aware completion described above I switched -Source to String and parse it to the enum at ProcessRecord time, with an ArgumentException that lists the accepted MCCS names if the input isn't recognized. The enum type is still public (used by the -Value completer for friendly names and would be referenced by Get-MonitorInput output below).

    That trades binding-time type safety for monitor-aware tab-completion. I'd lean toward String because the completion is the main UX win for this cmdlet, but the tradeoff is real — happy to revert to the enum if you'd rather keep -Source strict and let -Value carry the monitor-aware completion alone.

  3. Get-MonitorInput shape: include PossibleValues in the default output (more useful for discovery), or keep symmetrical with Get-MonitorBrightness and return just the current state? (Current sketch in MonitorInputInfo is CurrentValue + CurrentSource?, the latter null for vendor-specific values.)

Happy to draft a PR on whichever shape you prefer, or to leave it for you if you'd rather own the addition.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions