mindtrove Collecting ideas since 1980

Monitoring Global Input with pyHook


The pyHook library wraps the low-level mouse and keyboard hooks in the Windows Hooking API for use in Python applications. This short tutorial demonstrates how to set keyboard and mouse hooks, what information is available about events, and how to pass or block events.

As of 10/8/08, the pyHook library is maintained by new developers. This tutorial is frozen against the last version I maintained, version 1.4. You may need to adjust your code to account for any API changes in new releases.

Prerequisites

Message Pump

Any application that wishes to receive notifications of global input events must have a Windows message pump. The easiest way to get one of these is to use the PumpMessages method in the Win32 Extensions package for Python.

1
2
3
import pythoncom 
 
pythoncom.PumpMessages()

When run, this program just sits idle and waits for Windows events. If you are using a GUI toolkit (e.g. wxPython), this loop is unnecessary since the toolkit provides its own.

Mouse Hooks

To receive mouse events, you must create a HookManager object and provide it will callbacks for the events in which you are interested. For instance, you can elect to receive only left button down events, only right button up events, only movement events, or all mouse events to name a few. Each event type can be directed to one and only one callback function.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import pythoncom, pyHook 
 
def OnMouseEvent(event):
  # called when mouse events are received
  print 'MessageName:',event.MessageName
  print 'Message:',event.Message
  print 'Time:',event.Time
  print 'Window:',event.Window
  print 'WindowName:',event.WindowName
  print 'Position:',event.Position
  print 'Wheel:',event.Wheel
  print 'Injected:',event.Injected
  print '---'
 
# return True to pass the event to other handlers
  return True
 
# create a hook manager
hm = pyHook.HookManager()
# watch for all mouse events
hm.MouseAll = OnMouseEvent
# set the hook
hm.HookMouse()
# wait forever
pythoncom.PumpMessages()

For a complete list of supported callbacks, see the properties of the HookManager class in the pyHook documentation.

Keyboard Hooks

Keyboard hooks work in the same manner as mouse hooks, but return different information.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import pythoncom, pyHook 
 
def OnKeyboardEvent(event):
  print 'MessageName:',event.MessageName
  print 'Message:',event.Message
  print 'Time:',event.Time
  print 'Window:',event.Window
  print 'WindowName:',event.WindowName
  print 'Ascii:', event.Ascii, chr(event.Ascii)
  print 'Key:', event.Key
  print 'KeyID:', event.KeyID
  print 'ScanCode:', event.ScanCode
  print 'Extended:', event.Extended
  print 'Injected:', event.Injected
  print 'Alt', event.Alt
  print 'Transition', event.Transition
  print '---'
 
# return True to pass the event to other handlers
  return True
 
# create a hook manager
hm = pyHook.HookManager()
# watch for all mouse events
hm.KeyDown = OnKeyboardEvent
# set the hook
hm.HookKeyboard()
# wait forever
pythoncom.PumpMessages()

Event Filtering

Callbacks for key and mouse events can decide whether or not to allow the event messages to pass to the windows for which they were intended. If a callback function returns True, the message is allowed to pass to callbacks registered by other applications and then onto its destination. If the function returns False, the message is blocked.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import pythoncom, pyHook 
 
def OnKeyboardEvent(event):
  # block only the letter A, lower and uppercase
  return (event.Ascii not in (ord('a'), ord('A')))
 
# create a hook manager
hm = pyHook.HookManager()
# watch for all mouse events
hm.KeyDown = OnKeyboardEvent
# set the hook
hm.HookKeyboard()
# wait forever
pythoncom.PumpMessages()

Not all key and mouse events can be blocked. For instance, pyHook allows the Ctrl-Alt-Delete combo as is suggested by the Windows hooking documentation. (This behavior could be changed by hacking the pyHook C extension so it doesn't play as nicely.)

Timing

If a callback function does not return in a timely manner, the event is automatically forwarded along the hook callback chain, and, if no other callback blocks it, onto the destination window. Therefore, as little processing as possible should be done in a callback. Instead, the callback should add events to a queue for later processing by an application and quickly decide whether or not to block the message.

References

This tutorial introduces the basics of the pyHook library. Please refer to the full pyHook API documentation for more information.