diff --git a/native/uiabridge/bin/uiabridge32.dll b/native/uiabridge/bin/uiabridge32.dll index 7969ec0..4a70884 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 ce2c675..0562c3a 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 d6dfeff..d095bdd 100644 --- a/native/uiabridge/uiabridge.cpp +++ b/native/uiabridge/uiabridge.cpp @@ -67,7 +67,9 @@ void AutomationBridge::initializeCache(System::String ^cachedProperties) if (cachedPropStr->Contains(L"ValueProperty")) //special property not in the root property list { cacheList->Add(ValuePattern::ValueProperty); + cacheRequest->Add(AutomationElement::IsValuePatternAvailableProperty); cacheRequest->Add(ValuePattern::ValueProperty); + cacheRequest->Add(ValuePattern::Pattern); } for each(AutomationProperty ^ap in rootProperties) //loop through all supported Properties for a child { @@ -109,8 +111,8 @@ Boolean AutomationBridge::isElementFiltered(System::Windows::Automation::Automat int filterMatchCount = 0; if (enumFilters->Count == 0) return result; - array ^aps = cachedRootProperties;//element->GetSupportedProperties(); - for each(AutomationProperty ^ap in aps) //loop through all supported Properties for a child + //array ^aps = cachedRootProperties;//element->GetSupportedProperties(); + for each(AutomationProperty ^ap in cachedRootProperties) //loop through all supported Properties for a child { System::String ^currentPropertyStr = L""; //current property values System::String ^shortPropName = L" null "; @@ -252,8 +254,16 @@ array ^ AutomationBridge::enumWindowInfo(System::String ^prope array ^ AutomationBridge::enumWindowInfo(System::IntPtr windowHandle, System::String ^properties) { - AutomationElement ^element = AutomationElement::FromHandle(windowHandle); List ^winInfoList = gcnew List(); + AutomationElement ^element = nullptr; + try { + element = AutomationElement::FromHandle(windowHandle); + } catch (Exception ^ex) { + output(ex, ""); + return winInfoList->ToArray(); + } + if (element == nullptr) + return winInfoList->ToArray(); if (!isElementFiltered(element)) //test parent should be filtered winInfoList->Add(getWindowInfo(element, properties, nullptr)); winInfoList->AddRange(enumWindowInfo(element, properties)); @@ -307,7 +317,7 @@ array ^ AutomationBridge::enumWindowInfo(AutomationElement ^pa //currentElement-> } catch (Exception ^ex) { - System::Console::WriteLine("Exception: {0} {1}", ex->Message, ex->StackTrace); + output(ex, ""); } currentElement = tw->GetNextSibling(currentElement, cacheRequest); } @@ -342,7 +352,7 @@ System::String ^ AutomationBridge::getWindowInfo(AutomationElement ^element, Sys System::String ^delim = L","; array ^propSpltArray = properties->Split(delim->ToCharArray()); System::Int32 count = 0; - array ^aps = cachedRootProperties;//element->GetSupportedProperties(); + //array ^aps = cachedRootProperties;//element->GetSupportedProperties(); array ^propValues = gcnew array(propSpltArray->Length);//keep order System::String ^wildcardProperties = L""; if (wildcardEnabled) { @@ -357,7 +367,7 @@ System::String ^ AutomationBridge::getWindowInfo(AutomationElement ^element, Sys propValues[i] = parentRuntimeId; } } - for each(AutomationProperty ^ap in aps) //loop through all supported Properties for a child + for each(AutomationProperty ^ap in cachedRootProperties) //loop through all supported Properties for a child { propertyNameErrorCheck = ap->ProgrammaticName;//debug purposes System::String ^currentPropertyStr = L""; //current property values @@ -369,7 +379,15 @@ System::String ^ AutomationBridge::getWindowInfo(AutomationElement ^element, Sys { //System::Console::WriteLine("shortPropName: {0}", shortPropName); //System::Object ^currentVal = element->GetCurrentPropertyValue(ap); - System::Object ^currentVal = element->GetCachedPropertyValue(ap); + System::Object ^currentVal = nullptr; + if (shortPropName->Equals("ValueProperty")) //check if Value Pattern is an Available Property + { + if (((Boolean)element->GetCurrentPropertyValue(element->IsValuePatternAvailableProperty)) == false) + continue; + else + currentVal = element->GetCurrentPropertyValue(ap); //cached pattern was having issues; + } + currentVal = element->GetCachedPropertyValue(ap); if (currentVal == nullptr) continue; if (ap->ProgrammaticName->Equals(L"AutomationElementIdentifiers.RuntimeIdProperty")) @@ -409,7 +427,7 @@ System::String ^ AutomationBridge::getWindowInfo(AutomationElement ^element, Sys resultProperties += wildcardProperties; } catch (Exception ^ex) //when some elements close during enumeration it might cause valid exceptions { - System::Console::WriteLine("Exception ({2}): {0} {1}", ex->Message, ex->StackTrace, propertyNameErrorCheck); + output(ex, " getWindowInfo on " + propertyNameErrorCheck + ", results: " + resultProperties); } return resultProperties; @@ -418,12 +436,22 @@ 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)); + if (element == nullptr) + return ""; return getWindowInfo(element, properties, nullptr); } System::String ^ AutomationBridge::getWindowInfo(System::IntPtr windowHandle, System::String ^properties) { - AutomationElement ^element = AutomationElement::FromHandle(windowHandle); + AutomationElement ^element = nullptr; + try { + AutomationElement ^element = AutomationElement::FromHandle(windowHandle); + } catch (Exception ^ex) { + output(ex, ""); + return ""; + } + if (element == nullptr) + return ""; return getWindowInfo(element, properties, nullptr); } @@ -439,3 +467,8 @@ System::String ^ AutomationBridge::getWindowInfo(System::String ^runtimeIdStr, S return ""; //return getWindowInfo(element, properties); } + +void AutomationBridge::output(Exception ^ex, System::String ^message) +{ + System::Console::WriteLine("Exception ({0}): {1} \n{2}", message, ex->Message, ex->StackTrace); +} diff --git a/native/uiabridge/uiabridge.h b/native/uiabridge/uiabridge.h index 30c8103..6025d86 100644 --- a/native/uiabridge/uiabridge.h +++ b/native/uiabridge/uiabridge.h @@ -40,6 +40,7 @@ namespace uiabridge { static System::String ^DEFAULT_CACHED_PROPS = L"RuntimeIdProperty,ParentRuntimeIdProperty,NativeWindowHandleProperty,ProcessIdProperty,FrameworkIdProperty,LocalizedControlTypeProperty,ControlTypeProperty,ClassNameProperty,NameProperty,BoundingRectangleProperty,ValueProperty"; private: void initializeCache(System::String ^cachedProperties); + void output(Exception ^ex, System::String ^message); Dictionary ^enumFilters; void AutomationBridge::processFilterModifier(Boolean filtered, Boolean modifierChanged, List ^filterModifierList); CacheRequest ^cacheRequest; diff --git a/src/org/synthuse/KeyboardHook.java b/src/org/synthuse/KeyboardHook.java index 7fc7e63..034d311 100644 --- a/src/org/synthuse/KeyboardHook.java +++ b/src/org/synthuse/KeyboardHook.java @@ -14,6 +14,7 @@ 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.WinUser.*; import com.sun.jna.platform.win32.WinDef.*; import com.sun.jna.win32.W32APIOptions; @@ -62,8 +63,9 @@ public class KeyboardHook implements Runnable{ public static LowLevelKeyboardProc lpfn; public static volatile boolean quit = false; - public interface User32 extends W32APIOptions { - User32 instance = (User32) Native.loadLibrary("user32", User32.class, DEFAULT_OPTIONS); + + 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); @@ -72,11 +74,13 @@ public class KeyboardHook implements Runnable{ boolean PeekMessage(MSG lpMsg, HWND hWnd, int wMsgFilterMin, int wMsgFilterMax, int wRemoveMsg); boolean UnhookWindowsHookEx(HHOOK idHook); short GetKeyState(int nVirtKey); + short GetAsyncKeyState(int nVirtKey); //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); @@ -97,29 +101,48 @@ public class KeyboardHook implements Runnable{ events.keyPressed(target); //if (lParam.vkCode == 87) //w // quit = true; - return User32.instance.CallNextHookEx(hHook, nCode, wParam, lParam.getPointer()); + return User32.INSTANCE.CallNextHookEx(hHook, nCode, wParam, lParam.getPointer()); } }; - hHook = User32.instance.SetWindowsHookEx(WH_KEYBOARD_LL, lpfn, hMod, 0); + hHook = User32.INSTANCE.SetWindowsHookEx(WH_KEYBOARD_LL, lpfn, hMod, 0); if (hHook == null) return; MSG msg = new MSG(); + int cnt = 0; try { while (!quit) { - User32.instance.PeekMessage(msg, null, 0, 0, 0); + User32.INSTANCE.PeekMessage(msg, null, 0, 0, 1); Thread.sleep(10); + ++cnt; + if (cnt > 500) + { + cnt = 0; + //System.out.println("heartbeat test"); + } } } catch (Exception e) { e.printStackTrace(); } + /* + while (!quit) { + // hex arguments: WM_KEYFIRST, WM_KEYLAST + int result = User32.INSTANCE.GetMessage(msg, null, 0x100, 0x109); + if (result == -1) { + break; + } else { + User32.INSTANCE.TranslateMessage(msg); + User32.INSTANCE.DispatchMessage(msg); + } + }*/ + //System.out.println("message loop stopped"); } //unhook the Global Windows Keyboard hook public void unhook() { if (hHook == null) return; - if (!User32.instance.UnhookWindowsHookEx(hHook)) + if (!User32.INSTANCE.UnhookWindowsHookEx(hHook)) System.out.println("Failed to unhook"); //System.out.println("Unhooked"); hHook = null; @@ -136,9 +159,9 @@ public class KeyboardHook implements Runnable{ for (TargetKeyPress tkp : KeyboardHook.targetList) { if (tkp.targetKeyCode != keyCode) continue; - if (!tkp.withShift || ((User32.instance.GetKeyState(VK_SHIFT) & 0x8000) != 0)) { - if (!tkp.withCtrl || ((User32.instance.GetKeyState(VK_CONTROL) & 0x8000) != 0)) { - if (!tkp.withAlt || ((User32.instance.GetKeyState(VK_MENU) & 0x8000) != 0)) { + 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; } } diff --git a/src/org/synthuse/SynthuseDlg.java b/src/org/synthuse/SynthuseDlg.java index 4fefe13..dc23951 100644 --- a/src/org/synthuse/SynthuseDlg.java +++ b/src/org/synthuse/SynthuseDlg.java @@ -72,7 +72,7 @@ public class SynthuseDlg extends JFrame { /** * */ - public static String VERSION_STR = "1.1.7"; + public static String VERSION_STR = "1.1.8"; 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";