Skip to content

8150564: Migrate useful ExtendedRobot methods into awt.Robot #22044

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 32 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
514a813
init commit
alisenchung Oct 23, 2024
b21c56b
added tests
alisenchung Oct 25, 2024
b60c093
fix tests
alisenchung Nov 10, 2024
633318c
fix spacing
alisenchung Nov 10, 2024
b39bd2e
Merge branch 'master' of https://github.com/openjdk/jdk into 8150564
alisenchung Nov 10, 2024
1c54001
extendedRobot
alisenchung Nov 12, 2024
955f551
move mouseMove back to ER
alisenchung Nov 15, 2024
4cb44bc
merge
alisenchung Nov 15, 2024
c0733de
Merge branch 'master' of https://github.com/openjdk/jdk into 8150564
alisenchung Nov 15, 2024
a11b8ac
update specifications
alisenchung Nov 20, 2024
adb0f58
fix var names in ER
alisenchung Nov 21, 2024
d330af3
add specification to public default fields
alisenchung Nov 21, 2024
830a5b5
update specification to public default fields, add waitforidle except…
alisenchung Nov 21, 2024
a8482f5
Merge branch 'master' of https://github.com/openjdk/jdk into 8150564
alisenchung Nov 25, 2024
84384f9
removing lesser used overridden methods
alisenchung Nov 26, 2024
32b7079
fix syncdelay in ER
alisenchung Nov 27, 2024
420c422
add code tag to specifications in Robot
alisenchung Dec 3, 2024
449b1d5
fix test with removed robot.glide using points
alisenchung Dec 3, 2024
bbfef4a
merge
alisenchung Dec 3, 2024
97e2424
update glide in test
alisenchung Dec 3, 2024
c3e5671
update specifications, replace default values in specifications with …
alisenchung Dec 4, 2024
30ca6a6
merge
alisenchung Feb 6, 2025
c0cd6e7
remove specified numbers in constant fields, add exception to documen…
alisenchung May 12, 2025
cbcf3fb
Merge branch 'master' of https://github.com/openjdk/jdk into 8150564
alisenchung Jun 10, 2025
7eab183
migrate type(char) method
alisenchung Jun 10, 2025
a46b067
synchronized for type(char)
alisenchung Jun 10, 2025
0abc123
update tests
alisenchung Jun 12, 2025
9aa8201
update tests, remove extended robot from some tests
alisenchung Jun 13, 2025
8347d2f
remove /lib/client/ from tests with ER removed
alisenchung Jul 2, 2025
9f19885
remove ER from remaining modal test
alisenchung Jul 3, 2025
3a9372c
Merge branch 'master' of https://github.com/openjdk/jdk into 8150564
alisenchung Jul 7, 2025
c02d418
update robot specs
alisenchung Jul 10, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
210 changes: 210 additions & 0 deletions src/java.desktop/share/classes/java/awt/Robot.java
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,17 @@ public class Robot {

private DirectColorModel screenCapCM = null;

/**
* Default delay for mouse {@code click} and
* step delay for mouse {@code glide} in milliseconds.
*/
public static final int DEFAULT_DELAY = 20;

/**
* Default pixel step length for mouse {@code glide}.
*/
public static final int DEFAULT_STEP_LENGTH = 2;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to make the DEFAULT_DELAY and DEFAULT_STEP_LENGTH configurable?

Copy link
Contributor

@prrace prrace May 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"glide has over-rides step length"

Sorry, that text was not clear. What I mean is that glide(..) accepts delay and step parameters, and so at least in that case you can over-ride with your preferred values.

Other than that, it isn't configurable in the ExtendedRobot, so the need isn't clear.

Even so, we could do this but whether now or later, but in either case,
we ought to think now as to what it would look like so it can be compatibly added.

In ExtendedRobot the equivalent fields are private but here they are public.
Tests might start to use them directly. I'm not sure what for, but they might.
But if it is configurable tests probably should instead call a getter() for the currently set delay/step.

Then all the methods that now mention DEFAULT_ would probably need to mention something like
getMouseDelay() and getStepLength() instead.

So it may be better to do it now ? Thoughts ?


/**
* Constructs a Robot object in the coordinate system of the primary screen.
*
Expand Down Expand Up @@ -773,4 +784,203 @@ public synchronized String toString() {
String params = "autoDelay = "+getAutoDelay()+", "+"autoWaitForIdle = "+isAutoWaitForIdle();
return getClass().getName() + "[ " + params + " ]";
}

/**
* A convenience method that simulates clicking a mouse button by calling {@code mousePress}, {@code mouseRelease},
* and {@code waitForIdle}. Invokes {@code waitForIdle} with a default {@link #DEFAULT_DELAY delay} after
* {@code mousePress} and {@code mouseRelease} calls. For specifics on valid inputs see
* {@link java.awt.Robot#mousePress(int)}.
*
* @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
* @throws IllegalThreadStateException if called on the AWT event dispatching thread
* @see #mousePress(int)
* @see #mouseRelease(int)
* @see #DEFAULT_DELAY
* @see InputEvent#getMaskForButton(int)
* @see Toolkit#areExtraMouseButtonsEnabled()
* @see java.awt.event.MouseEvent
* @since 25
*/
public void click(int buttons) {
mousePress(buttons);
waitForIdle(DEFAULT_DELAY);
mouseRelease(buttons);
waitForIdle(DEFAULT_DELAY);
}

/**
* A convenience method that clicks mouse button 1.
*
* @throws IllegalThreadStateException if called on the AWT event dispatching thread
* @see #click(int)
* @since 25
*/
public void click() {
click(InputEvent.BUTTON1_DOWN_MASK);
}

/**
* A convenience method that calls {@code waitForIdle} then waits an additional specified
* {@code delayValue} time in milliseconds.
*
* @param delayValue Additional delay length in milliseconds to wait until thread
* sync been completed
* @throws IllegalThreadStateException if called on the AWT event
* dispatching thread
* @throws IllegalArgumentException if {@code delayValue} is not between {@code 0}
* and {@code 60,000} milliseconds inclusive
* @since 25
*/
public synchronized void waitForIdle(int delayValue) {
waitForIdle();
delay(delayValue);
}

/**
* A convenience method that moves the mouse in multiple
* steps from its current location to the destination coordinates
* with a default {@link #DEFAULT_STEP_LENGTH step-length} and {@link #DEFAULT_DELAY delay}.
*
* @param x Destination point x coordinate
* @param y Destination point y coordinate
*
* @throws IllegalThreadStateException if called on the AWT event dispatching
* thread and {@code isAutoWaitForIdle} would return true
* @see #DEFAULT_STEP_LENGTH
* @see #DEFAULT_DELAY
* @see #glide(int, int, int, int, int, int)
* @since 25
*/
public void glide(int x, int y) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see the public void glide(Point dest) and public void glide(Point src, Point dest) added, it may be convenient in some cases.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've taken a look at all the tests running glide and very few of them actually used glide(Point dest) and glide(Point src, Point dest) so I decided to remove them from them from the migration

Point p = MouseInfo.getPointerInfo().getLocation();
glide(p.x, p.y, x, y);
}

