give the mouse back when the user returns mid-movement

This commit is contained in:
bea
2026-10-01 22:48:15 +02:00
parent 4a7b4267f5
commit 5dc332e28d
2 changed files with 21 additions and 2 deletions
@@ -17,6 +17,9 @@ import java.util.function.BooleanSupplier;
*
* The movements only happen when the user is away: while the user is actively
* using the machine, they are skipped, so the app never fights for the mouse.
* The same goes for a movement already in progress: the task checks whether
* the user is still away at every step, and gives the mouse back when they
* are not.
*
* The movement itself is executed by a {@link SingleStepMovementTask}, which
* runs on its own virtual thread until it reaches its destination.
@@ -72,7 +75,7 @@ public class CursorMover implements Runnable
LOGGER.info("Destination coordinates: {}, {}", destX, destY);
try {
SingleStepMovementTask movement = new SingleStepMovementTask(robotTracker, destX, destY, click);
SingleStepMovementTask movement = new SingleStepMovementTask(robotTracker, destX, destY, click, isUserAway);
movementExecutor.execute(movement);
} catch (AWTException ex) {
LOGGER.error("Could not start movement task", ex);
@@ -5,6 +5,7 @@ import org.apache.logging.log4j.Logger;
import java.awt.*;
import java.awt.event.InputEvent;
import java.util.function.BooleanSupplier;
/**
* Moves the mouse cursor towards a destination one small step at a time.
@@ -13,6 +14,10 @@ import java.awt.event.InputEvent;
* it is free. When it gets to its destination, it can optionally perform a
* double click, with the pacing the app has always used.
*
* If the user comes back mid-movement, the movement is abandoned at once —
* within the latency of the away detection, which polls about once a second —
* so the mouse is returned to the user instead of being dragged to a corner.
*
* All the movements it performs are reported to the {@link RobotMouseTracker},
* so that the away detection can tell them apart from the user's.
*/
@@ -28,18 +33,21 @@ public class SingleStepMovementTask implements Runnable {
private final int destX;
private final int destY;
private final boolean click;
private final BooleanSupplier userIsAway;
private float currentX;
private float currentY;
private float stepX;
private float stepY;
public SingleStepMovementTask(RobotMouseTracker robotTracker, int destinationX, int destinationY, boolean click) throws AWTException {
public SingleStepMovementTask(RobotMouseTracker robotTracker, int destinationX, int destinationY, boolean click,
BooleanSupplier userIsAway) throws AWTException {
this.robotTracker = robotTracker;
this.destX = destinationX;
this.destY = destinationY;
this.click = click;
this.userIsAway = userIsAway;
Point location = MouseInfo.getPointerInfo().getLocation();
this.currentX = location.x;
@@ -65,6 +73,14 @@ public class SingleStepMovementTask implements Runnable {
try {
while (!hasReachedDestination()) {
// a user who came back mid-movement gets the mouse back
if (!userIsAway.getAsBoolean()) {
LOGGER.info("User is back: abandoning the movement at [{}, {}]",
Math.round(currentX), Math.round(currentY));
robotTracker.moveEnded(Math.round(currentX), Math.round(currentY));
return;
}
// when less than a full step is left, move exactly what is
// left, so that both axes always land on their destination
stepX = adjustedStep(currentX, destX, stepX);