diff --git a/native/uiabridge/bin/uiabridge32.dll b/native/uiabridge/bin/uiabridge32.dll index b730c4b..031f5f7 100644 Binary files a/native/uiabridge/bin/uiabridge32.dll and b/native/uiabridge/bin/uiabridge32.dll differ diff --git a/native/uiabridge/bin/uiabridge64.dll b/native/uiabridge/bin/uiabridge64.dll index 900a497..739108b 100644 Binary files a/native/uiabridge/bin/uiabridge64.dll and b/native/uiabridge/bin/uiabridge64.dll differ diff --git a/native/uiabridge/uiabridge.cpp b/native/uiabridge/uiabridge.cpp index 7b495c1..158ef1a 100644 --- a/native/uiabridge/uiabridge.cpp +++ b/native/uiabridge/uiabridge.cpp @@ -45,7 +45,7 @@ void AutomationBridge::initializeCache() cacheRequest->Add(AutomationElement::NameProperty); cacheRequest->Add(AutomationElement::BoundingRectangleProperty); */ - System::String ^cachedPropStr = L"RuntimeIdProperty,ParentRuntimeIdProperty,NativeWindowHandleProperty,ProcessIdProperty,FrameworkIdProperty,LocalizedControlTypeProperty,ControlTypeProperty,ClassNameProperty,NameProperty,BoundingRectangleProperty"; + System::String ^cachedPropStr = L"RuntimeIdProperty,ParentRuntimeIdProperty,NativeWindowHandleProperty,ProcessIdProperty,FrameworkIdProperty,LocalizedControlTypeProperty,ControlTypeProperty,ClassNameProperty,NameProperty,BoundingRectangleProperty,ValueProperty"; array ^rootProperties = AutomationElement::RootElement->GetSupportedProperties(); List ^cacheList = gcnew List(); if (cachedPropStr->Contains(L"NativeWindowHandleProperty")) //special property not in the root property list @@ -53,6 +53,11 @@ void AutomationBridge::initializeCache() cacheList->Add(AutomationElement::NativeWindowHandleProperty); cacheRequest->Add(AutomationElement::NativeWindowHandleProperty); } + if (cachedPropStr->Contains(L"ValueProperty")) //special property not in the root property list + { + cacheList->Add(ValuePattern::ValueProperty); + cacheRequest->Add(ValuePattern::ValueProperty); + } for each(AutomationProperty ^ap in rootProperties) //loop through all supported Properties for a child { System::String ^currentPropertyStr = L""; //current property values diff --git a/native/uiabridge/uiabridge.vcxproj b/native/uiabridge/uiabridge.vcxproj index c39c426..c26c978 100644 --- a/native/uiabridge/uiabridge.vcxproj +++ b/native/uiabridge/uiabridge.vcxproj @@ -112,6 +112,7 @@ Level3 WIN32;NDEBUG;%(PreprocessorDefinitions) Use + MultiThreadedDLL true diff --git a/src/org/synthuse/Api.java b/src/org/synthuse/Api.java index b29180f..6dcea55 100644 --- a/src/org/synthuse/Api.java +++ b/src/org/synthuse/Api.java @@ -299,13 +299,13 @@ public class Api { return null; } - public static String GetWindowClassName(HWND hWnd) { + public static String getWindowClassName(HWND hWnd) { char[] buffer = new char[1026]; User32.instance.GetClassName(hWnd, buffer, 1026); return Native.toString(buffer); } - public static String GetWindowText(HWND hWnd) { + public static String getWindowText(HWND hWnd) { String text = ""; byte[] buffer = new byte[1024]; User32.instance.GetWindowTextA(hWnd, buffer, buffer.length); @@ -315,19 +315,26 @@ public class Api { return text; } - public static HWND GetWindowFromPoint(Point p) { + public static Point getCursorPos() { + + long[] getPos = new long [1]; + User32.instance.GetCursorPos(getPos); + return new Point(POINT_X(getPos[0]), POINT_Y(getPos[0])); + } + + public static HWND getWindowFromCursorPos() { long[] getPos = new long [1]; User32.instance.GetCursorPos(getPos); HWND hwnd = User32.instance.WindowFromPoint(getPos[0]); - HWND childHwnd = GetHiddenChildWindowFromPoint(hwnd, 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) + public static HWND getHiddenChildWindowFromPoint(HWND inHwnd, long point) { //int x = POINT_X(point);int y = POINT_Y(point); diff --git a/src/org/synthuse/Config.java b/src/org/synthuse/Config.java index 6886a8e..93dcf0c 100644 --- a/src/org/synthuse/Config.java +++ b/src/org/synthuse/Config.java @@ -11,8 +11,10 @@ public class Config extends PropertiesSerializer { public static String DEFAULT_PROP_FILENAME = "synthuse.properties"; - public String disableWpf = "false"; - public String disableFiltersWpf = "false"; + public String disableUiaBridge = "false"; + public String disableFiltersUia = "false"; + public String refreshKey = "3"; + public String targetKey = "`"; public String urlList = ""; public String xpathList = ""; public String xpathHightlight = ".*process=\"([^\"]*)\".*"; @@ -27,17 +29,41 @@ public class Config extends PropertiesSerializer { load(propertyFilename); } - public boolean isWpfBridgeDisabled() + public boolean isUiaBridgeDisabled() { - if (disableWpf == null) + if (disableUiaBridge == null) return false; - return disableWpf.equals("true") || disableWpf.equals("True"); + return disableUiaBridge.equals("true") || disableUiaBridge.equals("True"); } - public boolean isFilterWpfDisabled() + public boolean isFilterUiaDisabled() { - if (disableFiltersWpf == null) + if (disableFiltersUia == null) return false; - return disableFiltersWpf.equals("true") || disableFiltersWpf.equals("True"); + return disableFiltersUia.equals("true") || disableFiltersUia.equals("True"); + } + + public int getRefreshKeyCode() + { + 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 RobotMacro.getKeyCode(keyStr.charAt(0))[0]; + } + + public int getTargetKeyCode() + { + 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 RobotMacro.getKeyCode(keyStr.charAt(0))[0]; } } diff --git a/src/org/synthuse/SynthuseDlg.java b/src/org/synthuse/SynthuseDlg.java index 086dfa3..a2b5d71 100644 --- a/src/org/synthuse/SynthuseDlg.java +++ b/src/org/synthuse/SynthuseDlg.java @@ -71,7 +71,7 @@ public class SynthuseDlg extends JFrame { /** * */ - public static String VERSION_STR = "1.1.2"; + public static String VERSION_STR = "1.1.3"; 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"; @@ -249,7 +249,7 @@ public class SynthuseDlg extends JFrame { c.gridy = 0; c.insets = new Insets(3,3,3,3); // add padding around objects - DragTarget lblTarget = new DragTarget(); + final DragTarget lblTarget = new DragTarget(); lblTarget.setHorizontalAlignment(SwingConstants.CENTER); lblTarget.setIcon(new ImageIcon(SynthuseDlg.class.getResource(RES_STR_TARGET_IMG))); @@ -389,15 +389,24 @@ public class SynthuseDlg extends JFrame { } }); - KeyboardHook.addKeyEvent(KeyEvent.VK_3, true, true, false);// refresh xml when CTRL+SHIFT+3 is pressed + 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.StartGlobalKeyboardHookThreaded(new KeyboardHook.KeyboardEvents() { @Override public void keyPressed(KeyboardHook.TargetKeyPress target) { //System.out.println("target key pressed " + target.targetKeyCode); - if (target.targetKeyCode == KeyEvent.VK_3){ + if (target.targetKeyCode == config.getRefreshKeyCode()){ btnRefresh.doClick(); } + if (target.targetKeyCode == config.getTargetKeyCode()){ + 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(); + } } }); @@ -445,11 +454,13 @@ public class SynthuseDlg extends JFrame { } public void targetDragged() { - HWND hwnd = Api.GetWindowFromPoint(new Point(targetX,targetY)); + HWND hwnd = Api.getWindowFromCursorPos();//new Point(targetX,targetY) String handleStr = Api.GetHandleAsString(hwnd); - String classStr = WindowsEnumeratedXml.escapeXmlAttributeValue(Api.GetWindowClassName(hwnd)); + String classStr = WindowsEnumeratedXml.escapeXmlAttributeValue(Api.getWindowClassName(hwnd)); String parentStr = Api.GetHandleAsString(User32.instance.GetParent(hwnd)); - String enumProperties = uiabridge.getWindowInfo(targetX, targetY, WindowInfo.UIA_PROPERTY_LIST); + String enumProperties = ""; + if (!SynthuseDlg.config.isUiaBridgeDisabled()) + enumProperties = uiabridge.getWindowInfo(targetX, targetY, WindowInfo.UIA_PROPERTY_LIST); String runtimeId = WindowInfo.getRuntimeIdFromProperties(enumProperties); lblStatus.setText("rid:" + runtimeId + " class: " + classStr + " hWnd: " + handleStr + " parent: " + parentStr + " X,Y: " + targetX + ", " + targetY); if (!lastDragHwnd.equals(handleStr) || !lastRuntimeId.equals(runtimeId)) { diff --git a/src/org/synthuse/UiaBridge.java b/src/org/synthuse/UiaBridge.java index fabaac9..b4cf59e 100644 --- a/src/org/synthuse/UiaBridge.java +++ b/src/org/synthuse/UiaBridge.java @@ -3,12 +3,26 @@ package org.synthuse; import java.awt.Point; import java.io.*; +import javax.swing.JOptionPane; + public class UiaBridge { static { - String archDataModel = System.getProperty("sun.arch.data.model");//32 or 64 bit - //System.loadLibrary("native/WpfBridge" + archDataModel); // WpfBridge32.dll (Windows) or WpfBridge32.so (Unixes) - loadNativeLibraryFromJar("/uiabridge" + archDataModel + ".dll"); + 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, "Failed to load uiabridge library, make sure you have .Net 4.0 already installed.\n" + sw.toString() , "Native Library Load Error", JOptionPane.ERROR_MESSAGE); + SynthuseDlg.config.disableUiaBridge = "true"; + } + } } public static void loadNativeLibraryFromJar(String path) { @@ -63,7 +77,8 @@ public class UiaBridge { public UiaBridge () { - initialize(""); + if (!SynthuseDlg.config.isUiaBridgeDisabled()) + initialize(""); } public native void initialize(String properties); diff --git a/src/org/synthuse/WindowInfo.java b/src/org/synthuse/WindowInfo.java index aae79af..fa1c226 100644 --- a/src/org/synthuse/WindowInfo.java +++ b/src/org/synthuse/WindowInfo.java @@ -172,7 +172,7 @@ public class WindowInfo { //WPF_PROPERTY_LIST = "RuntimeIdProperty,ParentRuntimeIdProperty,ProcessIdProperty,FrameworkIdProperty,LocalizedControlTypeProperty,ClassNameProperty,NameProperty,ValueProperty"; String[] spltProperties = enumProperties.split(","); this.isChild = isChild; - if (SynthuseDlg.config.isFilterWpfDisabled()) { //use wildcard mode + if (SynthuseDlg.config.isFilterUiaDisabled()) { //use wildcard mode extra = new LinkedHashMap(); for(String prop: spltProperties) { String[] propertyNameAndValue = prop.split(":", 2); diff --git a/src/org/synthuse/WindowsEnumeratedXml.java b/src/org/synthuse/WindowsEnumeratedXml.java index a3ee89e..8f7396e 100644 --- a/src/org/synthuse/WindowsEnumeratedXml.java +++ b/src/org/synthuse/WindowsEnumeratedXml.java @@ -121,7 +121,7 @@ public class WindowsEnumeratedXml implements Runnable{ Api.User32.instance.EnumWindows(new ParentWindowCallback(), 0); //Enumerate WPF, WinForm, Silverlight windows and add to list - if (!SynthuseDlg.config.isWpfBridgeDisabled()) + if (!SynthuseDlg.config.isUiaBridgeDisabled()) { UiaBridge uiabridge = new UiaBridge(); for (String handle : wpfParentList) { @@ -276,7 +276,7 @@ public class WindowsEnumeratedXml implements Runnable{ String parentRuntimeId = uiabridge.getWindowInfo((int) hwnd, WindowInfo.UIA_RUNTIME_ID); //System.out.println("runtimeId=" + runtimeId); String[] allIds = null; - if (SynthuseDlg.config.isFilterWpfDisabled()) + if (SynthuseDlg.config.isFilterUiaDisabled()) allIds = uiabridge.enumWindowInfo((int) hwnd, "*"); else allIds = uiabridge.enumWindowInfo((int) hwnd, WindowInfo.UIA_PROPERTY_LIST); diff --git a/src/org/synthuse/XpathManager.java b/src/org/synthuse/XpathManager.java index 08c26d7..38bed31 100644 --- a/src/org/synthuse/XpathManager.java +++ b/src/org/synthuse/XpathManager.java @@ -94,8 +94,6 @@ public class XpathManager implements Runnable{ String typeStr = wi.controlType; String txtOrig = wi.text; //String winValueOrig = wpf.getWindowValue(runtimeId); - if (typeStr == null || txtOrig == null) - return ""; //System.out.println("text: " + txtOrig); String txtStr = compareLongTextString(txtOrig); @@ -113,24 +111,24 @@ public class XpathManager implements Runnable{ String builtXpath = ""; try { String xml = this.windowsXmlTextPane.getText(); - if (enumProperties != null && !SynthuseDlg.config.isWpfBridgeDisabled()) { + if (enumProperties != null && !SynthuseDlg.config.isUiaBridgeDisabled()) { if (!enumProperties.isEmpty()) { builtXpath = buildUiaXpathStatement(); } } if (builtXpath != "") return builtXpath; - String classStr = WindowsEnumeratedXml.escapeXmlAttributeValue(Api.GetWindowClassName(hwnd)); + String classStr = WindowsEnumeratedXml.escapeXmlAttributeValue(Api.getWindowClassName(hwnd)); String handleStr = Api.GetHandleAsString(hwnd); - String txtOrig = Api.GetWindowText(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 = User32.instance.GetParent(hwnd); - String parentClassStr = WindowsEnumeratedXml.escapeXmlAttributeValue(Api.GetWindowClassName(parent)); - String parentTxtOrig = Api.GetWindowText(parent); + String parentClassStr = WindowsEnumeratedXml.escapeXmlAttributeValue(Api.getWindowClassName(parent)); + String parentTxtOrig = Api.getWindowText(parent); String parentTxtStr = WindowsEnumeratedXml.escapeXmlAttributeValue(parentTxtOrig); if (!parentTxtStr.isEmpty()) { if (parentTxtOrig.length() > 20) {// if the parent text is too long only test the first 20 characters diff --git a/src/org/synthuse/commands/BaseCommand.java b/src/org/synthuse/commands/BaseCommand.java index 03abcf1..13fbf72 100644 --- a/src/org/synthuse/commands/BaseCommand.java +++ b/src/org/synthuse/commands/BaseCommand.java @@ -16,7 +16,7 @@ public class BaseCommand { static long LAST_UPDATED_XML = 0; protected Api api = new Api(); - protected UiaBridge wpf = new UiaBridge(); + protected UiaBridge uiabridge = new UiaBridge(); protected CommandProcessor parentProcessor = null; protected int getExecuteErrorCount() { @@ -165,7 +165,7 @@ public class BaseCommand { if (handle.isWin32()) p = api.getWindowPosition(handle.hWnd); else - p = wpf.getCenterOfElement(handle.runtimeId); + p = uiabridge.getCenterOfElement(handle.runtimeId); return p; } diff --git a/synthuse.properties b/synthuse.properties index 4eb8c02..57850a8 100644 --- a/synthuse.properties +++ b/synthuse.properties @@ -1,8 +1,10 @@ # -#Tue Apr 29 23:17:11 EDT 2014 +#Wed Apr 30 22:00:36 EDT 2014 DEFAULT_PROP_FILENAME= +targetKey=` +disableFiltersUia=false urlList= -disableFiltersWpf=false -xpathList=//*[@class\='TextBlock' and starts-with(@text,'CheckBox is here')]\u00BA//win[@class\='HwndWrapper[WpfMockTestApp.exe;;e0e45a66-6643-4c32-a6b8-6313b79ee700]']\u00BA//win[starts-with(@class,'HwndWrapper[WpfMockTestApp.exe;;')]\u00BA//win[starts-with(@class,'HwndWrapper[WpfMockTestApp.exe;;' and @TEXT\="MAINWINDOW")]\u00BA//win[starts-with(@class,'HwndWrapper[WpfMockTestApp.exe;;' and @TEXT\='MAINWINDOW')]\u00BA//win[starts-with(@class,'HwndWrapper[WpfMockTestApp.exe;;') and @TEXT\='MAINWINDOW']\u00BA//win[@class\='HwndWrapper[WpfMockTestApp.exe;;7c11a88a-1622-4ec8-8a29-0d7f20d3f36d]']\u00BA//win[@class\='HwndWrapper']\u00BA//win[starts-with(@class,'HwndWrapper')]\u00BA//wpf\u00BA//*[@class\='WindowsForms10.Window.8.app.0.2bf8098_r13_ad1' and starts-with(@text,'')]\u00BA//*[@ListViewCount]\u00BA//*[@menuCount]\u00BA//*[@dgText]\u00BA//menus\u00BA//menu\u00BA//win[@class\='SunAwtFrame']\u00BA//win[@class\='Edit']\u00BA//win[@class\='Notepad']\u00BA//*[@class\='\#32768']\u00BA//menu[@text\='Help']\u00BA//win[@class\='WindowsForms10.Window.8.app.0.2bf8098_r13_ad1']/win[@class\='WindowsForms10.Window.8.app.0.2bf8098_r13_ad1'][2]\u00BA//*[@tbCount]\u00BA//win[@class\='WindowsForms10.Window.8.app.0.2bf8098_r13_ad1']/win[@class\='WindowsForms10.EDIT.app.0.2bf8098_r13_ad1']\u00BA//*[@class\='WindowsForms10.Window.8.app.0.2bf8098_r13_ad1' and starts-with(@text,'Form1')]\u00BA//*[@class\='WindowsForms10.Window.8.app.0.2bf8098_r13_ad1' and starts-with(@text,'Win Forms Mock Test ')]\u00BA//*[@class\='' and starts-with(@text,'toolStripButton1')]\u00BA//win[@class\='3147770']\u00BA//*[@hwnd\='52298946']\u00BA//*[@hwnd\='14222438']\u00BA//*[@hwnd\='9175840']\u00BA//*[@hwnd\='6751400']\u00BA//*[starts-with(@class,'WindowsForms')]\u00BA//win[starts-with(@class,'WindowsForms')]\u00BA/*/win[starts-with(@class,'WindowsForms')]\u00BA//winfrm\u00BA//win[@class\='WindowsForms10.Window.8.app.0.2bf8098_r13_ad1']/win[@class\='WindowsForms10.EDIT.app.0.2bf8098_r13_ad1'][2]\u00BA//*[@class\='WindowsForms10.Window.8.app.0.2bf8098_r13_ad1']/win[@class\='WindowsForms10.EDIT.app.0.2bf8098_r13_ad1']\u00BA//*[@type\='button' and starts-with(@text,'button1')]\u00BA -disableWpf=false -xpathHightlight=.*process\="([^"]*)".* +disableUiaBridge=false +refreshKey=3 +xpathList=//wpf\u00BA +xpathHightlight=