1 import cpyHook
2
4 return cpyHook.cGetKeyState(key_id)
5
7 '''
8 Stores internal windows hook constants including hook types, mappings from virtual
9 keycode name to value and value to name, and event type value to name.
10 '''
11 WH_MIN = -1
12 WH_MSGFILTER = -1
13 WH_JOURNALRECORD = 0
14 WH_JOURNALPLAYBACK = 1
15 WH_KEYBOARD = 2
16 WH_GETMESSAGE = 3
17 WH_CALLWNDPROC = 4
18 WH_CBT = 5
19 WH_SYSMSGFILTER = 6
20 WH_MOUSE = 7
21 WH_HARDWARE = 8
22 WH_DEBUG = 9
23 WH_SHELL = 10
24 WH_FOREGROUNDIDLE = 11
25 WH_CALLWNDPROCRET = 12
26 WH_KEYBOARD_LL = 13
27 WH_MOUSE_LL = 14
28 WH_MAX = 15
29
30 WM_MOUSEFIRST = 0x0200
31 WM_MOUSEMOVE = 0x0200
32 WM_LBUTTONDOWN = 0x0201
33 WM_LBUTTONUP = 0x0202
34 WM_LBUTTONDBLCLK = 0x0203
35 WM_RBUTTONDOWN =0x0204
36 WM_RBUTTONUP = 0x0205
37 WM_RBUTTONDBLCLK = 0x0206
38 WM_MBUTTONDOWN = 0x0207
39 WM_MBUTTONUP = 0x0208
40 WM_MBUTTONDBLCLK = 0x0209
41 WM_MOUSEWHEEL = 0x020A
42 WM_MOUSELAST = 0x020A
43
44 WM_KEYFIRST = 0x0100
45 WM_KEYDOWN = 0x0100
46 WM_KEYUP = 0x0101
47 WM_CHAR = 0x0102
48 WM_DEADCHAR = 0x0103
49 WM_SYSKEYDOWN = 0x0104
50 WM_SYSKEYUP = 0x0105
51 WM_SYSCHAR = 0x0106
52 WM_SYSDEADCHAR = 0x0107
53 WM_KEYLAST = 0x0108
54
55
56
57
58
59
60 vk_to_id = {'VK_LBUTTON' : 0x01, 'VK_RBUTTON' : 0x02, 'VK_CANCEL' : 0x03, 'VK_MBUTTON' : 0x04,
61 'VK_BACK' : 0x08, 'VK_TAB' : 0x09, 'VK_CLEAR' : 0x0C, 'VK_RETURN' : 0x0D, 'VK_SHIFT' : 0x10,
62 'VK_CONTROL' : 0x11, 'VK_MENU' : 0x12, 'VK_PAUSE' : 0x13, 'VK_CAPITAL' : 0x14, 'VK_KANA' : 0x15,
63 'VK_HANGEUL' : 0x15, 'VK_HANGUL' : 0x15, 'VK_JUNJA' : 0x17, 'VK_FINAL' : 0x18, 'VK_HANJA' : 0x19,
64 'VK_KANJI' : 0x19, 'VK_ESCAPE' : 0x1B, 'VK_CONVERT' : 0x1C, 'VK_NONCONVERT' : 0x1D, 'VK_ACCEPT' : 0x1E,
65 'VK_MODECHANGE' : 0x1F, 'VK_SPACE' : 0x20, 'VK_PRIOR' : 0x21, 'VK_NEXT' : 0x22, 'VK_END' : 0x23,
66 'VK_HOME' : 0x24, 'VK_LEFT' : 0x25, 'VK_UP' : 0x26, 'VK_RIGHT' : 0x27, 'VK_DOWN' : 0x28,
67 'VK_SELECT' : 0x29, 'VK_PRINT' : 0x2A, 'VK_EXECUTE' : 0x2B, 'VK_SNAPSHOT' : 0x2C, 'VK_INSERT' : 0x2D,
68 'VK_DELETE' : 0x2E, 'VK_HELP' : 0x2F, 'VK_LWIN' : 0x5B, 'VK_RWIN' : 0x5C, 'VK_APPS' : 0x5D,
69 'VK_NUMPAD0' : 0x60, 'VK_NUMPAD1' : 0x61, 'VK_NUMPAD2' : 0x62, 'VK_NUMPAD3' : 0x63, 'VK_NUMPAD4' : 0x64,
70 'VK_NUMPAD5' : 0x65, 'VK_NUMPAD6' : 0x66, 'VK_NUMPAD7' : 0x67, 'VK_NUMPAD8' : 0x68, 'VK_NUMPAD9' : 0x69,
71 'VK_MULTIPLY' : 0x6A, 'VK_ADD' : 0x6B, 'VK_SEPARATOR' : 0x6C, 'VK_SUBTRACT' : 0x6D, 'VK_DECIMAL' : 0x6E,
72 'VK_DIVIDE' : 0x6F ,'VK_F1' : 0x70, 'VK_F2' : 0x71, 'VK_F3' : 0x72, 'VK_F4' : 0x73, 'VK_F5' : 0x74,
73 'VK_F6' : 0x75, 'VK_F7' : 0x76, 'VK_F8' : 0x77, 'VK_F9' : 0x78, 'VK_F10' : 0x79, 'VK_F11' : 0x7A,
74 'VK_F12' : 0x7B, 'VK_F13' : 0x7C, 'VK_F14' : 0x7D, 'VK_F15' : 0x7E, 'VK_F16' : 0x7F, 'VK_F17' : 0x80,
75 'VK_F18' : 0x81, 'VK_F19' : 0x82, 'VK_F20' : 0x83, 'VK_F21' : 0x84, 'VK_F22' : 0x85, 'VK_F23' : 0x86,
76 'VK_F24' : 0x87, 'VK_NUMLOCK' : 0x90, 'VK_SCROLL' : 0x91, 'VK_LSHIFT' : 0xA0, 'VK_RSHIFT' : 0xA1,
77 'VK_LCONTROL' : 0xA2, 'VK_RCONTROL' : 0xA3, 'VK_LMENU' : 0xA4, 'VK_RMENU' : 0xA5, 'VK_PROCESSKEY' : 0xE5,
78 'VK_ATTN' : 0xF6, 'VK_CRSEL' : 0xF7, 'VK_EXSEL' : 0xF8, 'VK_EREOF' : 0xF9, 'VK_PLAY' : 0xFA,
79 'VK_ZOOM' : 0xFB, 'VK_NONAME' : 0xFC, 'VK_PA1' : 0xFD, 'VK_OEM_CLEAR' : 0xFE, 'VK_BROWSER_BACK' : 0xA6,
80 'VK_BROWSER_FORWARD' : 0xA7, 'VK_BROWSER_REFRESH' : 0xA8, 'VK_BROWSER_STOP' : 0xA9, 'VK_BROWSER_SEARCH' : 0xAA,
81 'VK_BROWSER_FAVORITES' : 0xAB, 'VK_BROWSER_HOME' : 0xAC, 'VK_VOLUME_MUTE' : 0xAD, 'VK_VOLUME_DOWN' : 0xAE,
82 'VK_VOLUME_UP' : 0xAF, 'VK_MEDIA_NEXT_TRACK' : 0xB0, 'VK_MEDIA_PREV_TRACK' : 0xB1, 'VK_MEDIA_STOP' : 0xB2,
83 'VK_MEDIA_PLAY_PAUSE' : 0xB3, 'VK_LAUNCH_MAIL' : 0xB4, 'VK_LAUNCH_MEDIA_SELECT' : 0xB5, 'VK_LAUNCH_APP1' : 0xB6,
84 'VK_LAUNCH_APP2' : 0xB7, 'VK_OEM_1' : 0xBA, 'VK_OEM_PLUS' : 0xBB, 'VK_OEM_COMMA' : 0xBC, 'VK_OEM_MINUS' : 0xBD,
85 'VK_OEM_PERIOD' : 0xBE, 'VK_OEM_2' : 0xBF, 'VK_OEM_3' : 0xC0, 'VK_OEM_4' : 0xDB, 'VK_OEM_5' : 0xDC,
86 'VK_OEM_6' : 0xDD, 'VK_OEM_7' : 0xDE, 'VK_OEM_8' : 0xDF, 'VK_OEM_102' : 0xE2, 'VK_PROCESSKEY' : 0xE5,
87 'VK_PACKET' : 0xE7}
88
89
90 id_to_vk = dict([(v,k) for k,v in vk_to_id.items()])
91
92
93 msg_to_name = {WM_MOUSEMOVE : 'mouse move', WM_LBUTTONDOWN : 'mouse left down',
94 WM_LBUTTONUP : 'mouse left up', WM_LBUTTONDBLCLK : 'mouse left double',
95 WM_RBUTTONDOWN : 'mouse right down', WM_RBUTTONUP : 'mouse right up',
96 WM_RBUTTONDBLCLK : 'mouse right double', WM_MBUTTONDOWN : 'mouse middle down',
97 WM_MBUTTONUP : 'mouse middle up', WM_MBUTTONDBLCLK : 'mouse middle double',
98 WM_MOUSEWHEEL : 'mouse wheel', WM_KEYDOWN : 'key down',
99 WM_KEYUP : 'key up', WM_CHAR : 'key char', WM_DEADCHAR : 'key dead char',
100 WM_SYSKEYDOWN : 'key sys down', WM_SYSKEYUP : 'key sys up',
101 WM_SYSCHAR : 'key sys char', WM_SYSDEADCHAR : 'key sys dead char'}
102
104 '''
105 Class method. Converts a message value to message name.
106
107 @param msg: Keyboard or mouse event message
108 @type msg: integer
109 @return: Name of the event
110 @rtype: string
111 '''
112 return HookConstants.msg_to_name.get(msg)
113
115 '''
116 Class method. Converts a virtual keycode name to its value.
117
118 @param vkey: Virtual keycode name
119 @type vkey: string
120 @return: Virtual keycode value
121 @rtype: integer
122 '''
123 return HookConstants.vk_to_id.get(vkey)
124
126 '''
127 Class method. Gets the keycode name for the given value.
128
129 @param code: Virtual keycode value
130 @type code: integer
131 @return: Virtual keycode name
132 @rtype: string
133 '''
134 if (code >= 0x30 and code <= 0x39) or (code >= 0x41 and code <= 0x5A):
135 text = chr(code)
136 else:
137 text = HookConstants.id_to_vk.get(code)
138 if text is not None:
139 text = text[3:].title()
140 return text
141
142 MsgToName=classmethod(MsgToName)
143 IDToName=classmethod(IDToName)
144 VKeyToID=classmethod(VKeyToID)
145
147 '''
148 Holds information about a general hook event.
149
150 @ivar Message: Keyboard or mouse event message
151 @type Message: integer
152 @ivar Time: Seconds since the epoch when the even current
153 @type Time: integer
154 @ivar Window: Window handle of the foreground window at the time of the event
155 @type Window: integer
156 @ivar WindowName: Name of the foreground window at the time of the event
157 @type WindowName: string
158 '''
159 - def __init__(self, msg, time, hwnd, window_name):
160 '''Initializes an event instance.'''
161 self.Message = msg
162 self.Time = time
163 self.Window = hwnd
164 self.WindowName = window_name
165
167 '''
168 @return: Name of the event
169 @rtype: string
170 '''
171 return HookConstants.MsgToName(self.Message)
172 MessageName = property(fget=GetMessageName)
173
175 '''
176 Holds information about a mouse event.
177
178 @ivar Position: Location of the mouse event on the screen
179 @type Position: 2-tuple of integer
180 @ivar Wheel: Positive if the wheel scrolls up, negative if down, zero otherwise
181 @type Wheel: integer
182 @ivar Injected: Was this event generated programmatically?
183 @type Injected: boolean
184 '''
185 - def __init__(self, msg, x, y, data, flags, time, hwnd, window_name):
186 '''Initializes an instance of the class.'''
187 HookEvent.__init__(self, msg, time, hwnd, window_name)
188 self.Position = (x,y)
189 if data > 0: w = 1
190 elif data < 0: w = -1
191 else: w = 0
192 self.Wheel = w
193 self.Injected = flags & 0x01
194
196 '''
197 Holds information about a mouse event.
198
199 @ivar KeyID: Virtual key code
200 @type KeyID: integer
201 @ivar ScanCode: Scan code
202 @type ScanCode: integer
203 @ivar Ascii: ASCII value, if one exists
204 @type Ascii: string
205 '''
206 - def __init__(self, msg, vk_code, scan_code, ascii, flags, time, hwnd, window_name):
207 '''Initializes an instances of the class.'''
208 HookEvent.__init__(self, msg, time, hwnd, window_name)
209 self.KeyID = vk_code
210 self.ScanCode = scan_code
211 self.Ascii = ascii
212 self.flags = flags
213
215 '''
216 @return: Name of the virtual keycode
217 @rtype: string
218 '''
219 return HookConstants.IDToName(self.KeyID)
220
222 '''
223 @return: Is this an extended key?
224 @rtype: boolean
225 '''
226 return self.flags & 0x01
227
229 '''
230 @return: Was this event generated programmatically?
231 @rtype: boolean
232 '''
233 return self.flags & 0x10
234
236 '''
237 @return: Was the alt key depressed?
238 @rtype: boolean
239 '''
240 return self.flags & 0x20
241
243 '''
244 @return: Is this a transition from up to down or vice versa?
245 @rtype: boolean
246 '''
247 return self.flags & 0x80
248
249 Key = property(fget=GetKey)
250 Extended = property(fget=IsExtended)
251 Injected = property(fget=IsInjected)
252 Alt = property(fget=IsAlt)
253 Transition = property(fget=IsTransition)
254
256 '''
257 Registers and manages callbacks for low level mouse and keyboard events.
258
259 @ivar mouse_funcs: Callbacks for mouse events
260 @type mouse_funcs: dictionary
261 @ivar keyboard_funcs: Callbacks for keyboard events
262 @type keyboard_funcs: dictionary
263 @ivar mouse_hook: Is a mouse hook set?
264 @type mouse_hook: boolean
265 @ivar key_hook: Is a keyboard hook set?
266 @type key_hook: boolean
267 '''
269 '''Initializes an instance by setting up an empty set of handlers.'''
270 self.mouse_funcs = {}
271 self.keyboard_funcs = {}
272
273 self.mouse_hook = False
274 self.key_hook = False
275
280
285
290
292 '''Stops watching for mouse events.'''
293 if self.mouse_hook:
294 cpyHook.cUnhook(HookConstants.WH_MOUSE_LL)
295 self.mouse_hook = False
296
298 '''Stops watching for keyboard events.'''
299 if self.keyboard_hook:
300 cpyHook.cUnhook(HookConstants.WH_KEYBOARD_LL)
301 self.keyboard_hook = False
302
303 - def MouseSwitch(self, msg, x, y, data, flags, time, hwnd, window_name):
304 '''
305 Passes a mouse event on to the appropriate handler if one is registered.
306
307 @param msg: Message value
308 @type msg: integer
309 @param x: x-coordinate of the mouse event
310 @type x: integer
311 @param y: y-coordinate of the mouse event
312 @type y: integer
313 @param data: Data associated with the mouse event (scroll information)
314 @type data: integer
315 @param flags: Flags associated with the mouse event (injected or not)
316 @type flags: integer
317 @param time: Seconds since the epoch when the even current
318 @type time: integer
319 @param hwnd: Window handle of the foreground window at the time of the event
320 @type hwnd: integer
321 '''
322 event = MouseEvent(msg, x, y, data, flags, time, hwnd, window_name)
323 func = self.mouse_funcs.get(msg)
324 if func:
325 return func(event)
326 else:
327 return True
328
329 - def KeyboardSwitch(self, msg, vk_code, scan_code, ascii, flags, time, hwnd, win_name):
330 '''
331 Passes a keyboard event on to the appropriate handler if one is registered.
332
333 @param msg: Message value
334 @type msg: integer
335 @param vk_code: The virtual keycode of the key
336 @type vk_code: integer
337 @param scan_code: The scan code of the key
338 @type scan_code: integer
339 @param ascii: ASCII numeric value for the key if available
340 @type ascii: integer
341 @param flags: Flags associated with the key event (injected or not, extended key, etc.)
342 @type flags: integer
343 @param time: Time since the epoch of the key event
344 @type time: integer
345 @param hwnd: Window handle of the foreground window at the time of the event
346 @type hwnd: integer
347 '''
348 event = KeyboardEvent(msg, vk_code, scan_code, ascii, flags, time, hwnd, win_name)
349 func = self.keyboard_funcs.get(msg)
350 if func:
351 return func(event)
352 else:
353 return True
354
356 '''
357 Registers the given function as the callback for this mouse event type. Use the
358 MouseMove property as a shortcut.
359
360 @param func: Callback function
361 @type func: callable
362 '''
363 if func is None:
364 self.disconnect(self.mouse_funcs, HookConstants.WM_MOUSEMOVE)
365 else:
366 self.connect(self.mouse_funcs, HookConstants.WM_MOUSEMOVE, func)
367
369 '''
370 Registers the given function as the callback for this mouse event type. Use the
371 MouseLeftUp property as a shortcut.
372
373 @param func: Callback function
374 @type func: callable
375 '''
376 if func is None:
377 self.disconnect(self.mouse_funcs, HookConstants.WM_LBUTTONUP)
378 else:
379 self.connect(self.mouse_funcs, HookConstants.WM_LBUTTONUP, func)
380
382 '''
383 Registers the given function as the callback for this mouse event type. Use the
384 MouseLeftDown property as a shortcut.
385
386 @param func: Callback function
387 @type func: callable
388 '''
389 if func is None:
390 self.disconnect(self.mouse_funcs, HookConstants.WM_LBUTTONDOWN)
391 else:
392 self.connect(self.mouse_funcs, HookConstants.WM_LBUTTONDOWN, func)
393
395 '''
396 Registers the given function as the callback for this mouse event type. Use the
397 MouseLeftDbl property as a shortcut.
398
399 @param func: Callback function
400 @type func: callable
401 '''
402 if func is None:
403 self.disconnect(self.mouse_funcs, HookConstants.WM_LBUTTONDBLCLK)
404 else:
405 self.connect(self.mouse_funcs, HookConstants.WM_LBUTTONDBLCLK, func)
406
408 '''
409 Registers the given function as the callback for this mouse event type. Use the
410 MouseRightUp property as a shortcut.
411
412 @param func: Callback function
413 @type func: callable
414 '''
415 if func is None:
416 self.disconnect(self.mouse_funcs, HookConstants.WM_RBUTTONUP)
417 else:
418 self.connect(self.mouse_funcs, HookConstants.WM_RBUTTONUP, func)
419
421 '''
422 Registers the given function as the callback for this mouse event type. Use the
423 MouseRightDown property as a shortcut.
424
425 @param func: Callback function
426 @type func: callable
427 '''
428 if func is None:
429 self.disconnect(self.mouse_funcs, HookConstants.WM_RBUTTONDOWN)
430 else:
431 self.connect(self.mouse_funcs, HookConstants.WM_RBUTTONDOWN, func)
432
434 '''
435 Registers the given function as the callback for this mouse event type. Use the
436 MouseRightDbl property as a shortcut.
437
438 @param func: Callback function
439 @type func: callable
440 '''
441 if func is None:
442 self.disconnect(self.mouse_funcs, HookConstants.WM_RBUTTONDBLCLK)
443 else:
444 self.connect(self.mouse_funcs, HookConstants.WM_RBUTTONDBLCLK, func)
445
447 '''
448 Registers the given function as the callback for this mouse event type. Use the
449 MouseMiddleUp property as a shortcut.
450
451 @param func: Callback function
452 @type func: callable
453 '''
454 if func is None:
455 self.disconnect(self.mouse_funcs, HookConstants.WM_MBUTTONUP)
456 else:
457 self.connect(self.mouse_funcs, HookConstants.WM_MBUTTONUP, func)
458
460 '''
461 Registers the given function as the callback for this mouse event type. Use the
462 MouseMiddleDown property as a shortcut.
463
464 @param func: Callback function
465 @type func: callable
466 '''
467 if func is None:
468 self.disconnect(self.mouse_funcs, HookConstants.WM_MBUTTONDOWN)
469 else:
470 self.connect(self.mouse_funcs, HookConstants.WM_MBUTTONDOWN, func)
471
473 '''
474 Registers the given function as the callback for this mouse event type. Use the
475 MouseMiddleDbl property as a shortcut.
476
477 @param func: Callback function
478 @type func: callable
479 '''
480 if func is None:
481 self.disconnect(self.mouse_funcs, HookConstants.WM_MBUTTONDBLCLK)
482 else:
483 self.connect(self.mouse_funcs, HookConstants.WM_MBUTTONDBLCLK, func)
484
486 '''
487 Registers the given function as the callback for this mouse event type. Use the
488 MouseWheel property as a shortcut.
489
490 @param func: Callback function
491 @type func: callable
492 '''
493 if func is None:
494 self.disconnect(self.mouse_funcs, HookConstants.WM_MOUSEWHEEL)
495 else:
496 self.connect(self.mouse_funcs, HookConstants.WM_MOUSEWHEEL, func)
497
509
521
533
545
557
572
587
589 '''
590 Registers the given function as the callback for this keyboard event type.
591 Use the KeyChar property as a shortcut.
592
593 B{Note}: this is currently non-functional, no WM_*CHAR messages are
594 processed by the keyboard hook.
595
596 @param func: Callback function
597 @type func: callable
598 '''
599 if func is None:
600 self.disconnect(self.keyboard_funcs, HookConstants.WM_CHAR)
601 self.disconnect(self.keyboard_funcs, HookConstants.WM_DEADCHAR)
602 self.disconnect(self.keyboard_funcs, HookConstants.WM_SYSCHAR)
603 self.disconnect(self.keyboard_funcs, HookConstants.WM_SYSDEADCHAR)
604 else:
605 self.connect(self.keyboard_funcs, HookConstants.WM_CHAR, func)
606 self.connect(self.keyboard_funcs, HookConstants.WM_DEADCHAR, func)
607 self.connect(self.keyboard_funcs, HookConstants.WM_SYSCHAR, func)
608 self.connect(self.keyboard_funcs, HookConstants.WM_SYSDEADCHAR, func)
609
611 '''
612 Registers the given function as the callback for all keyboard events.
613 Use the KeyAll property as a shortcut.
614
615 @param func: Callback function
616 @type func: callable
617 '''
618 self.SubscribeKeyDown(func)
619 self.SubscribeKeyUp(func)
620 self.SubscribeKeyChar(func)
621
622 MouseAll = property(fset=SubscribeMouseAll)
623 MouseAllButtons = property(fset=SubscribeMouseAllButtons)
624 MouseAllButtonsUp = property(fset=SubscribeMouseAllButtonsUp)
625 MouseAllButtonsDown = property(fset=SubscribeMouseAllButtonsDown)
626 MouseAllButtonsDbl = property(fset=SubscribeMouseAllButtonsDbl)
627
628 MouseWheel = property(fset=SubscribeMouseWheel)
629 MouseMove = property(fset=SubscribeMouseMove)
630 MouseLeftUp = property(fset=SubscribeMouseLeftUp)
631 MouseLeftDown = property(fset=SubscribeMouseLeftDown)
632 MouseLeftDbl = property(fset=SubscribeMouseLeftDbl)
633 MouseRightUp = property(fset=SubscribeMouseRightUp)
634 MouseRightDown = property(fset=SubscribeMouseRightDown)
635 MouseRightDbl = property(fset=SubscribeMouseRightDbl)
636 MouseMiddleUp = property(fset=SubscribeMouseMiddleUp)
637 MouseMiddleDown = property(fset=SubscribeMouseMiddleDown)
638 MouseMiddleDbl = property(fset=SubscribeMouseMiddleDbl)
639
640 KeyUp = property(fset=SubscribeKeyUp)
641 KeyDown = property(fset=SubscribeKeyDown)
642 KeyChar = property(fset=SubscribeKeyChar)
643 KeyAll = property(fset=SubscribeKeyAll)
644
645 - def connect(self, switch, id, func):
646 '''
647 Registers a callback to the given function for the event with the given ID in the
648 provided dictionary. Internal use only.
649
650 @param switch: Collection of callbacks
651 @type switch: dictionary
652 @param id: Event type
653 @type id: integer
654 @param func: Callback function
655 @type func: callable
656 '''
657 switch[id] = func
658
660 '''
661 Unregisters a callback for the event with the given ID in the provided dictionary.
662 Internal use only.
663
664 @param switch: Collection of callbacks
665 @type switch: dictionary
666 @param id: Event type
667 @type id: integer
668 '''
669 try:
670 del switch[id]
671 except:
672 pass
673