1 /*
2 * Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
73 private static final int MAX_DELAY = 60000;
74 private RobotPeer peer;
75 private boolean isAutoWaitForIdle = false;
76 private int autoDelay = 0;
77 private static int LEGAL_BUTTON_MASK = 0;
78
79 private DirectColorModel screenCapCM = null;
80
81 /**
82 * Constructs a Robot object in the coordinate system of the primary screen.
83 *
84 * @throws AWTException if the platform configuration does not allow
85 * low-level input control. This exception is always thrown when
86 * GraphicsEnvironment.isHeadless() returns true
87 * @throws SecurityException if {@code createRobot} permission is not granted
88 * @see java.awt.GraphicsEnvironment#isHeadless
89 * @see SecurityManager#checkPermission
90 * @see AWTPermission
91 */
92 public Robot() throws AWTException {
93 if (GraphicsEnvironment.isHeadless()) {
94 throw new AWTException("headless environment");
95 }
96 init(GraphicsEnvironment.getLocalGraphicsEnvironment()
97 .getDefaultScreenDevice());
98 }
99
100 /**
101 * Creates a Robot for the given screen device. Coordinates passed
102 * to Robot method calls like mouseMove, getPixelColor and
103 * createScreenCapture will be interpreted as being in the same coordinate
104 * system as the specified screen. Note that depending on the platform
105 * configuration, multiple screens may either:
106 * <ul>
107 * <li>share the same coordinate system to form a combined virtual screen</li>
108 * <li>use different coordinate systems to act as independent screens</li>
109 * </ul>
110 * <p>
111 * If screen devices are reconfigured such that the coordinate system is
112 * affected, the behavior of existing Robot objects is undefined.
113 *
114 * @param screen A screen GraphicsDevice indicating the coordinate
115 * system the Robot will operate in.
116 * @throws AWTException if the platform configuration does not allow
117 * low-level input control. This exception is always thrown when
118 * GraphicsEnvironment.isHeadless() returns true.
119 * @throws IllegalArgumentException if {@code screen} is not a screen
120 * GraphicsDevice.
121 * @throws SecurityException if {@code createRobot} permission is not granted
122 * @see java.awt.GraphicsEnvironment#isHeadless
123 * @see GraphicsDevice
124 * @see SecurityManager#checkPermission
125 * @see AWTPermission
126 */
127 public Robot(GraphicsDevice screen) throws AWTException {
128 checkIsScreenDevice(screen);
129 init(screen);
130 }
131
132 private void init(GraphicsDevice screen) throws AWTException {
133 checkRobotAllowed();
134 Toolkit toolkit = Toolkit.getDefaultToolkit();
135 if (toolkit instanceof ComponentFactory) {
136 peer = ((ComponentFactory)toolkit).createRobot(this, screen);
137 }
138 initLegalButtonMask();
139 }
140
141 @SuppressWarnings("deprecation")
142 private static synchronized void initLegalButtonMask() {
143 if (LEGAL_BUTTON_MASK != 0) return;
144
145 int tmpMask = 0;
146 if (Toolkit.getDefaultToolkit().areExtraMouseButtonsEnabled()){
147 if (Toolkit.getDefaultToolkit() instanceof SunToolkit) {
148 final int buttonsNumber = ((SunToolkit)(Toolkit.getDefaultToolkit())).getNumberOfButtons();
149 for (int i = 0; i < buttonsNumber; i++){
150 tmpMask |= InputEvent.getMaskForButton(i+1);
151 }
152 }
153 }
154 tmpMask |= InputEvent.BUTTON1_MASK|
155 InputEvent.BUTTON2_MASK|
156 InputEvent.BUTTON3_MASK|
157 InputEvent.BUTTON1_DOWN_MASK|
158 InputEvent.BUTTON2_DOWN_MASK|
159 InputEvent.BUTTON3_DOWN_MASK;
160 LEGAL_BUTTON_MASK = tmpMask;
161 }
162
163 /* determine if the security policy allows Robot's to be created */
164 private void checkRobotAllowed() {
165 SecurityManager security = System.getSecurityManager();
166 if (security != null) {
167 security.checkPermission(AWTPermissions.CREATE_ROBOT_PERMISSION);
168 }
169 }
170
171 /* check if the given device is a screen device */
172 private void checkIsScreenDevice(GraphicsDevice device) {
173 if (device == null || device.getType() != GraphicsDevice.TYPE_RASTER_SCREEN) {
174 throw new IllegalArgumentException("not a valid screen device");
175 }
176 }
177
178 /**
179 * Moves mouse pointer to given screen coordinates.
180 * @param x X position
181 * @param y Y position
182 */
183 public synchronized void mouseMove(int x, int y) {
184 peer.mouseMove(x, y);
185 afterEvent();
186 }
187
188 /**
189 * Presses one or more mouse buttons. The mouse buttons should
190 * be released using the {@link #mouseRelease(int)} method.
191 *
192 * @param buttons the Button mask; a combination of one or more
283 * However, it is recommended to use {@code InputEvent.BUTTON1_DOWN_MASK},
284 * {@code InputEvent.BUTTON2_DOWN_MASK}, {@code InputEvent.BUTTON3_DOWN_MASK} instead.
285 * Either extended {@code _DOWN_MASK} or old {@code _MASK} values
286 * should be used, but both those models should not be mixed.
287 * @throws IllegalArgumentException if the {@code buttons} mask contains the mask for extra mouse button
288 * and support for extended mouse buttons is {@link Toolkit#areExtraMouseButtonsEnabled() disabled} by Java
289 * @throws IllegalArgumentException if the {@code buttons} mask contains the mask for extra mouse button
290 * that does not exist on the mouse and support for extended mouse buttons is {@link Toolkit#areExtraMouseButtonsEnabled() enabled} by Java
291 * @see #mousePress(int)
292 * @see InputEvent#getMaskForButton(int)
293 * @see Toolkit#areExtraMouseButtonsEnabled()
294 * @see java.awt.MouseInfo#getNumberOfButtons()
295 * @see java.awt.event.MouseEvent
296 */
297 public synchronized void mouseRelease(int buttons) {
298 checkButtonsArgument(buttons);
299 peer.mouseRelease(buttons);
300 afterEvent();
301 }
302
303 private void checkButtonsArgument(int buttons) {
304 if ( (buttons|LEGAL_BUTTON_MASK) != LEGAL_BUTTON_MASK ) {
305 throw new IllegalArgumentException("Invalid combination of button flags");
306 }
307 }
308
309 /**
310 * Rotates the scroll wheel on wheel-equipped mice.
311 *
312 * @param wheelAmt number of "notches" to move the mouse wheel
313 * Negative values indicate movement up/away from the user,
314 * positive values indicate movement down/towards the user.
315 *
316 * @since 1.4
317 */
318 public synchronized void mouseWheel(int wheelAmt) {
319 peer.mouseWheel(wheelAmt);
320 afterEvent();
321 }
322
323 /**
342
343 /**
344 * Releases a given key.
345 * <p>
346 * Key codes that have more than one physical key associated with them
347 * (e.g. {@code KeyEvent.VK_SHIFT} could mean either the
348 * left or right shift key) will map to the left key.
349 *
350 * @param keycode Key to release (e.g. {@code KeyEvent.VK_A})
351 * @throws IllegalArgumentException if {@code keycode} is not a
352 * valid key
353 * @see #keyPress(int)
354 * @see java.awt.event.KeyEvent
355 */
356 public synchronized void keyRelease(int keycode) {
357 checkKeycodeArgument(keycode);
358 peer.keyRelease(keycode);
359 afterEvent();
360 }
361
362 private void checkKeycodeArgument(int keycode) {
363 // rather than build a big table or switch statement here, we'll
364 // just check that the key isn't VK_UNDEFINED and assume that the
365 // peer implementations will throw an exception for other bogus
366 // values e.g. -1, 999999
367 if (keycode == KeyEvent.VK_UNDEFINED) {
368 throw new IllegalArgumentException("Invalid key code");
369 }
370 }
371
372 /**
373 * Returns the color of a pixel at the given screen coordinates.
374 * @param x X position of pixel
375 * @param y Y position of pixel
376 * @return Color of the pixel
377 */
378 public synchronized Color getPixelColor(int x, int y) {
379 checkScreenCaptureAllowed();
380 AffineTransform tx = GraphicsEnvironment.
381 getLocalGraphicsEnvironment().getDefaultScreenDevice().
382 getDefaultConfiguration().getDefaultTransform();
647 * immediately with the interrupt status set. If the interrupted status is
648 * already set, this method returns immediately with the interrupt status
649 * set.
650 *
651 * @param ms time to sleep in milliseconds
652 * @throws IllegalArgumentException if {@code ms} is not between {@code 0}
653 * and {@code 60,000} milliseconds inclusive
654 */
655 public void delay(int ms) {
656 checkDelayArgument(ms);
657 Thread thread = Thread.currentThread();
658 if (!thread.isInterrupted()) {
659 try {
660 Thread.sleep(ms);
661 } catch (final InterruptedException ignored) {
662 thread.interrupt(); // Preserve interrupt status
663 }
664 }
665 }
666
667 private void checkDelayArgument(int ms) {
668 if (ms < 0 || ms > MAX_DELAY) {
669 throw new IllegalArgumentException("Delay must be to 0 to 60,000ms");
670 }
671 }
672
673 /**
674 * Waits until all events currently on the event queue have been processed.
675 * @throws IllegalThreadStateException if called on the AWT event dispatching thread
676 */
677 public synchronized void waitForIdle() {
678 checkNotDispatchThread();
679 SunToolkit.flushPendingEvents();
680 ((SunToolkit) Toolkit.getDefaultToolkit()).realSync();
681 }
682
683 private void checkNotDispatchThread() {
684 if (EventQueue.isDispatchThread()) {
685 throw new IllegalThreadStateException("Cannot call method from the event dispatcher thread");
686 }
687 }
688
689 /**
690 * Returns a string representation of this Robot.
691 *
692 * @return the string representation.
693 */
694 @Override
695 public synchronized String toString() {
696 String params = "autoDelay = "+getAutoDelay()+", "+"autoWaitForIdle = "+isAutoWaitForIdle();
697 return getClass().getName() + "[ " + params + " ]";
698 }
699 }
|
1 /*
2 * Copyright (c) 1999, 2020, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
73 private static final int MAX_DELAY = 60000;
74 private RobotPeer peer;
75 private boolean isAutoWaitForIdle = false;
76 private int autoDelay = 0;
77 private static int LEGAL_BUTTON_MASK = 0;
78
79 private DirectColorModel screenCapCM = null;
80
81 /**
82 * Constructs a Robot object in the coordinate system of the primary screen.
83 *
84 * @throws AWTException if the platform configuration does not allow
85 * low-level input control. This exception is always thrown when
86 * GraphicsEnvironment.isHeadless() returns true
87 * @throws SecurityException if {@code createRobot} permission is not granted
88 * @see java.awt.GraphicsEnvironment#isHeadless
89 * @see SecurityManager#checkPermission
90 * @see AWTPermission
91 */
92 public Robot() throws AWTException {
93 checkHeadless();
94 init(GraphicsEnvironment.getLocalGraphicsEnvironment()
95 .getDefaultScreenDevice());
96 }
97
98 /**
99 * Creates a Robot for the given screen device. Coordinates passed
100 * to Robot method calls like mouseMove, getPixelColor and
101 * createScreenCapture will be interpreted as being in the same coordinate
102 * system as the specified screen. Note that depending on the platform
103 * configuration, multiple screens may either:
104 * <ul>
105 * <li>share the same coordinate system to form a combined virtual screen</li>
106 * <li>use different coordinate systems to act as independent screens</li>
107 * </ul>
108 * <p>
109 * If screen devices are reconfigured such that the coordinate system is
110 * affected, the behavior of existing Robot objects is undefined.
111 *
112 * @param screen A screen GraphicsDevice indicating the coordinate
113 * system the Robot will operate in.
114 * @throws AWTException if the platform configuration does not allow
115 * low-level input control. This exception is always thrown when
116 * GraphicsEnvironment.isHeadless() returns true.
117 * @throws IllegalArgumentException if {@code screen} is not a screen
118 * GraphicsDevice.
119 * @throws SecurityException if {@code createRobot} permission is not granted
120 * @see java.awt.GraphicsEnvironment#isHeadless
121 * @see GraphicsDevice
122 * @see SecurityManager#checkPermission
123 * @see AWTPermission
124 */
125 public Robot(GraphicsDevice screen) throws AWTException {
126 checkHeadless();
127 checkIsScreenDevice(screen);
128 init(screen);
129 }
130
131 private void init(GraphicsDevice screen) throws AWTException {
132 checkRobotAllowed();
133 Toolkit toolkit = Toolkit.getDefaultToolkit();
134 if (toolkit instanceof ComponentFactory) {
135 peer = ((ComponentFactory)toolkit).createRobot(this, screen);
136 }
137 initLegalButtonMask();
138 }
139
140 @SuppressWarnings("deprecation")
141 private static synchronized void initLegalButtonMask() {
142 if (LEGAL_BUTTON_MASK != 0) return;
143
144 int tmpMask = 0;
145 if (Toolkit.getDefaultToolkit().areExtraMouseButtonsEnabled()){
146 if (Toolkit.getDefaultToolkit() instanceof SunToolkit) {
147 final int buttonsNumber = ((SunToolkit)(Toolkit.getDefaultToolkit())).getNumberOfButtons();
148 for (int i = 0; i < buttonsNumber; i++){
149 tmpMask |= InputEvent.getMaskForButton(i+1);
150 }
151 }
152 }
153 tmpMask |= InputEvent.BUTTON1_MASK|
154 InputEvent.BUTTON2_MASK|
155 InputEvent.BUTTON3_MASK|
156 InputEvent.BUTTON1_DOWN_MASK|
157 InputEvent.BUTTON2_DOWN_MASK|
158 InputEvent.BUTTON3_DOWN_MASK;
159 LEGAL_BUTTON_MASK = tmpMask;
160 }
161
162 /* determine if the security policy allows Robot's to be created */
163 private static void checkRobotAllowed() {
164 SecurityManager security = System.getSecurityManager();
165 if (security != null) {
166 security.checkPermission(AWTPermissions.CREATE_ROBOT_PERMISSION);
167 }
168 }
169
170 /**
171 * Check for headless state and throw {@code AWTException} if headless.
172 */
173 private static void checkHeadless() throws AWTException {
174 if (GraphicsEnvironment.isHeadless()) {
175 throw new AWTException("headless environment");
176 }
177 }
178
179 /* check if the given device is a screen device */
180 private static void checkIsScreenDevice(GraphicsDevice device) {
181 if (device == null || device.getType() != GraphicsDevice.TYPE_RASTER_SCREEN) {
182 throw new IllegalArgumentException("not a valid screen device");
183 }
184 }
185
186 /**
187 * Moves mouse pointer to given screen coordinates.
188 * @param x X position
189 * @param y Y position
190 */
191 public synchronized void mouseMove(int x, int y) {
192 peer.mouseMove(x, y);
193 afterEvent();
194 }
195
196 /**
197 * Presses one or more mouse buttons. The mouse buttons should
198 * be released using the {@link #mouseRelease(int)} method.
199 *
200 * @param buttons the Button mask; a combination of one or more
291 * However, it is recommended to use {@code InputEvent.BUTTON1_DOWN_MASK},
292 * {@code InputEvent.BUTTON2_DOWN_MASK}, {@code InputEvent.BUTTON3_DOWN_MASK} instead.
293 * Either extended {@code _DOWN_MASK} or old {@code _MASK} values
294 * should be used, but both those models should not be mixed.
295 * @throws IllegalArgumentException if the {@code buttons} mask contains the mask for extra mouse button
296 * and support for extended mouse buttons is {@link Toolkit#areExtraMouseButtonsEnabled() disabled} by Java
297 * @throws IllegalArgumentException if the {@code buttons} mask contains the mask for extra mouse button
298 * that does not exist on the mouse and support for extended mouse buttons is {@link Toolkit#areExtraMouseButtonsEnabled() enabled} by Java
299 * @see #mousePress(int)
300 * @see InputEvent#getMaskForButton(int)
301 * @see Toolkit#areExtraMouseButtonsEnabled()
302 * @see java.awt.MouseInfo#getNumberOfButtons()
303 * @see java.awt.event.MouseEvent
304 */
305 public synchronized void mouseRelease(int buttons) {
306 checkButtonsArgument(buttons);
307 peer.mouseRelease(buttons);
308 afterEvent();
309 }
310
311 private static void checkButtonsArgument(int buttons) {
312 if ( (buttons|LEGAL_BUTTON_MASK) != LEGAL_BUTTON_MASK ) {
313 throw new IllegalArgumentException("Invalid combination of button flags");
314 }
315 }
316
317 /**
318 * Rotates the scroll wheel on wheel-equipped mice.
319 *
320 * @param wheelAmt number of "notches" to move the mouse wheel
321 * Negative values indicate movement up/away from the user,
322 * positive values indicate movement down/towards the user.
323 *
324 * @since 1.4
325 */
326 public synchronized void mouseWheel(int wheelAmt) {
327 peer.mouseWheel(wheelAmt);
328 afterEvent();
329 }
330
331 /**
350
351 /**
352 * Releases a given key.
353 * <p>
354 * Key codes that have more than one physical key associated with them
355 * (e.g. {@code KeyEvent.VK_SHIFT} could mean either the
356 * left or right shift key) will map to the left key.
357 *
358 * @param keycode Key to release (e.g. {@code KeyEvent.VK_A})
359 * @throws IllegalArgumentException if {@code keycode} is not a
360 * valid key
361 * @see #keyPress(int)
362 * @see java.awt.event.KeyEvent
363 */
364 public synchronized void keyRelease(int keycode) {
365 checkKeycodeArgument(keycode);
366 peer.keyRelease(keycode);
367 afterEvent();
368 }
369
370 private static void checkKeycodeArgument(int keycode) {
371 // rather than build a big table or switch statement here, we'll
372 // just check that the key isn't VK_UNDEFINED and assume that the
373 // peer implementations will throw an exception for other bogus
374 // values e.g. -1, 999999
375 if (keycode == KeyEvent.VK_UNDEFINED) {
376 throw new IllegalArgumentException("Invalid key code");
377 }
378 }
379
380 /**
381 * Returns the color of a pixel at the given screen coordinates.
382 * @param x X position of pixel
383 * @param y Y position of pixel
384 * @return Color of the pixel
385 */
386 public synchronized Color getPixelColor(int x, int y) {
387 checkScreenCaptureAllowed();
388 AffineTransform tx = GraphicsEnvironment.
389 getLocalGraphicsEnvironment().getDefaultScreenDevice().
390 getDefaultConfiguration().getDefaultTransform();
655 * immediately with the interrupt status set. If the interrupted status is
656 * already set, this method returns immediately with the interrupt status
657 * set.
658 *
659 * @param ms time to sleep in milliseconds
660 * @throws IllegalArgumentException if {@code ms} is not between {@code 0}
661 * and {@code 60,000} milliseconds inclusive
662 */
663 public void delay(int ms) {
664 checkDelayArgument(ms);
665 Thread thread = Thread.currentThread();
666 if (!thread.isInterrupted()) {
667 try {
668 Thread.sleep(ms);
669 } catch (final InterruptedException ignored) {
670 thread.interrupt(); // Preserve interrupt status
671 }
672 }
673 }
674
675 private static void checkDelayArgument(int ms) {
676 if (ms < 0 || ms > MAX_DELAY) {
677 throw new IllegalArgumentException("Delay must be to 0 to 60,000ms");
678 }
679 }
680
681 /**
682 * Waits until all events currently on the event queue have been processed.
683 * @throws IllegalThreadStateException if called on the AWT event dispatching thread
684 */
685 public synchronized void waitForIdle() {
686 checkNotDispatchThread();
687 SunToolkit.flushPendingEvents();
688 ((SunToolkit) Toolkit.getDefaultToolkit()).realSync();
689 }
690
691 private static void checkNotDispatchThread() {
692 if (EventQueue.isDispatchThread()) {
693 throw new IllegalThreadStateException("Cannot call method from the event dispatcher thread");
694 }
695 }
696
697 /**
698 * Returns a string representation of this Robot.
699 *
700 * @return the string representation.
701 */
702 @Override
703 public synchronized String toString() {
704 String params = "autoDelay = "+getAutoDelay()+", "+"autoWaitForIdle = "+isAutoWaitForIdle();
705 return getClass().getName() + "[ " + params + " ]";
706 }
707 }
|