2013-05-16 33 views
10

Tôi muốn có màn hình của mình được điều khiển từ Windows (những thứ đơn giản như thay đổi nguồn đầu vào), nhưng không thể tìm thấy cách gửi lệnh DDC/CI từ ...Gửi lệnh DDC/CI để giám sát trên Windows bằng Python?

Bất kỳ đầu mối nào về thư viện hoặc phương pháp có thể giúp gì ở đây?

Trả lời

9

Điều này có thể dễ dàng sử dụng bằng cách sử dụng windows monitor API. Tôi không nghĩ rằng có bất kỳ ràng buộc Python ra khỏi đó và pywin32 không chứa các chức năng đó. Tuy nhiên, sử dụng ctypes để gọi cho họ không phải là khó khăn.

Dưới đây là ví dụ để tắt màn hình và sau đó bật lại; nó sẽ được khá dễ dàng để thích ứng với nó để thay đổi nguồn đầu vào vv. Phần phức tạp duy nhất là nhận được xử lý cho các màn hình vật lý sau khi tất cả:

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) 
+0

Tuyệt vời! Điều đó hoạt động tốt, chỉ khi màn hình philips của tôi hỗ trợ lệnh 0x60 với đầu vào displaylink: / – ronszon