Added more exception handling in uiabridge, fixing Keyboard hook stability
uiabridge was having issues with getting ValueProperty from the cached values. uiabridge was throwing exceptions if it couldn't find a missing HWND handle. Fixing keyboard hook to last longer.
This commit is contained in:
Binary file not shown.
Binary file not shown.
@@ -67,7 +67,9 @@ void AutomationBridge::initializeCache(System::String ^cachedProperties)
|
|||||||
if (cachedPropStr->Contains(L"ValueProperty")) //special property not in the root property list
|
if (cachedPropStr->Contains(L"ValueProperty")) //special property not in the root property list
|
||||||
{
|
{
|
||||||
cacheList->Add(ValuePattern::ValueProperty);
|
cacheList->Add(ValuePattern::ValueProperty);
|
||||||
|
cacheRequest->Add(AutomationElement::IsValuePatternAvailableProperty);
|
||||||
cacheRequest->Add(ValuePattern::ValueProperty);
|
cacheRequest->Add(ValuePattern::ValueProperty);
|
||||||
|
cacheRequest->Add(ValuePattern::Pattern);
|
||||||
}
|
}
|
||||||
for each(AutomationProperty ^ap in rootProperties) //loop through all supported Properties for a child
|
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;
|
int filterMatchCount = 0;
|
||||||
if (enumFilters->Count == 0)
|
if (enumFilters->Count == 0)
|
||||||
return result;
|
return result;
|
||||||
array<AutomationProperty^> ^aps = cachedRootProperties;//element->GetSupportedProperties();
|
//array<AutomationProperty^> ^aps = cachedRootProperties;//element->GetSupportedProperties();
|
||||||
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
|
||||||
{
|
{
|
||||||
System::String ^currentPropertyStr = L""; //current property values
|
System::String ^currentPropertyStr = L""; //current property values
|
||||||
System::String ^shortPropName = L" null ";
|
System::String ^shortPropName = L" null ";
|
||||||
@@ -252,8 +254,16 @@ array<System::String ^> ^ AutomationBridge::enumWindowInfo(System::String ^prope
|
|||||||
|
|
||||||
array<System::String ^> ^ AutomationBridge::enumWindowInfo(System::IntPtr windowHandle, System::String ^properties)
|
array<System::String ^> ^ AutomationBridge::enumWindowInfo(System::IntPtr windowHandle, System::String ^properties)
|
||||||
{
|
{
|
||||||
AutomationElement ^element = AutomationElement::FromHandle(windowHandle);
|
|
||||||
List<System::String ^> ^winInfoList = gcnew List<System::String ^>();
|
List<System::String ^> ^winInfoList = gcnew List<System::String ^>();
|
||||||
|
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
|
if (!isElementFiltered(element)) //test parent should be filtered
|
||||||
winInfoList->Add(getWindowInfo(element, properties, nullptr));
|
winInfoList->Add(getWindowInfo(element, properties, nullptr));
|
||||||
winInfoList->AddRange(enumWindowInfo(element, properties));
|
winInfoList->AddRange(enumWindowInfo(element, properties));
|
||||||
@@ -307,7 +317,7 @@ array<System::String ^> ^ AutomationBridge::enumWindowInfo(AutomationElement ^pa
|
|||||||
//currentElement->
|
//currentElement->
|
||||||
} catch (Exception ^ex)
|
} catch (Exception ^ex)
|
||||||
{
|
{
|
||||||
System::Console::WriteLine("Exception: {0} {1}", ex->Message, ex->StackTrace);
|
output(ex, "");
|
||||||
}
|
}
|
||||||
currentElement = tw->GetNextSibling(currentElement, cacheRequest);
|
currentElement = tw->GetNextSibling(currentElement, cacheRequest);
|
||||||
}
|
}
|
||||||
@@ -342,7 +352,7 @@ System::String ^ AutomationBridge::getWindowInfo(AutomationElement ^element, Sys
|
|||||||
System::String ^delim = L",";
|
System::String ^delim = L",";
|
||||||
array<System::String ^> ^propSpltArray = properties->Split(delim->ToCharArray());
|
array<System::String ^> ^propSpltArray = properties->Split(delim->ToCharArray());
|
||||||
System::Int32 count = 0;
|
System::Int32 count = 0;
|
||||||
array<AutomationProperty^> ^aps = cachedRootProperties;//element->GetSupportedProperties();
|
//array<AutomationProperty^> ^aps = cachedRootProperties;//element->GetSupportedProperties();
|
||||||
array<System::String ^> ^propValues = gcnew array<System::String ^>(propSpltArray->Length);//keep order
|
array<System::String ^> ^propValues = gcnew array<System::String ^>(propSpltArray->Length);//keep order
|
||||||
System::String ^wildcardProperties = L"";
|
System::String ^wildcardProperties = L"";
|
||||||
if (wildcardEnabled) {
|
if (wildcardEnabled) {
|
||||||
@@ -357,7 +367,7 @@ System::String ^ AutomationBridge::getWindowInfo(AutomationElement ^element, Sys
|
|||||||
propValues[i] = parentRuntimeId;
|
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
|
propertyNameErrorCheck = ap->ProgrammaticName;//debug purposes
|
||||||
System::String ^currentPropertyStr = L""; //current property values
|
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::Console::WriteLine("shortPropName: {0}", shortPropName);
|
||||||
//System::Object ^currentVal = element->GetCurrentPropertyValue(ap);
|
//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)
|
if (currentVal == nullptr)
|
||||||
continue;
|
continue;
|
||||||
if (ap->ProgrammaticName->Equals(L"AutomationElementIdentifiers.RuntimeIdProperty"))
|
if (ap->ProgrammaticName->Equals(L"AutomationElementIdentifiers.RuntimeIdProperty"))
|
||||||
@@ -409,7 +427,7 @@ System::String ^ AutomationBridge::getWindowInfo(AutomationElement ^element, Sys
|
|||||||
resultProperties += wildcardProperties;
|
resultProperties += wildcardProperties;
|
||||||
} catch (Exception ^ex) //when some elements close during enumeration it might cause valid exceptions
|
} 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;
|
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)
|
System::String ^ AutomationBridge::getWindowInfo(System::Int32 x, System::Int32 y, System::String ^properties)
|
||||||
{
|
{
|
||||||
AutomationElement ^element = AutomationElement::FromPoint(System::Windows::Point(x, y));
|
AutomationElement ^element = AutomationElement::FromPoint(System::Windows::Point(x, y));
|
||||||
|
if (element == nullptr)
|
||||||
|
return "";
|
||||||
return getWindowInfo(element, properties, nullptr);
|
return getWindowInfo(element, properties, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
System::String ^ AutomationBridge::getWindowInfo(System::IntPtr windowHandle, System::String ^properties)
|
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);
|
return getWindowInfo(element, properties, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -439,3 +467,8 @@ System::String ^ AutomationBridge::getWindowInfo(System::String ^runtimeIdStr, S
|
|||||||
return "";
|
return "";
|
||||||
//return getWindowInfo(element, properties);
|
//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);
|
||||||
|
}
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ namespace uiabridge {
|
|||||||
static System::String ^DEFAULT_CACHED_PROPS = L"RuntimeIdProperty,ParentRuntimeIdProperty,NativeWindowHandleProperty,ProcessIdProperty,FrameworkIdProperty,LocalizedControlTypeProperty,ControlTypeProperty,ClassNameProperty,NameProperty,BoundingRectangleProperty,ValueProperty";
|
static System::String ^DEFAULT_CACHED_PROPS = L"RuntimeIdProperty,ParentRuntimeIdProperty,NativeWindowHandleProperty,ProcessIdProperty,FrameworkIdProperty,LocalizedControlTypeProperty,ControlTypeProperty,ClassNameProperty,NameProperty,BoundingRectangleProperty,ValueProperty";
|
||||||
private:
|
private:
|
||||||
void initializeCache(System::String ^cachedProperties);
|
void initializeCache(System::String ^cachedProperties);
|
||||||
|
void output(Exception ^ex, System::String ^message);
|
||||||
Dictionary<System::String ^, System::String ^> ^enumFilters;
|
Dictionary<System::String ^, System::String ^> ^enumFilters;
|
||||||
void AutomationBridge::processFilterModifier(Boolean filtered, Boolean modifierChanged, List<System::String ^> ^filterModifierList);
|
void AutomationBridge::processFilterModifier(Boolean filtered, Boolean modifierChanged, List<System::String ^> ^filterModifierList);
|
||||||
CacheRequest ^cacheRequest;
|
CacheRequest ^cacheRequest;
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import java.util.Collections;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import com.sun.jna.*;
|
import com.sun.jna.*;
|
||||||
|
import com.sun.jna.platform.win32.User32;
|
||||||
import com.sun.jna.platform.win32.WinUser.*;
|
import com.sun.jna.platform.win32.WinUser.*;
|
||||||
import com.sun.jna.platform.win32.WinDef.*;
|
import com.sun.jna.platform.win32.WinDef.*;
|
||||||
import com.sun.jna.win32.W32APIOptions;
|
import com.sun.jna.win32.W32APIOptions;
|
||||||
@@ -62,8 +63,9 @@ public class KeyboardHook implements Runnable{
|
|||||||
public static LowLevelKeyboardProc lpfn;
|
public static LowLevelKeyboardProc lpfn;
|
||||||
public static volatile boolean quit = false;
|
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);
|
LRESULT LowLevelKeyboardProc(int nCode,WPARAM wParam,LPARAM lParam);
|
||||||
HHOOK SetWindowsHookEx(int idHook, HOOKPROC lpfn, HMODULE hMod, int dwThreadId);
|
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 PeekMessage(MSG lpMsg, HWND hWnd, int wMsgFilterMin, int wMsgFilterMax, int wRemoveMsg);
|
||||||
boolean UnhookWindowsHookEx(HHOOK idHook);
|
boolean UnhookWindowsHookEx(HHOOK idHook);
|
||||||
short GetKeyState(int nVirtKey);
|
short GetKeyState(int nVirtKey);
|
||||||
|
short GetAsyncKeyState(int nVirtKey);
|
||||||
|
|
||||||
//public static interface HOOKPROC extends StdCallCallback {
|
//public static interface HOOKPROC extends StdCallCallback {
|
||||||
// LRESULT callback(int nCode, WPARAM wParam, KBDLLHOOKSTRUCT lParam);
|
// LRESULT callback(int nCode, WPARAM wParam, KBDLLHOOKSTRUCT lParam);
|
||||||
//}
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface Kernel32 extends W32APIOptions {
|
public interface Kernel32 extends W32APIOptions {
|
||||||
Kernel32 instance = (Kernel32) Native.loadLibrary("kernel32", Kernel32.class, DEFAULT_OPTIONS);
|
Kernel32 instance = (Kernel32) Native.loadLibrary("kernel32", Kernel32.class, DEFAULT_OPTIONS);
|
||||||
|
|
||||||
@@ -97,29 +101,48 @@ public class KeyboardHook implements Runnable{
|
|||||||
events.keyPressed(target);
|
events.keyPressed(target);
|
||||||
//if (lParam.vkCode == 87) //w
|
//if (lParam.vkCode == 87) //w
|
||||||
// quit = true;
|
// 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)
|
if (hHook == null)
|
||||||
return;
|
return;
|
||||||
MSG msg = new MSG();
|
MSG msg = new MSG();
|
||||||
|
int cnt = 0;
|
||||||
try {
|
try {
|
||||||
while (!quit) {
|
while (!quit) {
|
||||||
User32.instance.PeekMessage(msg, null, 0, 0, 0);
|
User32.INSTANCE.PeekMessage(msg, null, 0, 0, 1);
|
||||||
Thread.sleep(10);
|
Thread.sleep(10);
|
||||||
|
++cnt;
|
||||||
|
if (cnt > 500)
|
||||||
|
{
|
||||||
|
cnt = 0;
|
||||||
|
//System.out.println("heartbeat test");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
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
|
//unhook the Global Windows Keyboard hook
|
||||||
public void unhook() {
|
public void unhook() {
|
||||||
if (hHook == null)
|
if (hHook == null)
|
||||||
return;
|
return;
|
||||||
if (!User32.instance.UnhookWindowsHookEx(hHook))
|
if (!User32.INSTANCE.UnhookWindowsHookEx(hHook))
|
||||||
System.out.println("Failed to unhook");
|
System.out.println("Failed to unhook");
|
||||||
//System.out.println("Unhooked");
|
//System.out.println("Unhooked");
|
||||||
hHook = null;
|
hHook = null;
|
||||||
@@ -136,9 +159,9 @@ public class KeyboardHook implements Runnable{
|
|||||||
for (TargetKeyPress tkp : KeyboardHook.targetList) {
|
for (TargetKeyPress tkp : KeyboardHook.targetList) {
|
||||||
if (tkp.targetKeyCode != keyCode)
|
if (tkp.targetKeyCode != keyCode)
|
||||||
continue;
|
continue;
|
||||||
if (!tkp.withShift || ((User32.instance.GetKeyState(VK_SHIFT) & 0x8000) != 0)) {
|
if (!tkp.withShift || ((User32Ex.instance.GetKeyState(VK_SHIFT) & 0x8000) != 0)) {
|
||||||
if (!tkp.withCtrl || ((User32.instance.GetKeyState(VK_CONTROL) & 0x8000) != 0)) {
|
if (!tkp.withCtrl || ((User32Ex.instance.GetKeyState(VK_CONTROL) & 0x8000) != 0)) {
|
||||||
if (!tkp.withAlt || ((User32.instance.GetKeyState(VK_MENU) & 0x8000) != 0)) {
|
if (!tkp.withAlt || ((User32Ex.instance.GetKeyState(VK_MENU) & 0x8000) != 0)) {
|
||||||
return tkp;
|
return tkp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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_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_REFRESH_IMG = "/org/synthuse/img/rapidsvn.png";
|
||||||
|
|||||||
Reference in New Issue
Block a user