From 724fae8e5dce3636c233b9cb8a48560f60e549b9 Mon Sep 17 00:00:00 2001 From: Rik Veenboer Date: Sun, 18 Oct 2015 15:52:12 +0100 Subject: [PATCH] Removed most except for core functionality code --- .settings/org.eclipse.jdt.core.prefs | 11 - README.md | 8 - build.xml | 90 -- ivy.xml | 12 - readme.txt | 35 - src/org/synthuse/Api.java | 802 ------------------ src/org/synthuse/CommandPopupMenu.java | 261 ------ src/org/synthuse/CommandProcessor.java | 318 ------- src/org/synthuse/Config.java | 138 --- src/org/synthuse/DragTarget.java | 167 ---- src/org/synthuse/KeyboardHook.java | 334 -------- src/org/synthuse/MenuInfo.java | 103 --- src/org/synthuse/MessageHookFrame.java | 290 ------- src/org/synthuse/MsgHook.java | 123 --- src/org/synthuse/PropertiesSerializer.java | 204 ----- src/org/synthuse/RobotMacro.java | 631 -------------- src/org/synthuse/StatusWindow.java | 72 -- src/org/synthuse/SynthuseConfigDialog.java | 45 - src/org/synthuse/SynthuseDlg.java | 579 ------------- src/org/synthuse/TestIdeFrame.java | 221 ----- src/org/synthuse/UiaBridge.java | 182 ---- src/org/synthuse/WinPtr.java | 70 -- src/org/synthuse/WindowInfo.java | 306 ------- src/org/synthuse/WindowsEnumeratedXml.java | 421 --------- src/org/synthuse/XmlEditorKit.java | 209 ----- src/org/synthuse/XpathManager.java | 292 ------- src/org/synthuse/commands/BaseCommand.java | 311 ------- src/org/synthuse/commands/FileCommands.java | 66 -- .../synthuse/commands/KeyboardCommands.java | 67 -- src/org/synthuse/commands/MainCommands.java | 247 ------ src/org/synthuse/commands/MouseCommands.java | 142 ---- .../synthuse/commands/WindowsCommands.java | 216 ----- .../SynthuseConfigDialogControllers.java | 121 --- .../synthuse/img/applications-education.png | Bin 1165 -> 0 bytes src/org/synthuse/img/arrow-right-3.png | Bin 951 -> 0 bytes .../synthuse/img/bullseye-logo-th18x18.png | Bin 610 -> 0 bytes .../synthuse/img/bullseye-logo-th32x32.png | Bin 333 -> 0 bytes src/org/synthuse/img/dialog-close.png | Bin 991 -> 0 bytes src/org/synthuse/img/document-close-2.png | Bin 1404 -> 0 bytes src/org/synthuse/img/document-new-5.png | Bin 1093 -> 0 bytes src/org/synthuse/img/document-open-folder.png | Bin 852 -> 0 bytes src/org/synthuse/img/document-save-6.png | Bin 1254 -> 0 bytes src/org/synthuse/img/edit-copy-7.png | Bin 1131 -> 0 bytes src/org/synthuse/img/edit-find-3.png | Bin 1035 -> 0 bytes src/org/synthuse/img/gnome-robots.png | Bin 1246 -> 0 bytes src/org/synthuse/img/help-3.png | Bin 1377 -> 0 bytes src/org/synthuse/img/preferences-desktop.png | Bin 825 -> 0 bytes src/org/synthuse/img/rapidsvn.png | Bin 1106 -> 0 bytes src/org/synthuse/img/run-rebuild-2.png | Bin 1198 -> 0 bytes src/org/synthuse/img/user-trash-2.png | Bin 1272 -> 0 bytes .../synthuse/test/CommandProcessorTest.java | 122 --- src/org/synthuse/test/Silverlight.js | 2 - .../synthuse/test/SilverlightMockTestApp.xap | Bin 145627 -> 0 bytes .../test/SilverlightMockTestAppTestPage.html | 73 -- src/org/synthuse/test/UnitTestHelper.java | 79 -- src/org/synthuse/test/WinApiTest.java | 161 ---- src/org/synthuse/test/WinFormsMockTestApp.exe | Bin 36352 -> 0 bytes src/org/synthuse/test/WpfMockTestApp.exe | Bin 54784 -> 0 bytes src/org/synthuse/test/WpfMockTestAppx64.exe | Bin 55296 -> 0 bytes .../synthuse/views/SynthuseConfigPanel.java | 225 ----- synthuse.properties | 12 - 61 files changed, 7768 deletions(-) delete mode 100644 .settings/org.eclipse.jdt.core.prefs delete mode 100644 README.md delete mode 100644 build.xml delete mode 100644 ivy.xml delete mode 100644 readme.txt delete mode 100644 src/org/synthuse/Api.java delete mode 100644 src/org/synthuse/CommandPopupMenu.java delete mode 100644 src/org/synthuse/CommandProcessor.java delete mode 100644 src/org/synthuse/Config.java delete mode 100644 src/org/synthuse/DragTarget.java delete mode 100644 src/org/synthuse/KeyboardHook.java delete mode 100644 src/org/synthuse/MenuInfo.java delete mode 100644 src/org/synthuse/MessageHookFrame.java delete mode 100644 src/org/synthuse/MsgHook.java delete mode 100644 src/org/synthuse/PropertiesSerializer.java delete mode 100644 src/org/synthuse/RobotMacro.java delete mode 100644 src/org/synthuse/StatusWindow.java delete mode 100755 src/org/synthuse/SynthuseConfigDialog.java delete mode 100644 src/org/synthuse/SynthuseDlg.java delete mode 100644 src/org/synthuse/TestIdeFrame.java delete mode 100644 src/org/synthuse/UiaBridge.java delete mode 100644 src/org/synthuse/WinPtr.java delete mode 100644 src/org/synthuse/WindowInfo.java delete mode 100644 src/org/synthuse/WindowsEnumeratedXml.java delete mode 100644 src/org/synthuse/XmlEditorKit.java delete mode 100644 src/org/synthuse/XpathManager.java delete mode 100644 src/org/synthuse/commands/BaseCommand.java delete mode 100644 src/org/synthuse/commands/FileCommands.java delete mode 100644 src/org/synthuse/commands/KeyboardCommands.java delete mode 100644 src/org/synthuse/commands/MainCommands.java delete mode 100644 src/org/synthuse/commands/MouseCommands.java delete mode 100644 src/org/synthuse/commands/WindowsCommands.java delete mode 100755 src/org/synthuse/controllers/SynthuseConfigDialogControllers.java delete mode 100644 src/org/synthuse/img/applications-education.png delete mode 100644 src/org/synthuse/img/arrow-right-3.png delete mode 100644 src/org/synthuse/img/bullseye-logo-th18x18.png delete mode 100644 src/org/synthuse/img/bullseye-logo-th32x32.png delete mode 100644 src/org/synthuse/img/dialog-close.png delete mode 100644 src/org/synthuse/img/document-close-2.png delete mode 100644 src/org/synthuse/img/document-new-5.png delete mode 100644 src/org/synthuse/img/document-open-folder.png delete mode 100644 src/org/synthuse/img/document-save-6.png delete mode 100644 src/org/synthuse/img/edit-copy-7.png delete mode 100644 src/org/synthuse/img/edit-find-3.png delete mode 100644 src/org/synthuse/img/gnome-robots.png delete mode 100644 src/org/synthuse/img/help-3.png delete mode 100644 src/org/synthuse/img/preferences-desktop.png delete mode 100644 src/org/synthuse/img/rapidsvn.png delete mode 100644 src/org/synthuse/img/run-rebuild-2.png delete mode 100644 src/org/synthuse/img/user-trash-2.png delete mode 100644 src/org/synthuse/test/CommandProcessorTest.java delete mode 100644 src/org/synthuse/test/Silverlight.js delete mode 100644 src/org/synthuse/test/SilverlightMockTestApp.xap delete mode 100644 src/org/synthuse/test/SilverlightMockTestAppTestPage.html delete mode 100644 src/org/synthuse/test/UnitTestHelper.java delete mode 100644 src/org/synthuse/test/WinApiTest.java delete mode 100644 src/org/synthuse/test/WinFormsMockTestApp.exe delete mode 100644 src/org/synthuse/test/WpfMockTestApp.exe delete mode 100644 src/org/synthuse/test/WpfMockTestAppx64.exe delete mode 100755 src/org/synthuse/views/SynthuseConfigPanel.java delete mode 100644 synthuse.properties diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs deleted file mode 100644 index 8000cd6..0000000 --- a/.settings/org.eclipse.jdt.core.prefs +++ /dev/null @@ -1,11 +0,0 @@ -eclipse.preferences.version=1 -org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 -org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve -org.eclipse.jdt.core.compiler.compliance=1.6 -org.eclipse.jdt.core.compiler.debug.lineNumber=generate -org.eclipse.jdt.core.compiler.debug.localVariable=generate -org.eclipse.jdt.core.compiler.debug.sourceFile=generate -org.eclipse.jdt.core.compiler.problem.assertIdentifier=error -org.eclipse.jdt.core.compiler.problem.enumIdentifier=error -org.eclipse.jdt.core.compiler.source=1.6 diff --git a/README.md b/README.md deleted file mode 100644 index 5cee0c9..0000000 --- a/README.md +++ /dev/null @@ -1,8 +0,0 @@ -synthuse-src -============ - -Synthuse (Synthetic-User) is a portable java base software testing framework for desktop windows applications. This framework has a built-in object spy and automation Test IDE. What makes this different from other frameworks is that it shares similar command syntax as Selenium. It also utilizes Xpath statements to locate target windows/objects The familiar syntax makes it easier to train automation tester in this frameworks. - -Synthuse can also be incorporated in to the fitnesse platform as a test fixture. - - Click here for Wiki and Screenshots \ No newline at end of file diff --git a/build.xml b/build.xml deleted file mode 100644 index 94e82ae..0000000 --- a/build.xml +++ /dev/null @@ -1,90 +0,0 @@ - - Simple build file for Synthuse - - - - - - - - - - - - - - - - - - - - basedir: ${basedir} - VM: ${java.vm.name} - VM Version: ${java.vm.specification.version} - VM Vendor: ${java.vm.vendor} - VM Build: ${java.vm.version} - Username: ${user.name} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/ivy.xml b/ivy.xml deleted file mode 100644 index 08b5ed1..0000000 --- a/ivy.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/readme.txt b/readme.txt deleted file mode 100644 index ca1069f..0000000 --- a/readme.txt +++ /dev/null @@ -1,35 +0,0 @@ -Synthuse - -Version 1.0.6 released on 2-17-2014 -By Edward Jakubowski ejakubowski7@gmail.com - -Description: - Synthuse is a portable java base software testing framework for desktop windows -applications. This framework has a built-in object spy and automation Test IDE. -What makes this different from other frameworks is that it shares similar command -syntax as Selenium. It also utilizes Xpath statements to locate target windows/objects -The familar syntaxes makes it easier to train automation tester in this frameworks. - - -Configurations: - All configurable settings are stored in the following file: synthuse.properties -Changes to this file will not take affect until you restart the application. -Example synthuse.properties file below: -urlList= -xpathList=//win[@class\='Notepad']\u00BA -xpathHightlight=.*process\="([^"]*)".* - - -Software Requirements: - - Java 1.6 or greater - - -Release Notes: - 4-8-2014 version 1.0.9 - - Added Support for automating WPF and Silverlight applications, this requires .Net 4.0 framework - - Added better mouse scripting support - 2-17-2014 version 1.0.6 - - fixed Test IDE window - 1-30-2014 version 1.0.5 - - Base version - diff --git a/src/org/synthuse/Api.java b/src/org/synthuse/Api.java deleted file mode 100644 index 85b08ef..0000000 --- a/src/org/synthuse/Api.java +++ /dev/null @@ -1,802 +0,0 @@ -/* - * Copyright 2014, Synthuse.org - * Released under the Apache Version 2.0 License. - * - * last modified by ejakubowski7@gmail.com -*/ - -package org.synthuse; - -import java.awt.Point; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import org.synthuse.Api.WinDefEx.*; -import com.sun.jna.Callback; -import com.sun.jna.Native; -import com.sun.jna.Pointer; -import com.sun.jna.Structure; -import com.sun.jna.platform.win32.WinDef.*; -import com.sun.jna.platform.win32.Advapi32Util; -import com.sun.jna.platform.win32.BaseTSD.LONG_PTR; -import com.sun.jna.platform.win32.BaseTSD.SIZE_T; -import com.sun.jna.platform.win32.BaseTSD.ULONG_PTR; -import com.sun.jna.platform.win32.WinBase.SYSTEM_INFO; -import com.sun.jna.platform.win32.WinNT.HANDLE; -import com.sun.jna.platform.win32.WinReg; -import com.sun.jna.platform.win32.WinUser; -import com.sun.jna.platform.win32.WinNT.LARGE_INTEGER; -import com.sun.jna.platform.win32.WinUser.WNDENUMPROC; -import com.sun.jna.ptr.IntByReference; -import com.sun.jna.ptr.PointerByReference; -import com.sun.jna.win32.StdCallLibrary.StdCallCallback; -import com.sun.jna.win32.W32APIOptions; - -public class Api { - - // Constants - - public static int WM_SETTEXT = 0x000c; - public static int WM_GETTEXT = 0x000D; - public static int WM_GETTEXTLENGTH = 0x000E; - public static int WM_MOUSEMOVE = 0x200; - public static int WM_LBUTTONDOWN = 0x0201; - public static int WM_LBUTTONUP = 0x0202; - public static int WM_LBUTTONDBLCLK = 0x203; - public static int WM_RBUTTONDOWN = 0x0204; - public static int WM_RBUTTONUP = 0x0205; - public static int WM_RBUTTONDBLCLK = 0x206; - public static int WM_MBUTTONDOWN = 0x207; - public static int WM_MBUTTONUP = 0x208; - public static int WM_MBUTTONDBLCLK = 0x209; - public static int WM_MOUSEWHEEL = 0x20A; - public static int WM_MOUSEHWHEEL = 0x20E; - public static int WM_MOUSEHOVER = 0x2A1; - public static int WM_NCMOUSELEAVE = 0x2A2; - public static int WM_MOUSELEAVE = 0x2A3; - - public static int WM_CLOSE = 0x10; - public static int WM_DESTROY = 0x0002; - public static int WM_NCDESTROY = 0x0082; - public static int WM_QUIT = 0x12; - - public static int WM_SETFOCUS = 0x0007; - public static int WM_NEXTDLGCTL = 0x0028; - public static int WM_ENABLE = 0x000A; - public static int WM_KEYFIRST = 0x100; - public static int WM_KEYDOWN = 0x100; - public static int WM_KEYUP = 0x101; - public static int WM_CHAR = 0x102; - public static int WM_DEADCHAR = 0x103; - public static int WM_SYSKEYDOWN = 0x104; - public static int WM_SYSKEYUP = 0x105; - public static int WM_SYSCHAR = 0x106; - - public static int WM_CUT = 0x300; - public static int WM_COPY = 0x301; - public static int WM_PASTE = 0x302; - public static int WM_CLEAR = 0x303; - public static int WM_UNDO = 0x304; - - - public static int PROCESS_QUERY_INFORMATION = 0x0400; - public static int PROCESS_VM_READ = 0x0010; - public static int PROCESS_VM_WRITE = 0x0020; - public static int PROCESS_VM_OPERATION = 0x0008; - - public static int PS_SOLID = 0x0; - public static int PS_DASH = 0x1; - public static int PS_DOT = 0x2; - public static int PS_DASHDOT = 0x3; - public static int PS_DASHDOTDOT = 0x4; - public static int PS_NULL = 0x5; - public static int PS_INSIDEFRAME = 0x6; - - public static int HOLLOW_BRUSH = 0x5; - - public static int WM_PAINT = 0x0F; - public static int WM_SETREDRAW = 0x0B; - public static int WM_ERASEBKGND = 0x14; - - public static int RDW_FRAME = 0x0400; - public static int RDW_INVALIDATE = 0x0001; - public static int RDW_UPDATENOW = 0x0100; - public static int RDW_ALLCHILDREN = 0x0080; - - public static int TB_GETBUTTONTEXTA = (0x0400 + 45); - public static int TB_GETBUTTONTEXTW = (0x0400 + 75); - public static int TB_GETRECT = (0x0400 + 51); - public static int TB_GETTOOLTIPS = (0x0400 + 35); - public static int TB_BUTTONCOUNT = 0x0418; - - public static int LVM_FIRST = 0x1000; - public static int LVM_GETITEMCOUNT = LVM_FIRST + 4; - public static int LVM_GETITEM = LVM_FIRST + 75; - public static int LVIF_TEXT = 0x0001; - public static int LVM_GETSELECTEDCOUNT = (LVM_FIRST + 50); - public static int LVM_SETITEMSTATE = (LVM_FIRST + 43); - public static int LVM_GETITEMSTATE = (LVM_FIRST + 44); - public static int LVIS_SELECTED = 0x0002; - public static int LVIS_FOCUSED = 0x0001; - - public static int LB_GETCOUNT = 0x18B; - public static int LB_GETCURSEL = 0x0188; - public static int LB_SETCURSEL = 0x0186; - public static int LB_GETTEXT = 0x0189; - public static int LB_GETTEXTLEN = 0x018A; - public static int LB_SELECTSTRING = 396; - - public static int CB_GETCOUNT = 0x146; - - public static int TV_FIRST = 0x1100; - public static int TVM_GETCOUNT = TV_FIRST + 5; - - public static int VK_SHIFT = 16; - public static int VK_LSHIFT = 0xA0; - public static int VK_RSHIFT = 0xA1; - public static int VK_CONTROL = 17; - public static int VK_LCONTROL = 0xA2; - public static int VK_RCONTROL = 0xA3; - public static int VK_MENU = 18; - public static int VK_LMENU = 0xA4; - public static int VK_RMENU = 0xA5; - - public static int WM_COMMAND = 0x111; - public static int MN_GETHMENU = 0x01E1; - - public static int CWP_ALL = 0x0000; // Does not skip any child windows - - public static int PAGE_READWRITE = 0x04; - - public static int MEM_COMMIT = 0x1000; - public static int MEM_RESERVE = 0x2000; - public static int MEM_RELEASE = 0x8000; - public static int MEM_FREE = 0x10000; - public static int MEM_DECOMMIT = 0x4000; - - public User32Ex user32; - public PsapiEx psapi; - public Kernel32Ex kernel32; - - public static final int POINT_Y(long i) - { - return (int) (i >> 32); - } - - public static final int POINT_X(long i) - { - return (int) (i & 0xFFFF); - } - - public static long MAKELONG(int low, int high) - { - return ((long)(((short)((int)(low) & 0xffff)) | ((int)((short)((int)(high) & 0xffff))) << 16)); - } - - public interface WinDefEx extends com.sun.jna.platform.win32.WinDef { - //Structures - public class MENUITEMINFO extends Structure { - public static final int MFS_CHECKED = 0x00000008; - public static final int MFS_DEFAULT = 0x00001000; - public static final int MFS_DISABLED = 0x00000003; - public static final int MFS_ENABLED = 0x00000000; - public static final int MFS_GRAYED = 0x00000003; - public static final int MFS_HILITE = 0x00000080; - public static final int MFS_UNCHECKED = 0x00000000; - public static final int MFS_UNHILITE = 0x00000000; - public static final int MFT_STRING = 0x0000; - public static final int MIIM_DATA = 0x00000020; - public static final int MIIM_STRING = 0x0040; - public static final int MIIM_SUBMENU = 0x0004; - public static final int MIIM_TYPE = 0x0010; - - public static class ByValue extends MENUITEMINFO implements Structure.ByValue { - } - - public static class ByReference extends MENUITEMINFO implements Structure.ByReference { - } - - public MENUITEMINFO() { - cbSize = size(); - } - - public MENUITEMINFO(Pointer p) { - super(p); - } - - @Override - protected List getFieldOrder() { - return Arrays.asList(new String[] { "cbSize", "fMask", "fType", "fState", "wID", "hSubMenu", "hbmpChecked", - "hbmpUnchecked", "dwItemData", "dwTypeData", "cch", "hbmpItem" }); - } - - public int cbSize; //The size of the structure, in bytes. The caller must set this member to sizeof(MENUITEMINFO). - public int fMask; //Indicates the members to be retrieved or set. MIIM_STRING or MIIM_SUBMENU or ... - public int fType; //The menu item type. fType is used only if fMask has a value of MIIM_FTYPE. - public int fState; //The menu item state. This member can be one or more of these values. Set fMask to MIIM_STATE to use fState. - public int wID; //An application-defined value that identifies the menu item. Set fMask to MIIM_ID to use wID. - public HMENU hSubMenu; //A handle to the drop-down menu or submenu associated with the menu item. Or NULL - public HBITMAP hbmpChecked; //A handle to the bitmap to display next to the item if it is selected. - public HBITMAP hbmpUnchecked; //A handle to the bitmap to display next to the item if it is not selected. - public ULONG_PTR dwItemData; //An application-defined value associated with the menu item. Set fMask to MIIM_DATA - //public byte[] dwTypeData = new byte[256]; - public String dwTypeData; //The contents of the menu item, depends on the value of fType and is used only if the MIIM_TYPE flag is set in the fMask member - public int cch; //The length of the menu item text, in characters, when information is received about a menu item of the MFT_STRING type. - public HBITMAP hbmpItem; //A handle to the bitmap to be displayed, or it can be one of the values in the following table. - } - - - //64bit LVITEM size 88 - //32bit LVITEM size 60 - public static class LVITEM_VISTA extends Structure { - public int mask; - public int iItem; - public int iSubItem; - public int state; - public int stateMask; - public Pointer pszText; - public int cchTextMax; - public int iImage; - public LPARAM lParam; - public int iIndent; - public int iGoupId; - public int cColumns; - public Pointer puColumns; - //NTDDI_VERSION >= NTDDI_VISTA - public Pointer piColFmt; - public int iGroup; - @Override - protected List getFieldOrder() { - return Arrays.asList(new String[] { - "mask", "iItem", "iSubItem", "state", "stateMask", "pszText", "cchTextMax", "iImage", "lParam", "iIndent", "iGoupId", "cColumns", "puColumns", "piColFmt", "iGroup" }); - } - } - - - - public static class COPYDATASTRUCT extends Structure { - //The by-reference version of this structure. - public static class ByReference extends COPYDATASTRUCT implements Structure.ByReference { } - - public COPYDATASTRUCT() { } - - //Instantiates a new COPYDATASTRUCT with existing data given the address of that data. - public COPYDATASTRUCT(final long pointer) { - this(new Pointer(pointer)); - } - - //Instantiates a new COPYDATASTRUCT with existing data given a pointer to that data. - public COPYDATASTRUCT(final Pointer memory) { - super(memory); - read(); - } - - public ULONG_PTR dwData; // The data to be passed to the receiving application. - public int cbData; //The size, in bytes, of the data pointed to by the lpData - public Pointer lpData; - - @SuppressWarnings("rawtypes") - @Override - protected final List getFieldOrder() { - return Arrays.asList(new String[] {"dwData", "cbData", "lpData" }); - } - } - } - - interface WNDPROC extends StdCallCallback { - - LRESULT callback(HWND hWnd, int uMsg, WPARAM uParam, LPARAM lParam); - - } - - public interface User32Ex extends W32APIOptions { - User32Ex instance = (User32Ex) Native.loadLibrary("user32", User32Ex.class, DEFAULT_OPTIONS); - - int SetWindowLongPtr(HWND hWnd, int nIndex, Callback callback); - LRESULT CallWindowProc(LONG_PTR proc, HWND hWnd, int uMsg, WPARAM uParam, LPARAM lParam); - - boolean ShowWindow(HWND hWnd, int nCmdShow); - boolean SetForegroundWindow(HWND hWnd); - void SwitchToThisWindow(HWND hWnd, boolean fAltTab); - HWND SetFocus(HWND hWnd); - - HWND FindWindow(String winClass, String title); - LRESULT PostMessage(HWND hWnd, int Msg, WPARAM wParam, LPARAM lParam); - LRESULT SendMessage(HWND hWnd, int Msg, WPARAM wParam, LPARAM lParam); - LRESULT SendMessage(HWND hWnd, int Msg, WPARAM wParam, LVITEM_VISTA lParam); - LRESULT SendMessageA(HWND editHwnd, int wmGettext, long l, byte[] lParamStr); - boolean DestroyWindow(HWND hWnd); - - boolean EnumWindows (WNDENUMPROC wndenumproc, int lParam); - boolean EnumChildWindows(HWND hWnd, WNDENUMPROC lpEnumFunc, Pointer data); - HWND GetParent(HWND hWnd); - boolean IsWindowVisible(HWND hWnd); - boolean IsWindow(HWND hWnd); - - int GetWindowRect(HWND hWnd, RECT r); - int MapWindowPoints(HWND hWndFrom, HWND hWndTo, RECT r, int cPoints); - HWND GetDesktopWindow(); - HDC GetWindowDC(HWND hWnd); - int ReleaseDC(HWND hWnd, HDC hDC); - boolean InvalidateRect(HWND hWnd, long lpRect, boolean bErase); - boolean UpdateWindow(HWND hWnd); - boolean RedrawWindow(HWND hWnd, long lprcUpdate, long hrgnUpdate, int flags); - - void GetWindowTextA(HWND hWnd, byte[] buffer, int buflen); - int GetTopWindow(HWND hWnd); - int GetWindow(HWND hWnd, int flag); - final int GW_HWNDNEXT = 2; - int GetClassName(HWND hWnd, char[] buffer2, int i); - int GetWindowModuleFileName(HWND hWnd, char[] buffer2, int i); - int GetWindowThreadProcessId(HWND hWnd, PointerByReference pref); - //int GetWindowThreadProcessId(HWND hWnd, IntByReference lpdwProcessId); - - - boolean GetCursorPos(long[] lpPoint); //use macros POINT_X() and POINT_Y() on long lpPoint[0] - - HWND WindowFromPoint(long point); - HWND ChildWindowFromPointEx(HWND hwndParent, long point, int uFlags); - boolean ClientToScreen(HWND hWnd, long[] lpPoint);//use macros POINT_X() and POINT_Y() on long lpPoint[0] - boolean ScreenToClient(HWND hWnd, long[] lpPoint);//use macros POINT_X() and POINT_Y() on long lpPoint[0] - //HWND WindowFromPoint(int xPoint, int yPoint); - //HWND WindowFromPoint(POINT point); - - HMENU GetMenu(HWND hWnd); - HMENU GetSystemMenu(HWND hWnd, boolean bRevert); - boolean IsMenu(HMENU hMenu); - int GetMenuString(HMENU hMenu, int uIDItem, char[] buffer, int nMaxCount, int uFlag); - HMENU GetSubMenu(HMENU hMenu, int nPos); - int GetMenuItemCount(HMENU hMenu); - int GetMenuItemID(HMENU hMenu, int nPos); - //BOOL WINAPI GetMenuItemInfo(_In_ HMENU hMenu, _In_ UINT uItem, _In_ BOOL fByPosition, _Inout_ LPMENUITEMINFO lpmii); - boolean GetMenuItemInfoA(HMENU hMenu, int uItem, boolean fByPosition, WinDefEx.MENUITEMINFO mii); //MENUITEMINFO - boolean TrackPopupMenu(HMENU hMenu, int uFlags, int x, int y, int nReserved, HWND hWnd, long prcRect); - boolean GetMenuItemRect(HWND hWnd, HMENU hMenu, int uItem, RECT rect); - - int GetDlgCtrlID(HWND hwndCtl); - int GetDlgItemText(HWND hDlg, int nIDDlgItem, byte[] buffer, int nMaxCount); - } - - public interface Gdi32Ex extends W32APIOptions { - Gdi32Ex instance = (Gdi32Ex) Native.loadLibrary("gdi32", Gdi32Ex.class, DEFAULT_OPTIONS); - HANDLE SelectObject(HDC hdc, HANDLE hgdiobj); - HANDLE GetStockObject(int fnObject); - boolean Rectangle(HDC hdc, int nLeftRect, int nTopRect, int nRightRect, int nBottomRect); - HPEN CreatePen(int fnPenStyle, int nWidth, int crColor); - } - - public interface PsapiEx extends W32APIOptions { - PsapiEx instance = (PsapiEx) Native.loadLibrary("psapi", PsapiEx.class, DEFAULT_OPTIONS); - int GetModuleBaseNameW(Pointer hProcess, Pointer hmodule, char[] lpBaseName, int size); - } - - public interface Kernel32Ex extends W32APIOptions { - Kernel32Ex instance = (Kernel32Ex) Native.loadLibrary("kernel32", Kernel32Ex.class, DEFAULT_OPTIONS); - boolean GetDiskFreeSpaceEx(String lpDirectoryName, LARGE_INTEGER.ByReference lpFreeBytesAvailable, LARGE_INTEGER.ByReference lpTotalNumberOfBytes, LARGE_INTEGER.ByReference lpTotalNumberOfFreeBytes); - int GetLastError(); - Pointer OpenProcess(int dwDesiredAccess, boolean bInheritHandle, Pointer pointer); - //int OpenProcess(int dwDesiredAccess, boolean bInheritHandle, Pointer pointer); - boolean CloseHandle(HANDLE hObject); - void GetNativeSystemInfo(SYSTEM_INFO lpSystemInfo); - boolean IsWow64Process(HANDLE hProcess, IntByReference Wow64Process); - //LPVOID VirtualAllocEx(HANDLE hProcess, LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect); - - //int VirtualAllocEx(HANDLE hProcess, int lpAddress, int dwSize, DWORD flAllocationType, DWORD flProtect); - IntByReference VirtualAllocEx(HANDLE hProc, IntByReference addr, SIZE_T size, int allocType, int prot); - Pointer VirtualAllocEx(HANDLE hProc, int i, int lngMemLen2, int allocType, int pAGE_READWRITE); - boolean VirtualFreeEx(HANDLE hProcess, IntByReference lpAddress, SIZE_T dwSize, DWORD dwFreeType); - boolean WriteProcessMemory(HANDLE hProcess, IntByReference lpBaseAddress, Pointer lpBuffer, int len, IntByReference bytesWritten); - - //boolean WriteProcessMemory(Pointer p, long address, Pointer buffer, int size, IntByReference written); - boolean ReadProcessMemory(Pointer hProcess, long inBaseAddress, Pointer outputBuffer, int nSize, IntByReference outNumberOfBytesRead); - int WriteProcessMemory(HANDLE handle, Pointer lngMemVar2, LVITEM_VISTA lvi, - int lngMemLen2, IntByReference byteIO); - int ReadProcessMemory(HANDLE handle, Pointer lngMemVar1, - Pointer lngVarPtr1, int lngMemLen1, IntByReference byteIO); - int VirtualFreeEx(HANDLE hProcess, Pointer lngMemVar1, int i, - int mEM_RELEASE); - } - - - public Api() { - user32 = User32Ex.instance; - psapi = PsapiEx.instance; - kernel32 = Kernel32Ex.instance; - } - - public static Long GetHandleAsLong(HWND hWnd) { - if (hWnd == null) - return (long)0; - //String longHexStr = hWnd.toString().substring("native@".length()); - String longHexStr = hWnd.getPointer().toString().substring("native@".length()); - return Long.decode(longHexStr); - } - - public static String GetHandleAsString(HWND hWnd) { - return GetHandleAsLong(hWnd).toString(); - } - - public static HWND GetHandleFromString(String hWnd) { - if (hWnd == null) - return null; - if (hWnd.isEmpty()) - return null; - String cleanNumericHandle = hWnd.replaceAll("[^\\d.]", ""); - try { - return (new HWND(new Pointer(Long.parseLong(cleanNumericHandle)))); - } catch (Exception e) { - e.printStackTrace(); - } - return null; - } - - public static String getWindowClassName(HWND hWnd) { - char[] buffer = new char[1026]; - User32Ex.instance.GetClassName(hWnd, buffer, 1026); - return Native.toString(buffer); - } - - public static String getWindowText(HWND hWnd) { - String text = ""; - byte[] buffer = new byte[1024]; - User32Ex.instance.GetWindowTextA(hWnd, buffer, buffer.length); - text = Native.toString(buffer); - if (text.isEmpty()) - text = new Api().sendWmGetText(hWnd); - return text; - } - - public static Point getCursorPos() { - - long[] getPos = new long [1]; - User32Ex.instance.GetCursorPos(getPos); - return new Point(POINT_X(getPos[0]), POINT_Y(getPos[0])); - } - - public static HWND getWindowFromCursorPos() { - - long[] getPos = new long [1]; - User32Ex.instance.GetCursorPos(getPos); - HWND hwnd = User32Ex.instance.WindowFromPoint(getPos[0]); - HWND childHwnd = getHiddenChildWindowFromPoint(hwnd, getPos[0]); - hwnd = childHwnd; - //System.out.println(getPos[0] + "," + getPos[1] + " int: " + x + ", " + y); - //System.out.println("child: " + GetHandleAsString(childHwnd) + " " + POINT_X(getPos[0]) +", " + POINT_Y(getPos[0])); - return hwnd; - } - - public static HWND getHiddenChildWindowFromPoint(HWND inHwnd, long point) - { - //int x = POINT_X(point);int y = POINT_Y(point); - - long[] getPos = new long [1]; - getPos[0] = point; - //if (!User32.instance.ClientToScreen(inHwnd, getPos)) return lHWND; - //x = POINT_X(getPos[0]);y = POINT_Y(getPos[0]); - //System.out.println("ClientToScreen " + GetHandleAsString(inHwnd) + ", " + x + ", " + y); - - if (!User32Ex.instance.ScreenToClient(inHwnd, getPos)) return inHwnd; // if point is not correct use original hwnd. - //x = POINT_X(getPos[0]);y = POINT_Y(getPos[0]); - //System.out.println("ScreenToClient " + GetHandleAsString(inHwnd) + ", " + x + ", " + y); - - HWND childHwnd = User32Ex.instance.ChildWindowFromPointEx(inHwnd, getPos[0], CWP_ALL); - //System.out.println("ChildWindowFromPointEx2 " + GetHandleAsString(inHwnd) + ", " + x + ", " + y + " = " + GetHandleAsString(childHwnd)); - - if (childHwnd == null) // if childHwnd is not correct use original hwnd. - return inHwnd; - - return childHwnd; - } - - public HWND findWindowByTitle(String title) { - HWND handle = user32.FindWindow(null, title); - return handle; - } - - public boolean activateWindow(HWND handle) { - boolean result = user32.SetForegroundWindow(handle); - user32.SetFocus(handle); - return result; - } - - public void SetDialogFocus(HWND hdlg, HWND hwndControl) { - WPARAM wp = new WPARAM(hwndControl.getPointer().getLong(0)); - LPARAM lp = new LPARAM(1); - user32.SendMessage(hdlg, WM_NEXTDLGCTL, wp, lp); - } - - public boolean showWindow(HWND handle) { - return user32.ShowWindow(handle, WinUser.SW_SHOW); - } - - public boolean hideWindow(HWND handle) { - return user32.ShowWindow(handle, WinUser.SW_HIDE); - } - - public boolean minimizeWindow(HWND handle) { - return user32.ShowWindow(handle, WinUser.SW_MINIMIZE); - } - - public boolean maximizeWindow(HWND handle) { - return user32.ShowWindow(handle, WinUser.SW_MAXIMIZE); - } - - public boolean restoreWindow(HWND handle) { - return user32.ShowWindow(handle, WinUser.SW_RESTORE); - } - - public boolean closeWindow(HWND handle) { - //return user32.DestroyWindow(handle); - //user32.SendMessage(handle, WM_CLOSE , null, null); - user32.PostMessage(handle, WM_CLOSE , null, null); - //user32.SendMessage(handle, WM_NCDESTROY , null, null); - return true; - } - - public void switchToThisWindow(HWND handle, boolean fAltTab) { - user32.SwitchToThisWindow(handle, fAltTab); - } - - public String sendWmGetText(HWND handle) { - int bufSize = 8192; - byte[] lParamStr = new byte[bufSize]; - user32.SendMessageA(handle, WM_GETTEXT, bufSize, lParamStr); - return (Native.toString(lParamStr)); - } - - public void sendWmSetText(HWND handle, String text) { - user32.SendMessageA(handle, WM_SETTEXT, 0, Native.toByteArray(text)); - } - - public void sendClick(HWND handle) { - user32.SendMessageA(handle, WM_LBUTTONDOWN, 0, null); - user32.SendMessageA(handle, WM_LBUTTONUP, 0, null); - } - - public void sendDoubleClick(HWND handle) { - user32.SendMessageA(handle, WM_LBUTTONDBLCLK, 0, null); - //user32.SendMessageA(handle, WM_LBUTTONUP, 0, null); - } - - public void sendRightClick(HWND handle) { - user32.SendMessageA(handle, WM_RBUTTONDOWN, 0, null); - user32.SendMessageA(handle, WM_RBUTTONUP, 0, null); - } - - public void sendKeyDown(HWND handle, int keyCode) { - user32.SendMessageA(handle, WM_KEYDOWN, keyCode, null); - //user32.SendMessageA(handle, WM_KEYUP, keyCode, null); - } - - public void sendKeyUp(HWND handle, int keyCode) { - //user32.SendMessageA(handle, WM_KEYDOWN, keyCode, null); - user32.SendMessageA(handle, WM_KEYUP, keyCode, null); - } - - public String GetMenuItemText(HMENU hmenu, int position) { - if (user32.IsMenu(hmenu) == false) - return ""; - char[] buffer = new char[256]; - user32.GetMenuString(hmenu, position, buffer, 256, 0x0400); - return Native.toString(buffer); - /* - Api.WinDefExt.MENUITEMINFO mii = new Api.WinDefExt.MENUITEMINFO(); // = (MENUITEMINFO)Api.MENUITEMINFO.newInstance(Api.MENUITEMINFO.class); - mii.fMask = Api.WinDefExt.MENUITEMINFO.MIIM_TYPE; - mii.fType = Api.WinDefExt.MENUITEMINFO.MFT_STRING; - mii.cch = 0; - mii.dwTypeData = ""; - @SuppressWarnings("unused") - boolean result = Api.User32.instance.GetMenuItemInfoA(hmenu, position, true, mii); - //System.out.println(position + " GetMenuItemInfo (" + result + ") : " + mii.cch + " " + mii.dwTypeData); - mii.fMask = Api.WinDefExt.MENUITEMINFO.MIIM_TYPE; - mii.fType = Api.WinDefExt.MENUITEMINFO.MFT_STRING; - mii.cch += 1; - mii.dwTypeData = "";//new String(new char[mii.cch]).replace("\0", " "); //buffer string with spaces - result = Api.User32.instance.GetMenuItemInfoA(hmenu, position, true, mii); - //System.out.println(position + " GetMenuItemInfo2 (" + result + ") Text: " + mii.dwTypeData + " " + mii.cch + " " + mii.wID); - //System.out.println("last error: " + Api.Kernel32.instance.GetLastError()); - return mii.dwTypeData; - */ - } - - public Point getWindowPosition(HWND handle) { - Point windowPoint = new Point(); - RECT rect = new RECT(); - user32.GetWindowRect(handle, rect); - //System.out.println("rect: l" + rect.left + ",t" + rect.top + ",r" + rect.right + ",b" + rect.bottom); - //user32.MapWindowPoints(user32.GetDesktopWindow(), user32.GetParent(handle), rect, 2); - windowPoint.x = ((rect.right - rect.left) / 2) + rect.left; - windowPoint.y = ((rect.bottom - rect.top) / 2) + rect.top; - return windowPoint; - } - - public Point getMenuItemPosition(HWND handle, HMENU hMenu, int pos) { - Point windowPoint = new Point(); - RECT rect = new RECT(); - user32.GetMenuItemRect(handle, hMenu, pos, rect); - //System.out.println("rect: l" + rect.left + ",t" + rect.top + ",r" + rect.right + ",b" + rect.bottom); - //user32.MapWindowPoints(user32.GetDesktopWindow(), user32.GetParent(handle), rect, 2); - windowPoint.x = ((rect.right - rect.left) / 2) + rect.left; - windowPoint.y = ((rect.bottom - rect.top) / 2) + rect.top; - return windowPoint; - } - - public int getDiskUsedPercentage() { - return getDiskUsedPercentage(null); - } - - public int getDiskUsedPercentage(String target) { - LARGE_INTEGER.ByReference lpFreeBytesAvailable = new LARGE_INTEGER.ByReference(); - LARGE_INTEGER.ByReference lpTotalNumberOfBytes = new LARGE_INTEGER.ByReference(); - LARGE_INTEGER.ByReference lpTotalNumberOfFreeBytes = new LARGE_INTEGER.ByReference(); - Kernel32Ex.instance.GetDiskFreeSpaceEx(target, lpFreeBytesAvailable, lpTotalNumberOfBytes, lpTotalNumberOfFreeBytes); - double freeBytes = lpTotalNumberOfFreeBytes.getValue(); - double totalBytes = lpTotalNumberOfBytes.getValue(); - //System.out.println("freespace " + humanReadableByteCount(freeBytes) + "/ totalspace " + humanReadableByteCount(totalBytes)); - return (int)(((totalBytes-freeBytes)/totalBytes) * 100.0); - } - - public static String humanReadableByteCount(double bytes) { - boolean si = true; - int unit = si ? 1000 : 1024; - if (bytes < unit) return bytes + " B"; - int exp = (int) (Math.log(bytes) / Math.log(unit)); - String pre = (si ? "kMGTPE" : "KMGTPE").charAt(exp-1) + (si ? "" : "i"); - return String.format("%.1f %sB", bytes / Math.pow(unit, exp), pre); - } - - public static void highlightWindow(HWND hwnd){ - RECT rect = new RECT(); - User32Ex.instance.GetWindowRect(hwnd, rect); - //System.out.println("RECT: " + rect.left + "," + rect.top + "," + (rect.right - rect.left) + "," + (rect.bottom - rect.top)); - highlightWindow(hwnd, 0, 0, rect.right - rect.left, rect.bottom - rect.top); - } - - // creates highlight around selected window - public static void highlightWindow(HWND hwnd, int x, int y, int x2, int y2){ - //COLORREF i.e. 0x00804070 Red = 0x70 green = 0x40 blue = 0x80 - //g_hRectanglePen = CreatePen (PS_SOLID, 3, RGB(256, 0, 0)); - HPEN rectPen = Gdi32Ex.instance.CreatePen(PS_SOLID, 3, 0x00000099); //RGB(255, 0, 0) - HDC dc = User32Ex.instance.GetWindowDC(hwnd); - if (dc != null) { - // Select our created pen into the DC and backup the previous pen. - HANDLE prevPen = Gdi32Ex.instance.SelectObject(dc, rectPen); - - // Select a transparent brush into the DC and backup the previous brush. - HANDLE prevBrush = Gdi32Ex.instance.SelectObject(dc, Gdi32Ex.instance.GetStockObject(HOLLOW_BRUSH)); - - // Draw a rectangle in the DC covering the entire window area of the found window. - Gdi32Ex.instance.Rectangle (dc, x, y, x2, y2); - - // Reinsert the previous pen and brush into the found window's DC. - Gdi32Ex.instance.SelectObject(dc, prevPen); - Gdi32Ex.instance.SelectObject(dc, prevBrush); - - // Finally release the DC. - User32Ex.instance.ReleaseDC(hwnd, dc); - } - } - - public static void refreshWindow(HWND hwnd) { - User32Ex.instance.InvalidateRect(hwnd, 0, true); - User32Ex.instance.UpdateWindow(hwnd); - User32Ex.instance.RedrawWindow(hwnd, 0, 0, RDW_FRAME | RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN); - } - - public static boolean isDotNet4Installed() { - try { - int installed = Advapi32Util.registryGetIntValue(WinReg.HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\NET Framework Setup\\NDP\\v4.0\\Client", "Install"); - //System.out.println("isDotNet4Installed: " + installed); - return (installed == 1); - } catch (Exception e) { - } - try { - int installed = Advapi32Util.registryGetIntValue(WinReg.HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\NET Framework Setup\\NDP\\v4\\Client", "Install"); - //System.out.println("isDotNet4Installed: " + installed); - return (installed == 1); - } catch (Exception e) { - } - return false; - } - - public static boolean isProcess64bit(int pid) - { - try { - SYSTEM_INFO lpSystemInfo = new SYSTEM_INFO(); - Kernel32Ex.instance.GetNativeSystemInfo(lpSystemInfo); - if (lpSystemInfo.processorArchitecture.dwOemID.intValue() == 0) - { - System.out.println("intel x86"); //not a 64 bit os - return false; - } - - Pointer process = Kernel32Ex.instance.OpenProcess(Api.PROCESS_QUERY_INFORMATION | Api.PROCESS_VM_READ, false, new Pointer(pid)); - IntByReference isWow64 = new IntByReference(0); - if (!Kernel32Ex.instance.IsWow64Process(new HANDLE(process), isWow64)) - { - //handle error - } - //System.out.println("isProcess64bit " + pid + " = " + isWow64.getValue()); - Kernel32Ex.instance.CloseHandle(new HANDLE(process)); - if (isWow64.getValue() == 1) - return false; - return true; - //CloseHandle() - } catch(Exception ex) - { - ex.printStackTrace(); - } - return false; - } - - public static HWND FindMainWindowFromPid(final long targetProcessId) { - - final List resultList = new ArrayList(); - class ParentWindowCallback implements WinUser.WNDENUMPROC { - @Override - public boolean callback(HWND hWnd, Pointer lParam) { - PointerByReference pointer = new PointerByReference(); - User32Ex.instance.GetWindowThreadProcessId(hWnd, pointer); - long pid = pointer.getPointer().getInt(0); - if (pid == targetProcessId) - if (resultList.isEmpty()) - resultList.add(hWnd); - return true; - } - } - - Api.User32Ex.instance.EnumWindows(new ParentWindowCallback(), 0); - if (!resultList.isEmpty()) - return resultList.get(0); - return null; - } - - public static void SelectListViewItemByIndex(HWND listViewHwnd, int index) - { - /* - HANDLE hProcess = OpenProcess(PROCESS_VM_WRITE | PROCESS_VM_OPERATION, FALSE, 0x0000c130); - LPVOID epLvi = VirtualAllocEx(hProcess, NULL, 4096, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); - - LVITEM lvi; - lvi.state = LVIS_FOCUSED | LVIS_SELECTED; - lvi.stateMask = LVIS_FOCUSED | LVIS_SELECTED; - SIZE_T cbWritten = 0; - WriteProcessMemory(hProcess, epLvi, &lvi, sizeof(lvi), &cbWritten); - DWORD dw = SendMessage((HWND)0x00020C4C, LVM_SETITEMSTATE, 1, (LPARAM)epLvi); - - VirtualFreeEx(hProcess, epLvi, 4096, MEM_DECOMMIT | MEM_RELEASE); - CloseHandle(hProcess); - */ - PointerByReference pointer = new PointerByReference(); - User32Ex.instance.GetWindowThreadProcessId(listViewHwnd, pointer); - int pid = pointer.getPointer().getInt(0); - Pointer process = Kernel32Ex.instance.OpenProcess(Api.PROCESS_VM_WRITE | Api.PROCESS_VM_OPERATION, false, new Pointer(pid)); - IntByReference addr = new IntByReference(0); - SIZE_T size = new SIZE_T(4096); - IntByReference epLvi = Kernel32Ex.instance.VirtualAllocEx(new HANDLE(process), addr, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); - - LVITEM_VISTA lvitem = new LVITEM_VISTA(); - lvitem.stateMask = LVIS_FOCUSED | LVIS_SELECTED; - lvitem.state = LVIS_FOCUSED | LVIS_SELECTED; - IntByReference bytesWritten = new IntByReference(); - Api.Kernel32Ex.instance.WriteProcessMemory(new HANDLE(process), epLvi, lvitem.getPointer(), lvitem.size(),bytesWritten); - Api.User32Ex.instance.SendMessage(listViewHwnd, LVM_SETITEMSTATE, new WPARAM(index), lvitem); - - Api.Kernel32Ex.instance.VirtualFreeEx(new HANDLE(process), epLvi, new SIZE_T(4096), new DWORD(MEM_DECOMMIT | MEM_RELEASE)); - Api.Kernel32Ex.instance.CloseHandle(new HANDLE(process)); - } - - public static void SelectListItemByIndex(HWND listHwnd, int index) - { - //com.sun.jna.platform.win32.User32.INSTANCE - Api.User32Ex.instance.SendMessage(listHwnd, LB_SETCURSEL, new WPARAM(index), new LPARAM(0)); - SelectListViewItemByIndex(listHwnd, index); - //GetListViewItemByIndex(listHwnd, index); - //LVITEM lvitem = new LVITEM(); - //lvitem.stateMask = LVIS_FOCUSED | LVIS_SELECTED; - //lvitem.state = LVIS_FOCUSED | LVIS_SELECTED; - //JOptionPane.showMessageDialog(null, "lvitem size: " + lvitem.size()); - - } -} diff --git a/src/org/synthuse/CommandPopupMenu.java b/src/org/synthuse/CommandPopupMenu.java deleted file mode 100644 index 7e032f9..0000000 --- a/src/org/synthuse/CommandPopupMenu.java +++ /dev/null @@ -1,261 +0,0 @@ -/* - * Copyright 2014, Synthuse.org - * Released under the Apache Version 2.0 License. - * - * last modified by ejakubowski7@gmail.com -*/ - -package org.synthuse; - -import javax.swing.JMenuItem; -import javax.swing.JOptionPane; -import javax.swing.JPopupMenu; -import javax.swing.JMenu; - -import java.awt.event.ActionListener; -import java.awt.event.ActionEvent; - -@SuppressWarnings("serial") -public class CommandPopupMenu extends JPopupMenu { - - public static interface menuEvents { - void menuItemClicked(String command, int paramCount, boolean useXpath, ActionEvent e); - } - public menuEvents events = new menuEvents() { - public void menuItemClicked(String command, int paramCount, boolean useXpath, ActionEvent e) { - JOptionPane.showMessageDialog(null, command); - } - }; - - public CommandPopupMenu() { - - JMenu mnKeyboard = new JMenu("Keyboard"); - add(mnKeyboard); - - CommandMenuItem mntmSendkeys = new CommandMenuItem("sendKeys", 2, false); - mnKeyboard.add(mntmSendkeys); - - CommandMenuItem mntmKeydown = new CommandMenuItem("keyDown", 2, false); - mnKeyboard.add(mntmKeydown); - - CommandMenuItem mntmKeyup = new CommandMenuItem("keyUp", 2, false); - mnKeyboard.add(mntmKeyup); - - CommandMenuItem mntmKeycopy = new CommandMenuItem("keyCopy", 1); - mnKeyboard.add(mntmKeycopy); - - CommandMenuItem mntmKeypaste = new CommandMenuItem("keyPaste", 1); - mnKeyboard.add(mntmKeypaste); - - CommandMenuItem mntmKeyEsc = new CommandMenuItem("keyEscape", 1); - mnKeyboard.add(mntmKeyEsc); - - CommandMenuItem mntmKeyFunc = new CommandMenuItem("keyFunctionX", 2, false); - mnKeyboard.add(mntmKeyFunc); - - JMenu mnMouse = new JMenu("Mouse"); - add(mnMouse); - - CommandMenuItem mntmClick = new CommandMenuItem("click", 2, true); - mnMouse.add(mntmClick); - - CommandMenuItem mntmDoubleclick = new CommandMenuItem("doubleClick", 2, true); - mnMouse.add(mntmDoubleclick); - - CommandMenuItem mntmRightclick = new CommandMenuItem("rightClick", 2, true); - mnMouse.add(mntmRightclick); - - CommandMenuItem mntmwinClick = new CommandMenuItem("winClick", 2); - mnMouse.add(mntmwinClick); - - CommandMenuItem mntmwinDoubleClick = new CommandMenuItem("winDoubleClick", 2); - mnMouse.add(mntmwinDoubleClick); - - CommandMenuItem mntmwinRightClick = new CommandMenuItem("winRightClick", 2); - mnMouse.add(mntmwinRightClick); - - CommandMenuItem mntmDraganddrop = new CommandMenuItem("dragAndDrop", 3); - mnMouse.add(mntmDraganddrop); - - CommandMenuItem mntmMousedown = new CommandMenuItem("mouseDown", 1, false); - mnMouse.add(mntmMousedown); - - CommandMenuItem mntmMouseup = new CommandMenuItem("mouseUp", 1, false); - mnMouse.add(mntmMouseup); - - CommandMenuItem mntmMousedownright = new CommandMenuItem("mouseDownRight", 1, false); - mnMouse.add(mntmMousedownright); - - CommandMenuItem mntmMouseupright = new CommandMenuItem("mouseUpRight", 1, false); - mnMouse.add(mntmMouseupright); - - CommandMenuItem mntmMousemove = new CommandMenuItem("mouseMove", 2, true); - mnMouse.add(mntmMousemove); - - CommandMenuItem mntmMousemoveXy = new CommandMenuItem("mouseMoveXy", 3, false); - mnMouse.add(mntmMousemoveXy); - - CommandMenuItem mntmSetTargetOffset = new CommandMenuItem("setTargetOffset", 3, false); - mnMouse.add(mntmSetTargetOffset); - - - JMenu mnWinMessages = new JMenu("Win Messages"); - add(mnWinMessages); - - CommandMenuItem mntmWindowfocus = new CommandMenuItem("windowFocus", 2); - mnWinMessages.add(mntmWindowfocus); - - CommandMenuItem mntmWindowSwitchToThis = new CommandMenuItem("windowSwitchToThis", 2); - mnWinMessages.add(mntmWindowSwitchToThis); - - CommandMenuItem mntmSelectMenu = new CommandMenuItem("selectMenu", 2); - mnWinMessages.add(mntmSelectMenu); - - CommandMenuItem mntmSelectContextMenuId = new CommandMenuItem("selectContextMenuId", 3); - mnWinMessages.add(mntmSelectContextMenuId); - - CommandMenuItem mntmSendCommandMsg = new CommandMenuItem("sendCommandMsg", 4); - mnWinMessages.add(mntmSendCommandMsg); - - CommandMenuItem mntmSendMessage = new CommandMenuItem("sendMessage", 5); - mnWinMessages.add(mntmSendMessage); - - CommandMenuItem mntmSetcursorposition = new CommandMenuItem("setCursorPosition", 3); - mnWinMessages.add(mntmSetcursorposition); - - CommandMenuItem mntmWindowminimize = new CommandMenuItem("windowMinimize", 2); - mnWinMessages.add(mntmWindowminimize); - - CommandMenuItem mntmWindowmaximize = new CommandMenuItem("windowMaximize", 2); - mnWinMessages.add(mntmWindowmaximize); - - CommandMenuItem mntmWindowrestore = new CommandMenuItem("windowRestore", 2); - mnWinMessages.add(mntmWindowrestore); - - CommandMenuItem mntmWindowhide = new CommandMenuItem("windowHide", 2); - mnWinMessages.add(mntmWindowhide); - - CommandMenuItem mntmWindowshow = new CommandMenuItem("windowShow", 2); - mnWinMessages.add(mntmWindowshow); - - CommandMenuItem mntmWindowclose = new CommandMenuItem("windowClose", 2); - mnWinMessages.add(mntmWindowclose); - - CommandMenuItem mntmSetwindowtext = new CommandMenuItem("setWindowText", 3); - mnWinMessages.add(mntmSetwindowtext); - - CommandMenuItem mntmGetwindowtext = new CommandMenuItem("getWindowText", 2); - mnWinMessages.add(mntmGetwindowtext); - - CommandMenuItem mntmGetwindowclass = new CommandMenuItem("getWindowClass", 2); - mnWinMessages.add(mntmGetwindowclass); - - CommandMenuItem mntmSelectListIndex = new CommandMenuItem("selectListIndex", 3); - mnWinMessages.add(mntmSelectListIndex); - - CommandMenuItem mntmSelectListString = new CommandMenuItem("selectListString", 3); - mnWinMessages.add(mntmSelectListString); - - CommandMenuItem mntmDisplayText = new CommandMenuItem("displayText", 3, false); - add(mntmDisplayText); - - CommandMenuItem mntmDisableStatus = new CommandMenuItem("disableStatus", 2, false); - add(mntmDisableStatus); - - CommandMenuItem mntmForceRefresh = new CommandMenuItem("forceRefresh", 1, false); - add(mntmForceRefresh); - - CommandMenuItem mntmForcewin32Refresh = new CommandMenuItem("forceWin32Refresh", 1, false); - add(mntmForcewin32Refresh); - - CommandMenuItem mntmOnlyRefreshWin32 = new CommandMenuItem("onlyRefreshWin32", 2, false); - add(mntmOnlyRefreshWin32); - - - CommandMenuItem mntmOpen = new CommandMenuItem("open", 2, false); - add(mntmOpen); - - //CommandMenuItem mntmOpenAndWait = new CommandMenuItem("openAndWait", 1, false); - //add(mntmOpenAndWait); - - CommandMenuItem mntmPause = new CommandMenuItem("pause", 2, false); - add(mntmPause); - - CommandMenuItem mntmSettimeout = new CommandMenuItem("setTimeout", 2, false); - add(mntmSettimeout); - - CommandMenuItem mntmSetspeed = new CommandMenuItem("setSpeed", 2, false); - add(mntmSetspeed); - - CommandMenuItem mntmSetUpdateThreshold = new CommandMenuItem("setUpdateThreshold", 2, false); - add(mntmSetUpdateThreshold); - - CommandMenuItem mntmTakeScreenCapture = new CommandMenuItem("takeScreenCapture", 2, false); - add(mntmTakeScreenCapture); - - CommandMenuItem mntmTargetRefresh = new CommandMenuItem("targetRefresh", 2); - add(mntmTargetRefresh); - - CommandMenuItem mntmVerifyElementNotPresent = new CommandMenuItem("verifyElementNotPresent", 2); - add(mntmVerifyElementNotPresent); - - CommandMenuItem mntmVerifyElementPresent = new CommandMenuItem("verifyElementPresent", 2); - add(mntmVerifyElementPresent); - - CommandMenuItem mntmWaitforclass = new CommandMenuItem("waitForClass", 2, false); - add(mntmWaitforclass); - - CommandMenuItem mntmWaitfortitle = new CommandMenuItem("waitForTitle", 2, false); - add(mntmWaitfortitle); - - CommandMenuItem mntmWaitfortext = new CommandMenuItem("waitForText", 2, false); - add(mntmWaitfortext); - - CommandMenuItem mntmWaitforvisible = new CommandMenuItem("waitForVisible", 2); - add(mntmWaitforvisible); - - } - - class CommandMenuItem extends JMenuItem { - public String commandText = ""; - public int paramCount = 2; - public boolean useXpath = true; - - public CommandMenuItem(String arg0, int paramCount) { - super(arg0); - init(arg0, paramCount, true); - } - - public CommandMenuItem(String arg0, int paramCount, boolean useXpath) { - super(arg0); - init(arg0, paramCount, useXpath); - } - - public void init(String arg0, int paramCount, boolean useXpath) { - this.commandText = arg0; - this.paramCount = paramCount; - this.useXpath = useXpath; - this.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - events.menuItemClicked(commandText, CommandMenuItem.this.paramCount, CommandMenuItem.this.useXpath, e); - } - }); - } - } - - public static String buildSkeletonCommand(String command, int paramCount, String xpathStr, boolean useXpath) { - String xpathItem = xpathStr; - if (!useXpath) - xpathItem = ""; - String actionStr = "| do | " + command + " | "; - if (paramCount > 1) - actionStr += "on | " + xpathItem + " | "; - if (paramCount > 2) - actionStr += "with | |"; - if (paramCount > 3) - actionStr += " and | |"; - if (paramCount > 4) - actionStr += " and | |"; - return actionStr; - } -} diff --git a/src/org/synthuse/CommandProcessor.java b/src/org/synthuse/CommandProcessor.java deleted file mode 100644 index 9aba605..0000000 --- a/src/org/synthuse/CommandProcessor.java +++ /dev/null @@ -1,318 +0,0 @@ -/* - * Copyright 2014, Synthuse.org - * Released under the Apache Version 2.0 License. - * - * last modified by ejakubowski -*/ - -package org.synthuse; - -import java.awt.Point; -import java.text.DecimalFormat; -import java.util.concurrent.atomic.AtomicBoolean; - -import javax.swing.JDialog; -import javax.swing.JOptionPane; -import org.synthuse.commands.*; - -public class CommandProcessor implements Runnable{ - - public static long SPEED = 1000; // ms - public static double XML_UPDATE_THRESHOLD = 5.0; // seconds - public static long WAIT_TIMEOUT_THRESHOLD = 30000; //ms - public static AtomicBoolean STOP_PROCESSOR = new AtomicBoolean(false); //stop script from executing - public static boolean DEFAULT_QUIET = false; //by default is quiet enabled - - protected CommandProcessor CommandProcessor = null; - public int executeCount = 0; - public int executeErrorCount; - public String lastError = ""; - public String currentCommandText = ""; - public Point targetOffset = new Point(); - public StatusWindow currentStatusWin = null; - - public String scriptStr = ""; - public BaseCommand base = new BaseCommand(this); - public MouseCommands mouse = new MouseCommands(this); - public KeyboardCommands keyboard = new KeyboardCommands(this); - public WindowsCommands win = new WindowsCommands(this); - public MainCommands main = new MainCommands(this); - - private boolean isQuiet = DEFAULT_QUIET; - private int scriptErrorCount = 0; - - public static interface Events { - void statusChanged(String status); - void executionCompleted(); - } - public Events events = new Events() { - public void statusChanged(String status){ - System.out.println(status); - } - public void executionCompleted(){ - - } - }; - - public int getErrors() { - return scriptErrorCount; - } - - public void setScript(String Script) { - scriptStr = Script; - } - - public void setQuiet(boolean val) { - isQuiet = val; - if (val) - { - if (currentStatusWin != null) - currentStatusWin.dispose(); - currentStatusWin = null; - } - - } - - public CommandProcessor () { - } - - public CommandProcessor (String scriptStr) { - this.scriptStr = scriptStr; - } - - public CommandProcessor (String scriptStr, Events customEvents) { //multithreading support - this.scriptStr = scriptStr; - if (customEvents != null) - this.events = customEvents; - } - - @Override - public void run() { //multithreading support - executeAllScriptCommands(scriptStr); - } - - public static CommandProcessor executeThreaded(String scriptStr, Events customEvents) { //multithreading support - CommandProcessor cp = new CommandProcessor(scriptStr, customEvents); - Thread t = new Thread(cp); - t.start(); - return cp; - } - - public void executeAllScriptCommands(String scriptStr) { - events.statusChanged("Executing Test Script..."); - //CommandProcessor cmdProcessor = new CommandProcessor(); - scriptErrorCount = 0; - executeCount = 0; - lastError = ""; - long startTime = System.nanoTime(); - String[] lines = scriptStr.split("\n"); - for (String line : lines) { - - if (!line.trim().startsWith("|")) - continue; //skip if it doesn't start with bar - String[] parsed = line.trim().split("\\|"); - // - - //System.out.println("line: " + line); - //System.out.println("parsed len = " + parsed.length); - //System.out.println("parsed 2 = " + parsed[2]); - //System.out.println("parsed 4 = " + parsed[4]); - events.statusChanged("Executing line: " + line); - if (parsed.length == 4 || parsed.length == 3) - execute(parsed[2].trim(), new String[] {}); - if (parsed.length == 6 || parsed.length == 5) - execute(parsed[2].trim(), new String[] {parsed[4].trim()}); - if (parsed.length == 7) - execute(parsed[2].trim(), new String[] {parsed[4].trim(), parsed[6].trim()}); - if (parsed.length == 9) - execute(parsed[2].trim(), new String[] {parsed[4].trim(), parsed[6].trim(), parsed[8].trim()}); - if (parsed.length == 11) - execute(parsed[2].trim(), new String[] {parsed[4].trim(), parsed[6].trim(), parsed[8].trim(), parsed[10].trim()}); - - if (executeErrorCount > 0) //check if any errors occurred - ++scriptErrorCount; - - if (STOP_PROCESSOR.get()) - break; - } - double seconds = ((double)(System.nanoTime() - startTime) / 1000000000); - String forcedStr = "Completed"; - if (STOP_PROCESSOR.get()) - forcedStr = "Stopped"; - events.statusChanged("Script Execution " + forcedStr + " " + executeCount + " command(s) with " + scriptErrorCount + " error(s) in " + new DecimalFormat("#.###").format(seconds) + " seconds"); - events.executionCompleted(); - if (scriptErrorCount > 0 && !isQuiet) - { - JOptionPane optionPane = new JOptionPane(lastError); - JDialog dialog = optionPane.createDialog("Errors"); - dialog.setAlwaysOnTop(SynthuseDlg.config.isAlwaysOnTop()); - dialog.setVisible(true); - dialog.dispose(); - //JOptionPane.showMessageDialog(null, lastError); - } - } - - public Object execute(String command, String[] args) { - ++executeCount; - executeErrorCount = 0; - currentCommandText = command; - String joinedArgs = ""; - for (String arg : args) - joinedArgs += arg + " | "; - if (joinedArgs.endsWith("| ")) - joinedArgs = joinedArgs.substring(0, joinedArgs.length()-2); - //StatusWindow sw = null; - if (!isQuiet) - currentStatusWin = new StatusWindow(command + " " + joinedArgs, -1); - - Object result = executeCommandSwitch(command, args); - if (SPEED > 0) - try { Thread.sleep(SPEED); } catch (Exception e) {e.printStackTrace();} - - if (!isQuiet && currentStatusWin != null) - currentStatusWin.dispose(); - return result; - } - - private Object executeCommandSwitch(String command, String[] args) { - try { - - //Key commands - if (command.equals("sendKeys")) - return keyboard.cmdSendKeys(args); - if (command.equals("keyDown")) - return keyboard.cmdKeyDown(args); - if (command.equals("keyUp")) - return keyboard.cmdKeyUp(args); - if (command.equals("keyCopy")) - return keyboard.cmdKeyCopy(args); - if (command.equals("keyPaste")) - return keyboard.cmdKeyPaste(args); - if (command.equals("keyEscape")) - return keyboard.cmdKeyEscape(args); - if (command.equals("keyFunctionX")) - return keyboard.cmdKeyFunc(args); - - - //Mouse commands - if (command.equals("click")) - return mouse.cmdClick(args); - if (command.equals("doubleClick")) - return mouse.cmdDoubleClick(args); - if (command.equals("rightClick")) - return mouse.cmdRightClick(args); - if (command.equals("winClick")) - return mouse.cmdWinClick(args); - if (command.equals("winDoubleClick")) - return mouse.cmdWinDoubleClick(args); - if (command.equals("winRightClick")) - return mouse.cmdWinRightClick(args); - if (command.equals("dragAndDrop")) - return mouse.cmdRightClick(args); - if (command.equals("mouseDown")) - return mouse.cmdMouseDown(args); - if (command.equals("mouseUp")) - return mouse.cmdMouseUp(args); - if (command.equals("mouseDownRight")) - return mouse.cmdMouseDownRight(args); - if (command.equals("mouseUpRight")) - return mouse.cmdMouseUpRight(args); - if (command.equals("mouseMove")) - return mouse.cmdMouseMove(args); - if (command.equals("mouseMoveXy")) - return mouse.cmdMouseMoveXy(args); - if (command.equals("setTargetOffset")) - return mouse.cmdSetTargetOffset(args); - - //Windows Api Commands - if (command.equals("windowFocus")) - return win.cmdWindowFocus(args); - if (command.equals("selectMenu")) - return win.cmdSelectMenu(args); - if (command.equals("selectContextMenuId")) - return win.cmdSelectContextMenuId(args); - if (command.equals("sendCommandMsg")) - return win.cmdSendCommandMsg(args); - if (command.equals("sendMessage")) - return win.cmdSendMessage(args); - if (command.equals("windowMinimize")) - return win.cmdWindowMinimize(args); - if (command.equals("windowMaximize")) - return win.cmdWindowMaximize(args); - if (command.equals("windowRestore")) - return win.cmdWindowRestore(args); - if (command.equals("windowShow")) - return win.cmdWindowShow(args); - if (command.equals("windowHide")) - return win.cmdWindowHide(args); - if (command.equals("windowSwitchToThis")) - return win.cmdWindowSwitchToThis(args); - if (command.equals("windowClose")) - return win.cmdWindowClose(args); - if (command.equals("setWindowText")) - return win.cmdSetText(args); - if (command.equals("getWindowText")) - return win.cmdGetText(args); - if (command.equals("selectListIndex")) - return win.cmdSelectListIndex(args); - if (command.equals("selectListString")) - return win.cmdSelectListString(args); - - // Misc Command and Test/Sample command - if (command.equals("delay") || command.equals("pause")) { - if (!base.checkArgumentLength(args, 1)) - return false; - if (!base.checkFirstArgumentLength(args)) - return false; - if (!base.checkIsNumeric(args[0])) - return false; - //System.out.println("sleeping for " + args[0] ); - Thread.sleep(Long.parseLong(args[0])); - return true; - } - - if (command.equals("open")) - return main.cmdOpen(args); - if (command.equals("displayText")) - return main.cmdDisplayText(args); - if (command.equals("disableStatus")) - return main.cmdDisableStatus(args); - if (command.equals("forceRefresh")) - return main.cmdForceRefresh(args); - if (command.equals("forceWin32Refresh")) - return main.cmdForceWin32Refresh(args); - if (command.equals("onlyRefreshWin32")) - return main.cmdOnlyRefreshWin32(args); - if (command.equals("setSpeed")) - return main.cmdSetSpeed(args); - if (command.equals("setTimeout")) - return main.cmdSetTimeout(args); - if (command.equals("setUpdateThreshold")) - return main.cmdSetUpdateThreshold(args); - if (command.equals("verifyElementNotPresent")) - return main.cmdVerifyElementNotPresent(args); - if (command.equals("verifyElementPresent")) - return main.cmdVerifyElementPresent(args); - if (command.equals("takeScreenCapture")) - return main.cmdTakeScreenCapture(args); - if (command.equals("targetRefresh")) - return main.cmdTargetRefresh(args); - if (command.equals("waitForTitle")) - return main.cmdWaitForTitle(args); - if (command.equals("waitForText")) - return main.cmdWaitForText(args); - if (command.equals("waitForClass")) - return main.cmdWaitForClass(args); - if (command.equals("waitForVisible")) - return main.cmdWaitForVisible(args); - - } - catch (Exception e) { - base.appendError(e); - return false; - } - base.appendError("Error: Command '" + command + "' not found."); - return false; - } - -} diff --git a/src/org/synthuse/Config.java b/src/org/synthuse/Config.java deleted file mode 100644 index 37504f5..0000000 --- a/src/org/synthuse/Config.java +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright 2014, Synthuse.org - * Released under the Apache Version 2.0 License. - * - * last modified by ejakubowski -*/ - -package org.synthuse; - -public class Config extends PropertiesSerializer { - - public static String DEFAULT_PROP_FILENAME = "synthuse.properties"; - - public String disableUiaBridge = "false"; - public String disableFiltersUia = "false"; - public String alwaysOnTop = "true"; - public String refreshKey = "3"; - public String targetKey = "`"; - public String urlList = ""; - public String xpathList = ""; - public String xpathHightlight = ".*process=\"([^\"]*)\".*"; - - public boolean useStrongTextMatching = false; - - - public Config() //needed for cloning - { - } - - public Config(String propertyFilename) - { - super(propertyFilename); - load(propertyFilename); - } - - public boolean isUiaBridgeDisabled() - { - if (disableUiaBridge == null) - return false; - return disableUiaBridge.equals("true") || disableUiaBridge.equals("True"); - } - - - public void setDisableUiaBridge(boolean aNewValue) { - disableUiaBridge=aNewValue?"true":"false"; - } - - - public boolean isFilterUiaDisabled() - { - if (disableFiltersUia == null) - return false; - return disableFiltersUia.equals("true") || disableFiltersUia.equals("True"); - } - - public void setDisableFiltersUia(boolean aNewValue) { - disableFiltersUia=aNewValue?"true":"false"; - } - - - public boolean isAlwaysOnTop() - { - if (alwaysOnTop == null) - return new Config().alwaysOnTop.equals("true") || new Config().alwaysOnTop.equals("True"); - return alwaysOnTop.equals("true") || alwaysOnTop.equals("True"); - } - - public void setAlwaysOnTop(boolean aNewValue) - { - alwaysOnTop=aNewValue?"true":"false"; - } - - public char getRefreshKey() - { - String keyStr = ""; - if (this.refreshKey == null) - keyStr = new Config().refreshKey; //use default value - else if (this.refreshKey.isEmpty()) - keyStr = new Config().refreshKey; //use default value - else - keyStr = this.refreshKey; - return keyStr.charAt(0); - } - - public int getRefreshKeyCode() - { - return RobotMacro.getKeyCode(this.getRefreshKey())[0]; - } - - public void setRefreshKey(String aText) { - this.refreshKey=aText; - } - - public char getTargetKey() - { - String keyStr = ""; - if (this.targetKey == null) - keyStr = new Config().targetKey; //use default value - else if (this.targetKey.isEmpty()) - keyStr = new Config().targetKey; //use default value - else - keyStr = this.targetKey; - return keyStr.charAt(0); - } - - public int getTargetKeyCode() - { - return RobotMacro.getKeyCode(this.getTargetKey())[0]; - } - - public void setTargetKey(String aText) { - this.targetKey=aText; - } - - public boolean isUseStrongTextMatching() { - return useStrongTextMatching; - } - - public void setUseStrongTextMatching(boolean useStrongTextMatching) { - this.useStrongTextMatching = useStrongTextMatching; - } - - public String getXpathList() { - return xpathList; - } - - public void setXPathList(String aText) { - xpathList=aText; - } - - public String getXpathHighlight() { - return xpathHightlight; - } - - public void setXPathHighlight(String aText) { - xpathHightlight=aText; - } -} diff --git a/src/org/synthuse/DragTarget.java b/src/org/synthuse/DragTarget.java deleted file mode 100644 index e5a36c3..0000000 --- a/src/org/synthuse/DragTarget.java +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Copyright 2014, Synthuse.org - * Released under the Apache Version 2.0 License. - * - * last modified by ejakubowski -*/ - -package org.synthuse; - -import java.awt.Cursor; -import java.awt.Point; -import java.awt.Toolkit; -import java.awt.datatransfer.DataFlavor; -import java.awt.datatransfer.Transferable; -import java.awt.dnd.DragSource; -import java.awt.dnd.DragSourceAdapter; -import java.awt.dnd.DragSourceDragEvent; -import java.awt.dnd.DragSourceMotionListener; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.awt.image.BufferedImage; - -import javax.activation.ActivationDataFlavor; -import javax.activation.DataHandler; -import javax.imageio.ImageIO; -import javax.swing.JComponent; -import javax.swing.JLabel; -import javax.swing.TransferHandler; - - -public class DragTarget extends JLabel { - - public static String CUSTOM_ICON_RESOURCE = "/org/synthuse/img/bullseye-logo-th32x32.png"; - - private static final long serialVersionUID = 1L; - - public static interface dragEvents { - void dragStarted(JComponent c); - void dragMouseMoved(int x, int y); - void dropped(JComponent c); - } - public dragEvents events = new dragEvents() { - public void dragStarted(JComponent c) { - - } - public void dragMouseMoved(int x, int y) { - - } - public void dropped(JComponent c) { - - } - }; - - public DragTarget() { - - this.setTransferHandler(new CustomTransferHandler()); - - this.addMouseListener(new MouseAdapter(){ - public void mousePressed(MouseEvent e) - { - JComponent comp = (JComponent)e.getSource(); - TransferHandler handler = comp.getTransferHandler(); - //c.setOpaque(true); - handler.exportAsDrag(comp, e, TransferHandler.MOVE); - } - }); - } - - @SuppressWarnings("serial") - class CustomTransferHandler extends TransferHandler { - //private final JWindow window = new JWindow(); - private final DataFlavor localObjectFlavor; - private final JLabel label = new JLabel(); - //public Cursor blankCursor = null; - public Cursor customCursor = null; - - public CustomTransferHandler () { - //System.out.println("CustomTransferHandler"); - localObjectFlavor = new ActivationDataFlavor(DragTarget.class, DataFlavor.javaJVMLocalObjectMimeType, "JLabel"); - //label = DragTarget.this; - //window.add(label); - //window.setAlwaysOnTop(true); - //window.setBackground(new Color(0,true)); - // Create a new blank cursor. - //BufferedImage cursorImg = new BufferedImage(16, 16, BufferedImage.TYPE_INT_ARGB); - //blankCursor = Toolkit.getDefaultToolkit().createCustomCursor(cursorImg, new Point(0, 0), "blank cursor"); - try { - BufferedImage image = ImageIO.read(SynthuseDlg.class.getResourceAsStream(CUSTOM_ICON_RESOURCE)); - customCursor = Toolkit.getDefaultToolkit().createCustomCursor(image, new Point(15, 16), "custom cursor"); - } catch (Exception e1) { - e1.printStackTrace(); - } - - - DragSource.getDefaultDragSource().addDragSourceMotionListener(new DragSourceMotionListener() { - @Override - public void dragMouseMoved(DragSourceDragEvent e) { - events.dragMouseMoved(e.getLocation().x, e.getLocation().y); - //Point pt = e.getLocation(); - //pt.translate(-9, -9); // offset - //window.setLocation(pt); - //e.getDragSourceContext().setCursor(customCursor);//DragSource.DefaultLinkDrop - } - }); - - DragSource.getDefaultDragSource().addDragSourceListener(new DragSourceAdapter() { - @Override - public void dragEnter(DragSourceDragEvent e) { - e.getDragSourceContext().setCursor(customCursor);//DragSource.DefaultLinkDrop - //System.out.println("dragEnter"); - } - }); - - } - - @Override - protected Transferable createTransferable(JComponent c) { - //System.out.println("createTransferable"); - //JLabel l = (JLabel)c; - //String text = l.getText(); - final DataHandler dh = new DataHandler(c, localObjectFlavor.getMimeType()); - return dh; - //return new StringSelection(""); - } - - @Override - public boolean canImport(TransferSupport support) { - return true; - } - - @Override - public boolean importData(TransferSupport support) { - //System.out.println("importData"); - return true; - } - - @Override - public int getSourceActions(JComponent c) { - //System.out.println("getSourceActions"); - events.dragStarted(c); - JLabel p = (JLabel)c; - label.setIcon(p.getIcon()); - //label.setText(p.draggingLabel.getText()); - //window.pack(); - //Point pt = p.getLocation(); - //SwingUtilities.convertPointToScreen(pt, p); - //window.setLocation(pt); - //window.setVisible(true); - return MOVE; - } - - @Override - protected void exportDone(JComponent c, Transferable data, int action) { - //System.out.println("exportDone"); - events.dropped(c); - JLabel src = (JLabel)c; - if(action == TransferHandler.MOVE) { - src.remove(src); - src.revalidate(); - src.repaint(); - } - src = null; - //window.setVisible(false); - //window.dispose(); - } - } -} diff --git a/src/org/synthuse/KeyboardHook.java b/src/org/synthuse/KeyboardHook.java deleted file mode 100644 index 815eefd..0000000 --- a/src/org/synthuse/KeyboardHook.java +++ /dev/null @@ -1,334 +0,0 @@ -/* - * Copyright 2014, Synthuse.org - * Released under the Apache Version 2.0 License. - * - * last modified by ejakubowski7@gmail.com -*/ - - -package org.synthuse; - -//import java.awt.event.KeyEvent; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import com.sun.jna.*; -import com.sun.jna.platform.win32.User32; -import com.sun.jna.platform.win32.WinDef; -import com.sun.jna.platform.win32.WinDef.HWND; -import com.sun.jna.platform.win32.WinUser.*; -import com.sun.jna.platform.win32.WinDef.*; -import com.sun.jna.win32.W32APIOptions; - -public class KeyboardHook implements Runnable{ - - - // Keyboard event class, interface, and array list - public static class TargetKeyPress { - int idNumber; - int targetKeyCode; - boolean withShift, withCtrl, withAlt; - public TargetKeyPress (int targetKeyCode) { - this.targetKeyCode = targetKeyCode; - this.withShift = false; - this.withCtrl = false; - this.withAlt = false; - } - public TargetKeyPress (int idNumber, int targetKeyCode, boolean withShift, boolean withCtrl, boolean withAlt) { - this.idNumber = idNumber; - this.targetKeyCode = targetKeyCode; - this.withShift = withShift; - this.withCtrl = withCtrl; - this.withAlt = withAlt; - } - public TargetKeyPress (int targetKeyCode, boolean withShift, boolean withCtrl, boolean withAlt) { - this.targetKeyCode = targetKeyCode; - this.withShift = withShift; - this.withCtrl = withCtrl; - this.withAlt = withAlt; - } - } - - public static List targetList = Collections.synchronizedList(new ArrayList());// all keys we want to throw events on - - public static interface KeyboardEvents { - void keyPressed(TargetKeyPress target); - } - public KeyboardEvents events = new KeyboardEvents() { - public void keyPressed(TargetKeyPress target) { - //System.out.println("target key pressed: " + target.targetKeyCode); - } - }; - - // JNA constants and functions - public static final int WH_KEYBOARD_LL = 13; - //Modifier key vkCode constants - public static final int VK_SHIFT = 0x10; - public static final int VK_CONTROL = 0x11; - public static final int VK_MENU = 0x12; - public static final int VK_CAPITAL = 0x14; - - public static final int MOD_ALT = 0x0001; - public static final int MOD_CONTROL = 0x0002; - public static final int MOD_NOREPEAT = 0x4000; - public static final int MOD_SHIFT = 0x0004; - public static final int MOD_WIN = 0x0008; - - public static final int QS_HOTKEY = 0x0080; - public static final int INFINITE = 0xFFFFFFFF; - - public static HHOOK hHook = null; - public static LowLevelKeyboardProc lpfn; - public static volatile boolean quit = false; - - private static Thread khThread = null; - - - public interface User32Ex extends W32APIOptions { - User32Ex instance = (User32Ex) Native.loadLibrary("user32", User32Ex.class, DEFAULT_OPTIONS); - - LRESULT LowLevelKeyboardProc(int nCode,WPARAM wParam,LPARAM lParam); - HHOOK SetWindowsHookEx(int idHook, HOOKPROC lpfn, HMODULE hMod, int dwThreadId); - LRESULT CallNextHookEx(HHOOK idHook, int nCode, WPARAM wParam, LPARAM lParam); - LRESULT CallNextHookEx(HHOOK idHook, int nCode, WPARAM wParam, Pointer lParam); - boolean PeekMessage(MSG lpMsg, HWND hWnd, int wMsgFilterMin, int wMsgFilterMax, int wRemoveMsg); - boolean UnhookWindowsHookEx(HHOOK idHook); - short GetKeyState(int nVirtKey); - short GetAsyncKeyState(int nVirtKey); - - /* - DWORD WINAPI MsgWaitForMultipleObjects( - __in DWORD nCount, //The number of object handles in the array pointed to by pHandles. - __in const HANDLE *pHandles, //An array of object handles. - __in BOOL bWaitAll, //If this parameter is TRUE, the function returns when the states of all objects in the pHandles array have been set to signaled and an input event has been received. - __in DWORD dwMilliseconds, //if dwMilliseconds is INFINITE, the function will return only when the specified objects are signaled. - __in DWORD dwWakeMask //The input types for which an input event object handle will be added to the array of object handles. - );*/ - int MsgWaitForMultipleObjects(int nCount, Pointer pHandles, boolean bWaitAll, int dwMilliSeconds, int dwWakeMask); - boolean RegisterHotKey(Pointer hWnd, int id, int fsModifiers, int vk); - - //public static interface HOOKPROC extends StdCallCallback { - // LRESULT callback(int nCode, WPARAM wParam, KBDLLHOOKSTRUCT lParam); - //} - } - - public interface Kernel32 extends W32APIOptions { - Kernel32 instance = (Kernel32) Native.loadLibrary("kernel32", Kernel32.class, DEFAULT_OPTIONS); - - HMODULE GetModuleHandle(String name); - } - - // Create Global Windows Keyboard hook and wait until quit == true - public void createGlobalKeyboardHook() { - - if (hHook != null) - return; //hook already running don't add anymore - System.out.println("starting global keyboard hook"); - HMODULE hMod = Kernel32.instance.GetModuleHandle(null); - HOOKPROC lpfn = new HOOKPROC() { - @SuppressWarnings("unused") - public LRESULT callback(int nCode, WPARAM wParam, KBDLLHOOKSTRUCT lParam) { - //System.out.println("here " + lParam.vkCode); - TargetKeyPress target = getTargetKeyPressed(lParam.vkCode); //find if this is a target key pressed - if (target != null) - events.keyPressed(target); - //if (lParam.vkCode == 87) //w - // quit = true; - return User32.INSTANCE.CallNextHookEx(hHook, nCode, wParam, lParam.getPointer()); - } - }; - - hHook = User32.INSTANCE.SetWindowsHookEx(WH_KEYBOARD_LL, lpfn, hMod, 0); - if (hHook == null) - return; - - //System.out.println("starting message loop"); - MSG msg = new MSG(); - try { - - while (!quit) { - User32.INSTANCE.PeekMessage(msg, null, 0, 0, 1); - if (msg.message == User32.WM_HOTKEY){ // && msg.wParam.intValue() == 1 - //System.out.println("Hot key pressed!"); - msg = new MSG(); //must clear msg so it doesn't repeat - } - Thread.sleep(10); - } - } catch (Exception e) { - e.printStackTrace(); - } - //System.out.println("message loop stopped"); - } - - // Create HotKeys Windows hook and wait until quit == true - public void createHotKeysHook() { - registerAllHotKeys(); - //User32Ex.instance.MsgWaitForMultipleObjects(0, Pointer.NULL, true, INFINITE, QS_HOTKEY); - - //System.out.println("starting message loop"); - MSG msg = new MSG(); - try { - - while (!quit) { - User32.INSTANCE.PeekMessage(msg, null, 0, 0, 1); - if (msg.message == User32.WM_HOTKEY){ // && msg.wParam.intValue() == 1 - //System.out.println("Hot key pressed " + msg.wParam); - TargetKeyPress target = findTargetKeyPressById(msg.wParam.intValue()); - if (target != null) - events.keyPressed(target); - msg = new MSG(); //must clear msg so it doesn't repeat - } - Thread.sleep(10); - } - } catch (Exception e) { - e.printStackTrace(); - } - unregisterAllHotKeys(); - //System.out.println("message loop stopped"); - } - - //unhook the Global Windows Keyboard hook - public void unhook() { - if (hHook == null) - return; - if (!User32.INSTANCE.UnhookWindowsHookEx(hHook)) - System.out.println("Failed to unhook"); - //System.out.println("Unhooked"); - hHook = null; - } - - //stops Keyboard hook and causes the unhook command to be called - public static void stopKeyboardHook() { - quit = true; - if (khThread != null) - { - try { - khThread.join(); - } catch (Exception e) { - e.printStackTrace(); - } - } - } - - // search target keyboard event list for a match and return it otherwise return null if no match - - private TargetKeyPress getTargetKeyPressed(int keyCode) { - TargetKeyPress target = null; - for (TargetKeyPress tkp : KeyboardHook.targetList) { - if (tkp.targetKeyCode != keyCode) - continue; - if (!tkp.withShift || ((User32Ex.instance.GetKeyState(VK_SHIFT) & 0x8000) != 0)) { - if (!tkp.withCtrl || ((User32Ex.instance.GetKeyState(VK_CONTROL) & 0x8000) != 0)) { - if (!tkp.withAlt || ((User32Ex.instance.GetKeyState(VK_MENU) & 0x8000) != 0)) { - return tkp; - } - } - } - } - return target; - } - - private TargetKeyPress findTargetKeyPressById(int idNumber) - { - TargetKeyPress target = null; - for (TargetKeyPress tkp : KeyboardHook.targetList) { - if (tkp.idNumber == idNumber) - return tkp; - } - return target; - } - - // clear all target keys to watch for - public static void clearKeyEvent() { - KeyboardHook.targetList.clear(); - } - - - // add more target keys to watch for - public static void addKeyEvent(int targetKeyCode, boolean withShift, boolean withCtrl, boolean withAlt) { - KeyboardHook.targetList.add(new TargetKeyPress(KeyboardHook.targetList.size() + 1 , targetKeyCode, withShift, withCtrl, withAlt)); - } - - // add more target keys to watch for - public static void addKeyEvent(int targetKeyCode) { - KeyboardHook.targetList.add(new TargetKeyPress(targetKeyCode)); - } - - - private void registerAllHotKeys() // must register hot keys in the same thread that is watching for hotkey messages - { - //System.out.println("registering hotkeys"); - for (TargetKeyPress tkp : KeyboardHook.targetList) { - //BOOL WINAPI RegisterHotKey(HWND hWnd, int id, UINT fsModifiers, UINT vk); - int modifiers = User32.MOD_NOREPEAT; - if (tkp.withShift) - modifiers = modifiers | User32.MOD_SHIFT; - if (tkp.withCtrl) - modifiers = modifiers | User32.MOD_CONTROL; - if (tkp.withAlt) - modifiers = modifiers | User32.MOD_ALT; - //System.out.println("RegisterHotKey " + tkp.idNumber + "," + modifiers + ", " + tkp.targetKeyCode); - - if (!User32.INSTANCE.RegisterHotKey(new WinDef.HWND(Pointer.NULL), tkp.idNumber, modifiers, tkp.targetKeyCode)) - { - System.out.println("Couldn't register hotkey " + tkp.targetKeyCode); - } - } - } - - private void unregisterAllHotKeys() // must register hot keys in the same thread that is watching for hotkey messages - { - //System.out.println("unregistering hotkeys"); - for (TargetKeyPress tkp : KeyboardHook.targetList) { - if (!User32.INSTANCE.UnregisterHotKey(Pointer.NULL, tkp.idNumber)) - { - System.out.println("Couldn't unregister hotkey " + tkp.targetKeyCode); - } - } - } - - @Override - public void run() { - //createGlobalKeyboardHook(); - createHotKeysHook(); - //System.out.println("Unhooking Global Keyboard Hook"); - unhook();//wait for quit == true then unhook - } - - public KeyboardHook() { - } - - public KeyboardHook(KeyboardEvents events) { - this.events = events; - } - - public static void StartKeyboardHookThreaded(KeyboardEvents events) { - quit = false; - khThread = new Thread(new KeyboardHook(events)); - khThread.start(); - } - - /* - // testing - public static void main(String[] args) throws Exception { - //add target keys - KeyboardHook.addKeyEvent(KeyEvent.VK_3, true, true, false); - KeyboardHook.addKeyEvent(KeyEvent.VK_5, false, true, false); - KeyboardHook.addKeyEvent(KeyEvent.VK_Q); - - //add global hook and event - KeyboardHook.StartGlobalKeyboardHookThreaded(new KeyboardHook.KeyboardEvents() { - @Override - public void keyPressed(KeyboardHook.TargetKeyPress target) { - System.out.println("target key pressed " + target.targetKeyCode); - if (target.targetKeyCode == KeyEvent.VK_Q){ // if Q was pressed then unhook - KeyboardHook.stopGlobalKeyboardHook(); - System.out.println("unhooking"); - } - } - }); - } - */ - -} diff --git a/src/org/synthuse/MenuInfo.java b/src/org/synthuse/MenuInfo.java deleted file mode 100644 index 2900c75..0000000 --- a/src/org/synthuse/MenuInfo.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright 2014, Synthuse.org - * Released under the Apache Version 2.0 License. - * - * last modified by ejakubowski7@gmail.com -*/ - -package org.synthuse; - -import java.math.BigInteger; - -import com.sun.jna.Pointer; -import com.sun.jna.platform.win32.WinDef.*; - -public class MenuInfo { - public HMENU hmenu = null; - public String hmenuStr = ""; - public String hwndStr = ""; - public int menuCount = 0; - public String text = ""; - public String unaltered = ""; - public int id = 0; - public int position = 0; - public boolean hasSubMenu = false; - public HMENU submenu = null; - public String submenuStr = ""; - public int submenuCount = 0; - public String center = ""; - - public MenuInfo(String hwndStr, HMENU hmenu) { - this.hwndStr = hwndStr; - loadMenuBase(hmenu); - } - - public MenuInfo(String hwndStr, HMENU hmenu, int position) { - this.hwndStr = hwndStr; - loadMenuBase(hmenu); - if (this.menuCount > 0) - loadMenuDetails(hmenu, position); - } - - public void loadMenuBase(HMENU hmenu) { - Api api = new Api(); - this.hmenu = hmenu; - this.hmenuStr = GetHandleMenuAsString(hmenu); - this.menuCount = api.user32.GetMenuItemCount(hmenu); - } - - public void loadMenuDetails(HMENU hmenu, int position) { - Api api = new Api(); - this.position = position; - this.unaltered = api.GetMenuItemText(hmenu, position); - this.text = unaltered; - if (this.unaltered.contains("\t")) - this.text = this.text.substring(0, this.text.indexOf("\t")); - this.text = text.replaceAll("[^a-zA-Z0-9.,\\+ ]", ""); - this.id = api.user32.GetMenuItemID(hmenu, position); - /* - HWND hWnd = Api.GetHandleFromString(hwndStr); - RECT rect = new RECT(); - api.user32.GetMenuItemRect(hWnd, hmenu, position, rect); - int centerX = ((rect.right - rect.left) / 2) + rect.left; - int centerY = ((rect.bottom - rect.top) / 2) + rect.top; - this.center = centerX + "," + centerY; - */ - HMENU submenu = api.user32.GetSubMenu(hmenu, position); - if (submenu != null) { - int subCount = api.user32.GetMenuItemCount(submenu); - if (subCount > 0) { - this.hasSubMenu = true; - this.submenu = submenu; - this.submenuStr = GetHandleMenuAsString(submenu); - this.submenuCount = subCount; - } - } - - } - - public static String GetHandleMenuAsString(HMENU hmenu) { - if (hmenu == null) - return "0"; - //String longHexStr = hWnd.toString().substring("native@".length()); - //String longHexStr = hmenu.getPointer() - String longHexStr = hmenu.getPointer().toString().substring("native@0x".length()); - long l = new BigInteger(longHexStr, 16).longValue(); - return l + ""; - } - - public static HMENU GetHandleMenuFromString(String hmenu) { - if (hmenu == null) - return null; - if (hmenu.isEmpty()) - return null; - String cleanNumericHandle = hmenu.replaceAll("[^\\d.]", ""); - try { - return (new HMENU(new Pointer(Long.parseLong(cleanNumericHandle)))); - } catch (Exception e) { - e.printStackTrace(); - } - return null; - } - -} diff --git a/src/org/synthuse/MessageHookFrame.java b/src/org/synthuse/MessageHookFrame.java deleted file mode 100644 index 6df678d..0000000 --- a/src/org/synthuse/MessageHookFrame.java +++ /dev/null @@ -1,290 +0,0 @@ -/* - * Copyright 2014, Synthuse.org - * Released under the Apache Version 2.0 License. - * - * last modified by ejakubowski7@gmail.com -*/ - -// This class is not actually used and is only here as a reference - -package org.synthuse; - -import javax.swing.JFrame; -import javax.swing.JToolBar; -import java.awt.BorderLayout; -import javax.swing.JTextArea; -import javax.swing.JScrollPane; -import javax.swing.JButton; -import javax.swing.WindowConstants; - - -import com.sun.jna.Native; -import com.sun.jna.Pointer; -import com.sun.jna.Structure; -import com.sun.jna.platform.win32.User32; -import com.sun.jna.platform.win32.WinDef.*; -import com.sun.jna.platform.win32.BaseTSD.LONG_PTR; -import com.sun.jna.ptr.IntByReference; - -import java.awt.event.ActionListener; -import java.awt.event.ActionEvent; -import java.awt.event.WindowAdapter; -import java.awt.event.WindowEvent; - -import javax.swing.JLabel; -import javax.swing.JTextField; -import java.awt.Dimension; -import java.awt.Component; -import java.util.Arrays; -import java.util.List; - -import javax.swing.Box; - - -public class MessageHookFrame extends JFrame { - - private static final long serialVersionUID = -5863279004595502801L; - - public static final String newLine = System.getProperty("line.separator"); - - public static final int WH_CALLWNDPROC = 4; - public static final int WH_GETMESSAGE = 3; - public static final int WH_KEYBOARD_LL = 13; - - public static final int WM_COPYDATA = 74; - public static final int GWLP_WNDPROC = -4; - - private JTextArea textArea; - private JButton btnSave; - private JButton btnStartMsgHook; - private JButton btnPause; - private JButton btnClear; - private LONG_PTR oldWndProc; - private MsgHook msgHook = null; - - public static volatile boolean quit = false; - private JLabel lblTargetHwnd; - public JTextField txtTarget; - private Component horizontalStrut; - - public MessageHookFrame() { - setTitle("Message Hook"); - setBounds(100, 100, 700, 367); - - JToolBar toolBar = new JToolBar(); - getContentPane().add(toolBar, BorderLayout.NORTH); - - btnStartMsgHook = new JButton("Start Hook"); - btnStartMsgHook.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - if (btnStartMsgHook.getText().equals("Start Hook")) - { //start Message Hook - btnStartMsgHook.setText("Stop Hook"); - createMessageHook(); - } - else - { //stop message hook - btnStartMsgHook.setText("Start Hook"); - stopMessageHook(); - } - } - }); - - lblTargetHwnd = new JLabel("Target HWND: "); - toolBar.add(lblTargetHwnd); - - txtTarget = new JTextField(); - txtTarget.setMaximumSize(new Dimension(70, 2147483647)); - txtTarget.setText("0"); - toolBar.add(txtTarget); - txtTarget.setColumns(10); - - horizontalStrut = Box.createHorizontalStrut(20); - toolBar.add(horizontalStrut); - toolBar.add(btnStartMsgHook); - - btnPause = new JButton("Pause"); - btnPause.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - - final HWND myHwnd = new HWND(Native.getWindowPointer(MessageHookFrame.this)); - oldWndProc = User32.INSTANCE.GetWindowLongPtr(myHwnd, GWLP_WNDPROC); - - Api.WNDPROC wndProc = new Api.WNDPROC() { - public LRESULT callback(HWND hWnd, int uMsg, WPARAM wParam, LPARAM lParam) { - if (uMsg == WM_COPYDATA){ - System.out.println("WM_COPYDATA"); - //handle the window message here - } - else - System.out.println("MESSAGE: " + uMsg); - return Api.User32Ex.instance.CallWindowProc(oldWndProc, hWnd, uMsg, wParam, lParam); - //return new LRESULT(0); - //return User32.INSTANCE.DefWindowProc(hWnd, uMsg, wParam, lParam); - } - }; - - Api.User32Ex.instance.SetWindowLongPtr(myHwnd, GWLP_WNDPROC, wndProc); - } - }); - toolBar.add(btnPause); - - btnSave = new JButton("Save"); - btnSave.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - } - }); - toolBar.add(btnSave); - - btnClear = new JButton("Clear"); - btnClear.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent arg0) { - textArea.setText(""); - } - }); - toolBar.add(btnClear); - - JScrollPane scrollPane = new JScrollPane(); - getContentPane().add(scrollPane, BorderLayout.CENTER); - - textArea = new JTextArea(); - scrollPane.setViewportView(textArea); - - this.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); - this.addWindowListener(new WindowAdapter() { - @Override - public void windowClosing(WindowEvent e) { - //TestIdeFrame.this.setVisible(false); - MessageHookFrame.this.dispose(); - } - }); - - super.setAlwaysOnTop(SynthuseDlg.config.isAlwaysOnTop()); - - } - /* - typedef struct - { - HWND hWnd; - int nCode; - DWORD dwHookType; - WPARAM wParam; - LPARAM lParam; - TCHAR wParamStr[25]; - TCHAR lParamStr[25]; - }HEVENT; - */ - - public static class HEVENT extends Structure { - //The by-reference version of this structure. - public static class ByReference extends HEVENT implements Structure.ByReference { } - - public HEVENT() { } - - //Instantiates a new COPYDATASTRUCT with existing data given the address of that data. - public HEVENT(final long pointer) { - this(new Pointer(pointer)); - } - - //Instantiates a new COPYDATASTRUCT with existing data given a pointer to that data. - public HEVENT(final Pointer memory) { - super(memory); - read(); - } - - public WORD hWnd; - public WORD nCode; - public DWORD dwHookType; - public DWORD wParam; - public DWORD lParam; - //public TCHAR wParamStr[25]; - //public TCHAR lParamStr[25]; - - @SuppressWarnings("rawtypes") - @Override - protected final List getFieldOrder() { - return Arrays.asList(new String[] {"hWnd", "nCode", "dwHookType", "wParam", "lParam" }); - } - } - - - public void createMessageHook() { - - quit = false; //don't quit - - //find the HWND and current WNDPROC on this java window - final HWND myHwnd = new HWND(Native.getWindowPointer(MessageHookFrame.this)); - oldWndProc = User32.INSTANCE.GetWindowLongPtr(myHwnd, GWLP_WNDPROC); - - Api.WNDPROC wndProc = new Api.WNDPROC() { - public LRESULT callback(HWND hWnd, int uMsg, WPARAM wParam, LPARAM lParam) { - if (uMsg == WM_COPYDATA){ - //(COPYDATASTRUCT *) lParam - //if( pCopyDataStruct->cbData == sizeof(HEVENT)) { - // HEVENT Event; - // memcpy(&Event, (HEVENT*)pCopyDataStruct->lpData, sizeof(HEVENT)); // transfer data to internal variable - //} - - Api.WinDefEx.COPYDATASTRUCT cds = new Api.WinDefEx.COPYDATASTRUCT(lParam.longValue()); - HEVENT he = new HEVENT(cds.lpData); - appendLine("msg: WM_COPYDATA" + cds.cbData); - appendLine("hwnd: " + he.hWnd + ", msg: " + he.nCode + ", wParam: " + he.wParam + ", lParam: " + he.lParam); - //System.out.println("WM_COPYDATA"); - //handle the window message here - } - //else - // System.out.println("MESSAGE: " + uMsg); - - return Api.User32Ex.instance.CallWindowProc(oldWndProc, hWnd, uMsg, wParam, lParam); - //return User32.INSTANCE.DefWindowProc(hWnd, uMsg, wParam, lParam); - } - }; - - //Set the wndproc callback on this MessageHookFrame so we can process Windows Messages - Api.User32Ex.instance.SetWindowLongPtr(myHwnd, GWLP_WNDPROC, wndProc); - - IntByReference intByRef = new IntByReference(0); - final int threadId = User32.INSTANCE.GetWindowThreadProcessId(Api.GetHandleFromString(txtTarget.getText()), intByRef); - - //int myPid = Kernel32.INSTANCE.GetCurrentProcessId(); - //HWND myHwnd = Api.FindMainWindowFromPid(myPid); - final long myHwndLong = Api.GetHandleAsLong(myHwnd); - - //System.out.println("Starting Msg Hook for " + myHwndLong + " on id " + threadId); - if (threadId == 0 ) // don't allow global - { - System.out.println("Not allowing global message hook " + threadId); - User32.INSTANCE.SetWindowLongPtr(myHwnd, GWLP_WNDPROC, oldWndProc); //restore default WNDPROC - quit = true; - return; - } - - msgHook = new MsgHook(); - if (!msgHook.setMessageHook((int) myHwndLong, threadId)) - appendLine("Error setting message hook"); - else - appendLine("Message hook started"); - - } - - public void unhook(MsgHook msgHook) { - msgHook.removeMessageHook(); - } - - //stops Keyboard hook and causes the unhook command to be called - public void stopMessageHook() { - //if (!quit) //if not hooked skip - // return; - quit = true; - appendLine("Message hook stopped"); - final HWND myHwnd = new HWND(Native.getWindowPointer(MessageHookFrame.this)); - User32.INSTANCE.SetWindowLongPtr(myHwnd, GWLP_WNDPROC, oldWndProc); //restore default WNDPROC - unhook(msgHook); - } - - public void appendLine(String txt) - { - textArea.append(txt + newLine); - textArea.setCaretPosition(textArea.getDocument().getLength()); - } -} diff --git a/src/org/synthuse/MsgHook.java b/src/org/synthuse/MsgHook.java deleted file mode 100644 index 1afc2a1..0000000 --- a/src/org/synthuse/MsgHook.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright 2014, Synthuse.org - * Released under the Apache Version 2.0 License. - * - * last modified by ejakubowski7@gmail.com -*/ - -package org.synthuse; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.PrintWriter; -import java.io.StringWriter; - - -import javax.swing.JOptionPane; - -public class MsgHook { - - public static String targetdllName = ""; - public static String dll64bitName = ""; - public static String dll32bitName = ""; - static - { - String loadFailedMsg = "Failed to load MsgHook library.\n"; - //System.out.println("SynthuseDlg.config.disableUiaBridge: " + SynthuseDlg.config.disableUiaBridge); - String archDataModel = System.getProperty("sun.arch.data.model");//32 or 64 bit - try { - targetdllName = "/MsgHook" + archDataModel + ".dll"; - dll64bitName = SaveNativeLibraryFromJar("/MsgHook64.dll"); //need to save both 32 and 64 bit dlls for hooking both types - dll32bitName = SaveNativeLibraryFromJar("/MsgHook32.dll"); - if (archDataModel.equals("32")) - System.load(dll32bitName); - else - System.load(dll64bitName); - - } catch (Exception ex) { - StringWriter sw = new StringWriter(); - PrintWriter pw = new PrintWriter(sw); - ex.printStackTrace(pw); - System.out.println(sw.toString()); - JOptionPane.showMessageDialog(null, loadFailedMsg + sw.toString() , "Native Library Load Error", JOptionPane.ERROR_MESSAGE); - } - } - - public static String SaveNativeLibraryFromJar(String path) { - // Obtain filename from path - String[] parts = path.split("/"); - String filename = (parts.length > 1) ? parts[parts.length - 1] : null; - // Split filename to prexif and suffix (extension) - String prefix = ""; - String suffix = null; - if (filename != null) { - parts = filename.split("\\.", 2); - prefix = parts[0]; - suffix = (parts.length > 1) ? "."+parts[parts.length - 1] : null; - } - File temp = null; - try { - // Prepare temporary file - temp = File.createTempFile(prefix, suffix); - temp.deleteOnExit(); - } catch(Exception e) { - e.printStackTrace(); - } - if (!temp.exists()) { //some reason the temp file wasn't create so abort - System.out.println("File " + temp.getAbsolutePath() + " does not exist."); - return ""; - } - - // Prepare buffer for data copying - byte[] buffer = new byte[1024]; - int readBytes; - // Open and check input stream - InputStream is = MsgHook.class.getResourceAsStream(path); - if (is == null) { //check if valid - System.out.println("File " + path + " was not found inside JAR."); - return ""; - } - // Open output stream and copy data between source file in JAR and the temporary file - OutputStream os = null; - try { - os = new FileOutputStream(temp); - while ((readBytes = is.read(buffer)) != -1) { - os.write(buffer, 0, readBytes); - } - os.close(); - is.close(); - } catch(Exception e) { - e.printStackTrace(); - } - // Finally, load the library - return temp.getAbsolutePath(); - } - - public native boolean initialize(String dll32bitName, String dll64bitName); - public native boolean createMsgHookWindow(); - public native boolean setMsgHookWindowTargetHwnd(int hwnd); - public native boolean setMsgHookWindowTargetPid(int pid); - public native boolean setMessageHook(int hwnd, int threadId); - public native boolean removeMessageHook(); - //public native boolean shutdown(); - - public static Thread createMsgHookWinThread(final long targetHwnd, final int targetPid) - { - Thread t = new Thread() { - public void run() { - MsgHook mh = new MsgHook(); - mh.initialize(dll32bitName, dll64bitName); - if (targetPid != 0) - mh.setMsgHookWindowTargetPid(targetPid); - if (targetHwnd != 0) - mh.setMsgHookWindowTargetHwnd((int)targetHwnd); - mh.createMsgHookWindow(); - } - }; - t.start(); - return t; - } - -} diff --git a/src/org/synthuse/PropertiesSerializer.java b/src/org/synthuse/PropertiesSerializer.java deleted file mode 100644 index f29c839..0000000 --- a/src/org/synthuse/PropertiesSerializer.java +++ /dev/null @@ -1,204 +0,0 @@ -/* - * Copyright 2014, Synthuse.org - * Released under the Apache Version 2.0 License. - * - * last modified by ejakubowski -*/ - -package org.synthuse; - -import java.io.*; -import java.util.Properties; -import java.lang.reflect.Field; - - -/* - -// example class for PropertiesSerializer -public class Configuration extends PropertiesSerializer{ - - public static final String DEFAULT_PROP_FILENAME = "./ctf.properties"; - - // General Settings - public String tests_dir = "./tests"; - public String logs_dir = "./logs"; - public int statusTimer = 2000; - - public Configuration() //needed for cloning - { - } - - public Configuration(String propertyFilename) - { - super(propertyFilename); - load(propertyFilename); - } -} - - */ - -public class PropertiesSerializer { - - protected Properties prop = new Properties(); - protected String propertyFilename = null; - - public PropertiesSerializer() - { - } - - public PropertiesSerializer(String propertyFilename) - { - this.propertyFilename = propertyFilename; - } - - public void load(String propertyFilename) - { - try - { - prop.load(new FileInputStream(propertyFilename)); - } - catch (Exception e) - { - System.out.println("Unable to load properties from file: "+propertyFilename+". Default values will be used."); - return; - } - - Field[] fields = this.getClass().getFields(); - for (int i = 0 ; i < fields.length; i++) - { - String pName = fields[i].getName(); - String pType = "String"; - try - { - pType = fields[i].get(this).getClass().getSimpleName(); - } - catch (Exception e) - { -// e.printStackTrace(); - } - final Object myProperty = prop.get(pName); - try - { - if(myProperty==null) { -// System.out.println("Property "+pName+"["+pType+"] not set; input was null"); - } else { - if (pType.equalsIgnoreCase("integer")) - fields[i].set(this, Integer.parseInt(myProperty + "")); - if (pType.equalsIgnoreCase("boolean")) - fields[i].set(this, Boolean.parseBoolean(myProperty + "")); - else - fields[i].set(this, myProperty); - System.out.println("Property "+pName+"["+pType+"] set to: "+myProperty); - } - } - catch (Exception e) - { -// e.printStackTrace(); - } - } - } - - public void save() - { - Field[] fields = this.getClass().getFields(); - for (int i = 0 ; i < fields.length; i++) - { - //fields[i].get(this); - try { - String pName = fields[i].getName(); - //String pType = fields[i].get(this).getClass().getSimpleName(); - if (fields[i].get(this) == null) - prop.setProperty(pName, ""); - else - prop.setProperty(pName, fields[i].get(this) + ""); - } catch (Exception e) { - //e.printStackTrace(); - } - } - try - { - FileOutputStream fos = new FileOutputStream(propertyFilename); - prop.store(fos, ""); - fos.flush(); - fos.close(); - } - catch (Exception e) { - e.printStackTrace(); - } - } - - public Object clone() - { - Object newObject = null; - try { - newObject = (Object)this.getClass().newInstance(); - } - catch (Exception e) - { - e.printStackTrace(); - } - Field[] fields = this.getClass().getFields(); - for (int i = 0 ; i < fields.length; i++) - { - try { - //fields[i].get(this); - //String pName = fields[i].getName(); - fields[i].set(newObject, fields[i].get(this)); - } - catch (Exception e) - { - //e.printStackTrace(); - } - } - return newObject; - } - - public boolean hasChanged() - { - boolean changes = false; - Field[] fields = this.getClass().getFields(); - for (int i = 0 ; i < fields.length; i++) - { - //fields[i].get(this); - try { - String pName = fields[i].getName(); - //String pType = fields[i].get(this).getClass().getSimpleName(); - if (prop.getProperty(pName).compareTo(fields[i].get(this)+"") != 0) - changes = true; - - } catch (Exception e) { - //e.printStackTrace(); - } - } - return changes; - } - - public String getPropertyFilename() - { - return this.propertyFilename; - } - - public void setPropertyFilename(String filename) - { - this.propertyFilename = filename; - } - - public String readValue(String propertyName) - { - String val = ""; - val = prop.getProperty(propertyName); - return val; - } - - public void writeValue(String propertyName, String propertValue) - { - prop.setProperty(propertyName, propertValue); - try { - prop.store(new FileOutputStream(propertyFilename), null); - } catch (Exception e) { - e.printStackTrace(); - } - } - -} - diff --git a/src/org/synthuse/RobotMacro.java b/src/org/synthuse/RobotMacro.java deleted file mode 100644 index dfb6bf9..0000000 --- a/src/org/synthuse/RobotMacro.java +++ /dev/null @@ -1,631 +0,0 @@ -/* - * Copyright 2014, Synthuse.org - * Released under the Apache Version 2.0 License. - * - * last modified by ejakubowski -*/ - -package org.synthuse; - -import java.awt.*; -import java.awt.event.*; - -public class RobotMacro { - - public static Exception lastException = null; - - public static boolean executeCommand(String cmd) { - Runtime runtime = Runtime.getRuntime(); - try { - runtime.exec(cmd); - } catch (Exception e) { - lastException = e; - return false; - } - return true; - } - - public static void delay(int time) { - try { - Robot robot = new Robot(); - robot.delay(time); - } catch (Exception e) { - lastException = e; - } - } - - public static void moveMouse(int x, int y) { - try { - Robot robot = new Robot(); - robot.mouseMove(x, y); - } catch (Exception e) { - lastException = e; - } - } - - public static void leftClickMouse() { - try { - Robot robot = new Robot(); - robot.mousePress(InputEvent.BUTTON1_MASK); - robot.mouseRelease(InputEvent.BUTTON1_MASK); - } catch (Exception e) { - lastException = e; - } - } - - public static void doubleClickMouse() { - try { - Robot robot = new Robot(); - robot.mousePress(InputEvent.BUTTON1_MASK); - robot.mouseRelease(InputEvent.BUTTON1_MASK); - robot.delay(100); - robot.mousePress(InputEvent.BUTTON1_MASK); - robot.mouseRelease(InputEvent.BUTTON1_MASK); - } catch (Exception e) { - lastException = e; - } - } - - public static void rightClickMouse() { - try { - //System.out.println("rightClickMouse"); - Robot robot = new Robot(); - //robot.mouseMove(200, 200); - //robot.delay(1000); - robot.mousePress(InputEvent.BUTTON3_MASK); - robot.mouseRelease(InputEvent.BUTTON3_MASK); - //System.out.println("rightClickMouse good"); - } catch (Exception e) { - lastException = e; - e.printStackTrace(); - } - } - - public static void leftMouseDown() { - try { - Robot robot = new Robot(); - robot.mousePress(InputEvent.BUTTON1_MASK); - } catch (Exception e) { - lastException = e; - } - } - - public static void leftMouseUp() { - try { - Robot robot = new Robot(); - robot.mouseRelease(InputEvent.BUTTON1_MASK); - } catch (Exception e) { - lastException = e; - } - } - - public static void rightMouseDown() { - try { - Robot robot = new Robot(); - robot.mousePress(InputEvent.BUTTON3_MASK); - } catch (Exception e) { - lastException = e; - } - } - - public static void rightMouseUp() { - try { - Robot robot = new Robot(); - robot.mouseRelease(InputEvent.BUTTON3_MASK); - } catch (Exception e) { - lastException = e; - e.printStackTrace(); - } - } - - public static void mouseMove(int x, int y) { - try { - Robot robot = new Robot(); - robot.mouseMove(x, y); - } catch (Exception e) { - lastException = e; - e.printStackTrace(); - } - } - - public static void copyKey() { - try { - Robot robot = new Robot(); - robot.keyPress(KeyEvent.VK_CONTROL); - robot.keyPress(KeyEvent.VK_C); - robot.keyRelease(KeyEvent.VK_C); - robot.keyRelease(KeyEvent.VK_CONTROL); - } catch (Exception e) { - lastException = e; - } - } - - public static void pasteKey() { - try { - Robot robot = new Robot(); - robot.keyPress(KeyEvent.VK_CONTROL); - robot.keyPress(KeyEvent.VK_V); - robot.keyRelease(KeyEvent.VK_V); - robot.keyRelease(KeyEvent.VK_CONTROL); - } catch (Exception e) { - lastException = e; - } - } - - public static void escapeKey() { - try { - Robot robot = new Robot(); - robot.keyPress(KeyEvent.VK_ESCAPE); - robot.keyRelease(KeyEvent.VK_ESCAPE); - } catch (Exception e) { - lastException = e; - } - } - - public static void functionKey(int functionNum) { - try { - Robot robot = new Robot(); - int keyCode = 0; - switch (functionNum) { - case 1: keyCode = KeyEvent.VK_F1; break; - case 2: keyCode = KeyEvent.VK_F2; break; - case 3: keyCode = KeyEvent.VK_F3; break; - case 4: keyCode = KeyEvent.VK_F4; break; - case 5: keyCode = KeyEvent.VK_F5; break; - case 6: keyCode = KeyEvent.VK_F6; break; - case 7: keyCode = KeyEvent.VK_F7; break; - case 8: keyCode = KeyEvent.VK_F8; break; - case 9: keyCode = KeyEvent.VK_F9; break; - case 10: keyCode = KeyEvent.VK_F10; break; - case 11: keyCode = KeyEvent.VK_F11; break; - case 12: keyCode = KeyEvent.VK_F12; break; - } - robot.keyPress(keyCode); - robot.keyRelease(keyCode); - } catch (Exception e) { - lastException = e; - } - } - - public static void tildeKey() { - try { - Robot robot = new Robot(); - pressKeyCodes(robot, new int[]{KeyEvent.VK_SHIFT, KeyEvent.VK_BACK_QUOTE}); - } catch (Exception e) { - lastException = e; - } - } -/* SendKeys Special Keys List -{BACKSPACE}, {BS}, or {BKSP} -{BREAK} -{CAPSLOCK} -{DELETE} or {DEL} -{DOWN} -{END} -{ENTER} or ~ -{ESC} -{HELP} -{HOME} -{INSERT} or {INS} -{LEFT} -{NUMLOCK} -{PGDN} -{PGUP} -{PRTSC} (reserved for future use) -{RIGHT} -{SCROLLLOCK} -{TAB} -{UP} -{F1} -{F2} -{F3} -{F4} -{F5} -{F6} -{F7} -{F8} -{F9} -{F10} -{F11} -{F12} -{F13} -{F14} -{F15} -{F16} -{ADD} -{SUBTRACT} -{MULTIPLY} -{DIVIDE} -{{} -{}} -SHIFT + -CTRL ^ -ALT % - - */ - - public static boolean sendKeys(String keyCommands) { - try { - Robot robot = new Robot(); - boolean specialKeyFlag = false; - String specialKey = ""; - boolean modifierKeyFlag = false; - String modifierKeys = ""; - for (int i = 0; i < keyCommands.length(); i++) { - char key = keyCommands.charAt(i); - if (specialKeyFlag) - specialKey += key; - if (key == '{' && specialKeyFlag == false) { - specialKeyFlag = true; - specialKey = "{"; - } - - if (!specialKeyFlag) { //not special key(tab,enter,...) just press normal keys and modifiers - // Modifier key logic - if (key == '+' || key == '^' || key == '%') { //shift alt or ctrl - if (!modifierKeyFlag) { - modifierKeys = key + ""; - modifierKeyFlag = true; - } - else - modifierKeys += key + ""; //append multiple modifiers - if (key == '+') - robot.keyPress(KeyEvent.VK_SHIFT); - if (key == '^') - robot.keyPress(KeyEvent.VK_CONTROL); - if (key == '%') - robot.keyPress(KeyEvent.VK_ALT); - continue; //skip to next key - } - pressKeyCodes(robot, getKeyCode(key)); - } - if (specialKeyFlag) { - if (specialKey.equals("{ENTER}")) { - specialKeyFlag = false; - pressKeyCodes(robot, new int[]{KeyEvent.VK_ENTER} ); - } - else if (specialKey.equals("{ESC}")) { - specialKeyFlag = false; - pressKeyCodes(robot, new int[]{KeyEvent.VK_ESCAPE} ); - } - else if (specialKey.equals("{HOME}")) { - specialKeyFlag = false; - pressKeyCodes(robot, new int[]{KeyEvent.VK_HOME} ); - } - else if (specialKey.equals("{END}")) { - specialKeyFlag = false; - pressKeyCodes(robot, new int[]{KeyEvent.VK_END} ); - } - else if (specialKey.equals("{PGDN}")) { - specialKeyFlag = false; - pressKeyCodes(robot, new int[]{KeyEvent.VK_PAGE_DOWN} ); - } - else if (specialKey.equals("{PGUP}")) { - specialKeyFlag = false; - pressKeyCodes(robot, new int[]{KeyEvent.VK_PAGE_UP} ); - } - else if (specialKey.equals("{TAB}")) { - specialKeyFlag = false; - pressKeyCodes(robot, new int[]{KeyEvent.VK_TAB} ); - } - else if (specialKey.equals("{UP}")) { - specialKeyFlag = false; - pressKeyCodes(robot, new int[]{KeyEvent.VK_UP} ); - } - else if (specialKey.equals("{DOWN}")) { - specialKeyFlag = false; - pressKeyCodes(robot, new int[]{KeyEvent.VK_DOWN} ); - } - else if (specialKey.equals("{LEFT}")) { - specialKeyFlag = false; - pressKeyCodes(robot, new int[]{KeyEvent.VK_LEFT} ); - } - else if (specialKey.equals("{RIGHT}")) { - specialKeyFlag = false; - pressKeyCodes(robot, new int[]{KeyEvent.VK_RIGHT} ); - } - else if (specialKey.equals("{PRTSC}")) { - specialKeyFlag = false; - pressKeyCodes(robot, new int[]{KeyEvent.VK_PRINTSCREEN} ); - } - else if (specialKey.equals("{DELETE}") || specialKey.equals("{DEL}")) { - specialKeyFlag = false; - pressKeyCodes(robot, new int[]{KeyEvent.VK_DELETE} ); - } - else if (specialKey.equals("{BACKSPACE}") || specialKey.equals("{BS}")) { - specialKeyFlag = false; - pressKeyCodes(robot, new int[]{KeyEvent.VK_BACK_SPACE} ); - } - else if (specialKey.equals("{F1}")) { - specialKeyFlag = false; - pressKeyCodes(robot, new int[]{KeyEvent.VK_F1} ); - } - else if (specialKey.equals("{F2}")) { - specialKeyFlag = false; - pressKeyCodes(robot, new int[]{KeyEvent.VK_F2} ); - } - else if (specialKey.equals("{F3}")) { - specialKeyFlag = false; - pressKeyCodes(robot, new int[]{KeyEvent.VK_F3} ); - } - else if (specialKey.equals("{F4}")) { - specialKeyFlag = false; - pressKeyCodes(robot, new int[]{KeyEvent.VK_F4} ); - } - else if (specialKey.equals("{F5}")) { - specialKeyFlag = false; - pressKeyCodes(robot, new int[]{KeyEvent.VK_F5} ); - } - else if (specialKey.equals("{F6}")) { - specialKeyFlag = false; - pressKeyCodes(robot, new int[]{KeyEvent.VK_F6} ); - } - else if (specialKey.equals("{F7}")) { - specialKeyFlag = false; - pressKeyCodes(robot, new int[]{KeyEvent.VK_F7} ); - } - else if (specialKey.equals("{F8}")) { - specialKeyFlag = false; - pressKeyCodes(robot, new int[]{KeyEvent.VK_F8} ); - } - else if (specialKey.equals("{F9}")) { - specialKeyFlag = false; - pressKeyCodes(robot, new int[]{KeyEvent.VK_F9} ); - } - else if (specialKey.equals("{F10}")) { - specialKeyFlag = false; - pressKeyCodes(robot, new int[]{KeyEvent.VK_F10} ); - } - else if (specialKey.equals("{F11}")) { - specialKeyFlag = false; - pressKeyCodes(robot, new int[]{KeyEvent.VK_F11} ); - } - else if (specialKey.equals("{F12}")) { - specialKeyFlag = false; - pressKeyCodes(robot, new int[]{KeyEvent.VK_F12} ); - } - else if (specialKey.equals("{F13}")) { - specialKeyFlag = false; - pressKeyCodes(robot, new int[]{KeyEvent.VK_F13} ); - } - else if (specialKey.equals("{F14}")) { - specialKeyFlag = false; - pressKeyCodes(robot, new int[]{KeyEvent.VK_F14} ); - } - else if (specialKey.equals("{F15}")) { - specialKeyFlag = false; - pressKeyCodes(robot, new int[]{KeyEvent.VK_F15} ); - } - else if (specialKey.equals("{F16}")) { - specialKeyFlag = false; - pressKeyCodes(robot, new int[]{KeyEvent.VK_F16} ); - } - else if (specialKey.equals("{PRTSC}")) { - specialKeyFlag = false; - pressKeyCodes(robot, new int[]{KeyEvent.VK_PRINTSCREEN} ); - } - else if (specialKey.equals("{ADD}")) { - specialKeyFlag = false; - pressKeyCodes(robot, new int[]{KeyEvent.VK_ADD} ); - } - else if (specialKey.equals("{SUBTRACT}")) { - specialKeyFlag = false; - pressKeyCodes(robot, new int[]{KeyEvent.VK_SUBTRACT} ); - } - else if (specialKey.equals("{MULTIPLY}")) { - specialKeyFlag = false; - pressKeyCodes(robot, new int[]{KeyEvent.VK_MULTIPLY} ); - } - else if (specialKey.equals("{DIVIDE}")) { - specialKeyFlag = false; - pressKeyCodes(robot, new int[]{KeyEvent.VK_DIVIDE} ); - } - else if (specialKey.equals("{PERCENT}")) { - specialKeyFlag = false; - pressKeyCodes(robot, new int[]{KeyEvent.VK_SHIFT, KeyEvent.VK_5} ); - } - else if (specialKey.equals("{CARROT}")) { - specialKeyFlag = false; - pressKeyCodes(robot, new int[]{KeyEvent.VK_SHIFT, KeyEvent.VK_6} ); - } - else if (specialKey.equals("{INSERT}")) { - specialKeyFlag = false; - pressKeyCodes(robot, new int[]{KeyEvent.VK_INSERT} ); - } - else if (specialKey.equals("{BREAK}")) { - specialKeyFlag = false; - pressKeyCodes(robot, new int[]{KeyEvent.VK_CANCEL} ); - } - else if (specialKey.equals("{BAR}")) { - specialKeyFlag = false; - pressKeyCodes(robot, new int[]{KeyEvent.VK_SHIFT, KeyEvent.VK_BACK_SLASH}); - } - else if (specialKey.equals("{{}")) { - specialKeyFlag = false; - pressKeyCodes(robot, new int[]{KeyEvent.VK_SHIFT, KeyEvent.VK_OPEN_BRACKET} ); - } - else if (specialKey.equals("{}}")) { - specialKeyFlag = false; - pressKeyCodes(robot,new int[]{KeyEvent.VK_SHIFT, KeyEvent.VK_CLOSE_BRACKET} ); - } - } - - if (modifierKeyFlag) { //time to release all the modifier keys - modifierKeyFlag = false; - for (int m = 0; m < modifierKeys.length(); m++) { - char mkey = modifierKeys.charAt(m); - if (mkey == '+') - robot.keyRelease(KeyEvent.VK_SHIFT); - if (mkey == '^') - robot.keyRelease(KeyEvent.VK_CONTROL); - if (mkey == '%') - robot.keyRelease(KeyEvent.VK_ALT); - } - modifierKeys = ""; - } - } - } catch (Exception e) { - lastException = e; - return false; - } - return true; - } - - public static boolean pressKey(char key) { - try { - Robot robot = new Robot(); - int[] keyCode = getKeyCode(key); - pressKeyCodes(robot, keyCode); - } catch (Exception e) { - lastException = e; - return false; - } - return true; - } - - public static boolean keyDown(char key) { - try { - Robot robot = new Robot(); - int[] keyCodes = getKeyCode(key); - for (int i = 0; i < keyCodes.length; i++) { - robot.keyPress(keyCodes[i]); - //System.out.println("pressed: " + keyCodes[i]); - } - } catch (Exception e) { - lastException = e; - return false; - } - return true; - } - - public static boolean keyUp(char key) { - try { - Robot robot = new Robot(); - int[] keyCodes = getKeyCode(key); - for (int i = keyCodes.length - 1; i >= 0; i--) { - robot.keyRelease(keyCodes[i]); - //System.out.println("released: " + keyCodes[i]); - } - } catch (Exception e) { - lastException = e; - return false; - } - return true; - } - - public static void pressKeyCodes(Robot robot, int[] keyCodes) { - for (int i = 0; i < keyCodes.length; i++) { - robot.keyPress(keyCodes[i]); - //System.out.println("pressed: " + keyCodes[i]); - } - //robot.delay(50); - for (int i = keyCodes.length - 1; i >= 0; i--) { - robot.keyRelease(keyCodes[i]); - //System.out.println("released: " + keyCodes[i]); - } - } - - public static int[] getKeyCode(char key) { - switch (key) { - case 'a': return(new int[]{KeyEvent.VK_A}); - case 'b': return(new int[]{KeyEvent.VK_B}); - case 'c': return(new int[]{KeyEvent.VK_C}); - case 'd': return(new int[]{KeyEvent.VK_D}); - case 'e': return(new int[]{KeyEvent.VK_E}); - case 'f': return(new int[]{KeyEvent.VK_F}); - case 'g': return(new int[]{KeyEvent.VK_G}); - case 'h': return(new int[]{KeyEvent.VK_H}); - case 'i': return(new int[]{KeyEvent.VK_I}); - case 'j': return(new int[]{KeyEvent.VK_J}); - case 'k': return(new int[]{KeyEvent.VK_K}); - case 'l': return(new int[]{KeyEvent.VK_L}); - case 'm': return(new int[]{KeyEvent.VK_M}); - case 'n': return(new int[]{KeyEvent.VK_N}); - case 'o': return(new int[]{KeyEvent.VK_O}); - case 'p': return(new int[]{KeyEvent.VK_P}); - case 'q': return(new int[]{KeyEvent.VK_Q}); - case 'r': return(new int[]{KeyEvent.VK_R}); - case 's': return(new int[]{KeyEvent.VK_S}); - case 't': return(new int[]{KeyEvent.VK_T}); - case 'u': return(new int[]{KeyEvent.VK_U}); - case 'v': return(new int[]{KeyEvent.VK_V}); - case 'w': return(new int[]{KeyEvent.VK_W}); - case 'x': return(new int[]{KeyEvent.VK_X}); - case 'y': return(new int[]{KeyEvent.VK_Y}); - case 'z': return(new int[]{KeyEvent.VK_Z}); - case 'A': return(new int[]{KeyEvent.VK_SHIFT, KeyEvent.VK_A}); - case 'B': return(new int[]{KeyEvent.VK_SHIFT, KeyEvent.VK_B}); - case 'C': return(new int[]{KeyEvent.VK_SHIFT, KeyEvent.VK_C}); - case 'D': return(new int[]{KeyEvent.VK_SHIFT, KeyEvent.VK_D}); - case 'E': return(new int[]{KeyEvent.VK_SHIFT, KeyEvent.VK_E}); - case 'F': return(new int[]{KeyEvent.VK_SHIFT, KeyEvent.VK_F}); - case 'G': return(new int[]{KeyEvent.VK_SHIFT, KeyEvent.VK_G}); - case 'H': return(new int[]{KeyEvent.VK_SHIFT, KeyEvent.VK_H}); - case 'I': return(new int[]{KeyEvent.VK_SHIFT, KeyEvent.VK_I}); - case 'J': return(new int[]{KeyEvent.VK_SHIFT, KeyEvent.VK_J}); - case 'K': return(new int[]{KeyEvent.VK_SHIFT, KeyEvent.VK_K}); - case 'L': return(new int[]{KeyEvent.VK_SHIFT, KeyEvent.VK_L}); - case 'M': return(new int[]{KeyEvent.VK_SHIFT, KeyEvent.VK_M}); - case 'N': return(new int[]{KeyEvent.VK_SHIFT, KeyEvent.VK_N}); - case 'O': return(new int[]{KeyEvent.VK_SHIFT, KeyEvent.VK_O}); - case 'P': return(new int[]{KeyEvent.VK_SHIFT, KeyEvent.VK_P}); - case 'Q': return(new int[]{KeyEvent.VK_SHIFT, KeyEvent.VK_Q}); - case 'R': return(new int[]{KeyEvent.VK_SHIFT, KeyEvent.VK_R}); - case 'S': return(new int[]{KeyEvent.VK_SHIFT, KeyEvent.VK_S}); - case 'T': return(new int[]{KeyEvent.VK_SHIFT, KeyEvent.VK_T}); - case 'U': return(new int[]{KeyEvent.VK_SHIFT, KeyEvent.VK_U}); - case 'V': return(new int[]{KeyEvent.VK_SHIFT, KeyEvent.VK_V}); - case 'W': return(new int[]{KeyEvent.VK_SHIFT, KeyEvent.VK_W}); - case 'X': return(new int[]{KeyEvent.VK_SHIFT, KeyEvent.VK_X}); - case 'Y': return(new int[]{KeyEvent.VK_SHIFT, KeyEvent.VK_Y}); - case 'Z': return(new int[]{KeyEvent.VK_SHIFT, KeyEvent.VK_Z}); - case '`': return(new int[]{KeyEvent.VK_BACK_QUOTE}); - case '0': return(new int[]{KeyEvent.VK_0}); - case '1': return(new int[]{KeyEvent.VK_1}); - case '2': return(new int[]{KeyEvent.VK_2}); - case '3': return(new int[]{KeyEvent.VK_3}); - case '4': return(new int[]{KeyEvent.VK_4}); - case '5': return(new int[]{KeyEvent.VK_5}); - case '6': return(new int[]{KeyEvent.VK_6}); - case '7': return(new int[]{KeyEvent.VK_7}); - case '8': return(new int[]{KeyEvent.VK_8}); - case '9': return(new int[]{KeyEvent.VK_9}); - case '-': return(new int[]{KeyEvent.VK_MINUS}); - case '=': return(new int[]{KeyEvent.VK_EQUALS}); - case '~': return(new int[]{KeyEvent.VK_ENTER});//return(new int[]{KeyEvent.VK_SHIFT, KeyEvent.VK_BACK_QUOTE}); - case '!': return(new int[]{KeyEvent.VK_SHIFT, KeyEvent.VK_1}); - case '@': return(new int[]{KeyEvent.VK_SHIFT, KeyEvent.VK_2}); - case '#': return(new int[]{KeyEvent.VK_SHIFT, KeyEvent.VK_3}); - case '$': return(new int[]{KeyEvent.VK_SHIFT, KeyEvent.VK_4}); - case '%': return(new int[]{KeyEvent.VK_SHIFT, KeyEvent.VK_5}); - case '^': return(new int[]{KeyEvent.VK_SHIFT, KeyEvent.VK_6}); - case '&': return(new int[]{KeyEvent.VK_SHIFT, KeyEvent.VK_7}); - case '*': return(new int[]{KeyEvent.VK_SHIFT, KeyEvent.VK_8}); - case '(': return(new int[]{KeyEvent.VK_SHIFT, KeyEvent.VK_9}); - case ')': return(new int[]{KeyEvent.VK_SHIFT, KeyEvent.VK_0}); - case '_': return(new int[]{KeyEvent.VK_SHIFT, KeyEvent.VK_MINUS}); - case '+': return(new int[]{KeyEvent.VK_SHIFT, KeyEvent.VK_EQUALS}); - case '\t': return(new int[]{KeyEvent.VK_TAB}); - case '\n': return(new int[]{KeyEvent.VK_ENTER}); - case '[': return(new int[]{KeyEvent.VK_OPEN_BRACKET}); - case ']': return(new int[]{KeyEvent.VK_CLOSE_BRACKET}); - case '\\': return(new int[]{KeyEvent.VK_BACK_SLASH}); - case '{': return(new int[]{KeyEvent.VK_SHIFT, KeyEvent.VK_OPEN_BRACKET}); - case '}': return(new int[]{KeyEvent.VK_SHIFT, KeyEvent.VK_CLOSE_BRACKET}); - case '|': return(new int[]{KeyEvent.VK_SHIFT, KeyEvent.VK_BACK_SLASH}); - case ';': return(new int[]{KeyEvent.VK_SEMICOLON}); - case ':': return(new int[]{KeyEvent.VK_SHIFT, KeyEvent.VK_SEMICOLON}); - case '\'': return(new int[]{KeyEvent.VK_QUOTE}); - case '"': return(new int[]{KeyEvent.VK_QUOTEDBL}); - case ',': return(new int[]{KeyEvent.VK_COMMA}); - case '<': return(new int[]{KeyEvent.VK_LESS}); - case '.': return(new int[]{KeyEvent.VK_PERIOD}); - case '>': return(new int[]{KeyEvent.VK_GREATER}); - case '/': return(new int[]{KeyEvent.VK_SLASH}); - case '?': return(new int[]{KeyEvent.VK_SHIFT, KeyEvent.VK_SLASH}); // needs Shift - case ' ': return(new int[]{KeyEvent.VK_SPACE}); - default: - throw new IllegalArgumentException("Cannot find Key Code for character " + key); - } - } -} diff --git a/src/org/synthuse/StatusWindow.java b/src/org/synthuse/StatusWindow.java deleted file mode 100644 index 1623ef8..0000000 --- a/src/org/synthuse/StatusWindow.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2014, Synthuse.org - * Released under the Apache Version 2.0 License. - * - * last modified by ejakubowski -*/ - -package org.synthuse; - -import java.awt.Color; -import java.awt.Dimension; -import java.awt.FlowLayout; -import java.awt.Font; -import java.awt.Toolkit; -import java.util.Timer; -import java.util.TimerTask; - -import javax.swing.JLabel; -import javax.swing.JWindow; - - -public class StatusWindow extends JWindow { - - private static final long serialVersionUID = 1L; - public static int FONT_SIZE = 14; - public static int FONT_BOLD = Font.BOLD; //Font.PLAIN - public static int Y_BOTTOM_OFFSET = -100; - public static Color BACKGROUND_COLOR = Color.yellow; - public static Color FOREGROUND_COLOR = Color.black; - //private int displayTime = -1; - //private String displayText = ""; - public StatusWindow(String lblText, int displayTime) { - super(); - //this.displayTime = displayTime; - //this.displayText = lblText; - //this.setLayout(new FlowLayout()); - JLabel lbl = new JLabel(lblText); - lbl.setFont(new Font(lbl.getName(), FONT_BOLD, FONT_SIZE)); - lbl.setOpaque(true); //background isn't painted without this - lbl.setBackground(BACKGROUND_COLOR); - lbl.setForeground(FOREGROUND_COLOR); - this.getContentPane().setLayout(new FlowLayout()); - this.getContentPane().add(lbl); - this.pack(); - this.setVisible(true); - // - if (displayTime > 0) { - Timer timer = new Timer(true); - timer.schedule(new TimerTask() { - @Override - public void run() { - StatusWindow.this.dispose(); - } - }, displayTime); - } - } - - @Override - public void setVisible(final boolean visible) { - super.setVisible(visible); - // ...and bring window to the front.. in a strange and weird way - if (visible) { - super.setAlwaysOnTop(true); - super.toFront(); - super.requestFocus(); - Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); - //this.setLocation(dim.width/2-this.getSize().width/2, dim.height/2-this.getSize().height/2); - this.setLocation(dim.width/2-this.getSize().width/2, dim.height + Y_BOTTOM_OFFSET ); - } - } - -} diff --git a/src/org/synthuse/SynthuseConfigDialog.java b/src/org/synthuse/SynthuseConfigDialog.java deleted file mode 100755 index 3c4fa25..0000000 --- a/src/org/synthuse/SynthuseConfigDialog.java +++ /dev/null @@ -1,45 +0,0 @@ -package org.synthuse; - -import javax.swing.JDialog; -import javax.swing.JFrame; -import javax.swing.SwingUtilities; - -import org.synthuse.controllers.SynthuseConfigDialogControllers; -import org.synthuse.views.SynthuseConfigPanel; - -public class SynthuseConfigDialog extends JDialog { - - /** - * - */ - private static final long serialVersionUID = -4877764256323621418L; - - private Config theConfig; //Model - private final SynthuseConfigPanel theSynthuseConfigPanel; //View - - public SynthuseConfigDialog(JFrame aParentFrame, Config aConfig) { - super(aParentFrame); - - this.setConfig(aConfig); - - this.setTitle("Synthuse Properties"); - - theSynthuseConfigPanel = new SynthuseConfigPanel(); - - SynthuseConfigDialogControllers.bindActionControllers(theSynthuseConfigPanel,theConfig); - - this.getContentPane().add(theSynthuseConfigPanel); - this.setSize(492, 260); - - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - SynthuseConfigDialogControllers.initializeUI(theSynthuseConfigPanel,theConfig); - } - }); - } - - synchronized private void setConfig(Config aConfig) { - theConfig = aConfig; - } -} diff --git a/src/org/synthuse/SynthuseDlg.java b/src/org/synthuse/SynthuseDlg.java deleted file mode 100644 index 928442b..0000000 --- a/src/org/synthuse/SynthuseDlg.java +++ /dev/null @@ -1,579 +0,0 @@ -/* - * Copyright 2014, Synthuse.org - * Released under the Apache Version 2.0 License. - * - * last modified by ejakubowski -*/ - -package org.synthuse; - -import java.awt.BorderLayout; -import java.awt.EventQueue; -import java.awt.GridBagConstraints; -import java.awt.GridBagLayout; -import java.awt.Insets; -import java.awt.Point; -import java.awt.Rectangle; -import java.awt.Toolkit; - -import javax.swing.border.EmptyBorder; -import javax.swing.*; - -import java.awt.Component; -import java.awt.Dimension; - -/* -import com.jgoodies.forms.layout.FormLayout; -import com.jgoodies.forms.layout.ColumnSpec; -import com.jgoodies.forms.layout.RowSpec; -import com.jgoodies.forms.factories.FormFactory; -*/ -import com.sun.jna.platform.win32.WinDef.HWND; -import com.sun.jna.ptr.PointerByReference; - -import java.awt.FlowLayout; -import java.awt.event.ActionListener; -import java.awt.event.ActionEvent; -import java.awt.event.KeyAdapter; -import java.awt.event.KeyEvent; -import java.awt.event.WindowAdapter; -import java.awt.event.WindowEvent; -import java.util.ArrayList; -import java.util.List; - -import org.synthuse.Api.User32Ex; -import org.synthuse.DragTarget.dragEvents; - - -//public class SynthuseDlg extends JDialog { -public class SynthuseDlg extends JFrame { - /** - * - */ - public static String VERSION_STR = "1.2.4"; - - public static String RES_STR_MAIN_ICON = "/org/synthuse/img/gnome-robots.png"; - public static String RES_STR_REFRESH_IMG = "/org/synthuse/img/rapidsvn.png"; - public static String RES_STR_TESTIDE_IMG = "/org/synthuse/img/applications-education.png"; - public static String RES_STR_HELP_IMG = "/org/synthuse/img/help-3.png"; - public static String RES_STR_TARGET_IMG = "/org/synthuse/img/bullseye-logo-th18x18.png"; - public static String RES_STR_FIND_IMG = "/org/synthuse/img/edit-find-3.png"; - public static String RES_STR_SETACTION_IMG = "/org/synthuse/img/document-new-5.png"; - public static String RES_STR_CANCEL_IMG = "/org/synthuse/img/document-close-2.png"; - public static String RES_STR_PREFERENCES_IMG = "/org/synthuse/img/preferences-desktop.png"; - - private static final int STRUT_WIDTH = 10; - - public static List actionListQueue = new ArrayList(); - private static final long serialVersionUID = 1L; - private XpathManager.Events xpathEvents = null; - private JPanel contentPane; - private JLabel lblStatus; - private JButton btnRefresh; - private JTextPane textPane; - private JButton btnSetAction; - private JButton btnCancel; - private JButton btnFind; - public static Config config = new Config(Config.DEFAULT_PROP_FILENAME); - private String dialogResult = ""; - private String lastDragHwnd = ""; - private int lastDragPid = 0; - private String lastRuntimeId =""; - private JComboBox cmbXpath; - private JButton btnTestIde; - private JButton btnAdvanced; - - private TestIdeFrame testIde = null; - protected SynthuseConfigDialog configDialog=null; - //private MessageHookFrame msgHook = null; - private int targetX; - private int targetY; - private UiaBridge uiabridge = null; - - /** - * Launch the application. - */ - public static void main(String[] args) { - EventQueue.invokeLater(new Runnable() { - public void run() { - try { - SynthuseDlg frame = new SynthuseDlg(); - frame.setVisible(true); - } catch (Exception e) { - e.printStackTrace(); - } - } - }); - } - - /** - * Create the frame. - */ - public SynthuseDlg() { - setIconImage(Toolkit.getDefaultToolkit().getImage(SynthuseDlg.class.getResource(RES_STR_MAIN_ICON))); - //setModal(true); - setTitle("Synthuse"); - setBounds(100, 100, 827, 420); - contentPane = new JPanel(); - contentPane.setBorder(new EmptyBorder(5, 5, 5, 5)); - contentPane.setLayout(new BorderLayout(0, 0)); - setContentPane(contentPane); - - JToolBar toolBar = new JToolBar(); - contentPane.add(toolBar, BorderLayout.NORTH); - - JRadioButton rdbtnWindows = new JRadioButton("Windows Enumerated Xml"); - rdbtnWindows.setSelected(true); - toolBar.add(rdbtnWindows); - - Component horizontalStrut = Box.createHorizontalStrut(STRUT_WIDTH); - toolBar.add(horizontalStrut); - - JRadioButton rdbtnUrl = new JRadioButton("Url: "); - rdbtnUrl.setEnabled(false); - toolBar.add(rdbtnUrl); - - // Group the radio buttons. - ButtonGroup group = new ButtonGroup(); - group.add(rdbtnWindows); - group.add(rdbtnUrl); - - JComboBox cmbUrl = new JComboBox(); - cmbUrl.setEnabled(false); - cmbUrl.setEditable(true); - toolBar.add(cmbUrl); - - Component horizontalStrut_1 = Box.createHorizontalStrut(STRUT_WIDTH); - toolBar.add(horizontalStrut_1); - - btnRefresh = new JButton(" Refresh "); - btnRefresh.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent arg0) { - //WindowsEnumeratedXml wex = new WindowsEnumeratedXml(textPane, lblStatus); - //wex.run(); - WindowsEnumeratedXml.getXmlThreaded(textPane, lblStatus); - } - }); - btnRefresh.setIcon(new ImageIcon(SynthuseDlg.class.getResource(RES_STR_REFRESH_IMG))); - toolBar.add(btnRefresh); - - Component horizontalStrut_3 = Box.createHorizontalStrut(STRUT_WIDTH); - toolBar.add(horizontalStrut_3); - - btnTestIde = new JButton("Test IDE"); - btnTestIde.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent arg0) { - if (testIde == null) { - testIde = new TestIdeFrame(); - if (SynthuseDlg.actionListQueue.size() > 0) { // if stuff is already in the queue add it to the test ide - for (String action : SynthuseDlg.actionListQueue) { - testIde.txtTest.append(action + "\n"); - } - } - } - testIde.setVisible(true); - } - }); - btnTestIde.setIcon(new ImageIcon(SynthuseDlg.class.getResource(RES_STR_TESTIDE_IMG))); - toolBar.add(btnTestIde); - - Component horizontalStrut_2 = Box.createHorizontalStrut(STRUT_WIDTH); - toolBar.add(horizontalStrut_2); - - btnAdvanced = new JButton("Advanced"); - btnAdvanced.setIcon(new ImageIcon(SynthuseDlg.class.getResource(RES_STR_PREFERENCES_IMG))); - btnAdvanced.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - JPopupMenu menu = new JPopupMenu(); - ActionListener menuListener = new ActionListener() { - public void actionPerformed(ActionEvent event) { - //System.out.println("Popup menu item [" + event.getActionCommand() + "] was pressed."); - if (event.getActionCommand() == "Message Hook"){ - /* - if (msgHook == null) - msgHook = new MessageHookFrame(); - msgHook.setVisible(true); - msgHook.txtTarget.setText(lastDragHwnd); - */ - long lastHwndLong = 0; - try { - //lastHwndLong = Long.parseLong(lastDragHwnd); - } catch (Exception ex) { - } - MsgHook.createMsgHookWinThread(lastHwndLong, lastDragPid); - - } - if (event.getActionCommand() == "Settings") { - if(configDialog==null) { - createConfigDialog(); - } - configDialog.setVisible(true); - - } - } - }; - JMenuItem mnMessageHook = new JMenuItem("Message Hook"); - mnMessageHook.addActionListener(menuListener); - menu.add(mnMessageHook); - JMenuItem mnSettings = new JMenuItem("Settings"); - mnSettings.setEnabled(true); - mnSettings.addActionListener(menuListener); - menu.add(mnSettings); - - Component c = (Component) e.getSource(); - menu.show(c, -1, c.getHeight()); - } - }); - toolBar.add(btnAdvanced); - - Component horizontalStrut_4 = Box.createHorizontalStrut(STRUT_WIDTH); - toolBar.add(horizontalStrut_4); - - JButton helpBtn = new JButton("Help"); - helpBtn.setIcon(new ImageIcon(SynthuseDlg.class.getResource(RES_STR_HELP_IMG))); - helpBtn.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent arg0) { - String about = ""; - about += "Synthuse Version " + VERSION_STR + " created by Edward Jakubowski ejakubowski7@gmail.com\n\n"; - - about += "Application information: \n"; - about += " alwaysOnTop - " + config.isAlwaysOnTop() + "\n"; - about += " refreshKey - " + config.refreshKey + "\n"; - about += " targetKey - " + config.targetKey + "\n"; - about += " disableUiaBridge - " + config.isUiaBridgeDisabled() + "\n"; - about += " disableFiltersUia - " + config.isFilterUiaDisabled() + "\n"; - - about += " Synthuse location - " + SynthuseDlg.class.getProtectionDomain().getCodeSource().getLocation().toString(); - - about += "\n\nSystem information: \n"; - about += " Java version - " + System.getProperty("java.version") + "\n"; - about += " Java home - " + System.getProperty("java.home") + "\n"; - about += " OS Name - " + System.getProperty("os.name") + "\n"; - about += " OS Arch - " + System.getProperty("os.arch") + "\n"; - String jclasspath = System.getProperty("java.class.path"); - jclasspath = jclasspath.replaceAll(";", ";\n "); - if (!System.getProperty("os.name").startsWith("Windows")) - jclasspath = jclasspath.replaceAll(":", ":\n "); - if (jclasspath.length() > 500) - jclasspath = jclasspath.substring(0, 500) + "..."; - about += " Java class path - " + jclasspath + "\n\n"; - JOptionPane.showMessageDialog(SynthuseDlg.this, about , "About", JOptionPane.QUESTION_MESSAGE); - } - }); - toolBar.add(helpBtn); - - JSplitPane splitPane = new JSplitPane(); - splitPane.setOrientation(JSplitPane.VERTICAL_SPLIT); - contentPane.add(splitPane, BorderLayout.CENTER); - - JPanel panel = new JPanel(); - panel.setMinimumSize(new Dimension(20, 35)); - splitPane.setLeftComponent(panel); - /* - panel.setLayout(new FormLayout(new ColumnSpec[] { - FormFactory.RELATED_GAP_COLSPEC, - ColumnSpec.decode("left:max(11dlu;default)"), - FormFactory.RELATED_GAP_COLSPEC, - ColumnSpec.decode("left:default"), - FormFactory.RELATED_GAP_COLSPEC, - FormFactory.DEFAULT_COLSPEC, - FormFactory.RELATED_GAP_COLSPEC, - FormFactory.DEFAULT_COLSPEC, - FormFactory.RELATED_GAP_COLSPEC, - FormFactory.DEFAULT_COLSPEC,}, - new RowSpec[] { - FormFactory.RELATED_GAP_ROWSPEC, - RowSpec.decode("default:grow"),})); - */ - panel.setLayout(new GridBagLayout()); - - GridBagConstraints c = new GridBagConstraints(); - c.fill = GridBagConstraints.HORIZONTAL; - c.weightx = 0.5; - c.gridwidth = 2; - c.gridx = 0; - c.gridy = 0; - c.insets = new Insets(3,3,3,3); // add padding around objects - - final DragTarget lblTarget = new DragTarget(); - - lblTarget.setHorizontalAlignment(SwingConstants.CENTER); - final ImageIcon imageIcon = new ImageIcon(SynthuseDlg.class.getResource(RES_STR_TARGET_IMG)); - lblTarget.setMinimumSize(new Dimension(imageIcon.getIconWidth(), imageIcon.getIconHeight())); - lblTarget.setIcon(imageIcon); - panel.add(lblTarget, c); - - btnFind = new JButton("Find"); - btnFind.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent arg0) { - String xpathItem = cmbXpath.getSelectedItem().toString(); - int matches = XpathManager.nextXpathMatch(xpathItem, textPane, lblStatus, false); - if (matches < 0) //check for an error - return; //don't save bad xpath to combobox - if (config.xpathList == null) - config.xpathList = ""; - if (!config.xpathList.contains(xpathItem + "\u00ba")){ - config.xpathList += xpathItem + "\u00ba"; - refreshDatabinding(); - cmbXpath.setSelectedItem(xpathItem); - } - } - }); - - cmbXpath = new JComboBox(); - cmbXpath.setPreferredSize(new Dimension(440, 20));//fix the width of the combobox - cmbXpath.setPrototypeDisplayValue("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");//fix the width of the combobox - cmbXpath.setEditable(true); - cmbXpath.getEditor().getEditorComponent().addKeyListener(new KeyAdapter() { - @Override - public void keyReleased(KeyEvent event) { - if (event.getKeyChar() == KeyEvent.VK_ENTER) { - btnFind.doClick(); - } - } - }); - c.gridwidth = 1; - c.gridx = 3; - panel.add(cmbXpath, c); - btnFind.setIcon(new ImageIcon(SynthuseDlg.class.getResource(RES_STR_FIND_IMG))); - c.gridwidth = 1; - c.gridx = 4; - panel.add(btnFind, c); - - - btnSetAction = new JButton("Set Action"); - btnSetAction.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - CommandPopupMenu menu = new CommandPopupMenu(); - final String xpathItem = cmbXpath.getSelectedItem().toString(); - menu.events = new CommandPopupMenu.menuEvents() { - @Override - public void menuItemClicked(String command, int paramCount, boolean useXpath, ActionEvent e) { - String actionStr = CommandPopupMenu.buildSkeletonCommand(command, paramCount, xpathItem, useXpath); - SynthuseDlg.actionListQueue.add(actionStr); - lblStatus.setText("Setting Action: " + actionStr); - if (testIde != null) - testIde.txtTest.append(actionStr + "\n"); - } - }; - Component c = (Component) e.getSource(); - menu.show(c, -1, c.getHeight()); - } - }); - btnSetAction.setIcon(new ImageIcon(SynthuseDlg.class.getResource(RES_STR_SETACTION_IMG))); - c.gridwidth = 1; - c.gridx = 5; - panel.add(btnSetAction, c); - - btnCancel = new JButton("Cancel"); - btnCancel.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent arg0) { - dialogResult = ""; - SynthuseDlg.this.disposeWindow(); - } - }); - btnCancel.setIcon(new ImageIcon(SynthuseDlg.class.getResource(RES_STR_CANCEL_IMG))); - c.gridwidth = 1; - c.gridx = 6; - panel.add(btnCancel, c); - - JScrollPane scrollPane = new JScrollPane(); - splitPane.setRightComponent(scrollPane); - - textPane = new JTextPane(); - textPane.setEditable(false); - textPane.setEditorKitForContentType("text/xml", new XmlEditorKit()); - textPane.setContentType("text/xml"); - - scrollPane.setViewportView(textPane); - - JPanel panel_1 = new JPanel(); - FlowLayout flowLayout = (FlowLayout) panel_1.getLayout(); - flowLayout.setAlignment(FlowLayout.LEFT); - panel_1.setMinimumSize(new Dimension(20, 20)); - contentPane.add(panel_1, BorderLayout.SOUTH); - - lblStatus = new JLabel("Status:"); - lblStatus.setHorizontalAlignment(SwingConstants.LEFT); - lblStatus.setVerticalAlignment(SwingConstants.TOP); - panel_1.add(lblStatus); - xpathEvents = new XpathManager.Events() { - @Override - public void statusChanged(String status) { - lblStatus.setText(status); - } - @Override - public void executionCompleted(Object input, final String results) { //buildXpathStatementThreaded finished, with results being the xpath statement - if (input instanceof HWND) { // in case thread takes long time to process - lastDragHwnd = Api.GetHandleAsString((HWND)input); - } - SwingUtilities.invokeLater(new Runnable() {//swing components are not thread safe, this will run on Swings event dispatch thread - public void run() { - XpathManager.nextXpathMatch(results, textPane, lblStatus, true); - cmbXpath.setSelectedItem(results); - } - }); - - } - }; - - lblTarget.events = new dragEvents() { - public void dragStarted(JComponent c) { - //might be nice to minimize this window, if we weren't displaying realtime information about each window - } - public void dragMouseMoved(int x, int y) { - targetX = x; - targetY = y; - targetDragged(); - } - public void dropped(JComponent c) { - lastDragHwnd = ""; //sometimes with multithreaded the order becomes incorrect, so we may want to refresh this on dropped. - targetDragged(); - } - }; - - this.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); - this.addWindowListener(new WindowAdapter() { - @Override - public void windowClosing(WindowEvent arg0) { - //System.out.println("synthuse window closed"); - KeyboardHook.stopKeyboardHook(); //stop keyboard hook - config.save(); - SynthuseDlg.this.dispose(); // force app to close - } - }); - - initializeHotKeys(); - - btnRefresh.doClick(); - //uiabridge = new UiaBridge(); - //uiabridge.useCachedRequests(false); - refreshDatabinding(); - super.setAlwaysOnTop(config.isAlwaysOnTop()); - } - - /* - @Override - public void setVisible(final boolean visible) { - // make sure that frame is marked as not disposed if it is asked to be visible - if (visible) { - //setDisposed(false); - } - // let's handle visibility... - if (!visible || !isVisible()) { // have to check this condition simply because super.setVisible(true) invokes toFront if frame was already visible - super.setVisible(visible); - } - // ...and bring frame to the front.. in a strange and weird way - if (visible) { - int state = super.getExtendedState(); - state &= ~JFrame.ICONIFIED; - super.setExtendedState(state); - super.setAlwaysOnTop(true); - super.toFront(); - super.requestFocus(); - super.setAlwaysOnTop(false); - } - } - */ - - public String showDialog() { - //this.setModal(true); - Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); - this.setLocation(dim.width/2-this.getSize().width/2, dim.height/2-this.getSize().height/2); - this.setVisible(true); - return dialogResult;// this gets returned immediately - } - - public void refreshDatabinding() { - if (config.xpathList != null) - cmbXpath.setModel(new DefaultComboBoxModel(config.xpathList.split("\u00ba"))); - if (config.xpathHightlight != null) - XmlEditorKit.TAG_HIGHLIGHTED = config.xpathHightlight; - } - - private void initializeHotKeys() - { - KeyboardHook.clearKeyEvent(); - KeyboardHook.addKeyEvent(config.getRefreshKeyCode(), true, true, false);// refresh xml when CTRL+SHIFT+3 is pressed - KeyboardHook.addKeyEvent(config.getTargetKeyCode(), true, true, false);// target window when CTRL+SHIFT+~ is pressed - //add global hook and event - KeyboardHook.StartKeyboardHookThreaded(new KeyboardHook.KeyboardEvents() { - @Override - public void keyPressed(KeyboardHook.TargetKeyPress target) { - //System.out.println("target key pressed " + target.targetKeyCode); - if (target.targetKeyCode == config.getRefreshKeyCode()){ - SwingUtilities.invokeLater(new Runnable() {//swing components are not thread safe, this will run on Swings event dispatch thread - public void run() { - btnRefresh.doClick(); - } - }); - } - if (target.targetKeyCode == config.getTargetKeyCode()){ - SwingUtilities.invokeLater(new Runnable() {//swing components are not thread safe, this will run on Swings event dispatch thread - public void run() { - //if (!SynthuseDlg.config.isUiaBridgeDisabled()) - // uiabridge.initialize("");//need to re-initialize because it might be in a different thread. - Point p = Api.getCursorPos(); - targetX = p.x; - targetY = p.y; - targetDragged(); - } - }); - - } - } - }); - } - - public void targetDragged() { - HWND hwnd = Api.getWindowFromCursorPos();//new Point(targetX,targetY) - String handleStr = Api.GetHandleAsString(hwnd); - String classStr = WindowsEnumeratedXml.escapeXmlAttributeValue(Api.getWindowClassName(hwnd)); - String parentStr = Api.GetHandleAsString(User32Ex.instance.GetParent(hwnd)); - PointerByReference pointer = new PointerByReference(); - User32Ex.instance.GetWindowThreadProcessId(hwnd, pointer); - int pid = pointer.getPointer().getInt(0); - - String enumProperties = ""; - if (!SynthuseDlg.config.isUiaBridgeDisabled()) - { - //System.out.println("useCachedRequests false"); - if (uiabridge == null) - uiabridge = new UiaBridge(); - uiabridge.useCachedRequests(false); - enumProperties = uiabridge.getWindowInfo(targetX, targetY, WindowInfo.UIA_PROPERTY_LIST_ADV); - } - String runtimeId = WindowInfo.getRuntimeIdFromProperties(enumProperties); - String framework = WindowInfo.getFrameworkFromProperties(enumProperties); - Rectangle rect = UiaBridge.getBoundaryRect(enumProperties); - Point offsetPoint = WindowInfo.findOffset(rect, targetX, targetY); - lblStatus.setText("rid:" + runtimeId + " " + framework + " class: " + classStr + " hWnd: " + handleStr + " parent: " + parentStr + " X,Y (" + targetX + ", " + targetY + ") offset: " + offsetPoint.x + ", " + offsetPoint.y); - if (!lastDragHwnd.equals(handleStr) || !lastRuntimeId.equals(runtimeId)) { - if (!lastDragHwnd.isEmpty()) { - Api.refreshWindow(Api.GetHandleFromString(lastDragHwnd)); - } - lastDragHwnd = handleStr; - lastRuntimeId = runtimeId; - lastDragPid = pid; - //lastDragHwnd = (hwnd + ""); - if (framework.equals(UiaBridge.FRAMEWORK_ID_WPF) || framework.equals(UiaBridge.FRAMEWORK_ID_SILVER)) - {// WPF and Silverlight apps don't expose their child windows boundaries the same as win32 apps - Api.highlightWindow(Api.User32Ex.instance.GetDesktopWindow(), rect.x, rect.y, rect.x + rect.width, rect.y + rect.height); - } - else - Api.highlightWindow(hwnd); - XpathManager.buildXpathStatementThreaded(hwnd, enumProperties, textPane, xpathEvents); - } - } - - public void disposeWindow() - { - WindowEvent closingEvent = new WindowEvent(this, WindowEvent.WINDOW_CLOSING); - Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(closingEvent); - } - - private void createConfigDialog() { - configDialog=new SynthuseConfigDialog(this, config); - configDialog.setLocationRelativeTo(null); - } -} diff --git a/src/org/synthuse/TestIdeFrame.java b/src/org/synthuse/TestIdeFrame.java deleted file mode 100644 index aa14ddd..0000000 --- a/src/org/synthuse/TestIdeFrame.java +++ /dev/null @@ -1,221 +0,0 @@ -/* - * Copyright 2014, Synthuse.org - * Released under the Apache Version 2.0 License. - * - * last modified by ejakubowski -*/ - -package org.synthuse; - -import java.awt.BorderLayout; - -import javax.swing.JFrame; -import javax.swing.JPanel; -import javax.swing.border.EmptyBorder; -import javax.swing.filechooser.FileNameExtensionFilter; -import javax.swing.ImageIcon; -import javax.swing.JFileChooser; -import javax.swing.JToolBar; -import javax.swing.JButton; -import javax.swing.JScrollPane; -import javax.swing.JTextArea; -import javax.swing.WindowConstants; - -import java.awt.datatransfer.Clipboard; -import java.awt.datatransfer.StringSelection; -import java.awt.event.ActionListener; -import java.awt.event.ActionEvent; -import java.awt.event.WindowAdapter; -import java.awt.event.WindowEvent; -import java.awt.Toolkit; -import java.io.*; - -import javax.swing.JLabel; - -public class TestIdeFrame extends JFrame { - - public static String RES_STR_MAIN_ICON = "/org/synthuse/img/applications-education.png"; - public static String RES_STR_STOP_IMG = "/org/synthuse/img/dialog-close.png"; - public static String RES_STR_RUN_IMG = "/org/synthuse/img/arrow-right-3.png"; - public static String RES_STR_CLEAR_IMG = "/org/synthuse/img/user-trash-2.png"; - public static String RES_STR_COPY_IMG = "/org/synthuse/img/edit-copy-7.png"; - public static String RES_STR_SAVE_IMG = "/org/synthuse/img/document-save-6.png"; - public static String RES_STR_OPEN_IMG = "/org/synthuse/img/document-open-folder.png"; - /** - * - */ - private static final long serialVersionUID = 1L; - private JPanel contentPane; - public JTextArea txtTest; - private JButton btnRun; - private JButton btnClear; - private JButton btnCopy; - private JButton btnSave; - private JButton btnOpen; - private JLabel lblStatus; - - /** - * Create the frame. - */ - - public TestIdeFrame() { - setTitle("Test IDE - Synthuse"); - setIconImage(Toolkit.getDefaultToolkit().getImage(TestIdeFrame.class.getResource(RES_STR_MAIN_ICON))); - setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); - setBounds(100, 100, 700, 367); - contentPane = new JPanel(); - contentPane.setBorder(new EmptyBorder(5, 5, 5, 5)); - contentPane.setLayout(new BorderLayout(0, 0)); - setContentPane(contentPane); - - JToolBar toolBar = new JToolBar(); - contentPane.add(toolBar, BorderLayout.NORTH); - - btnRun = new JButton("Run"); - btnRun.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent arg0) { - runTestScript(); - } - }); - btnRun.setIcon(new ImageIcon(SynthuseDlg.class.getResource(RES_STR_RUN_IMG))); - toolBar.add(btnRun); - - btnSave = new JButton("Save"); - btnSave.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent arg0) { - saveTestScript(); - } - }); - btnSave.setIcon(new ImageIcon(SynthuseDlg.class.getResource(RES_STR_SAVE_IMG))); - toolBar.add(btnSave); - - btnOpen = new JButton("Open"); - btnOpen.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent arg0) { - openTestScript(); - } - }); - btnOpen.setIcon(new ImageIcon(SynthuseDlg.class.getResource(RES_STR_OPEN_IMG))); - toolBar.add(btnOpen); - - btnClear = new JButton("Clear"); - btnClear.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent arg0) { - txtTest.setText(""); - } - }); - btnClear.setIcon(new ImageIcon(SynthuseDlg.class.getResource(RES_STR_CLEAR_IMG))); - toolBar.add(btnClear); - - btnCopy = new JButton("Copy Script"); - btnCopy.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent arg0) { - StringSelection stringSelection = new StringSelection(txtTest.getText()); - Clipboard clpbrd = Toolkit.getDefaultToolkit().getSystemClipboard(); - clpbrd.setContents(stringSelection, null); - //StatusWindow sw = new StatusWindow("this is a test BLAH really long string goes here to test status of stuff yaya!!!!123123 123 123", 4000); - } - }); - btnCopy.setIcon(new ImageIcon(SynthuseDlg.class.getResource(RES_STR_COPY_IMG))); - toolBar.add(btnCopy); - - JScrollPane scrollPane = new JScrollPane(); - contentPane.add(scrollPane, BorderLayout.CENTER); - - txtTest = new JTextArea(); - txtTest.setText("Click the Run button above to test the script below...\r\n\r\n"); - scrollPane.setViewportView(txtTest); - - lblStatus = new JLabel(" "); - contentPane.add(lblStatus, BorderLayout.SOUTH); - - this.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); - this.addWindowListener(new WindowAdapter() { - @Override - public void windowClosing(WindowEvent e) { - //TestIdeFrame.this.setVisible(false); - TestIdeFrame.this.dispose(); - } - }); - super.setAlwaysOnTop(SynthuseDlg.config.isAlwaysOnTop()); - } - - public void runTestScript() - { - if (btnRun.getText().equals("Run")) { - btnRun.setText("Stop"); - btnRun.setIcon(new ImageIcon(SynthuseDlg.class.getResource(RES_STR_STOP_IMG))); - CommandProcessor.STOP_PROCESSOR.set(false); - CommandProcessor.executeThreaded(txtTest.getText(), new CommandProcessor.Events() { - @Override - public void statusChanged(String status) { - lblStatus.setText(status); - } - @Override - public void executionCompleted() { - btnRun.setText("Run"); - btnRun.setIcon(new ImageIcon(SynthuseDlg.class.getResource(RES_STR_RUN_IMG))); - } - }); - } - else { - CommandProcessor.STOP_PROCESSOR.set(true); - //btnRun.setText("Run"); - //btnRun.setIcon(new ImageIcon(SynthuseDlg.class.getResource(RES_STR_RUN_IMG))); - } - } - - private void saveTestScript() - { - JFileChooser fChoose = new JFileChooser(); - fChoose.setFileFilter(new FileNameExtensionFilter("Text Files", "txt", "text")); - int result = fChoose.showSaveDialog(this); - if (result == JFileChooser.CANCEL_OPTION) - return; - File file = fChoose.getSelectedFile(); - if (fChoose.getFileFilter().getDescription().startsWith("Text") && !file.getAbsolutePath().toLowerCase().endsWith(".txt")) - file = new File(file.getAbsolutePath() + ".txt"); //append extension if not already there - - FileWriter fw = null; - try { - fw = new FileWriter(file); - fw.write(txtTest.getText()); - fw.flush(); - fw.close(); - fw = null; - } catch (Exception e) { - e.printStackTrace(); - } - if (fw != null) - try { fw.close(); } catch (Exception e){ e.printStackTrace(); }; - lblStatus.setText("Script Saved: " + file.getAbsolutePath()); - } - - private void openTestScript() - { - JFileChooser fChoose = new JFileChooser(); - fChoose.setFileFilter(new FileNameExtensionFilter("Text Files", "txt", "text")); - int result = fChoose.showOpenDialog(this); - if (result == JFileChooser.CANCEL_OPTION) - return; - File file = fChoose.getSelectedFile(); - BufferedReader br = null; - try { - br = new BufferedReader(new FileReader(file)); - String line = ""; - txtTest.setText(""); - while((line = br.readLine()) != null){ - txtTest.append(line + System.getProperty("line.separator")); - //System.out.println(line); - } - br.close(); - br = null; - } catch (Exception e) { - e.printStackTrace(); - } - if (br != null) - try { br.close(); } catch (Exception e){ e.printStackTrace(); }; - lblStatus.setText("Script Loaded: " + file.getAbsolutePath()); - } - -} diff --git a/src/org/synthuse/UiaBridge.java b/src/org/synthuse/UiaBridge.java deleted file mode 100644 index e136f7c..0000000 --- a/src/org/synthuse/UiaBridge.java +++ /dev/null @@ -1,182 +0,0 @@ -/* - * Copyright 2014, Synthuse.org - * Released under the Apache Version 2.0 License. - * - * last modified by ejakubowski7@gmail.com -*/ - -package org.synthuse; - -import java.awt.Point; -import java.awt.Rectangle; -import java.io.*; - -import javax.swing.JOptionPane; - -public class UiaBridge { - - public static String CACHED_PROPERTY_LIST = "RuntimeIdProperty,ParentRuntimeIdProperty,ProcessIdProperty,FrameworkIdProperty,LocalizedControlTypeProperty,ClassNameProperty,NameProperty,ValueProperty,BoundingRectangleProperty"; - public static final String FRAMEWORK_ID_WPF = "WPF"; - public static final String FRAMEWORK_ID_SILVER = "Silverlight"; - public static final String FRAMEWORK_ID_WINFORM = "WinForm"; - public static final String FRAMEWORK_ID_WIN = "Win32"; - - static - { - String loadFailedMsg = "Failed to load uiabridge library, make sure you have .Net 4.0 already installed.\n"; - if (!Api.isDotNet4Installed()) { //if .net 4.0 isn't installed don't use uiabridge - SynthuseDlg.config.disableUiaBridge = "true"; - JOptionPane.showMessageDialog(null, loadFailedMsg , "Native Library Load Error", JOptionPane.ERROR_MESSAGE); - } - if (!SynthuseDlg.config.isUiaBridgeDisabled()) { - //System.out.println("SynthuseDlg.config.disableUiaBridge: " + SynthuseDlg.config.disableUiaBridge); - String archDataModel = System.getProperty("sun.arch.data.model");//32 or 64 bit - try { - //System.loadLibrary("native/WpfBridge" + archDataModel); // WpfBridge32.dll (Windows) or WpfBridge32.so (Unixes) - loadNativeLibraryFromJar("/uiabridge" + archDataModel + ".dll"); - } catch (Exception ex) { - StringWriter sw = new StringWriter(); - PrintWriter pw = new PrintWriter(sw); - ex.printStackTrace(pw); - System.out.println(sw.toString()); - JOptionPane.showMessageDialog(null, loadFailedMsg + sw.toString() , "Native Library Load Error", JOptionPane.ERROR_MESSAGE); - SynthuseDlg.config.disableUiaBridge = "true"; - } - } - } - - public static void loadNativeLibraryFromJar(String path) { - // Obtain filename from path - String[] parts = path.split("/"); - String filename = (parts.length > 1) ? parts[parts.length - 1] : null; - // Split filename to prexif and suffix (extension) - String prefix = ""; - String suffix = null; - if (filename != null) { - parts = filename.split("\\.", 2); - prefix = parts[0]; - suffix = (parts.length > 1) ? "."+parts[parts.length - 1] : null; - } - File temp = null; - try { - // Prepare temporary file - temp = File.createTempFile(prefix, suffix); - temp.deleteOnExit(); - } catch(Exception e) { - e.printStackTrace(); - } - if (!temp.exists()) { //some reason the temp file wasn't create so abort - System.out.println("File " + temp.getAbsolutePath() + " does not exist."); - return; - } - - // Prepare buffer for data copying - byte[] buffer = new byte[1024]; - int readBytes; - // Open and check input stream - InputStream is = UiaBridge.class.getResourceAsStream(path); - if (is == null) { //check if valid - System.out.println("File " + path + " was not found inside JAR."); - return; - } - // Open output stream and copy data between source file in JAR and the temporary file - OutputStream os = null; - try { - os = new FileOutputStream(temp); - while ((readBytes = is.read(buffer)) != -1) { - os.write(buffer, 0, readBytes); - } - os.close(); - is.close(); - } catch(Exception e) { - e.printStackTrace(); - } - // Finally, load the library - System.load(temp.getAbsolutePath()); - } - - public UiaBridge () - { - if (!SynthuseDlg.config.isUiaBridgeDisabled()) - initialize(CACHED_PROPERTY_LIST); - } - - public native void initialize(String properties); - public native void shutdown(); - public native void useCachedRequests(boolean cacheRequestsFlg); - public native int addEnumFilter(String propertyName, String propertyValue); - public native void clearEnumFilters(); - public native String[] enumWindowInfo(String properties); - public native String[] enumWindowInfo(int windowHandle, String properties); - //native String[] enumWindowInfo(AutomationElement ^element, String properties); - //native String[] enumWindowInfo(AutomationElement ^element, String properties, String[] filterModifierList); - //native String getWindowInfo(AutomationElement ^element, String properties); - public native String getWindowInfo(int x, int y, String properties); - public native String getWindowInfo(int windowHandle, String properties); - public native String getWindowInfo(String runtimeId, String properties); - - - /* - public native void setFrameworkId(String propertyValue); //default is WPF, but also accepts Silverlight, Win32 - public native void setTouchableOnly(boolean val); //default is true - - //Descendants will walk the full tree of windows, NOT just one level of children - public native int countDescendantWindows(); - public native int countDescendantWindows(String runtimeIdValue); - - public native int countChildrenWindows(); - public native int countChildrenWindows(String runtimeIdValue); - - public String[] enumChildrenWindowIds(String runtimeIdValue); //if runtimeIdValue is null will start at desktop - public native String[] enumDescendantWindowIds(String runtimeIdValue); //if runtimeIdValue is null will start at desktop - public native String[] enumDescendantWindowIds(long processId); - //In all the above Enumerate methods will return a list of Runtime Ids for all related windows. - public native String[] enumDescendantWindowInfo(String runtimeIdValue, String properties); //returns properties comma separated - - public native String getRuntimeIdFromHandle(long windowHandle); - public native String getRuntimeIdFromPoint(int x, int y); - public native String getParentRuntimeId(String runtimeIdValue); - public native String getProperty(String propertyName, String runtimeIdValue); - public native String[] getProperties(String runtimeIdValue); - public native String[] getPropertiesAndValues(String runtimeIdValue); - */ - - public static String replaceEscapedCodes(String input) { - //, is a comma , - String result = input; - result = result.replaceAll(",", ","); - result = result.replaceAll("<", "<"); - result = result.replaceAll(">", ">"); - result = result.replaceAll("'", "'"); - result = result.replaceAll(""", "\""); - result = result.replaceAll("&", "&"); - return result; - } - - public Point getCenterOfElement(String runtimeIdValue) { - Point p = new Point(); - String boundaryProperty = getWindowInfo(runtimeIdValue, "BoundingRectangleProperty"); - Rectangle rect = getBoundaryRect(boundaryProperty); - p.x = ((rect.width) /2) + rect.x; - p.y = ((rect.height) /2) + rect.y; - return p; - } - - //BoundingRectangleProperty is the last property listed in comma separated properties string - public static Rectangle getBoundaryRect(String properties) { - Rectangle rect = new Rectangle(); - String[] propSplt = properties.split(","); - if (propSplt.length > 0) - { - String[] boundarySplt = replaceEscapedCodes(propSplt[propSplt.length - 1]).split(","); - if (boundarySplt.length == 4 ) - { - rect.x = Integer.parseInt(boundarySplt[0]); - rect.y = Integer.parseInt(boundarySplt[1]); - rect.width = Integer.parseInt(boundarySplt[2]); - rect.height = Integer.parseInt(boundarySplt[3]); - } - } - return rect; - } -} diff --git a/src/org/synthuse/WinPtr.java b/src/org/synthuse/WinPtr.java deleted file mode 100644 index 5aaeccc..0000000 --- a/src/org/synthuse/WinPtr.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2014, Synthuse.org - * Released under the Apache Version 2.0 License. - * - * last modified by ejakubowski7@gmail.com -*/ - -package org.synthuse; - -import com.sun.jna.platform.win32.WinDef.HWND; - -public class WinPtr { - - public HWND hWnd = null; - public String hWndStr = ""; - public String runtimeId = ""; - - public String hmenuStr = "";//store menu handle - public int hmenuPos = -1;//store menu position or id - - public WinPtr() { - } - - public WinPtr(HWND hWnd) { - this.hWnd = hWnd; - this.hWndStr = Api.GetHandleAsString(hWnd); - } - - public WinPtr(String runtimeId) { - this.runtimeId = runtimeId; - } - - public boolean isWin32() { - return (hWnd != null || !hWndStr.equals("")); - } - - public boolean isWpf() { - return (!runtimeId.equals("")); - } - - public boolean isEmpty() { - return (hWnd == null && hWndStr.equals("") && runtimeId.equals("")); - } - - public static boolean isWpfRuntimeIdFormat(String runtimeIdTest) { - return (runtimeIdTest.contains("-")); - } - - public void convertToNativeHwnd() - { - if (isWpfRuntimeIdFormat(runtimeId)){ - hWndStr = runtimeId.split("-")[1]; - hWnd = Api.GetHandleFromString(hWndStr); - } - } - - public String toString() { - if (isWin32() && !hWndStr.equals("")) - return hWndStr; - else if (isWin32() && hWnd != null) - { - hWndStr = Api.GetHandleAsString(hWnd); - return hWndStr; - } - else if (isWpf()) - return runtimeId; - else - return null; - } -} diff --git a/src/org/synthuse/WindowInfo.java b/src/org/synthuse/WindowInfo.java deleted file mode 100644 index 81d1d7a..0000000 --- a/src/org/synthuse/WindowInfo.java +++ /dev/null @@ -1,306 +0,0 @@ -/* - * Copyright 2014, Synthuse.org - * Released under the Apache Version 2.0 License. - * - * last modified by ejakubowski -*/ - -package org.synthuse; - -import java.awt.Point; -import java.awt.Rectangle; -import java.util.LinkedHashMap; -import java.util.Map; - -import org.synthuse.Api.*; - -import com.sun.jna.Native; -import com.sun.jna.Pointer; -import com.sun.jna.platform.win32.WinDef.HMENU; -import com.sun.jna.platform.win32.WinDef.HWND; -import com.sun.jna.platform.win32.WinDef.LPARAM; -import com.sun.jna.platform.win32.WinDef.LRESULT; -import com.sun.jna.platform.win32.WinDef.RECT; -import com.sun.jna.platform.win32.WinDef.WPARAM; -import com.sun.jna.platform.win32.WinNT.HANDLE; -import com.sun.jna.ptr.PointerByReference; - -public class WindowInfo { - - public static String UIA_PROPERTY_LIST = "RuntimeIdProperty,ParentRuntimeIdProperty,ProcessIdProperty,FrameworkIdProperty,LocalizedControlTypeProperty,ClassNameProperty,NameProperty,ValueProperty"; - public static String UIA_PROPERTY_LIST_ADV = "RuntimeIdProperty,ParentRuntimeIdProperty,ProcessIdProperty,FrameworkIdProperty,LocalizedControlTypeProperty,ClassNameProperty,NameProperty,ValueProperty,BoundingRectangleProperty"; - public static String UIA_RUNTIME_ID = "RuntimeIdProperty"; - public static String UIA_BOUNDING_RECT = "BoundingRectangleProperty"; - public static int MAX_TEXT_SIZE = 200; - - public HWND hwnd; - public String hwndStr = ""; - public HWND parent = null; - public String parentStr = ""; - public RECT rect; - public String text; - public String value; - public String controlType = ""; - public String className = ""; - public boolean isChild = false; - public String processName = ""; - public long pid = 0; - public Object xmlObj = null; - public String framework = "win32";//default as win32 - public String runtimeId = ""; - public int menus = 0; - public HMENU menu = null; - public boolean useUiaBridge = false; - public boolean is64bit = false; - - public Map extra = null; - - //Default Win32 support - public WindowInfo(HWND hWnd, boolean isChild) { - this.framework = "win32"; - byte[] buffer = new byte[1024]; - User32Ex.instance.GetWindowTextA(hWnd, buffer, buffer.length); - text = Native.toString(buffer); - if (text.isEmpty()) - text = new Api().sendWmGetText(hWnd); - //if (text.isEmpty()) { - //System.out.println("getting toolbar text"); - //} - if (text.length() > MAX_TEXT_SIZE) //if text is too large it will slow down xml display - text = text.substring(0, MAX_TEXT_SIZE); - - //Get item count depending on what type of control it is - LRESULT tbCount = Api.User32Ex.instance.SendMessage(hWnd, Api.TB_BUTTONCOUNT, new WPARAM(0), new LPARAM(0)); - if (tbCount.intValue() > 0) { // toolbar button count - //System.out.println("TB_BUTTONCOUNT: " + tbCount.intValue()); - if (extra == null) - extra = new LinkedHashMap(); - extra.put("tbCount", tbCount.intValue() + ""); - //Api.User32.instance.SendMessageA(hWnd, Api.TB_GETTOOLTIPS, 0, buffer); - //text = Native.toString(buffer); - } - LRESULT lvCount = Api.User32Ex.instance.SendMessage(hWnd, Api.LVM_GETITEMCOUNT, new WPARAM(0), new LPARAM(0)); - if (lvCount.intValue() > 0) { // listview item count - if (extra == null) - extra = new LinkedHashMap(); - extra.put("lvCount", lvCount.intValue() + ""); - } - LRESULT lbCount = Api.User32Ex.instance.SendMessage(hWnd, Api.LB_GETCOUNT, new WPARAM(0), new LPARAM(0)); - if (lbCount.intValue() > 0) { // listbox item count - if (extra == null) - extra = new LinkedHashMap(); - extra.put("lbCount", lbCount.intValue() + ""); - } - LRESULT cbCount = Api.User32Ex.instance.SendMessage(hWnd, Api.CB_GETCOUNT, new WPARAM(0), new LPARAM(0)); - if (cbCount.intValue() > 0) { // listbox item count - if (extra == null) - extra = new LinkedHashMap(); - extra.put("cbCount", cbCount.intValue() + ""); - } - LRESULT tvCount = Api.User32Ex.instance.SendMessage(hWnd, Api.TVM_GETCOUNT, new WPARAM(0), new LPARAM(0)); - if (tvCount.intValue() > 0) { //treeview node count - if (extra == null) - extra = new LinkedHashMap(); - extra.put("tvCount", tvCount.intValue() + ""); - } - - char[] buffer2 = new char[1026]; - User32Ex.instance.GetClassName(hWnd, buffer2, 1026); - className = Native.toString(buffer2); - - //check if window has a menu - HMENU hmenu = null; - try { - hmenu = Api.User32Ex.instance.GetMenu(hWnd); - } catch(Exception ex) { - //ex.printStackTrace(); - } - if (hmenu != null) { //menu item count - int menuCount = Api.User32Ex.instance.GetMenuItemCount(hmenu); - if (menuCount > 0) { - this.menus = menuCount; - this.menu = hmenu; - } - } - else // if (className.equals("#32768")) //check if its a popup menu window - { - //LRESULT result = Api.User32.instance.PostMessage(hWnd, Api.MN_GETHMENU, new WPARAM(0), new LPARAM(0)); - LRESULT result = Api.User32Ex.instance.SendMessage(hWnd, Api.MN_GETHMENU, new WPARAM(0), new LPARAM(0)); - if (result.longValue() != 1) - { - //System.out.println("MN_GETHMENU: " + result.longValue()); - hmenu = new HMENU(new Pointer(result.longValue())); - int menuCount = Api.User32Ex.instance.GetMenuItemCount(hmenu); - if (menuCount > 0) - { - //System.out.println("Popup Win: " + menuCount); - this.menus = menuCount; - this.menu = hmenu; - } - } - } - - - rect = new RECT(); - User32Ex.instance.GetWindowRect(hWnd, rect); - - this.isChild = isChild; - if (isChild) { - parent = User32Ex.instance.GetParent(hWnd); - parentStr = Api.GetHandleAsString(parent); - // test to see if uiaBridge should be used on this child - if (this.className.startsWith("HwndWrapper") || this.className.startsWith("MicrosoftSilverlight") || this.className.startsWith("GeckoPluginWindow")) - useUiaBridge = true; - } - else { - PointerByReference pointer = new PointerByReference(); - User32Ex.instance.GetWindowThreadProcessId(hWnd, pointer); - pid = pointer.getPointer().getInt(0); - getProcessInfo(); - //test to see if uiaBridge should be used on this parent - if (this.className.startsWith("HwndWrapper") || this.className.startsWith("WindowsForms")) - useUiaBridge = true; - } - this.hwnd = hWnd; - hwndStr = Api.GetHandleAsString(hWnd); - if (this.hwndStr == null) - this.hwndStr = ""; - } - - //support for WPF, Silverlight, WinForms - public WindowInfo(String enumProperties, boolean isChild) { - //WPF_PROPERTY_LIST = "RuntimeIdProperty,ParentRuntimeIdProperty,ProcessIdProperty,FrameworkIdProperty,LocalizedControlTypeProperty,ClassNameProperty,NameProperty,ValueProperty"; - String[] spltProperties = enumProperties.split(","); - this.isChild = isChild; - this.useUiaBridge = true; - if (SynthuseDlg.config.isFilterUiaDisabled()) { //use wildcard mode - extra = new LinkedHashMap(); - for(String prop: spltProperties) { - String[] propertyNameAndValue = prop.split(":", 2); - if (propertyNameAndValue.length < 2) - continue; - - if (propertyNameAndValue[0].equals("RuntimeIdProperty")) - this.runtimeId = propertyNameAndValue[1]; - else if (propertyNameAndValue[0].equals("ParentRuntimeIdProperty")) - this.parentStr = propertyNameAndValue[1]; - else if (propertyNameAndValue[0].equals("ProcessIdProperty")) - this.pid = Long.parseLong(propertyNameAndValue[1]); - else if (propertyNameAndValue[0].equals("FrameworkIdProperty")) - this.framework = propertyNameAndValue[1]; - else if (propertyNameAndValue[0].equals("LocalizedControlTypeProperty")) - this.controlType = propertyNameAndValue[1]; - else if (propertyNameAndValue[0].equals("ClassNameProperty")) - this.className = propertyNameAndValue[1]; - else if (propertyNameAndValue[0].equals("NameProperty")) - this.text = propertyNameAndValue[1]; - else if (propertyNameAndValue[0].equals("ValueProperty")) - this.value = propertyNameAndValue[1]; - else{ - extra.put(propertyNameAndValue[0], propertyNameAndValue[1]); - } - } - this.hwndStr = this.runtimeId; - if (text != null) - if (text.length() > MAX_TEXT_SIZE) - text = text.substring(0, MAX_TEXT_SIZE); - if (this.hwndStr == null) - this.hwndStr = ""; - //if (this.framework == null) - // this.framework = "na"; - if(this.controlType.equals("window")) - this.isChild = false; - return; - } - // non-wildcard mode - if (spltProperties.length > 0) - this.runtimeId = spltProperties[0]; - this.hwndStr = this.runtimeId; - if (spltProperties.length > 1 && isChild) - this.parentStr = spltProperties[1]; - if (spltProperties.length > 2) - this.pid = Long.parseLong(spltProperties[2]); - if (spltProperties.length > 3) - this.framework = spltProperties[3]; - if (spltProperties.length > 4) - this.controlType = UiaBridge.replaceEscapedCodes(spltProperties[4]); - if (spltProperties.length > 5) - this.className = UiaBridge.replaceEscapedCodes(spltProperties[5]); - if (spltProperties.length > 6) - this.text = UiaBridge.replaceEscapedCodes(spltProperties[6]); - if (spltProperties.length > 7) - this.value = UiaBridge.replaceEscapedCodes(spltProperties[7]); - if (this.className == "") - this.className = this.controlType; - if (text != null) - if (text.length() > MAX_TEXT_SIZE) - text = text.substring(0, MAX_TEXT_SIZE); - if (value != null) - if (value.length() > MAX_TEXT_SIZE) - value = value.substring(0, MAX_TEXT_SIZE); - if (this.hwndStr == null) - this.hwndStr = ""; - getProcessInfo(); - if(this.controlType.equals("window")) - this.isChild = false; - /* - this.rect = new RECT(); - try { - String rectStr = wb.getProperty("BoundingRectangleProperty", runtimeId); - String[] rectSplt = rectStr.split(","); - this.rect.right = Integer.parseInt(rectSplt[0]); - this.rect.bottom = Integer.parseInt(rectSplt[1]); - this.rect.left = Integer.parseInt(rectSplt[2]); - this.rect.top = Integer.parseInt(rectSplt[3]); - } catch (Exception e) { - e.printStackTrace(); - } - */ - } - - private void getProcessInfo() - { - if (pid == 0) - return; - char[] buffer = new char[1026]; - Pointer process = Kernel32Ex.instance.OpenProcess(Api.PROCESS_QUERY_INFORMATION | Api.PROCESS_VM_READ, false, new Pointer(pid)); - PsapiEx.instance.GetModuleBaseNameW(process, null, buffer, 512); - processName = Native.toString(buffer); - Kernel32Ex.instance.CloseHandle(new HANDLE(process)); - is64bit = Api.isProcess64bit((int)pid); - } - - - public static String getRuntimeIdFromProperties(String enumProperties) - { - String[] spltProperties = enumProperties.split(","); - if (spltProperties.length > 0) - return spltProperties[0]; - return ""; - } - - public static String getFrameworkFromProperties(String enumProperties) - { - String[] spltProperties = enumProperties.split(","); - if (spltProperties.length > 3) - return spltProperties[3]; - return ""; - } - - public static Point findOffset(Rectangle rect, int xPos, int yPos) - { - Point offset = new Point(); - int x = ((rect.width) /2) + rect.x; - int y = ((rect.height) /2) + rect.y; - - offset.x = xPos - x; - offset.y = yPos - y; - - return offset; - } - - public String toString() { - return String.format("%s \"%s\" [%s] (%s) {%s}", framework, text, className, controlType, hwndStr); - } - -} diff --git a/src/org/synthuse/WindowsEnumeratedXml.java b/src/org/synthuse/WindowsEnumeratedXml.java deleted file mode 100644 index dcfd946..0000000 --- a/src/org/synthuse/WindowsEnumeratedXml.java +++ /dev/null @@ -1,421 +0,0 @@ -/* - * Copyright 2014, Synthuse.org - * Released under the Apache Version 2.0 License. - * - * last modified by ejakubowski -*/ - -package org.synthuse; - -import java.io.StringReader; -import java.io.StringWriter; -import java.sql.Timestamp; -import java.text.DecimalFormat; -import java.util.ArrayList; -import java.util.Date; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.atomic.AtomicBoolean; - -import javax.swing.JLabel; -import javax.swing.JTextPane; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.transform.OutputKeys; -import javax.xml.transform.Transformer; -import javax.xml.transform.TransformerFactory; -import javax.xml.transform.dom.DOMSource; -import javax.xml.transform.stream.StreamResult; -import javax.xml.xpath.XPath; -import javax.xml.xpath.XPathConstants; -import javax.xml.xpath.XPathExpression; -import javax.xml.xpath.XPathFactory; - -import org.w3c.dom.Attr; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; -import org.xml.sax.InputSource; - -import com.sun.jna.Pointer; -import com.sun.jna.platform.win32.WinDef.HMENU; -import com.sun.jna.platform.win32.WinUser; -import com.sun.jna.platform.win32.WinDef.HWND; - -public class WindowsEnumeratedXml implements Runnable{ - - public static Exception lastException = null; - public static AtomicBoolean enumeratingXmlFlag = new AtomicBoolean(false); - public JTextPane outputPane = null; - public JLabel lblStatus = null; - public WindowsEnumeratedXml() { - } - - public WindowsEnumeratedXml(JTextPane outputPane, JLabel lblStatus) { - this.outputPane = outputPane; - this.lblStatus = lblStatus; - } - - @Override - public void run() { - lblStatus.setText("Loading Windows Enumerated Xml..."); - long startTime = System.nanoTime(); - outputPane.setText(getXml()); - outputPane.setCaretPosition(0); - double seconds = ((double)(System.nanoTime() - startTime) / 1000000000); - lblStatus.setText("Windows Enumerated Xml loaded in " + new DecimalFormat("#.###").format(seconds) + " seconds"); - enumeratingXmlFlag.set(false); - } - - public static void getXmlThreaded(JTextPane outputPane, JLabel lblStatus) { - if (enumeratingXmlFlag.get()) - return; //something is already running - enumeratingXmlFlag.set(true); //if we don't do this the multiple xml's could get combined on the textpane - Thread t = new Thread(new WindowsEnumeratedXml(outputPane, lblStatus)); - t.start(); - } - - public static String getXml() { - final Map infoList = getWin32XmlMap(); - - //process all windows that have been flagged for uiaBridge (useUiaBridge == true) - appendUiaBridgeWindows(infoList); - - return generateWindowsXml(infoList, "EnumeratedWindows"); - } - - public static String getWin32Xml() { - final Map infoList = getWin32XmlMap(); - return generateWindowsXml(infoList, "EnumeratedWindows"); - } - - public static Map getWin32XmlMap() { - final Map infoList = new LinkedHashMap(); - - HWND desktopRootHwnd = Api.User32Ex.instance.GetDesktopWindow(); - WindowInfo wi = new WindowInfo(desktopRootHwnd, false); - wi.controlType = "DesktopRoot"; - infoList.put(wi.hwndStr, wi); - - class ParentWindowCallback implements WinUser.WNDENUMPROC { - @Override - public boolean callback(HWND hWnd, Pointer lParam) { - WindowInfo wi = new WindowInfo(hWnd, false); - infoList.put(wi.hwndStr, wi); - infoList.putAll(EnumerateWin32ChildWindows(hWnd)); - return true; - } - } - Api.User32Ex.instance.EnumWindows(new ParentWindowCallback(), 0); - return infoList; - } - - public static void appendUiaBridgeWindows(Map infoList) - { - //Enumerate WPF, WinForm, Silverlight windows and add to list - if (!SynthuseDlg.config.isUiaBridgeDisabled()) - { - UiaBridge uiabridge = new UiaBridge(); - Map uiaInfoList = new LinkedHashMap(); - for (String handle : infoList.keySet()) { - if (infoList.get(handle).useUiaBridge) { - uiaInfoList.putAll(EnumerateWindowsWithUiaBridge(uiabridge, handle, "*")); - } - } - infoList.putAll(uiaInfoList); - } - //return infoList; - } - - public static Map EnumerateWin32ChildWindows(HWND parentHwnd) - { - final Map infoList = new LinkedHashMap(); - - class ChildWindowCallback implements WinUser.WNDENUMPROC { - @Override - public boolean callback(HWND hWnd, Pointer lParam) { - WindowInfo wi = new WindowInfo(hWnd, true); - infoList.put(wi.hwndStr, wi); - return true; - } - } - - Api.User32Ex.instance.EnumChildWindows(parentHwnd, new ChildWindowCallback(), new Pointer(0)); - - return infoList; - } - - public static String generateWindowsXml(Map infoList, String rootElementName) - { - final Map processList = new LinkedHashMap(); - int wpfCount = 0; - int winFormCount = 0; - int silverlightCount = 0; - int menuCount = 0; - // convert window info list to xml dom - try { - DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance(); - DocumentBuilder docBuilder = docFactory.newDocumentBuilder(); - - // root elements - Document doc = docBuilder.newDocument(); - Element rootElement = doc.createElement(rootElementName); - doc.appendChild(rootElement); - - long parentCount = 0; - long childCount = 0; - for (String handle : infoList.keySet()) { - WindowInfo w = infoList.get(handle); - //System.out.println(w); - // create new win xml element - Element win = null; - if (w.framework.equals("win32")) - win = doc.createElement("win"); - else if (w.framework.equals(UiaBridge.FRAMEWORK_ID_WPF)) - { - win = doc.createElement("wpf"); - ++wpfCount; - } - else if (w.framework.equals(UiaBridge.FRAMEWORK_ID_WINFORM)) - { - win = doc.createElement("winfrm"); - ++winFormCount; - } - else if (w.framework.equals(UiaBridge.FRAMEWORK_ID_SILVER)) - { - win = doc.createElement("silver"); - ++silverlightCount; - } - else - win = doc.createElement("win"); - //System.out.println(w.toString()); - - win.setAttribute("hwnd", w.hwndStr); - win.setAttribute("text", w.text); - if (w.value != "" && w.value != null) - win.setAttribute("value", w.value); - if (w.text != null) - win.setAttribute("TEXT", w.text.toUpperCase()); - win.setAttribute("class", w.className); - if (w.className != null) - win.setAttribute("CLASS", w.className.toUpperCase()); - if (w.controlType != null) - if (!w.controlType.isEmpty()) - win.setAttribute("type", w.controlType); - if (!w.isChild) { - //win.setAttribute("parent", "yes"); - parentCount++; - if (w.processName != null && !w.processName.isEmpty()) { - if (!processList.containsKey(w.pid+"")) - processList.put(w.pid+"", w.hwndStr); - win.setAttribute("process", w.processName); - if (w.processName != null) - win.setAttribute("PROCESS", w.processName.toUpperCase()); - } - if (w.pid != 0) - { - if (w.is64bit) - win.setAttribute("bits", "64"); - else - win.setAttribute("bits", "32"); - } - } - if (w.pid != 0) - win.setAttribute("pid", w.pid+""); - //else - //win.setAttribute("parent", w.parent + ""); // not really needed since child node is append to parent node - - - if (w.extra != null) { - for(String extraName: w.extra.keySet()) { - win.setAttribute(extraName, w.extra.get(extraName)+""); - } - } - - if (w.menus > 0) { - win.setAttribute("menus", w.menus+""); - //String menuStr = MenuInfo.GetHandleMenuAsString(w.menu); - buildMenuXmlElements(doc, win, w.menu, w.hwndStr); - ++menuCount; - } - - if (w.isChild && infoList.containsKey(w.parentStr)) { - childCount++; - WindowInfo parentWi = infoList.get(w.parentStr); - if (parentWi.xmlObj != null) - ((Element)parentWi.xmlObj).appendChild(win); - else - rootElement.appendChild(win); - } - else - rootElement.appendChild(win); - w.xmlObj = win; - - } - - // calculate totals on various windows. - Element totals = doc.createElement("totals"); - totals.setAttribute("parentCount", parentCount+""); - totals.setAttribute("childCount", childCount+""); - totals.setAttribute("windowCount", infoList.size()+""); - //totals.setAttribute("wpfWrapperCount", wpfParentList.size()+""); - totals.setAttribute("wpfCount", wpfCount+""); - totals.setAttribute("winFormCount", winFormCount+""); - totals.setAttribute("silverlightCount", silverlightCount+""); - totals.setAttribute("menuCount", menuCount+""); - totals.setAttribute("processCount", processList.size()+""); - totals.setAttribute("updatedLast", new Timestamp((new Date()).getTime()) + ""); - rootElement.appendChild(totals); - String output = nodeToString(rootElement); - //System.out.println("count - " + infoList.size() + "\r\n"); - return output; - } catch (Exception e) { - e.printStackTrace(); - lastException = e; - } - return ""; - } - - public static Element buildMenuXmlElements(Document xmlDoc, Element xmlElement, HMENU targetMenu, String targetWin) - { - MenuInfo firstMi = new MenuInfo(targetWin, targetMenu); - for (int i = 0 ; i < firstMi.menuCount ; i++ ) { - MenuInfo menuInfo = new MenuInfo(targetWin, targetMenu, i); - Element menuElement = xmlDoc.createElement("menu"); - menuElement.setAttribute("unaltered", menuInfo.unaltered + ""); - menuElement.setAttribute("text", menuInfo.text + ""); - menuElement.setAttribute("id", menuInfo.id + ""); - menuElement.setAttribute("position", menuInfo.position + ""); - menuElement.setAttribute("hmenu", menuInfo.hmenuStr + ""); - menuElement.setAttribute("hwnd", menuInfo.hwndStr + ""); - if (!menuInfo.center.isEmpty()) - menuElement.setAttribute("center", menuInfo.center + ""); - if (menuInfo.hasSubMenu) { - buildMenuXmlElements(xmlDoc, menuElement, menuInfo.submenu, targetWin); - } - xmlElement.appendChild(menuElement); - } - return xmlElement; - } - - public static Map EnumerateWindowsWithUiaBridge(UiaBridge uiabridge, String parentHwndStr, String frameworkType) { - final Map infoList = new LinkedHashMap(); - //WpfBridge wb = new WpfBridge(); - //wpf.setFrameworkId(frameworkType); - long hwnd = Long.parseLong(parentHwndStr); - //System.out.println("getRuntimeIdFromHandle of " + hwnd); - String parentRuntimeId = uiabridge.getWindowInfo((int) hwnd, WindowInfo.UIA_RUNTIME_ID); - //System.out.println("runtimeId=" + runtimeId); - String[] allIds = null; - if (SynthuseDlg.config.isFilterUiaDisabled()) - allIds = uiabridge.enumWindowInfo((int) hwnd, "*"); - else - allIds = uiabridge.enumWindowInfo((int) hwnd, WindowInfo.UIA_PROPERTY_LIST); - if (allIds == null) - return infoList; //empty list - //System.out.println("enumDescendantWindowIds " + allIds.length); - for(String runtimeIdAndInfo : allIds) { - //System.out.println("getting window info for: " + runtimeIdAndInfo); - WindowInfo wi = new WindowInfo(runtimeIdAndInfo, true); - if (wi.parentStr.equals(parentRuntimeId)) - wi.parentStr = parentHwndStr; - //System.out.println("is parent? " + onlyRuntimeId); - infoList.put(wi.runtimeId, wi); - } - return infoList; - } - - public static String escapeXmlAttributeValue(String unescapedStr) { - String result = ""; - try { - DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance(); - DocumentBuilder docBuilder = docFactory.newDocumentBuilder(); - // root elements - Document doc = docBuilder.newDocument(); - Element rootElement = doc.createElement("temp"); - doc.appendChild(rootElement); - Attr attribute = doc.createAttribute("attrib"); - attribute.setNodeValue(unescapedStr); - rootElement.setAttributeNode(attribute); - result = nodeToString(rootElement); - result = result.replaceAll("[^\"]*\"([^\"]*)\"[^\"]*", "$1"); // keep the string within quotes. - } catch (Exception e) { - e.printStackTrace(); - //lastException = e; - } - return result; - } - - private static String nodeToString(Node node) { - StringWriter sw = new StringWriter(); - try { - Transformer t = TransformerFactory.newInstance().newTransformer(); - t.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); - t.setOutputProperty(OutputKeys.INDENT, "yes"); - t.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4"); - t.transform(new DOMSource(node), new StreamResult(sw)); - } catch (Exception e) { - e.printStackTrace(); - lastException = e; - } - return sw.toString(); - } - - public static String queryWindowInfoXml(String xpathExpr) { - String nl = System.getProperty("line.separator"); - String result = "" + nl; - String xml = getXml(); - List resultList = evaluateXpathGetValues(xml, xpathExpr); - for(String item: resultList) { - result += " " + item; - } - result += "" + nl; - return result; - } - - public static HWND queryHandleWindowInfoXml(String xpathExpr) { - String xml = getXml(); - String result = ""; - List resultList = evaluateXpathGetValues(xml, xpathExpr); - for(String item: resultList) { - if (item.contains("hwnd")) { - List hwndList = evaluateXpathGetValues(item, "//@hwnd"); - result = hwndList.get(0); - } - else - result = item; - break; - } - return Api.GetHandleFromString(result); - } - - - public static List evaluateXpathGetValues(String xml, String xpathExpr) { - List resultLst = new ArrayList(); - try { - InputSource inSource = new InputSource(new StringReader(xml)); - XPathFactory factory = XPathFactory.newInstance(); - XPath xpath = factory.newXPath(); - XPathExpression expr = xpath.compile(xpathExpr); - - Object result = expr.evaluate(inSource, XPathConstants.NODESET); - NodeList nodes = (NodeList) result; - for (int i = 0; i < nodes.getLength(); i++) { - String val = nodes.item(i).getNodeValue(); - if (val == null) // if we can't get a string value try to transform the xml node to a string - val = nodeToString(nodes.item(i)); - else - val += System.getProperty("line.separator"); - resultLst.add(val); - //System.out.println("match " + i + ": " + val); - } - } catch(Exception e) { - e.printStackTrace(); - lastException = e; - } - return resultLst; - } - -} diff --git a/src/org/synthuse/XmlEditorKit.java b/src/org/synthuse/XmlEditorKit.java deleted file mode 100644 index 4e01166..0000000 --- a/src/org/synthuse/XmlEditorKit.java +++ /dev/null @@ -1,209 +0,0 @@ -/* - * Copyright 2014, Synthuse.org - * Released under the Apache Version 2.0 License. - * - * last modified by ejakubowski -*/ - -package org.synthuse; - -import java.awt.Color; -import java.awt.Graphics; -import java.util.*; -import java.util.regex.*; -import javax.swing.text.*; - -/* Example: - - // Set editor kit - jtextpane.setEditorKitForContentType("text/xml", new XmlEditorKit()); - jtextpane.setContentType("text/xml"); - - */ - -public class XmlEditorKit extends StyledEditorKit { - - private static final long serialVersionUID = 2969169649596107757L; - private ViewFactory xmlViewFactory; - - private static HashMap patternColors; - private static String TAG_PATTERN = "(?"; - private static String TAG_END_PATTERN = "(/>)"; - private static String TAG_ATTRIBUTE_PATTERN = "\\s([a-zA-Z0-9]*)\\s*?\\=\\s*?\\\""; - private static String TAG_ATTRIBUTE_VALUE = "[a-zA-Z0-9]*\\=(\"[^\"]*\")"; - private static String TAG_COMMENT = "()"; - private static String TAG_CDATA_START = "(\\)"; - - //public static String TAG_HIGHLIGHTED = ".*hwnd=\"([^\"]*)\".*"; - public static String TAG_HIGHLIGHTED = ""; - public static Color TAG_HIGHLIGHTED_COLOR = new Color(170, 255, 48); - - public static int HIGHLIGHTED_START = 0; - public static int HIGHLIGHTED_END = 0; - public static Color HIGHLIGHTED_COLOR = new Color(240, 255, 112); - - static { - // NOTE: the order is important! - patternColors = new HashMap(); - patternColors.put(Pattern.compile(TAG_CDATA_START), new Color(128, 128, 128)); - patternColors.put(Pattern.compile(TAG_CDATA_END), new Color(128, 128, 128)); - patternColors.put(Pattern.compile(TAG_PATTERN), new Color(63, 127, 127)); - patternColors.put(Pattern.compile(TAG_ATTRIBUTE_PATTERN), new Color(127, 0, 127)); - patternColors.put(Pattern.compile(TAG_END_PATTERN), new Color(63, 127, 127)); - patternColors.put(Pattern.compile(TAG_ATTRIBUTE_VALUE), new Color(42, 0, 255)); - patternColors.put(Pattern.compile(TAG_COMMENT), new Color(63, 95, 191)); - } - - - class XmlView extends PlainView { - - - public XmlView(Element element) { - - super(element); - - // Set tabsize to 4 (instead of the default 8) - getDocument().putProperty(PlainDocument.tabSizeAttribute, 4); - } - - @Override - protected int drawUnselectedText(Graphics graphics, int x, int y, int p0, int p1) throws BadLocationException { - try { - - Document doc = getDocument(); - String text = doc.getText(p0, p1 - p0); - - Segment segment = getLineBuffer(); - int initialXpos = x; - - SortedMap startMap = new TreeMap(); - SortedMap colorMap = new TreeMap(); - - // Match all regexes on this snippet, store positions - for (Map.Entry entry : patternColors.entrySet()) { - - Matcher matcher = entry.getKey().matcher(text); - - while (matcher.find()) { - startMap.put(matcher.start(1), matcher.end(1)); - colorMap.put(matcher.start(1), entry.getValue()); - } - } - - // TODO: check the map for overlapping parts - - int i = 0; - //add tag highlighted background colors - if (!TAG_HIGHLIGHTED.isEmpty()) { - Matcher highlightMatcher = Pattern.compile(TAG_HIGHLIGHTED).matcher(text); - while(highlightMatcher.find()) { - int start = highlightMatcher.start(1); - int end = highlightMatcher.end(1); - if (i < start) { - graphics.setColor(Color.black); - doc.getText(p0 + i, start - i, segment); - x = Utilities.drawTabbedText(segment, x, y, graphics, this, i); - } - graphics.setColor(TAG_HIGHLIGHTED_COLOR); - i = end; - doc.getText(p0 + start, i - start, segment); - int width = Utilities.getTabbedTextWidth(segment, graphics.getFontMetrics(), x, this, p0 + start); - //graphics.drawLine(x, y, width, y);graphics.getFontMetrics() - graphics.fillRect(x, y - graphics.getFontMetrics().getHeight() + 2, width, graphics.getFontMetrics().getHeight()); - graphics.setColor(Color.black); - doc.getText(p0 + start, i - start, segment); - x = Utilities.drawTabbedText(segment, x, y, graphics, this, start); - } - } - x = initialXpos; - i=0; - //add highlighted background colors based on position - //String textx = doc.getText(p0, p1 - p0); - if ((HIGHLIGHTED_START < p1 && HIGHLIGHTED_START >= p0) || (HIGHLIGHTED_END <= p1 && HIGHLIGHTED_END > p0) || ( HIGHLIGHTED_START < p1 && HIGHLIGHTED_END > p0)) { - //select whole line - int start = 0; - int end = text.length(); - // test to see if only partial line is needed. - if (HIGHLIGHTED_START > p0) - start = HIGHLIGHTED_START - p0; - if (HIGHLIGHTED_END < p1) - end -= p1 - HIGHLIGHTED_END; - if (i < start) { // fill in normal color if start highlight isn't at the beginning - graphics.setColor(Color.black); - doc.getText(p0 + i, start - i, segment); - x = Utilities.drawTabbedText(segment, x, y, graphics, this, i); - } - graphics.setColor(HIGHLIGHTED_COLOR);// fill in the highlight color - i = end; - if (i - start > 0) { - doc.getText(p0 + start, i - start, segment); - int width = Utilities.getTabbedTextWidth(segment, graphics.getFontMetrics(), x, this, p0 + start); - //graphics.drawLine(x, y, width, y);graphics.getFontMetrics() - graphics.fillRect(x, y - graphics.getFontMetrics().getHeight() + 2, width, graphics.getFontMetrics().getHeight()); - graphics.setColor(Color.black); - doc.getText(p0 + start, i - start, segment); - x = Utilities.drawTabbedText(segment, x, y, graphics, this, start); - } - //else - // System.out.println("invalid highlighting " + (i - start) + " is <= 0 (" + p0 + "-" + p1 + "=" + (p1 - p0) +") " + start + ", " + end + " len=" + text.length()); - } - - x = initialXpos; - i=0; - // Color the parts of xml foreground font - for (Map.Entry entry : startMap.entrySet()) { - int start = entry.getKey(); - int end = entry.getValue(); - - if (i < start) { - graphics.setColor(Color.black); - doc.getText(p0 + i, start - i, segment); - x = Utilities.drawTabbedText(segment, x, y, graphics, this, i); - } - - graphics.setColor(colorMap.get(start)); - i = end; - doc.getText(p0 + start, i - start, segment); - x = Utilities.drawTabbedText(segment, x, y, graphics, this, start); - } - - - // Paint possible remaining text black - if (i < text.length()) { - graphics.setColor(Color.black); - doc.getText(p0 + i, text.length() - i, segment); - x = Utilities.drawTabbedText(segment, x, y, graphics, this, i); - } - } catch (Exception e) { - e.printStackTrace(); - } - return x; - } - } - - - class XmlViewFactory extends Object implements ViewFactory { - /** - * @see javax.swing.text.ViewFactory#create(javax.swing.text.Element) - */ - public View create(Element element) { - - return new XmlView(element); - } - } - - public XmlEditorKit() { - xmlViewFactory = new XmlViewFactory(); - } - - @Override - public ViewFactory getViewFactory() { - return xmlViewFactory; - } - - @Override - public String getContentType() { - return "text/xml"; - } -} diff --git a/src/org/synthuse/XpathManager.java b/src/org/synthuse/XpathManager.java deleted file mode 100644 index 76c73e9..0000000 --- a/src/org/synthuse/XpathManager.java +++ /dev/null @@ -1,292 +0,0 @@ -/* - * Copyright 2014, Synthuse.org - * Released under the Apache Version 2.0 License. - * - * last modified by ejakubowski -*/ - -package org.synthuse; - -import java.awt.EventQueue; -import java.util.List; - -import javax.swing.JLabel; -import javax.swing.JOptionPane; -import javax.swing.JTextPane; - -import org.synthuse.Api.User32Ex; - -import com.sun.jna.platform.win32.WinDef.HWND; - -public class XpathManager implements Runnable{ - - private HWND hwnd = null; - private String enumProperties = null; - private JTextPane windowsXmlTextPane = null; - - public static interface Events { - void statusChanged(String status); - void executionCompleted(Object input, String results); - } - public Events events = new Events() { - public void statusChanged(String status){ - System.out.println(status); - } - public void executionCompleted(Object input, String results){ - - } - }; - - public XpathManager(HWND hwnd, JTextPane windowsXmlTextPane, Events events) { - this.events = events; - this.hwnd = hwnd; - this.windowsXmlTextPane = windowsXmlTextPane; - } - - public XpathManager(HWND hwnd, String enumProperties, JTextPane windowsXmlTextPane, Events events) { - this.events = events; - this.hwnd = hwnd; - this.enumProperties = enumProperties; - this.windowsXmlTextPane = windowsXmlTextPane; - } - - @Override - public void run() { - String results = SynthuseDlg.config.isUseStrongTextMatching()?buildXpathStatement(true,50,50):buildXpathStatement(); - events.executionCompleted(hwnd, results); - } - - public static void buildXpathStatementThreaded(HWND hwnd, JTextPane windowsXmlTextPane, Events events) { - Thread t = new Thread(new XpathManager(hwnd, windowsXmlTextPane, events)); - t.start(); - } - - public static void buildXpathStatementThreaded(HWND hwnd, String runtimeId, JTextPane windowsXmlTextPane, Events events) { - Thread t = new Thread(new XpathManager(hwnd, runtimeId, windowsXmlTextPane, events)); - t.start(); - } - - public String compareLongTextString(String rawText) { - String escapedTxtStr = WindowsEnumeratedXml.escapeXmlAttributeValue(rawText); - if (!escapedTxtStr.isEmpty()) { - if (rawText.length() > 20) {// if the raw text is too long only test the first 20 characters - escapedTxtStr = WindowsEnumeratedXml.escapeXmlAttributeValue(rawText.substring(0, 20)); - } - } - return escapedTxtStr; - } - - public String buildUiaXpathStatement() { - if (enumProperties == null) - return ""; - if (enumProperties.isEmpty()) - return ""; - String builtXpath = ""; - String xml = this.windowsXmlTextPane.getText(); - - WindowInfo wi = new WindowInfo(enumProperties, true); - String onlyRuntimeIdXpath = "//*[@hwnd='" + wi.runtimeId + "']"; - List wpfResultList = WindowsEnumeratedXml.evaluateXpathGetValues(xml, onlyRuntimeIdXpath); - //System.out.println("evaluateXpathGetValues1: " + onlyRuntimeIdXpath + " = " + wpfResultList.size()); - if (wpfResultList.size() == 0) - return""; - //System.out.println("enumProperties: " + enumProperties); - String typeStr = wi.controlType; - String txtOrig = wi.text; - //String winValueOrig = wpf.getWindowValue(runtimeId); - //System.out.println("text: " + txtOrig); - String txtStr = compareLongTextString(txtOrig); - - builtXpath = "//*[@type='" + typeStr + "' and starts-with(@text,'" + txtStr + "')" + "]"; - - //builtXpath = "//*[@hwnd='" + runtimeId + "']"; - wpfResultList = WindowsEnumeratedXml.evaluateXpathGetValues(xml, builtXpath); - //System.out.println("evaluateXpathGetValues2: " + builtXpath + " = " + wpfResultList.size()); - if (wpfResultList.size() == 1) - return builtXpath; - return onlyRuntimeIdXpath; - } - - public String buildXpathStatement() { - return buildXpathStatement(false, 20, 30); - } - - public String buildXpathStatement(boolean useFullTextMatching, int maxParentTextLength, int maxTextLength) { - String builtXpath = ""; - try { - String xml = this.windowsXmlTextPane.getText(); - if (enumProperties != null && !SynthuseDlg.config.isUiaBridgeDisabled()) { - if (!enumProperties.isEmpty()) { - builtXpath = buildUiaXpathStatement(); - } - } - if (builtXpath != "") - return builtXpath; - String classStr = WindowsEnumeratedXml.escapeXmlAttributeValue(Api.getWindowClassName(hwnd)); - String handleStr = Api.GetHandleAsString(hwnd); - String txtOrig = Api.getWindowText(hwnd); - String txtStr = WindowsEnumeratedXml.escapeXmlAttributeValue(txtOrig); - builtXpath = "//win[@class='" + classStr + "']"; - List resultList = WindowsEnumeratedXml.evaluateXpathGetValues(xml, builtXpath); - //int matches = nextXpathMatch(builtXpath, textPane, true); - if (resultList.size() > 1) { // if there are multiple results with the simple xpath then include parent class and text with the xpath statement. - HWND parent = User32Ex.instance.GetParent(hwnd); - String parentClassStr = WindowsEnumeratedXml.escapeXmlAttributeValue(Api.getWindowClassName(parent)); - String parentTxtOrig = Api.getWindowText(parent); - String parentTxtStr = WindowsEnumeratedXml.escapeXmlAttributeValue(parentTxtOrig); - if (!parentTxtStr.isEmpty()) { - if (parentTxtOrig.length() > maxParentTextLength) {// if the parent text is too long only test the first maxParentTextLength characters - parentTxtStr = WindowsEnumeratedXml.escapeXmlAttributeValue(parentTxtOrig.substring(0, maxParentTextLength)); - parentTxtStr = " and starts-with(@text,'" + parentTxtStr + "')"; - } - else - parentTxtStr = " and @text='" + parentTxtStr + "'"; - } - if (!parentClassStr.isEmpty()) - { - if (!txtStr.isEmpty()&&useFullTextMatching) { - String copyOfTxtStr = txtStr; - if (copyOfTxtStr.length() > maxTextLength) {// if the text is too long only test the first maxTextLength characters - copyOfTxtStr = WindowsEnumeratedXml.escapeXmlAttributeValue(copyOfTxtStr.substring(0, maxTextLength)); - copyOfTxtStr = " and starts-with(@text,'" + copyOfTxtStr + "')"; - } - else - copyOfTxtStr = " and @text='" + copyOfTxtStr + "'"; - builtXpath = "//win[@class='" + parentClassStr + "'" + parentTxtStr + "]/win[@class='" + classStr + "'" + copyOfTxtStr + "]"; - } - else - { - builtXpath = "//win[@class='" + parentClassStr + "'" + parentTxtStr + "]/win[@class='" + classStr + "']"; - } - } - System.out.println(builtXpath); - resultList = WindowsEnumeratedXml.evaluateXpathGetValues(xml, builtXpath); - if (resultList.size() > 1) { // if there are still multiple results add position to the xpath - int position = 1; - for (String result : resultList) { - if (result.contains(handleStr)) { - builtXpath += "[" + position + "]"; - break; - } - ++position; - } - } - if (resultList.size() == 0) { //some reason a window might have a parent window that is not associated with it's child (orphans!!) - if (!txtStr.isEmpty()) { - if (txtStr.length() > maxTextLength) {// if the text is too long only test the first maxTextLength characters - txtStr = WindowsEnumeratedXml.escapeXmlAttributeValue(txtStr.substring(0, maxTextLength)); - txtStr = " and starts-with(@text,'" + txtStr + "')"; - } - else - txtStr = " and @text='" + txtStr + "'"; - } - builtXpath = "//win[@class='" + classStr + "'" + txtStr + "]"; - } - resultList = WindowsEnumeratedXml.evaluateXpathGetValues(xml, builtXpath); - if (resultList.size() > 1) //still too many matched, only use hwnd - builtXpath = "//win[@hwnd='" + handleStr + "']"; - } - } catch (Exception e) { - e.printStackTrace(); - } - - return builtXpath; - } - - public static int nextXpathMatch(String xpathExpr, JTextPane targetText, JLabel lblStatus, boolean alwaysFromTop) { - int results = 0; - try { - if (xpathExpr.length() == 0) - return results; - - if (targetText instanceof JTextPane) { - final JTextPane target = (JTextPane)targetText; - target.requestFocus(); - int cPos = 0; - try { - cPos = target.getCaretPosition(); - } catch(Exception ex) { - //return 0;//something is throwing nullpointer exception - } - if (alwaysFromTop) - cPos = 0; - int len = target.getStyledDocument().getLength(); - String xml = target.getText(0, len); - WindowsEnumeratedXml.lastException = null; - List resultList = WindowsEnumeratedXml.evaluateXpathGetValues(xml, xpathExpr); - if (resultList.size() == 0 && WindowsEnumeratedXml.lastException != null) { - String errMsg = WindowsEnumeratedXml.lastException.getCause().getMessage(); - JOptionPane.showMessageDialog(target.getTopLevelAncestor(), "Exception: " + errMsg, "Error", JOptionPane.ERROR_MESSAGE); - return -1; - } - results = resultList.size(); - String txt = ""; - String targetStr = target.getText(cPos, (len - cPos)); - int matches = 0; - int mPos = 0; - target.select(cPos, cPos); //clear selection - for (int i = 0; i < resultList.size(); i++) { - txt = resultList.get(i).trim(); - if (txt.length() == 0) - continue; - //if (txt.endsWith("\r\n")) - // txt = txt.substring(0, txt.length() - 2).trim(); - txt = txt.replaceAll("\r\n", "\n").trim(); - while ((mPos = targetStr.indexOf(txt)) != -1) { - if (matches == 0){ - if (!alwaysFromTop) - flashMatchingWindow(txt); - //target.setCaretPosition(cPos + mPos); - //target.select(cPos + mPos, cPos + mPos + txt.length()); - XmlEditorKit.HIGHLIGHTED_START = cPos + mPos; - XmlEditorKit.HIGHLIGHTED_END = cPos + mPos + txt.length(); - //System.out.println("HIGHLIGHTED_START = " + (cPos + mPos)); - //System.out.println("HIGHLIGHTED_END = " + (cPos + mPos + txt.length())); - final int cpos = cPos + mPos +2; - EventQueue.invokeLater(new Runnable() { - @Override - public void run() { - target.updateUI(); - target.setCaretPosition(cpos); - } - }); - } - targetStr = targetStr.substring(mPos + txt.length()); - ++matches; - } - } - lblStatus.setText(results + " match(es)"); - if (cPos > 0 && matches == 0 && !alwaysFromTop) { //ask if user wants to search from top - int result = JOptionPane.showConfirmDialog(target.getTopLevelAncestor(), "No more matches found. Do you want to search from the top of the document?", "Find", JOptionPane.YES_NO_OPTION); - if (result == JOptionPane.YES_OPTION) { - target.setCaretPosition(0); - nextXpathMatch(xpathExpr, targetText, lblStatus, alwaysFromTop); - } - } - } - } catch (Exception e) { - XmlEditorKit.HIGHLIGHTED_START = 0; - XmlEditorKit.HIGHLIGHTED_END = 0; - e.printStackTrace(); - } - return results; - } - - public static void flashMatchingWindow(String txtXml) { - if (txtXml.contains("hwnd")) { - List hwndList = WindowsEnumeratedXml.evaluateXpathGetValues(txtXml, "//@hwnd"); - if (hwndList.size() > 0) { - String hwndStr = hwndList.get(0); - HWND tHwnd = Api.GetHandleFromString(hwndStr); - Api.highlightWindow(tHwnd); - try { Thread.sleep(100); } catch (Exception e) {e.printStackTrace();} - Api.refreshWindow(tHwnd); - try { Thread.sleep(100); } catch (Exception e) {e.printStackTrace();} - Api.highlightWindow(tHwnd); - try { Thread.sleep(100); } catch (Exception e) {e.printStackTrace();} - Api.refreshWindow(tHwnd); - } - } - } - -} diff --git a/src/org/synthuse/commands/BaseCommand.java b/src/org/synthuse/commands/BaseCommand.java deleted file mode 100644 index 4025c0c..0000000 --- a/src/org/synthuse/commands/BaseCommand.java +++ /dev/null @@ -1,311 +0,0 @@ -/* - * Copyright 2014, Synthuse.org - * Released under the Apache Version 2.0 License. - * - * last modified by ejakubowski -*/ - -package org.synthuse.commands; - - -import java.awt.Point; -import java.io.PrintWriter; -import java.io.StringWriter; -import java.sql.Timestamp; -import java.util.Date; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; - -import org.synthuse.*; - -import com.sun.jna.platform.win32.WinDef.HWND; - -public class BaseCommand { - - static String WIN_XML = ""; - static long LAST_UPDATED_XML = 0; - - protected Api api = new Api(); - protected UiaBridge uiabridge = new UiaBridge(); - protected CommandProcessor parentProcessor = null; - - protected int getExecuteErrorCount() { - return parentProcessor.executeErrorCount; - } - - protected void setExecuteErrorCount(int val) { - parentProcessor.executeErrorCount = val; - } - - protected String getCurrentCommand() { - return parentProcessor.currentCommandText; - } - - protected void setCurrentCommand(String val) { - parentProcessor.currentCommandText = val; - } - - protected boolean isProcessorStopped() { - return CommandProcessor.STOP_PROCESSOR.get(); - } - - public BaseCommand(CommandProcessor cp) { // should pass in the parent command processor - parentProcessor = cp; - } - - public void appendError(Exception e) { - setExecuteErrorCount(getExecuteErrorCount() + 1); - StringWriter sw = new StringWriter(); - e.printStackTrace(new PrintWriter(sw)); - parentProcessor.lastError += new Timestamp((new Date()).getTime()) + " - " + sw.toString() + "\n"; - try { - sw.close(); - } catch (Exception ex) { - ex.printStackTrace(); - } - } - - public void appendError(String msg) { - setExecuteErrorCount(getExecuteErrorCount() + 1); - parentProcessor.lastError += new Timestamp((new Date()).getTime()) + " - " + msg + "\n"; - } - - public boolean checkArgumentLength(String[] args, int expectedLength) { - if (args.length < expectedLength) { - appendError("Error: expected at least " + expectedLength + " arguments (" + getCurrentCommand() + "[" + args.length + "])"); - return false; - } - return true; - } - - public boolean checkFirstArgumentLength(String[] args) { - if (args[0].length() <= 0) { - appendError("Error: command '" + getCurrentCommand() + "' failed, expected first argument length > 0"); - return false; - } - return true; - } - - public boolean checkIsNumeric(String val) { - try { - Long.parseLong(val); - } catch(NumberFormatException e) { - appendError("Error: command '" + getCurrentCommand() + "' failed, was expecting a numeric value instead '" + val + "'"); - return false; - } - return true; - } - - public boolean whenFalseAppendError(boolean cmdResult) { - if (!cmdResult) - appendError("Error: command '" + getCurrentCommand() + "' failed"); - return cmdResult; - } - - public void forceXmlRefresh() { - WIN_XML = WindowsEnumeratedXml.getXml(); - LAST_UPDATED_XML = System.nanoTime(); - } - - public void forceWin32OnlyXmlRefresh() { - WIN_XML = WindowsEnumeratedXml.getWin32Xml(); - LAST_UPDATED_XML = System.nanoTime(); - } - - public void onlyRefreshWin32(boolean flg) { - SynthuseDlg.config.disableUiaBridge = flg + ""; - } - - public void targetXmlRefresh(String xpath) { - if (WIN_XML.isEmpty()) //can't target refresh unless there is XML to start with - { - forceXmlRefresh(); - return; - } - //WIN_XML = WindowsEnumeratedXml.getXml(); - LAST_UPDATED_XML = System.nanoTime(); - - String resultStr = ""; - String resultHwndStr = ""; - List resultList = WindowsEnumeratedXml.evaluateXpathGetValues(WIN_XML, xpath); - for(String item: resultList) { - //System.out.println("xpath result item: " + item); - resultStr = item; - if (item.contains("hwnd=")) { - List hwndList = WindowsEnumeratedXml.evaluateXpathGetValues(item, "//@hwnd"); - if (hwndList.size() > 0) - resultHwndStr = hwndList.get(0).replaceAll("[^\\d-.]", ""); //get first hwnd; - } - else - resultStr = item; - break; - } - String newXml = ""; - Map infoList; - if (resultHwndStr.contains("-")) { //uiabridge target refresh - resultHwndStr = resultHwndStr.split("-")[1]; - infoList = WindowsEnumeratedXml.EnumerateWindowsWithUiaBridge(uiabridge, resultHwndStr, "*"); - newXml = WindowsEnumeratedXml.generateWindowsXml(infoList, "updates"); - //System.out.println("newXml: " + newXml); - } - else - { // native target refresh - infoList = new LinkedHashMap(); - HWND parentHwnd = Api.GetHandleFromString(resultHwndStr); - WindowInfo wi = new WindowInfo(parentHwnd, false); - infoList.put(wi.hwndStr, wi); - infoList.putAll(WindowsEnumeratedXml.EnumerateWin32ChildWindows(parentHwnd)); - //WindowsEnumeratedXml.appendUiaBridgeWindows(infoList); //if we need this we should specify a runtimeID handle instead - newXml = WindowsEnumeratedXml.generateWindowsXml(infoList, "updates"); - System.out.println("newNativeXml: " + newXml); - } - - int pos = WIN_XML.indexOf(resultStr); - WIN_XML = WIN_XML.substring(0, pos) + newXml + WIN_XML.substring(pos + resultStr.length()); - - } - - public String getWindowTypeWithXpath(String xpath) { - String result = ""; - double secondsFromLastUpdate = ((double)(System.nanoTime() - LAST_UPDATED_XML) / 1000000000); - if (secondsFromLastUpdate > CommandProcessor.XML_UPDATE_THRESHOLD) { //default 5 second threshold - WIN_XML = WindowsEnumeratedXml.getXml(); - LAST_UPDATED_XML = System.nanoTime(); - } - String resultStr = ""; - List resultList = WindowsEnumeratedXml.evaluateXpathGetValues(WIN_XML, xpath); - if (resultList.size() > 0) - { - resultStr = resultList.get(0).trim(); - if (resultStr.startsWith(" CommandProcessor.XML_UPDATE_THRESHOLD) { //default 5 second threshold - WIN_XML = WindowsEnumeratedXml.getXml(); - LAST_UPDATED_XML = System.nanoTime(); - } - //WindowsEnumeratedXml.evaluateXpathGetValues(WIN_XML, xpath); - String resultStr = ""; - List resultList = WindowsEnumeratedXml.evaluateXpathGetValues(WIN_XML, xpath); - for(String item: resultList) { - //System.out.println("xpath result item: " + item); - if (item.contains("hwnd=")) { - List hwndList = WindowsEnumeratedXml.evaluateXpathGetValues(item, "//@hwnd"); - if (hwndList.size() > 0) - resultStr = hwndList.get(0); //get first hwnd; - } - else - resultStr = item; - if (item.contains("hmenu=")) { //get menu information, useful for getting center of menu - List hmenuList = WindowsEnumeratedXml.evaluateXpathGetValues(item, "//@hmenu"); - if (hmenuList.size() > 0) - result.hmenuStr = hmenuList.get(0).replaceAll("[^\\d-.]", ""); //get first hmenu; - if (item.contains("id=")) { - List menuidList = WindowsEnumeratedXml.evaluateXpathGetValues(item, "//@position"); - if (menuidList.size() > 0) - result.hmenuPos = Integer.parseInt(menuidList.get(0).replaceAll("[^\\d-.]", "")); //get first id; - } - } - break;// we only care about the first item - } - - resultStr = resultStr.replaceAll("[^\\d-.]", ""); //remove all non-numeric values (except dash -) - if (WinPtr.isWpfRuntimeIdFormat(resultStr)) { - result.runtimeId = resultStr; - if (!ignoreFailedFind && result.isEmpty()) - appendError("Error: Failed to find window handle matching: " + xpath); - } - else { - result.hWnd = Api.GetHandleFromString(resultStr); - if (!ignoreFailedFind && !api.user32.IsWindow(result.hWnd)) - appendError("Error: Failed to locate window HWND(" + resultStr + ") from : " + xpath); - } - return result; - } - - public int findMenuIdWithXpath(String xpath) { - int result = 0; - double secondsFromLastUpdate = ((double)(System.nanoTime() - LAST_UPDATED_XML) / 1000000000); - if (secondsFromLastUpdate > CommandProcessor.XML_UPDATE_THRESHOLD) { //default 5 second threshold - WIN_XML = WindowsEnumeratedXml.getXml(); - LAST_UPDATED_XML = System.nanoTime(); - } - //WindowsEnumeratedXml.evaluateXpathGetValues(WIN_XML, xpath); - String resultStr = ""; - List resultList = WindowsEnumeratedXml.evaluateXpathGetValues(WIN_XML, xpath); - for(String item: resultList) { - if (item.contains("hmenu=")) { - List list = WindowsEnumeratedXml.evaluateXpathGetValues(item, "//@id"); - if (list.size() > 0) - resultStr = list.get(0); //get first id - } - else - resultStr = item; - break; - } - resultStr = resultStr.replaceAll("[^\\d.]", ""); //remove all non-numeric values - //System.out.println("findMenuIdWithXpath: " + resultStr); - if (resultStr.isEmpty()) - appendError("Error: Failed to find window handle matching: " + xpath); - else - result = Integer.parseInt(resultStr); - return result; - } - - - public Point getCenterWindowPosition(WinPtr handle) { - Point p = null; - if (handle.isWin32()) - p = api.getWindowPosition(handle.hWnd); - else - p = uiabridge.getCenterOfElement(handle.runtimeId); - return p; - } - - public Point getCenterWindowPosition(WinPtr handle, String windowType) { - Point p = null; - - if (handle.isWpf() || windowType.equals("winfrm") || windowType.equals("wpf") || windowType.equals("silver")) - p = uiabridge.getCenterOfElement(handle.runtimeId); - else if (windowType.equals("win")) - p = api.getWindowPosition(handle.hWnd); - else if (windowType.equals("menu")) - p = api.getMenuItemPosition(handle.hWnd, MenuInfo.GetHandleMenuFromString(handle.hmenuStr), handle.hmenuPos); - return p; - } - - public String convertListToString(List listStr, String delimiter) { - StringBuilder result = new StringBuilder(""); - for (String item: listStr) { - result.append(item + delimiter); - } - return result.toString(); - } - - public void killStatusWindow() { - parentProcessor.currentStatusWin.dispose(); - parentProcessor.currentStatusWin = null; - } - -} diff --git a/src/org/synthuse/commands/FileCommands.java b/src/org/synthuse/commands/FileCommands.java deleted file mode 100644 index 46fb55b..0000000 --- a/src/org/synthuse/commands/FileCommands.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2014, Synthuse.org - * Released under the Apache Version 2.0 License. - * - * last modified by ejakubowski -*/ - -package org.synthuse.commands; - -import java.io.*; -import org.synthuse.*; - -public class FileCommands extends BaseCommand { - - public FileCommands(CommandProcessor cp) { - super(cp); - } - - public String cmdGrepFile(String[] args) throws Exception { - if (!checkArgumentLength(args, 2)) - return null; - String filename = args[0]; - String pattern = args[1]; - StringBuilder result = new StringBuilder(""); - FileInputStream fis = null; - BufferedReader br = null; - try { - fis = new FileInputStream(filename); - DataInputStream dis = new DataInputStream(fis); - br = new BufferedReader(new InputStreamReader(dis)); - String strLine = ""; - while ((strLine = br.readLine()) != null) { - if (strLine.matches(pattern)) - result.append(strLine + "\n"); - } - } - catch (Exception ex) { - throw ex; - } - finally { - if (fis != null) - fis.close(); - if (br != null) - br.close(); - } - return result.toString(); - } - - public String cmdFileSearch(String[] args) { - if (!checkArgumentLength(args, 2)) - return null; - String path = args[0]; - String filenamePattern = args[1]; - StringBuilder result = new StringBuilder(""); - File parent = new File(path); - for(File child : parent.listFiles()) { - if (child.isFile() && child.getName().matches(filenamePattern)) - result.append(child.getAbsolutePath() + "\n"); - else if (child.isDirectory()) { - result.append(cmdFileSearch(new String[] {child.getAbsolutePath(), filenamePattern})); - } - } - return result.toString(); - } - -} diff --git a/src/org/synthuse/commands/KeyboardCommands.java b/src/org/synthuse/commands/KeyboardCommands.java deleted file mode 100644 index f5f1c1a..0000000 --- a/src/org/synthuse/commands/KeyboardCommands.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2014, Synthuse.org - * Released under the Apache Version 2.0 License. - * - * last modified by ejakubowski -*/ - -package org.synthuse.commands; - -import org.synthuse.*; - -public class KeyboardCommands extends BaseCommand { - - public KeyboardCommands(CommandProcessor commandProcessor) { - super(commandProcessor); - } - - public boolean cmdSendKeys(String[] args) { - if (!checkArgumentLength(args, 1)) - return false; - return whenFalseAppendError(RobotMacro.sendKeys(args[0])); - } - - public boolean cmdKeyDown(String[] args) { - if (!checkArgumentLength(args, 1)) - return false; - if (!checkFirstArgumentLength(args)) - return false; - char keyChar = args[0].charAt(0); - return RobotMacro.keyDown(keyChar); - } - - public boolean cmdKeyUp(String[] args) { - if (!checkArgumentLength(args, 1)) - return false; - if (!checkFirstArgumentLength(args)) - return false; - char keyChar = args[0].charAt(0); - return RobotMacro.keyUp(keyChar); - } - - public boolean cmdKeyCopy(String[] args) { - RobotMacro.copyKey(); - return true; - } - - public boolean cmdKeyPaste(String[] args) { - RobotMacro.pasteKey(); - return true; - } - - public boolean cmdKeyEscape(String[] args) { - RobotMacro.escapeKey(); - return true; - } - - public boolean cmdKeyFunc(String[] args) { - if (!checkArgumentLength(args, 1)) - return false; - if (!checkFirstArgumentLength(args)) - return false; - int fNum = Integer.parseInt(args[0]); - RobotMacro.functionKey(fNum); - return true; - } - -} diff --git a/src/org/synthuse/commands/MainCommands.java b/src/org/synthuse/commands/MainCommands.java deleted file mode 100644 index 406db3e..0000000 --- a/src/org/synthuse/commands/MainCommands.java +++ /dev/null @@ -1,247 +0,0 @@ -/* - * Copyright 2014, Synthuse.org - * Released under the Apache Version 2.0 License. - * - * last modified by ejakubowski -*/ - -package org.synthuse.commands; - -import java.awt.Dimension; -import java.awt.Rectangle; -import java.awt.Robot; -import java.awt.Toolkit; -import java.awt.image.BufferedImage; -import java.io.*; - -import javax.imageio.ImageIO; - -import org.synthuse.*; - -public class MainCommands extends BaseCommand { - - public MainCommands(CommandProcessor cp) { - super(cp); - } - - public boolean cmdOpen(String[] args) throws IOException { - if (!checkArgumentLength(args, 1)) - return false; - Runtime runtime = Runtime.getRuntime(); - runtime.exec(args[0]); - return true; - } - - public boolean cmdDisplayText(String[] args) throws IOException { - if (!checkArgumentLength(args, 2)) - return false; - if (!checkIsNumeric(args[1])) //arg[1] is in milliseconds - return false; - this.killStatusWindow(); - //System.out.println("StatusWindow " + args[0] + ", " + Integer.parseInt(args[1])); - StatusWindow sw = new StatusWindow(args[0], Integer.parseInt(args[1])); - Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); - sw.setLocation(dim.width/2-sw.getSize().width/2, dim.height + StatusWindow.Y_BOTTOM_OFFSET - 80 ); - return true; - } - - public boolean cmdSetSpeed(String[] args) { - if (!checkArgumentLength(args, 1)) - return false; - long speed = Long.parseLong(args[0]); - CommandProcessor.SPEED = speed; - return true; - } - - public boolean cmdSetTimeout(String[] args) { - if (!checkArgumentLength(args, 1)) - return false; - long timeout = Long.parseLong(args[0]); - CommandProcessor.WAIT_TIMEOUT_THRESHOLD = timeout; - return true; - } - - public boolean cmdSetUpdateThreshold(String[] args) { - if (!checkArgumentLength(args, 1)) - return false; - long threshold = Long.parseLong(args[0]); - CommandProcessor.XML_UPDATE_THRESHOLD = threshold; - return true; - } - - public boolean cmdForceRefresh(String[] args) { - if (!checkArgumentLength(args, 0)) - return false; - forceXmlRefresh(); - return true; - } - - public boolean cmdForceWin32Refresh(String[] args) { - if (!checkArgumentLength(args, 0)) - return false; - forceWin32OnlyXmlRefresh(); - return true; - } - - public boolean cmdOnlyRefreshWin32(String[] args) { - if (!checkArgumentLength(args, 1)) - return false; - boolean flg = Boolean.parseBoolean(args[0]); - onlyRefreshWin32(flg); - return true; - } - - public boolean cmdTargetRefresh(String[] args) { - if (!checkArgumentLength(args, 1)) - return false; - targetXmlRefresh(args[0]); - return true; - } - - public boolean cmdWaitForTitle(String[] args) { - if (!checkArgumentLength(args, 1)) - return false; - long totalAttempts = (long) (CommandProcessor.WAIT_TIMEOUT_THRESHOLD / (CommandProcessor.XML_UPDATE_THRESHOLD * 1000)); - long attemptCount = 0; - String xpath = "/EnumeratedWindows/*[@TEXT='" + WindowsEnumeratedXml.escapeXmlAttributeValue(args[0].toUpperCase()) + "']"; - WinPtr handle = findHandleWithXpath(xpath, true); - if (!handle.isEmpty())// first test without a timeout - return true; - while (attemptCount < totalAttempts) { - handle = findHandleWithXpath(xpath, true); - if (!handle.isEmpty()) - break; - try {Thread.sleep((long)(CommandProcessor.XML_UPDATE_THRESHOLD * 1000));} catch (Exception e) {e.printStackTrace();} - ++attemptCount; - if (isProcessorStopped()) - break; - } - if (handle.isEmpty()) - appendError("Error: command '" + getCurrentCommand() + "' failed to find element matching " + args[0]); - return (!handle.isEmpty()); - } - - public boolean cmdWaitForText(String[] args) { - if (!checkArgumentLength(args, 1)) - return false; - long totalAttempts = (long) (CommandProcessor.WAIT_TIMEOUT_THRESHOLD / (CommandProcessor.XML_UPDATE_THRESHOLD * 1000)); - long attemptCount = 0; - String xpath = "//[@TEXT='" + WindowsEnumeratedXml.escapeXmlAttributeValue(args[0].toUpperCase()) + "']"; - WinPtr handle = findHandleWithXpath(xpath, true); - if (!handle.isEmpty())// first test without a timeout - return true; - while (attemptCount < totalAttempts) { - handle = findHandleWithXpath(xpath, true); - if (!handle.isEmpty()) - break; - try {Thread.sleep((long)(CommandProcessor.XML_UPDATE_THRESHOLD * 1000));} catch (Exception e) {e.printStackTrace();} - ++attemptCount; - if (isProcessorStopped()) - break; - } - if (handle.isEmpty()) - appendError("Error: command '" + getCurrentCommand() + "' failed to find element matching " + args[0]); - return (!handle.isEmpty()); - } - - public boolean cmdWaitForClass(String[] args) { - if (!checkArgumentLength(args, 1)) - return false; - long totalAttempts = (long) (CommandProcessor.WAIT_TIMEOUT_THRESHOLD / (CommandProcessor.XML_UPDATE_THRESHOLD * 1000)); - long attemptCount = 0; - String xpath = "//[@CLASS='" + WindowsEnumeratedXml.escapeXmlAttributeValue(args[0].toUpperCase()) + "']"; - WinPtr handle = findHandleWithXpath(xpath, true); - if (!handle.isEmpty())// first test without a timeout - return true; - while (attemptCount < totalAttempts) { - handle = findHandleWithXpath(xpath, true); - if (!handle.isEmpty()) - break; - try {Thread.sleep((long)(CommandProcessor.XML_UPDATE_THRESHOLD * 1000));} catch (Exception e) {e.printStackTrace();} - ++attemptCount; - if (isProcessorStopped()) - break; - } - if (handle.isEmpty()) - appendError("Error: command '" + getCurrentCommand() + "' failed to find element matching " + args[0]); - return (!handle.isEmpty()); - } - - public boolean cmdWaitForVisible(String[] args) { - if (!checkArgumentLength(args, 1)) - return false; - long totalAttempts = (long) (CommandProcessor.WAIT_TIMEOUT_THRESHOLD / (CommandProcessor.XML_UPDATE_THRESHOLD * 1000)); - long attemptCount = 0; - WinPtr handle = findHandleWithXpath(args[0], true); - if (!handle.isEmpty())// first test without a timeout - return true; - while (attemptCount < totalAttempts) { - handle = findHandleWithXpath(args[0], true); - if (!handle.isEmpty()) - break; - try {Thread.sleep((long)(CommandProcessor.XML_UPDATE_THRESHOLD * 1000));} catch (Exception e) {e.printStackTrace();} - ++attemptCount; - if (isProcessorStopped()) - break; - } - if (handle.isEmpty()) - appendError("Error: command '" + getCurrentCommand() + "' failed to find element matching " + args[0]); - return (!handle.isEmpty()); - } - - public boolean cmdVerifyElementNotPresent(String[] args) - { - if (!checkArgumentLength(args, 1)) - return false; - WinPtr handle = findHandleWithXpath(args[0], true); - if (!handle.isEmpty()) - { - appendError("Error: command '" + getCurrentCommand() + "' failed to NOT find element matching " + args[0]); - return false; - } - else - return true; - } - - public boolean cmdVerifyElementPresent(String[] args) - { - if (!checkArgumentLength(args, 1)) - return false; - WinPtr handle = findHandleWithXpath(args[0], true); - if (!handle.isEmpty()) - return true; - else - { - appendError("Error: command '" + getCurrentCommand() + "' failed to find element matching " + args[0]); - return false; - } - } - - public boolean cmdDisableStatus(String[] args) { - if (!checkArgumentLength(args, 1)) - return false; - boolean val = args[0].toUpperCase().equals("TRUE"); - parentProcessor.setQuiet(val); - return true; - } - - public boolean cmdTakeScreenCapture(String[] args) { - if (!checkArgumentLength(args, 1)) - return false; - try { - String saveName = args[0]; - if (!saveName.toLowerCase().endsWith(".png")) - saveName += ".png"; - //LOG.debug("take Screen Capture " + new File(saveName).getAbsolutePath()); - Robot robot = new Robot(); - Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); - BufferedImage image = robot.createScreenCapture(new Rectangle(screenSize)); - ImageIO.write(image, "png", new File(saveName)); - } - catch(Exception e) { - //e.printStackTrace(); - appendError(e); - } - return true; - } -} diff --git a/src/org/synthuse/commands/MouseCommands.java b/src/org/synthuse/commands/MouseCommands.java deleted file mode 100644 index 4f90236..0000000 --- a/src/org/synthuse/commands/MouseCommands.java +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright 2014, Synthuse.org - * Released under the Apache Version 2.0 License. - * - * last modified by ejakubowski -*/ - -package org.synthuse.commands; - -import java.awt.Point; - -import org.synthuse.*; - -public class MouseCommands extends BaseCommand { - - public MouseCommands(CommandProcessor commandProcessor) { - super(commandProcessor); - } - - public boolean cmdClick(String[] args) { - if (!checkArgumentLength(args, 1)) - return false; - WinPtr handle = findHandleWithXpath(args[0]); - //System.out.println("cmdClick1: " + args[0]); - if (handle.isEmpty()) - return false; - String wtype = getWindowTypeWithXpath(args[0]); - //System.out.println("wtype: " + wtype + " hwnd " + handle.hWnd + " hmenu " + handle.hmenuStr + " pos " + handle.hmenuPos); - Point p = getCenterWindowPosition(handle, wtype); - //System.out.println("cmdClick: " + p.x + "," + p.y); - RobotMacro.mouseMove(p.x + parentProcessor.targetOffset.x, p.y + parentProcessor.targetOffset.y); - RobotMacro.leftClickMouse(); - return true; - } - - public boolean cmdDoubleClick(String[] args) { - if (!checkArgumentLength(args, 1)) - return false; - WinPtr handle = findHandleWithXpath(args[0]); - if (handle.isEmpty()) - return false; - String wtype = getWindowTypeWithXpath(args[0]); - Point p = getCenterWindowPosition(handle, wtype); - RobotMacro.mouseMove(p.x + parentProcessor.targetOffset.x, p.y + parentProcessor.targetOffset.y); - RobotMacro.doubleClickMouse(); - return true; - } - - public boolean cmdRightClick(String[] args) { - if (!checkArgumentLength(args, 1)) - return false; - WinPtr handle = findHandleWithXpath(args[0]); - if (handle.isEmpty()) - return false; - String wtype = getWindowTypeWithXpath(args[0]); - Point p = getCenterWindowPosition(handle, wtype); - RobotMacro.mouseMove(p.x + parentProcessor.targetOffset.x, p.y + parentProcessor.targetOffset.y); - RobotMacro.rightClickMouse(); - return true; - } - - public boolean cmdMouseDown(String[] args) { - RobotMacro.leftMouseDown(); - return true; - } - - public boolean cmdMouseUp(String[] args) { - RobotMacro.leftMouseUp(); - return true; - } - - public boolean cmdMouseDownRight(String[] args) { - RobotMacro.rightMouseDown(); - return true; - } - - public boolean cmdMouseUpRight(String[] args) { - RobotMacro.rightMouseUp(); - return true; - } - - public boolean cmdMouseMove(String[] args) { - if (!checkArgumentLength(args, 1)) - return false; - WinPtr handle = findHandleWithXpath(args[0]); - if (handle.isEmpty()) - return false; - String wtype = getWindowTypeWithXpath(args[0]); - Point p = getCenterWindowPosition(handle, wtype); - RobotMacro.mouseMove(p.x + parentProcessor.targetOffset.x, p.y + parentProcessor.targetOffset.y); - //System.out.println("point " + p.x + "," + p.y); - return true; - } - - public boolean cmdSetTargetOffset(String[] args) { - if (!checkArgumentLength(args, 2)) - return false; - int x = Integer.parseInt(args[0]); - int y = Integer.parseInt(args[1]); - parentProcessor.targetOffset.x = x; - parentProcessor.targetOffset.y = y; - return true; - } - public boolean cmdMouseMoveXy(String[] args) { - if (!checkArgumentLength(args, 2)) - return false; - int x = Integer.parseInt(args[0]); - int y = Integer.parseInt(args[1]); - RobotMacro.mouseMove(x, y); - return true; - } - - public boolean cmdWinClick(String[] args) { - if (!checkArgumentLength(args, 1)) - return false; - WinPtr handle = findHandleWithXpath(args[0]); - if (handle.isEmpty()) - return false; - api.sendClick(handle.hWnd); - return true; - } - - public boolean cmdWinDoubleClick(String[] args) { - if (!checkArgumentLength(args, 1)) - return false; - WinPtr handle = findHandleWithXpath(args[0]); - if (handle.isEmpty()) - return false; - api.sendDoubleClick(handle.hWnd); - return true; - } - - public boolean cmdWinRightClick(String[] args) { - if (!checkArgumentLength(args, 1)) - return false; - WinPtr handle = findHandleWithXpath(args[0]); - if (handle.isEmpty()) - return false; - api.sendRightClick(handle.hWnd); - return true; - } -} diff --git a/src/org/synthuse/commands/WindowsCommands.java b/src/org/synthuse/commands/WindowsCommands.java deleted file mode 100644 index bf1b517..0000000 --- a/src/org/synthuse/commands/WindowsCommands.java +++ /dev/null @@ -1,216 +0,0 @@ -/* - * Copyright 2014, Synthuse.org - * Released under the Apache Version 2.0 License. - * - * last modified by ejakubowski -*/ - -package org.synthuse.commands; - -import org.synthuse.*; - -import com.sun.jna.platform.win32.WinDef.LPARAM; -import com.sun.jna.platform.win32.WinDef.WPARAM; - -public class WindowsCommands extends BaseCommand { - - public WindowsCommands(CommandProcessor cp) { - super(cp); - } - - public boolean cmdWindowFocus(String[] args) { - if (!checkArgumentLength(args, 1)) - return false; - WinPtr handle = findHandleWithXpath(args[0]); - if (handle.isEmpty()) - return false; - handle.convertToNativeHwnd(); - api.activateWindow(handle.hWnd); - //api.showWindow(handle); - return true; - } - - public boolean cmdWindowMinimize(String[] args) { - if (!checkArgumentLength(args, 1)) - return false; - WinPtr handle = findHandleWithXpath(args[0]); - if (handle.isEmpty()) - return false; - handle.convertToNativeHwnd(); - api.minimizeWindow(handle.hWnd); - return true; - } - - public boolean cmdWindowMaximize(String[] args) { - if (!checkArgumentLength(args, 1)) - return false; - WinPtr handle = findHandleWithXpath(args[0]); - if (handle.isEmpty()) - return false; - handle.convertToNativeHwnd(); - api.maximizeWindow(handle.hWnd); - return true; - } - - public boolean cmdWindowRestore(String[] args) { - if (!checkArgumentLength(args, 1)) - return false; - WinPtr handle = findHandleWithXpath(args[0]); - if (handle.isEmpty()) - return false; - handle.convertToNativeHwnd(); - api.restoreWindow(handle.hWnd); - return true; - } - - public boolean cmdWindowHide(String[] args) { - if (!checkArgumentLength(args, 1)) - return false; - WinPtr handle = findHandleWithXpath(args[0]); - if (handle.isEmpty()) - return false; - handle.convertToNativeHwnd(); - api.hideWindow(handle.hWnd); - return true; - } - - public boolean cmdWindowShow(String[] args) { - if (!checkArgumentLength(args, 1)) - return false; - WinPtr handle = findHandleWithXpath(args[0]); - if (handle.isEmpty()) - return false; - handle.convertToNativeHwnd(); - api.showWindow(handle.hWnd); - return true; - } - - public boolean cmdWindowSwitchToThis(String[] args) { - if (!checkArgumentLength(args, 1)) - return false; - WinPtr handle = findHandleWithXpath(args[0]); - if (handle.isEmpty()) - return false; - handle.convertToNativeHwnd(); - api.switchToThisWindow(handle.hWnd, true); - return true; - } - - - public boolean cmdWindowClose(String[] args) { - if (!checkArgumentLength(args, 1)) - return false; - WinPtr handle = findHandleWithXpath(args[0]); - if (handle.isEmpty()) - return false; - handle.convertToNativeHwnd(); - api.closeWindow(handle.hWnd); - return true; - } - - public boolean cmdSetText(String[] args) { - if (!checkArgumentLength(args, 2)) - return false; - WinPtr handle = findHandleWithXpath(args[0]); - if (handle.isEmpty()) - return false; - handle.convertToNativeHwnd(); - api.sendWmSetText(handle.hWnd, args[1]); - return true; - } - - public String cmdGetText(String[] args) { - if (!checkArgumentLength(args, 1)) - return ""; - WinPtr handle = findHandleWithXpath(args[0]); - if (handle.isEmpty()) - return ""; - handle.convertToNativeHwnd(); - return api.sendWmGetText(handle.hWnd); - } - - public boolean cmdSelectMenu(String[] args) { - if (!checkArgumentLength(args, 1)) - return false; - WinPtr handle = findHandleWithXpath(args[0]); - if (handle.isEmpty()) - return false; - int id = findMenuIdWithXpath(args[0]); - handle.convertToNativeHwnd(); - //LRESULT result = - //System.out.println("PostMessage to " + handle.hWndStr + " for id " + id); - api.user32.PostMessage(handle.hWnd, Api.WM_COMMAND, new WPARAM(id), new LPARAM(0)); - //api.user32.SendMessage(handle.hWnd, Api.WM_COMMAND, new WPARAM(id), new LPARAM(0)); - return true; - } - - public boolean cmdSelectContextMenuId(String[] args) { - if (!checkArgumentLength(args, 2)) - return false; - WinPtr handle = findHandleWithXpath(args[0]); //xpath to HWND is first argument - if (handle.isEmpty()) - return false; - int id = Integer.parseInt(args[1]); //context menu id is supplied as second argument - handle.convertToNativeHwnd(); - //LRESULT result = - System.out.println("PostMessage to " + handle.toString() + " for id " + id + " - " + Api.MAKELONG(id, 0)); - //api.user32.PostMessage(handle.hWnd, Api.WM_COMMAND, new WPARAM(id), new LPARAM(0)); - api.user32.SendMessage(handle.hWnd, Api.WM_COMMAND, new WPARAM(Api.MAKELONG(id, 0)), new LPARAM(0)); - - return true; - } - - public boolean cmdSendCommandMsg(String[] args) { - if (!checkArgumentLength(args, 3)) - return false; - WinPtr handle = findHandleWithXpath(args[0]); //xpath to HWND is first argument - if (handle.isEmpty()) - return false; - int id = Integer.parseInt(args[1]); //context menu id is supplied as second argument - int idLparam = Integer.parseInt(args[2]); //context menu id is supplied as second argument - handle.convertToNativeHwnd(); - //LRESULT result = - //System.out.println("Send Message WM_COMMAND to " + handle.toString() + " PARAMS: " + id + ", " + idLparam); - //api.user32.PostMessage(handle.hWnd, Api.WM_COMMAND, new WPARAM(id), new LPARAM(0)); - api.user32.SendMessage(handle.hWnd, Api.WM_COMMAND, new WPARAM(id), new LPARAM(idLparam)); - - return true; - } - - public boolean cmdSendMessage(String[] args) { - if (!checkArgumentLength(args, 4)) - return false; - WinPtr handle = findHandleWithXpath(args[0]); //xpath to HWND is first argument - if (handle.isEmpty()) - return false; - int msg = Integer.parseInt(args[1]); - int id = Integer.parseInt(args[2]); //context menu id is supplied as second argument - int idLparam = Integer.parseInt(args[3]); //context menu id is supplied as second argument - handle.convertToNativeHwnd(); - //LRESULT result = - //System.out.println("Send Message WM_COMMAND to " + handle.toString() + " PARAMS: " + id + ", " + idLparam); - //api.user32.PostMessage(handle.hWnd, Api.WM_COMMAND, new WPARAM(id), new LPARAM(0)); - api.user32.SendMessage(handle.hWnd, msg, new WPARAM(id), new LPARAM(idLparam)); - - return true; - } - - public boolean cmdSelectListIndex(String[] args) { - if (!checkArgumentLength(args, 2)) - return false; - WinPtr handle = findHandleWithXpath(args[0]); //xpath to HWND is first argument - if (handle.isEmpty()) - return false; - handle.convertToNativeHwnd(); - int index = Integer.parseInt(args[1]); - Api.SelectListItemByIndex(handle.hWnd, index); - return true; - } - - public boolean cmdSelectListString(String[] args) { - //CB_SELECTSTRING - return true; - - } - -} \ No newline at end of file diff --git a/src/org/synthuse/controllers/SynthuseConfigDialogControllers.java b/src/org/synthuse/controllers/SynthuseConfigDialogControllers.java deleted file mode 100755 index c3d7fbd..0000000 --- a/src/org/synthuse/controllers/SynthuseConfigDialogControllers.java +++ /dev/null @@ -1,121 +0,0 @@ -package org.synthuse.controllers; - -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; - -import javax.swing.JOptionPane; - -import org.synthuse.Config; -import org.synthuse.views.SynthuseConfigPanel; - -public class SynthuseConfigDialogControllers { - - public static void initializeUI(SynthuseConfigPanel aSynthuseConfigPanel, Config aConfig) { - aSynthuseConfigPanel.getAlwaysOnTopCheckBox().setSelected(aConfig.isAlwaysOnTop()); - aSynthuseConfigPanel.getDisableFiltersUiaCheckBox().setSelected(aConfig.isFilterUiaDisabled()); - aSynthuseConfigPanel.getDisableUiaBridgeCheckBox().setSelected(aConfig.isUiaBridgeDisabled()); - aSynthuseConfigPanel.getRefreshKeyTextField().setText(Character.toString(aConfig.getRefreshKey())); - aSynthuseConfigPanel.getStrongTextMatchingCheckBox().setSelected(aConfig.isUseStrongTextMatching()); - aSynthuseConfigPanel.getTargetKeyTextField().setText(Character.toString(aConfig.getTargetKey())); - aSynthuseConfigPanel.getXPathHighlightTextField().setText(aConfig.getXpathHighlight()); - aSynthuseConfigPanel.getXPathListTextField().setText(aConfig.getXpathList()); - } - - public static void bindActionControllers(final SynthuseConfigPanel aSynthuseConfigPanel, final Config aConfig) { - aSynthuseConfigPanel.getAlwaysOnTopCheckBox().addActionListener(alwaysOnTopCheckboxActionHandler(aSynthuseConfigPanel, aConfig)); - aSynthuseConfigPanel.getDisableFiltersUiaCheckBox().addActionListener(disableFiltersUiaCheckboxActionHandler(aSynthuseConfigPanel, aConfig)); - aSynthuseConfigPanel.getDisableUiaBridgeCheckBox().addActionListener(disableUiaBridgeCheckboxActionHandler(aSynthuseConfigPanel, aConfig)); - aSynthuseConfigPanel.getRefreshKeyTextField().addActionListener(refreshKeyCodeTextFieldActionHandler(aSynthuseConfigPanel, aConfig)); - aSynthuseConfigPanel.getStrongTextMatchingCheckBox().addActionListener(strongTextMatchingCheckboxActionHandler(aSynthuseConfigPanel, aConfig)); - aSynthuseConfigPanel.getTargetKeyTextField().addActionListener(targetKeyCodeTextFieldActionHandler(aSynthuseConfigPanel, aConfig)); - aSynthuseConfigPanel.getXPathHighlightTextField().addActionListener(xpathHighlightTextFieldActionHandler(aSynthuseConfigPanel, aConfig)); - aSynthuseConfigPanel.getXPathListTextField().addActionListener(xpathListTextFieldActionHandler(aSynthuseConfigPanel, aConfig)); - } - - private static ActionListener xpathListTextFieldActionHandler(final SynthuseConfigPanel aSynthuseConfigPanel, - final Config aConfig) { - return new ActionListener() { - @Override - public void actionPerformed(ActionEvent aE) { - aConfig.setXPathList(aSynthuseConfigPanel.getXPathListTextField().getText()); - JOptionPane.showMessageDialog(aSynthuseConfigPanel, "May require restart to be effective"); - } - }; - } - - private static ActionListener xpathHighlightTextFieldActionHandler(final SynthuseConfigPanel aSynthuseConfigPanel, - final Config aConfig) { - return new ActionListener() { - @Override - public void actionPerformed(ActionEvent aE) { - aConfig.setXPathHighlight(aSynthuseConfigPanel.getXPathHighlightTextField().getText()); - JOptionPane.showMessageDialog(aSynthuseConfigPanel, "May require restart to be effective"); - } - }; - } - - private static ActionListener targetKeyCodeTextFieldActionHandler(final SynthuseConfigPanel aSynthuseConfigPanel, - final Config aConfig) { - return new ActionListener() { - @Override - public void actionPerformed(ActionEvent aE) { - aConfig.setTargetKey(aSynthuseConfigPanel.getTargetKeyTextField().getText()); - JOptionPane.showMessageDialog(aSynthuseConfigPanel, "May require restart to be effective"); - } - }; - } - - private static ActionListener strongTextMatchingCheckboxActionHandler( - final SynthuseConfigPanel aSynthuseConfigPanel, final Config aConfig) { - return new ActionListener() { - @Override - public void actionPerformed(ActionEvent aE) { - aConfig.setUseStrongTextMatching(aSynthuseConfigPanel.getStrongTextMatchingCheckBox().isSelected()); - } - }; - } - - private static ActionListener refreshKeyCodeTextFieldActionHandler(final SynthuseConfigPanel aSynthuseConfigPanel, - final Config aConfig) { - return new ActionListener() { - @Override - public void actionPerformed(ActionEvent aE) { - aConfig.setRefreshKey(aSynthuseConfigPanel.getRefreshKeyTextField().getText()); - JOptionPane.showMessageDialog(aSynthuseConfigPanel, "May require restart to be effective"); - } - }; - } - - private static ActionListener disableUiaBridgeCheckboxActionHandler(final SynthuseConfigPanel aSynthuseConfigPanel, - final Config aConfig) { - return new ActionListener() { - @Override - public void actionPerformed(ActionEvent aE) { - aConfig.setDisableUiaBridge(aSynthuseConfigPanel.getDisableUiaBridgeCheckBox().isSelected()); - JOptionPane.showMessageDialog(aSynthuseConfigPanel, "May require restart to be effective"); - } - }; - } - - private static ActionListener disableFiltersUiaCheckboxActionHandler(final SynthuseConfigPanel aSynthuseConfigPanel, - final Config aConfig) { - return new ActionListener() { - @Override - public void actionPerformed(ActionEvent aE) { - aConfig.setDisableFiltersUia(aSynthuseConfigPanel.getDisableFiltersUiaCheckBox().isSelected()); - JOptionPane.showMessageDialog(aSynthuseConfigPanel, "May require restart to be effective"); - } - }; - } - - private static ActionListener alwaysOnTopCheckboxActionHandler(final SynthuseConfigPanel aSynthuseConfigPanel, - final Config aConfig) { - return new ActionListener() { - @Override - public void actionPerformed(ActionEvent aE) { - aConfig.setAlwaysOnTop(aSynthuseConfigPanel.getAlwaysOnTopCheckBox().isSelected()); - JOptionPane.showMessageDialog(aSynthuseConfigPanel, "May require restart to be effective"); - } - }; - } -} diff --git a/src/org/synthuse/img/applications-education.png b/src/org/synthuse/img/applications-education.png deleted file mode 100644 index 957faf7e35426b99b2f73855c46d39ee2b5df300..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1165 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkEaiMiX|nnOwSFtCAu=4LNYFItDB)?_L9TWKQD$)Mppi)fRZ9h)B6wm z4qLKItnw0G=;<7KLe+h~(&xkb&-h=yl{GUUIM24eJ4}0NXvmbSJN#F+261l<<@?4b z@mtlmWz*e&*%kAPKbGDTs7-ny&Xf7%n|Ha##^=X29N!dQw83i0wnP7l=AUDo6>{p& zjHop6XEx2zg~=O_@4bIM@_hYdrw0k8C;F$`8!S^z;}c9g70s8w@4(UK;wwh8zn1bE zUf3F@sb~C6Irv_|&*!Sex^H;3|5cR8ZGv0+{))$~{As^0;PpB` zUx&@Dc5UYZ%&rGl{`_#Y>KKe#_hWgR{HpwtILY#*b3I@iyhL$0Q23Dpy=MP+(wo`PpG(DiR5 t*1Z5qt0Sc2LxX%^UIiJJ4_2+42~rLA>wEK6r-51+JYD@<);T3K0RUFg%s2o5 diff --git a/src/org/synthuse/img/arrow-right-3.png b/src/org/synthuse/img/arrow-right-3.png deleted file mode 100644 index d46a76ed375ef1205ce08ea5cdb1f75a87b31e31..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 951 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE3JI?vzAn^JMPuV()?r2U9J-xJvda_6VA6od|A$V2Cf{RPsj{aCy zIsf_IST5IK(^s;&R5mo!Ys2Wb!xTJOQF(ZRd z|H3~x|D3Dr|MnhR@w>1=B4D4+Vb{4c=FO2i#gn%0G7Im0)&N~E_JDQM8JR?;oalWr zY1!pBmqc_wndRGZ2)LaRu5L2mS-4=q+GYR3|IX`svB>=W)24$Dl-K|1UMDIby2&e) zMa03HS5(6z-s$+3Q+z3(mmZeS?|32m|Lp($4MI~BoVkB6#0nhQ*|6GT#{D*D;d>s- zj=H?eR19MBV0yu1ajrnHU3~A|Yiftr_wG9u{p`2jhn7cE7}haFI9xYnf72B8_>b`V z-M#F-D!!9U7+H=8mIvOC3H^J^V!dhk?XJKq)t@&WrS83ctNBCv*B2#IxMMPZPizq? zdJxWbz549j%~4NH>-SYlGQ2304plT_T{I;&FK1Ej!spk1^4EJ$HQw3Hbq*L=swJ)w zCCNppi6yDJDL{h3$iTo-*U(Vc&@{x*+{(bn%GgBL0LU=d_PkFBrU9hV3Ze_B!O%e0 zz)07~AjHVn%E-*h&=jJ9%{rzLMMG|WN@iLmR0Gfk!w>^YDPx#24YJ`L;(K){{a7>y{D4^000SaNLh0L01>qS01>qT<(-hC00007bV*G`2i^e- z4haKH)V{X>00H7jL_t(I%XQSvZ%k1b2Jqj^+|Eotq9yg!M$||&Xtia<(xP@Y{sM`u zf5pbahCjp3UL+zSV$mWjgdo+T`e8a_G0!wt)lE*`d*1ur_dL&Yo^vYxeJU9PC@_sK zmav2E%)8~Eiakwgi3iZaCXOce8x6e1&n(v7uTd>1<}!a$LI^JtuVAY*ZhGC2KX#KC#`idOKIS|Y#6Pm_kE6+n7<0An z?EZOL3*-(y#j&HMMr(2YMw*Q0D0NDr@6u?*4vU#rqS;K|3tWp?>*YgV+2M*N|GU`!0In2y>2eCdivR!s07*qoM6N<$f*QjX@Bjb+ diff --git a/src/org/synthuse/img/bullseye-logo-th32x32.png b/src/org/synthuse/img/bullseye-logo-th32x32.png deleted file mode 100644 index 71aa4c1b5b5d6ed0fafef650d79bc2638d63cf19..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 333 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdzwj^(N7l!{JxM1({$v_d#0*}aI z1_r^cAk6r5?u11^LG}_)Usv{fjC_33y7x7VX99(8dAc};L>zuQZ8tBIp@7SLU5&<$ zC=Lz}jTSQjUWGtrA>Rw^ikhYlMl32XEdE4CPp?=qS?6b2xy|;?=`UWq*x-1LWnEF= z^+^qGk4z$>`NVYBxtLD*oLO`1WbCq4s~jC#C#g;TaLvwA>i6kr-EBD;SEo3v?X8Sa z`H=pfNvFYh1M|BByb+AIKelLXT$*(L+2#v&fBqS#osM*vsqk65fZ@AF$fhX%Ia20{ zIuXUye8SbQ>#k|!eOlcoSkS66$-Uy7M%dd&D_Po9_I2+0XA-mNt=fJ;-#Ya-FJ{Q( YR|k4~#rtTa1AWQh>FVdQ&MBb@0Cfp}lmGw# diff --git a/src/org/synthuse/img/dialog-close.png b/src/org/synthuse/img/dialog-close.png deleted file mode 100644 index 5efd28341c75d9c8e8c5e5dcfa2734e740829521..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 991 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE0z%d<2gY`4S99w&sfq}{0)5S5w;`GvBNB>6-61Bm*CQREV(Y(8R z%F_e)e0tpVv!nMEKG?!upLBk&pm6TjCyhrYNchV+L~K*)-4dZQ_vM>|tsU(8b<0nF zzgP3~UbS&cao_nVJFIq0Q+<|ZEZx$Od8@Os&hNfZ>}jFm#0=&e2Ug%-QH5)^>r{S!&L_Sr-dlFf^=sy(~{c z=xZ&TmUUoYis4cqrUXE9!h~ov5JJt7$8Lsdwp5ZFU;(GAG8y&vm z$?s3!jlKP3&ZJN-J;kJ;_10NSlm1v(P1^iZ#xj(ZVS_=-f>jbRF-I;|yb=BNciTzJ z*!&G<-2#ORU-xa>{d;v)#fpZ1{7xci2QcT zC-{O2?G2CF{Ds`Np;pE%g zKSHi?KY#AzW$5p*tgo_7e*WBFa*nch@P_a259o``X<8(~FyYMed)rkaU;p8_Z%{br z^i76<#5YfJL*ySm*?j+}{Fd*r-YtGv-N5vvTH+c}l9E`GYL#4+3Zxi}3=9o)4UBXR z%|i^#tqhE(}6TtKSRv1wTBrPnAdu`IEGl94xQ+o6B5eM_P_Yt9qaOU*>SZ| zzYlDS2+r2t7L~z0BP43~0roCEuSIU=M3`ttF$hi^6T2Pf8yKA_f3}%x$Pr8uXDAz+w9x(Pl|@v z_r2cC{b$|Wx$n!jn!e#bdCxa|*|I4ozAU}C&iva;osbYY9bLV5w?AGwXZw29Dogej zHj$l@4b`unoL8QBU;mPLneA`C>eFre3Jeq~D)c$op16yPJ-hPd)G3RbxAtz|yL8)| z)whmIaVKd@-socv{iG=7A7wmoX>(-k_ElP5zq+^&#pU|4AFouXw3U#wn?0v9bvGxs zoeHy1)=lo*HN1Xsq%`}s1Tx7SH6 zXgsBSMp=Aj)uZ*Dx3@nFy0Y5lVKDQfpd885Cq))*RN1>%AidkWa81_#b+c#9@aX0F zYca$3th|_$=;||((M$}t&CYsj&Q)u!Z1r8F;`#E6))pVJs5IVbQ<;w!M)Vz@JpH&n z&k|*Gd*(Ae6Zf!InY(}drDi+#;{GYAFLUB77*20l@Y;&!aKpOS0V14>{3Xt3{JOY@ zJ!?y~BxAzi;{4{5iR%`wEbLd{SnneK*y-GqFhMm zzT)l=qN%F33R~u0&8e}ntjv|NId8sd)e-g($+pCdjYm!~B){QU`X$L~?a~y_8zLXH z?M_L|IG*exE_}R1`MaqqOJ{byAOEX1!-&whIbo{tTJs_-m#jFoyk!E<(jy#C+xuO` z9{qk3qZb%9XTB-#=g%1>nf8hun=W3y|LEa0z3#_5IS)Qw$+9$gTX*y7OyA#WA9Q0R zZF@ic(k(N1vY+R=XwGdvz2#f>_Pti|m#Gr|&+y~&gse9n8fm~>tXkq4QIcGgnpl#m zn*t;lj0_Acbqx)5jVwY8&8-YAtc)yl4a}_!3=Ai3(t&9JskDOV0%|Zc&^0j9H8Kb> zGPW`@vobV=XkfFBX++VGo1c=IRteQ$2(%=`z{1MJ$jTIIgZ8p(JwOenASd}`Ca2~V zr!r)eloVL$>x1peEK5z!&&|!xE7r>|O4rYUC@I$WaS!m(H_|iIw?4Q<0%jw`GE6_2 zSQ#5x8Ja+xc(wbDCs2bJ$j0FO(xT*42Ir#6;*!K1g@B^`tkmR^*N>lc168OaRK$k{ o`M{i&T9#Urn3IyP2Xq(EjbNSnOD9f_25MpOboFyt=akR{0Nq7Py8r+H diff --git a/src/org/synthuse/img/document-new-5.png b/src/org/synthuse/img/document-new-5.png deleted file mode 100644 index e7d4847683594dbf0835b72396117f93416171bf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1093 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 diff --git a/src/org/synthuse/img/edit-copy-7.png b/src/org/synthuse/img/edit-copy-7.png deleted file mode 100644 index d2f21bd67e435805d5466960a32592e42c41321f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1131 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Ea{HEjtmUzPnffIy#(^vlDyqr zfHV;NblzPLq&N#aB8!2v2N=7Z%(epwmK8Xr18J~%3^B*n9%f)*()4t346!&}df7H3 z#8IT};rBCV?&fUDD-*46n&f2QsT$_kEfLr)GRsTa(O{`YROf=Z3pQ?;o}kFGW{aP? zkZ_<7&x+KJ%t;+8JC5!6U;a*}dw0{MyO({8pC_L)Ha04IfB5vhnvydTU0rGl9a_BW zr_Rm#T)8=<%FNz0Zn^Wxr|#YJn-*|owXQKfqxawL)(5%w%*WaJ3$uTDyEdKjySsk< z+N<#<-b>X#2R}Al-k=bX9Hr&O;icTSv+kQg^izkd%hxY&lAIBDqi(~N9fmel$chKP&GDwHMQrL>xre7WKB_-E zH|NEs4#72BH6A=lTP!rQX5EC|Kvv}@k69PaxrJ~#3J8WA{OPhkcJ`l&1ur!lt|`1d zC$1yBy#LK6L&g&h+nGa;p7oh0m2LiiX}fo!(4K7Dsj;G0oCSQ2`!Bk-)a>o*ho?OZ z9$DqCxb|x4i6`IRZc>!JG%K#@*RmB^w;Mi}-`l^{jqSjf#;||4wnV6A1nE6l^v+&< z`hRK7w@a#kDM+=%HKHWBC^fMpRW}7lFc=vaSn3)Y>KdAb7#Ud^T38vH>l&C_85l$} z{5uHK08(iM(FN3CXrOBV)L?j;A#0BT4A zImst8IW@01l_8^~q`*pFA8c1rx_%BsNwI!XrM|JAfxbe1kphv* zjr2_QyW4D1Va|iN3?2Yxx(3F&hDISqhE}GgR)$6p|7@3ux(C!C336U=ep*R+Vo@rC zV@iHfs)A>3VtQ&&YGO)d;mK4Rpdx9AqSB(|R0cOkUkFkN&dkYH@Jt4Jps6b5H&B@| zLRoxhkPpna<>lpiX^FWIqzCk~eokVNekMqxelgGt{X<81d4bv)JYD@<);T3K0RT&Q BvH1W1 diff --git a/src/org/synthuse/img/edit-find-3.png b/src/org/synthuse/img/edit-find-3.png deleted file mode 100644 index 9a10550da648c6ea0e59eb9c3a48eafefe1f4425..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1035 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE(}6TtKSRv1wTBrPn4CRb978NlFP(JJ`*NVjar^J(^|wuya%TF? zwenn8Gr`C3Vv6b}kD3+jO3E)3Uv6Y~Y*CWe@_4n<{C}TZl}1OGhVa5mUYC#Lte%SQ$-+Q0S@cmhSyrT%2(Ib89nD(6eaI-7=# zcMojR`M+`=1N*C0fnGoVPyN5RY1y^1xf_i$*4FRhHdI);C1>e7t)&bTmOZ)pqWg{Y z&dLmnk{w$Y?b-6a=6z<(RM8oi5(+ght=!5t$KsyqdY*5WFWotDyFB=b_)dAf+P_jP z0={c=r{^wxXA!Gc`|*%vxQ0YZRaF;%vE!@n*C+a@&5Y+L{C!Q};Rhw|`A&Cs|39!P zSDM){L2GUMdcJSg*;%V*&YY<#*Pj|~btAxEMJTaOk;Or2;sFDN3pXG7EY*>-t+mU! zv2E`B>CcsfV$(`XRd4^lzeOf8E$^K&Q|~pa`z#xBrH@~;*i>b2>#a2L#zl>}p3DhS zhdfj#OY8Ng>mNO;dL-#}##+y%qWNmea~MlXf2B^`-7)Er(4&o|7be{DP*hNrx_x`S zrgm{{`=zOg66Q;$tSqsr{rr6{qkt37$xE9y+5WECH}9UY`dmKF-7$REl0LroDlAL- z^VGvaq~_VjFrRDh4&3MxJghi(`mWu~tfBj~_Dqc{+kLmFteWj(W$gNXhclxpAEJDrqgS@G+5M-MIDXPKk>b?kw`X z?2`T0o5822pR*z64F9L`iZ{YGO&MZVHfKFfuT()HO8JH8c$| zGPW`>u`)2zH88g_Fpx7`ehH=lq|yqa3#h@+K-a)X*T?{*!N|^YD+3EF6GMmwj-M;}ff`IePV&i2PR%P$WymNgDX`Ml2iuidmYSTO zo133kte0PuuAc)@QmpSD;G=J(XP}>x#kK-wA;c~MUUF=>_zb8)9Asf|erZv1DucV9 zzptx;XL5d?LP$nxZtB6GYMDSK3J4|fp+P<{XC)Su=%wf7=ca-kWb|ZWB~UGcr>mdK II;Vst08hA_^8f$< diff --git a/src/org/synthuse/img/gnome-robots.png b/src/org/synthuse/img/gnome-robots.png deleted file mode 100644 index c34a56e3365680d6dc344add7324ce105fcd1cc3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1246 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkEq=mzKrjryt*$Kx=6*y*Re@#52_?f?Dq_-kQxzrJ1C^J9PAfAD7Kb-}j4Z>ztz7At?DO;3`|a;?^22U)aJ)NzhKJw2_)SuH_`{Bk zY)VW?P0CD`?B6GN&T-J(lDT$QaNH~L+fyR1{$+0VWv|{9fAV>B|0Dw;B@3|)Z_1Rt z95s2DiYyRyVYxZ&OmM5y@zeX{m*lPtIm7BWWB%NExid7fveVc&52rWoVA1n@VC^); zB0xsjLuO8xqsVdDo!4q3Pb)>6*X_2{^Y&h<96dXIzJJmc*AEWTPu93bF?ut#%xf20 z8_;;D%Bt2jEBkMRX6$8`7L7iZCn~NjIt^)J6;CFJxlLx6#xadUlhMTZ08g0;m(sP2 zyJjXozF5CiJ|4d%vB5RXLhMP4qE3cIyNsoYWs|{TXNk4P=B&wizvu7uy}!lZ{`z&S zFa7Pee@W?LQUVNaEON#t1cja_OqS3qOb~Qn2^86S<-}hGIP5+u8uD{IA^(mWYemw4d z^n0-8?XzbR(l&g^ThcBdmUBIedv*5HkGq2}3v*u%-tB!SBL1mG;b*Vc0ot`Uq9zA> zz1+LDn`4p2v#VRb{+xO9=f~UI)%5IV?7Lp^Wu^_o+*>pDHSgW4|MlzFc^YEf>_)n0 zB@^A&ZWCU&=FesubMxR}c?aebOedH%B(itky8U_X%xP!r1Ot1k z?ye78ovIeayn$^2(*m{wf4S$R--~;*bnACuwo)x|jVMV;EJ?LWE=mPb3`Pcq2D%1j zx(1dZhUQkrCRRq4K(3X6L7qyh1&W5;{FKbJO57UcD{WhV8gxN6_+%!h<`t(hge4Yb z=9d=hC={orDx~Bm7wbEQhIse~1;-~A6zFE=6_+IDmmtT}V`<;yxP?0!9QE5?fDg%-cx<0nK6XboFyt=akR{0GZhm AN&o-= diff --git a/src/org/synthuse/img/help-3.png b/src/org/synthuse/img/help-3.png deleted file mode 100644 index 884f6c1981cea101b293a33dc22a40abaf97ba2f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1377 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Ea{HEjtmUzPnffIy#(^vlDyqr zfHV;NblzPLq&N#aB8!2v2N=7Z%(epwmK8Xr18J~%3^B*n9%f)*j`VbK46!(^diiFy zOew>GkMHx#zRj3xYxFX2o0E-14jr$3&VB!OFehkm!G$< z&HS}9@RH=*ZL*I_4)Ra^k#}_7kJr~;9hv)c_WoP9cW+jB$8iNRvzbWi|^0#iU+;?H^+gN3>)kh4@E!z_F?C{N< zGmC@IPl>qw=E0RyG4qUGRLS-8XU(ZlIr+8K=;|(Kr^_BP5{BQ*uJyC>er9J~C}Usx zY~}U&vf6?92fo#Ie@v8Bp8w!a^s#vW4l@I-XSZu)zm~P25L+&sk#@`{rBj~ zqeWujyKKUE1f2rPN><(0<2~&jEaS%ZYeh7pZ}6j%(5Sa;8D=Y;-mjQ-_T|nZ<44NdAzhU3*soTifmS1G-;l8cWm zmyiy4aq&UM{s+Cqu4nq5++F?uXgkGpF!E?!^W{8*^pNv$uf;!$GnnatTbIsVuFV21*5a-|f?A!NEx4U+H^q;IClwoVD^4KbA zee>oWC70Ld?&o@?#KCg(yIhNlVo^+NON@`CZSl!R`;?u$)s-Y4&fNAsH0$-I$lo?x zPp=DHbz~Iz$L@V*QIuU@RVgsXsg}4#lq46WCYGe?rT_^BBLf3VT|+}%L(>pLGb;lN zD-%Oq19K|_1C@0TAHXz#R9ZoF0W}yJ=o%R58X1Hb8Cw~dSs9u`G)!FLy8=Z+ZhlH; zS|wBi&<4X014}DI3oBzYhz2%M#|WSXQ;?H^!34ZWtOET=jZ0; z=N0Sa7p3dxK$H~g`?v@A=o{%7>RTV&A_21zVi^HHRm)Gm0@NT0vN1S6t)x7$D3!r6 zB|j-u!8128JvAsbF{QHbWU38N5idkhX;E@2gI{S`eoo>Vf76dZ2@`}wd}xpl%*o~D v<$9UP`FXn8nR)4YK!@uW6y;~7CYKcJ=Yh5Bm)ULs6`~BDu6{1-oD!M7o^m3{2u3(s-zJKntia4E`g;Tn0_?~Y%mh$bon7a*w z|Nd^>BlcUhmR^Vw{x@MS=8*Kd7Z7?@ibTUZ&G=^B_>85k%>El)<#kei>9 znO2EgLlC?CeV_(2kPSYW$*Fn8sSFt0z%d<2gY`4S99w&sfq`k4r;B5V#p$V&y>miCMcVe)%00EKk{8M9 z-m*7CTBpsA$846Rp2=Hd?(Kb3DLHLzJiu= zk`~`z9ofvhxc4nfqap`SVgd&b%drMV5f{vT=n_2PcLjCoRf?Z(%Xx!T3P zOvxRGN)K2aN#J?$zad8M+rEc#d(KNuT=ihjgBm}X){t()$&Z^ux(wMew#rVgi+J+Q ztE(eOyZmCzR*U(IwOq8CzDnLp|8kvcPhmz&)z0k0+5fLGEw?#dChvl13{kebEx8X{a&};b!0jq1tYoDLFJz3hhJS^zm%zyJfO|x2i?Wf7iy|R|s zrPc41$KA98D}~#4e)_!sOw7J>YcBaw@`uzC3 zWkGrd`^woLSC=z9C_Z?rXY%{nwyhUl?)WMa(qd9-@%+bw$LoK5xE#5P_3+2*d_`ZT ziff8)XPBTeEjfSg)AM0IA!{yp28Xa1*F4$sPEPXC{IuCm-tl_fW;?m}=vuuXF5_2M zg|y$clvyj@vvP@9vxv)jd%3aseg~CR+^5%8_s;X;43<15!Mu#Y*3@YFgw(!wxq?^s z%`kYy6dJN{XAOU7Y=_DD<q60xo1c=IR*74KGygv` zpav6=4L+I4sd>ez3>hUQ1y=g{V7oHQQj_y@bMy0x_413-^>ZLfiuK(CeDsa<4D@rd z*j51bOM>(V=ckpFCl;kLl$V$5W#(lUCnpx9g0#(kXCnnvBn(khT9lm1;O^(|>#FOV zpOaryylSS)BcQY)LOMP)$OrC>{FGF^^!)tvoK!uaQ}he;)ARCkQ+1QUdi4Wjx4s5y OX7F_Nb6Mw<&;$SpGQ<4< diff --git a/src/org/synthuse/img/run-rebuild-2.png b/src/org/synthuse/img/run-rebuild-2.png deleted file mode 100644 index da123faae8ee8915fa78e1a28b244deaf1e5f10f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1198 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Ea{HEjtmUzPnffIy#(^vlDyqr zfHV;NblzPLq&N#aB8!2v2N=7Z%(epwmK8Xr18J~%3^B*n9%f)*TIT8E7-Dg{x6e0w zPO3!f`sZ_>&z}8sfEFTv$db$cs6%&u$Q8=^fim&4$?Q*?4zuA8=-`TOD z!*#8fHsi%r6IxX}<=0MLHeqJpjS{1>Subn$%Ac>b*9*F|JuZq7tWPDXUuI}rHAAamYjYk~+ zY!B*SeUx&3InzW2MT?xBo9n8N*}YLK{O?zNr!VLOqh#wEhl9;8>KfCZIGMFOGiA1b>gT)Hx|qrwX7fFe z=qkGW-~W=%*i-EH_x5k(RynDXu(x#4pXmDKx6`)nbF2QL-h8lQA`d6`{z)pDH+aHa zKF(l1Eq!}-%)Y`-zoq9QOq(r5g0!9+xJ&K%ca257Y`ytA^GpSu;}Q@Hiz&6ie5?5_@1 zbNC#{%kQ53UEgR%rctczxuVy_Ohz+~msy5sZrpe2$4!yv)9p`&clR$ZT=hycv|rp` zD*Eix>&5H$7Jqj6lXKYT%QDW%HbNFg7bRwgx6O{%kB>K!*)=0wK-MjYm34gslcnPR z&>59ayUow*&8ysgKV`?Kzo*(~F8HwEy7686cW-N6N#shbl6Mqow)n@mqUrR+l_nFG z>)*)Q`DNS3;PiL-xjGm9w;%3&{A82rufYEO3`^=tRXMP=ld?u7Q!RkwJ)& zv6YdTm7xVhL;4$AV7`Lb0M?M3pOTqY3Dp3!!7#+Y5~$kB*bJh9P1G?0sKFHEB%jRW z)V$(UhK!Pu0xNxeuw9vDsmb}dx%qj;dih1^`Z*9K#ri((0Y3UhdWQPe2e(MTY=l@w zz)#ik)2{$ENP=t(&QB{TPb^Aha7@WhN>%X8O-xS>N=;0uEIgTN160HdQB+!#oXX%= zT9%)axW?b~BT&KwArT)MZgyr~x*pKs`UOS#S*gh-#rk<*?fPZ5 RTR0z%d<2gY`4S99w&sfq^-})5S5w;iXq3UGhfAZ&9>zRtJ?8Rw?*9&R=ky*<@q4oc_Lg*ZdzdLMRckom#(&7- z=%t|Bo8DoE!K4RbRY#@te1*hO>Nq6hHj_E#MTv7&7~;)~ixqu2!cz^X9u>FV)(r)#}9P z8We+PiqvoAF^JSTn&Zcd=d5fh%>c#7oZ&WAuJx)K*!PZ={H!h^x>*u2;^Qqii ztxU6)JuI=<7`0~3(;|^>S2m`-S9u+#rW%>eF3qY)k+_&u_@Qckjh(;U{N+)rlQu?d zh|+m+SE|ur!izH|X0v}zmZ_(Yf#SwqRJv+P`RBq@_KfNqbVo8wZp@#;iPoJ*&@PYBPz0T(khuzow z-RGtwrn+%sqs^UrTBIecR;)0^pDs=nq@B_%gJRm^70p8fRYdHl3 ziDqq;nxwMYyW9JwHh0oj*E?@slnBUiKQ651U}Fx^5{>a=cbdV|?)2qXm4uw!!)I$b z>mn-?l@u9780t5~$Hvy$J^uJ}$+~rUJFnNv_FwNl{+ij7(Q{#{lhIT|Ieoi}tTjK+ zpZv(xaOD3^(as*tNuLh9d$DJw$EOv`%zyFTeGw$GbIGb#3wtK5xxRY$B&EMwB>VU8 zdG(iF%DKyc|LRv8V8&A|ag8WRNi0dVN-jzTQVd20h6cI@M!H5uA%@0QMg~?!#<~XP zRt5&LyXBUnXvob^$xN$+YB1C_Gz>AYv@$fZGBJf{(2_bN3e;c%vcV@aIW@01l_8^~ zq`*pFA8c1rx_%BsNwL0rfRDbBo`HT&7TXG-eo2u2;QX|b^2DN4 zhVt@qz0ADq;^f4FRFJmW?`))iii9DGN{f 1); - - commandProcessor.setScript(badTestScript2); - commandProcessor.setQuiet(true); - assertEquals(commandProcessor.scriptStr, badTestScript2); - commandProcessor.run(); - //System.out.println(commandProcessor.lastError); - assertEquals(commandProcessor.getErrors(), 2); - assertTrue(commandProcessor.lastError.length() > 1); - - } - - // test running mulithreaded bad scripts - - // test parsing bars, and arguments that contain values with bars - - // test command sections ie keyboard, mouse, win, main, base -} diff --git a/src/org/synthuse/test/Silverlight.js b/src/org/synthuse/test/Silverlight.js deleted file mode 100644 index 80ff397..0000000 --- a/src/org/synthuse/test/Silverlight.js +++ /dev/null @@ -1,2 +0,0 @@ -//v2.0.30511.0 -if(!window.Silverlight)window.Silverlight={};Silverlight._silverlightCount=0;Silverlight.__onSilverlightInstalledCalled=false;Silverlight.fwlinkRoot="http://go2.microsoft.com/fwlink/?LinkID=";Silverlight.__installationEventFired=false;Silverlight.onGetSilverlight=null;Silverlight.onSilverlightInstalled=function(){window.location.reload(false)};Silverlight.isInstalled=function(b){if(b==undefined)b=null;var a=false,m=null;try{var i=null,j=false;if(window.ActiveXObject)try{i=new ActiveXObject("AgControl.AgControl");if(b===null)a=true;else if(i.IsVersionSupported(b))a=true;i=null}catch(l){j=true}else j=true;if(j){var k=navigator.plugins["Silverlight Plug-In"];if(k)if(b===null)a=true;else{var h=k.description;if(h==="1.0.30226.2")h="2.0.30226.2";var c=h.split(".");while(c.length>3)c.pop();while(c.length<4)c.push(0);var e=b.split(".");while(e.length>4)e.pop();var d,g,f=0;do{d=parseInt(e[f]);g=parseInt(c[f]);f++}while(f");delete a.id;delete a.width;delete a.height;for(var c in a)if(a[c])b.push('');b.push("");return b.join("")};Silverlight.createObjectEx=function(b){var a=b,c=Silverlight.createObject(a.source,a.parentElement,a.id,a.properties,a.events,a.initParams,a.context);if(a.parentElement==null)return c};Silverlight.buildPromptHTML=function(b){var a="",d=Silverlight.fwlinkRoot,c=b.version;if(b.alt)a=b.alt;else{if(!c)c="";a="Get Microsoft Silverlight";a=a.replace("{1}",c);a=a.replace("{2}",d+"108181")}return a};Silverlight.getSilverlight=function(e){if(Silverlight.onGetSilverlight)Silverlight.onGetSilverlight();var b="",a=String(e).split(".");if(a.length>1){var c=parseInt(a[0]);if(isNaN(c)||c<2)b="1.0";else b=a[0]+"."+a[1]}var d="";if(b.match(/^\d+\056\d+$/))d="&v="+b;Silverlight.followFWLink("149156"+d)};Silverlight.followFWLink=function(a){top.location=Silverlight.fwlinkRoot+String(a)};Silverlight.HtmlAttributeEncode=function(c){var a,b="";if(c==null)return null;for(var d=0;d96&&a<123||a>64&&a<91||a>43&&a<58&&a!=47||a==95)b=b+String.fromCharCode(a);else b=b+"&#"+a+";"}return b};Silverlight.default_error_handler=function(e,b){var d,c=b.ErrorType;d=b.ErrorCode;var a="\nSilverlight error message \n";a+="ErrorCode: "+d+"\n";a+="ErrorType: "+c+" \n";a+="Message: "+b.ErrorMessage+" \n";if(c=="ParserError"){a+="XamlFile: "+b.xamlFile+" \n";a+="Line: "+b.lineNumber+" \n";a+="Position: "+b.charPosition+" \n"}else if(c=="RuntimeError"){if(b.lineNumber!=0){a+="Line: "+b.lineNumber+" \n";a+="Position: "+b.charPosition+" \n"}a+="MethodName: "+b.methodName+" \n"}alert(a)};Silverlight.__cleanup=function(){for(var a=Silverlight._silverlightCount-1;a>=0;a--)window["__slEvent"+a]=null;Silverlight._silverlightCount=0;if(window.removeEventListener)window.removeEventListener("unload",Silverlight.__cleanup,false);else window.detachEvent("onunload",Silverlight.__cleanup)};Silverlight.__getHandlerName=function(b){var a="";if(typeof b=="string")a=b;else if(typeof b=="function"){if(Silverlight._silverlightCount==0)if(window.addEventListener)window.addEventListener("onunload",Silverlight.__cleanup,false);else window.attachEvent("onunload",Silverlight.__cleanup);var c=Silverlight._silverlightCount++;a="__slEvent"+c;window[a]=b}else a=null;return a};Silverlight.onRequiredVersionAvailable=function(){};Silverlight.onRestartRequired=function(){};Silverlight.onUpgradeRequired=function(){};Silverlight.onInstallRequired=function(){};Silverlight.IsVersionAvailableOnError=function(d,a){var b=false;try{if(a.ErrorCode==8001&&!Silverlight.__installationEventFired){Silverlight.onUpgradeRequired();Silverlight.__installationEventFired=true}else if(a.ErrorCode==8002&&!Silverlight.__installationEventFired){Silverlight.onRestartRequired();Silverlight.__installationEventFired=true}else if(a.ErrorCode==5014||a.ErrorCode==2106){if(Silverlight.__verifySilverlight2UpgradeSuccess(a.getHost()))b=true}else b=true}catch(c){}return b};Silverlight.IsVersionAvailableOnLoad=function(b){var a=false;try{if(Silverlight.__verifySilverlight2UpgradeSuccess(b.getHost()))a=true}catch(c){}return a};Silverlight.__verifySilverlight2UpgradeSuccess=function(d){var c=false,b="2.0.31005",a=null;try{if(d.IsVersionSupported(b+".99")){a=Silverlight.onRequiredVersionAvailable;c=true}else if(d.IsVersionSupported(b+".0"))a=Silverlight.onRestartRequired;else a=Silverlight.onUpgradeRequired;if(a&&!Silverlight.__installationEventFired){a();Silverlight.__installationEventFired=true}}catch(e){}return c} \ No newline at end of file diff --git a/src/org/synthuse/test/SilverlightMockTestApp.xap b/src/org/synthuse/test/SilverlightMockTestApp.xap deleted file mode 100644 index 0d37c77c34b9f537064e9d9fd7a240bc579b38a3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 145627 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
    ;3WEBd)(xSB%4$Ig2pdIcR{p%NM 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 TpZlRdckj>9k>~jwa=`xpVapQ% diff --git a/src/org/synthuse/test/SilverlightMockTestAppTestPage.html b/src/org/synthuse/test/SilverlightMockTestAppTestPage.html deleted file mode 100644 index ed16466..0000000 --- a/src/org/synthuse/test/SilverlightMockTestAppTestPage.html +++ /dev/null @@ -1,73 +0,0 @@ - - - - - SilverlightMockTestApp - - - - - -
    -
    - - - - - - - - Get Microsoft Silverlight - -
    -
    - - diff --git a/src/org/synthuse/test/UnitTestHelper.java b/src/org/synthuse/test/UnitTestHelper.java deleted file mode 100644 index fc75158..0000000 --- a/src/org/synthuse/test/UnitTestHelper.java +++ /dev/null @@ -1,79 +0,0 @@ -package org.synthuse.test; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; - -// This class doesn't contain Test, only some methods that are used by the unit tests -public class UnitTestHelper { - - static Process runningApp = null; - public static void RunApp(String ResourceFilePath) { - String tempFilename = ExtractFileFromJar(ResourceFilePath); - Runtime runtime = Runtime.getRuntime(); - try { - runningApp = runtime.exec(tempFilename); - } catch (IOException e) { - e.printStackTrace(); - } - } - - public static void DestroyApp() { - if (runningApp != null) - runningApp.destroy(); - } - - public static String ExtractFileFromJar(String path) { - // Obtain filename from path - String[] parts = path.split("/"); - String filename = (parts.length > 1) ? parts[parts.length - 1] : null; - // Split filename to prexif and suffix (extension) - String prefix = ""; - String suffix = null; - if (filename != null) { - parts = filename.split("\\.", 2); - prefix = parts[0]; - suffix = (parts.length > 1) ? "."+parts[parts.length - 1] : null; - } - File temp = null; - try { - // Prepare temporary file - temp = File.createTempFile(prefix, suffix); - temp.deleteOnExit(); - } catch(Exception e) { - e.printStackTrace(); - } - if (!temp.exists()) { //some reason the temp file wasn't create so abort - System.out.println("File " + temp.getAbsolutePath() + " does not exist."); - return null; - } - - // Prepare buffer for data copying - byte[] buffer = new byte[1024]; - int readBytes; - // Open and check input stream - InputStream is = UnitTestHelper.class.getResourceAsStream(path); - if (is == null) { //check if valid - System.out.println("File " + path + " was not found inside JAR."); - return null; - } - // Open output stream and copy data between source file in JAR and the temporary file - OutputStream os = null; - try { - os = new FileOutputStream(temp); - while ((readBytes = is.read(buffer)) != -1) { - os.write(buffer, 0, readBytes); - } - os.close(); - is.close(); - } catch(Exception e) { - e.printStackTrace(); - } - return temp.getAbsolutePath(); - // Finally, load the library - //System.load(temp.getAbsolutePath()); - } - -} diff --git a/src/org/synthuse/test/WinApiTest.java b/src/org/synthuse/test/WinApiTest.java deleted file mode 100644 index 1155a4a..0000000 --- a/src/org/synthuse/test/WinApiTest.java +++ /dev/null @@ -1,161 +0,0 @@ -package org.synthuse.test; - - -import java.util.LinkedHashMap; -import java.util.Map; - - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import static org.junit.Assert.*; - -import org.synthuse.Api; -import org.synthuse.WindowInfo; -import org.synthuse.WindowsEnumeratedXml; -import org.synthuse.Api.Kernel32Ex; -import org.synthuse.Api.PsapiEx; -import org.synthuse.Api.User32Ex; - -import com.sun.jna.Native; -import com.sun.jna.Pointer; -import com.sun.jna.platform.win32.WinUser; -import com.sun.jna.platform.win32.WinDef.HMENU; -import com.sun.jna.platform.win32.WinDef.HWND; -import com.sun.jna.platform.win32.WinDef.RECT; -import com.sun.jna.ptr.PointerByReference; - -public class WinApiTest { - Api api = new Api(); - - @Before - public void setUp() throws Exception { - - } - - @After - public void tearDown() throws Exception { - - } - - public static void output(String val) { - //System.out.println(val); - } - - //copied and modified slightly from WindowInfo class - public String getWindow32Information(HWND hWnd, boolean isChild) { - String hwndStr = ""; - HWND parent = null; - String parentStr = ""; - RECT rect; - String text; - String className = ""; - String processName = ""; - long pid = 0; - - Map extra = null; - - byte[] buffer = new byte[1024]; - output("Calling GetWindowTextA"); - User32Ex.instance.GetWindowTextA(hWnd, buffer, buffer.length); - text = Native.toString(buffer); - output("GetWindowTextA returned: " + text); - if (text.isEmpty()) { - output("Calling sendWmGetText"); - text = new Api().sendWmGetText(hWnd); - output("sendWmGetText returned: " + text); - } - - char[] buffer2 = new char[1026]; - output("Calling GetClassName"); - User32Ex.instance.GetClassName(hWnd, buffer2, 1026); - className = Native.toString(buffer2); - output("GetClassName returned: " + className); - - HMENU hmenu = Api.User32Ex.instance.GetMenu(hWnd); - //hmenu = Api.User32.instance.GetSubMenu(hmenu, 0); - if (hmenu != null) { //menu item count - int menuCount = Api.User32Ex.instance.GetMenuItemCount(hmenu); - if (menuCount > 0) { - if (extra == null) - extra = new LinkedHashMap(); - extra.put("menuCount", menuCount + ""); - System.out.println("className: " + className); - System.out.println("text: " + text); - System.out.println("menuCount: " + menuCount); - - for (int m = 0 ; m < menuCount ; m++) { - String menuTxt = api.GetMenuItemText(hmenu, m); - System.out.println("Menu Text: " + menuTxt); - } - } - } - - rect = new RECT(); - output("Calling GetWindowRect"); - User32Ex.instance.GetWindowRect(hWnd, rect); - output("GetWindowRect returned: " + rect.toString()); - - if (isChild) { - output("Calling GetParent"); - parent = User32Ex.instance.GetParent(hWnd); - parentStr = Api.GetHandleAsString(parent); - output("GetParent returned: " + parentStr); - } - else { - //User32.instance.GetWindowModuleFileName(hWnd, path, 512); - //IntByReference pointer = new IntByReference(); - PointerByReference pointer = new PointerByReference(); - output("Calling GetWindowThreadProcessId"); - User32Ex.instance.GetWindowThreadProcessId(hWnd, pointer); - pid = pointer.getPointer().getInt(0); - output("GetWindowThreadProcessId returned: " + pid); - Pointer process = Kernel32Ex.instance.OpenProcess(Api.PROCESS_QUERY_INFORMATION | Api.PROCESS_VM_READ, false, pointer.getPointer()); - //output("OpenProcess returned: " + process.getLong(0)); - output("Calling GetModuleBaseNameW"); - PsapiEx.instance.GetModuleBaseNameW(process, null, buffer2, 512); - processName = Native.toString(buffer2); - output("GetModuleBaseNameW returned: " + processName); - //processName = Native.toString(path); - } - hwndStr = Api.GetHandleAsString(hWnd); - output("GetHandleAsString returned: " + hwndStr); - return hwndStr; - } - - @Test - public void enumerateParentWindowsTest() { - final Map infoList = new LinkedHashMap(); - - class ParentWindowCallback implements WinUser.WNDENUMPROC { - @Override - public boolean callback(HWND hWnd, Pointer lParam) { - output("Getting window info " + Api.GetHandleAsString(hWnd)); - //WindowInfo wi = new WindowInfo(hWnd, false); - infoList.put(getWindow32Information(hWnd, false), null); - //Api.User32.instance.EnumChildWindows(hWnd, new ChildWindowCallback(), new Pointer(0)); - return true; - } - } - Api.User32Ex.instance.EnumWindows(new ParentWindowCallback(), 0); - output("enumerateParentWindowsTest size: " + infoList.size()); - assertTrue(infoList.size() > 0); - } - - @Test - public void getXmlTest() { - String xml = WindowsEnumeratedXml.getXml(); - output("getXmlTest len: " + xml.length()); - assertTrue(xml.length() > 500); - } - - public static void main(String[] args) { - output("WinApiTest"); - WinApiTest wat = new WinApiTest(); - wat.enumerateParentWindowsTest(); - wat.getXmlTest(); - output("done."); - - } - -} diff --git a/src/org/synthuse/test/WinFormsMockTestApp.exe b/src/org/synthuse/test/WinFormsMockTestApp.exe deleted file mode 100644 index 2b49f132085c8ab3b33e97a2bc2a6c8c6e544734..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 36352 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 KzyJR{@c#gi9F6k; diff --git a/src/org/synthuse/test/WpfMockTestApp.exe b/src/org/synthuse/test/WpfMockTestApp.exe deleted file mode 100644 index c5f8e278d8f3ff639579960e6acdc963c869ac6f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 54784 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 diff --git a/src/org/synthuse/test/WpfMockTestAppx64.exe b/src/org/synthuse/test/WpfMockTestAppx64.exe deleted file mode 100644 index 4b5b4ad1189d9e666b5455b68e19a3cd015af43a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 55296 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//GEN-BEGIN:initComponents - private void initComponents() { - java.awt.GridBagConstraints gridBagConstraints; - - theStrongTextMatchingCheckBox = new javax.swing.JCheckBox(); - theAlwaysOnTopCheckBox = new javax.swing.JCheckBox(); - theDisableUiaBridgeCheckBox = new javax.swing.JCheckBox(); - theDisableFiltersUiaCheckBox = new javax.swing.JCheckBox(); - jLabel1 = new javax.swing.JLabel(); - jLabel2 = new javax.swing.JLabel(); - jLabel3 = new javax.swing.JLabel(); - jLabel4 = new javax.swing.JLabel(); - filler1 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 20), new java.awt.Dimension(0, 20), new java.awt.Dimension(0, 32767)); - filler2 = new javax.swing.Box.Filler(new java.awt.Dimension(90, 0), new java.awt.Dimension(90, 0), new java.awt.Dimension(32767, 0)); - theRefreshKeyTextField = new javax.swing.JTextField(); - theTargetKeyTextField = new javax.swing.JTextField(); - theXPathListTextField = new javax.swing.JTextField(); - theXPathHighlightTextField = new javax.swing.JTextField(); - filler3 = new javax.swing.Box.Filler(new java.awt.Dimension(50, 0), new java.awt.Dimension(50, 0), new java.awt.Dimension(50, 32767)); - - setLayout(new java.awt.GridBagLayout()); - - theStrongTextMatchingCheckBox.setText("Use Strong Text Matching"); - theStrongTextMatchingCheckBox.setHorizontalTextPosition(javax.swing.SwingConstants.LEADING); - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 0; - gridBagConstraints.gridy = 0; - gridBagConstraints.gridwidth = 2; - gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; - gridBagConstraints.insets = new java.awt.Insets(3, 3, 3, 3); - add(theStrongTextMatchingCheckBox, gridBagConstraints); - - theAlwaysOnTopCheckBox.setText("Always On Top"); - theAlwaysOnTopCheckBox.setHorizontalTextPosition(javax.swing.SwingConstants.LEADING); - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 0; - gridBagConstraints.gridy = 1; - gridBagConstraints.gridwidth = 2; - gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; - gridBagConstraints.insets = new java.awt.Insets(3, 3, 3, 3); - add(theAlwaysOnTopCheckBox, gridBagConstraints); - - theDisableUiaBridgeCheckBox.setText("Disable Uia Bridge"); - theDisableUiaBridgeCheckBox.setHorizontalTextPosition(javax.swing.SwingConstants.LEADING); - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 0; - gridBagConstraints.gridy = 2; - gridBagConstraints.gridwidth = 2; - gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; - gridBagConstraints.insets = new java.awt.Insets(3, 3, 3, 3); - add(theDisableUiaBridgeCheckBox, gridBagConstraints); - - theDisableFiltersUiaCheckBox.setText("Disable Filters Uia"); - theDisableFiltersUiaCheckBox.setHorizontalTextPosition(javax.swing.SwingConstants.LEADING); - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 0; - gridBagConstraints.gridy = 3; - gridBagConstraints.gridwidth = 2; - gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; - gridBagConstraints.insets = new java.awt.Insets(3, 3, 3, 3); - add(theDisableFiltersUiaCheckBox, gridBagConstraints); - - jLabel1.setText("Refresh Key:"); - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 4; - gridBagConstraints.gridy = 0; - gridBagConstraints.gridheight = 2; - gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; - gridBagConstraints.insets = new java.awt.Insets(3, 3, 3, 3); - add(jLabel1, gridBagConstraints); - - jLabel2.setText("Target Key:"); - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 4; - gridBagConstraints.gridy = 2; - gridBagConstraints.gridheight = 2; - gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; - gridBagConstraints.insets = new java.awt.Insets(3, 3, 3, 3); - add(jLabel2, gridBagConstraints); - - jLabel3.setText("XPath List:"); - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 0; - gridBagConstraints.gridy = 5; - gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; - gridBagConstraints.insets = new java.awt.Insets(6, 6, 6, 6); - add(jLabel3, gridBagConstraints); - - jLabel4.setText("XPath Highlight:"); - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 0; - gridBagConstraints.gridy = 6; - gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; - gridBagConstraints.insets = new java.awt.Insets(6, 6, 6, 6); - add(jLabel4, gridBagConstraints); - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 0; - gridBagConstraints.gridy = 4; - add(filler1, gridBagConstraints); - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 2; - gridBagConstraints.gridy = 0; - add(filler2, gridBagConstraints); - - theRefreshKeyTextField.setText("XXXX"); - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 5; - gridBagConstraints.gridy = 0; - gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; - gridBagConstraints.gridheight = 2; - gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; - add(theRefreshKeyTextField, gridBagConstraints); - - theTargetKeyTextField.setText("XXXX"); - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 5; - gridBagConstraints.gridy = 2; - gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; - gridBagConstraints.gridheight = 2; - gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; - add(theTargetKeyTextField, gridBagConstraints); - - theXPathListTextField.setText("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"); - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 1; - gridBagConstraints.gridy = 5; - gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; - gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; - gridBagConstraints.insets = new java.awt.Insets(6, 6, 6, 6); - add(theXPathListTextField, gridBagConstraints); - - theXPathHighlightTextField.setText("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"); - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 1; - gridBagConstraints.gridy = 6; - gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; - gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; - gridBagConstraints.insets = new java.awt.Insets(6, 6, 6, 6); - add(theXPathHighlightTextField, gridBagConstraints); - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 5; - gridBagConstraints.gridy = 4; - add(filler3, gridBagConstraints); - }// //GEN-END:initComponents - - - // Variables declaration - do not modify//GEN-BEGIN:variables - private javax.swing.Box.Filler filler1; - private javax.swing.Box.Filler filler2; - private javax.swing.Box.Filler filler3; - private javax.swing.JLabel jLabel1; - private javax.swing.JLabel jLabel2; - private javax.swing.JLabel jLabel3; - private javax.swing.JLabel jLabel4; - private javax.swing.JCheckBox theAlwaysOnTopCheckBox; - private javax.swing.JCheckBox theDisableFiltersUiaCheckBox; - private javax.swing.JCheckBox theDisableUiaBridgeCheckBox; - private javax.swing.JTextField theRefreshKeyTextField; - private javax.swing.JCheckBox theStrongTextMatchingCheckBox; - private javax.swing.JTextField theTargetKeyTextField; - private javax.swing.JTextField theXPathHighlightTextField; - private javax.swing.JTextField theXPathListTextField; - // End of variables declaration//GEN-END:variables - - public JCheckBox getAlwaysOnTopCheckBox() { - return theAlwaysOnTopCheckBox; - } - - public JCheckBox getDisableFiltersUiaCheckBox() { - return theDisableFiltersUiaCheckBox; - } - - public JCheckBox getDisableUiaBridgeCheckBox() { - return theDisableUiaBridgeCheckBox; - } - - public JTextField getRefreshKeyTextField() { - return theRefreshKeyTextField; - } - - public JCheckBox getStrongTextMatchingCheckBox() { - return theStrongTextMatchingCheckBox; - } - - public JTextField getTargetKeyTextField() { - return theTargetKeyTextField; - } - - public JTextField getXPathHighlightTextField() { - return theXPathHighlightTextField; - } - - public JTextField getXPathListTextField() { - return theXPathListTextField; - } -} diff --git a/synthuse.properties b/synthuse.properties deleted file mode 100644 index 7a41ee7..0000000 --- a/synthuse.properties +++ /dev/null @@ -1,12 +0,0 @@ -# -#Tue Sep 22 12:05:52 CEST 2015 -targetKey=` -useStrongTextMatching=true -disableUiaBridge=false -disableFiltersUia=false -alwaysOnTop=false -refreshKey=3 -DEFAULT_PROP_FILENAME= -xpathHightlight= -xpathList= -urlList=