使用Python和SetWindowsHookExA应用低级键盘挂钩
所以我想弄清楚如何使用Python注册一个全局键盘钩子。从我所读到的内容来看,在DLL中没有回调似乎是可以的。如果你使用什么键盘。我不能确定这一点,但我发现令人鼓舞的是,如果我尝试连接到say使用Python和SetWindowsHookExA应用低级键盘挂钩,python,winapi,Python,Winapi,所以我想弄清楚如何使用Python注册一个全局键盘钩子。从我所读到的内容来看,在DLL中没有回调似乎是可以的。如果你使用什么键盘。我不能确定这一点,但我发现令人鼓舞的是,如果我尝试连接到sayWH\u CBT,我不会像我那样出现1428错误 我有一个钩子把手,但当我按键盘上的按钮时,什么也没显示出来 你知道为什么我的电话没人打吗?或者这可能吗 有关守则: import time import string import ctypes import functools import atexit
WH\u CBT
,我不会像我那样出现1428错误
我有一个钩子把手,但当我按键盘上的按钮时,什么也没显示出来
你知道为什么我的电话没人打吗?或者这可能吗
有关守则:
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()
导入时间
导入字符串
导入ctypes
导入功能工具
进口退欧
进口蟒蛇
从ctypes导入Windell
hookID=0
类键盘(对象):
按键事件向下=0
按键事件向上=2
按键输入=2
按键移位=16
键空间=32
钩钩动作=13
钩形键盘=13
HOOK_KEYDOWN=0x100
挂钩键合=0x101
类钩子:
“保存一般钩子信息”
定义初始化(自):
self.hook=0
self.struct=None
类HookStruct(ctypes.Structure):
''windows为键盘事件返回的结构''
__字段\ \=[
('keycode',ctypes.c_long),
('scancode',ctypes.c_long),
('flags',ctypes.c_long),
(“时间”,ctypes.c_long),
('info',ctypes.POINTER(ctypes.c_ulong))
]
def ascii_to_密钥码(self,char):
返回windl.user32.VkKeyScanA(ord(char))
def注入键向下(自身,键代码):
scancode=windell.user32.MapVirtualKeyA(keycode,0)
windell.user32.keybd_事件(keycode、scancode、Keyboard.KEY_事件下,0)
def注入键向上(自身,键代码):
scan=windell.user32.MapVirtualKeyA(键码,0)
windell.user32.keybd_事件(keycode,scan,Keyboard.KEY_事件,0)
def注入键按下(自身、键码、暂停=0.05):
自注入键向下(键代码)
时间。睡眠(暂停)
自注入键向上(键代码)
def注入顺序(自身、顺序、暂停=0.05):
对于输入序列:
如果键=='':
self.injection\u key\u press(键盘、按键、空格、暂停)
elif键=='\n':
自我注入键按(键盘键输入,暂停)
其他:
如果输入string.ascii_大写:
自注入键向下(键盘键移位)
self.inject_key_按(self.ascii_to_keycode(key),暂停)
自注入键向上(键盘键移位)
其他:
self.inject_key_按(self.ascii_to_keycode(key),暂停)
def_win32_copy_mem(self、dest、src):
src=ctypes.c\u void\u p(src)
rtlmovemory(ctypes.addressof(dest)、src、ctypes.sizeof(dest))
def_win32_get_last_错误(自身):
返回windl.kernel32.GetLastError()
def_win32_get_模块(自身,mname):
返回windl.kernel32.GetModuleHandleA(mname)
def\u win32\u调用\u下一个\u钩子(self、id、code、wparam、lparam):
返回windell.kernel32.CallNextHookEx(id、代码、wparam、lparam)
def_win32_set_hook(self、id、回调、模块、线程):
callback_decl=ctypes.WINFUNCTYPE(ctypes.c_long、ctypes.c_long、ctypes.c_long、ctypes.c_long)
返回windell.user32.SetWindowsHookExA(id,回调,模块,线程)
def_win32_解除挂钩(self,id):
返回windell.user32.UnhookWindowsHookEx(id)
def键盘_事件(自身、数据):
打印数据.scancode
返回错误
def捕获_输入(自身):
self.hook=Keyboard.hook()
self.hook.struct=Keyboard.HookStruct()
def低级别键盘程序(代码、事件类型、kb数据ptr):
#win32规范表示,如果代码小于0,则返回CallNextHookEx的结果
如果代码<0:
返回self.\u win32\u调用\u下一个\u钩子(self.hook.hook,代码,事件类型,kb\u数据\u ptr)
如果代码==Keyboard.HOOK\u操作:
#将数据从struct复制到Python结构中
self.\u win32\u copy\u mem(self.hook.struct,kb\u data\u ptr)
#只有在处理程序返回false时才调用其他处理程序-允许停止处理密钥
如果self.keyboard_事件(self.hook.struct):
返回self.\u win32\u调用\u下一个\u钩子(self.hook.hook,代码,事件类型,kb\u数据\u ptr)
#定位钩
尝试:
hookId=self.hook.hook=self.\u win32\u set\u hook(Keyboard.hook\u Keyboard,low\u level\u Keyboard\u proc,self.\u win32\u get\u module(0),0)
如果self.hook.hook==0:
打印“错误-”,self.\u win32\u get\u last\u Error()
其他:
打印'Hook ID-',self.Hook.Hook
除异常、错误外:
打印错误
#如果python退出,则取消注册钩子
atexit.register(functools.partial(self.\u win32\u unhook,self.hook.hook))
def end_捕获(自身):
如果self.hook.hook:
返回self.\u win32\u取消挂钩(self.hook.hook)
kb=Keyboard()#kb.injection_序列('这是一个测试,\n这是第2行')
kb.capture_input()
pythoncom.PumpMessages()
kb.end_capture()
我没有专门用Python尝试过这一点,但是是的,它应该可以用于低级键盘或鼠标挂钩。对于其他挂钩类型,挂钩函数必须位于dll中
HOOK_ACTION应该是0,而不是13。我无法让你的班级正常工作,但我找到了一种类似的方法来实现相同的目标 以下是经过修改的代码:
from collections import namedtuple
KeyboardEvent = namedtuple('KeyboardEvent', ['event_type', 'key_code',
'scan_code', 'alt_pressed',
'time'])
handlers = []
def listen():
"""
Calls `handlers` for each keyboard event received. This is a blocking call.
"""
# Adapted from http://www.hackerthreads.org/Topic-42395
from ctypes import windll, CFUNCTYPE, POINTER, c_int, c_void_p, byref
import win32con, win32api, win32gui, atexit
event_types = {win32con.WM_KEYDOWN: 'key down',
win32con.WM_KEYUP: 'key up',
0x104: 'key down', # WM_SYSKEYDOWN, used for Alt key.
0x105: 'key up', # WM_SYSKEYUP, used for Alt key.
}
def low_level_handler(nCode, wParam, lParam):
"""
Processes a low level Windows keyboard event.
"""
event = KeyboardEvent(event_types[wParam], lParam[0], lParam[1],
lParam[2] == 32, lParam[3])
for handler in handlers:
handler(event)
# Be a good neighbor and call the next hook.
return windll.user32.CallNextHookEx(hook_id, nCode, wParam, lParam)
# Our low level handler signature.
CMPFUNC = CFUNCTYPE(c_int, c_int, c_int, POINTER(c_void_p))
# Convert the Python handler into C pointer.
pointer = CMPFUNC(low_level_handler)
# Hook both key up and key down events for common keys (non-system).
hook_id = windll.user32.SetWindowsHookExA(win32con.WH_KEYBOARD_LL, pointer,
win32api.GetModuleHandle(None), 0)
# Register to remove the hook when the interpreter exits. Unfortunately a
# try/finally block doesn't seem to work here.
atexit.register(windll.user32.UnhookWindowsHookEx, hook_id)
while True:
msg = win32gui.GetMessage(None, 0, 0)
win32gui.TranslateMessage(byref(msg))
win32gui.DispatchMessage(byref(msg))
if __name__ == '__main__':
def print_event(e):
print(e)
handlers.append(print_event)
listen()
我制作了一个高级库来包装它:。Tim的原始代码不起作用的原因是,指向
低级键盘程序的ctypes函数指针被垃圾收集,因此他的回调无效且未被调用。它只是默默地失败了
Windows不保留Python指针,因此我们需要单独保留对确切的callback\u decl(callback)
ctypes的引用