4
4
5
5
@author Erki Suurjaak
6
6
@created 06.04.2015
7
- @modified 24 .04.2015
7
+ @modified 29 .04.2015
8
8
"""
9
9
from __future__ import print_function
10
- import collections
11
10
import datetime
12
11
import multiprocessing
13
12
import Queue
19
18
import conf
20
19
import db
21
20
21
+ DEBUG = False
22
+
22
23
23
24
class Listener (object ):
24
25
"""Runs mouse and keyboard listeners, and handles incoming commands."""
@@ -63,7 +64,7 @@ class DataHandler(threading.Thread):
63
64
"""Output thread, inserts events to database and to output function."""
64
65
def __init__ (self , output ):
65
66
threading .Thread .__init__ (self )
66
- self .counts = collections . defaultdict ( int ) # {type: count}
67
+ self .counts = {} # {type: count}
67
68
self .output = output
68
69
self .inqueue = Queue .Queue ()
69
70
self .lasts = {"moves" : None }
@@ -84,6 +85,7 @@ def run(self):
84
85
if self .lasts [event ] == pos : continue # while self.running
85
86
self .lasts [event ] = pos
86
87
88
+ if event not in self .counts : self .counts [event ] = 0
87
89
self .counts [event ] += 1
88
90
dbqueue .append ((event , data ))
89
91
try :
@@ -124,10 +126,10 @@ def scroll(self, x, y, wheel):
124
126
125
127
class KeyHandler (pykeyboard .PyKeyboardEvent ):
126
128
"""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" }
128
130
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 )]
129
131
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" }
131
133
KEYS_DOWN = (0x0100 , 0x0104 ) # [WM_KEYDOWN, WM_SYSKEYDOWN]
132
134
KEYS_UP = (0x0101 , 0x0105 ) # [WM_KEYUP, WM_SYSKEYUP]
133
135
ALT_GRS = (36 , 64 , 91 , 92 , 93 , 123 , 124 , 125 , 128 , 163 , 208 , 222 , 240 , 254 ) # $@[\]{|}€£ŠŽšž
@@ -137,9 +139,11 @@ class KeyHandler(pykeyboard.PyKeyboardEvent):
137
139
def __init__ (self , output ):
138
140
pykeyboard .PyKeyboardEvent .__init__ (self )
139
141
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 ())
143
147
self .realmodifiers = dict ((x , False ) for x in self .MODIFIERNAMES )
144
148
self .start ()
145
149
@@ -152,13 +156,11 @@ def keyname(self, key):
152
156
153
157
def handle_windows (self , event ):
154
158
"""Windows key event handler."""
155
- if event .IsInjected (): return True # Programmatically generated event
156
-
157
159
vkey = self .keyname (event .GetKey ())
158
160
if event .Message in self .KEYS_UP + self .KEYS_DOWN :
159
161
if vkey in self .MODIFIERNAMES :
160
- self .modifiers [self .MODIFIERNAMES [vkey ]] = event .Message in self .KEYS_DOWN
161
162
self .realmodifiers [vkey ] = event .Message in self .KEYS_DOWN
163
+ self .modifiers [self .MODIFIERNAMES [vkey ]] = self .realmodifiers [vkey ]
162
164
if event .Message not in self .KEYS_DOWN :
163
165
return True
164
166
@@ -171,18 +173,33 @@ def handle_windows(self, event):
171
173
is_altgr = event .Ascii in self .ALT_GRS
172
174
key = self .keyname (unichr (event .Ascii ))
173
175
176
+ if DEBUG : print ("Adding key %s (real %s)" % (key .encode ("utf-8" ), vkey .encode ("utf-8" )))
174
177
self .output (type = "keys" , key = key , realkey = vkey )
175
178
176
179
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 ])
178
182
if modifier and modifier != "Shift" : # Shift-X is not a combo
179
183
if self .modifiers ["Ctrl" ] and event .Ascii :
180
184
key = self .keyname (unichr (event .KeyID ))
181
185
realmodifier = "-" .join (k for k , v in self .realmodifiers .items () if v )
182
186
realkey = "%s-%s" % (realmodifier , key )
183
187
key = "%s-%s" % (modifier , key )
188
+ if DEBUG : print ("Adding combo %s (real %s)" % (key .encode ("utf-8" ), realkey .encode ("utf-8" )))
184
189
self .output (type = "combos" , key = key , realkey = realkey )
185
190
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 ()
186
203
return True
187
204
188
205
@@ -201,11 +218,15 @@ def escape(self, event):
201
218
return False
202
219
203
220
204
-
205
- if "__main__" == __name__ :
221
+ def main ():
222
+ """Entry point for stand-alone execution."""
206
223
conf .init (), db .init (conf .DbPath )
207
224
inqueue = multiprocessing .Queue ()
208
225
outqueue = type ("PrintQueue" , (), {"put" : lambda self , x : print (x )})()
209
226
if conf .MouseEnabled : inqueue .put ("mouse_start" )
210
227
if conf .KeyboardEnabled : inqueue .put ("keyboard_start" )
211
228
Listener (inqueue , outqueue ).run ()
229
+
230
+
231
+ if "__main__" == __name__ :
232
+ main ()
0 commit comments