旋转记录的鼠标移动 [Java]

Posted

技术标签:

【中文标题】旋转记录的鼠标移动 [Java]【英文标题】:Rotating Recorded Mouse Movements [Java] 【发布时间】:2021-04-12 18:26:34 【问题描述】:

我创建了一个有趣的小项目,目的是记录我做出的自然鼠标移动,然后回放它,但将它指向一个目标。

问题:假设我制作并记录了一个在 x: 250, y: 278 结束的自然运动,现在我想要的是让自然运动记录在目标坐标处结束我指定(EX:x:100,y:100)。

现在是代码:(请注意,代码并不干净,但如果我可以这么说,它只是第一个原型,所以请在阅读时牢记这一点)。

我如何记录动作

    当 MOUSE_MOVED 事件发生时,录制在 MOUSE_PRESSED 开始和结束。

(必须将 Main.recordMoves 设置为 true 才能发生上述情况,我使用 Scanner System 输入将其设置为 true/false。)

    只要发生 MOUSE_MOVED 事件,mouseMoved 方法就会调用 MovesRecorder.record(MouseEvent e) 方法。

    mousePressed 方法将 Main.recordMoves 布尔值设置为 false,并将记录添加到 Records 列表中。

鼠标.java:

public class Mouse implements MouseListener, MouseMotionListener 

    private Point location = new Point(0,0);
        
    private boolean mouseOnScreen = false;

    private Component c;

    public Mouse(Component c) 
        this.c = c;
    

    public void pushStraight(int x, int y) 
        if(!mouseOnScreen) 
            c.dispatchEvent(new MouseEvent(c,MouseEvent.MOUSE_ENTERED, System.currentTimeMillis(),0,x,y,
                    0,false));
            mouseOnScreen = true;
        
        c.dispatchEvent(new MouseEvent(c,MouseEvent.MOUSE_MOVED,System.currentTimeMillis(),0,x,y,
                0,false));
        location.setLocation(x,y);
    

    @Override
    public void mouseClicked(MouseEvent e) 

    @Override
    public void mousePressed(MouseEvent e) 
        if(Main.recordMoves) 
            Main.recordMoves = false;
            MovesRecorder.currentMove.time = System.currentTimeMillis() - MovesRecorder.startTime;
            MousePatterns.moves.add(MovesRecorder.currentMove);
            MovesRecorder.currentMove = null;
        
        System.out.println("Pressed");
    

    @Override
    public void mouseReleased(MouseEvent e) 

    @Override
    public void mouseEntered(MouseEvent e) 
        mouseOnScreen = true;
    

    @Override
    public void mouseExited(MouseEvent e) 
        mouseOnScreen = false;
    

    @Override
    public void mouseDragged(MouseEvent e) 
        location.setLocation(e.getPoint());
    

    @Override
    public void mouseMoved(MouseEvent e) 
        location.setLocation(e.getPoint());
        if(Main.recordMoves) MovesRecorder.record(e);
    

    public Point getLocation() 
        return location;
    

    public boolean isMouseOnScreen() 
        return mouseOnScreen;
    

    public Component getC() 
        return c;
    

MouseRecorder.java:

public class MovesRecorder 

    public static Move currentMove;

    public static Point lastPos; //First lastPos (startingPos) is set here by Main.java

    public static long startTime;

    public static void record(MouseEvent e) 
        if(currentMove == null) 
            currentMove = new Move(Screen.mouse);
            startTime = System.currentTimeMillis();
        
        currentMove.movements.add(new Point(e.getPoint().x - lastPos.x,
                e.getPoint().y - lastPos.y));
        lastPos = e.getPoint();
    

移动.java:

public class Move 

    public List<Point> movements = new ArrayList<>();

    public long time;

    private Mouse m;

    public Move(Mouse m) 
        this.m = m;
    

    public void executeEvents(int x, int y)  //This method as of now doesn't target the params.. it just does the recording
        for(Point p : movements) 
            execute(m.getLocation().x+p.x, m.getLocation().y+p.y, MouseEvent.MOUSE_MOVED);
            try 
                Thread.sleep(time / movements.size());
             catch (InterruptedException e) 
                e.printStackTrace();
            
        
    

    private void execute(int x, int y, int event) 
        m.getC().dispatchEvent(new MouseEvent(m.getC(),event,
                System.currentTimeMillis(),0,
                x,y,0,false));
    


