diff --git a/make/mapfiles/libnio/mapfile-linux b/make/mapfiles/libnio/mapfile-linux index 30f795f6f57755513d939c4109aacef8415833d5..bdfaa45f13f9a789716cd12a21e45fda87348d08 100644 --- a/make/mapfiles/libnio/mapfile-linux +++ b/make/mapfiles/libnio/mapfile-linux @@ -153,8 +153,9 @@ SUNWprivate_1.1 { Java_sun_nio_fs_LinuxNativeDispatcher_fsetxattr0; Java_sun_nio_fs_LinuxNativeDispatcher_fremovexattr0; Java_sun_nio_fs_LinuxNativeDispatcher_setmntent0; - Java_sun_nio_fs_LinuxNativeDispatcher_getmntent; + Java_sun_nio_fs_LinuxNativeDispatcher_getmntent0; Java_sun_nio_fs_LinuxNativeDispatcher_endmntent; + Java_sun_nio_fs_LinuxNativeDispatcher_getlinelen; Java_sun_nio_fs_UnixNativeDispatcher_init; Java_sun_nio_fs_UnixNativeDispatcher_getcwd; Java_sun_nio_fs_UnixNativeDispatcher_strerror; @@ -176,6 +177,7 @@ SUNWprivate_1.1 { Java_sun_nio_fs_UnixNativeDispatcher_close; Java_sun_nio_fs_UnixNativeDispatcher_read; Java_sun_nio_fs_UnixNativeDispatcher_write; + Java_sun_nio_fs_UnixNativeDispatcher_rewind; Java_sun_nio_fs_UnixNativeDispatcher_fopen0; Java_sun_nio_fs_UnixNativeDispatcher_fclose; Java_sun_nio_fs_UnixNativeDispatcher_opendir0; diff --git a/src/share/classes/sun/rmi/transport/tcp/TCPEndpoint.java b/src/share/classes/sun/rmi/transport/tcp/TCPEndpoint.java index 0d849ed7f293b84ba7775f0349da7cb9cf7fb09b..409b6fb809149ec9228e17539fd14e6a68aa4f4c 100644 --- a/src/share/classes/sun/rmi/transport/tcp/TCPEndpoint.java +++ b/src/share/classes/sun/rmi/transport/tcp/TCPEndpoint.java @@ -554,7 +554,7 @@ public class TCPEndpoint implements Endpoint { host = in.readUTF(); port = in.readInt(); csf = (RMIClientSocketFactory) in.readObject(); - if (Proxy.isProxyClass(csf.getClass())) { + if (csf != null && Proxy.isProxyClass(csf.getClass())) { throw new IOException("Invalid SocketFactory"); } break; diff --git a/src/solaris/classes/sun/nio/fs/LinuxFileSystem.java b/src/solaris/classes/sun/nio/fs/LinuxFileSystem.java index c154ff564769b3b012bd0b5fe5331ee1de9e0f00..cfd83963b2bce8e9bafac7b4e39b6b5e386617a7 100644 --- a/src/solaris/classes/sun/nio/fs/LinuxFileSystem.java +++ b/src/solaris/classes/sun/nio/fs/LinuxFileSystem.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2019, 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 @@ -79,10 +79,26 @@ class LinuxFileSystem extends UnixFileSystem { ArrayList entries = new ArrayList<>(); try { long fp = setmntent(Util.toBytes(fstab), Util.toBytes("r")); + int maxLineSize = 1024; + try { + for (;;) { + int lineSize = getlinelen(fp); + if (lineSize == -1) + break; + if (lineSize > maxLineSize) + maxLineSize = lineSize; + } + } catch (UnixException x) { + // nothing we need to do + } finally { + rewind(fp); + } + try { for (;;) { UnixMountEntry entry = new UnixMountEntry(); - int res = getmntent(fp, entry); + // count in NUL character at the end + int res = getmntent(fp, entry, maxLineSize + 1); if (res < 0) break; entries.add(entry); diff --git a/src/solaris/classes/sun/nio/fs/LinuxNativeDispatcher.java b/src/solaris/classes/sun/nio/fs/LinuxNativeDispatcher.java index 0186870688a23c2c5c2253f05bcfd03aa2b25230..a0713a3686cb1d3708c5dfb51b3b3d6e47071f08 100644 --- a/src/solaris/classes/sun/nio/fs/LinuxNativeDispatcher.java +++ b/src/solaris/classes/sun/nio/fs/LinuxNativeDispatcher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2019, 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 @@ -54,7 +54,17 @@ class LinuxNativeDispatcher extends UnixNativeDispatcher { /** * int getmntent(FILE *fp, struct mnttab *mp, int len); */ - static native int getmntent(long fp, UnixMountEntry entry) + + static int getmntent(long fp, UnixMountEntry entry, int buflen) throws UnixException { + NativeBuffer buffer = NativeBuffers.getNativeBuffer(buflen); + try { + return getmntent0(fp, entry, buffer.address(), buflen); + } finally { + buffer.release(); + } + } + + static native int getmntent0(long fp, UnixMountEntry entry, long buffer, int bufLen) throws UnixException; /** @@ -62,6 +72,11 @@ class LinuxNativeDispatcher extends UnixNativeDispatcher { */ static native void endmntent(long stream) throws UnixException; + /** + * ssize_t getline(char **lineptr, size_t *n, FILE *stream); + */ + static native int getlinelen(long stream) throws UnixException; + /** * ssize_t fgetxattr(int filedes, const char *name, void *value, size_t size); */ diff --git a/src/solaris/classes/sun/nio/fs/UnixNativeDispatcher.java b/src/solaris/classes/sun/nio/fs/UnixNativeDispatcher.java index 7a8c918af2b12f5db7f0c208ddaa35022c450b78..6aa24f2e29038760eae5e9feefb256d3c3f2f542 100644 --- a/src/solaris/classes/sun/nio/fs/UnixNativeDispatcher.java +++ b/src/solaris/classes/sun/nio/fs/UnixNativeDispatcher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2019, 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 @@ -116,6 +116,11 @@ class UnixNativeDispatcher { */ static native void fclose(long stream) throws UnixException; + /** + * void rewind(FILE* stream); + */ + static native void rewind(long stream) throws UnixException; + /** * link(const char* existing, const char* new) */ diff --git a/src/solaris/native/sun/nio/fs/LinuxNativeDispatcher.c b/src/solaris/native/sun/nio/fs/LinuxNativeDispatcher.c index c8500db5c877e63aea7cb71c598230c3d4bae77d..bd836bfcd6b8639d7b3a7dcd1258082d3c3cd65a 100644 --- a/src/solaris/native/sun/nio/fs/LinuxNativeDispatcher.c +++ b/src/solaris/native/sun/nio/fs/LinuxNativeDispatcher.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2019, 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 @@ -169,12 +169,11 @@ Java_sun_nio_fs_LinuxNativeDispatcher_setmntent0(JNIEnv* env, jclass this, jlong } JNIEXPORT jint JNICALL -Java_sun_nio_fs_LinuxNativeDispatcher_getmntent(JNIEnv* env, jclass this, - jlong value, jobject entry) +Java_sun_nio_fs_LinuxNativeDispatcher_getmntent0(JNIEnv* env, jclass this, + jlong value, jobject entry, jlong buffer, jint bufLen) { struct mntent ent; - char buf[1024]; - int buflen = sizeof(buf); + char * buf = (char*)jlong_to_ptr(buffer); struct mntent* m; FILE* fp = jlong_to_ptr(value); jsize len; @@ -184,7 +183,7 @@ Java_sun_nio_fs_LinuxNativeDispatcher_getmntent(JNIEnv* env, jclass this, char* fstype; char* options; - m = getmntent_r(fp, &ent, (char*)&buf, buflen); + m = getmntent_r(fp, &ent, buf, (int)bufLen); if (m == NULL) return -1; name = m->mnt_fsname; @@ -230,3 +229,37 @@ Java_sun_nio_fs_LinuxNativeDispatcher_endmntent(JNIEnv* env, jclass this, jlong /* FIXME - man page doesn't explain how errors are returned */ endmntent(fp); } + +/** + * This function returns line length without NUL terminator or -1 on EOF. + * Since getline is missing on Solaris10 this function was moved from + * UnixNativeDispatcher to LinuxNativeDispatcher as part of backport form jdk11. + */ +JNIEXPORT jint JNICALL +Java_sun_nio_fs_LinuxNativeDispatcher_getlinelen(JNIEnv* env, jclass this, jlong stream) +{ + FILE* fp = jlong_to_ptr(stream); + size_t lineSize = 0; + char * lineBuffer = NULL; + int saved_errno; + + ssize_t res = getline(&lineBuffer, &lineSize, fp); + saved_errno = errno; + + /* Should free lineBuffer no matter result, according to man page */ + if (lineBuffer != NULL) + free(lineBuffer); + + if (feof(fp)) + return -1; + + /* On successfull return res >= 0, otherwise res is -1 */ + if (res == -1) + throwUnixException(env, saved_errno); + + if (res > INT_MAX) + throwUnixException(env, EOVERFLOW); + + return (jint)res; +} + diff --git a/src/solaris/native/sun/nio/fs/UnixNativeDispatcher.c b/src/solaris/native/sun/nio/fs/UnixNativeDispatcher.c index 2799f9ab0d61f8a30d372e14ab66019db3ea83bc..cb4cfc01908d99f6490cbc98c66ab1ba5274253c 100644 --- a/src/solaris/native/sun/nio/fs/UnixNativeDispatcher.c +++ b/src/solaris/native/sun/nio/fs/UnixNativeDispatcher.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2019, 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 @@ -367,6 +367,20 @@ Java_sun_nio_fs_UnixNativeDispatcher_fclose(JNIEnv* env, jclass this, jlong stre } } +JNIEXPORT void JNICALL +Java_sun_nio_fs_UnixNativeDispatcher_rewind(JNIEnv* env, jclass this, jlong stream) +{ + FILE* fp = jlong_to_ptr(stream); + int saved_errno; + + errno = 0; + rewind(fp); + saved_errno = errno; + if (ferror(fp)) { + throwUnixException(env, saved_errno); + } +} + JNIEXPORT jint JNICALL Java_sun_nio_fs_UnixNativeDispatcher_open0(JNIEnv* env, jclass this, jlong pathAddress, jint oflags, jint mode) diff --git a/test/java/rmi/server/RMISocketFactory/useSocketFactory/unicast/TCPEndpointReadBug.java b/test/java/rmi/server/RMISocketFactory/useSocketFactory/unicast/TCPEndpointReadBug.java new file mode 100644 index 0000000000000000000000000000000000000000..9c29aad9548497d59f2093e88ac24ef4dc5868d3 --- /dev/null +++ b/test/java/rmi/server/RMISocketFactory/useSocketFactory/unicast/TCPEndpointReadBug.java @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2020, 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. + * + * 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. + */ + + +import java.io.IOException; +import java.io.Serializable; +import java.io.ObjectInputStream; +import java.net.Socket; +import java.rmi.Remote; +import java.rmi.RemoteException; +import java.rmi.server.RMIClientSocketFactory; +import java.rmi.server.RMISocketFactory; +import java.rmi.server.UnicastRemoteObject; + +/* @test + * @bug 8237368 + * @summary Allow custom socket factory to be null in TCPEndpoint. + * @run main/othervm TCPEndpointReadBug + */ +public class TCPEndpointReadBug { + + public static void main(String[] args) throws Exception { + final I implC = new C(); + final I remoteC = (I)UnicastRemoteObject.exportObject( + implC, 0, new CSF(), RMISocketFactory.getDefaultSocketFactory()); + + // Pass a remote object with a custom socket factory as an argument + remoteC.echo(remoteC); + + // Pass nothing and get an object with a custom socket factory in return + remoteC.echo(null); + } + + interface I extends Remote { + I echo(I intf) throws RemoteException; + } + + static class C implements I { + @Override + public I echo(I intf) { + try { + return (I)UnicastRemoteObject + .exportObject(new C(),0, new CSF(), RMISocketFactory.getDefaultSocketFactory()); + } catch (RemoteException e) { + e.printStackTrace(); + } + return null; + } + } + + /** + * A configurable socket factory in which for test purposes supplies null. + */ + static class CSF implements Serializable, RMIClientSocketFactory { + private static final long serialVersionUID = 1; + + @Override + public boolean equals(Object object) { + return object instanceof CSF; + } + + @Override + public int hashCode() { + return 424242; + } + + @Override + public Socket createSocket(String host, int port) + throws IOException { + + final RMIClientSocketFactory defaultFactory = + RMISocketFactory.getDefaultSocketFactory(); + return defaultFactory.createSocket(host, port); + } + + /** + * Use writeReplace to use a different client socket factory. In the + * problematic case, the replacement is null. + */ + private Object writeReplace() { + return null; + } + + /** + * Instances of this class should never be deserialized because they + * are always replaced during serialization. + */ + @SuppressWarnings("unused") + private void readObject(ObjectInputStream in) { + throw new AssertionError(); + } + } +} diff --git a/test/lib/testlibrary/ExtendedRobot.java b/test/lib/testlibrary/ExtendedRobot.java new file mode 100644 index 0000000000000000000000000000000000000000..d28aca0f6423aa5ebd5a9dd674ab8624eb661135 --- /dev/null +++ b/test/lib/testlibrary/ExtendedRobot.java @@ -0,0 +1,372 @@ +/* + * Copyright (c) 2014, 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. + */ + +import sun.awt.ExtendedKeyCodes; +import sun.awt.SunToolkit; +import sun.security.action.GetIntegerAction; + +import java.awt.AWTException; +import java.awt.Robot; +import java.awt.GraphicsDevice; +import java.awt.Toolkit; +import java.awt.Point; +import java.awt.MouseInfo; +import java.awt.event.InputEvent; +import java.security.AccessController; +import java.security.PrivilegedAction; + +/** + * ExtendedRobot is a subclass of {@link java.awt.Robot}. It provides some convenience methods that are + * ought to be moved to {@link java.awt.Robot} class. + *

+ * ExtendedRobot uses delay {@link #getSyncDelay()} to make syncing threads with {@link #waitForIdle()} + * more stable. This delay can be set once on creating object and could not be changed throughout object + * lifecycle. Constructor reads vm integer property {@code java.awt.robotdelay} and sets the delay value + * equal to the property value. If the property was not set 500 milliseconds default value is used. + *

+ * When using jtreg you would include this class via something like: + *

+ * {@literal @}library ../../../../lib/testlibrary
+ * {@literal @}build ExtendedRobot
+ * 
+ * + * @author Dmitriy Ermashov + * @since 1.9 + */ + +public class ExtendedRobot extends Robot { + + private static int DEFAULT_SPEED = 20; // Speed for mouse glide and click + private static int DEFAULT_SYNC_DELAY = 500; // Default Additional delay for waitForIdle() + private static int DEFAULT_STEP_LENGTH = 2; // Step length (in pixels) for mouse glide + + private final int syncDelay = DEFAULT_SYNC_DELAY; + + //TODO: uncomment three lines below after moving functionality to java.awt.Robot + //{ + // syncDelay = AccessController.doPrivileged(new GetIntegerAction("java.awt.robotdelay", DEFAULT_SYNC_DELAY)); + //} + + /** + * Constructs an ExtendedRobot object in the coordinate system of the primary screen. + * + * @throws AWTException if the platform configuration does not allow low-level input + * control. This exception is always thrown when + * GraphicsEnvironment.isHeadless() returns true + * @throws SecurityException if {@code createRobot} permission is not granted + * + * @see java.awt.GraphicsEnvironment#isHeadless + * @see SecurityManager#checkPermission + * @see java.awt.AWTPermission + */ + public ExtendedRobot() throws AWTException { + super(); + } + + /** + * Creates an ExtendedRobot for the given screen device. Coordinates passed + * to ExtendedRobot method calls like mouseMove and createScreenCapture will + * be interpreted as being in the same coordinate system as the specified screen. + * Note that depending on the platform configuration, multiple screens may either: + * + * This constructor is meant for the latter case. + *

+ * If screen devices are reconfigured such that the coordinate system is + * affected, the behavior of existing ExtendedRobot objects is undefined. + * + * @param screen A screen GraphicsDevice indicating the coordinate + * system the Robot will operate in. + * @throws AWTException if the platform configuration does not allow low-level input + * control. This exception is always thrown when + * GraphicsEnvironment.isHeadless() returns true. + * @throws IllegalArgumentException if {@code screen} is not a screen + * GraphicsDevice. + * @throws SecurityException if {@code createRobot} permission is not granted + * + * @see java.awt.GraphicsEnvironment#isHeadless + * @see GraphicsDevice + * @see SecurityManager#checkPermission + * @see java.awt.AWTPermission + */ + public ExtendedRobot(GraphicsDevice screen) throws AWTException { + super(screen); + } + + /** + * Returns delay length for {@link #waitForIdle()} method + * + * @return Current delay value + * + * @see #waitForIdle() + */ + public int getSyncDelay(){ return this.syncDelay; } + + /** + * Clicks mouse button(s) by calling {@link java.awt.Robot#mousePress(int)} and + * {@link java.awt.Robot#mouseRelease(int)} methods + * + * + * @param buttons The button mask; a combination of one or more mouse button masks. + * @throws IllegalArgumentException if the {@code buttons} mask contains the mask for + * extra mouse button and support for extended mouse buttons is + * {@link Toolkit#areExtraMouseButtonsEnabled() disabled} by Java + * @throws IllegalArgumentException if the {@code buttons} mask contains the mask for + * extra mouse button that does not exist on the mouse and support for extended + * mouse buttons is {@link Toolkit#areExtraMouseButtonsEnabled() enabled} + * by Java + * + * @see #mousePress(int) + * @see #mouseRelease(int) + * @see InputEvent#getMaskForButton(int) + * @see Toolkit#areExtraMouseButtonsEnabled() + * @see java.awt.event.MouseEvent + */ + public void click(int buttons) { + mousePress(buttons); + waitForIdle(DEFAULT_SPEED); + mouseRelease(buttons); + waitForIdle(); + } + + /** + * Clicks mouse button 1 + * + * @throws IllegalArgumentException if the {@code buttons} mask contains the mask for + * extra mouse button and support for extended mouse buttons is + * {@link Toolkit#areExtraMouseButtonsEnabled() disabled} by Java + * @throws IllegalArgumentException if the {@code buttons} mask contains the mask for + * extra mouse button that does not exist on the mouse and support for extended + * mouse buttons is {@link Toolkit#areExtraMouseButtonsEnabled() enabled} + * by Java + * + * @see #click(int) + */ + public void click() { + click(InputEvent.BUTTON1_DOWN_MASK); + } + + /** + * Waits until all events currently on the event queue have been processed with given + * delay after syncing threads. It uses more advanced method of synchronizing threads + * unlike {@link java.awt.Robot#waitForIdle()} + * + * @param delayValue Additional delay length in milliseconds to wait until thread + * sync been completed + * @throws sun.awt.SunToolkit.IllegalThreadException if called on the AWT event + * dispatching thread + */ + public synchronized void waitForIdle(int delayValue) { + SunToolkit.flushPendingEvents(); + ((SunToolkit) Toolkit.getDefaultToolkit()).realSync(); + delay(delayValue); + } + + /** + * Waits until all events currently on the event queue have been processed with delay + * {@link #getSyncDelay()} after syncing threads. It uses more advanced method of + * synchronizing threads unlike {@link java.awt.Robot#waitForIdle()} + * + * @throws sun.awt.SunToolkit.IllegalThreadException if called on the AWT event + * dispatching thread + * + * @see #waitForIdle(int) + */ + @Override + public synchronized void waitForIdle() { + waitForIdle(syncDelay); + } + + /** + * Move the mouse in multiple steps from where it is + * now to the destination coordinates. + * + * @param x Destination point x coordinate + * @param y Destination point y coordinate + * + * @see #glide(int, int, int, int) + */ + public void glide(int x, int y) { + Point p = MouseInfo.getPointerInfo().getLocation(); + glide(p.x, p.y, x, y); + } + + /** + * Move the mouse in multiple steps from where it is + * now to the destination point. + * + * @param dest Destination point + * + * @see #glide(int, int) + */ + public void glide(Point dest) { + glide(dest.x, dest.y); + } + + /** + * Move the mouse in multiple steps from source coordinates + * to the destination coordinates. + * + * @param fromX Source point x coordinate + * @param fromY Source point y coordinate + * @param toX Destination point x coordinate + * @param toY Destination point y coordinate + * + * @see #glide(int, int, int, int, int, int) + */ + public void glide(int fromX, int fromY, int toX, int toY) { + glide(fromX, fromY, toX, toY, DEFAULT_STEP_LENGTH, DEFAULT_SPEED); + } + + /** + * Move the mouse in multiple steps from source point to the + * destination point with default speed and step length. + * + * @param src Source point + * @param dest Destination point + * + * @see #glide(int, int, int, int, int, int) + */ + public void glide(Point src, Point dest) { + glide(src.x, src.y, dest.x, dest.y, DEFAULT_STEP_LENGTH, DEFAULT_SPEED); + } + + /** + * Move the mouse in multiple steps from source point to the + * destination point with given speed and step length. + * + * @param srcX Source point x cordinate + * @param srcY Source point y cordinate + * @param destX Destination point x cordinate + * @param destY Destination point y cordinate + * @param stepLength Approximate length of one step + * @param speed Delay between steps. + * + * @see #mouseMove(int, int) + * @see #delay(int) + */ + public void glide(int srcX, int srcY, int destX, int destY, int stepLength, int speed) { + int stepNum; + double tDx, tDy; + double dx, dy, ds; + double x, y; + + dx = (destX - srcX); + dy = (destY - srcY); + ds = Math.sqrt(dx*dx + dy*dy); + + tDx = dx / ds * stepLength; + tDy = dy / ds * stepLength; + + int stepsCount = (int) ds / stepLength; + + // Walk the mouse to the destination one step at a time + mouseMove(srcX, srcY); + + for (x = srcX, y = srcY, stepNum = 0; + stepNum < stepsCount; + stepNum++) { + x += tDx; + y += tDy; + mouseMove((int)x, (int)y); + delay(speed); + } + + // Ensure the mouse moves to the right destination. + // The steps may have led the mouse to a slightly wrong place. + mouseMove(destX, destY); + } + + /** + * Moves mouse pointer to given screen coordinates. + * + * @param position Target position + * + * @see java.awt.Robot#mouseMove(int, int) + */ + public synchronized void mouseMove(Point position) { + mouseMove(position.x, position.y); + } + + /** + * Successively presses and releases a given key. + *

+ * Key codes that have more than one physical key associated with them + * (e.g. {@code KeyEvent.VK_SHIFT} could mean either the + * left or right shift key) will map to the left key. + * + * @param keycode Key to press (e.g. {@code KeyEvent.VK_A}) + * @throws IllegalArgumentException if {@code keycode} is not + * a valid key + * + * @see java.awt.Robot#keyPress(int) + * @see java.awt.Robot#keyRelease(int) + * @see java.awt.event.KeyEvent + */ + public void type(int keycode) { + keyPress(keycode); + waitForIdle(DEFAULT_SPEED); + keyRelease(keycode); + waitForIdle(DEFAULT_SPEED); + } + + /** + * Types given character + * + * @param c Character to be typed (e.g. {@code 'a'}) + * + * @see #type(int) + * @see java.awt.event.KeyEvent + */ + public void type(char c) { + type(ExtendedKeyCodes.getExtendedKeyCodeForChar(c)); + } + + /** + * Types given array of characters one by one + * + * @param symbols Array of characters to be typed + * + * @see #type(char) + */ + public void type(char[] symbols) { + for (int i = 0; i < symbols.length; i++) { + type(symbols[i]); + } + } + + /** + * Types given string + * + * @param s String to be typed + * + * @see #type(char[]) + */ + public void type(String s) { + type(s.toCharArray()); + } +}