Search code examples
javajavafxawtrobot

Robot.mouseMove(1000,1000) moves mouse to random locations on screen... why?


public class MoveCursor extends Application {
    public static void main(String[] args) {
        launch(args);
    }
    @Override
    public void start(Stage stage) throws Exception {
        Button b = new Button("X");
        b.setOnAction((event) -> {
            try {
                new Robot().mouseMove(1000, 1000);
            } catch (AWTException ex) {
                Logger.getLogger(MoveCursor.class.getName()).log(Level.SEVERE, null, ex);
            }
        });
        stage.setScene(new Scene(b));
        stage.show();
    }
}
  1. this should move the mouse cursor over to position 1000x1000 on my/your screen (i.e. 1000px away from the absolute 0x0 coordinate of my screen... and should wind up always in the same position). ... it doesn't... it depends on where the button is. why?

  2. what's causing this?

... this used to work on an old laptop. i.e. windows 10, 1 intel graphics card, 1 nvidia graphics card, 1920x1080 display.

I'm currently using Windows 10, 2 graphics cards in SLI on a 3840x2160 resolution scaled at 175%.

adjusting the scaling factor doesn't seem to do anything.

... i'm also using jdk8.

using the -Dsun.java2d.dpiaware=true or -Dsun.java2d.dpiaware=false vm options doesn't seem to do anything.

[edit] ... for quesiton duplicate issue... it's not a duplicate of that. the fix in that question is useless.

THIS DOES NOT WORK!

 for(int count = 0;(MouseInfo.getPointerInfo().getLocation().getX() != x || 
        MouseInfo.getPointerInfo().getLocation().getY() != y) &&
        count < 100; count++) {
    new Robot().mouseMove(x, y);
  }

Solution

  • Sub-optimal, pathetically bad solution... but it WORKS... and i've wasted far too much time on this issue than i should have.

    import com.sun.jna.platform.win32.BaseTSD.ULONG_PTR;
    import com.sun.jna.platform.win32.User32;
    import com.sun.jna.platform.win32.WinDef.DWORD;
    import com.sun.jna.platform.win32.WinDef.LONG;
    import com.sun.jna.platform.win32.WinUser.INPUT;
    import java.awt.MouseInfo;
    import java.awt.Point;
    
    public class Mouse {
    
        public static final int MOUSEEVENTF_MOVE = 1;
    
        public static void _winEvent_mi_move(int x, int y) {
            mouseAction(x, y, MOUSEEVENTF_MOVE);
        }
    
        public static void mouseAction(int x, int y, int flags) {
            INPUT input = new INPUT();
            input.type = new DWORD(INPUT.INPUT_MOUSE);
            input.input.setType("mi");
            if (x != -1) {
                input.input.mi.dx = new LONG(x);
            }
            if (y != -1) {
                input.input.mi.dy = new LONG(y);
            }
            input.input.mi.time = new DWORD(0);
            input.input.mi.dwExtraInfo = new ULONG_PTR(0);
            input.input.mi.dwFlags = new DWORD(flags);
            User32.INSTANCE.SendInput(new DWORD(1), new INPUT[]{input}, input.size());
        }
    
        public static void forceMove(int x, int y) {
            init_abs_move_0_0:
            {
                Point ip = MouseInfo.getPointerInfo().getLocation();
                _winEvent_mi_move(-ip.x, -ip.y);
            }
            moveX:
            {
                while (MouseInfo.getPointerInfo().getLocation().x < x - 1) {
                    _winEvent_mi_move(1, 0);
                }
            }
            moveY:
            {
                while (MouseInfo.getPointerInfo().getLocation().y < y - 1) {
                    _winEvent_mi_move(0, 1);
                }
            }
            System.out.println(MouseInfo.getPointerInfo().getLocation().toString());
        }
    
        public static void main(String[] args) {
            forceMove(1000, 1000);
            forceMove(2000, 1500);
        }
    
    }
    

    Theoretially one could achieve the same results by using an awt.Robot instance to move something pixel by pixel... this seems to work better.

    yeah... and i did try to calculate the relative target position of the pointer destination based on the current position of the mouse cursor and everything... but it's still based on obscurely difficult to acquire information about whether or not DPI scaling and whatever nonsense MS has decided to implement in the WPI and GDI input event processing routines.

    ... moving it directly to 0x0 then 1000x1000 makes it result in a cursor position defined by (2000x1400) ... don't have the time nor the patience to figure it out. ... solution works. end of story.