Применение низкоуровневых клавиатурных хуков с помощью Python и SetWindowsHookExA

Итак, я пытаюсь выяснить, как зарегистрировать глобальный клавиатурный хук с помощью Python. Судя по тому, что я прочитал, кажется нормальным не иметь обратного вызова в DLL. Если вы используете WH_KEYBOARD_LL. Я не могу подтвердить это наверняка, но меня обнадеживает то, что я не получаю ошибку 1428, как если бы я попытался подключиться, скажем, к WH_CBT.

Я получаю ручку-крюк, но ничего не появляется, когда я нажимаю кнопки на клавиатуре, как и ожидалось.

Есть идеи, почему мой обратный вызов не вызывается? Или это вообще возможно?

Соответствующий код:

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 < 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()
9
задан Sachin D 22 March 2012 в 09:16
поделиться