HookManager.py 23 KB

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