All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.sikuli.script.App Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2010-2021, sikuli.org, sikulix.com - MIT license
 */
package org.sikuli.script;

import org.sikuli.basics.Debug;
import org.sikuli.natives.OSUtil;
import org.sikuli.natives.SysUtil;
import org.sikuli.script.support.RunTime;

import java.awt.Desktop;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.datatransfer.*;
import java.io.*;
import java.net.URL;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
//import org.apache.http.HttpEntity;
//import org.apache.http.HttpResponse;
//import org.apache.http.StatusLine;
//import org.apache.http.client.ClientProtocolException;
//import org.apache.http.client.HttpResponseException;
//import org.apache.http.client.ResponseHandler;
//import org.apache.http.client.methods.CloseableHttpResponse;
//import org.apache.http.client.methods.HttpGet;
//import org.apache.http.impl.client.CloseableHttpClient;
//import org.apache.http.impl.client.HttpClients;

/**
 * App implements features to manage (open, switch to, close) applications. on the system we are running on and to
 * access their assets like windows
 * 
* TAKE CARE: function behavior differs depending on the running system (cosult the docs for more info) */ public class App { private static OSUtil _osUtil = null; private static final Map appsWindows; private static final Map appsMac; private static final Region aRegion = new Region(); static { appsWindows = new HashMap(); appsWindows.put(Type.EDITOR, "Notepad"); appsWindows.put(Type.BROWSER, "Google Chrome"); appsWindows.put(Type.VIEWER, ""); appsMac = new HashMap(); appsMac.put(Type.EDITOR, "TextEdit"); appsMac.put(Type.BROWSER, "Safari"); appsMac.put(Type.VIEWER, "Preview"); } private boolean isGivenAsWindowTitle = false; public boolean isWindow() { return isGivenAsWindowTitle; } private void setGivenAsWindowTitle() { isGivenAsWindowTitle = true; } private void resetGivenAsWindowTitle() { isGivenAsWindowTitle = false; } // // // private static CloseableHttpClient httpclient = null; // // /** // * create a HTTP Client (for use of wwGet, ... multiple times as session) // * @return true on success, false otherwise // */ // public static boolean wwwStart() { // if (httpclient != null) { // return true; // } // httpclient = HttpClients.createDefault(); // if (httpclient != null) { // return true; // } // return false; // } // // /** // * stop a started HTTP Client // */ // public static void wwwStop() { // if (httpclient != null) { // try { // httpclient.close(); // } catch (IOException ex) { // } // httpclient = null; // } // } // // /** // * issue a http(s) request // * @param url a valid url as used in a browser // * @return textual content of the response or empty (UTF-8) // * @throws IOException // */ // public static String wwwGet(String url) throws IOException { // HttpGet httpget = new HttpGet(url); // CloseableHttpResponse response = null; // ResponseHandler rh = new ResponseHandler() { // @Override // public String handleResponse(final HttpResponse response) throws IOException { // StatusLine statusLine = response.getStatusLine(); // HttpEntity entity = response.getEntity(); // if (statusLine.getStatusCode() >= 300) { // throw new HttpResponseException( // statusLine.getStatusCode(), // statusLine.getReasonPhrase()); // } // if (entity == null) { // throw new ClientProtocolException("Response has no content"); // } // InputStream is = entity.getContent(); // ByteArrayOutputStream result = new ByteArrayOutputStream(); // byte[] buffer = new byte[1024]; // int length; // while ((length = is.read(buffer)) != -1) { // result.write(buffer, 0, length); // } // return result.toString("UTF-8"); // } // }; // boolean oneTime = false; // if (httpclient == null) { // wwwStart(); // oneTime = true; // } // Object content = httpclient.execute(httpget, rh); // if (oneTime) { // wwwStop(); // } // return (String) content; // } // // /** // * same as wwwGet(), but the content is also saved to a file // * @param url a valid url as used in a browser // * @param pOut absolute path to output file (overwritten) (if null: bundlePath/wwwSave.txt is taken) // * @return textual content of the response or empty (UTF-8) // * @throws IOException // */ // public static String wwwSave(String url, String pOut) throws IOException { // String content = wwwGet(url); // File out = null; // if (pOut == null) { // out = new File(ImagePath.getBundleFolder(), "wwwSave.txt"); // } else { // out = new File(pOut); // } // FileManager.writeStringToFile(content, out); // return content; // } // // // public static enum Type { EDITOR, BROWSER, VIEWER } public static Region start(Type appType) { App app = null; Region win; try { if (Type.EDITOR.equals(appType)) { if (RunTime.get().runningMac) { app = new App(appsMac.get(appType)); if (app.window() != null) { app.focus(); aRegion.wait(0.5); win = app.window(); aRegion.click(win); aRegion.write("#M.a#B."); return win; } else { app.open(); win = app.waitForWindow(); app.focus(); aRegion.wait(0.5); aRegion.click(win); return win; } } if (RunTime.get().runningWindows) { app = new App(appsWindows.get(appType)); if (app.window() != null) { app.focus(); aRegion.wait(0.5); win = app.window(); aRegion.click(win); aRegion.write("#C.a#B."); return win; } else { app.open(); win = app.waitForWindow(); app.focus(); aRegion.wait(0.5); aRegion.click(win); return win; } } } else if (Type.BROWSER.equals(appType)) { if (RunTime.get().runningWindows) { app = new App(appsWindows.get(appType)); if (app.window() != null) { app.focus(); aRegion.wait(0.5); win = app.window(); aRegion.click(win); // aRegion.write("#C.a#B."); return win; } else { app.open(); win = app.waitForWindow(); app.focus(); aRegion.wait(0.5); aRegion.click(win); return win; } } return null; } else if (Type.VIEWER.equals(appType)) { return null; } } catch (Exception ex) { } return null; } public Region waitForWindow() { return waitForWindow(5); } public Region waitForWindow(int seconds) { Region win = null; while ((win = window()) == null && seconds > 0) { aRegion.wait(0.5); seconds -= 0.5; } return win; } public static boolean openLink(String url) { if (!Desktop.isDesktopSupported()) { return false; } try { Desktop.getDesktop().browse(new URL(url).toURI()); } catch (Exception ex) { return false; } return true; } private static Region asRegion(Rectangle r) { if (r != null) { return Region.create(r); } else { return null; } } public static void pause(int time) { try { Thread.sleep(time * 1000); } catch (InterruptedException ex) { } } public static void pause(float time) { try { Thread.sleep((int) (time * 1000)); } catch (InterruptedException ex) { } } // // private static boolean shouldLog = false; private String appNameGiven = ""; private String appName = ""; private String appToken = ""; private String appExec = ""; private String appExecPath = ""; private String appWorkDir = ""; private String appOptions = ""; private String appWindow = ""; private int appPID = -1; private int maxWait = 10; public static void log(String msg, Object... args) { if (shouldLog) { Debug.logp("[AppLog] " + msg, args); } } public static void logOn() { shouldLog = true; } public static void logOff() { shouldLog = false; } public void reset() { appPID = -1; appWindow = ""; } public App() { if (_osUtil == null) { _osUtil = SysUtil.getOSUtil(); _osUtil.checkFeatureAvailability(); } } public App(String name) { this(); init(name); } private void init(String name) { if (name.isEmpty()) { return; } appNameGiven = name.trim(); String[] parts; //C:\Program Files\Mozilla Firefox\firefox.exe -- options parts = appNameGiven.split(" -- "); String possibleAppExec = ""; if (parts.length > 1) { appOptions = parts[1].trim(); possibleAppExec = parts[0].replace("\"", "").trim(); } else { if (appNameGiven.startsWith("\"")) { parts = appNameGiven.substring(1).split("\""); if (parts.length > 1) { appOptions = appNameGiven.substring(parts[0].length() + 2).trim(); possibleAppExec = parts[0]; } else { possibleAppExec = appNameGiven.replace("\"", ""); } } else { possibleAppExec = appNameGiven; } } File fExec = new File(possibleAppExec); if (fExec.isAbsolute()) { if (!fExec.exists()) { log("App: init: does not exist or not valid: %s", fExec); } else { appExec = fExec.getAbsolutePath(); appExecPath = fExec.getParent(); } } if (!appExec.isEmpty()) { appName = fExec.getName(); } else { if (RunTime.get().runningWindows || possibleAppExec.startsWith("?")) { appName = appNameGiven; setGivenAsWindowTitle(); if (appName.startsWith("?")) { appName = appName.substring(1); } } else if (!RunTime.get().runningWindows) { appExec = possibleAppExec; appName = possibleAppExec; } } log("App.create: %s", toString()); } @Override public String toString() { if (isWindow()) { return String.format("[%d:?%s (%s)] %s", appPID, appName, appWindow, appNameGiven); } else { return String.format("[%d:%s (%s)] %s %s", appPID, appName, appWindow, appExec, appOptions); } } public String toStringShort() { if (isWindow()) { return String.format("[%d:?%s]", appPID, appName); } else { return String.format("[%d:%s]", appPID, appName); } } // // public static List getApps() { new App(); return _osUtil.getApps(""); } public static List getApps(String name) { new App(); return _osUtil.getApps(name); } public static void listApps() { new App(); List appList = _osUtil.getApps(""); logOn(); log("***** all running apps"); for (App app : appList) { if (app.getPID() > 0) { log("%s", app); } } log("***** end of list (%d)", appList.size()); logOff(); } public static void listApps(String name) { new App(); List appList = _osUtil.getApps(name); logOn(); log("***** running apps matching: %s", name); for (App app : appList) { log("%s", app); } log("***** end of list (%d)", appList.size()); logOff(); } // // public String getToken() { return appToken; } public void setToken(String appToken) { this.appToken = appToken; } public App setUsing(String options) { if (options != null) { appOptions = options; } else { appOptions = ""; } return this; } public void setNameGiven(String nameGiven) { appNameGiven = nameGiven; } public String getNameGiven() { return appNameGiven; } public String getOptions() { return appOptions; } public String getName() { return appName; } public void setName(String name) { appName = name; } public String getExec() { return appExec; } public void setExec(String exec) { appExec = exec; } public String getTitle() { return getWindowTitle(); } public String getTitle(int windowNumber) { return getWindowTitle(); } public String getWindowTitle() { return appWindow == null ? "" : appWindow; } public void setWindow(String appWindow) { this.appWindow = appWindow; } public void setPID(int appPID) { this.appPID = appPID; } public void setPID(String appPID) { try { this.appPID = Integer.parseInt(appPID); } catch (NumberFormatException e) { reset(); } } public int getPID() { return appPID; } public boolean setWorkDir() { if (appExecPath.isEmpty()) { return false; } appWorkDir = appExecPath; return true; } public boolean setWorkDir(String workDirPath) { if (workDirPath == null || workDirPath.isEmpty()) { return false; } File fWorkDir = new File(workDirPath); if (!fWorkDir.isAbsolute() || !fWorkDir.isDirectory() || !fWorkDir.exists()) { return false; } appWorkDir = fWorkDir.getAbsolutePath(); return true; } public String getWorkDir() { return appWorkDir; } // // public boolean isValid() { return appPID > 0; } public boolean isRunning() { return isRunning(0); } public boolean isRunning(int maxTime) { _osUtil.get(this); if (maxTime == 0 && !isValid()) { return false; } while (!isValid() && maxTime > 0) { maxTime -= 1; pause(1); _osUtil.get(this); } return isValid(); } public boolean hasWindow() { if (!isValid()) { return false; } return !getWindowTitle().isEmpty(); } // // boolean isOpen = false; /** * tries to open an app using the given name and waits waitTime for being ready * If the app is already open, it is brought to foreground * * @param appName name - something that could be used on commandline to start the app * @param waitTime to wait for app to open (secs) * @return the App instance */ public static App open(String appName, int waitTime) { App app = new App(appName); app.openAndWait(waitTime); return app; } /** * tries to open an app using the given name and waits 1 sec for being ready * If the app is already open, it is brought to foreground * * @param appName name - something that could be used on commandline to start the app * @return the App instance */ public static App open(String appName) { return open(appName, 1); } /** * tries to open the app defined by this App instance
* do not wait for the app to get running * * @return this or null on failure */ public boolean open() { openAndWait(5); return isValid(); } /** * tries to open the app defined by this App instance
* and waits until app is running * * @param waitTime max waittime until running * @return this or null on failure */ public boolean open(int waitTime) { openAndWait(waitTime); return isValid() & hasWindow(); } private void openAndWait(int waitTime) { isOpen = false; if (!isRunning(0)) { boolean isOpen = _osUtil.open(this); if (isOpen) { if (!isRunning(waitTime)) { log("App.open: not running after %d secs (%s)", waitTime, appNameGiven); } else { log("App.open: %s", this); if (!focus()) { while (!hasWindow() && waitTime > 0) { waitTime -= 1; pause(1); focus(); } } } } else { log("App.open: %s: did not work - app not valid", appNameGiven); } } else { log("App.open: already running: %s", this); isOpen = true; focus(); } } //
// /** * tries to identify a running app with the given name and then tries to close it * * @param appName name * @return 0 for success -1 otherwise */ public static boolean close(String appName) { return new App(appName).close(); } public boolean isClosing() { return isClosing; } private boolean isClosing = false; /** * tries to close the app defined by this App instance, waits max 10 seconds for the app to no longer be running * * @return this or null on failure */ public boolean close() { return close(5); } /** * tries to close the app defined by this App instance, waits max given seconds for the app to no longer be running * * @param waitTime to wait for app to close (secs) * @return this or null on failure */ public boolean close(int waitTime) { if (!isRunning()) { log("App.close: not running: %s", this); return false; } boolean success = _osUtil.close(this); if (success) { isClosing = true; int timeTowait = maxWait; if (waitTime > 0) { timeTowait = waitTime; } while (isRunning(0) && timeTowait > 0) { pause(1); timeTowait--; } } isClosing = false; if (isValid() || !success) { log("App.close: did not work: %s", this); return false; } log("App.close: %s", this); reset(); return true; } public int closeByKey() { return closeByKey(0); } public int closeByKey(int waitTime) { if (!isRunning()) { log("App.closeByKey: not running: %s", this); return 1; } focus(); RunTime.pause(1); if (RunTime.get().runningWindows) { window().type(Key.F4, Key.ALT); } else if (RunTime.get().runningMac) { window().type("q", Key.CMD); } else { window().type("q", Key.CTRL); } int timeTowait = maxWait; if (waitTime > 0) { timeTowait = waitTime; } while (isRunning(0) && timeTowait > 0) { timeTowait--; } if (!isValid()) { log("App.closeByKey: %s", this); } else { log("App.closeByKey: did not work: %s", this); return 1; } return 0; } // // private boolean isFocused = false; public void setFocused(boolean state) { isFocused = state; } public boolean hasFocus() { return isFocused; } /** * tries to identify a running app with name or (part of) window title * bringing its topmost window to front * * @param title name * @return an App instance - is invalid and not useable if not found as running */ public static App focus(String title) { return focus(title, 0); } /** * tries to identify a running app with name or (part of) window title * bringing its window with given index to front * * @param index of the window among the found windows * @param title name * @return an App instance - is invalid and not useable if not found as running */ public static App focus(String title, int index) { App app = new App(title); app.focus(); return app; } /** * tries to make it the foreground application bringing its frontmost window to front * * @return the App instance */ public boolean focus() { isFocused = false; if (!isOpen && !isRunning(0)) { log("App.focus: not running: %s", toString()); return false; } isOpen = false; if (!_osUtil.switchto(this)) { log("App.focus: no window for %s", toString()); return false; } else { isFocused = true; if (isWindow()) { resetGivenAsWindowTitle(); } log("App.focus: %s", this); } return true; } // // /** * evaluates the region currently occupied by the topmost window of this App instance. The region might not be fully * visible, not visible at all or invalid with respect to the current monitor configuration (outside any screen) * * @return the region */ public Region window() { return window(0); } /** * evaluates the region currently occupied by the window with the given number of this App instance. The region might * not be fully visible, not visible at all or invalid with respect to the current monitor configuration (outside any * screen) * * @param winNum window * @return the region */ public Region window(int winNum) { Region windowRegion = null; Rectangle windowRect = _osUtil.getWindow(this, winNum); if (null != windowRect) { windowRegion = asRegion(windowRect); if (winNum == 0) { windowRegion.setName(getTitle()); } else { } } return windowRegion; } /** * evaluates the region currently occupied by the systemwide frontmost window (usually the one that has focus for * mouse and keyboard actions) * * @return the region */ public static Region focusedWindow() { new App(); return asRegion(_osUtil.getFocusedWindow()); } public List getWindows() { new App(); List regWindows = new ArrayList<>(); return _osUtil.getWindows(this); } // // public static int lastRunReturnCode = -1; public static String lastRunStdout = ""; public static String lastRunStderr = ""; public static String lastRunResult = ""; /** * the given text is parsed into a String[] suitable for issuing a Runtime.getRuntime().exec(args). quoting is * preserved/obeyed. the first item must be an executable valid for the running system.
* After completion, the following information is available:
* App.lastRunResult: a string containing the complete result according to the docs of the run() command
* App.lastRunStdout: a string containing only the output lines that went to stdout
* App.lastRunStderr: a string containing only the output lines that went to stderr
* App.lastRunReturnCode: the value, that is returnd as returncode * * @param cmd the command to run starting with an executable item * @return the final returncode of the command execution */ public static int run(String cmd) { lastRunResult = RunTime.get().runcmd(cmd); String NL = RunTime.get().runningWindows ? "\r\n" : "\n"; String[] res = lastRunResult.split(NL); try { lastRunReturnCode = Integer.parseInt(res[0].trim()); } catch (Exception ex) { } lastRunStdout = ""; lastRunStderr = ""; boolean isError = false; for (int n = 1; n < res.length; n++) { if (isError) { lastRunStderr += res[n] + NL; continue; } if (RunTime.get().runCmdError.equals(res[n])) { isError = true; continue; } lastRunStdout += res[n] + NL; } return lastRunReturnCode; } //
// /** * evaluates the current textual content of the system clipboard * * @return the textual content or empty string if not possible */ public static String getClipboard() { Transferable content = null; try { content = Clipboard.getSystemClipboard().getContents(null); } catch (Exception ex) { Debug.error("Env.getClipboard: %s", ex.getMessage()); } if (content != null) { try { if (content.isDataFlavorSupported(DataFlavor.stringFlavor)) { return (String) content.getTransferData(DataFlavor.stringFlavor); } } catch (UnsupportedFlavorException ex) { Debug.error("Env.getClipboard: UnsupportedFlavorException: " + content); } catch (IOException ex) { Debug.error("Env.getClipboard: %s", ex.getMessage()); } } return ""; } /** * sets the current textual content of the system clipboard to the given text * * @param text text */ public static void setClipboard(String text) { try { Clipboard.putText(Clipboard.PLAIN, Clipboard.UTF8, Clipboard.CHAR_BUFFER, text); } catch (Exception ex) { Debug.error("Env.setClipboard: %s", ex.getMessage()); } } private static class Clipboard { public static final TextType HTML = new TextType("text/html"); public static final TextType PLAIN = new TextType("text/plain"); public static final Charset UTF8 = new Charset("UTF-8"); public static final Charset UTF16 = new Charset("UTF-16"); public static final Charset UNICODE = new Charset("unicode"); public static final Charset US_ASCII = new Charset("US-ASCII"); public static final TransferType READER = new TransferType(Reader.class); public static final TransferType INPUT_STREAM = new TransferType(InputStream.class); public static final TransferType CHAR_BUFFER = new TransferType(CharBuffer.class); public static final TransferType BYTE_BUFFER = new TransferType(ByteBuffer.class); private static java.awt.datatransfer.Clipboard systemClipboard = null; private Clipboard() { } /** * Dumps a given text (either String or StringBuffer) into the Clipboard, with a default MIME type */ public static void putText(CharSequence data) throws Exception { StringSelection copy = new StringSelection(data.toString()); getSystemClipboard().setContents(copy, copy); } /** * Dumps a given text (either String or StringBuffer) into the Clipboard with a specified MIME type */ public static void putText(TextType type, Charset charset, TransferType transferType, CharSequence data) throws Exception { String mimeType = type + "; charset=" + charset + "; class=" + transferType; TextTransferable transferable = new TextTransferable(mimeType, data.toString()); getSystemClipboard().setContents(transferable, transferable); } public static java.awt.datatransfer.Clipboard getSystemClipboard() throws Exception { if (systemClipboard == null) { systemClipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); if (systemClipboard == null) { throw new Exception("Clipboard: Toolkit.getDefaultToolkit().getSystemClipboard() returns null"); } } return systemClipboard; } private static class TextTransferable implements Transferable, ClipboardOwner { private String data; private DataFlavor flavor; public TextTransferable(String mimeType, String data) { flavor = new DataFlavor(mimeType, "Text"); this.data = data; } @Override public DataFlavor[] getTransferDataFlavors() { return new DataFlavor[]{flavor, DataFlavor.stringFlavor}; } @Override public boolean isDataFlavorSupported(DataFlavor flavor) { boolean b = this.flavor.getPrimaryType().equals(flavor.getPrimaryType()); return b || flavor.equals(DataFlavor.stringFlavor); } @Override public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException { if (flavor.isRepresentationClassInputStream()) { return new StringReader(data); } else if (flavor.isRepresentationClassReader()) { return new StringReader(data); } else if (flavor.isRepresentationClassCharBuffer()) { return CharBuffer.wrap(data); } else if (flavor.isRepresentationClassByteBuffer()) { return ByteBuffer.wrap(data.getBytes()); } else if (flavor.equals(DataFlavor.stringFlavor)) { return data; } throw new UnsupportedFlavorException(flavor); } @Override public void lostOwnership(java.awt.datatransfer.Clipboard clipboard, Transferable contents) { } } /** * Enumeration for the text type property in MIME types */ public static class TextType { private String type; private TextType(String type) { this.type = type; } @Override public String toString() { return type; } } /** * Enumeration for the charset property in MIME types (UTF-8, UTF-16, etc.) */ public static class Charset { private String name; private Charset(String name) { this.name = name; } @Override public String toString() { return name; } } /** * Enumeration for the transferScriptt type property in MIME types (InputStream, CharBuffer, etc.) */ public static class TransferType { private Class dataClass; private TransferType(Class streamClass) { this.dataClass = streamClass; } public Class getDataClass() { return dataClass; } @Override public String toString() { return dataClass.getName(); } } } // }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy