[英]Smooth Mouse Movement using mouse_event with set delay C++
I'm coding a mouse macro.我正在编写一个鼠标宏。 It needs to meet certain points on the screen in a set delay between each point.
它需要在每个点之间的设定延迟内满足屏幕上的某些点。 For exammple, it must move (x 14, y 30) in 132ms.
例如,它必须在 132 毫秒内移动 (x 14, y 30)。 The issue I'm having is mouse_event jumps to that exact position so I need to include some sort of smoothing method so that it moves smoothly to each point.
我遇到的问题是 mouse_event 跳转到那个确切位置,所以我需要包含某种平滑方法,以便它平滑地移动到每个点。 (the smoother the movement is the better the macro).
(运动越平滑,宏观越好)。 Currently I am using this method of smoothing each movement.
目前我正在使用这种平滑每个动作的方法。
This works well but it has its limitations for example if it needs to move 10 pixels left and the smoothing is set to 20 it will continue to jump.这很有效,但它有其局限性,例如,如果它需要向左移动 10 个像素并且平滑设置为 20,它将继续跳跃。
Does anyone know of a more accurate method of smoothing mouse movements?有谁知道平滑鼠标移动的更准确方法? (requirements accurate, smooth)
(要求准确、流畅)
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);
}
Linear Interpolation was my first thought when I read the question (as well as mentioned in the other answer ). 线性插值是我阅读问题时的第一个想法(以及在其他答案中提到的)。
A general formular for interpolation is:插值的通用公式是:
x = (1 - t) · x 0 + t · x 1 x = (1 - t) · x 0 + t · x 1
x ... interpolated value x ... 内插值
x 0 ... start value x 0 ... 起始值
x 1 ... destination value x 1 ... 目标值
t ... interpolation parameter in range [0, 1] t ... 范围内的插值参数 [0, 1]
I even intended to write this as answer when I realized some facts that might form possible constraints (which the OP unfortunately didn't mention explicitly).当我意识到一些可能构成可能约束的事实(不幸的是 OP 没有明确提及)时,我什至打算将其写为答案。
mouse_event()
as well as the AccurateSleep()
is called with delta values.mouse_event()
和AccurateSleep()
。 This might be dictated by the API used by OP. So, I thought twice and made the following MCVE to resemble OPs problem:所以,我三思而后行,使以下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));
}
Output:输出:
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
Then I modified Smoothing()
implementing the above mentioned interpolation formula with some adjustments to the specific situation:然后我修改了
Smoothing()
实现上述插值公式,并根据具体情况进行了一些调整:
i / smoothing
(with i
in range [1, smoothing]) is used.i / smoothing
( i
在 [1,平滑] 范围内)。i
, the values of previous iteration are kept and used to compute delta values for the function calls of mouse_event()
and AccurateSleep()
.i
进行插值时,前一次迭代的值被保留并用于计算mouse_event()
和AccurateSleep()
函数调用的增量值。xI = i * x / smoothing
is not equivalent to xI = i / smoothing * x
.xI = i * x / smoothing
不等于xI = i / smoothing * x
。 (Ie commutativity is not provided by these integral operations.) The modified Smoothing()
:修改后的
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;
}
}
Output:输出:
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在coliru上进行现场演示
Note:笔记:
The last iteration is done with i == smoothing
so that i / smoothing
results in 1. Hence, the last interpolation step yields the exact values – no post-correction is necessary like in OPs original approach.最后一次迭代是用
i == smoothing
完成的,因此i / smoothing
结果为 1。因此,最后一个插值步骤产生了精确的值——不需要像 OP 原始方法那样进行后校正。
View the points as vectors and interpolate between them.将点视为向量并在它们之间进行插值。 This is often referred to as "lerping" sort for linear interpolation.
这通常被称为线性插值的“lerping”排序。 You can find many resources that may help if you search up linear interpolation.
如果您搜索线性插值,您可以找到许多可能有帮助的资源。 Here's an answer that may help understand what it is.
这是一个可能有助于理解它是什么的答案。
Since I have extra time on my hands I've typed up an example of a program that does it as well.由于我手头有多余的时间,因此我已经输入了一个程序示例,该示例也可以执行此操作。
#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;
}
Short Explaination: t
isa value from 0 to 1. When t == 0.0
lerp
will return a "copy" of p1
.简短说明:
t
是从 0 到 1 的值。当t == 0.0
lerp
将返回p1
的“副本”。 When t == 1.0
lerp
will return a "copy" of p2
.当
t == 1.0
lerp
将返回p2
的“副本”。 When t == 0.5
lerp
will return (p1 + p2) / 2
(the mid point between them).当
t == 0.5
lerp
将返回(p1 + p2) / 2
(它们之间的中点)。
You'll also need to add code to continually update the position of the mouse.您还需要添加代码以不断更新鼠标的位置。 To do this you'll need to keep track of how much time has elapsed and calculate the value of
t
based on the amount of time required to travel from p1
to p2
and the actual time that has elapsed.为此,您需要跟踪经过了多少时间,并根据从
p1
到p2
所需的时间量以及实际经过的时间来计算t
的值。 The above code does this with the use of a while loop and std::chrono
to keep track of elapsed time.上面的代码使用 while 循环和
std::chrono
来跟踪经过的时间。 This will implementation however will be dependent on how you intend to trigger these "updates".然而,这将实现将取决于您打算如何触发这些“更新”。
Hope this helped.希望这有帮助。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.