以编程方式更改监视器输入源

Lia*_*iam 3 python multiple-monitors python-3.x

我最近偶然发现了这个软件: https: //clickmonitorddc.bplaced.net/ 我想找到一种方法来以编程方式更改我的默认显示器的输入源(从 DP 到 HDMI 并返回)(在我的两个显示器中的第一个上)。

我发现这个Sending DDC/CI Commands to Monitor on Windows using Python? 详细介绍如何通过 python 发送 ddc-ci 命令。

Now this is all well and good, but the linked pdf file to the list of DDC commands has expired and I can't seem to figure out how I'd apply this to my specific case. Messing around has only resulted in me succesfully making my monitors go blank one after the other, but that's not really what I'm trying to accomplish.

I sadly do not have much of any attempts or code to share a part from the one in the linked post above.

Any help would be greatly appreciated.

Lia*_*iam 9

经过对原件中链接的代码进行一些测试后,我设法弄清楚了:

from ctypes import windll, byref, Structure, WinError, POINTER, WINFUNCTYPE
from ctypes.wintypes import BOOL, HMONITOR, HDC, RECT, LPARAM, DWORD, BYTE, WCHAR, HANDLE


_MONITORENUMPROC = WINFUNCTYPE(BOOL, HMONITOR, HDC, POINTER(RECT), LPARAM)


class _PHYSICAL_MONITOR(Structure):
    _fields_ = [('handle', HANDLE),
                ('description', WCHAR * 128)]


def _iter_physical_monitors(close_handles=True):
    """Iterates physical monitors.

    The handles are closed automatically whenever the iterator is advanced.
    This means that the iterator should always be fully exhausted!

    If you want to keep handles e.g. because you need to store all of them and
    use them later, set `close_handles` to False and close them manually."""

    def callback(hmonitor, hdc, lprect, lparam):
        monitors.append(HMONITOR(hmonitor))
        return True

    monitors = []
    if not windll.user32.EnumDisplayMonitors(None, None, _MONITORENUMPROC(callback), None):
        raise WinError('EnumDisplayMonitors failed')

    for monitor in monitors:
        # Get physical monitor count
        count = DWORD()
        if not windll.dxva2.GetNumberOfPhysicalMonitorsFromHMONITOR(monitor, byref(count)):
            raise WinError()
        # Get physical monitor handles
        physical_array = (_PHYSICAL_MONITOR * count.value)()
        if not windll.dxva2.GetPhysicalMonitorsFromHMONITOR(monitor, count.value, physical_array):
            raise WinError()
        for physical in physical_array:
            yield physical.handle
            if close_handles:
                if not windll.dxva2.DestroyPhysicalMonitor(physical.handle):
                    raise WinError()


def set_vcp_feature(monitor, code, value):
    """Sends a DDC command to the specified monitor.

    See this link for a list of commands:
    ftp://ftp.cis.nctu.edu.tw/pub/csie/Software/X11/private/VeSaSpEcS/VESA_Document_Center_Monitor_Interface/mccsV3.pdf
    """
    if not windll.dxva2.SetVCPFeature(HANDLE(monitor), BYTE(code), DWORD(value)):
        raise WinError()


# Switch to HDMI, wait for the user to press return and then back to DP
for handle in _iter_physical_monitors():
    set_vcp_feature(handle, 0x60, 0x11) #Change input to HDMI
    input()
    set_vcp_feature(handle, 0x60, 0x0F) #Change input to DisplayPort
Run Code Online (Sandbox Code Playgroud)

结果输入命令的 vcp 代码是0x60,从那里可以很容易地确定这些值,它们如下:

0x01: D-sub/VGA, 0x03: DVI, 0x11 or 0x04 depending on the brand: HDMI, 0x0F: DisplayPort