Main.java 包含一个循环和一个 Scanner 的 switch 语句以获取命令:

while(true) 
    switch (s.next()) 
        case "movesRec":
            Main.recordMoves = true;
            MovesRecorder.lastPos = Screen.mouse.getLocation();
            break;
        case "move":
            MousePatterns.moves.get(0).executeEvents(100,100);
            break;
    

MousePatterns.java 包含一个用于添加移动的静态列表:

public static List<Move> moves = new ArrayList<>();

我们将不胜感激!

编辑:

录音示例:https://pastebin.pl/view/e461d2bd 我希望它从 X: 274 Y: 265 开始并在 X: 100, Y: 100 结束

【问题讨论】:

您想使用之前记录的动作中的数据来模拟自然动作吗?例如:您想使用在 x: 250, y: 278 结束的运动的数据来模拟将在 x: 100, y: 100 结束的运动。对吗? @GuilhermeSchaidhauerCastro 是的,这是正确的。抱歉回复晚了,睡着了。 【参考方案1】:

考虑以下场景,其中您记录的运动 (x1, y1) 是您的起点,(x2, y2) 是您的终点,您记录的这两个点之间的唯一点是 (xm1, ym1)。

当然,在真实场景中,在 (x1, y1) 和 (x2, y2) 之间会有更多点,但为简单起见,我们假设只有一个。

x1: 0, y1: 0

xm1: 45: , ym1:60

x2:100,y2:100

现在您有了一个起点 (x3, y3),并希望按照您之前记录的相同运动前往 (x4, y4)。为此,您需要找到 (xm2, ym2)。

x3:15,y3:45

xm2: ?, ym2: ?

x4:150,y4:200

考虑到 xp1 是 xm1 走过的 x1 和 x2 之间距离的百分比,您可以执行以下操作来找到 xm2 和 ym2:

xp1 = xm1 * 100 / (x2 - x1)

xm2 = xp1 * (x4 - x3) / 100

yp1 = ym1 * 100 / (y2 - y1)

ym2 = yp1 * (y4 - y3) / 100

(在 (x1, y1) 到 (x2, y2) 场景中,xp1 = 45% 和 yp1 = 60% 因为它们从 (x1, y1) 和 (x1, y1) 之间的距离“移动”了 45% 和 65% x2, y2))

求解它变成的方程:

xp1 = 45 * 100 / 100 = 45

xm1 = 45 * 135 / 100 = 60.75

yp1 = 60 * 100 / (100 - 0) = 60

ym2 = 60 * (200 - 45) / 100 = 93

现在您只需对从 (x1, y1) 到 (x2, y2) 记录的每个点执行此操作,您将拥有从 (x3, y3) 到 (x4, y4) 的所有点

【讨论】:

很抱歉回复晚了,我会试试这个,让你知道会发生什么。非常感谢您的回答,谢谢谢谢 我已经对其进行了测试,但它只适用于直线和平行图案。但是当它像环状图案、垂直图案时它不起作用 如果您可以发布您在运动中记录的点列表以及您正在使用的起点和终点,将会很有帮助。 我很抱歉没有这样做,录音示例:pastebin.pl/view/e461d2bd 我希望它从 X: 274 Y: 265 开始并在 X: 100, Y: 100 结束

以上是关于旋转记录的鼠标移动 [Java]的主要内容,如果未能解决你的问题,请参考以下文章

canvas里有一张图,怎么实现鼠标可以拖动该图片移动,放大缩小旋转

鼠标点击时对象的动画(旋转、移动)

在鼠标拖动时旋转和移动 2D 对象

鼠标移动时旋转Three.js场景

移动鼠标时旋转项目

Blender甜甜圈教程笔记