问题描述
我创建了一个有趣的小项目,目的是记录我所做的自然鼠标移动,然后播放它,但将其对准目标。
问题:假设我制作并记录了一个以 x: 250,y: 278 结束的自然运动,现在我想要的是使自然运动记录在目标坐标处结束我指定(例如:x:100,y:100)。
现在是代码:(请注意代码并不干净,但如果我可以这么说,它只是第一个原型,因此请在阅读时记住这一点)。
我如何记录运动:
- 当 MOUSE_MOVED 事件发生时,录制开始和结束于 MOUSE_pressed。
(必须将 Main.recordMoves 设置为 true 才能发生上述情况,我使用扫描仪系统输入将其设置为 true/false。)
-
只要发生 MOUSE_MOVED 事件,mouseMoved 方法就会调用 MovesRecorder.record(MouseEvent e) 方法。
-
mousepressed 方法将 Main.recordMoves 布尔值设置为 false 并将记录添加到记录列表中。
鼠标.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(),x,y,false));
mouSEOnScreen = true;
}
c.dispatchEvent(new MouseEvent(c,MouseEvent.MOUSE_MOVED,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,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 结束
解决方法
考虑以下场景,在您记录的运动中,(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) 和( 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,y2) 记录的每个点执行此操作,并且您将拥有从 (x3,y3) 到 (x4,y4) 的所有点>