Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactoring and windows support #14

Merged
merged 10 commits into from
Apr 25, 2017
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ logs
*.egg-info
build
dist
*~
2 changes: 2 additions & 0 deletions aw_watcher_afk/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
from .afk import main

import __main__
2 changes: 2 additions & 0 deletions aw_watcher_afk/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import aw_watcher_afk
aw_watcher_afk.main()
21 changes: 19 additions & 2 deletions aw_watcher_afk/afk.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,25 @@
from .listeners import KeyboardListener, MouseListener
from .config import watcher_config

if platform.system() == "Windows":
from .windows import time_since_last_input as _time_since_last_input_winfail

settings = {}

def _time_since_last_input_unix():
raise NotImplementedError


def time_since_last_input():
system = platform.system()
if system == "Darwin" or system == "Linux":
return _time_since_last_input_unix()
elif system == "Windows":
return _time_since_last_input_winfail()
else:
raise Exception("unknown platform")


def main() -> None:
""" Set up argparse """
parser = argparse.ArgumentParser("A watcher for keyboard and mouse input to detect AFK state")
Expand Down Expand Up @@ -44,6 +61,7 @@ def main() -> None:
client.setup_bucket(bucketname, eventtype)
client.connect()

# TODO: Get rid of desktop notifications, move to client instead
""" Desktop Notifications """
if args.desktop_notify:
from gi.repository import Notify
Expand Down Expand Up @@ -73,7 +91,6 @@ def send_notification(msg):
last_activity = now # Last time of input activity
second_last_activity = now # Second last time of input activity
last_update = now # Last report time
last_check = now # Last check/poll time

def _report_state(afk, duration, timestamp, update=False):
"""
Expand Down Expand Up @@ -143,7 +160,7 @@ def set_state(new_afk, when):

new_event = False
if mouseListener.has_new_event() or keyboardListener.has_new_event():
# logger.debug("New event")
logger.debug("New event")
new_event = True
second_last_activity, last_activity = last_activity, now
# Get/clear events
Expand Down
2 changes: 1 addition & 1 deletion aw_watcher_afk/listeners.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class KeyboardListener(PyKeyboardEvent, EventFactory):
def __init__(self):
PyKeyboardEvent.__init__(self)
self.logger = logging.getLogger("aw.watchers.afk.keyboard")
self.logger.setLevel(logging.INFO)
self.logger.setLevel(logging.DEBUG)
self.new_event = threading.Event()
self._reset_data()

Expand Down
41 changes: 41 additions & 0 deletions aw_watcher_afk/windows.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import time

import ctypes
from ctypes import Structure, POINTER, WINFUNCTYPE, windll
from ctypes.wintypes import BOOL, UINT, DWORD


class LastInputInfo(Structure):
_fields_ = [
("cbSize", UINT),
("dwTime", DWORD)
]


def _getLastInputTick():
prototype = WINFUNCTYPE(BOOL, POINTER(LastInputInfo))
paramflags = (1, "lastinputinfo"),
c_GetLastInputInfo = prototype(("GetLastInputInfo", ctypes.windll.user32), paramflags)

l = LastInputInfo()
l.cbSize = ctypes.sizeof(LastInputInfo)
assert 0 != c_GetLastInputInfo(l)
return l.dwTime


def _getTickCount() -> int:
Copy link
Member Author

@ErikBjare ErikBjare Apr 20, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We might want to use GetTickCount64 instead.

prototype = WINFUNCTYPE(DWORD)
paramflags = ()
c_GetTickCount = prototype(("GetTickCount", ctypes.windll.kernel32), paramflags)
return c_GetTickCount()


def time_since_last_input():
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that getTickCount and getLastInputTick both only have DWORD (32bit uint) length and will wrap after that. We might want to check for negative values or something and correct as necessary.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Created an issue for this: #16

seconds_since_input = (_getTickCount() - _getLastInputTick())/1000
return seconds_since_input


if __name__ == "__main__":
while True:
time.sleep(1)
print(time_since_last_input())