简体   繁体   English

如何在 Windows 10 (C++) 中生成全局滚动事件并禁用鼠标移动?

[英]How to generate global scroll events and disable mouse movement in Windows 10 (C++)?

I'm writing a program to implement chiral scrolling on a touchpad.我正在编写一个程序来在触摸板上实现手性滚动。 I have the code to read the raw touchpad data, and I have a rough idea of how I want to implement the gesture.我有读取原始触摸板数据的代码,并且我对如何实现手势有一个粗略的了解。 My question is how to implement the scrolling behavior.我的问题是如何实现滚动行为。 These are my requirements:这些是我的要求:

  1. My program needs to be able to generate scrolling events, as if by the default touchpad gesture or the mouse scroll wheel.我的程序需要能够生成滚动事件,就像默认的触摸板手势或鼠标滚轮一样。 This should effect any program that is running, just like real mouse or touchpad scrolling.这应该会影响任何正在运行的程序,就像真正的鼠标或触摸板滚动一样。 Preferably, scrolling should be smooth as well (not in large ticks).最好,滚动也应该是平滑的(不是大刻度)。
  2. While the scrolling gesture is in effect, normal mouse movement should be disabled.当滚动手势生效时,应该禁用正常的鼠标移动。 This is important because it will ensure that the UI element that is being scrolled will not change during scrolling.这很重要,因为它将确保正在滚动的 UI 元素在滚动期间不会发生变化。
  3. Other built-in touchpad gestures should not be effected.不应影响其他内置触摸板手势。

What are my options here?我在这里有什么选择?
Are there any libraries that can help?有没有可以提供帮助的图书馆?
Does this need to be implemented as some kind of driver?这是否需要作为某种驱动程序来实现?

I have thought of and looked into a few possible solutions, but none of them seem complete:我已经想到并研究了一些可能的解决方案,但它们似乎都不完整:

  • There might be some sort of programmatic virtual mouse library, if so I could use this to generate scroll wheel events, but I haven't found such a library yet, and I'm not sure if it can achieve #2.可能有某种程序化的虚拟鼠标库,如果是这样我可以使用它来生成滚轮事件,但是我还没有找到这样的库,我不确定它是否可以实现#2。
  • I've read a little about Windows hooks, but it looks like that can only modify existing mouse events, which would not work here.我已经阅读了一些关于 Windows 钩子的内容,但看起来只能修改现有的鼠标事件,这在此处不起作用。
  • I've also read a little about the SentInput function, but it also doesn't sound like it could achieve #2, and I'm not sure if it can effect all other programs.我还阅读了一些关于 SentInput function 的信息,但听起来它也不能达到 #2,而且我不确定它是否会影响所有其他程序。

I think hook and SendInput can meet your needs.我认为 hook 和SendInput可以满足您的需求。

Here is a quick gif demo.这是一个快速的gif演示。

Run the code,运行代码,

  1. Press "L" key => install mouse hook(start)按“L”键=>安装鼠标钩(开始)
  2. Press left mouse button => Start scrolling按鼠标左键 => 开始滚动
  3. Press right mouse button => Stop scrolling按鼠标右键 => 停止滚动
  4. Press "P" key => uninstall mouse hook(end)按“P”键 => 卸载鼠标钩子(结束)

After the hook is installed, the mouse cannot be moved.安装挂钩后,鼠标无法移动。 Press the left mouse button and the mouse will scroll automatically.按下鼠标左键,鼠标会自动滚动。 Press the right mouse button to stop scrolling.按鼠标右键停止滚动。 After pressing the P key to uninstall the hook, everything will be back to normal.按P键卸载钩子后,一切都会恢复正常。

When the mouse is automatically scrolling, I can still manually scroll the mouse wheel.当鼠标自动滚动时,我仍然可以手动滚动鼠标滚轮。

Code Sample: (The code is rough, for reference only)代码示例:(代码比较粗略,仅供参考)

#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;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM