IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Python知识库 -> 【Python】关于PyHook3.HookManager的几个坑 -> 正文阅读

[Python知识库]【Python】关于PyHook3.HookManager的几个坑

疫情当下,群羊乱舞,请做好个人防护谨慎外出

接下来进入正题。



1、建议先把PyHook3.HookManager的一个小bug修好

这是类对象的析构bug,被析构(del)时触发:AttributeError: 'HookManager' object has no attribute 'keyboard_hook'

from PyHook3 import HookManager
def Func():
    hm = HookManager()
Func()    

因为这个bug我已经修过了,我就不发执行结果。
解决方法如图(点击图片跳转github链接):




2、HookManager的挂钩行为要在单个线程内完成,不允许跨线程

提到钩子,就不得不提到伟大的win32编程中的一个坑爹伟大的API,没错就是SetWindowsHookEx 函数 (winuser.h)
虽然它提到了调用SetWindowsHookEx之后需要调用UnhookWindowsHookEx卸载钩子,但是它只字不提跨线程的事,说的简单点就是,钩子的挂上和取下,都要在同一个函数内完成,不能跨线程,要不然你就能切身体会到什么叫“摸不着的痛苦”。关于win32的钩子使用方法我有空再写。

回到这里,同样的,PyHook3的全局钩子,怎么可能绕得开底层API,既然底层API都要在同个线程里完成钩子的挂上和取下,那么在Python更不用提了。如果不在同个生命周期内完成钩子的安装和卸载,那么这个钩子就直接废掉无法正常使用

测试代码如下:

from threading import Thread
from PyHook3 import HookManager
from time import sleep
import pythoncom

def onMouseEvent(event):#回调函数-鼠标
    print(event.Position)
    return True

hm=None#HookManager对象,由函数ThreadFunc创建生成
def ThreadFunc():
    global hm
    hm=HookManager()
    hm.MouseAll = onMouseEvent
    hm.HookMouse()
    # hm.UnhookMouse()#取消这条注释,或者注释掉上一条的“hm.HookMouse()”,都能成功运行钩子函数
    
if __name__=='__main__':
    Thread(target=ThreadFunc).start()
    sleep(0.1)
    hm.UnhookMouse()
    hm.HookMouse()
    pythoncom.PumpMessages()#进入消息循环

然后就是,顺便说一下“全局钩子”。以下为简短的科普时间,不感兴趣的可以跳过。

在win32编程中,全局钩子指的是鼠标和键盘,全局钩子是个挂上后到哪都能成功生效的玩意儿(而不只是局限于某个进程)。其中,钩子的枚举值为WH_KEYBOARD_LLWH_MOUSE_LL(点此查看所有钩子枚举值),其中“LL”的意思是“Low-Level”,也就是“低级”的意思,但这并不是通俗意义上的“差”的意思,而是“底层”的那种,说白了就是,它优先级高,而且生效范围广。一般情况下Low-Level函数会更加难用、更易受限一点(例如适用系统受限),例如Low-Level控制台输出函数




3、钩子挂上后必须进入消息循环

钩子必须进入消息循环才能正常生效,想通过time.sleep()threading.Event.wait()等方法替代消息循环让钩子只运行一段时间的白日梦实际上只会徒增痛苦。这里和“一般线程不允许修改UI元素,想修改UI元素必须使用UI线程”有点像,也就是“用特定的API完成特定的行为”,在这里的话就是挂上钩子后必须进入消息循环,(我可没说进入消息循环只能用pythoncom.PumpMessages这个函数)

from threading import Event#信号量
from threading import Thread
from PyHook3 import HookManager
from time import sleep
import pythoncom

def onMouseEvent(event):#回调函数-鼠标
    print(event.Position)
    return True

event=Event()#信号量
def ThreadFunc():
    hm=HookManager()
    hm.MouseAll = onMouseEvent
    hm.HookMouse()
    pythoncom.PumpMessages()#进入消息循环,只有这个才能成功运行,但是无法退出
    # sleep(1)#使用sleep,无端的挣扎并且钩子函数并没有成功调用
    # event.wait()#使用Event.wait等待信号,也是无端的挣扎
    hm.UnhookMouse()
    
if __name__=='__main__':
    event.clear()#清除状态
    Thread(target=ThreadFunc).start()
    sleep(2)
    event.set()#设置状态



4、建议使用win32gui.PumpMessages进入消息循环

这里先说一下,win32gui和pythoncom应该是一家人,为什么说是“应该”呢,因为我也没去细查。
pythoncom的API:http://www.markjour.com/docs/pywin32-docs/pythoncom.html
win32gui的API:http://www.markjour.com/docs/pywin32-docs/win32gui.html
这俩模块均在同一个网站中,只不过这网站我也不敢说它是官网,虽然文档是英文的,但是文档不全(有些API只有签名没有说明功能和用法),而且网页的标签图标居然是中文的“码”字…

然后就是,pythoncom.PumpMessageswin32gui.PumpMessages可以说是一模一样了,API一样,功能也一样的说,而且更主要的是,使用win32gui的API能让代码更加可控,让你随时退出消息循环取下钩子。运行下面测试代码,带你开辟新世界。(编程老手请绕道,容我在此装杯)

#代码运行的1秒内,移动鼠标将输出鼠标坐标
#代码运行1秒后,钩子取下
#代码运行2秒后,结束运行

import win32gui as WG#喜闻乐见的消息循环PumpMessages
import win32api as WA#获取当前线程tid
import win32con as WC#获取枚举值WM_QUIT
from threading import Thread
from PyHook3 import HookManager
from time import sleep

def onMouseEvent(event):#回调函数-鼠标
    print(event.Position)
    return True

tid=0#线程id
def ThreadFunc():#线程
    global tid
    hm = HookManager()
    hm.MouseAll = onMouseEvent
    hm.HookMouse()
    tid=WA.GetCurrentThreadId()
    WG.PumpMessages()


if __name__=='__main__':
	print("Start Tracking")
	Thread(target=ThreadFunc).start()

	sleep(1)
	print("Stop Tracking")
	WG.PostThreadMessage(tid,WC.WM_QUIT,0,0)#偶然找到的API:https://www.cnblogs.com/strive-sun/p/14487576.html

	sleep(1)
	print("Exit")
	exit()




以上就是本人踩过的关于PyHook3.HookManager的几个坑。码字不易,白嫖随意,但请勿私自转载。
原博客发布于CSDN:https://blog.csdn.net/weixin_44733774/article/details/128379683

  Python知识库 最新文章
Python中String模块
【Python】 14-CVS文件操作
python的panda库读写文件
使用Nordic的nrf52840实现蓝牙DFU过程
【Python学习记录】numpy数组用法整理
Python学习笔记
python字符串和列表
python如何从txt文件中解析出有效的数据
Python编程从入门到实践自学/3.1-3.2
python变量
上一篇文章      下一篇文章      查看所有文章
加:2022-12-25 11:04:55  更:2022-12-25 11:09:27 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年3日历 -2024/3/28 17:46:34-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码