Изменение источника входного сигнала монитора программно - PullRequest
0 голосов
/ 07 марта 2020

Я недавно наткнулся на это программное обеспечение: https://clickmonitorddc.bplaced.net/ И я хотел найти способ программно изменить источник входного сигнала моего монитора по умолчанию (с DP на HDMI и обратно) (На моем первом из двух мониторов) .

Я нашел это Отправка команд DDC / CI для мониторинга на Windows с использованием Python? , подробно описывающих, как отправлять команды dd c -ci через python.

Теперь все это хорошо, но связанный файл pdf со списком команд DD C просрочен, и я не могу понять, как бы я применил это к моему конкретному c случаю , Из-за того, что я возился, я только успешно засеял мониторы go один за другим, но на самом деле это не то, чего я пытался достичь sh.

К сожалению, у меня не было особых попыток или код, чтобы поделиться частью из той, что в связанном посте выше.

Любая помощь будет принята с благодарностью.

1 Ответ

0 голосов
/ 19 марта 2020

После некоторого тестирования с кодом, связанным в моем оригинале, мне удалось выяснить это:

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 or 0x04 depending on the brand: HDMI, 0x0F: DisplayPort

...