使用具有设置延迟的mouse_event的平滑鼠标移动C ++

问题描述 投票:0回答:2

我正在编码鼠标宏。它需要在屏幕上的每个点之间以设置的延迟满足某些点。例如,它必须在132毫秒内移动(x 14,y 30)。我遇到的问题是mouse_event跳到那个确切的位置,因此我需要包括某种平滑方法,以便它可以平滑地移动到每个点。 (移动越流畅,宏越好)。目前,我正在使用这种平滑每个运动的方法。

这很好,但是有其局限性,例如,如果它需要向左移动10个像素并且将平滑设置为20,它将继续跳跃。

有人知道一种更精确的平滑鼠标移动方法吗? (要求准确,流畅)

void Smoothing(int smoothing, int delay, int x, int y) {
    for (int i = 0; i < smoothing; i++) {
        mouse_event(1, x / smoothing, y / smoothing, 0, 0);
        AccurateSleep(delay / smoothing);
    }
    mouse_event(1, x % smoothing, y % smoothing, 0, 0);
    Sleep(delay % smoothing);
}


c++ macros mouseevent mouse smoothing
2个回答
1
投票

[Linear Interpolation是我在阅读问题时(以及在the other answer中提到的)时的第一个想法。

用于插值的通用公式是:

x 0 + t·x 1

<< x ...插值

x 0

...起始值x 1 ...目标值t ...范围[0,1]中的插值参数>[当我意识到可能构成约束的一些事实时,我甚至打算将其写为答案(不幸的是,OP并未明确提及)。

所有操作都是关于整数值。因此,最好进行整数运算。

    mouse_event()以及AccurateSleep()用增量值调用。这可能是由OP使用的API决定的。
  1. 所以,我三思而后行,做出了以下MCVE以类似于OP问题:
  • #include <iostream> static int xMouse = 0, yMouse = 0, t = 0; void mouse_event(int _1, int dx, int dy, int _4, int _5) { xMouse += dx; yMouse += dy; std::cout << "mouse_event(" << _1 << ", " << dx << ", " << dy << ", " << _4 << ", " << _5 << "): " << xMouse << ", " << yMouse << '\n'; } void AccurateSleep(int delay) { t += delay; std::cout << "AccurateSleep(" << delay << "): " << t << '\n'; } void Sleep(int delay) { t += delay; std::cout << "Sleep(" << delay << "): " << t << '\n'; } void Smoothing(int smoothing, int delay, int x, int y) { for (int i = 0; i < smoothing; i++) { mouse_event(1, x / smoothing, y / smoothing, 0, 0); AccurateSleep(delay / smoothing); } mouse_event(1, x % smoothing, y % smoothing, 0, 0); Sleep(delay % smoothing); } #define PRINT_AND_DO(...) std::cout << #__VA_ARGS__ << ";\n"; __VA_ARGS__ int main() { PRINT_AND_DO(xMouse = 0; yMouse = 0; t = 0); PRINT_AND_DO(Smoothing(10, 132, 14, 30)); PRINT_AND_DO(xMouse = 0; yMouse = 0; t = 0); PRINT_AND_DO(Smoothing(20, 15, 10, 0)); }

    输出:

    xMouse = 0; yMouse = 0; t = 0;
    Smoothing(10, 132, 14, 30);
    mouse_event(1, 1, 3, 0, 0): 1, 3
    AccurateSleep(13): 13
    mouse_event(1, 1, 3, 0, 0): 2, 6
    AccurateSleep(13): 26
    mouse_event(1, 1, 3, 0, 0): 3, 9
    AccurateSleep(13): 39
    mouse_event(1, 1, 3, 0, 0): 4, 12
    AccurateSleep(13): 52
    mouse_event(1, 1, 3, 0, 0): 5, 15
    AccurateSleep(13): 65
    mouse_event(1, 1, 3, 0, 0): 6, 18
    AccurateSleep(13): 78
    mouse_event(1, 1, 3, 0, 0): 7, 21
    AccurateSleep(13): 91
    mouse_event(1, 1, 3, 0, 0): 8, 24
    AccurateSleep(13): 104
    mouse_event(1, 1, 3, 0, 0): 9, 27
    AccurateSleep(13): 117
    mouse_event(1, 1, 3, 0, 0): 10, 30
    AccurateSleep(13): 130
    mouse_event(1, 4, 0, 0, 0): 14, 30
    Sleep(2): 132
    
    xMouse = 0; yMouse = 0; t = 0;
    Smoothing(20, 15, 10, 0);
    mouse_event(1, 0, 0, 0, 0): 0, 0
    AccurateSleep(0): 0
    mouse_event(1, 0, 0, 0, 0): 0, 0
    AccurateSleep(0): 0
    mouse_event(1, 0, 0, 0, 0): 0, 0
    AccurateSleep(0): 0
    mouse_event(1, 0, 0, 0, 0): 0, 0
    AccurateSleep(0): 0
    mouse_event(1, 0, 0, 0, 0): 0, 0
    AccurateSleep(0): 0
    mouse_event(1, 0, 0, 0, 0): 0, 0
    AccurateSleep(0): 0
    mouse_event(1, 0, 0, 0, 0): 0, 0
    AccurateSleep(0): 0
    mouse_event(1, 0, 0, 0, 0): 0, 0
    AccurateSleep(0): 0
    mouse_event(1, 0, 0, 0, 0): 0, 0
    AccurateSleep(0): 0
    mouse_event(1, 0, 0, 0, 0): 0, 0
    AccurateSleep(0): 0
    mouse_event(1, 0, 0, 0, 0): 0, 0
    AccurateSleep(0): 0
    mouse_event(1, 0, 0, 0, 0): 0, 0
    AccurateSleep(0): 0
    mouse_event(1, 0, 0, 0, 0): 0, 0
    AccurateSleep(0): 0
    mouse_event(1, 0, 0, 0, 0): 0, 0
    AccurateSleep(0): 0
    mouse_event(1, 0, 0, 0, 0): 0, 0
    AccurateSleep(0): 0
    mouse_event(1, 0, 0, 0, 0): 0, 0
    AccurateSleep(0): 0
    mouse_event(1, 0, 0, 0, 0): 0, 0
    AccurateSleep(0): 0
    mouse_event(1, 0, 0, 0, 0): 0, 0
    AccurateSleep(0): 0
    mouse_event(1, 0, 0, 0, 0): 0, 0
    AccurateSleep(0): 0
    mouse_event(1, 0, 0, 0, 0): 0, 0
    AccurateSleep(0): 0
    mouse_event(1, 10, 0, 0, 0): 10, 0
    Sleep(15): 15
    

    然后我修改了Smoothing(),以实现上述插值公式,并对特定情况进行了一些调整:

    对于

      t,使用i / smoothingi的范围为[1,平滑])。
  • 虽然循环为每个i进行插值,但先前迭代的值将保留并用于计算mouse_event()AccurateSleep()的函数调用的增量值。
  • 当然,运算顺序很重要,因为这是整数运算。因此,xI = i * x / smoothing不等于xI = i / smoothing * x。 (即这些积分运算未提供可交换性。)
  • 修改后的Smoothing()
  • void Smoothing(int smoothing, int delay, int x, int y) { int x_ = 0, y_ = 0, t_ = 0; for (int i = 1; i <= smoothing; ++i) { // i / smoothing provides the interpolation paramter in [0, 1] int xI = i * x / smoothing; int yI = i * y / smoothing; int tI = i * delay / smoothing; mouse_event(1, xI - x_, yI - y_, 0, 0); AccurateSleep(tI - t_); x_ = xI; y_ = yI; t_ = tI; } }

    输出:

    xMouse = 0; yMouse = 0; t = 0;
    Smoothing(10, 132, 14, 30);
    mouse_event(1, 1, 3, 0, 0): 1, 3
    AccurateSleep(13): 13
    mouse_event(1, 1, 3, 0, 0): 2, 6
    AccurateSleep(13): 26
    mouse_event(1, 2, 3, 0, 0): 4, 9
    AccurateSleep(13): 39
    mouse_event(1, 1, 3, 0, 0): 5, 12
    AccurateSleep(13): 52
    mouse_event(1, 2, 3, 0, 0): 7, 15
    AccurateSleep(14): 66
    mouse_event(1, 1, 3, 0, 0): 8, 18
    AccurateSleep(13): 79
    mouse_event(1, 1, 3, 0, 0): 9, 21
    AccurateSleep(13): 92
    mouse_event(1, 2, 3, 0, 0): 11, 24
    AccurateSleep(13): 105
    mouse_event(1, 1, 3, 0, 0): 12, 27
    AccurateSleep(13): 118
    mouse_event(1, 2, 3, 0, 0): 14, 30
    AccurateSleep(14): 132
    
    xMouse = 0; yMouse = 0; t = 0;
    Smoothing(20, 15, 10, 0);
    mouse_event(1, 0, 0, 0, 0): 0, 0
    AccurateSleep(0): 0
    mouse_event(1, 1, 0, 0, 0): 1, 0
    AccurateSleep(1): 1
    mouse_event(1, 0, 0, 0, 0): 1, 0
    AccurateSleep(1): 2
    mouse_event(1, 1, 0, 0, 0): 2, 0
    AccurateSleep(1): 3
    mouse_event(1, 0, 0, 0, 0): 2, 0
    AccurateSleep(0): 3
    mouse_event(1, 1, 0, 0, 0): 3, 0
    AccurateSleep(1): 4
    mouse_event(1, 0, 0, 0, 0): 3, 0
    AccurateSleep(1): 5
    mouse_event(1, 1, 0, 0, 0): 4, 0
    AccurateSleep(1): 6
    mouse_event(1, 0, 0, 0, 0): 4, 0
    AccurateSleep(0): 6
    mouse_event(1, 1, 0, 0, 0): 5, 0
    AccurateSleep(1): 7
    mouse_event(1, 0, 0, 0, 0): 5, 0
    AccurateSleep(1): 8
    mouse_event(1, 1, 0, 0, 0): 6, 0
    AccurateSleep(1): 9
    mouse_event(1, 0, 0, 0, 0): 6, 0
    AccurateSleep(0): 9
    mouse_event(1, 1, 0, 0, 0): 7, 0
    AccurateSleep(1): 10
    mouse_event(1, 0, 0, 0, 0): 7, 0
    AccurateSleep(1): 11
    mouse_event(1, 1, 0, 0, 0): 8, 0
    AccurateSleep(1): 12
    mouse_event(1, 0, 0, 0, 0): 8, 0
    AccurateSleep(0): 12
    mouse_event(1, 1, 0, 0, 0): 9, 0
    AccurateSleep(1): 13
    mouse_event(1, 0, 0, 0, 0): 9, 0
    AccurateSleep(1): 14
    mouse_event(1, 1, 0, 0, 0): 10, 0
    AccurateSleep(1): 15
    

    Live Demo on coliru

    注意:

    [最后一次迭代是用i == smoothing完成的,因此i / smoothing的结果为1。因此,最后的插值步骤会产生精确的值–像OP原始方法一样,不需要后校正。

    将点作为矢量查看并在它们之间进行插值。这通常被称为线性插值的“公差”排序。您可以找到许多资源,这些资源在搜索线性插值时可能会有所帮助。这是an answer,可能有助于您了解它的含义。
    由于我手头有多余的时间,所以我也输入了一个可以执行此操作的程序示例。

    #include <iostream> #include <chrono> struct Vec2d { double x; double y; Vec2d(double x, double y) : x(x), y(y) {}; }; Vec2d lerp(Vec2d const& a, Vec2d const& b, double t) { double x((1.0 - t) * a.x + t * b.x); double y((1.0 - t) * a.y + t * b.y); return Vec2d(x, y); } int main(int argc, char* argv[]) { Vec2d p1(10, 10); Vec2d p2(20, 40); double maxTime(100); //max time 100 milliseconds double elapsedTime(0); std::chrono::time_point<std::chrono::system_clock> start(std::chrono::system_clock::now()); std::chrono::time_point<std::chrono::system_clock> end(start); while(elapsedTime < maxTime) { elapsedTime += std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count(); start = end; //This is where the lerping happens double t(elapsedTime / maxTime); Vec2d p3(lerp(p1, p2, t)); //Show what's happening. std::cout << "p3: " << p3.x << ", " << p3.y << std::endl; end = std::chrono::system_clock::now(); } return 0; }

    简短说明:tisa值,从0到1。当t == 0.0时,lerp将返回p1的“副本”。当t == 1.0时,lerp将返回p2的“副本”。当t == 0.5时,lerp将返回(p1 + p2) / 2(它们之间的中点)。

    您还需要添加代码以不断更新鼠标的位置。为此,您需要跟踪经过了多少时间,并根据从tp1所需的时间量和实际经过的时间来计算p2的值。上面的代码使用while循环和std::chrono来跟踪经过的时间,从而做到了这一点。但是,此实现将取决于您打算如何触发这些“更新”。

    希望这有所帮助。

  • 0
    投票
    © www.soinside.com 2019 - 2024. All rights reserved.