钩子介绍
“钩子”是一种特殊的消息处理机制,它可以监视系统或者进程中的各种事件消息,截获发往目标窗口的消息并进行处理。我们可以在系统中自定义钩子,用来监视系统中特定事件的发生,完成特定功能,如屏幕取词,监视日志,截获键盘、鼠标输入等等。
钩子的种类很多,每种钩子可以截获相应的消息,如键盘钩子可以截获键盘消息,外壳钩子可以截取、启动和关闭应用程序的消息等。钩子可以分为线程钩子和系统钩子,线程钩子可以监视指定线程的事件消息,系统钩子监视系统中的所有线程的事件消息。因为系统钩子会影响系统中所有的应用程序,所以钩子函数必须放在独立的动态链接库 (DLL) 中。
当创建一个钩子时,Windows会先在内存中创建一个数据结构,该数据结构包含了钩子的相关信息,然后把该结构体加到已经存在的钩子链表中去。所以说,hook(钩子)就是一个Windows消息的拦截机制,可以拦截单个进程的消息 (线程钩子),也可以拦截所有进程的消息 (系统钩子),也可以对拦截的消息进行自定义的处理。
使用系统钩子需要谨慎,因为它会影响系统中所有的应用程序,可能会降低系统性能。此外,滥用系统钩子可能会导致安全问题,因为它允许一个程序监视或改变其他程序的行为。只有在必要的时候才应该使用系统钩子。
钩子举例
在这里展示的两个Python钩子程序,这个Python程序并不是一个传统意义上的Windows系统钩子或线程钩子。这两个Python钩子程序,虽然可以在后台运行并捕获鼠标、键盘事件,但它并不是传统意义上的Windows系统钩子。在Windows编程中,多数使用C++和Windows API来设置各种类型的系统钩子和线程钩子,可以拦截所有进程的消息。而这个Python程序是在应用程序级别工作的,它只能监听运行这个Python程序的进程中的事件。
总的来说,这个Python程序可以看作是一个应用程序级别的线程钩子,它并不具备系统钩子那样可以全局拦截消息的能力。
鼠标钩子
在这个程序中,我们定义了三个函数on_move
、on_click
和on_scroll
来处理鼠标移动、点击和滚动事件。然后,我们创建了一个鼠标监听器,并将这三个函数作为参数传递给它。当你运行这个程序时,每当你移动鼠标、点击鼠标按钮或滚动鼠标滚轮时,相应的函数就会被调用,并在控制台输出一个消息。
# 导入pynput库中的mouse模块
from pynput import mouse
# 定义当鼠标移动时要执行的操作
def on_move(x, y):
# 打印出鼠标当前的位置
print('鼠标移动到 ({0}, {1})'.format(x, y))
# 定义当鼠标按钮被点击时要执行的操作
def on_click(x, y, button, pressed):
# 如果鼠标按钮被按下,打印出按键信息和位置
if pressed:
print('{0} 在 ({1}, {2}) 被按下'.format(button, x, y))
# 如果鼠标按钮被释放,打印出按键信息和位置
else:
print('{0} 在 ({1}, {2}) 被释放'.format(button, x, y))
# 定义当鼠标滚轮被滚动时要执行的操作
def on_scroll(x, y, dx, dy):
# 打印出鼠标滚轮的滚动方向和滚动量
print('鼠标在 ({0}, {1}) 滚动了 {2}'.format(x, y, dy))
# 创建并启动鼠标监听器
with mouse.Listener(on_move=on_move, on_click=on_click,on_scroll=on_scroll) as listener:
listener.join()
键盘钩子
在这个程序中,我们定义了两个函数on_press
和on_release
来处理键盘按键按下和释放事件。然后,我们创建了一个键盘监听器,并将这两个函数作为参数传递给它。当你运行这个程序时,每当你按下或释放一个键,相应的函数就会被调用,并在控制台输出一个消息。
# 导入pynput库中的keyboard模块
from pynput import keyboard
# 定义当按键被按下时要执行的操作
def on_press(key):
try:
# 如果按下的是字母或数字键,打印出按键信息
# 如果key.char是None,那么就会使用key.name来代替
print('字母或数字键 {0} 被按下'.format(key.char if key.char is not None else key.name))
except AttributeError:
# 如果按下的是特殊键(如空格键或回车键),打印出按键信息
print('特殊键 {0} 被按下'.format(key))
# 定义当按键被释放时要执行的操作
def on_release(key):
# 打印出被释放的按键信息
print('{0} 被释放'.format(key))
# 如果按下的是Esc键,停止监听
if key == keyboard.Key.esc:
return False
# 创建并启动键盘监听器
with keyboard.Listener(on_press=on_press,on_release=on_release) as listener:
listener.join()