如何自动化鼠标操作

Ufx*_*Ufx 4 c++ events winapi mouseevent

我需要自动化一些鼠标操作。

我需要做
mousemove1, lbuttondown1, wait1, mousemove1, lbuttonup1, wait1,
mousemove2, lbuttondown2, wait2, mousemove2, lbuttonup2, wait2,
...

这些动作必须针对屏幕坐标起作用。此时必须接受事件的窗口是顶部窗口。

有一个包含数据的文件。
例如

500 450  1000  500 300  2000
600 450  1000  600 300  5000
Run Code Online (Sandbox Code Playgroud)

我试图做什么

#include <fstream>
#include <vector>
#include <windows.h>

struct A
{
    POINT point1;
    unsigned sleep1;
    POINT point2;
    unsigned sleep2;
    A() { point1.x = point1.y = sleep1 = point2.x = point2.y = sleep2 = 0; }
};

void f(const A &a)
{
    mouse_event(MOUSEEVENTF_LEFTDOWN, a.point1.x, a.point1.y, 0, 0);
    mouse_event(MOUSEEVENTF_MOVE,     a.point1.x, a.point1.y, 0, 0);
    Sleep(a.sleep1);

    mouse_event(MOUSEEVENTF_LEFTUP,   a.point2.x, a.point2.y, 0, 0);
    mouse_event(MOUSEEVENTF_MOVE,     a.point2.x, a.point2.y, 0, 0);
    Sleep(a.sleep2);
}

int main()
{
    std::vector<A> as;

    std::ifstream fin("params.txt");
    if (fin) {
        A a;
        while (fin.good()) {
            fin >> a.point1.x;
            fin >> a.point1.y;
            fin >> a.sleep1;

            fin >> a.point2.x;
            fin >> a.point2.y;
            fin >> a.sleep2;

            if (fin.eof()) {
                break;
            }
            as.push_back(a);
        }
    }

    for (;;) {
        for (const A &a : as) {
            f(a);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

发生了一些事情,但我不明白什么是错误以及错误在哪里。

Chr*_*les 6

您的代码的一个问题是您使用的是带有屏幕坐标的 mouse_event 而不是标准化的绝对坐标。归一化绝对坐标的范围始终介于左上角的 (0,0) 和右下角的 (65535,65535) 之间,无论桌面大小如何。

下面示例中的 MouseTo 函数接受屏幕坐标作为输入,然后使用桌面窗口的大小转换为规范化的绝对​​坐标。此示例使用 SendInput,它取代了 mouse_event,但它们都使用相同的坐标。我不确定 mouse_event 是否可以采用 MOUSEEVENTF_VIRTUALDESK 标志,但这是为了支持多显示器桌面。

如果您希望构建此示例,请从一个新的 Win32 控制台应用程序开始。

#include <Windows.h>
#include <cmath>

void MouseTo(int x, int y) {
    RECT desktop_rect;
    GetClientRect(GetDesktopWindow(), &desktop_rect);
    INPUT input = {0};
    input.type = INPUT_MOUSE;
    input.mi.dwFlags =
        MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_VIRTUALDESK | MOUSEEVENTF_MOVE;
    input.mi.dx = x * 65536 / desktop_rect.right;
    input.mi.dy = y * 65536 / desktop_rect.bottom;
    SendInput(1, &input, sizeof(input));
}

void MouseLButton(bool tf_down_up) {
    INPUT input = {0};
    input.type = INPUT_MOUSE;
    input.mi.dwFlags = tf_down_up ? MOUSEEVENTF_LEFTDOWN : MOUSEEVENTF_LEFTUP;
    SendInput(1, &input, sizeof(input));
}

void MouseLButtonDown() { MouseLButton(true);  }
void MouseLButtonUp()   { MouseLButton(false); }

void AnimatedDrag(const POINT& from, const POINT& to) {
    static const double iteration_dist     = 20;
    static const DWORD  iteration_delay_ms = 1;

    const double dx = to.x - from.x;
    const double dy = to.y - from.y;
    const double dist = sqrt(dx*dx + dy*dy);
    const int count = static_cast<int>(dist / iteration_dist);

    MouseTo(from.x, from.y);
    MouseLButtonDown();

    for(int i=1; i<count; ++i) {
        const int x = from.x + static_cast<int>(dx * i / count);
        const int y = from.y + static_cast<int>(dy * i / count);
        MouseTo(x, y);
        Sleep(iteration_delay_ms);
    }

    MouseTo(to.x, to.y);
    MouseLButtonUp();
}

int main() {
    // minimize console window
    ShowWindow(GetConsoleWindow(), SW_SHOWMINNOACTIVE);
    Sleep(500);

    // Drag whatever is at the window coordinates in "from" to "to"
    const POINT from = {300, 100};
    const POINT to   = {900, 600};
    AnimatedDrag(from, to);
}
Run Code Online (Sandbox Code Playgroud)