使用Python进行Windows钩子

6 投票
1 回答
9060 浏览
提问于 2025-04-16 11:57

我正在尝试在Windows系统中获取一个钩子,并使用Python来记录键盘输入。为此,我使用了一个叫做LowLevelKeyboard Callback的过程。

def run():
    
    global KeyBdHook
    global messages
    
    KeyBdHook = HHook()
    messages = []
        
    start = time.time()

    #Record keystrokes for 2 seconds.
    while time.time() < (start + 2):
        KeyBdHook.hook = SetWindowsHookEx(13, KeyboardProc,
                                          GetModuleHandle(0), 0)
        if KeyBdHook.hook == 0:
            print 'ERROR: '+str(ctypes.windll.kernel32.GetLastError())
        UnhookWindowsHookEx(KeyBdHook.hook)
        
    print messages
            
def KeyboardProc(nCode, wParam, lParam):
    """http://msdn.microsoft.com/en-us/library/ms644985(v=vs.85).aspx"""
      

    if nCode < 0:
        return ctypes.windll.user32.GetNextHookEx(KeyBdHook.hook,
                                              nCode, wParam, lParam)
    else:
        ctypes.windll.kernel32.RtlMoveMemory(ctypes.addressof(KeyBdHook.kStruct),
                                             ctypes.c_void_p(lParam),
                                             ctypes.sizeof(lParam))
        
        messages.append(KeyBdHook.kStruct)
        return ctypes.windll.user32.GetNextHookEx(KeyBdHook.hook,
                                          nCode, wParam, lParam)
    
    
def SetWindowsHookEx(idHook, lpFn, hMod, dwThreadId):
    WinFunc = ctypes.WINFUNCTYPE(c_ulong, c_ulong, c_ulong, c_ulong)
    return ctypes.windll.user32.SetWindowsHookExA(idHook, WinFunc(lpFn), hMod, dwThreadId)

def GetModuleHandle(lpModuleName):
    return ctypes.windll.kernel32.GetModuleHandleA(lpModuleName)

def UnhookWindowsHookEx(hHook):
    return ctypes.windll.user32.UnhookWindowsHookEx(hHook)
    
class HHook():        
    def __init__(self):
        self.hook = HHOOK
        self.kStruct = KBLLHOOKSTRUCT()
        
class KBLLHOOKSTRUCT(Structure):
    """http://msdn.microsoft.com/en-us/library/ms644967(v=vs.85).aspx"""
    
    _fields_ = [("vkCode", c_ulong),
                ("scanCode", c_ulong),
                ("flags", c_ulong),
                ("time", c_ulong),
                ("dwExtraInfo", POINTER(c_ulong))]

问题是,它从来没有进入KeyboardProc这个函数。我在想,也许我需要用ctypes.WINFUNCTYPE或ctypes.CFUNCTYPE把它转换成C语言类型的函数,但我搞不明白怎么做。Windows在调用SetWindowsEx时似乎也没有报错。

我猜可能是SetWindowsEx没有正确处理传入的KeyboardProc参数。有没有什么办法可以转换这个参数,让Windows能够把数据输入到里面?谢谢。

1 个回答

6

为了重新提起一个老问题,ThiefMaster认为需要一个dll文件的看法并不准确。作为反例,我提供了一个纯Python的热键模块,它实现了提问者所要求的功能。这是GitHub上的项目链接

另外,如果你想要更多功能,我推荐pyHook或者pyhk

此外,如果你还想要更多功能,可以考虑pywinauto,它包含了热键模块,还有很多其他的功能。

撰写回答