/**
* A convenience method that moves the mouse in multiple steps
* from source coordinates to the destination coordinates with
* a default {@link #DEFAULT_STEP_LENGTH step-length} and {@link #DEFAULT_DELAY delay}.
*
* @param fromX Source point x coordinate
* @param fromY Source point y coordinate
* @param toX Destination point x coordinate
* @param toY Destination point y coordinate
*
* @throws IllegalThreadStateException if called on the AWT event dispatching
* thread and {@code isAutoWaitForIdle} would return true
* @see #DEFAULT_STEP_LENGTH
* @see #DEFAULT_DELAY
* @see #glide(int, int, int, int, int, int)
* @since 25
*/
public void glide(int fromX, int fromY, int toX, int toY) {
glide(fromX, fromY, toX, toY, DEFAULT_STEP_LENGTH, DEFAULT_DELAY);
}

/**
* A convenience method that moves the mouse in multiple
* steps from source point to the destination point with
* given {@code stepLength} and {@code stepDelay}.
*
* @param srcX Source point x coordinate
* @param srcY Source point y coordinate
* @param destX Destination point x coordinate
* @param destY Destination point y coordinate
* @param stepLength Preferred length of one step in pixels
* @param stepDelay Delay between steps in milliseconds
*
* @throws IllegalArgumentException if {@code stepLength} is a negative value or
* greater than the distance between source and destination points
* @throws IllegalArgumentException if {@code stepDelay} is not between {@code 0}
* and {@code 60,000} milliseconds inclusive
* @throws IllegalThreadStateException if called on the AWT event dispatching
* thread and {@code isAutoWaitForIdle} would return true
* @see #mouseMove(int, int)
* @see #delay(int)
* @since 25
*/
public void glide(int srcX, int srcY, int destX, int destY, int stepLength, int stepDelay) {
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);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mouseMove can throw an IllegalThreadStateException under certain circumstances.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes should be added to all glide API methods

