【问题标题】:How to distinguish between real mouse scrollwheels and generated ones, with WinAPI?如何使用 WinAPI 区分真正的鼠标滚轮和生成的滚轮?
【发布时间】:2021-09-17 10:02:53
【问题描述】:

此 Python 代码检测鼠标滚轮滚动,它运行良好(参见 Get Mouse Wheel Scroll using Win32api in Python):

import win32api, win32con
from ctypes import windll, CFUNCTYPE, c_int, c_void_p, wintypes, byref
user32 = windll.user32
def LowLevelMouseProc(nCode, wParam, lParam):
    if wParam == win32con.WM_MOUSEWHEEL:
        print(nCode, wParam, lParam)
    # win32api.mouse_event(win32con.MOUSEEVENTF_WHEEL, 0, 0, 1, 0)             # code-generated scrollwheels
CMPFUNC = CFUNCTYPE(c_void_p, c_int, wintypes.WPARAM, wintypes.LPARAM)
user32.SetWindowsHookExW.argtypes = [c_int, CMPFUNC, wintypes.HINSTANCE, wintypes.DWORD]
pointer = CMPFUNC(LowLevelMouseProc)
hook_id = user32.SetWindowsHookExW(win32con.WH_MOUSE_LL,pointer,win32api.GetModuleHandle(None), 0)
msg = wintypes.MSG()
while user32.GetMessageW(byref(msg), 0, 0, 0) != 0:
    user32.TranslateMessage(msg)
    user32.DispatchMessageW(msg)

它可以工作,但它不区分滚动向下和滚动向上。在这两种情况下,我都有:

0 522 3010120
0 522 3010120
0 522 3010120
0 522 3010120

如何区分上下滚动,使用win32apictypes,但没有其他第三方库?

另外,根据一些特定的鼠标行为,我想触发额外的鼠标滚动:

def LowLevelMouseProc(nCode, wParam, lParam):
    if wParam == win32con.WM_MOUSEWHEEL:
        print(nCode, wParam, lParam)
    win32api.mouse_event(win32con.MOUSEEVENTF_WHEEL, 0, 0, 1, 0)    # TRIGGER HERE

问题:这些代码触发的假鼠标滚轮被检测为真正的 WM_MOUSEWHEEL 事件,它们落入事件循环/事件侦听器中,并自己生成新事件,这是我不想要的。

问题:如何避免这个鼠标滚轮事件监听器考虑到代码生成的滚动?

【问题讨论】:

  • 签入MSLLHOOKSTRUCT::flags LLMHF_INJECTED - 测试 LLMHF_INJECTED(位 0)将告诉您事件是否被注入。
  • inside LowLevelMouseProc - lParam - 指向 MSLLHOOKSTRUCT 结构的指针。
  • 你的 MSLLHOOKSTRUCT 声明是错误的。 DWORD mouseData; 在哪里?
  • 请注意(正如我在另一篇文章中评论的那样)你有 UB[SO]: C function called from Python via ctypes returns incorrect value (@CristiFati's answer),它的工作原理是纯粹的(愚蠢)运气。
  • @CristiFati 您能否建议对我当前的答案进行修改(这似乎可行,只是运气?)以纠正它?对以后的参考很有用,在此先感谢!

标签: python winapi mouse ctypes pywin32


【解决方案1】:

按照@RbMm 的建议,这是MSLLHOOKSTRUCT 的解决方案:

import win32api, win32con, ctypes
from ctypes import windll, CFUNCTYPE, c_int, c_void_p, wintypes, byref, POINTER, Structure
user32 = windll.user32

class MSLLHOOKSTRUCT(Structure):
    _fields_ = [
        ("x", ctypes.c_long),
        ("y", ctypes.c_long),
        ("mouseData", ctypes.c_ulong),
        ("flags", ctypes.c_ulong),
        ("time", ctypes.c_ulong),
        ("dwExtraInfo", ctypes.c_ulong)
    ]

def LowLevelMouseProc(nCode, wParam, lParam):
    if wParam == win32con.WM_MOUSEWHEEL:
        injected = lParam.contents.flags & 0x00000001
        print(lParam.contents.x, lParam.contents.y, injected)
        if injected == 0:
            win32api.mouse_event(win32con.MOUSEEVENTF_WHEEL, 0, 0, 1, 0)

CMPFUNC = CFUNCTYPE(c_void_p, c_int, wintypes.WPARAM, POINTER(MSLLHOOKSTRUCT))
user32.SetWindowsHookExW.argtypes = [c_int, CMPFUNC, wintypes.HINSTANCE, wintypes.DWORD]
pointer = CMPFUNC(LowLevelMouseProc)
hook_id = user32.SetWindowsHookExW(win32con.WH_MOUSE_LL, pointer, win32api.GetModuleHandle(None), 0)
msg = wintypes.MSG()
while user32.GetMessageW(byref(msg), 0, 0, 0) != 0:
    user32.TranslateMessage(msg)
    user32.DispatchMessageW(msg)

【讨论】:

    猜你喜欢
    • 2013-11-10
    • 2013-10-21
    • 2014-10-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-29
    相关资源
    最近更新 更多