org.sikuli.script.RobotDesktop Maven / Gradle / Ivy
/*
* Copyright (c) 2010-2016, Sikuli.org, sikulix.com
* Released under the MIT License.
*
*/
package org.sikuli.script;
import org.sikuli.basics.Animator;
import org.sikuli.basics.AnimatorOutQuarticEase;
import org.sikuli.basics.AnimatorTimeBased;
import org.sikuli.basics.Settings;
import org.sikuli.basics.Debug;
import java.awt.AWTException;
import java.awt.Color;
import java.awt.MouseInfo;
import java.awt.Point;
import java.awt.PointerInfo;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.Date;
/**
* INTERNAL USE Implementation of IRobot making a DesktopRobot using java.awt.Robot
*/
public class RobotDesktop extends Robot implements IRobot {
final static int MAX_DELAY = 60000;
private static int heldButtons = 0;
private static String heldKeys = "";
private static final ArrayList heldKeyCodes = new ArrayList();
public static int stdAutoDelay = 0;
public static int stdDelay = 10;
public static int stdMaxElapsed = 1000;
private Screen scr = null;
private static RunTime runTime = RunTime.get();
private long start;
private static boolean alwaysNewRobot = false;
private static boolean isMouseInitialized = false;
private void logRobot(int delay, String msg) {
start = new Date().getTime();
int theDelay = getAutoDelay();
if (theDelay > 0 && theDelay > delay) {
Debug.log(0, msg, isAutoWaitForIdle(), theDelay);
}
}
private void logRobot(String msg, int maxElapsed) {
long elapsed = new Date().getTime() - start;
if (elapsed > maxElapsed) {
Debug.log(0, msg, elapsed);
setAutoDelay(stdAutoDelay);
setAutoWaitForIdle(false);
}
}
private void doMouseMove(int x, int y) {
mouseMove(x, y);
}
private void doMouseDown(int buttons) {
if (Settings.RobotFake && runTime.needsRobotFake()) {
Screen.getFakeRegion().silentHighlight(true);
}
logRobot(stdAutoDelay, "MouseDown: WaitForIdle: %s - Delay: %d");
setAutoDelay(stdAutoDelay);
setAutoWaitForIdle(Settings.ClickFast);
if (Settings.RobotFake && runTime.needsRobotFake()) {
delay(20);
Screen.getFakeRegion().silentHighlight(false);
delay(20);
}
mousePress(buttons);
setAutoWaitForIdle(false);
if (!Settings.ClickFast && stdAutoDelay == 0) {
delay(stdDelay);
}
logRobot("MouseDown: extended delay: %d", stdMaxElapsed);
}
private void doMouseUp(int buttons) {
logRobot(stdAutoDelay, "MouseUp: WaitForIdle: %s - Delay: %d");
setAutoDelay(stdAutoDelay);
setAutoWaitForIdle(Settings.ClickFast);
mouseRelease(buttons);
setAutoWaitForIdle(false);
if (!Settings.ClickFast && stdAutoDelay == 0) {
delay(stdDelay);
}
logRobot("MouseUp: extended delay: %d", stdMaxElapsed);
}
private void doKeyPress(int keyCode) {
logRobot(stdAutoDelay, "KeyPress: WaitForIdle: %s - Delay: %d");
setAutoDelay(stdAutoDelay);
setAutoWaitForIdle(false);
keyPress(keyCode);
if (stdAutoDelay == 0) {
delay(stdDelay);
}
logRobot("KeyPress: extended delay: %d", stdMaxElapsed);
}
private void doKeyRelease(int keyCode) {
logRobot(stdAutoDelay, "KeyRelease: WaitForIdle: %s - Delay: %d");
setAutoDelay(stdAutoDelay);
setAutoWaitForIdle(false);
keyRelease(keyCode);
if (stdAutoDelay == 0) {
delay(stdDelay);
}
logRobot("KeyRelease: extended delay: %d", stdMaxElapsed);
}
private Robot getRobot() {
return null;
}
@Override
public boolean isRemote() {
return false;
}
@Override
public Screen getScreen() {
return scr;
}
public RobotDesktop(Screen screen) throws AWTException {
super(runTime.getGraphicsDevice(screen.getcurrentID()));
scr = screen;
}
public RobotDesktop() throws AWTException {
super();
setAutoDelay(stdAutoDelay);
setAutoWaitForIdle(false);
}
@Override
public void smoothMove(Location dest) {
smoothMove(Mouse.at(), dest, (long) (Settings.MoveMouseDelay * 1000L));
}
@Override
public void smoothMove(Location src, Location dest, long ms) {
Debug.log(4, "RobotDesktop: smoothMove (%.1f): " + src.toString() + "---" + dest.toString(), ms/1000f);
if (ms == 0) {
doMouseMove(dest.x, dest.y);
waitForIdle();
checkMousePosition(dest);
return;
}
Animator aniX = new AnimatorTimeBased(
new AnimatorOutQuarticEase(src.x, dest.x, ms));
Animator aniY = new AnimatorTimeBased(
new AnimatorOutQuarticEase(src.y, dest.y, ms));
float x = 0, y = 0;
while (aniX.running()) {
x = aniX.step();
y = aniY.step();
doMouseMove((int) x, (int) y);
}
checkMousePosition(new Location((int) x, (int) y));
}
private void checkMousePosition(Location p) {
PointerInfo mp = MouseInfo.getPointerInfo();
Point pc;
if (mp == null) {
Debug.error("RobotDesktop: checkMousePosition: MouseInfo.getPointerInfo invalid\nafter move to %s", p);
} else {
pc = mp.getLocation();
if (pc.x != p.x || pc.y != p.y) {
if (isMouseInitialized) {
Debug.error("RobotDesktop: checkMousePosition: should be %s\nbut after move is %s"
+ "\nPossible cause in case you did not touch the mouse while script was running:\n"
+ " Mouse actions are blocked generally or by the frontmost application."
+ (Settings.isWindows() ? "\nYou might try to run the SikuliX stuff as admin." : ""),
p, new Location(pc));
}
}
}
if (!isMouseInitialized) {
isMouseInitialized = true;
}
}
@Override
public void mouseDown(int buttons) {
if (heldButtons != 0) {
heldButtons |= buttons;
} else {
heldButtons = buttons;
}
doMouseDown(heldButtons);
}
@Override
public int mouseUp(int buttons) {
if (buttons == 0) {
doMouseUp(heldButtons);
heldButtons = 0;
} else {
doMouseUp(buttons);
heldButtons &= ~buttons;
}
return heldButtons;
}
@Override
public void mouseReset() {
if (heldButtons != 0) {
setAutoWaitForIdle(false);
mouseRelease(heldButtons);
heldButtons = 0;
}
}
@Override
public void clickStarts() {
}
@Override
public void clickEnds() {
}
@Override
public void delay(int ms) {
if (ms < 0) {
return;
}
while (ms > MAX_DELAY) {
super.delay(MAX_DELAY);
ms -= MAX_DELAY;
}
super.delay(ms);
}
@Override
public ScreenImage captureScreen(Rectangle rect) {
// Rectangle s = scr.getBounds();
Rectangle cRect = new Rectangle(rect);
// cRect.translate(-s.x, -s.y);
BufferedImage img = createScreenCapture(rect);
Debug.log(4, "RobotDesktop: captureScreen: [%d,%d, %dx%d]",
rect.x, rect.y, rect.width, rect.height);
return new ScreenImage(rect, img);
}
@Override
public Color getColorAt(int x, int y) {
return getPixelColor(x, y);
}
@Override
public void pressModifiers(int modifiers) {
if ((modifiers & KeyModifier.SHIFT) != 0) {
doKeyPress(KeyEvent.VK_SHIFT);
}
if ((modifiers & KeyModifier.CTRL) != 0) {
doKeyPress(KeyEvent.VK_CONTROL);
}
if ((modifiers & KeyModifier.ALT) != 0) {
doKeyPress(KeyEvent.VK_ALT);
}
if ((modifiers & KeyModifier.META) != 0) {
if (Settings.isWindows()) {
doKeyPress(KeyEvent.VK_WINDOWS);
} else {
doKeyPress(KeyEvent.VK_META);
}
}
}
@Override
public void releaseModifiers(int modifiers) {
if ((modifiers & KeyModifier.SHIFT) != 0) {
doKeyRelease(KeyEvent.VK_SHIFT);
}
if ((modifiers & KeyModifier.CTRL) != 0) {
doKeyRelease(KeyEvent.VK_CONTROL);
}
if ((modifiers & KeyModifier.ALT) != 0) {
doKeyRelease(KeyEvent.VK_ALT);
}
if ((modifiers & KeyModifier.META) != 0) {
if (Settings.isWindows()) {
doKeyRelease(KeyEvent.VK_WINDOWS);
} else {
doKeyRelease(KeyEvent.VK_META);
}
}
}
@Override
public void keyDown(String keys) {
if (keys != null && !"".equals(keys)) {
for (int i = 0; i < keys.length(); i++) {
if (heldKeys.indexOf(keys.charAt(i)) == -1) {
Debug.log(4, "press: " + keys.charAt(i));
typeChar(keys.charAt(i), IRobot.KeyMode.PRESS_ONLY);
heldKeys += keys.charAt(i);
}
}
}
}
@Override
public void keyDown(int code) {
if (!heldKeyCodes.contains(code)) {
doKeyPress(code);
heldKeyCodes.add(code);
}
}
@Override
public void keyUp(String keys) {
if (keys != null && !"".equals(keys)) {
for (int i = 0; i < keys.length(); i++) {
int pos;
if ((pos = heldKeys.indexOf(keys.charAt(i))) != -1) {
Debug.log(4, "release: " + keys.charAt(i));
typeChar(keys.charAt(i), IRobot.KeyMode.RELEASE_ONLY);
heldKeys = heldKeys.substring(0, pos)
+ heldKeys.substring(pos + 1);
}
}
}
}
@Override
public void keyUp(int code) {
if (heldKeyCodes.contains(code)) {
doKeyRelease(code);
heldKeyCodes.remove((Object) code);
}
}
@Override
public void keyUp() {
keyUp(heldKeys);
for (int code : heldKeyCodes) {
keyUp(code);
}
}
private void doType(KeyMode mode, int... keyCodes) {
waitForIdle();
if (mode == KeyMode.PRESS_ONLY) {
for (int i = 0; i < keyCodes.length; i++) {
doKeyPress(keyCodes[i]);
}
} else if (mode == KeyMode.RELEASE_ONLY) {
for (int i = 0; i < keyCodes.length; i++) {
doKeyRelease(keyCodes[i]);
}
} else {
for (int i = 0; i < keyCodes.length; i++) {
doKeyPress(keyCodes[i]);
}
for (int i = 0; i < keyCodes.length; i++) {
doKeyRelease(keyCodes[i]);
}
}
waitForIdle();
}
@Override
public void typeChar(char character, KeyMode mode) {
Debug.log(4, "Robot: doType: %s ( %d )",
KeyEvent.getKeyText(Key.toJavaKeyCode(character)[0]).toString(),
Key.toJavaKeyCode(character)[0]);
doType(mode, Key.toJavaKeyCode(character));
}
@Override
public void typeKey(int key) {
Debug.log(4, "Robot: doType: %s ( %d )", KeyEvent.getKeyText(key), key);
if (Settings.isMac()) {
if (key == Key.toJavaKeyCodeFromText("#N.")) {
doType(KeyMode.PRESS_ONLY, Key.toJavaKeyCodeFromText("#C."));
doType(KeyMode.PRESS_RELEASE, key);
doType(KeyMode.RELEASE_ONLY, Key.toJavaKeyCodeFromText("#C."));
return;
} else if (key == Key.toJavaKeyCodeFromText("#T.")) {
doType(KeyMode.PRESS_ONLY, Key.toJavaKeyCodeFromText("#C."));
doType(KeyMode.PRESS_ONLY, Key.toJavaKeyCodeFromText("#A."));
doType(KeyMode.PRESS_RELEASE, key);
doType(KeyMode.RELEASE_ONLY, Key.toJavaKeyCodeFromText("#A."));
doType(KeyMode.RELEASE_ONLY, Key.toJavaKeyCodeFromText("#C."));
return;
} else if (key == Key.toJavaKeyCodeFromText("#X.")) {
key = Key.toJavaKeyCodeFromText("#T.");
doType(KeyMode.PRESS_ONLY, Key.toJavaKeyCodeFromText("#A."));
doType(KeyMode.PRESS_RELEASE, key);
doType(KeyMode.RELEASE_ONLY, Key.toJavaKeyCodeFromText("#A."));
return;
}
}
doType(KeyMode.PRESS_RELEASE, key);
}
@Override
public void typeStarts() {
}
@Override
public void typeEnds() {
}
@Override
public void cleanup() {
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy