Skip to content

Instantly share code, notes, and snippets.

@ChrisCrossCrash
Created June 14, 2021 11:59
Show Gist options
  • Save ChrisCrossCrash/b552357eb21403d77fe1ab54515902b8 to your computer and use it in GitHub Desktop.
Save ChrisCrossCrash/b552357eb21403d77fe1ab54515902b8 to your computer and use it in GitHub Desktop.
from time import sleep
from typing import Union
from ctypes import Structure, windll, c_uint, sizeof, byref
class IdleWatcher:
"""Used for instancing 'idle watchers', which handle the
user going idle or becoming active after a set amount of time."""
def __init__(self, timeout_seconds: Union[int, float]):
self.timeout_seconds = timeout_seconds
self.is_watching = False
self.is_idle = False
self.last_idle_duration = 0
class LastInputInfo(Structure):
_fields_ = [
('cbSize', c_uint),
('dwTime', c_uint),
]
def get_idle_duration(self) -> float:
"""
Return the elapsed time in seconds since the last keyboard or mouse activity.
More info: "detecting idle time using python" solution from StackOverflow
https://stackoverflow.com/a/912223/8886761
"""
last_input_info = self.LastInputInfo()
last_input_info.cbSize = sizeof(last_input_info)
windll.user32.GetLastInputInfo(byref(last_input_info))
millis = windll.kernel32.GetTickCount() - last_input_info.dwTime
return millis / 1000.0
def handle_going_idle(self):
"""This method gets called once when the idle time has exceeded self.timeout_seconds."""
pass
def handle_resume(self):
"""This method gets called once after the idle time returns to 0. Set self.is_watching to false
in this method to stop watching for inputs."""
pass
def handle_start_watching(self):
"""This method gets called once in the beginning of the watch() method."""
pass
def handle_stop_watching(self):
"""This method gets called once after stopping to watch for input events."""
pass
def watch(self):
"""Start listening for user input and handle when the user become idle or active."""
self.is_watching = True
self.handle_start_watching()
while self.is_watching:
this_idle_duration = self.get_idle_duration()
if this_idle_duration > self.timeout_seconds:
if not self.is_idle:
self.handle_going_idle()
self.is_idle = True
elif this_idle_duration < self.last_idle_duration:
if self.is_idle:
self.is_idle = False
self.handle_resume()
self.last_idle_duration = this_idle_duration
sleep(0.5)
self.handle_stop_watching()
if __name__ == '__main__':
class MyIdleWatcher(IdleWatcher):
def handle_going_idle(self):
print(f'The user has become idle.')
def handle_resume(self):
print(f'The user has resumed after {self.last_idle_duration} seconds.')
watcher = MyIdleWatcher(10)
watcher.watch()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment