Less known is that nowadays most of the monitors can communicate more than just video. That is, on a digital connection between a PC and a monitor, there is more than just video signal but also a data connection through which the PC can read data from the monitor and send commands to it.

Most of the settings that can be adjust with the physical buttons on the monitor can also be controled using this connection. These commands are called VCP (Virtual Control Panel) codes and are part of the VESA Monitor Control Command Set Standard.

I recently bought myself a very nice Philips 329M1RV monitor, an excellent display, but sadly it only has a physical joystick that can be used to access its menu to adjust brightness, contrast, or more important for me, change the input source. While I rarely adjust brightness and contrast, as I am usually working with a work laptop and a personal PC, I find myself switching the input source a few times a day. And this is quite a complicated operation when there is no dedicated physical button on the display and you need to find the joystick on the back of the monitor, go right, down, down, down, right, down, right, right and press ok just to switch from work to personal PC. There has to be a better way!

As a minimum, I would like to press a key on the keyboard and toggle the input source between laptop and PC. After that, a small window showing all the monitors and the current source for each one and maybe a drop down with the available sources to change to for each monitor.

But before going to wilde, let’s see if this is even possible.

A quick Google search brings up a Microsoft page describing various Monitor Configuration capabilities under Windows.

There seems to be some high level and some low level monitor configuring functions.

With the high-level ones, there are EnumDisplayMonitors, MonitorFromWindow and GetPhysicalMonitorsFromHMONITOR and GetMonitorCapabilities. This one seems intersting.

GetMonitorCapabilities seems to work with work using the VESA Monitor Control Command, that’s good, but it only suppors some common settings like brightness, contrast, color temperature, not changing the input source that I am looking for.

The low-level functions look like they cand send VCP and this is what I need.

From the docs, with the high level functions EnumDisplayMonitors and GetPhysicalMonitorsFromHMONITOR I can obtain handles for each physical monitors.

And for this handle, I can call now CapabilitiesRequestAndCapabilitiesReply to obtain a description string of what VCP codes the monitors support.

(prot(monitor)type(lcd)model(329M1RV)cmds(01 02 03 07 0C E3 F3)vcp(02 04 05 08 0B 0C 10 12 14(01 04 05 06 07 08 0A 0B) 16 18 1A 52 60(00 11 12 13 0F 10 21 22 2F 30 ) 62 6C 6E 70 72(05 78 FB 50 64 78 8C A0) 86(01 02 08) 8D(01 02) 95 96 97 98 AA(01 02) AC AE B6 C0 C6 C8 C9 CA(01 02) CC(02 03 04 05 07 08 09 0A 0C 0D 01 06 0B 0E 12 14 16 17 1A 1E 24) D6(01 04 05) DC(00 01 06 07 05 04 0B E2) DF E0(00 01 02 03 04) E7 E9(00 02) EB(00 01 02 03) EC(00 01 02 03) EE(00 01 02 03) EF(00 01 02 03 04 FF) F0(00 01) F6(01 ) F7(02FF) FF)mswhql(1)asset_eep(40)mccs_ver(2.2))
15 8206

From the documentation, we get that this VCP code 60h marked above is of interest.

For this VCP code 60h, the possible values are inside the parathesis and my monitor seems to support some standard 11, 12 (HDMI 1 & 2), and some none standard vendor specific 13, 0F, 10, 21, 22, 2F, 30. That’s more than the physical connections I see on the back, but in the end I am only concerned about USB-C and DisplayPort as I will connect a laptop through USB-C and a desktop through DisaplyPort.

Let’s see if I can use GetVCPFeatureAndVCPFeatureReply to read the current value while I am connected through USB-C or DisplayPort.

This returns 0x15 when the monitor receives signal over DisplayPort and 0x16 when over USB-C.

Input VCP 60 code value
HDMI 1 0x11
HDMI 2 0x12
HDMI 3 0x13
Display Port 0x10
USB-C 0x0F

I’m wondering what the remaining 0x21, 0x22, 0x2F and 0x30 mean, as the monitor has only HDMI 1-3, DisplayPort and USB-C physical connectors. Wireless maybe. 🙂

Finally, calling SetVCPFeature with either 0x10 or 0x0F is instantly switching the monitor to DisplayPort / USB-C. Exactly what I wanted. It works! Now I just need to make this more beautiful / easy to use / UX friendly.