在最小化/最大化/关闭窗口按钮上调用Sendinput后鼠标指针冻结

时间:2014-10-25 02:24:31

标签: c++ qt winapi sendinput

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

除非我点击生成Sendinput调用的同一窗口的最小化或最大化或关闭按钮,否则一切正常。

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

以下是在最小化按钮上生成sendinput调用时会发生什么情况的屏幕截图: enter image description here

这是我用来模拟鼠标移动/按下/释放的代码: 的 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

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

1 个答案:

答案 0 :(得分:3)

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

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

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