Skip to content

Commit 2d4519c

Browse files
fix(windows): use GetTickCount64 to prevent overflow after 49.7 days (#76)
GetTickCount returns a DWORD (32-bit) that wraps at 2^32 ms (~49.7 days of uptime). After wrapping, the idle time calculation would produce incorrect values (either negative or huge numbers). Switch to GetTickCount64 which returns a 64-bit value with no practical overflow limit. Also handle the 32-bit wraparound of dwTime from GetLastInputInfo (which always returns DWORD per the Windows API). Fixes #16
1 parent 403a331 commit 2d4519c

1 file changed

Lines changed: 23 additions & 7 deletions

File tree

‎aw_watcher_afk/windows.py‎

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import ctypes
22
import time
3-
from ctypes import POINTER, WINFUNCTYPE, Structure # type: ignore
3+
from ctypes import POINTER, WINFUNCTYPE, Structure, c_ulonglong # type: ignore
44
from ctypes.wintypes import BOOL, DWORD, UINT
55

6+
ULONGLONG = c_ulonglong
7+
68

79
class LastInputInfo(Structure):
810
_fields_ = [("cbSize", UINT), ("dwTime", DWORD)]
@@ -19,16 +21,30 @@ def _getLastInputTick() -> int:
1921
return lastinput.dwTime
2022

2123

22-
def _getTickCount() -> int:
23-
prototype = WINFUNCTYPE(DWORD)
24+
def _getTickCount64() -> int:
25+
"""Use GetTickCount64 to avoid 32-bit overflow after ~49.7 days of uptime."""
26+
prototype = WINFUNCTYPE(ULONGLONG)
2427
paramflags = ()
25-
c_GetTickCount = prototype(("GetTickCount", ctypes.windll.kernel32), paramflags) # type: ignore
26-
return c_GetTickCount()
28+
c_GetTickCount64 = prototype(("GetTickCount64", ctypes.windll.kernel32), paramflags) # type: ignore
29+
return c_GetTickCount64()
2730

2831

2932
def seconds_since_last_input():
30-
seconds_since_input = (_getTickCount() - _getLastInputTick()) / 1000
31-
return seconds_since_input
33+
tick_count = _getTickCount64()
34+
last_input_tick = _getLastInputTick() # 32-bit DWORD from GetLastInputInfo
35+
36+
# GetLastInputInfo returns a 32-bit DWORD tick count that wraps at 2^32 ms.
37+
# GetTickCount64 returns 64-bit. To compute the difference correctly, we
38+
# compare only the lower 32 bits when the values are close (normal case),
39+
# and handle the wraparound when dwTime > lower 32 bits of tick_count.
40+
tick_lower32 = tick_count & 0xFFFFFFFF
41+
if tick_lower32 >= last_input_tick:
42+
diff_ms = tick_lower32 - last_input_tick
43+
else:
44+
# 32-bit wraparound: tick_count's lower bits wrapped past dwTime
45+
diff_ms = (0x100000000 - last_input_tick) + tick_lower32
46+
47+
return diff_ms / 1000
3248

3349

3450
if __name__ == "__main__":

0 commit comments

Comments
 (0)