【问题标题】:Mouse pointer freezes after calling Sendinput, on minimize/maximize/close window buttons在最小化/最大化/关闭窗口按钮上调用 Sendinput 后​​鼠标指针冻结
【发布时间】:2014-12-20 22:20:58
【问题描述】:

我正在构建一个应用程序,该应用程序从另一台计算机接收鼠标移动/按下/释放命令,并使用 windows Sendinput 函数模拟它们。

除了单击生成 Sendinput 调用的同一窗口的最小化或最大化或关闭按钮之外,一切正常。

在这种情况下,鼠标指针在最小化按钮(或最大化或关闭)上冻结,并且 UI 事件循环似乎完全冻结。 如果我手动单击屏幕上的某个位置,UI 会解冻,一切都会再次运行。

这是我在最小化按钮顶部生成 sendinput 调用时发生的屏幕截图:

这是我用来模拟鼠标移动/按下/释放的代码: Mouse.cpp

#include "Mouse.h"

#ifdef _WIN32
    #include <windows.h>
#endif

#ifdef _WIN32

void Mouse::moveToPoint(const int x, const int y)
{
    // get screen resolution
    HDC hDCScreen = GetDC(NULL);
    int horres = GetDeviceCaps(hDCScreen, HORZRES);
    int vertres = GetDeviceCaps(hDCScreen, VERTRES);
    ReleaseDC(NULL, hDCScreen);

    const int points_in_line = 65535;
    const double points_in_x_pixel = points_in_line / static_cast<double>(horres);
    const double points_in_y_pixel = points_in_line / static_cast<double>(vertres);

    INPUT event;
    event.type = INPUT_MOUSE;
    event.mi.dx = x * points_in_x_pixel; //+ 0.5;
    event.mi.dy = y * points_in_y_pixel; //+ 0.5;
    event.mi.mouseData = 0;
    event.mi.dwFlags =  MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE;
    event.mi.time = 0;
    event.mi.dwExtraInfo = 0;

    SendInput(1, &event, sizeof(event));
}

void Mouse::press(Qt::MouseButton button)
{
    DWORD btn = button == Qt::LeftButton  ? MOUSEEVENTF_LEFTDOWN   :
                button == Qt::RightButton ? MOUSEEVENTF_RIGHTDOWN  :
                button == Qt::MidButton   ? MOUSEEVENTF_MIDDLEDOWN : 0;

    INPUT event;
    event.type = INPUT_MOUSE;
    event.mi.dx = 0;
    event.mi.dy = 0;
    event.mi.mouseData = 0;
    event.mi.dwFlags = btn;
    event.mi.time = 0;
    event.mi.dwExtraInfo = 0;

    SendInput(1, &event, sizeof(event));
}

void Mouse::release(Qt::MouseButton button)
{
    DWORD btn = button == Qt::LeftButton  ? MOUSEEVENTF_LEFTUP   :
                button == Qt::RightButton ? MOUSEEVENTF_RIGHTUP  :
                button == Qt::MidButton   ? MOUSEEVENTF_MIDDLEUP : 0;

    INPUT event;
    event.type = INPUT_MOUSE;
    event.mi.dx = 0;
    event.mi.dy = 0;
    event.mi.mouseData = 0;
    event.mi.dwFlags = btn;
    event.mi.time = 0;
    event.mi.dwExtraInfo = 0;

    SendInput(1, &event, sizeof(event));
}

void Mouse::scroll(int value)
{
    INPUT event;
    event.type = INPUT_MOUSE;
    event.mi.dx = 0;
    event.mi.dy = 0;
    event.mi.mouseData = value * WHEEL_DELTA;
    event.mi.dwFlags = MOUSEEVENTF_WHEEL;
    event.mi.time = 0;
    event.mi.dwExtraInfo = 0;

    SendInput(1, &event, sizeof(event));
}

void Mouse::doubleClick(Qt::MouseButton button)
{
    press(button);
    release(button);

    std::chrono::milliseconds dura(100);
    std::this_thread::sleep_for(dura);

    press(button);
    release(button);
}
#endif

和头文件:Mouse.h

#ifndef MOUSE_H
#define MOUSE_H

#include <thread>
#include <QtGlobal>
#include <QtEvents>
#include <QDebug>
#include <iostream> //std::cout

class Mouse {
public:
    // fails if given coordinates are not in the screen's rect
    // Linux: fails if there is an opening X display error
    static void moveToPoint(const int x, const int y);

    static void doubleClick(Qt::MouseButton button);

    // fails if the given button is not Qt::LeftButton, Qt::RightButton or Qt::MiddleButton
    // Linux: fails if there is an opening X display error
    static void press(Qt::MouseButton button);
    static void release(Qt::MouseButton button);

    // Linux: fails if there is an opening X display error
    static void scroll(int value); //positive values for scrolling up, negative for scrolling down

private:
    static Qt::MouseButtons bp;
    static void selectArea(const int x, const int y);
};
#endif // MOUSE_H

这种奇怪行为的原因可能是什么?

【问题讨论】:

  • 作为猜测,单击其中一个标题按钮会导致 Windows 进入其自己的消息循环等待按钮释放,以及您自己的消息循环正在等待的任何消息(知道何时释放按钮)在此期间不会发送给您。
  • @JonathanPotter 您的假设看起来合乎逻辑。我会尝试找到一种方法来发出从非 UI 线程调用 Sendinput 的 Qt 信号,看看会发生什么
  • @JonathanPotter 您的回答为我指明了正确的方向。我不得不从非 GUI 线程调用 Sendinput。我使用“Qt::ConnectionType::DirectConnection”选项将 SIGNAL 与 SLOT 连接起来,并从非 GUI 线程调用 emit。冻结问题现在解决了。您可以发布您的回复作为接受它的答案吗?
  • 当然可以。很高兴它有帮助!

标签: c++ qt winapi sendinput


【解决方案1】:

如您所见,单击其中一个标题按钮会导致 Windows 进入其自己的消息循环,等待按钮释放。

当 Windows 处于此消息循环中时,您自己的消息循环正在等待的任何消息(以了解何时释放按钮)都不会发送给您。您永远不会收到释放鼠标按钮的消息,因此永远不要注入该输入,因此指针似乎冻结了。

解决方案是将您的 SendInput 调用移至非 GUI 线程。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-16
    • 2014-03-30
    • 1970-01-01
    • 2021-08-26
    • 1970-01-01
    • 2016-10-04
    相关资源
    最近更新 更多