import win32gui import win32process import win32con import win32api import threading from typing import Callable import psutil def get_active_window() -> str: """Returns a string like 'YouTube - Chrome (chrome.exe)'""" try: hwnd = win32gui.GetForegroundWindow() title = win32gui.GetWindowText(hwnd) or "Unknown Window" # Get process name _, pid = win32process.GetWindowThreadProcessId(hwnd) try: proc = psutil.Process(pid) exe_name = proc.name() except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess): exe_name = "unknown.exe" return f"{title} ({exe_name})" except Exception: return "Error getting window info" def register_session_listener(callback: Callable[[str], None]) -> None: """Register a callback for Windows session lock/unlock events""" def session_event_handler(hwnd, msg, wparam, lparam): # Fallback numeric constants WM_WTSSESSION_CHANGE = 0x02B1 WTS_SESSION_LOCK = 0x1 WTS_SESSION_UNLOCK = 0x2 if msg == WM_WTSSESSION_CHANGE: if wparam == WTS_SESSION_LOCK: callback("locked") elif wparam == WTS_SESSION_UNLOCK: callback("unlocked") return win32gui.DefWindowProc(hwnd, msg, wparam, lparam) def run_message_loop(): hinst = win32api.GetModuleHandle(None) wndclass = win32gui.WNDCLASS() wndclass.hInstance = hinst wndclass.lpszClassName = "SessionWatcher" wndclass.lpfnWndProc = session_event_handler try: win32gui.RegisterClass(wndclass) except: pass # Already registered hwnd = win32gui.CreateWindow( wndclass.lpszClassName, "Session Watcher", 0, 0, 0, 0, 0, 0, 0, hinst, None ) # Register for session notifications try: from win32ts import WTSRegisterSessionNotification WTSRegisterSessionNotification(hwnd, 1) except ImportError: pass win32gui.PumpMessages() thread = threading.Thread(target=run_message_loop, daemon=True) thread.start() def get_idle_time() -> int: """Get the system idle time in seconds on Windows""" from ctypes import Structure, windll, c_uint, sizeof, byref class LASTINPUTINFO(Structure): _fields_ = [('cbSize', c_uint), ('dwTime', c_uint)] lastInputInfo = LASTINPUTINFO() lastInputInfo.cbSize = sizeof(lastInputInfo) windll.user32.GetLastInputInfo(byref(lastInputInfo)) millis = windll.kernel32.GetTickCount() - lastInputInfo.dwTime return millis // 1000