首页 > 解决方案 > 如何在 Windows 10 (C++) 中生成全局滚动事件并禁用鼠标移动?

问题描述

我正在编写一个程序来在触摸板上实现手性滚动。我有读取原始触摸板数据的代码,并且我对如何实现手势有一个粗略的了解。我的问题是如何实现滚动行为。这些是我的要求:

  1. 我的程序需要能够生成滚动事件,就像默认的触摸板手势或鼠标滚轮一样。这应该会影响任何正在运行的程序,就像真正的鼠标或触摸板滚动一样。最好,滚动也应该是平滑的(不是大刻度)。
  2. 当滚动手势生效时,应该禁用正常的鼠标移动。这很重要,因为它将确保正在滚动的 UI 元素在滚动期间不会发生变化。
  3. 不应影响其他内置触摸板手势。

我在这里有什么选择?
有没有可以提供帮助的图书馆?
这是否需要作为某种驱动程序来实现?

我已经想到并研究了一些可能的解决方案,但它们似乎都不完整:

标签: c++windowswinapi

解决方案


我认为 hook 和SendInput可以满足您的需求。

这是一个快速的gif演示。

运行代码,

  1. 按“L”键=>安装鼠标钩(开始)
  2. 按鼠标左键 => 开始滚动
  3. 按鼠标右键 => 停止滚动
  4. 按“P”键 => 卸载鼠标钩子(结束)

安装挂钩后,鼠标无法移动。按下鼠标左键,鼠标会自动滚动。按鼠标右键停止滚动。按P键卸载钩子后,一切都会恢复正常。

当鼠标自动滚动时,我仍然可以手动滚动鼠标滚轮。

代码示例:(代码比较粗略,仅供参考)

#include <Windows.h>
#include <iostream>
#include <thread>

using namespace std;

UINT ScrollMouse(int scroll);
void SetHook();
LRESULT __stdcall MouseHookCallback(int, WPARAM, LPARAM);

HHOOK MouseHook;
BOOL flag = 0;

void fun1()
{
    while (1)
    {
        if (GetAsyncKeyState(0x50) & 0x0001)
        {
            UnhookWindowsHookEx(MouseHook);
        }
    }
}

void fun2()
{
    while (1)
    {
        if (flag)
        {
            ScrollMouse(50);
            Sleep(100);
        }
    }
}

int fun3()
{
    while (1)
    {
        if (GetAsyncKeyState(0x4C) & 0x0001)
        {
            SetHook();
            MSG msg;

            while(GetMessage(&msg, NULL, 0, 0))
            {
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }
            return msg.wParam;
        }       
    }   
}

UINT ScrollMouse(int scroll)
{
    INPUT input;
    POINT pos;
    GetCursorPos(&pos);

    input.type = INPUT_MOUSE;
    input.mi.dwFlags = MOUSEEVENTF_WHEEL;
    input.mi.time = NULL; //Windows will do the timestamp
    input.mi.mouseData = (DWORD)scroll; //A positive value indicates that the wheel was rotated forward, away from the user; a negative value indicates that the wheel was rotated backward, toward the user. One wheel click is defined as WHEEL_DELTA, which is 120.
    input.mi.dx = pos.x;
    input.mi.dy = pos.y;
    input.mi.dwExtraInfo = GetMessageExtraInfo();

    return SendInput(1, &input, sizeof(INPUT));
}

LRESULT __stdcall MouseHookCallback(int nCode, WPARAM wParam, LPARAM lParam)
{
    if (nCode >= 0)
    {
        switch (wParam)
        {
        case WM_MOUSEMOVE:
        {           
            return 1;         
        }
        case WM_LBUTTONDOWN:
        {
            flag = 1;            
        }
        break;
        case WM_RBUTTONDOWN:
        {
            flag = 0;
        }
        break;
        }
    }
    return CallNextHookEx(MouseHook, nCode, wParam, lParam);
}

void SetHook()
{
    if (!(MouseHook = SetWindowsHookEx(WH_MOUSE_LL, MouseHookCallback, NULL, 0)))
    {
        cout << "Failed to install MouseHook hook!" << endl;
    }
}

int main()
{
    thread t1(fun1);
    thread t2(fun2);   
    thread t3(fun3);  
    t3.join();

    return 0;
}

推荐阅读