changeset 10945:284d06bb1364 11+15

8196031: FX Robot mouseMove fails on Windows 10 1709 with HiDPI Reviewed-by: kcr, mbilla
author pbansal
date Tue, 12 Jun 2018 14:40:17 +0530
parents ea5e4dd85b91
children fccccb076578 051a1cc4df22
files modules/javafx.graphics/src/main/native-glass/win/Robot.cpp tests/system/src/test/java/test/robot/javafx/scene/MouseLocationOnScreenTest.java
diffstat 2 files changed, 151 insertions(+), 35 deletions(-) [+]
line wrap: on
line diff
--- a/modules/javafx.graphics/src/main/native-glass/win/Robot.cpp	Tue Jun 12 14:12:43 2018 +0530
+++ b/modules/javafx.graphics/src/main/native-glass/win/Robot.cpp	Tue Jun 12 14:40:17 2018 +0530
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -102,43 +102,16 @@
 JNIEXPORT void JNICALL Java_com_sun_glass_ui_win_WinRobot__1mouseMove
     (JNIEnv *env, jobject jrobot, jint x, jint y)
 {
-    int oldAccel[3], newAccel[3];
-    INT_PTR oldSpeed, newSpeed;
-    BOOL bResult;
-
     jfloat fx = (jfloat) x + 0.5f;
     jfloat fy = (jfloat) y + 0.5f;
     GlassScreen::FX2Win(&fx, &fy);
-    x = (jint) fx;
-    y = (jint) fy;
-
-    // The following values set mouse ballistics to 1 mickey/pixel.
-    newAccel[0] = 0;
-    newAccel[1] = 0;
-    newAccel[2] = 0;
-    newSpeed = 10;
-
-    // Save the Current Mouse Acceleration Constants
-    bResult = ::SystemParametersInfo(SPI_GETMOUSE, 0, oldAccel, 0);
-    bResult = ::SystemParametersInfo(SPI_GETMOUSESPEED, 0, &oldSpeed, 0);
-    // Set the new Mouse Acceleration Constants (Disabled).
-    bResult = ::SystemParametersInfo(SPI_SETMOUSE, 0, newAccel, SPIF_SENDCHANGE);
-    bResult = ::SystemParametersInfo(SPI_SETMOUSESPEED, 0,
-            (PVOID)newSpeed,
-            SPIF_SENDCHANGE);
-
-    POINT curPos;
-    ::GetCursorPos(&curPos);
-    x -= curPos.x;
-    y -= curPos.y;
-
-    ::mouse_event(MOUSEEVENTF_MOVE, x, y, 0, 0);
-    // Move the cursor to the desired coordinates.
-
-    // Restore the old Mouse Acceleration Constants.
-    bResult = ::SystemParametersInfo(SPI_SETMOUSE,0, oldAccel, SPIF_SENDCHANGE);
-    bResult = ::SystemParametersInfo(SPI_SETMOUSESPEED, 0, (PVOID)oldSpeed,
-            SPIF_SENDCHANGE);
+    INPUT mouseInput = {0};
+    mouseInput.type = INPUT_MOUSE;
+    mouseInput.mi.time = 0;
+    mouseInput.mi.dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE;
+    mouseInput.mi.dx = (jint)(fx * 65536.0 / ::GetSystemMetrics(SM_CXSCREEN));
+    mouseInput.mi.dy = (jint)(fy * 65536.0 / ::GetSystemMetrics(SM_CYSCREEN));
+    ::SendInput(1, &mouseInput, sizeof(mouseInput));
 }
 
 /*
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/system/src/test/java/test/robot/javafx/scene/MouseLocationOnScreenTest.java	Tue Jun 12 14:40:17 2018 +0530
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package test.robot.javafx.scene;
+
+import com.sun.glass.ui.Robot;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import javafx.application.Application;
+import javafx.application.Platform;
+import javafx.geometry.Rectangle2D;
+import javafx.stage.Screen;
+import javafx.stage.Stage;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import test.util.Util;
+
+
+public class MouseLocationOnScreenTest {
+    static CountDownLatch startupLatch;
+    static Robot robot;
+
+    public static class TestApp extends Application {
+
+        @Override
+        public void start(Stage primaryStage) throws Exception {
+            robot = com.sun.glass.ui.Application.GetApplication().createRobot();
+            startupLatch.countDown();
+        }
+    }
+
+    @BeforeClass
+    public static void initFX() {
+        startupLatch = new CountDownLatch(1);
+
+        new Thread(() -> Application.launch(TestApp.class, (String[]) null))
+                .start();
+        try {
+            if (!startupLatch.await(15, TimeUnit.SECONDS)) {
+                Assert.fail("Timeout waiting for FX runtime to start");
+            }
+        } catch (InterruptedException ex) {
+            Assert.fail("Unexpected exception: " + ex);
+        }
+    }
+
+    @Test(timeout = 20000)
+    public void testMouseLocation() throws Exception {
+
+        Screen screen = Screen.getPrimary();
+        Rectangle2D bounds = screen.getBounds();
+        int x1 = (int) bounds.getMinX();
+        int x2 = (int) (x1 + bounds.getWidth() - 1);
+        int y1 = (int) bounds.getMinY();
+        int y2 = (int) (y1 + bounds.getHeight() - 1);
+
+        // Check all edge (two pixels in a width)
+        Util.runAndWait(() -> {
+            edge(robot, x1, y1, x2, y1);         // top
+            edge(robot, x1, y1 + 1, x2, y1 + 1); // top
+
+            edge(robot, x2, y1, x2, y2);         // right
+            edge(robot, x2 - 1, y1, x2 - 1, y2); // right
+        });
+
+        Util.runAndWait(() -> {
+            edge(robot, x1, y1, x1, y2);         // left
+            edge(robot, x1 + 1, y1, x1 + 1, y2); // left
+
+            edge(robot, x1, y2, x2, y2);         // bottom
+            edge(robot, x1, y2 - 1, x2, y2 - 1); // bottom
+        });
+
+        // Check crossing of diagonals
+        Util.runAndWait(() -> {
+            cross(robot, x1, y1, x2, y2); // cross left-bottom
+            cross(robot, x1, y2, x2, y1); // cross left-top
+        });
+    }
+
+    @AfterClass
+    public static void teardown() {
+        Platform.exit();
+    }
+
+    /**
+     * This method checks the coordinates which were passed to robot and
+     * returned by robot are same
+     */
+    static void validate(Robot robot, int x, int y) {
+        Assert.assertEquals(x, robot.getMouseX());
+        Assert.assertEquals(y, robot.getMouseY());
+    }
+
+    private static void edge(Robot robot, int x1, int y1, int x2, int y2) {
+        for (int x = x1; x <= x2; x++) {
+            for (int y = y1; y <= y2; y++) {
+                robot.mouseMove(x, y);
+                validate(robot, x, y);
+            }
+        }
+    }
+
+    private static void cross(Robot robot, int x0, int y0, int x1, int y1) {
+        double dmax = (double) Math.max(Math.abs(x1 - x0), Math.abs(y1 - y0));
+        double dx = (x1 - x0) / dmax;
+        double dy = (y1 - y0) / dmax;
+
+        robot.mouseMove(x0, y0);
+        validate(robot, x0, y0);
+
+        for (int i = 1; i <= dmax; i++) {
+            int x = (int) (x0 + dx * i);
+            int y = (int) (y0 + dy * i);
+            robot.mouseMove(x, y);
+            validate(robot, x, y);
+        }
+    }
+}