-
Notifications
You must be signed in to change notification settings - Fork 6.1k
8150564: Migrate useful ExtendedRobot methods into awt.Robot #26969
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
base: master
Are you sure you want to change the base?
Changes from 15 commits
c51406a
a98fb87
947f73d
b17e483
9583f8a
d76baf5
abd6ab9
0824a98
781a2ba
8f07b10
4f522f4
0196752
2410e00
b9e68d5
a9f6f5b
d324ea9
215ff9d
a744389
4e2afa4
9801f13
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
@@ -126,6 +126,18 @@ public class Robot { | |||||||||
|
||||||||||
private DirectColorModel screenCapCM = null; | ||||||||||
|
||||||||||
/** | ||||||||||
* Default step-delay in milliseconds for mouse | ||||||||||
* {@link #glide(int, int, int, int) glide}. | ||||||||||
*/ | ||||||||||
public static final int DEFAULT_STEP_DELAY = 20; | ||||||||||
|
||||||||||
/** | ||||||||||
* Default pixel step-length for mouse | ||||||||||
* {@link #glide(int, int, int, int) glide}. | ||||||||||
*/ | ||||||||||
public static final int DEFAULT_STEP_LENGTH = 2; | ||||||||||
|
||||||||||
/** | ||||||||||
* Constructs a Robot object in the coordinate system of the primary screen. | ||||||||||
* | ||||||||||
|
@@ -774,3 +786,215 @@ public synchronized String toString() { | |||||||||
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 delay of 20 milliseconds after | ||||||||||
DamonGuy marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||||||
* {@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 | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||
* @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} | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||
* by Java | ||||||||||
* @throws IllegalThreadStateException if called on the AWT event dispatching thread | ||||||||||
* @see #mousePress(int) | ||||||||||
* @see #mouseRelease(int) | ||||||||||
* @see InputEvent#getMaskForButton(int) | ||||||||||
* @see Toolkit#areExtraMouseButtonsEnabled() | ||||||||||
* @see java.awt.event.MouseEvent | ||||||||||
* @since 26 | ||||||||||
*/ | ||||||||||
public void click(int buttons) { | ||||||||||
try { | ||||||||||
mousePress(buttons); | ||||||||||
waitForIdle(DEFAULT_STEP_DELAY); | ||||||||||
} finally { | ||||||||||
mouseRelease(buttons); | ||||||||||
waitForIdle(DEFAULT_STEP_DELAY); | ||||||||||
} | ||||||||||
} | ||||||||||
|
||||||||||
/** | ||||||||||
* A convenience method that clicks mouse button 1. | ||||||||||
* | ||||||||||
* @throws IllegalThreadStateException if called on the AWT event dispatching thread | ||||||||||
* @see #click(int) | ||||||||||
* @since 26 | ||||||||||
*/ | ||||||||||
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 26 | ||||||||||
*/ | ||||||||||
public synchronized void waitForIdle(int delayValue) { | ||||||||||
waitForIdle(); | ||||||||||
delay(delayValue); | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. think we should recheck whether new methods like this one need to be synchronized. Some time ago, the synchronized keyword was removed from the delay method because synchronization could cause the delay to last longer than intended and unnecessarily block other methods. In this case, waitForIdle() might be in a synchronized block (but the method itself is already synchronized), but do we really want to call delay() while holding the lock? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I expect you are referring to this fix you did about 6 years ago https://bugs.openjdk.org/browse/JDK-8210231 ? That bug was more about side-effects of delay but ended up removing synchronized.
I'm not sure that ever affected any actual tests since Robot usage should be single threaded in all usual cases. I can just about see a case for removing synchronized from the waitForIdle(delay) method - because waitForIdle() is already synchronized There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, the click operation is a different operation and it would be nice to mark it as synchronized, but nothing is stopping the user from creating two robots and using them in parallel, which would lead to the same chaos. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Updated to make waitForIdle(int delay) not synchronized. Thanks! Will update the CSR accordingly. |
||||||||||
} | ||||||||||
|
||||||||||
/** | ||||||||||
* A convenience method that moves the mouse in multiple | ||||||||||
* steps from its current location to the destination coordinates. | ||||||||||
* | ||||||||||
* @implSpec Invokes {@link #mouseMove(int, int) mouseMove} with a default | ||||||||||
* {@link #DEFAULT_STEP_LENGTH step-length} and {@link #DEFAULT_STEP_DELAY step-delay}. | ||||||||||
DamonGuy marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||||||
* | ||||||||||
* @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_STEP_DELAY | ||||||||||
* @see #glide(int, int, int, int, int, int) | ||||||||||
* @since 26 | ||||||||||
*/ | ||||||||||
public void glide(int x, int y) { | ||||||||||
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. | ||||||||||
* | ||||||||||
* @implSpec Invokes {@link #mouseMove(int, int) mouseMove} with a default | ||||||||||
* {@link #DEFAULT_STEP_LENGTH step-length} and {@link #DEFAULT_STEP_DELAY step-delay}. | ||||||||||
* | ||||||||||
* @param srcX Source point x coordinate | ||||||||||
* @param srcY Source point y coordinate | ||||||||||
* @param dstX Destination point x coordinate | ||||||||||
* @param dstY 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_STEP_DELAY | ||||||||||
* @see #glide(int, int, int, int, int, int) | ||||||||||
* @since 26 | ||||||||||
*/ | ||||||||||
public void glide(int srcX, int srcY, int dstX, int dstY) { | ||||||||||
glide(srcX, srcY, dstX, dstY, DEFAULT_STEP_LENGTH, DEFAULT_STEP_DELAY); | ||||||||||
} | ||||||||||
|
||||||||||
/** | ||||||||||
* A convenience method that moves the mouse in multiple | ||||||||||
* steps from source point to the destination point with a | ||||||||||
* 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 not greater than zero | ||||||||||
* @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 26 | ||||||||||
*/ | ||||||||||
public void glide(int srcX, int srcY, int destX, int destY, int stepLength, int stepDelay) { | ||||||||||
if (stepLength <= 0) { | ||||||||||
throw new IllegalArgumentException("Step length must be greater than zero"); | ||||||||||
} | ||||||||||
if (stepDelay <= 0 || stepDelay > 60000) { | ||||||||||
throw new IllegalArgumentException("Step delay must be between 0 and 60,000 milliseconds"); | ||||||||||
} | ||||||||||
|
||||||||||
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(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 delay of 20 milliseconds | ||||||||||
* 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 | ||||||||||
* @since 26 | ||||||||||
*/ | ||||||||||
public synchronized void type(int keycode) { | ||||||||||
DamonGuy marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||
keyPress(keycode); | ||||||||||
waitForIdle(20); | ||||||||||
DamonGuy marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||||||
keyRelease(keycode); | ||||||||||
waitForIdle(20); | ||||||||||
} | ||||||||||
|
||||||||||
/** | ||||||||||
* 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). | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Or
Suggested change
|
||||||||||
* | ||||||||||
* @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 | ||||||||||
* @since 26 | ||||||||||
*/ | ||||||||||
public synchronized void type(char c) { | ||||||||||
type(KeyEvent.getExtendedKeyCodeForChar(c)); | ||||||||||
} | ||||||||||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
many new lines still longer than 80 chars.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried to follow a similar structure to the rest of the class. Some may be longer due to formatting links but I thought the result when generating the html looked fine. Was there any specific issue with the lines that are still longer than 80 chars?