delay(stepDelay);
}

// Ensure the mouse moves to the right destination.
// The steps may have led the mouse to a slightly wrong place.
if (x != destX || y != destY) mouseMove(destX, destY);
}

/**
* A convenience method that simulates typing a key by calling {@code keyPress}
* and {@code keyRelease}. Invokes {@code waitForIdle} with a default {@link #DEFAULT_DELAY delay}
* after {@code keyPress} and {@code keyRelease} calls.
* <p>
* 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 type (e.g. {@code KeyEvent.VK_A})
* @throws IllegalArgumentException if {@code keycode} is not
* a valid key
* @throws IllegalThreadStateException if called on the AWT event dispatching thread
* @see #keyPress(int)
* @see #keyRelease(int)
* @see java.awt.event.KeyEvent
* @see #DEFAULT_DELAY
* @since 25
*/
public synchronized void type(int keycode) {
keyPress(keycode);
waitForIdle(DEFAULT_DELAY);
keyRelease(keycode);
waitForIdle(DEFAULT_DELAY);
}

/**
* A convenience method that simulates typing a char by calling {@code keyPress}
* and {@code keyRelease}. Gets the ExtendedKeyCode for the char and calls
* type(int keycode).
*
* @param c Character to be typed (e.g. {@code 'a'})
* @throws IllegalArgumentException if {@code keycode} is not
* a valid key
* @throws IllegalThreadStateException if called on the AWT event dispatching thread
* @see #type(int)
* @see #keyPress(int)
* @see #keyRelease(int)
* @see java.awt.event.KeyEvent
* @see #DEFAULT_DELAY
* @since 25
*/
public synchronized void type(char c) {
type(KeyEvent.getExtendedKeyCodeForChar(c));
}
}
7 changes: 3 additions & 4 deletions test/jdk/java/awt/Component/PaintAll/PaintAll.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import java.awt.Label;
import java.awt.List;
import java.awt.Panel;
import java.awt.Robot;
import java.awt.ScrollPane;
import java.awt.Scrollbar;
import java.awt.TextArea;
Expand All @@ -47,8 +48,6 @@
@bug 6596915
@summary Test Component.paintAll() method
@author [email protected]: area=awt.component
@library /lib/client/
@build ExtendedRobot
@run main PaintAll
*/
public class PaintAll {
Expand All @@ -67,7 +66,7 @@ public class PaintAll {
private static volatile boolean scrollPanePainted;
private static volatile boolean textAreaPainted;
private static volatile boolean textFieldPainted;
private static ExtendedRobot robot = null;
private static Robot robot = null;

private static final Button buttonStub = new Button() {
@Override
Expand Down Expand Up @@ -287,7 +286,7 @@ private static void validation() {
private static void sleep() {
if(robot == null) {
try {
robot = new ExtendedRobot();
robot = new Robot();
}catch(Exception ex) {
ex.printStackTrace();
throw new RuntimeException("Unexpected failure");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,11 @@
* @summary An attempt to set non-trivial background, shape, or translucency
* to a decorated toplevel should end with an exception.
* @author Dmitriy Ermashov ([email protected])
* @library /lib/client
* @build ExtendedRobot
* @run main DecoratedExceptions
*/
public class DecoratedExceptions {
public static void main(String args[]) throws Exception{
ExtendedRobot robot = new ExtendedRobot();
Robot robot = new Robot();
Toolkit.getDefaultToolkit().getSystemEventQueue().invokeAndWait(() -> {
Frame frame = new Frame("Frame");
frame.setBounds(50,50,400,200);
Expand Down
7 changes: 3 additions & 4 deletions test/jdk/java/awt/Frame/DisposeParentGC/DisposeParentGC.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import java.awt.Label;
import java.awt.List;
import java.awt.Point;
import java.awt.Robot;
import java.awt.Scrollbar;
import java.awt.TextArea;
import java.awt.TextField;
Expand All @@ -52,14 +53,12 @@
* @summary Display a dialog with a parent, the dialog contains all awt components
* added to it & each components are setted with different cursors types.
* Dispose the parent & collect GC. Garbage collection should happen
* @library /lib/client
* @build ExtendedRobot
* @run main/othervm -Xmx20m DisposeParentGC
*/

public class DisposeParentGC {
Frame parentFrame;
ExtendedRobot robot;
Robot robot;

ArrayList<PhantomReference<Dialog>> refs = new ArrayList<PhantomReference<Dialog>>();
ReferenceQueue<Dialog> que = new ReferenceQueue<>();
Expand All @@ -69,7 +68,7 @@ public static void main(String []args) throws Exception {
}

DisposeParentGC() throws Exception {
robot = new ExtendedRobot();
robot = new Robot();
EventQueue.invokeAndWait(this::initGui);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,6 @@
* @test
* @key headful
* @summary To check proper WINDOW_EVENTS are triggered when Frame gains or losses the focus
* @library /lib/client
* @build ExtendedRobot
* @run main ActiveAWTWindowTest
*/

Expand All @@ -36,6 +34,7 @@
import java.awt.EventQueue;
import java.awt.FlowLayout;
import java.awt.Frame;
import java.awt.Robot;
import java.awt.TextField;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
Expand Down Expand Up @@ -165,9 +164,9 @@ public void actionPerformed(ActionEvent e) {
}

public void doTest() {
ExtendedRobot robot;
Robot robot;
try {
robot = new ExtendedRobot();
robot = new Robot();
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("Cannot create robot");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
* @author Jitender([email protected]) area=AWT
* @author yan
* @library /lib/client
* @build ExtendedRobot
* @run main ActiveSwingWindowTest
*/

Expand All @@ -45,7 +44,7 @@ public class ActiveSwingWindowTest {
private JButton button, button2;
private JTextField textField, textField2;
private int eventType, eventType1;
private ExtendedRobot robot;
private Robot robot;
private Object lock1 = new Object();
private Object lock2 = new Object();
private Object lock3 = new Object();
Expand Down Expand Up @@ -151,7 +150,7 @@ public void actionPerformed(ActionEvent e) {

public void doTest() {
try {
robot = new ExtendedRobot();
robot = new Robot();
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("Cannot create robot");
Expand Down
5 changes: 2 additions & 3 deletions test/jdk/java/awt/Frame/MiscUndecorated/FrameCloseTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
* @author Jitender([email protected]) area=AWT*
* @author yan
* @library /lib/client
* @build ExtendedRobot
* @run main FrameCloseTest
*/

Expand All @@ -43,7 +42,7 @@ public class FrameCloseTest {
private Frame frame, frame2;
private Component button, dummyButton;
private int eventType, eventType1, eventType2;
private ExtendedRobot robot;
private Robot robot;
private Object lock1 = new Object();
private Object lock2 = new Object();
private Object lock3 = new Object();
Expand Down Expand Up @@ -156,7 +155,7 @@ public void run() {
throw new RuntimeException("Interrupted or unexpected Exception occured");
}
try {
robot = new ExtendedRobot();
robot = new Robot();
robot.waitForIdle(1000);
} catch (Exception e) {
e.printStackTrace();
Expand Down
Loading