我正在尝试用Python(3.4.3)后台应用程序(windows7/8)全局跟踪鼠标。这涉及到设置一个WindowsHook,它应该向我返回该特定钩子的有效句柄,但是我的句柄总是0。在
使用GetCursorPos
只跟踪鼠标位置非常简单(作为替代方案,GetCursorInfo
也可以):
from ctypes.wintypes import *
ppoint = ctypes.pointer(POINT())
ctypes.windll.user32.GetCursorPos(ppoint)
print('({}, {})'.format(ppoint[0].x, ppoint[0].y))
还可以方便地只跟踪位置^{
不过,我想也能跟踪点击,拖动等。
一个好的解决方案似乎是^{
为了能够使用LealLealMouthPro,文档告诉我们使用^{
HHOOK WINAPI SetWindowsHookEx(
_In_ int idHook,
_In_ HOOKPROC lpfn,
_In_ HINSTANCE hMod,
_In_ DWORD dwThreadId
);
在python中,以下值应该是我的正确值:
idHook
:^{hMod
:HINSTANCE(0)
(基本上是一个空指针)dwThreadId
:ctypes.windll.kernel32.GetCurrentThreadId()
对于lpfn
,我需要一些实现^{LLMouseProc
:
def _LLMouseProc (nCode, wParam, lParam):
return ctypes.windll.user32.CallNextHookEx(None, nCode, wParam, lParam)
LLMouseProcCB = ctypes.CFUNCTYPE(LRESULT, ctypes.c_int, WPARAM, LPARAM)
LLMouseProc = LLMouseProcCB(_LLMouseProc)
综上所述,我希望这能奏效:
from ctypes.wintypes import *
LONG_PTR = ctypes.c_long
LRESULT = LONG_PTR
WH_MOUSE_LL = 14
def _LLMouseProc(nCode, wParam, lParam):
print("_LLMouseProc({!s}, {!s}, {!s})".format(nCode, wParam, lParam))
return ctypes.windll.user32.CallNextHookEx(None, nCode, wParam, lParam)
LLMouseProcCB = ctypes.CFUNCTYPE(LRESULT, ctypes.c_int, WPARAM, LPARAM)
LLMouseProc = LLMouseProcCB(_LLMouseProc)
threadId = ctypes.windll.kernel32.GetCurrentThreadId()
# register callback as hook
print('hook = SetWindowsHookExW({!s}, {!s}, {!s}, {!s})'.format(WH_MOUSE_LL, LLMouseProc,
HINSTANCE(0), threadId))
hook = ctypes.windll.user32.SetWindowsHookExW(WH_MOUSE_LL, LLMouseProc,
HINSTANCE(0), threadId)
print('Hook: {}'.format(hook))
import time
try:
while True:
time.sleep(0.2)
except keyboardInterrupt:
pass
但是输出显示hook == 0
:
hook = SetWindowsHookExW(14, <CFunctionType object at 0x026183F0>, c_void_p(None), 5700)
Hook: 0
我认为回调函数的最后一个参数,名称lParam
与LPARAM(即ctypes.c_long
)不太正确,因为我假设实际需要的是指向这个结构的指针:
class MSLLHOOKSTRUCT(ctypes.Structure):
_fields_ = [
("pt", POINT),
("mouseData", DWORD),
("flags", DWORD),
("time", DWORD),
("dwExtraInfo", ULONG_PTR)
]
但是将签名改为LLMouseProcCB = ctypes.CFUNCTYPE(LRESULT, ctypes.c_int, WPARAM, ctypes.POINTER(MSLLHOOKSTRUCT))
并不能解决问题,我仍然有一个0的钩子。在
这是追踪鼠标的正确方法吗?我需要做些什么才能正确注册Windows钩子?在
如果您选中}。在
GetLastError
,您会发现错误是ERROR_GLOBAL_ONLY_HOOK
(1429),即WH_MOUSE_LL
需要设置一个全局钩子。dwThreadId
参数用于设置本地钩子。幸运的是,WH_MOUSE_LL
是不寻常的,因为全局钩子回调可以是挂接过程中的任何函数,而不必在DLL中定义,即hMod
可以是{如果需要支持32位Windows,请注意调用约定。通常,{cd8}的回调需要
另一个问题是您的代码缺少消息循环。设置钩子的线程需要运行一个消息循环,以便将消息发送到回调。在下面的示例中,我为这个消息循环使用了一个专用线程。线程设置钩子并进入一个循环,该循环仅在出错时或在发布
WM_QUIT
消息时中断。当用户输入Ctrl+C
时,我调用PostThreadMessageW
优雅地退出。在相关问题 更多 >
编程相关推荐