diff --git a/native/uiabridge/bin/uiabridge32.dll b/native/uiabridge/bin/uiabridge32.dll index 031f5f7..7969ec0 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 739108b..ce2c675 100644 Binary files a/native/uiabridge/bin/uiabridge64.dll and b/native/uiabridge/bin/uiabridge64.dll differ diff --git a/native/uiabridge/org_synthuse_UiaBridge.cpp b/native/uiabridge/org_synthuse_UiaBridge.cpp index 6bd5bc9..949f69d 100644 --- a/native/uiabridge/org_synthuse_UiaBridge.cpp +++ b/native/uiabridge/org_synthuse_UiaBridge.cpp @@ -24,7 +24,8 @@ using namespace uiabridge; */ JNIEXPORT void JNICALL Java_org_synthuse_UiaBridge_initialize(JNIEnv *env, jobject obj, jstring jproperties) { - Global::AUTO_BRIDGE = gcnew AutomationBridge(); + const char *properties = env->GetStringUTFChars(jproperties, 0);//convert string + Global::AUTO_BRIDGE = gcnew AutomationBridge(marshal_as(properties)); } /* diff --git a/native/uiabridge/uiabridge.cpp b/native/uiabridge/uiabridge.cpp index 158ef1a..d6dfeff 100644 --- a/native/uiabridge/uiabridge.cpp +++ b/native/uiabridge/uiabridge.cpp @@ -18,7 +18,14 @@ AutomationBridge::AutomationBridge() { enumFilters = gcnew Dictionary(); cacheRequest = nullptr; - initializeCache(); + initializeCache(""); +} + +AutomationBridge::AutomationBridge(System::String ^cachedProperties) +{ + enumFilters = gcnew Dictionary(); + cacheRequest = nullptr; + initializeCache(cachedProperties); } AutomationBridge::~AutomationBridge() @@ -29,7 +36,7 @@ AutomationBridge::~AutomationBridge() //Console::WriteLine("disposing of AutomationBridge"); } -void AutomationBridge::initializeCache() +void AutomationBridge::initializeCache(System::String ^cachedProperties) { cacheRequest = gcnew CacheRequest(); //cacheRequest->AutomationElementMode = AutomationElementMode::Full; @@ -45,7 +52,11 @@ 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,ValueProperty"; + System::String ^cachedPropStr = cachedProperties; + if (cachedPropStr == nullptr) // check if blank/null we need to use DEFAULT_CACHED_PROPS; + cachedPropStr = DEFAULT_CACHED_PROPS; + else if (cachedPropStr->Equals("")) + cachedPropStr = DEFAULT_CACHED_PROPS; array ^rootProperties = AutomationElement::RootElement->GetSupportedProperties(); List ^cacheList = gcnew List(); if (cachedPropStr->Contains(L"NativeWindowHandleProperty")) //special property not in the root property list @@ -244,7 +255,7 @@ array ^ AutomationBridge::enumWindowInfo(System::IntPtr window AutomationElement ^element = AutomationElement::FromHandle(windowHandle); List ^winInfoList = gcnew List(); if (!isElementFiltered(element)) //test parent should be filtered - winInfoList->Add(getWindowInfo(element, properties)); + winInfoList->Add(getWindowInfo(element, properties, nullptr)); winInfoList->AddRange(enumWindowInfo(element, properties)); return winInfoList->ToArray(); } @@ -255,25 +266,16 @@ array ^ AutomationBridge::enumWindowInfo(AutomationElement ^el return enumWindowInfo(element, properties, filterModifierList); } -array ^ AutomationBridge::enumWindowInfo(AutomationElement ^element, System::String ^properties, List ^filterModifierList) +array ^ AutomationBridge::enumWindowInfo(AutomationElement ^parentElement, System::String ^properties, List ^filterModifierList) { List ^winInfoList = gcnew List(); - if (element == nullptr) + if (parentElement == nullptr) return winInfoList->ToArray(); TreeWalker ^tw = TreeWalker::RawViewWalker; //System::Console::WriteLine("get info: {0}", getWindowInfo(element, properties)); //AutomationElement ^currentElement = tw->GetFirstChild(element, cacheRequest); AutomationElement ^currentElement = nullptr; - /*if (element->CachedChildren != nullptr) - { - System::Console::WriteLine("using cached child"); - currentElement = element->CachedChildren[0]; - } - else*/ - { - //System::Console::WriteLine("not cached child"); - currentElement = tw->GetFirstChild(element, cacheRequest); - } + currentElement = tw->GetFirstChild(parentElement, cacheRequest); if (currentElement == nullptr) { //System::Console::WriteLine("no children {0}", element->CachedChildren->Count); @@ -292,7 +294,7 @@ array ^ AutomationBridge::enumWindowInfo(AutomationElement ^el Boolean modifierChanged = fmlOriginalSize != filterModifierList->Count; if (!filtered) //not filtered so return element { - winInfoList->Add(getWindowInfo(currentElement, properties)); + winInfoList->Add(getWindowInfo(currentElement, properties, parentElement)); winInfoList->AddRange(enumWindowInfo(currentElement, properties, filterModifierList)); } else //filtered, but if modifier used keep searching children @@ -303,16 +305,16 @@ array ^ AutomationBridge::enumWindowInfo(AutomationElement ^el processFilterModifier(filtered, modifierChanged, filterModifierList); //cleans filterModifierList //System::Console::WriteLine("element: {0}", currentElement); //currentElement-> - currentElement = tw->GetNextSibling(currentElement, cacheRequest); } catch (Exception ^ex) { System::Console::WriteLine("Exception: {0} {1}", ex->Message, ex->StackTrace); } + currentElement = tw->GetNextSibling(currentElement, cacheRequest); } return winInfoList->ToArray(); } -System::String ^ AutomationBridge::getWindowInfo(AutomationElement ^element, System::String ^properties) +System::String ^ AutomationBridge::getWindowInfo(AutomationElement ^element, System::String ^properties, AutomationElement ^optionalParentElement) { System::String ^resultProperties = L""; System::String ^propertyNameErrorCheck = L""; @@ -323,16 +325,28 @@ System::String ^ AutomationBridge::getWindowInfo(AutomationElement ^element, Sys if (properties->Equals(L"*")) wildcardEnabled = true; + //setup parentElement + System::String ^parentRuntimeId = L""; + if (wildcardEnabled || properties->Contains(L"ParentRuntimeIdProperty")) + { + if (optionalParentElement == nullptr) + { + TreeWalker ^tw = TreeWalker::ControlViewWalker; + parentRuntimeId = getRuntimeIdFromElement(tw->GetParent(element, cacheRequest)); + } + else + parentRuntimeId = getRuntimeIdFromElement(optionalParentElement); + } + //create array for keeping order of properties System::String ^delim = L","; array ^propSpltArray = properties->Split(delim->ToCharArray()); - TreeWalker ^tw = TreeWalker::ControlViewWalker; System::Int32 count = 0; array ^aps = cachedRootProperties;//element->GetSupportedProperties(); array ^propValues = gcnew array(propSpltArray->Length);//keep order System::String ^wildcardProperties = L""; if (wildcardEnabled) { - wildcardProperties += "ParentRuntimeIdProperty:" + getRuntimeIdFromElement(tw->GetParent(element, cacheRequest)) + ","; + wildcardProperties += "ParentRuntimeIdProperty:" + parentRuntimeId + ","; //propValues = gcnew array(aps->Length +1 );//add one for parent property since it doesn't exist } for(int i=0 ; i < propValues->Length ; i++) @@ -340,7 +354,7 @@ System::String ^ AutomationBridge::getWindowInfo(AutomationElement ^element, Sys propValues[i] = L""; if (propSpltArray[i]->Equals("ParentRuntimeIdProperty"))//custom property for getting parent { - propValues[i] = getRuntimeIdFromElement(tw->GetParent(element, cacheRequest)); + propValues[i] = parentRuntimeId; } } for each(AutomationProperty ^ap in aps) //loop through all supported Properties for a child @@ -404,13 +418,13 @@ System::String ^ AutomationBridge::getWindowInfo(AutomationElement ^element, Sys System::String ^ AutomationBridge::getWindowInfo(System::Int32 x, System::Int32 y, System::String ^properties) { AutomationElement ^element = AutomationElement::FromPoint(System::Windows::Point(x, y)); - return getWindowInfo(element, properties); + return getWindowInfo(element, properties, nullptr); } System::String ^ AutomationBridge::getWindowInfo(System::IntPtr windowHandle, System::String ^properties) { AutomationElement ^element = AutomationElement::FromHandle(windowHandle); - return getWindowInfo(element, properties); + return getWindowInfo(element, properties, nullptr); } System::String ^ AutomationBridge::getWindowInfo(System::String ^runtimeIdStr, System::String ^properties) diff --git a/native/uiabridge/uiabridge.h b/native/uiabridge/uiabridge.h index 16cd3aa..30c8103 100644 --- a/native/uiabridge/uiabridge.h +++ b/native/uiabridge/uiabridge.h @@ -18,6 +18,7 @@ namespace uiabridge { { public: AutomationBridge(void); + AutomationBridge(System::String ^cachedProperties); ~AutomationBridge(); int addEnumFilter(System::String ^propertyName, System::String ^propertyValue); void clearEnumFilters(); @@ -28,7 +29,7 @@ namespace uiabridge { array ^ enumWindowInfo(System::IntPtr windowHandle, System::String ^properties); array ^ enumWindowInfo(AutomationElement ^element, System::String ^properties); array ^ enumWindowInfo(AutomationElement ^element, System::String ^properties, List ^filterModifierList); - System::String ^ getWindowInfo(AutomationElement ^element, System::String ^properties); + System::String ^ getWindowInfo(AutomationElement ^element, System::String ^properties, AutomationElement ^optionalParentElement); System::String ^ getWindowInfo(System::Int32 x, System::Int32 y, System::String ^properties); System::String ^ getWindowInfo(System::IntPtr windowHandle, System::String ^properties); System::String ^ getWindowInfo(System::String ^runtimeIdStr, System::String ^properties); @@ -36,8 +37,9 @@ namespace uiabridge { static System::String ^ALL_MODIFIER = L"All";// find all matching elements of this filter static System::String ^PARENT_MODIFIER = L"Parent";//find all children of this matching parent filter static System::String ^FIRST_MODIFIER = L"First"; //find first element matching this filter then stop + static System::String ^DEFAULT_CACHED_PROPS = L"RuntimeIdProperty,ParentRuntimeIdProperty,NativeWindowHandleProperty,ProcessIdProperty,FrameworkIdProperty,LocalizedControlTypeProperty,ControlTypeProperty,ClassNameProperty,NameProperty,BoundingRectangleProperty,ValueProperty"; private: - void initializeCache(); + void initializeCache(System::String ^cachedProperties); Dictionary ^enumFilters; void AutomationBridge::processFilterModifier(Boolean filtered, Boolean modifierChanged, List ^filterModifierList); CacheRequest ^cacheRequest; diff --git a/native/uiabtest/Release/uiabridge.dll b/native/uiabtest/Release/uiabridge.dll new file mode 100644 index 0000000..9f4a4c8 Binary files /dev/null and b/native/uiabtest/Release/uiabridge.dll differ diff --git a/native/uiabtest/Release/uiabtest.exe b/native/uiabtest/Release/uiabtest.exe new file mode 100644 index 0000000..030141b Binary files /dev/null and b/native/uiabtest/Release/uiabtest.exe differ diff --git a/native/uiabtest/uiabtest.cpp b/native/uiabtest/uiabtest.cpp index c14b813..9c39bda 100644 --- a/native/uiabtest/uiabtest.cpp +++ b/native/uiabtest/uiabtest.cpp @@ -25,32 +25,67 @@ void outputResults(array ^winInfo) } +void runBasicTests(AutomationBridge ^ab, System::String ^propList) +{ + array ^winInfo = nullptr; + System::DateTime start; + System::Double seconds = 0; + + start = System::DateTime::Now; + ab->clearEnumFilters(); + ab->addEnumFilter("Parent/FrameworkIdProperty", "WinForm"); + winInfo = ab->enumWindowInfo(propList); + //outputResults(winInfo); + seconds = System::Math::Round(System::DateTime::Now.Subtract(start).TotalSeconds, 4); + Console::WriteLine(L"Total WinForm Elements: {0} in {1} seconds", winInfo->Length, seconds); + + start = System::DateTime::Now; + ab->clearEnumFilters(); + ab->addEnumFilter("Parent/FrameworkIdProperty", "WPF"); + winInfo = ab->enumWindowInfo(propList); + //outputResults(winInfo); + seconds = System::Math::Round(System::DateTime::Now.Subtract(start).TotalSeconds, 4); + Console::WriteLine(L"Total WPF Elements: {0} in {1} seconds", winInfo->Length, seconds); + + start = System::DateTime::Now; + ab->clearEnumFilters(); + winInfo = ab->enumWindowInfo(propList); + //outputResults(winInfo); + seconds = System::Math::Round(System::DateTime::Now.Subtract(start).TotalSeconds, 4); + Console::WriteLine(L"Total All Elements: {0} in {1} seconds", winInfo->Length, seconds); + Console::WriteLine(L"---------------------------------------"); +} + int main(array ^args) { Console::WriteLine(L"UI Automation Bridge Test"); - AutomationBridge ^ab = gcnew AutomationBridge(); - System::String ^propList = L"RuntimeIdProperty,ParentRuntimeIdProperty,NativeWindowHandleProperty,ProcessIdProperty,FrameworkIdProperty,LocalizedControlTypeProperty,ClassNameProperty,NameProperty"; + //System::String ^propList = L"RuntimeIdProperty,ProcessIdProperty,FrameworkIdProperty,LocalizedControlTypeProperty,ClassNameProperty,NameProperty"; + System::String ^propList = L"RuntimeIdProperty,ParentRuntimeIdProperty,NativeWindowHandleProperty,ProcessIdProperty,FrameworkIdProperty,LocalizedControlTypeProperty,ControlTypeProperty,ClassNameProperty,NameProperty,BoundingRectangleProperty"; + AutomationBridge ^ab = gcnew AutomationBridge(propList); //System::String ^propList = L"RuntimeIdProperty,BoundingRectangleProperty"; Console::WriteLine(propList); - //System::String ^winInfo1 = ab->getWindowInfo(System::IntPtr(3409618), propList); - System::DateTime start = System::DateTime::Now; + runBasicTests(ab, propList); + runBasicTests(ab, propList); + runBasicTests(ab, propList); + + //System::String ^winInfo1 = ab->getWindowInfo(System::IntPtr(3409618), propList); //ab->addEnumFilter("Parent/ClassNameProperty", "Notepad"); //ab->addEnumFilter("First/RuntimeIdProperty", "42-4784952"); //ab->addEnumFilter("ClassNameProperty", "Notepad"); //ab->addEnumFilter("All/ClassNameProperty", "Edit"); //ab->addEnumFilter("All/LocalizedControlTypeProperty", "menu item"); - ab->addEnumFilter("Parent/FrameworkIdProperty", "WinForm"); + //ab->addEnumFilter("Parent/FrameworkIdProperty", "WinForm"); //ab->addEnumFilter("Parent/FrameworkIdProperty", "WPF"); //ab->addEnumFilter("Parent/ClassNameProperty", "WindowsForms10.Window.8.app.0.2bf8098_r13_ad1"); - array ^winInfo = ab->enumWindowInfo(propList); //L"*" + //array ^winInfo = ab->enumWindowInfo(propList); //L"*" //ab->clearEnumFilters(); //ab->addEnumFilter("Parent/FrameworkIdProperty", "WinForm"); //array ^winInfo = ab->enumWindowInfo(System::IntPtr(3409618), propList); //L"*" //array ^winInfo = ab->enumWindowInfo(System::IntPtr(12977932), propList); //L"*" //Console::WriteLine("enumWindowInfo x,y: {0}", ab->getWindowInfo(100,100, propList); //L"*" - outputResults(winInfo); + //outputResults(winInfo); //Globals::Global::AUTO_BRIDGE->clearEnumFilters(); //winInfo = nullptr; //winInfo = Globals::Global::AUTO_BRIDGE->enumWindowInfo(System::IntPtr(7603636), propList); @@ -64,8 +99,9 @@ int main(array ^args) //array ^winInfo2 = ab->enumWindowInfo(propList); //L"*" //outputResults(winInfo2); - System::Double seconds = System::Math::Round(System::DateTime::Now.Subtract(start).TotalSeconds, 4); - Console::WriteLine(L"Total Elements: {0} in {1} seconds", winInfo->Length, seconds); + //System::Double seconds = System::Math::Round(System::DateTime::Now.Subtract(start).TotalSeconds, 4); + //Console::WriteLine(L"Total Elements: {0} in {1} seconds", winInfo->Length, seconds); + Console::WriteLine(L"press any key to exit"); getch();//wait for user input return 0; } diff --git a/src/org/synthuse/Api.java b/src/org/synthuse/Api.java index 6dcea55..a5c0e79 100644 --- a/src/org/synthuse/Api.java +++ b/src/org/synthuse/Api.java @@ -15,9 +15,11 @@ 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.ULONG_PTR; import com.sun.jna.platform.win32.WinDef; 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; @@ -133,6 +135,11 @@ public class Api { 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 WinDefExt extends WinDef { //Structures public class MENUITEMINFO extends Structure { @@ -235,6 +242,7 @@ public class Api { //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); @@ -243,7 +251,7 @@ public class Api { //BOOL WINAPI GetMenuItemInfo(_In_ HMENU hMenu, _In_ UINT uItem, _In_ BOOL fByPosition, _Inout_ LPMENUITEMINFO lpmii); boolean GetMenuItemInfoA(HMENU hMenu, int uItem, boolean fByPosition, WinDefExt.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); @@ -536,4 +544,10 @@ public class Api { User32.instance.RedrawWindow(hwnd, 0, 0, RDW_FRAME | RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN); } + public static boolean isDotNet4Installed() { + 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); + } + } diff --git a/src/org/synthuse/CommandPopupMenu.java b/src/org/synthuse/CommandPopupMenu.java index bc535a8..c085af7 100644 --- a/src/org/synthuse/CommandPopupMenu.java +++ b/src/org/synthuse/CommandPopupMenu.java @@ -109,6 +109,9 @@ public class CommandPopupMenu extends JPopupMenu { CommandMenuItem mntmSelectMenu = new CommandMenuItem("selectMenu", 2); mnWinMessages.add(mntmSelectMenu); + + CommandMenuItem mntmSelectContextMenuId = new CommandMenuItem("selectContextMenuId", 3); + mnWinMessages.add(mntmSelectContextMenuId); CommandMenuItem mntmSetcursorposition = new CommandMenuItem("setCursorPosition", 3); mnWinMessages.add(mntmSetcursorposition); diff --git a/src/org/synthuse/CommandProcessor.java b/src/org/synthuse/CommandProcessor.java index 5317da5..f69d185 100644 --- a/src/org/synthuse/CommandProcessor.java +++ b/src/org/synthuse/CommandProcessor.java @@ -205,6 +205,8 @@ public class CommandProcessor implements Runnable{ return win.cmdWindowFocus(args); if (command.equals("selectMenu")) return win.cmdSelectMenu(args); + if (command.equals("selectContextMenuId")) + return win.cmdSelectContextMenuId(args); if (command.equals("windowMinimize")) return win.cmdWindowMinimize(args); if (command.equals("windowMaximize")) diff --git a/src/org/synthuse/KeyboardHook.java b/src/org/synthuse/KeyboardHook.java index 397ed09..ff3b4d9 100644 --- a/src/org/synthuse/KeyboardHook.java +++ b/src/org/synthuse/KeyboardHook.java @@ -131,7 +131,7 @@ public class KeyboardHook implements Runnable{ } // search target keyboard event list for a match and return it otherwise return null if no match - public TargetKeyPress getTargetKeyPressed(int keyCode) { + private TargetKeyPress getTargetKeyPressed(int keyCode) { TargetKeyPress target = null; for (TargetKeyPress tkp : KeyboardHook.targetList) { if (tkp.targetKeyCode != keyCode) @@ -159,6 +159,7 @@ public class KeyboardHook implements Runnable{ @Override public void run() { createGlobalKeyboardHook(); + System.out.println("Unhooking Global Keyboard Hook"); unhook();//wait for quit == true then unhook } diff --git a/src/org/synthuse/MenuInfo.java b/src/org/synthuse/MenuInfo.java index 8ca3217..2900c75 100644 --- a/src/org/synthuse/MenuInfo.java +++ b/src/org/synthuse/MenuInfo.java @@ -10,7 +10,7 @@ package org.synthuse; import java.math.BigInteger; import com.sun.jna.Pointer; -import com.sun.jna.platform.win32.WinDef.HMENU; +import com.sun.jna.platform.win32.WinDef.*; public class MenuInfo { public HMENU hmenu = null; @@ -25,12 +25,15 @@ public class MenuInfo { public HMENU submenu = null; public String submenuStr = ""; public int submenuCount = 0; + public String center = ""; - public MenuInfo(HMENU hmenu) { + public MenuInfo(String hwndStr, HMENU hmenu) { + this.hwndStr = hwndStr; loadMenuBase(hmenu); } - public MenuInfo(HMENU hmenu, int position) { + public MenuInfo(String hwndStr, HMENU hmenu, int position) { + this.hwndStr = hwndStr; loadMenuBase(hmenu); if (this.menuCount > 0) loadMenuDetails(hmenu, position); @@ -52,6 +55,14 @@ public class MenuInfo { 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); diff --git a/src/org/synthuse/RobotMacro.java b/src/org/synthuse/RobotMacro.java index 999365b..04d7115 100644 --- a/src/org/synthuse/RobotMacro.java +++ b/src/org/synthuse/RobotMacro.java @@ -68,7 +68,7 @@ public class RobotMacro { public static void rightClickMouse() { try { - System.out.println("rightClickMouse"); + //System.out.println("rightClickMouse"); Robot robot = new Robot(); //robot.mouseMove(200, 200); //robot.delay(1000); diff --git a/src/org/synthuse/SynthuseDlg.java b/src/org/synthuse/SynthuseDlg.java index a2b5d71..8a173f2 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.3"; + public static String VERSION_STR = "1.1.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"; diff --git a/src/org/synthuse/UiaBridge.java b/src/org/synthuse/UiaBridge.java index b4cf59e..3f84b10 100644 --- a/src/org/synthuse/UiaBridge.java +++ b/src/org/synthuse/UiaBridge.java @@ -6,8 +6,13 @@ 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"; + static { + if (!Api.isDotNet4Installed()) //if .net 4.0 isn't installed don't use uiabridge + SynthuseDlg.config.disableUiaBridge = "true"; 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 @@ -78,7 +83,7 @@ public class UiaBridge { public UiaBridge () { if (!SynthuseDlg.config.isUiaBridgeDisabled()) - initialize(""); + initialize(CACHED_PROPERTY_LIST); } public native void initialize(String properties); diff --git a/src/org/synthuse/WindowInfo.java b/src/org/synthuse/WindowInfo.java index fa1c226..242b304 100644 --- a/src/org/synthuse/WindowInfo.java +++ b/src/org/synthuse/WindowInfo.java @@ -26,6 +26,7 @@ public class WindowInfo { public static String UIA_PROPERTY_LIST = "RuntimeIdProperty,ParentRuntimeIdProperty,ProcessIdProperty,FrameworkIdProperty,LocalizedControlTypeProperty,ClassNameProperty,NameProperty,ValueProperty"; public static String UIA_RUNTIME_ID = "RuntimeIdProperty"; + public static String UIA_BOUNDING_RECT = "BoundingRectangleProperty"; public static int MAX_TEXT_SIZE = 200; public HWND hwnd; @@ -96,23 +97,7 @@ public class WindowInfo { extra = new LinkedHashMap(); extra.put("tvCount", tvCount.intValue() + ""); } - - //check if window has a menu - HMENU hmenu = Api.User32.instance.GetMenu(hWnd); - if (hmenu != null) { //menu item count - int menuCount = Api.User32.instance.GetMenuItemCount(hmenu); - if (menuCount > 0) { - this.menus = menuCount; - this.menu = hmenu; - } - else - { - LRESULT result = Api.User32.instance.PostMessage(hWnd, Api.MN_GETHMENU, new WPARAM(0), new LPARAM()); - if (result.longValue() != 1) - System.out.println("MN_GETHMENU: " + result.longValue()); - } - } - + /* if (isChild) { int ctrlID = Api.User32.instance.GetDlgCtrlID(hWnd); if (ctrlID > 0){ @@ -125,12 +110,40 @@ public class WindowInfo { extra.put("dgText", dgText + ""); } } - } + }*/ char[] buffer2 = new char[1026]; User32.instance.GetClassName(hWnd, buffer2, 1026); className = Native.toString(buffer2); + //check if window has a menu + HMENU hmenu = Api.User32.instance.GetMenu(hWnd); + if (hmenu != null) { //menu item count + int menuCount = Api.User32.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.User32.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.User32.instance.GetMenuItemCount(hmenu); + if (menuCount > 0) + { + //System.out.println("Popup Win: " + menuCount); + this.menus = menuCount; + this.menu = hmenu; + } + } + } + + rect = new RECT(); User32.instance.GetWindowRect(hWnd, rect); diff --git a/src/org/synthuse/WindowsEnumeratedXml.java b/src/org/synthuse/WindowsEnumeratedXml.java index 8f7396e..7c2b1cf 100644 --- a/src/org/synthuse/WindowsEnumeratedXml.java +++ b/src/org/synthuse/WindowsEnumeratedXml.java @@ -249,16 +249,18 @@ public class WindowsEnumeratedXml implements Runnable{ public static Element buildMenuXmlElements(Document xmlDoc, Element xmlElement, HMENU targetMenu, String targetWin) { - MenuInfo firstMi = new MenuInfo(targetMenu); + MenuInfo firstMi = new MenuInfo(targetWin, targetMenu); for (int i = 0 ; i < firstMi.menuCount ; i++ ) { - MenuInfo menuInfo = new MenuInfo(targetMenu, 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", targetWin + ""); + menuElement.setAttribute("hwnd", menuInfo.hwndStr + ""); + if (!menuInfo.center.isEmpty()) + menuElement.setAttribute("center", menuInfo.center + ""); if (menuInfo.hasSubMenu) { buildMenuXmlElements(xmlDoc, menuElement, menuInfo.submenu, targetWin); } diff --git a/src/org/synthuse/commands/WindowsCommands.java b/src/org/synthuse/commands/WindowsCommands.java index 0a8b5eb..7180508 100644 --- a/src/org/synthuse/commands/WindowsCommands.java +++ b/src/org/synthuse/commands/WindowsCommands.java @@ -122,6 +122,22 @@ public class WindowsCommands extends BaseCommand { //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 + //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; } }