From d16a2db9ae811a9a3a26e46d8ea817c610cd8bd3 Mon Sep 17 00:00:00 2001 From: Hermes Agent Date: Fri, 18 Sep 2026 11:21:28 +0200 Subject: [PATCH] Add periodic invisible mouse nudge (30s) to keep display awake and prevent ESC wake-swallow double-press; log SetThreadExecutionState result --- black_screen_dim.py | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/black_screen_dim.py b/black_screen_dim.py index 68d3d60..3d04745 100644 --- a/black_screen_dim.py +++ b/black_screen_dim.py @@ -348,6 +348,8 @@ if sys.platform == "win32": user32.DestroyWindow.restype = wt.BOOL user32.ShowCursor.argtypes = [wt.BOOL] user32.ShowCursor.restype = wt.INT + user32.mouse_event.argtypes = [wt.DWORD, wt.DWORD, wt.DWORD, wt.DWORD, ctypes.c_void_p] + user32.mouse_event.restype = None user32.DefWindowProcW.argtypes = [wt.HWND, wt.UINT, wt.WPARAM, wt.LPARAM] user32.DefWindowProcW.restype = LRESULT user32.SetProcessDPIAware.argtypes = [] @@ -526,12 +528,27 @@ 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( + # keep display awake while running (prevents monitor standby, which would + # make ESC's first press get swallowed by the wake and a ~30s DDC hang) + sees = kernel32.SetThreadExecutionState( ES_CONTINUOUS | ES_DISPLAY_REQUIRED | ES_SYSTEM_REQUIRED ) + LOG.info("SetThreadExecutionState -> %s", sees) + + # belt-and-suspenders: emit a tiny (invisible) mouse move every 30s so the + # OS and any monitor hardware idle timer never trip during long idle. + _activity_stop = threading.Event() + + def _activity(): + while not _activity_stop.wait(30): + try: + user32.mouse_event(0x0001, 1, 0, 0, None) + user32.mouse_event(0x0001, 0xFFFFFFFF, 0, 0, None) + except Exception: + pass + + at = threading.Thread(target=_activity, daemon=True) + at.start() msg = wt.MSG() while user32.GetMessageW(ctypes.byref(msg), 0, 0, 0) > 0: @@ -540,6 +557,8 @@ if sys.platform == "win32": if _hook_id: user32.UnhookWindowsHookEx(_hook_id) + _activity_stop.set() + at.join(timeout=1) kernel32.SetThreadExecutionState(ES_CONTINUOUS) # allow display sleep again for h in _hwnds: user32.DestroyWindow(h)