Created
June 14, 2021 11:59
-
-
Save ChrisCrossCrash/b552357eb21403d77fe1ab54515902b8 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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