Keep display awake while running (SetThreadExecutionState) so the monitor does not enter standby and the DDC/CI brightness restore on exit no longer hangs ~30s; bound native DDC calls with a 2s timeout as defense
This commit is contained in:
1 parent
d3437f924b
commit
0725915317
1 file changed
+55
-6
+55
-6
@@ -80,16 +80,52 @@ class BrightnessController:
|
||||
def _write_native(self, handle, value):
|
||||
try:
|
||||
dx = ctypes.windll.dxva2
|
||||
return bool(dx.SetMonitorBrightness(int(handle), wt.DWORD(int(value))))
|
||||
res = {}
|
||||
|
||||
def _t():
|
||||
try:
|
||||
res["v"] = bool(
|
||||
dx.SetMonitorBrightness(int(handle), wt.DWORD(int(value)))
|
||||
)
|
||||
except Exception as e:
|
||||
res["e"] = e
|
||||
|
||||
th = threading.Thread(target=_t, daemon=True)
|
||||
th.start()
|
||||
th.join(timeout=2.0)
|
||||
if th.is_alive():
|
||||
LOG.warning("native SetMonitorBrightness timed out (monitor in standby?)")
|
||||
return False
|
||||
if "e" in res:
|
||||
LOG.warning("native write failed: %r", res["e"])
|
||||
return False
|
||||
return res.get("v", False)
|
||||
except Exception as e:
|
||||
LOG.warning("native write failed: %r", e)
|
||||
LOG.warning("native write error: %r", e)
|
||||
return False
|
||||
|
||||
def _close_native(self, handle):
|
||||
dx = ctypes.windll.dxva2
|
||||
arr = (BrightnessController.PHYSICAL_MONITOR * 1)()
|
||||
arr[0].hPhysicalMonitor = handle
|
||||
dx.DestroyPhysicalMonitors(1, arr)
|
||||
try:
|
||||
dx = ctypes.windll.dxva2
|
||||
arr = (BrightnessController.PHYSICAL_MONITOR * 1)()
|
||||
arr[0].hPhysicalMonitor = handle
|
||||
res = {}
|
||||
|
||||
def _t():
|
||||
try:
|
||||
res["v"] = dx.DestroyPhysicalMonitors(1, arr)
|
||||
except Exception as e:
|
||||
res["e"] = e
|
||||
|
||||
th = threading.Thread(target=_t, daemon=True)
|
||||
th.start()
|
||||
th.join(timeout=2.0)
|
||||
if th.is_alive():
|
||||
return
|
||||
if "e" in res:
|
||||
LOG.warning("native close failed: %r", res["e"])
|
||||
except Exception as e:
|
||||
LOG.warning("native close error: %r", e)
|
||||
|
||||
def _build(self):
|
||||
self.targets = []
|
||||
@@ -214,6 +250,9 @@ if sys.platform == "win32":
|
||||
DT_SINGLELINE = 0x00000020
|
||||
TRANSPARENT = 1
|
||||
DEFAULT_GUI_FONT = 17
|
||||
ES_CONTINUOUS = 0x80000000
|
||||
ES_SYSTEM_REQUIRED = 0x00000001
|
||||
ES_DISPLAY_REQUIRED = 0x00000002
|
||||
|
||||
LRESULT = ctypes.c_int64
|
||||
HMONITOR = ctypes.c_void_p
|
||||
@@ -329,6 +368,8 @@ if sys.platform == "win32":
|
||||
kernel32.GetModuleHandleW.restype = wt.HINSTANCE
|
||||
kernel32.GetLastError.argtypes = []
|
||||
kernel32.GetLastError.restype = wt.DWORD
|
||||
kernel32.SetThreadExecutionState.argtypes = [wt.DWORD]
|
||||
kernel32.SetThreadExecutionState.restype = wt.DWORD
|
||||
|
||||
# --- native DDC/CI brightness (dxva2) ---
|
||||
class PHYSICAL_MONITOR(ctypes.Structure):
|
||||
@@ -485,6 +526,13 @@ if sys.platform == "win32":
|
||||
if not _hook_id:
|
||||
LOG.warning("SetWindowsHookExW failed: %d", kernel32.GetLastError())
|
||||
|
||||
# keep display awake while running: prevents the monitor from entering
|
||||
# standby during idle, which would make the DDC/CI brightness restore on
|
||||
# exit block/hang (often ~30s) waiting for the monitor to wake.
|
||||
kernel32.SetThreadExecutionState(
|
||||
ES_CONTINUOUS | ES_DISPLAY_REQUIRED | ES_SYSTEM_REQUIRED
|
||||
)
|
||||
|
||||
msg = wt.MSG()
|
||||
while user32.GetMessageW(ctypes.byref(msg), 0, 0, 0) > 0:
|
||||
user32.TranslateMessage(ctypes.byref(msg))
|
||||
@@ -492,6 +540,7 @@ if sys.platform == "win32":
|
||||
|
||||
if _hook_id:
|
||||
user32.UnhookWindowsHookEx(_hook_id)
|
||||
kernel32.SetThreadExecutionState(ES_CONTINUOUS) # allow display sleep again
|
||||
for h in _hwnds:
|
||||
user32.DestroyWindow(h)
|
||||
# restore cursor
|
||||
|
||||
Reference in new issue
Block a user