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

标签 python python-3.x multiple-monitors

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

我找到了这个 Sending DDC/CI commands to monitor on Windows using Python?详细介绍如何通过 python 发送 ddc-ci 命令。

现在一切都很好,但是链接到 DDC 命令列表的 pdf 文件已经过期,我似乎无法弄清楚如何将它应用到我的具体案例中。胡思乱想只让我成功地让我的显示器一个接一个地变黑,但这并不是我真正想要完成的。

遗憾的是,我没有太多尝试或代码来分享上面链接帖子中的一部分。

如有任何帮助,我们将不胜感激。

最佳答案

在对原始链接中的代码进行了一些测试后,我设法弄明白了:

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

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

0x01:D-sub/VGA,0x03:DVI,0x11 或 0x04 取决于品牌:HDMI,0x0F:DisplayPort

关于python - 以编程方式更改监视器输入源,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60580536/

相关文章:

python - tensorflow 周期性填充

string - python - 将字符串与 bool 值进行比较

C# 检查第二个屏幕的方向

browser - 在第二台显示器上打开新的浏览器页面

python:如果它只有常量,那么实例化一个类与引用相比有什么缺点吗?

python - 将 python sqlalchemy 类转换为原始 SQL(使用外键创建表)

Python __closure__ 变量和单元格

python - 如何提取 HTML 标签来识别已完成的任务?

development-environment - 最大化和多个显示器

python - 无法在 Ubuntu 上的 Python 中导入 torchvision