44
55@author Erki Suurjaak
66@created 06.04.2015
7- @modified 24 .04.2015
7+ @modified 29 .04.2015
88"""
99from __future__ import print_function
10- import collections
1110import datetime
1211import multiprocessing
1312import Queue
1918import conf
2019import db
2120
21+ DEBUG = False
22+
2223
2324class Listener (object ):
2425 """Runs mouse and keyboard listeners, and handles incoming commands."""
@@ -63,7 +64,7 @@ class DataHandler(threading.Thread):
6364 """Output thread, inserts events to database and to output function."""
6465 def __init__ (self , output ):
6566 threading .Thread .__init__ (self )
66- self .counts = collections . defaultdict ( int ) # {type: count}
67+ self .counts = {} # {type: count}
6768 self .output = output
6869 self .inqueue = Queue .Queue ()
6970 self .lasts = {"moves" : None }
@@ -84,6 +85,7 @@ def run(self):
8485 if self .lasts [event ] == pos : continue # while self.running
8586 self .lasts [event ] = pos
8687
88+ if event not in self .counts : self .counts [event ] = 0
8789 self .counts [event ] += 1
8890 dbqueue .append ((event , data ))
8991 try :
@@ -124,10 +126,10 @@ def scroll(self, x, y, wheel):
124126
125127class KeyHandler (pykeyboard .PyKeyboardEvent ):
126128 """Listens to keyboard events and forwards to output."""
127- CONTROLCODES = {"\x00 " : "Nul" , "\x01 " : "Start-Of-Header" , "\x02 " : "Start-Of-Text" , "\x03 " : "Break" , "\x04 " : "End-Of-Transmission" , "\x05 " : "Enquiry" , "\x06 " : "Ack" , "\x07 " : "Bell" , "\x08 " : "Backspace" , "\x09 " : "Tab" , "\x09 " : "Tab" , " \ x0a " : "Linefeed" , "\x0b " : "Vertical-Tab" , "\x0c " : "Form-Fe" , "\x0d " : "Enter" , "\x0e " : "Shift-In" , "\x0f " : "Shift-Out" , "\x10 " : "Data-Link-Escape" , "\x11 " : "Devicecontrol1" , "\x12 " : "Devicecontrol2" , "\x13 " : "Devicecontrol3" , "\x14 " : "Devicecontrol4" , "\x15 " : "Nak" , "\x16 " : "Syn" , "\x17 " : "End-Of-Transmission-Block" , "\x18 " : "Break" , "\x19 " : "End-Of-Medium" , "\x1a " : "Substitute" , "\x1b " : "Escape" , "\x1c " : "File-Separator" , "\x1d " : "Group-Separator" , "\x1e " : "Record-Separator" , "\x1f " : "Unit-Separator" , "\x20 " : "Space" , "\x7f " : "Del" , "\xa0 " : "Non-Breaking Space" }
129+ CONTROLCODES = {"\x00 " : "Nul" , "\x01 " : "Start-Of-Header" , "\x02 " : "Start-Of-Text" , "\x03 " : "Break" , "\x04 " : "End-Of-Transmission" , "\x05 " : "Enquiry" , "\x06 " : "Ack" , "\x07 " : "Bell" , "\x08 " : "Backspace" , "\x09 " : "Tab" , "\x0a " : "Linefeed" , "\x0b " : "Vertical-Tab" , "\x0c " : "Form-Fe" , "\x0d " : "Enter" , "\x0e " : "Shift-In" , "\x0f " : "Shift-Out" , "\x10 " : "Data-Link-Escape" , "\x11 " : "Devicecontrol1" , "\x12 " : "Devicecontrol2" , "\x13 " : "Devicecontrol3" , "\x14 " : "Devicecontrol4" , "\x15 " : "Nak" , "\x16 " : "Syn" , "\x17 " : "End-Of-Transmission-Block" , "\x18 " : "Break" , "\x19 " : "End-Of-Medium" , "\x1a " : "Substitute" , "\x1b " : "Escape" , "\x1c " : "File-Separator" , "\x1d " : "Group-Separator" , "\x1e " : "Record-Separator" , "\x1f " : "Unit-Separator" , "\x20 " : "Space" , "\x7f " : "Del" , "\xa0 " : "Non-Breaking Space" }
128130 NUMPAD_SPECIALS = [("Insert" , False ), ("Delete" , False ), ("Home" , False ), ("End" , False ), ("PageUp" , False ), ("PageDown" , False ), ("Up" , False ), ("Down" , False ), ("Left" , False ), ("Right" , False ), ("Clear" , False ), ("Enter" , True )]
129131 MODIFIERNAMES = {"Lcontrol" : "Ctrl" , "Rcontrol" : "Ctrl" , "Lshift" : "Shift" , "Rshift" : "Shift" , "Alt" : "Alt" , "AltGr" : "Alt" , "Lwin" : "Win" , "Rwin" : "Win" }
130- RENAMES = {"Prior" : "PageUp" , "Next" : "PageDown" , "Lmenu" : "Alt" , "Rmenu" : "AltGr" , "Apps" : "Menu" , "Return" : "Enter" , "Back" : "Backspace" , "Capital" : "CapsLock" , "Numlock" : "NumLock" , "Snapshot" : "PrintScreen" , "Scroll" : "ScrollLock" , "Decimal" : "Numpad-Decimal" , "Divide" : "Numpad-Divide" , "Subtract" : "Numpad-Subtract" , "Multiply" : "Numpad-Multiply" , "Add" : "Numpad-Add" }
132+ RENAMES = {"Prior" : "PageUp" , "Next" : "PageDown" , "Lmenu" : "Alt" , "Rmenu" : "AltGr" , "Apps" : "Menu" , "Return" : "Enter" , "Back" : "Backspace" , "Capital" : "CapsLock" , "Numlock" : "NumLock" , "Snapshot" : "PrintScreen" , "Scroll" : "ScrollLock" , "Decimal" : "Numpad-Decimal" , "Divide" : "Numpad-Divide" , "Subtract" : "Numpad-Subtract" , "Multiply" : "Numpad-Multiply" , "Add" : "Numpad-Add" , "Cancel" : "Break" }
131133 KEYS_DOWN = (0x0100 , 0x0104 ) # [WM_KEYDOWN, WM_SYSKEYDOWN]
132134 KEYS_UP = (0x0101 , 0x0105 ) # [WM_KEYUP, WM_SYSKEYUP]
133135 ALT_GRS = (36 , 64 , 91 , 92 , 93 , 123 , 124 , 125 , 128 , 163 , 208 , 222 , 240 , 254 ) # $@[\]{|}€£ŠŽšž
@@ -137,9 +139,11 @@ class KeyHandler(pykeyboard.PyKeyboardEvent):
137139 def __init__ (self , output ):
138140 pykeyboard .PyKeyboardEvent .__init__ (self )
139141 self .output = output
140- HANDLERS = {"win32" : self .handle_windows , "darwin" : self .handle_mac }
141- self .handler = HANDLERS .get (sys .platform , self .handle_linux ) # Override
142- self .modifiers = {"Ctrl" : False , "Alt" : False , "Shift" : False , "Win" : False }
142+ NAMES = {"win32" : "handler" , "linux2" : "tap" , "darwin" : "keypress" }
143+ HANDLERS = {"win32" : self .handle_windows , "linux2" : self .handle_linux ,
144+ "darwin" : self .handle_mac }
145+ setattr (self , NAMES [sys .platform ], HANDLERS [sys .platform ])
146+ self .modifiers = dict ((x , False ) for x in self .MODIFIERNAMES .values ())
143147 self .realmodifiers = dict ((x , False ) for x in self .MODIFIERNAMES )
144148 self .start ()
145149
@@ -152,13 +156,11 @@ def keyname(self, key):
152156
153157 def handle_windows (self , event ):
154158 """Windows key event handler."""
155- if event .IsInjected (): return True # Programmatically generated event
156-
157159 vkey = self .keyname (event .GetKey ())
158160 if event .Message in self .KEYS_UP + self .KEYS_DOWN :
159161 if vkey in self .MODIFIERNAMES :
160- self .modifiers [self .MODIFIERNAMES [vkey ]] = event .Message in self .KEYS_DOWN
161162 self .realmodifiers [vkey ] = event .Message in self .KEYS_DOWN
163+ self .modifiers [self .MODIFIERNAMES [vkey ]] = self .realmodifiers [vkey ]
162164 if event .Message not in self .KEYS_DOWN :
163165 return True
164166
@@ -171,18 +173,33 @@ def handle_windows(self, event):
171173 is_altgr = event .Ascii in self .ALT_GRS
172174 key = self .keyname (unichr (event .Ascii ))
173175
176+ if DEBUG : print ("Adding key %s (real %s)" % (key .encode ("utf-8" ), vkey .encode ("utf-8" )))
174177 self .output (type = "keys" , key = key , realkey = vkey )
175178
176179 if vkey not in self .MODIFIERNAMES and not is_altgr :
177- modifier = "-" .join (k for k , v in self .modifiers .items () if v )
180+ modifier = "-" .join (k for k in ["Ctrl" , "Alt" , "Shift" , "Win" ]
181+ if self .modifiers [k ])
178182 if modifier and modifier != "Shift" : # Shift-X is not a combo
179183 if self .modifiers ["Ctrl" ] and event .Ascii :
180184 key = self .keyname (unichr (event .KeyID ))
181185 realmodifier = "-" .join (k for k , v in self .realmodifiers .items () if v )
182186 realkey = "%s-%s" % (realmodifier , key )
183187 key = "%s-%s" % (modifier , key )
188+ if DEBUG : print ("Adding combo %s (real %s)" % (key .encode ("utf-8" ), realkey .encode ("utf-8" )))
184189 self .output (type = "combos" , key = key , realkey = realkey )
185190
191+ if DEBUG :
192+ print ("CHARACTER: %r" % key )
193+ print ('GetKey: {0}' .format (event .GetKey ())) # Name of the virtual keycode, str
194+ print ('IsAlt: {0}' .format (event .IsAlt ())) # Was the alt key depressed?, bool
195+ print ('IsExtended: {0}' .format (event .IsExtended ())) # Is this an extended key?, bool
196+ print ('IsInjected: {0}' .format (event .IsInjected ())) # Was this event generated programmatically?, bool
197+ print ('IsTransition: {0}' .format (event .IsTransition ())) #Is this a transition from up to down or vice versa?, bool
198+ print ('ASCII: {0}' .format (event .Ascii )) # ASCII value, if one exists, str
199+ print ('KeyID: {0}' .format (event .KeyID )) # Virtual key code, int
200+ print ('ScanCode: {0}' .format (event .ScanCode )) # Scan code, int
201+ print ('Message: {0}' .format (event .Message )) # Name of the virtual keycode, str
202+ print ()
186203 return True
187204
188205
@@ -201,11 +218,15 @@ def escape(self, event):
201218 return False
202219
203220
204-
205- if "__main__" == __name__ :
221+ def main ():
222+ """Entry point for stand-alone execution."""
206223 conf .init (), db .init (conf .DbPath )
207224 inqueue = multiprocessing .Queue ()
208225 outqueue = type ("PrintQueue" , (), {"put" : lambda self , x : print (x )})()
209226 if conf .MouseEnabled : inqueue .put ("mouse_start" )
210227 if conf .KeyboardEnabled : inqueue .put ("keyboard_start" )
211228 Listener (inqueue , outqueue ).run ()
229+
230+
231+ if "__main__" == __name__ :
232+ main ()
0 commit comments