Block all keyboard (except ESC) and all mouse input via WH_MOUSE_LL; tagged idle nudge passes through own hook; hint updated
This commit is contained in:
1 parent
d16a2db9ae
commit
d3286ef3b8
1 file changed
+40
-7
+40
-7
@@ -245,6 +245,8 @@ if sys.platform == "win32":
|
||||
WM_KEYDOWN_LL = 0x0100
|
||||
VK_ESCAPE = 0x1B
|
||||
WH_KEYBOARD_LL = 13
|
||||
WH_MOUSE_LL = 14
|
||||
MOUSE_NUDGE_TAG = 0x42424242
|
||||
DT_CENTER = 0x00000001
|
||||
DT_VCENTER = 0x00000004
|
||||
DT_SINGLELINE = 0x00000020
|
||||
@@ -302,6 +304,15 @@ if sys.platform == "win32":
|
||||
("dwExtraInfo", ULONG_PTR),
|
||||
]
|
||||
|
||||
class MSLLHOOKSTRUCT(ctypes.Structure):
|
||||
_fields_ = [
|
||||
("pt", wt.POINT),
|
||||
("mouseData", wt.DWORD),
|
||||
("flags", wt.DWORD),
|
||||
("time", wt.DWORD),
|
||||
("dwExtraInfo", ULONG_PTR),
|
||||
]
|
||||
|
||||
# --- prototypes (64-bit safe) ---
|
||||
user32.EnumDisplayMonitors.argtypes = [wt.HDC, ctypes.POINTER(wt.RECT), MONITORENUMPROC, wt.LPARAM]
|
||||
user32.EnumDisplayMonitors.restype = wt.BOOL
|
||||
@@ -401,7 +412,7 @@ if sys.platform == "win32":
|
||||
_hwnds = []
|
||||
_hint_active = True
|
||||
_hook_id = None
|
||||
_hint_text = "ESC - exit"
|
||||
_hint_text = "ESC - exit | mouse/keyboard locked"
|
||||
|
||||
def enum_monitor_rects():
|
||||
rects = []
|
||||
@@ -456,15 +467,28 @@ if sys.platform == "win32":
|
||||
return user32.DefWindowProcW(hwnd, msg, wparam, lparam)
|
||||
|
||||
def _low_level_keyboard_proc(nCode, wParam, lParam):
|
||||
if nCode >= 0 and wParam == WM_KEYDOWN_LL:
|
||||
if nCode >= 0:
|
||||
kb = ctypes.cast(lParam, ctypes.POINTER(KBDLLHOOKSTRUCT)).contents
|
||||
if kb.vkCode == VK_ESCAPE:
|
||||
if kb.vkCode == VK_ESCAPE and wParam == WM_KEYDOWN_LL:
|
||||
LOG.info("ESC pressed -> exit")
|
||||
user32.PostQuitMessage(0)
|
||||
return 1 # block ALL keyboard input while the overlay is up
|
||||
return user32.CallNextHookEx(_hook_id, nCode, wParam, lParam)
|
||||
|
||||
_mouse_hook_id = None
|
||||
|
||||
def _low_level_mouse_proc(nCode, wParam, lParam):
|
||||
if nCode >= 0:
|
||||
ms = ctypes.cast(lParam, ctypes.POINTER(MSLLHOOKSTRUCT)).contents
|
||||
# allow only our own idle-keepalive nudge (tagged dwExtraInfo);
|
||||
# block every real mouse event (moves, clicks, wheel)
|
||||
if int(ms.dwExtraInfo) == MOUSE_NUDGE_TAG:
|
||||
return user32.CallNextHookEx(_mouse_hook_id, nCode, wParam, lParam)
|
||||
return 1
|
||||
return user32.CallNextHookEx(_mouse_hook_id, nCode, wParam, lParam)
|
||||
|
||||
def run_overlay():
|
||||
global _hwnds, _hook_id
|
||||
global _hwnds, _hook_id, _mouse_hook_id
|
||||
# Per-monitor V2 DPI awareness: device-coord rects map 1:1 to each
|
||||
# monitor regardless of mixed DPI / where the primary sits.
|
||||
if shcore is not None:
|
||||
@@ -522,11 +546,16 @@ if sys.platform == "win32":
|
||||
for _ in range(12):
|
||||
if user32.ShowCursor(False) < 0:
|
||||
break
|
||||
# global ESC hook
|
||||
# global ESC hook (also blocks all other keyboard input)
|
||||
kb_proc = HOOKPROC(_low_level_keyboard_proc)
|
||||
_hook_id = user32.SetWindowsHookExW(WH_KEYBOARD_LL, kb_proc, hinst, 0)
|
||||
if not _hook_id:
|
||||
LOG.warning("SetWindowsHookExW failed: %d", kernel32.GetLastError())
|
||||
# global mouse hook: block all real mouse input
|
||||
mouse_proc = HOOKPROC(_low_level_mouse_proc)
|
||||
_mouse_hook_id = user32.SetWindowsHookExW(WH_MOUSE_LL, mouse_proc, hinst, 0)
|
||||
if not _mouse_hook_id:
|
||||
LOG.warning("mouse hook failed: %d", kernel32.GetLastError())
|
||||
|
||||
# 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)
|
||||
@@ -542,8 +571,9 @@ if sys.platform == "win32":
|
||||
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)
|
||||
tag = ctypes.c_void_p(MOUSE_NUDGE_TAG)
|
||||
user32.mouse_event(0x0001, 1, 0, 0, tag)
|
||||
user32.mouse_event(0x0001, 0xFFFFFFFF, 0, 0, tag)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
@@ -557,6 +587,9 @@ if sys.platform == "win32":
|
||||
|
||||
if _hook_id:
|
||||
user32.UnhookWindowsHookEx(_hook_id)
|
||||
if _mouse_hook_id:
|
||||
user32.UnhookWindowsHookEx(_mouse_hook_id)
|
||||
_mouse_hook_id = None
|
||||
_activity_stop.set()
|
||||
at.join(timeout=1)
|
||||
kernel32.SetThreadExecutionState(ES_CONTINUOUS) # allow display sleep again
|
||||
|
||||
Reference in new issue
Block a user