Changes

Jump to navigation Jump to search
3,476 bytes added ,  11:54, 28 April 2015
Line 33: Line 33:     
===Template===
 
===Template===
<pre>
  −
Some code
  −
</pre>
      +
<syntaxhighlight lang="python">
 +
import time
 +
from ctypes import windll, byref, c_char, 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:
 +
handle = physical.handle
 +
 +
# Get physical monitor capabilities. This may take a while...
 +
length = DWORD()
 +
if not windll.dxva2.GetCapabilitiesStringLength(HANDLE(handle), byref(length)):
 +
raise WinError()
 +
capabilities_string = (c_char * length.value)()
 +
if not windll.dxva2.CapabilitiesRequestAndCapabilitiesReply(HANDLE(handle), capabilities_string, length):
 +
raise WinError()
 +
raw_capabilities = capabilities_string.value.decode('ascii')
 +
capabilities = _parse_capabilities_string(raw_capabilities)
 +
if capabilities:
 +
# We only care about the model info for now.
 +
yield [capabilities['model'], handle]
 +
if close_handles:
 +
if not windll.dxva2.DestroyPhysicalMonitor(handle):
 +
raise WinError()
 +
 +
 +
def _parse_capabilities_string(capabilities_string):
 +
level = 0
 +
capabilities = {}
 +
open_p = {}
 +
close_p = {0: 0}
 +
id = {}
 +
for i, chr in enumerate(capabilities_string):
 +
if chr == '(':
 +
if i == 0:
 +
close_p[0] = 1
 +
continue
 +
open_p[level] = i
 +
if level == 0:
 +
id[0] = capabilities_string[close_p[0] + 1:i]
 +
level += 1
 +
elif chr == ')':
 +
level -= 1
 +
close_p[level] = i
 +
if level == 0:
 +
values = capabilities_string[open_p[0] + 1:i]
 +
# We only care about the model info for now.
 +
if id[0] == 'model':
 +
capabilities[id[0]] = values
 +
return capabilities
 +
 +
 +
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()
 +
 +
 +
for model, handle in _iter_physical_monitors():
 +
if model == "XL2420Z":
 +
set_vcp_feature(handle, 0xDC, 12) # picture mode
 +
 +
time.sleep(2) # wait for picture mode to load
 +
 +
set_vcp_feature(handle, 0x10, 31) # brightness
 +
set_vcp_feature(handle, 0x12, 50) # contrast
 +
set_vcp_feature(handle, 0xF0, 0) # AMA (overdrive)
 +
 +
</syntaxhighlight>
    
==See Also== <!-- Optional -->
 
==See Also== <!-- Optional -->

Navigation menu