title: Applying low-level keyboard hooks with Python and SetWindowsHookExA
body: <p>So I'm trying to figure out how to register a global keyboard hook using Python.  From what I have read, it seems to be okay to not have the callback in a DLL. If you use WH_KEYBOARD_LL. I can't confirm that for sure but I find it encouraging that I don't get a 1428 error like I do if I try to hook into say <code>WH_CBT</code>.</p>
  
  <p>I get a hook handle but nothing shows up when I press buttons on the keyboard as I would expect.</p>
  
  <p>Any idea's on why my callback is not being called?  Or is this even possible?</p>
  
  <p>The relevant code :</p>
  
  <pre><code>import time
  import string
  import ctypes
  import functools
  import atexit
  import pythoncom
  from ctypes import windll
  
  hookID = 0
  
  class Keyboard(object):
  
      KEY_EVENT_DOWN = 0
      KEY_EVENT_UP = 2
  
      KEY_ENTER = 2
      KEY_SHIFT = 16
      KEY_SPACE = 32
  
      HOOK_ACTION = 13
      HOOK_KEYBOARD = 13
      HOOK_KEYDOWN = 0x100
      HOOK_KEYUP = 0x101
  
      class Hook:
          '''Holds general hook information'''
          def __init__(self):
              self.hook = 0
              self.struct = None            
  
      class HookStruct(ctypes.Structure):
          '''Structure that windows returns for keyboard events'''
          __fields__ = [
              ('keycode', ctypes.c_long),
              ('scancode', ctypes.c_long),
              ('flags', ctypes.c_long),
              ('time', ctypes.c_long),
              ('info', ctypes.POINTER(ctypes.c_ulong))
          ]
  
      def ascii_to_keycode(self, char):
          return windll.user32.VkKeyScanA(ord(char))
  
      def inject_key_down(self, keycode):
          scancode = windll.user32.MapVirtualKeyA(keycode, 0)
          windll.user32.keybd_event(keycode, scancode, Keyboard.KEY_EVENT_DOWN, 0)
  
      def inject_key_up(self, keycode):
          scan = windll.user32.MapVirtualKeyA(keycode, 0)
          windll.user32.keybd_event(keycode, scan, Keyboard.KEY_EVENT_UP, 0)
  
      def inject_key_press(self, keycode, pause=0.05):
          self.inject_key_down(keycode)
          time.sleep(pause)
          self.inject_key_up(keycode)
  
      def inject_sequence(self, seq, pause=0.05):
          for key in seq:
              if key == ' ':
                  self.inject_key_press(Keyboard.KEY_SPACE, pause)
              elif key == '\n':
                  self.inject_key_press(Keyboard.KEY_ENTER, pause)
              else:
                  if key in string.ascii_uppercase:
                      self.inject_key_down(Keyboard.KEY_SHIFT)
                      self.inject_key_press(self.ascii_to_keycode(key), pause)
                      self.inject_key_up(Keyboard.KEY_SHIFT)
                  else:
                      self.inject_key_press(self.ascii_to_keycode(key), pause)
  
      def _win32_copy_mem(self, dest, src):
          src = ctypes.c_void_p(src)
          windll.kernel32.RtlMoveMemory(ctypes.addressof(dest), src, ctypes.sizeof(dest))
  
      def _win32_get_last_error(self):
          return windll.kernel32.GetLastError()
  
      def _win32_get_module(self, mname):
          return windll.kernel32.GetModuleHandleA(mname)
  
      def _win32_call_next_hook(self, id, code, wparam, lparam):
          return windll.kernel32.CallNextHookEx(id, code, wparam, lparam)
  
      def _win32_set_hook(self, id, callback, module, thread):
          callback_decl = ctypes.WINFUNCTYPE(ctypes.c_long, ctypes.c_long, ctypes.c_long, ctypes.c_long)
          return windll.user32.SetWindowsHookExA(id, callback_decl(callback), module, thread)
  
      def _win32_unhook(self, id):
          return windll.user32.UnhookWindowsHookEx(id)
  
      def keyboard_event(self, data):
          print data.scancode
          return False
  
      def capture_input(self):
  
          self.hook = Keyboard.Hook()
          self.hook.struct = Keyboard.HookStruct()
  
          def low_level_keyboard_proc(code, event_type, kb_data_ptr):
              # win32 spec says return result of CallNextHookEx if code is less than 0
              if code &lt; 0:
                  return self._win32_call_next_hook(self.hook.hook, code, event_type, kb_data_ptr)
  
              if code == Keyboard.HOOK_ACTION:
                  # copy data from struct into Python structure
                  self._win32_copy_mem(self.hook.struct, kb_data_ptr)
  
                  # only call other handlers if we return false from our handler - allows to stop processing of keys
                  if self.keyboard_event(self.hook.struct):
                      return self._win32_call_next_hook(self.hook.hook, code, event_type, kb_data_ptr)
  
          # register hook 
          try:          
              hookId = self.hook.hook = self._win32_set_hook(Keyboard.HOOK_KEYBOARD, low_level_keyboard_proc, self._win32_get_module(0), 0)
              if self.hook.hook == 0:
                  print 'Error - ', self._win32_get_last_error()
              else:
                  print 'Hook ID - ', self.hook.hook
  
          except Exception, error:
              print error
  
          # unregister hook if python exits
          atexit.register(functools.partial(self._win32_unhook, self.hook.hook))
  
      def end_capture(self):
          if self.hook.hook:
              return self._win32_unhook(self.hook.hook)
  
  
  kb = Keyboard()#kb.inject_sequence('This is a test\nand tHis is line 2')
  kb.capture_input()
  pythoncom.PumpMessages()
  kb.end_capture()
  </code></pre>