1+ """
2+ Listeners for aggregated keyboard and mouse events.
3+
4+ This is used for AFK detection on Linux, as well as used in aw-watcher-input to track input activity in general.
5+
6+ NOTE: Logging usage should be commented out before committed, for performance reasons.
7+ """
8+
19import logging
210import threading
11+ from abc import ABCMeta , abstractmethod
12+ from collections import defaultdict
313
414logger = logging .getLogger (__name__ )
15+ # logger.setLevel(logging.DEBUG)
516
617
7- class EventFactory :
18+ class EventFactory (metaclass = ABCMeta ):
19+ def __init__ (self ):
20+ self .new_event = threading .Event ()
21+ self ._reset_data ()
22+
23+ @abstractmethod
24+ def _reset_data (self ):
25+ raise NotImplementedError
26+
827 def next_event (self ):
928 """Returns an event and prepares the internal state so that it can start to build a new event"""
10- raise NotImplementedError
29+ self .new_event .clear ()
30+ data = self .event_data
31+ # self.logger.debug(f"Event: {data}")
32+ self ._reset_data ()
33+ return data
1134
1235 def has_new_event (self ):
13- raise NotImplementedError
36+ return self . new_event . is_set ()
1437
1538
1639class KeyboardListener (EventFactory ):
1740 def __init__ (self ):
41+ EventFactory .__init__ (self )
1842 self .logger = logger .getChild ("keyboard" )
19- # self.logger.setLevel(logging.DEBUG)
20- self .new_event = threading .Event ()
21- self ._reset_data ()
2243
2344 def start (self ):
2445 from pynput import keyboard
@@ -30,36 +51,27 @@ def _reset_data(self):
3051 self .event_data = {"presses" : 0 }
3152
3253 def on_press (self , key ):
33- print ("press" , key )
34- self .logger .debug ("Input received" )
54+ # self.logger.debug(f"Press: {key}")
3555 self .event_data ["presses" ] += 1
3656 self .new_event .set ()
3757
3858 def on_release (self , key ):
39- print ("release" , key )
40-
41- def next_event (self ):
42- """Returns an event and prepares the internal state so that it can start to build a new event"""
43- self .new_event .clear ()
44- data = self .event_data
45- print (data )
46- self ._reset_data ()
47- return data
48-
49- def has_new_event (self ):
50- return self .new_event .is_set ()
59+ # Don't count releases, only clicks
60+ # self.logger.debug(f"Release: {key}")
61+ pass
5162
5263
5364class MouseListener (EventFactory ):
5465 def __init__ (self ):
66+ EventFactory .__init__ (self )
5567 self .logger = logger .getChild ("mouse" )
56- self .logger .setLevel (logging .INFO )
57- self .new_event = threading .Event ()
5868 self .pos = None
59- self ._reset_data ()
6069
6170 def _reset_data (self ):
62- self .event_data = {"clicks" : 0 , "deltaX" : 0 , "deltaY" : 0 }
71+ self .event_data = defaultdict (int )
72+ self .event_data .update (
73+ {"clicks" : 0 , "deltaX" : 0 , "deltaY" : 0 , "scrollX" : 0 , "scrollY" : 0 }
74+ )
6375
6476 def start (self ):
6577 from pynput import mouse
@@ -75,34 +87,22 @@ def on_move(self, x, y):
7587 if not self .pos :
7688 self .pos = newpos
7789
78- delta = tuple (abs ( self .pos [i ] - newpos [i ]) for i in range (2 ))
79- self .event_data ["deltaX" ] += delta [0 ]
80- self .event_data ["deltaY" ] += delta [1 ]
90+ delta = tuple (self .pos [i ] - newpos [i ] for i in range (2 ))
91+ self .event_data ["deltaX" ] += abs ( delta [0 ])
92+ self .event_data ["deltaY" ] += abs ( delta [1 ])
8193
8294 self .pos = newpos
8395 self .new_event .set ()
8496
85- def on_click (self , * args ):
86- self .logger .debug (args )
87-
88- def click (self , x , y , button , press ):
89- # TODO: Differentiate between leftclick and rightclick?
90- if press :
91- self .logger .debug ("Clicked mousebutton" )
97+ def on_click (self , x , y , button , down ):
98+ # self.logger.debug(f"Click: {button} at {(x, y)}")
99+ # Only count presses, not releases
100+ if down :
92101 self .event_data ["clicks" ] += 1
93- self .new_event .set ()
102+ self .new_event .set ()
94103
95104 def on_scroll (self , x , y , scrollx , scrolly ):
96- self .logger .debug (f"{ scrollx } , { scrolly } at { (x , y )} " )
97-
98- def has_new_event (self ):
99- answer = self .new_event .is_set ()
100- self .new_event .clear ()
101- return answer
102-
103- def next_event (self ):
104- self .new_event .clear ()
105- data = self .event_data
106- print (data )
107- self ._reset_data ()
108- return data
105+ # self.logger.debug(f"Scroll: {scrollx}, {scrolly} at {(x, y)}")
106+ self .event_data ["scrollX" ] += abs (scrollx )
107+ self .event_data ["scrollY" ] += abs (scrolly )
108+ self .new_event .set ()
0 commit comments