C# 真实地移动鼠标
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/913646/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
C# moving the mouse around realistically
提问by flavour404
I am demoing a piece of software and want to build a mouse 'mover' function so that I can basically automate the process. I want to create realistic mouse movements but am having a bit of a mental block in the thought process. I can move a mouse around easily with c# but want it to be a bit more realistic than just the cursor appearing at a certain x, y, coordinates and then pressing a button.
我正在演示一个软件,并希望构建一个鼠标“移动器”功能,以便我基本上可以自动化该过程。我想创建逼真的鼠标移动,但在思考过程中有点心理障碍。我可以使用 c# 轻松移动鼠标,但希望它比仅光标出现在某个 x、y 坐标处然后按下按钮更真实一些。
I get the current position of the mouse and then get the end point. Calculate an arc between the two points, but then I need to calculate points along that arc so that I can add a timer event into that so that I can move from one point to the next, and then repeat this till I get to the target...
我得到鼠标的当前位置,然后得到终点。计算两点之间的弧线,然后我需要计算沿该弧线的点,以便我可以向其中添加一个计时器事件,以便我可以从一个点移动到下一个点,然后重复此操作直到到达目标...
Anybody want to elaborate?
有人想详细说明吗?
Thanks, R.
谢谢,R。
采纳答案by Erik Forbes
I tried the arc calculation method, turned out to be far to complex and, in the end, it didn't look realistic. Straight lines look much more human, as JP suggests in his comment.
我尝试了圆弧计算方法,结果太复杂了,最后看起来不太现实。正如 JP 在评论中所暗示的那样,直线看起来更人性化。
This is a function I wrote to calculate a linear mouse movement. Should be pretty self-explanatory. GetCursorPosition() and SetCursorPosition(Point) are wrappers around the win32 functions GetCursorPos and SetCursorPos.
这是我编写的用于计算线性鼠标移动的函数。应该是不言自明的。GetCursorPosition() 和 SetCursorPosition(Point) 是 win32 函数 GetCursorPos 和 SetCursorPos 的包装器。
As far as the math goes - technically, this is called Linear Interpolationof a line segment.
就数学而言 - 从技术上讲,这称为线段的线性插值。
public void LinearSmoothMove(Point newPosition, int steps) {
Point start = GetCursorPosition();
PointF iterPoint = start;
// Find the slope of the line segment defined by start and newPosition
PointF slope = new PointF(newPosition.X - start.X, newPosition.Y - start.Y);
// Divide by the number of steps
slope.X = slope.X / steps;
slope.Y = slope.Y / steps;
// Move the mouse to each iterative point.
for (int i = 0; i < steps; i++)
{
iterPoint = new PointF(iterPoint.X + slope.X, iterPoint.Y + slope.Y);
SetCursorPosition(Point.Round(iterPoint));
Thread.Sleep(MouseEventDelayMS);
}
// Move the mouse to the final destination.
SetCursorPosition(newPosition);
}
回答by ChrisW
A usual way, I think, is to physically move the real mouse with your own hand: and have the software capture those (real) movements, and replay them.
我认为,通常的方法是用自己的手物理移动真正的鼠标:让软件捕捉这些(真实的)动作,然后重放它们。
回答by Erik Forbes
procedure WindMouse(xs, ys, xe, ye, gravity, wind, minWait, maxWait, maxStep, targetArea: extended);
var
veloX, veloY, windX, windY, veloMag, dist, randomDist, lastDist, step: extended;
lastX, lastY: integer;
sqrt2, sqrt3, sqrt5: extended;
begin
sqrt2:= sqrt(2);
sqrt3:= sqrt(3);
sqrt5:= sqrt(5);
while hypot(xs - xe, ys - ye) > 1 do
begin
dist:= hypot(xs - xe, ys - ye);
wind:= minE(wind, dist);
if dist >= targetArea then
begin
windX:= windX / sqrt3 + (random(round(wind) * 2 + 1) - wind) / sqrt5;
windY:= windY / sqrt3 + (random(round(wind) * 2 + 1) - wind) / sqrt5;
end else
begin
windX:= windX / sqrt2;
windY:= windY / sqrt2;
if (maxStep < 3) then
begin
maxStep:= random(3) + 3.0;
end else
begin
maxStep:= maxStep / sqrt5;
end;
end;
veloX:= veloX + windX;
veloY:= veloY + windY;
veloX:= veloX + gravity * (xe - xs) / dist;
veloY:= veloY + gravity * (ye - ys) / dist;
if hypot(veloX, veloY) > maxStep then
begin
randomDist:= maxStep / 2.0 + random(round(maxStep) / 2);
veloMag:= sqrt(veloX * veloX + veloY * veloY);
veloX:= (veloX / veloMag) * randomDist;
veloY:= (veloY / veloMag) * randomDist;
end;
lastX:= Round(xs);
lastY:= Round(ys);
xs:= xs + veloX;
ys:= ys + veloY;
if (lastX <> Round(xs)) or (lastY <> Round(ys)) then
MoveMouse(Round(xs), Round(ys));
step:= hypot(xs - lastX, ys - lastY);
wait(round((maxWait - minWait) * (step / maxStep) + minWait));
lastdist:= dist;
end;
if (Round(xe) <> Round(xs)) or (Round(ye) <> Round(ys)) then
MoveMouse(Round(xe), Round(ye));
end;
{*******************************************************************************
procedure MMouse(x, y, rx, ry: integer);
By: Benland100
Description: Moves the mouse.
*******************************************************************************}
//Randomness is just added to the x,y. Might want to change that.
procedure MMouse(x, y, rx, ry: integer);
var
cx, cy: integer;
randSpeed: extended;
begin
randSpeed:= (random(MouseSpeed) / 2.0 + MouseSpeed) / 10.0;
if randSpeed = 0.0 then
randSpeed := 0.1;
getMousePos(cx,cy);
X := x + random(rx);
Y := y + random(ry);
WindMouse(cx,cy,x,y,9.0,3.0,10.0/randSpeed,15.0/randSpeed,10.0*randSpeed,10.0*randSpeed);
end;
Here are some methods written in SCAR. Converting them C# shouldn't be too hard, these are quite realistic.
下面是一些用 SCAR 编写的方法。将它们转换为 C# 应该不会太难,这些是非常现实的。
回答by Coder1095
I converted the WindMouse
function mentioned earlier into C# and it is actually pretty realistic. Note that this is just a rough sample and does not use wrappers for GetCursorPos
and SetCursorPos
. I will be using the Windows Input Simulatorwrappers.
我把WindMouse
前面提到的函数转换成C#,其实还挺现实的。请注意,这只是一个粗略的示例,并没有对GetCursorPos
和使用包装器SetCursorPos
。我将使用Windows 输入模拟器包装器。
static class SampleMouseMove {
static Random random = new Random();
static int mouseSpeed = 15;
static void Main(string[] args) {
MoveMouse(0, 0, 0, 0);
}
static void MoveMouse(int x, int y, int rx, int ry) {
Point c = new Point();
GetCursorPos(out c);
x += random.Next(rx);
y += random.Next(ry);
double randomSpeed = Math.Max((random.Next(mouseSpeed) / 2.0 + mouseSpeed) / 10.0, 0.1);
WindMouse(c.X, c.Y, x, y, 9.0, 3.0, 10.0 / randomSpeed,
15.0 / randomSpeed, 10.0 * randomSpeed, 10.0 * randomSpeed);
}
static void WindMouse(double xs, double ys, double xe, double ye,
double gravity, double wind, double minWait, double maxWait,
double maxStep, double targetArea) {
double dist, windX = 0, windY = 0, veloX = 0, veloY = 0, randomDist, veloMag, step;
int oldX, oldY, newX = (int)Math.Round(xs), newY = (int)Math.Round(ys);
double waitDiff = maxWait - minWait;
double sqrt2 = Math.Sqrt(2.0);
double sqrt3 = Math.Sqrt(3.0);
double sqrt5 = Math.Sqrt(5.0);
dist = Hypot(xe - xs, ye - ys);
while (dist > 1.0) {
wind = Math.Min(wind, dist);
if (dist >= targetArea) {
int w = random.Next((int)Math.Round(wind) * 2 + 1);
windX = windX / sqrt3 + (w - wind) / sqrt5;
windY = windY / sqrt3 + (w - wind) / sqrt5;
}
else {
windX = windX / sqrt2;
windY = windY / sqrt2;
if (maxStep < 3)
maxStep = random.Next(3) + 3.0;
else
maxStep = maxStep / sqrt5;
}
veloX += windX;
veloY += windY;
veloX = veloX + gravity * (xe - xs) / dist;
veloY = veloY + gravity * (ye - ys) / dist;
if (Hypot(veloX, veloY) > maxStep) {
randomDist = maxStep / 2.0 + random.Next((int)Math.Round(maxStep) / 2);
veloMag = Hypot(veloX, veloY);
veloX = (veloX / veloMag) * randomDist;
veloY = (veloY / veloMag) * randomDist;
}
oldX = (int)Math.Round(xs);
oldY = (int)Math.Round(ys);
xs += veloX;
ys += veloY;
dist = Hypot(xe - xs, ye - ys);
newX = (int)Math.Round(xs);
newY = (int)Math.Round(ys);
if (oldX != newX || oldY != newY)
SetCursorPos(newX, newY);
step = Hypot(xs - oldX, ys - oldY);
int wait = (int)Math.Round(waitDiff * (step / maxStep) + minWait);
Thread.Sleep(wait);
}
int endX = (int)Math.Round(xe);
int endY = (int)Math.Round(ye);
if (endX != newX || endY != newY)
SetCursorPos(endX, endY);
}
static double Hypot(double dx, double dy) {
return Math.Sqrt(dx * dx + dy * dy);
}
[DllImport("user32.dll")]
static extern bool SetCursorPos(int X, int Y);
[DllImport("user32.dll")]
public static extern bool GetCursorPos(out Point p);
}