如何使用 WinAPI 区分真实的鼠标滚轮和生成的滚轮?

How to distinguish between real mouse scrollwheels and generated ones, with WinAPI?

这个 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 事件,它们落入事件循环/事件侦听器中,并自行生成我不想要的新事件。

问题:如何避免此鼠标滚轮事件侦听器将代码生成的滚动考虑在内?

按照@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)