Подтвердить что ты не робот

Отправка команд DDC/CI для мониторинга в Windows с использованием Python?

Я хотел бы, чтобы мои мониторы управлялись из Windows (простые вещи, такие как изменение источника ввода), но не могут найти способ отправки команд DDC/CI из Python...

Любая подсказка о библиотеке или методе, которые могут помочь здесь?

4b9b3361

Ответ 1

Это легко можно использовать с помощью API-монитора Windows. Я не думаю, что есть какие-либо связки Python, и pywin32 не содержит этих функций. Однако использование ctypes для вызова их не так уж сложно.

Вот пример, который переключает монитор на мягкое, а затем обратно; его довольно легко адаптировать к изменению источника входного сигнала и т.д. Единственная сложная часть - получение ручек для физических мониторов:

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 SOFT-OFF, wait for the user to press return and then back to ON
for handle in _iter_physical_monitors():
    set_vcp_feature(handle, 0xd6, 0x04)
    raw_input()
    set_vcp_feature(handle, 0xd6, 0x01)