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

Time:09-23

This Python code detects mouse wheel scrolls, it works perfectly (see 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)

It works but it does not distinguish between scrolling down and scrolling up. In both cases, I have:

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

How to distinguish up and down scrolls, by using win32api, ctypes, but no other third party library?

Also, based on some specific mouse behaviour, I'd like to trigger additional mousescrolls with:

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

Problem: these code-triggered fake mousewheels are detected as real WM_MOUSEWHEEL events, and they fall in the event loop / event listener, and generate themselves new events, which I don't want.

Question: how to avoid that this mousewheel event listener takes the code-generated scrolls in consideration?

CodePudding user response:

Following @RbMm's advice, here is a solution with 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)
  • Related