【发布时间】: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。冻结问题现在解决了。您可以发布您的回复作为接受它的答案吗?
-
当然可以。很高兴它有帮助!