【Python】关于PyHook3.HookManager的几个坑

news2024/12/24 8:58:49

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

接下来进入正题。



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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/102614.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【服务器数据恢复】xfs文件系统误操作导致分区丢失不可用的数据恢复案例

服务器数据恢复环境: 某公司一组服务器:磁盘柜raid卡,raid5磁盘阵列; linux操作系统XFS文件系统,共3个分区。 服务器故障: 服务器重装操作系统,完成操作后用户发现服务器的磁盘分区出现问题&am…

大三上算法习题

难度&#xff1a;1 1 二分查找返回关键值key在长度为len的数组arr[]中的位置&#xff0c;没有key则返回-1 int bi_search( int key, int arr[], int len ) //1 二分查找返回关键值key在长度为len的数组arr[]中的位置&#xff0c;没有key则返回-1#include <iostream> u…

如何制作一张标准地图样式的地图(附数据)

概述 大家有没有想过这样一个问题&#xff0c;我们在标准地图网站上看到的标准地图的样式&#xff08;形状&#xff09;和我们平时用到的地图不一样&#xff0c;那么是什么原因导致的呢&#xff0c;我们能够制作这样样式&#xff08;形状&#xff09;的标准地图吗&#xff0c;…

Tableau可视化设计案例-04标靶图、甘特图、瀑布图

文章目录Tableau可视化设计案例04标靶图、甘特图、瀑布图1.标靶图1.1二月份电量销售额完成情况1.2参考线与参考区间2.甘特图2.1甘特图的概念与用途2.2交货延期情况的甘特图2.3不同的日期类型选择3.创建超市不同子类别产品的盈亏瀑布图Tableau可视化设计案例 本文是Tableau的案…

手把手转行|你真的要转行吗?

首先&#xff0c;我不鼓励盲目转行。 但凡你还有选择的机会&#xff0c;转行&#xff0c;都不是你的第一选择。 如果你是为了逃避而转行&#xff0c;那多半会以失败告终。 原因是&#xff0c;你现在想要逃避的问题&#xff0c;当前不解决&#xff0c;换一家公司&#xff0c;也要…

现在学编程,只要开始行动都不晚

我要告诉大家的是&#xff0c;学习编程&#xff0c;任何时候都不晚。 咱们首先说工资&#xff0c;我一直认为&#xff0c;不看工资的岗位纯属耍流氓。如果你关注每年的薪资排行榜&#xff0c;金融和 IT 行业连续多年稳居前二&#xff0c;而比较有意思的是&#xff0c;哪怕薪资…

C++ Primer 第二章 变量和基本类型

C Primer 第二章 变量和基本类型2.1. Primitive Built-in Types2.1.1. Arithmetic Types2.1.3. Literals2.2 Variables2.2.1. Variable DefinitionsInitializersList InitializationDefault Initialization2.2.2. Variable Declarations and Definitions2.2.3. Identifiers2.3.…

set系列集合、collection集合的总结

无序 不重复 无索引 HashSet 元素无序的底层原理&#xff1a;哈希表&#xff1a; JDk1.7之前&#xff1a; JDK1.8之后&#xff1a; 总结&#xff1a; HashSet 元素去重复的底层原理&#xff1a; 因为传入的参数值一样&#xff0c;所以重写之后的hashcode方法所给出的哈希值是…

开科唯识冲刺创业板:年营收3.7亿 红杉奕信是二股东

雷递网 雷建平 12月19日北京开科唯识技术股份有限公司&#xff08;简称&#xff1a;“开科唯识”&#xff09;日前递交招股书&#xff0c;准备在深交所创业板上市。开科唯识计划募资8亿元&#xff0c;其中&#xff0c;3.19亿用于开科唯识智能财富管理及投研一体化平台建设项目&…

怎样使用Odoo 16 实现多公司管理

专业人士面临的最具挑战性的任务之一是在同一系统内管理多家公司。我们希望在浏览产品时不从一家公司切换到另一家公司。母公司下各公司的集中管理制定了多公司方法。一个组织由多个地点的分支机构组成&#xff0c;而母公司管理他分支机构的产品列表。母公司的每个分支机构都使…

[附源码]Python计算机毕业设计Django医院挂号住院管理系统

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

后端必知:遵循Google Java规范并引入checkstyle检查

IDEA配置Code Style 协同工作时&#xff0c;为了保证统一的代码风格&#xff0c;要求我们使用的规范&#xff0c;如果大家都用的是 IDEA&#xff0c;则推荐使用 Google Code Style&#xff0c;推荐阅读Google Java 编程风格中文文档。 先下载配置文件&#xff1a;github.com/…

牛客竞赛每日俩题 - Day10

目录 输入输出的细节 函数find&#xff08;&#xff09;的用法 输入输出的细节 收件人列表__牛客网 细节一&#xff1a;当输入转行后又要使用getline&#xff08;&#xff09;时&#xff0c;必须先使用getchar&#xff08;&#xff09;吃掉前面的转行符\n;细节二&#xff1a…

介绍一个助你事半功倍的数据挖掘神器!!

在Pandas模块当中&#xff0c;对于表格数据的分组操作&#xff08;groupby&#xff09;和透视表&#xff08;pivot_table&#xff09;的制作一直都是比较常见的&#xff0c;今天小编为大家分享一个数据分析的利器&#xff0c;能够自动为我们完成上述提到的一系列操作&#xff0…

arcgis读取NetCDF格式的数据(c#读取数据)

项目里面要用到降雨的数据&#xff0c;正好是.NC格式的&#xff0c;以前也没用过&#xff0c;正好记录下&#xff0c;大家也可以参考下&#xff0c;首先是arcgis是如何处理NC数据的&#xff0c;在arcgis软件里面有个多维工具箱&#xff0c;我用的是汉化版本的&#xff0c;英文版…

[附源码]计算机毕业设计Python的剧本杀管理系统(程序+源码+LW文档)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程 项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等…

Verilog 简易单周期CPU

目录 本实验包含&#xff1a; 简易结构图&#xff1a; 各部件代码或实现&#xff1a; 控制器&#xff1a; 寄存器堆&#xff1a; ALU&#xff1a; 数据存储器&#xff1a; 指令存储器&#xff1a; CPU&#xff1a; tp&#xff08;仿真文件&#xff09;&#xff1a; 仿真…

如何去掉idea的诸多警告

File->setting->Editor->inspections 选择漏斗&#xff0c;选中warning&#xff0c;筛选出所有警告级别&#xff0c;然后去掉勾选&#xff0c;然后重启idea即可

重构物理Entity架构,支持更多的形状

上一节实战如何编译BEPUphysicsint源码到自己的项目, 如何整合物理引擎与Unity图形渲染。本节来从新调整设计,让物理的Entity基本操作与物理的形状分离,支持更多的物理形状,支持物理entity与Unity物体位移与旋转同步。主要分成以下3个部分: 1: 设计PhyBaseEntity&#xff0c;让…

学到一招!PyCharm连接MySQL竟如此简单!

在 PyCharm 中是可以通过内置的工具来连接、操作数据库的&#xff0c;并且对于市面上大多数主流数据库都是支持的。 连接 MySQL 首先打开 PyCharm &#xff0c;点击菜单栏的 View --> Tool Windows --> Database 或者直接点击 PyCharm 右侧的 Database 然后就会在 PyCh…