使鼠标移动更像人类(使用弧线而不是直线到达目的地)

3

我正在使用java.awt.Robot制作自动点击器。然而,我担心的是移动并不像人类那样自然。有没有人能建议一些修改我的代码来使其更像人类?目前它只是直线移动。

/**
 * 
 * @param robot The java.awt.Robot being utilized
 * @param sx The start x position of the mouse
 * @param sy The start y potition of the mouse
 * @param ex The end x position of the mouse
 * @param ey The end y position of the mouse
 * @param speed The speed at which to travel
 */
public void moveMouse(Robot robot, int sx, int sy, int ex, int ey, int speed){
    for (int i=0; i<100; i++){  
        int mov_x = ((ex * i)/100) + (sx*(100-i)/100);
        int mov_y = ((ey * i)/100) + (sy*(100-i)/100);
        robot.mouseMove(mov_x,mov_y);
        robot.delay(speed);
    }

}
更新: 我决定采用一种利用贝塞尔曲线的算法。虽然我已经实现了这个变化很长时间,但我想把它发布在这里,以防将来有人会发现它有用。以下是我的最终结果:
public class MouseEvent{
    public int getMouseX(){
        return MouseInfo.getPointerInfo().getLocation().x;
    }

    public int getMouseY(){
        return MouseInfo.getPointerInfo().getLocation().y;
    }

    public void moveMouse(int speed, int destX, int destY, int ranX, int ranY){
        Mouse.moveMouse(new Robot(), new Point(getMouseX(),getMouseY()), new Point(destX, destY), speed, ranX, ranY);
    }
}

public class Mouse {
    public static void moveMouse(Robot robot, Point s, Point e, int speed, int ranX, int ranY){
        if(Math.abs(e.x-s.x) <= ranX && Math.abs(e.y-s.y) <= ranY)
            return;

        Point[] cooardList;
        double t;    //the time interval
        double k = .025;
        cooardList = new Point[4];

        //set the beginning and end points
        cooardList[0] = s;
        cooardList[3] = new Point(e.x+random(-ranX,ranX),e.y+(random(-ranY,ranY)));

        int xout = (int)(Math.abs(e.x - s.x) /10);
        int yout = (int)(Math.abs(e.y - s.y) /10);

        int x=0,y=0;

        x = s.x < e.x 
            ? s.x + ((xout > 0) ? random(1,xout) : 1)
            : s.x - ((xout > 0) ? random(1,xout) : 1);
        y = s.y < e.y 
            ? s.y + ((yout > 0) ? random(1,yout) : 1)
            : s.y - ((yout > 0) ? random(1,yout) : 1);
        cooardList[1] = new Point(x,y);

        x = e.x < s.x 
            ? e.x + ((xout > 0) ? random(1,xout) : 1)
            : e.x - ((xout > 0) ? random(1,xout) : 1);
        y = e.y < s.y 
            ?  e.y + ((yout > 0) ? random(1,yout) : 1)
            : e.y - ((yout > 0) ? random(1,yout) : 1);
        cooardList[2] = new Point(x,y);

        double px = 0,py = 0;
        for(t=k;t<=1+k;t+=k){
            //use Berstein polynomials
            px=(cooardList[0].x+t*(-cooardList[0].x*3+t*(3*cooardList[0].x-
                cooardList[0].x*t)))+t*(3*cooardList[1].x+t*(-6*cooardList[1].x+
                cooardList[1].x*3*t))+t*t*(cooardList[2].x*3-cooardList[2].x*3*t)+
                cooardList[3].x*t*t*t;
            py=(cooardList[0].y+t*(-cooardList[0].y*3+t*(3*cooardList[0].y-
                cooardList[0].y*t)))+t*(3*cooardList[1].y+t*(-6*cooardList[1].y+
                cooardList[1].y*3*t))+t*t*(cooardList[2].y*3-cooardList[2].y*3*t)+
                cooardList[3].y*t*t*t;
            robot.mouseMove((int)px, (int)py);
            robot.delay(random(speed,speed*2));
        }
    }    
}

“Humanlike”应该是什么意思? - nebula
不一定沿着直线移动,可能会在这里或那里弧形移动几个像素。 - Michael Rentmeister
然后生成随机数,并使用该数字改变直线。接着使用机器人类。 - nebula
但我不想随机生成一个数字,因为那样鼠标移动会有点抖动,想想看,鼠标移动大多是平滑的弧线。 - Michael Rentmeister
更新很好,但只有在点高度随机化时才会产生曲线。如果您想要一个精确的目标(或在10个像素范围内),它仍然是一条直线。我考虑过两次调用该方法,但感觉不对。我觉得我会加入一些随机调用。其中一些调用该方法2-3次(第一次调用高度随机化的目标,而最后一次调用则是精确的),试图“纠正”目标,有些则直接到达目标等等,我认为这更像人类。 - Pengiuns
在进一步尝试您的代码后,我将 int xout = (int)(Math.abs(e.x - s.x) /10); int yout = (int)(Math.abs(e.y - s.y) /10); 更改为/2,并且个人认为它得到了我一直在寻找的结果。https://i.imgur.com/PITMbH3.png 这是精度为5的情况 moveMouse0(7,700,700,5,5); - Pengiuns
2个回答

2
 public void moveMouse(int sx, int sy, int ex, int ey, int speed) throws AWTException {
        Robot robot = new Robot();
        int a = 10;
        boolean flag = true;
        for (int i = 0; i < 100; i++) {
            int mov_x = ((ex * i) / 100) + (sx * (100 - i) / 100);
            int mov_y = ((ey * i) / 100) + (sy * (100 - i) / 100);
            if (flag == true) {
                robot.mouseMove(mov_x + a, mov_y); // adds 10 to X-axis
                flag = false;
            } else {
                robot.mouseMove(mov_x - 2 * a, mov_y); // subtracts 20 to X-axis
                flag = true;
            }
            robot.delay(speed);
        }
    }

我刚刚修改了你的代码。这会让鼠标在X轴上直线移动。你可以从这里实现你想要的效果。只需理解这些思路。只要你能控制 mov_xmov_y ,你就可以按照任何方式移动。


请纠正我,但我没有看到你添加的任何内容能确保终点是目标位置。此外,即使你改变a = 1,这一切也只是来回摆动,鼠标仍然会快速晃动,远远不能形成平滑的弧线。 - Michael Rentmeister
你在 moveMouse() 中传递了什么参数?我尝试了 moveMouse(30,30,30,500,100)。我认为 arc 意味着圆弧的一部分,这不像人类。 - nebula
不,我不是指一个圆圈,当我说弧线时,我的意思是偏离直线大约1-4个像素,而不是巨大的弧线。 - Michael Rentmeister
尝试将其运行,其中起点与目的地仅相隔 10-20 像素。 - Michael Rentmeister
1
你应该得到你想要的确切代码吗?那只是如何实现它的逻辑。你可以编辑代码,使其适用于10-20个像素。现在,你听起来连你发布的代码都不理解。祝你好运。 - nebula
显示剩余3条评论

1
你可以使用Catmull-Rom方法。在端点周围和直线可能存在的地方生成随机控制点,并在从起点到终点移动的每一步(参数t,从零到一)上询问坐标。
查看演示应用程序和源代码:http://www.cse.unsw.edu.au/~lambert/splines/

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接