How do I detect if the system is idle on Windows using Python (i.e. no keyboard or mouse activity).
This has already been asked before, but there doesn't seem to be a GetLastInputInfo
in the pywin32
module.
-
5Since it was asked before, why are you asking again? What do you think has changed that will yield a different answer? – S.Lott May 26 '09 at 17:41
-
2Maybe there's someone around now who can answer it, but the old question is buried in age and obscurity. How can you "bump" someone else's old question? – Craig McQueen May 27 '09 at 02:42
-
2when it was previously asked, the answer was about detecting mouse clicks, which was nowhere near an answer to that question! – Badri May 27 '09 at 03:41
6 Answers
from ctypes import Structure, windll, c_uint, sizeof, byref
class LASTINPUTINFO(Structure):
_fields_ = [
('cbSize', c_uint),
('dwTime', c_uint),
]
def get_idle_duration():
lastInputInfo = LASTINPUTINFO()
lastInputInfo.cbSize = sizeof(lastInputInfo)
windll.user32.GetLastInputInfo(byref(lastInputInfo))
millis = windll.kernel32.GetTickCount() - lastInputInfo.dwTime
return millis / 1000.0
Call get_idle_duration()
to get idle time in seconds.

- 74,300
- 25
- 125
- 131
-
Another library could set `argtypes`, `restype`, or `errcheck` on `windll.user32.GetLastInputInfo` in an incompatible way, so you should use your own `WinDLL` instance, e.g. `user32 = WinDLL('user32', use_last_error=True)`. – Eryk Sun May 16 '16 at 01:25
-
1@ErykSun , Sometimes this returns negative numbers, even with the user32 = ... code – Luis Mauricio Jan 11 '22 at 05:32
import win32api
def getIdleTime():
return (win32api.GetTickCount() - win32api.GetLastInputInfo()) / 1000.0

- 759
- 1
- 11
- 20
-
This yields a number less than 1 which does not seem to increase over time. It resets to zero when input is detected, but then it just becomes 0.015 or 0.016 and stays there. – jewbix.cube Nov 21 '21 at 19:18
Seems like GetLastInputInfo
is now available in pywin32:
win32api.GetLastInputInfo()
does the trick and returns the timer tick from the last user input action.
Here with an example program
import time
import win32api
for i in range(10):
print(win32api.GetLastInputInfo())
time.sleep(1)
If one presses a key/moves the mouse while the script sleeps, the printed number changes.

- 2,334
- 2
- 20
- 25
@FogleBird's answer is pretty cool and working, but in a hurry i wasn't sure how it works, so a little test example here. A thread is starting, looking for last idle time every 10 seconds. If any movement is made within this time window, it will be printed out.
from ctypes import Structure, windll, c_uint, sizeof, byref
import threading
//Print out every n seconds the idle time, when moving mouse, this should be < 10
def printit():
threading.Timer(10.0, printit).start()
print get_idle_duration()
class LASTINPUTINFO(Structure):
_fields_ = [
('cbSize', c_uint),
('dwTime', c_uint),
]
def get_idle_duration():
lastInputInfo = LASTINPUTINFO()
lastInputInfo.cbSize = sizeof(lastInputInfo)
windll.user32.GetLastInputInfo(byref(lastInputInfo))
millis = windll.kernel32.GetTickCount() - lastInputInfo.dwTime
return millis / 1000.0
printit()

- 23,311
- 18
- 141
- 164
-
note that as of some recent update (on my end) (windows 10), the time millis returns is not correct, replacing it with `(win32api.GetTickCount() - win32api.GetLastInputInfo()) / 1000.0` worked – Sleepy Jun 13 '23 at 13:43
There's basically two types of answers so far. One using pywin32
(via win32api
and one using ctypes
. The only thing I could think of distinguishing them would be time of execution, so here are the results of a timeit test:
# idlefuncs.py
import ctypes
from ctypes import Structure, c_uint, sizeof, byref
import win32api
user32 = ctypes.WinDLL("user32", use_last_error=True)
kernel32 = ctypes.WinDLL("kernel32", use_last_error=True)
class LASTINPUTINFO(Structure):
_fields_ = [
('cbSize', c_uint),
('dwTime', c_uint),
]
def get_idle_duration():
lastInputInfo = LASTINPUTINFO()
lastInputInfo.cbSize = sizeof(lastInputInfo)
user32.GetLastInputInfo(byref(lastInputInfo))
millis = kernel32.GetTickCount() - lastInputInfo.dwTime
return millis / 1000.0
def getIdleTime():
return (win32api.GetTickCount() - win32api.GetLastInputInfo()) / 1000.0
In ipython:
In[1]: from idlefuncs import *
In[2]: %timeit get_idle_duration()
1.21 µs ± 12 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
In[4]: %timeit getIdleTime()
465 ns ± 7.69 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
Contrary to my expectations, the ctypes version takes 2.6 times as long!

- 4,046
- 5
- 31
- 60
Actually, you can access GetLastInputInfo
via the cytpes
library:
import ctypes
GetLastInputInfo = ctypes.windll.User32.GetLastInputInfo # callable function pointer
This might not be what you want though, as it does not provide idle information across the whole system, but only about the session that called the function. See MSDN docs.
Alternatively, you could check if the system is locked, or if the screen-saver has been started.

- 17,601
- 10
- 42
- 50