diff --git a/aw_watcher_afk/windows.py b/aw_watcher_afk/windows.py index a55f7cb..675e3e7 100644 --- a/aw_watcher_afk/windows.py +++ b/aw_watcher_afk/windows.py @@ -1,8 +1,10 @@ import ctypes import time -from ctypes import POINTER, WINFUNCTYPE, Structure # type: ignore +from ctypes import POINTER, WINFUNCTYPE, Structure, c_ulonglong # type: ignore from ctypes.wintypes import BOOL, DWORD, UINT +ULONGLONG = c_ulonglong + class LastInputInfo(Structure): _fields_ = [("cbSize", UINT), ("dwTime", DWORD)] @@ -19,16 +21,30 @@ def _getLastInputTick() -> int: return lastinput.dwTime -def _getTickCount() -> int: - prototype = WINFUNCTYPE(DWORD) +def _getTickCount64() -> int: + """Use GetTickCount64 to avoid 32-bit overflow after ~49.7 days of uptime.""" + prototype = WINFUNCTYPE(ULONGLONG) paramflags = () - c_GetTickCount = prototype(("GetTickCount", ctypes.windll.kernel32), paramflags) # type: ignore - return c_GetTickCount() + c_GetTickCount64 = prototype(("GetTickCount64", ctypes.windll.kernel32), paramflags) # type: ignore + return c_GetTickCount64() def seconds_since_last_input(): - seconds_since_input = (_getTickCount() - _getLastInputTick()) / 1000 - return seconds_since_input + tick_count = _getTickCount64() + last_input_tick = _getLastInputTick() # 32-bit DWORD from GetLastInputInfo + + # GetLastInputInfo returns a 32-bit DWORD tick count that wraps at 2^32 ms. + # GetTickCount64 returns 64-bit. To compute the difference correctly, we + # compare only the lower 32 bits when the values are close (normal case), + # and handle the wraparound when dwTime > lower 32 bits of tick_count. + tick_lower32 = tick_count & 0xFFFFFFFF + if tick_lower32 >= last_input_tick: + diff_ms = tick_lower32 - last_input_tick + else: + # 32-bit wraparound: tick_count's lower bits wrapped past dwTime + diff_ms = (0x100000000 - last_input_tick) + tick_lower32 + + return diff_ms / 1000 if __name__ == "__main__":