以编程方式更改监视器输入源
Changing monitor input source programmatically
我最近偶然发现了这个软件:https://clickmonitorddc.bplaced.net/
我想找到一种方法来以编程方式更改默认显示器的输入源(从 DP 到 HDMI 并返回)(在我的两个显示器中的第一个)。
我发现这个 Sending DDC/CI commands to monitor on Windows using Python? 详细说明了如何通过 python 发送 ddc-ci 命令。
现在一切都很好,但是链接到 DDC 命令列表的 pdf 文件已经过期,我似乎无法弄清楚如何将它应用到我的 specific案子。胡闹只是让我成功地让我的显示器一个接一个地变成空白,但这并不是我真正想要完成的。
遗憾的是,我没有太多尝试或代码来分享上面链接 post 中的一部分。
如有任何帮助,我们将不胜感激ci。
在对我原来链接的代码进行了一些测试后,我设法弄明白了:
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
此页面可能有您要查找的信息。似乎类似于评论中引用的 no-longer-linked PDF:
https://milek7.pl/ddcbacklight/mccs.pdf
我最近偶然发现了这个软件:https://clickmonitorddc.bplaced.net/ 我想找到一种方法来以编程方式更改默认显示器的输入源(从 DP 到 HDMI 并返回)(在我的两个显示器中的第一个)。
我发现这个 Sending DDC/CI commands to monitor on Windows using Python? 详细说明了如何通过 python 发送 ddc-ci 命令。
现在一切都很好,但是链接到 DDC 命令列表的 pdf 文件已经过期,我似乎无法弄清楚如何将它应用到我的 specific案子。胡闹只是让我成功地让我的显示器一个接一个地变成空白,但这并不是我真正想要完成的。
遗憾的是,我没有太多尝试或代码来分享上面链接 post 中的一部分。
如有任何帮助,我们将不胜感激ci。
在对我原来链接的代码进行了一些测试后,我设法弄明白了:
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
此页面可能有您要查找的信息。似乎类似于评论中引用的 no-longer-linked PDF: https://milek7.pl/ddcbacklight/mccs.pdf