写在前面
工作中要通过自动化来操作java桌面程序,Windows的UIA只能识别顶层窗口,无法具体到内部的元素,所以无法使用,经过一番搜索,发现可以通过JavaAccessBridge来访问java中的ui组件。
相关文件
Java在某个版本后内置了JAB,可以在JDK安装目录\\include\\win32\\bridge
下找到以下文件:
- AccessBridgeCallbacks.h (事件监听)
- AccessBridgeCalls.c (API)
- AccessBridgeCalls.h (API)
- AccessBridgePackages.h (数据结构)
可以在JDK安装目录\\include
下找到以下文件:
- jni.h (数据类型)
可以在JRE安装目录\\include
下找到以下文件:
- WindowsAccessBridge-64.dll (包含API具体实现的动态链接库)
文档
JavaAccessBridge指引
JavaAccessBridge介绍
在使用前,一定要通过命令行或控制面板启用jab。
C++调用
正常来说,只需要#include "AccessBridgeCalls.c"
、#include "AccessBridgeCalls.h"
就可以轻松愉快的使用了,然而这样会存在一些问题,具体什么问题我忘了,反正编译无法通过。
对AccessBridgeCalls.c
稍作修改得到AccessBridgeCalls.cpp
:
#include <jni.h>
#include <bridge/AccessBridgeCalls.h>
#define ACCESSBRIDGE_ARCH_64
#define error_code_offset 0x00007FF892C571C5 - 0x00007FF892C50000
// 某些版本的`WindowsAccessBridge-64.dll`存在bug,无法正常回调,所以要修改汇编指令
static unsigned char fix_asm_code[] = { 0x49,0x8B,0xF9 }; // mov rdi,r9
void fix_jab(HMODULE BaseAddr) {
LONGLONG dwFixAddr = (LONGLONG)BaseAddr + error_code_offset;
DWORD OldProtext = 0;
VirtualProtect((LPVOID)dwFixAddr, 3, PAGE_EXECUTE_READWRITE, &OldProtext);
memcpy((void*)dwFixAddr, fix_asm_code, 3);
VirtualProtect((LPVOID)dwFixAddr, 5, OldProtext, &OldProtext);
}
#ifdef __cplusplus
extern "C" {
#endif
HINSTANCE theAccessBridgeInstance;
AccessBridgeFPs theAccessBridge;
BOOL theAccessBridgeInitializedFlag = FALSE;
#define LOAD_FP(result, type, name) \
if ((theAccessBridge.result = \
(type) GetProcAddress(theAccessBridgeInstance, name)) == (type) 0) { \
return FALSE; \
}
BOOL initializeAccessBridge() {
// 这里看你使用的编码,如果是unicode,要在字符串前面加L,如果是ANSI则无需改动
#ifdef ACCESSBRIDGE_ARCH_32 // For 32bit AT new bridge
theAccessBridgeInstance = LoadLibrary(L"WINDOWSACCESSBRIDGE-32");
#else
#ifdef ACCESSBRIDGE_ARCH_64 // For 64bit AT new bridge
theAccessBridgeInstance = LoadLibrary(L"WINDOWSACCESSBRIDGE-64");
#else // legacy
theAccessBridgeInstance = LoadLibrary(L"WINDOWSACCESSBRIDGE");
#endif
#endif
// 后面的跟AccessBridgeCalls.c完全一样,篇幅受限,就不写了
...
使用API
调用JAB的进程需要包含一个消息循环(消息循环必须在调用API之前创建完成),否则无法和Java虚拟机通信。
void PumbThread() {
ChangeWindowMessageFilter(WM_COPYDATA, 1);
for (int i = WM_USER + 0x1; i < 0xffff; i++) {
if (!ChangeWindowMessageFilter(i, 1)) {
cout << i << "error" << endl;
}
}
INITCOMMONCONTROLSEX cc;
cc.dwSize = sizeof(INITCOMMONCONTROLSEX);
cc.dwICC = ICC_TREEVIEW_CLASSES;
InitCommonControlsEx(&cc);
// 初始化
BOOL result = initializeAccessBridge();
if (result != FALSE) {
MSG msg = { 0 };
int ret;
while ((ret = GetMessage(&msg, 0, 0, 0)) != 0) {
switch (msg.message) {
case 0x401:
break;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
// 卸载
shutdownAccessBridge();
}
}
一段简单的处理逻辑
#include <jni.h>
#include <bridge/AccessBridgeCalls.h>
#include <bridge/AccessBridgeCallbacks.h>
// 鼠标点击事件回调函数
void OnMouseClicked(long vmID, JOBJECT64 event, JOBJECT64 source) {
AccessibleContextInfo aci = { 0 };
printf("MouseClicked: vmID: 0x%08lX, event: 0x%016llX, source: 0x%016llX\n", vmID, event, source);
if (GetAccessibleContextInfo(vmID, source, &aci)) {
printf("role: %ws, name: %ws\n", aci.role, wcslen(aci.name) != 0 ? aci.name : L"null");
}
ReleaseJavaObject(vmID, source);
ReleaseJavaObject(vmID, event);
}
void dealJavaWindow(HWND hwnd) {
// 判断是否是java窗口
if (IsJavaWindow(hwnd)) {
long vmId = 0;
AccessibleContext ac = { 0 };
// 根据窗口句柄获取虚拟机ID和控件的AccessibleContext
if (GetAccessibleContextFromHWND(hwnd, &vmId, &ac) == FALSE) {
return;
};
// 获取Java版本信息
AccessBridgeVersionInfo version = { 0 };
GetVersionInfo(vmId, &version);
wcout << version.bridgeWinDLLVersion << endl;
AccessibleContextInfo aci = { 0 };
// 获取可见子元素数量
int length = getVisibleChildrenCount(vmId, ac);
VisibleChildrenInfo vci = { 0 };
// 获取可见子元素
getVisibleChildren(vmId, ac, 0, &vci);
for (int i = 0; i < vci.returnedChildrenCount; i++) {
AccessibleContext* ac_temp = &vci.children[i];
GetAccessibleContextInfo(vmId, *ac_temp, &aci);
RECT ac_rect = { aci.x,aci.y,aci.x + aci.width,aci.y + aci.height };
}
wcout << (long long)hwnd << L" is a java window" << endl;
SetMouseClicked(NULL);
SetMouseClicked(OnMouseClicked);
return;
}
else {
wcout << (long long)hwnd << L" is not java window" << endl;
}
}
int main() {
DWORD threadid = 0;
wcout.imbue(locale("chs"));
HANDLE hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)PumbThread, NULL, NULL, &threadid);
if (hThread)
{
// 等待消息循环创建完成
while (!PostThreadMessage(threadid, 0x401, 0, 0)) {
Sleep(55);
}
Sleep(55);
// 查找目标窗口句柄
HWND nWnd = FindWindow(L"SunAwtFrame", L"");
dealJavaWindow(nWnd);
PostThreadMessage(threadid, WM_QUIT, 0, 0);
WaitForSingleObject(hThread,-1);
CloseHandle(hThread);
}
return 0;
}
python调用
用编译语言写查找元素的工具比较合适,但用来执行操作,就显得过于麻烦了,用python这类脚本语言实现自动化流程更加合适。
python调用jab,也有现成的解决方案,可以参考pyjab这个库,也是在github上开源的。可以像操作selenium一样操作Java窗口。
如果想自己封装,那就要用到ctypes,加载WindowsAccessBridge-64.dll
,还需要编写相关的结构体(这部分也可以从pyjab的代码里copy)
下面是我自己写的封装,消息循环的实现借鉴了pyjab,其他就纯手打了,累了个半死。希望对你有帮助:
# -*- coding: utf-8 -*-
import ctypes
import ctypes.wintypes
import win32event
import pythoncom
from collections import deque
from functools import wraps
ChangeWindowMessageFilter = ctypes.windll.user32.ChangeWindowMessageFilter
GetMessageW = ctypes.windll.user32.GetMessageW
TranslateMessage = ctypes.windll.user32.TranslateMessage
DispatchMessageW = ctypes.windll.user32.DispatchMessageW
PostThreadMessageW = ctypes.windll.user32.PostThreadMessageW
FindWindowW = ctypes.windll.user32.FindWindowW
FreeLibrary = ctypes.windll.kernel32.FreeLibrary
MAX_STRING_SIZE = 1024
SHORT_STRING_SIZE = 256
MAX_BUFFER_SIZE = 10240
MAX_RELATION_TARGETS = 25
MAX_RELATIONS = 5
MAX_HYPERLINKS = 64
MAX_ICON_INFO = 8
MAX_ACTIONS_TO_DO = 32
MAX_KEY_BINDINGS = 10
MAX_ACTION_INFO = 256
long = ctypes.c_long
jlong = ctypes.c_longlong
jint = long
jchar = ctypes.c_ushort
jboolean = ctypes.c_ubyte
jfloat = ctypes.c_float
JOBJECT64 = jlong
ABHWND64 = ctypes.c_long
AccessibleContext = JOBJECT64
AccessibleText = JOBJECT64
AccessibleValue = JOBJECT64
AccessibleSelection = JOBJECT64
PropertyChangeEvent = JOBJECT64
FocusEvent = JOBJECT64
CaretEvent = JOBJECT64
MouseEvent = JOBJECT64
MenuEvent = JOBJECT64
AccessibleTable = JOBJECT64
AccessibleHyperlink = JOBJECT64
AccessibleHypertext = JOBJECT64
Java_Object = JOBJECT64
BOOL = ctypes.wintypes.BOOL
c_void_p = ctypes.c_void_p
HWND = ctypes.wintypes.HWND
POINTER = ctypes.POINTER
AccessBridge_JavaShutdownFP = ctypes.CFUNCTYPE(None,
ctypes.c_long)
AccessBridge_FocusGainedFP = ctypes.CFUNCTYPE(None,
ctypes.c_long,
JOBJECT64,
JOBJECT64)
AccessBridge_FocusLostFP = ctypes.CFUNCTYPE(None,
ctypes.c_long,
JOBJECT64,
JOBJECT64)
AccessBridge_CaretUpdateFP = ctypes.CFUNCTYPE(None,
ctypes.c_long,
JOBJECT64,
JOBJECT64)
AccessBridge_MouseClickedFP = ctypes.CFUNCTYPE(None,
ctypes.c_long,
JOBJECT64,
JOBJECT64)
AccessBridge_MouseEnteredFP = ctypes.CFUNCTYPE(None,
ctypes.c_long,
JOBJECT64,
JOBJECT64)
AccessBridge_MouseExitedFP = ctypes.CFUNCTYPE(None,
ctypes.c_long,
JOBJECT64,
JOBJECT64)
AccessBridge_MousePressedFP = ctypes.CFUNCTYPE(None,
ctypes.c_long,
JOBJECT64,
JOBJECT64)
AccessBridge_MouseReleasedFP = ctypes.CFUNCTYPE(None,
ctypes.c_long,
JOBJECT64,
JOBJECT64)
AccessBridge_MenuCanceledFP = ctypes.CFUNCTYPE(None,
ctypes.c_long,
JOBJECT64,
JOBJECT64)
AccessBridge_MenuDeselectedFP = ctypes.CFUNCTYPE(None,
ctypes.c_long,
JOBJECT64,
JOBJECT64)
AccessBridge_MenuSelectedFP = ctypes.CFUNCTYPE(None,
ctypes.c_long,
JOBJECT64,
JOBJECT64)
AccessBridge_PopupMenuCanceledFP = ctypes.CFUNCTYPE(None,
ctypes.c_long,
JOBJECT64,
JOBJECT64)
AccessBridge_PopupMenuWillBecomeInvisibleFP = ctypes.CFUNCTYPE(None,
ctypes.c_long,
JOBJECT64,
JOBJECT64)
AccessBridge_PopupMenuWillBecomeVisibleFP = ctypes.CFUNCTYPE(None,
ctypes.c_long,
JOBJECT64,
JOBJECT64)
AccessBridge_PropertyNameChangeFP = ctypes.CFUNCTYPE(None,
ctypes.c_long,
JOBJECT64,
JOBJECT64,
ctypes.c_wchar_p,
ctypes.c_wchar_p)
AccessBridge_PropertyDescriptionChangeFP = ctypes.CFUNCTYPE(None,
ctypes.c_long,
JOBJECT64,
JOBJECT64,
ctypes.c_wchar_p,
ctypes.c_wchar_p)
AccessBridge_PropertyStateChangeFP = ctypes.CFUNCTYPE(None,
ctypes.c_long,
JOBJECT64,
JOBJECT64,
ctypes.c_wchar_p,
ctypes.c_wchar_p)
AccessBridge_PropertyValueChangeFP = ctypes.CFUNCTYPE(None,
ctypes.c_long,
JOBJECT64,
JOBJECT64,
ctypes.c_wchar_p,
ctypes.c_wchar_p)
AccessBridge_PropertySelectionChangeFP = ctypes.CFUNCTYPE(None,
ctypes.c_long,
JOBJECT64,
JOBJECT64,
ctypes.c_wchar_p,
ctypes.c_wchar_p)
AccessBridge_PropertyTextChangeFP = ctypes.CFUNCTYPE(None,
ctypes.c_long,
JOBJECT64,
JOBJECT64,
ctypes.c_wchar_p,
ctypes.c_wchar_p)
AccessBridge_PropertyCaretChangeFP = ctypes.CFUNCTYPE(None,
ctypes.c_long,
JOBJECT64,
JOBJECT64,
ctypes.c_wchar_p,
ctypes.c_wchar_p)
AccessBridge_PropertyVisibleDataChangeFP = ctypes.CFUNCTYPE(None,
ctypes.c_long,
JOBJECT64,
JOBJECT64,
ctypes.c_wchar_p,
ctypes.c_wchar_p)
AccessBridge_PropertyChildChangeFP = ctypes.CFUNCTYPE(None,
ctypes.c_long,
JOBJECT64,
JOBJECT64,
ctypes.c_wchar_p,
ctypes.c_wchar_p)
AccessBridge_PropertyActiveDescendentChangeFP = ctypes.CFUNCTYPE(None,
ctypes.c_long,
JOBJECT64,
JOBJECT64,
ctypes.c_wchar_p,
ctypes.c_wchar_p)
AccessBridge_PropertyTableModelChangeFP = ctypes.CFUNCTYPE(None,
ctypes.c_long,
JOBJECT64,
JOBJECT64,
ctypes.c_wchar_p,
ctypes.c_wchar_p)
class AccessBridgeVersionInfo(ctypes.Structure):
_fields_=[
('VMVersion',ctypes.c_wchar * SHORT_STRING_SIZE),
('bridgeJavaClassVersion',ctypes.c_wchar * SHORT_STRING_SIZE),
('bridgeJavaDLLVersion',ctypes.c_wchar * SHORT_STRING_SIZE),
('bridgeWinDLLVersion',ctypes.c_wchar * SHORT_STRING_SIZE)
]
class AccessibleContextInfo(ctypes.Structure):
_fields_ = [
('name',ctypes.c_wchar * MAX_STRING_SIZE),
('description',ctypes.c_wchar * MAX_STRING_SIZE),
('role',ctypes.c_wchar * SHORT_STRING_SIZE),
('role_en_US',ctypes.c_wchar * SHORT_STRING_SIZE),
('states',ctypes.c_wchar * SHORT_STRING_SIZE),
('states_en_US',ctypes.c_wchar * SHORT_STRING_SIZE),
('indexInParent',jint),
('childrenCount',jint),
('x',jint),
('y',jint),
('width',jint),
('height',jint),
('accessibleComponent',BOOL),
('accessibleAction',BOOL),
('accessibleSelection',BOOL),
('accessibleText',BOOL),
('accessibleInterfaces',BOOL)
]
class VisibleChildrenInfo(ctypes.Structure):
_fields_ = [
('returnedChildrenCount',ctypes.c_int),
('children',AccessibleContext * SHORT_STRING_SIZE)
]
class AccessibleTextInfo(ctypes.Structure):
_fields_=[
('charCount',jint),
('caretIndex',jint),
('indexAtPoint',jint)
]
class AccessibleTextItemsInfo(ctypes.Structure):
_fields_=[
('letter',ctypes.c_wchar),
('word',ctypes.c_wchar * SHORT_STRING_SIZE),
('sentence',ctypes.c_wchar * MAX_STRING_SIZE)
]
class AccessibleTextSelectionInfo(ctypes.Structure):
_fields_=[
('selectionStartIndex',jint),
('selectionEndIndex',jint),
('selectedText',ctypes.c_wchar * MAX_STRING_SIZE)
]
class AccessibleTextRectInfo(ctypes.Structure):
_fields_=[
('x',jint),
('y',jint),
('width',jint),
('height',jint)
]
class AccessibleTextAttributesInfo(ctypes.Structure):
_fields_=[
('bold',BOOL),
('italic',BOOL),
('underline',BOOL),
('strikethrough',BOOL),
('superscript',BOOL),
('subscript',BOOL),
('backgroundColor',ctypes.c_wchar * SHORT_STRING_SIZE),
('foregroundColor',ctypes.c_wchar * SHORT_STRING_SIZE),
('fontFamily',ctypes.c_wchar * SHORT_STRING_SIZE),
('fontSize',jint),
('alignment',jint),
('bidiLevel',jint),
('firstLineIndent',jfloat),
('LeftIndent',jfloat),
('rightIndent',jfloat),
('lineSpacing',jfloat),
('spaceAbove',jfloat),
('spaceBelow',jfloat),
('fullAttributesString',ctypes.c_wchar * MAX_STRING_SIZE)
]
class AccessibleRelationInfo(ctypes.Structure):
_fields_ = [
("key", ctypes.c_wchar * SHORT_STRING_SIZE),
("targetCount", jint),
("targets", JOBJECT64 * MAX_RELATION_TARGETS)
]
class AccessibleRelationSetInfo(ctypes.Structure):
_fields_ = [
("relationCount", jint),
("relations", AccessibleRelationInfo * MAX_RELATIONS)
]
class AccessibleTableInfo(ctypes.Structure):
_fields_ = [
('caption',JOBJECT64),
('summary',JOBJECT64),
('rowCount',jint),
('columnCount',jint),
('accessibleContext',JOBJECT64),
('accessibleTable',JOBJECT64)
]
class AccessibleTableCellInfo(ctypes.Structure):
_fields_ = [
('accessibleContext',JOBJECT64),
('index',jint),
('row',jint),
('column',jint),
('rowExtent',jint),
('columnExtent',jint),
('isSelected',jboolean)
]
class AccessibleHyperlinkInfo(ctypes.Structure):
_fields_ = [
('text',ctypes.c_wchar * SHORT_STRING_SIZE),
('startIndex',jint),
('endIndex',jint),
('accessibleHyperlink',JOBJECT64),
]
class AccessibleHypertextInfo(ctypes.Structure):
_fields_ = [
('linkCount',jint),
('links',AccessibleHyperlinkInfo * MAX_HYPERLINKS),
('accessibleHypertext',JOBJECT64)
]
class AccessibleKeyBindingInfo(ctypes.Structure):
_fields_ = [
('character',jchar),
('modifiers',jint)
]
class AccessibleKeyBindings(ctypes.Structure):
_fields_ = [
('keyBindingsCount',jint),
('keyBindingInfo',AccessibleKeyBindingInfo * MAX_KEY_BINDINGS)
]
class AccessibleIconInfo(ctypes.Structure):
_fields_ = [
('description',ctypes.c_wchar * SHORT_STRING_SIZE),
('height',jint),
('width',jint)
]
class AccessibleIcons(ctypes.Structure):
_fields_ = [
('iconsCount',jint),
('iconInfo',AccessibleIconInfo * MAX_ICON_INFO)
]
class AccessibleActionInfo(ctypes.Structure):
_fields_ = [
('name',ctypes.c_wchar * SHORT_STRING_SIZE)
]
class AccessibleActions(ctypes.Structure):
_fields_ = [
('actionsCount',jint),
('actionInfo',AccessibleActionInfo * MAX_ACTION_INFO)
]
class AccessibleActionsToDo(ctypes.Structure):
_fields_ = [
('actionsCount',jint),
('actions',AccessibleActionInfo * MAX_ACTIONS_TO_DO)
]
def singleton(cls):
instances = {}
@wraps(cls)
def wrapper(*args, **kwargs):
if cls not in instances:
instances[cls] = cls(*args, **kwargs)
return instances[cls]
return wrapper
def GetModuleFileName(handle):
filepath = ctypes.create_unicode_buffer(260)
ctypes.windll.kernel32.GetModuleFileNameW(ctypes.wintypes.HMODULE(handle),
filepath,
260)
return filepath.value
@singleton
class JABUtils():
stop_event = win32event.CreateEvent(None, 0, 0, None)
other_event = win32event.CreateEvent(None, 0, 0, None)
def setup_msg_pump(self):
waitables = self.stop_event, self.other_event
while True:
rc = win32event.MsgWaitForMultipleObjects(
waitables,
0,
200,
win32event.QS_ALLEVENTS,
)
if rc == win32event.WAIT_OBJECT_0:
break
elif rc == win32event.WAIT_OBJECT_0 + 1:
pass
elif rc == win32event.WAIT_OBJECT_0 + len(waitables):
if pythoncom.PumpWaitingMessages():
break
elif rc == win32event.WAIT_TIMEOUT:
pass
else:
raise RuntimeError("unexpected win32wait return value")
try:
yield
finally:
win32event.SetEvent(self.stop_event)
@singleton
class ActorScheduler:
def __init__(self):
self.actors = {}
self.msg_queue = deque()
def new_actor(self, name, actor):
self.msg_queue.append((actor, None))
self.actors[name] = actor
def send(self, name, msg):
actor = self.actors.get(name)
if actor is not None:
self.msg_queue.append((actor, msg))
def run(self):
while self.msg_queue:
actor, msg = self.msg_queue.popleft()
try:
actor.send(msg)
except StopIteration:
pass
class JABFixedFunc(object):
def __init__(self, bridge) -> None:
self.bridge = bridge
@staticmethod
def _check_error(result, func, args):
if not result:
raise RuntimeError(f"Result {result}")
return result
def _fix_bridge_function(self, restype, name, *argtypes, **kwargs):
try:
func = getattr(self.bridge, name)
except AttributeError:
self.log.error(
f"{name} not found in Java Access Bridge DLL"
)
return
func.restype = restype
func.argtypes = argtypes
if kwargs.get("errorcheck"):
func.errorcheck = self._check_error
def _fix_bridge_functions(self):
"""Appropriately set the return and argument types of all the access bridge dll functions"""
self._fix_bridge_function(None, "Windows_run")
self._fix_bridge_function(None, "setFocusGainedFP", c_void_p)
self._fix_bridge_function(None, "setPropertyNameChangeFP", c_void_p)
self._fix_bridge_function(None, "setPropertyDescriptionChangeFP", c_void_p)
self._fix_bridge_function(None, "setPropertyValueChangeFP", c_void_p)
self._fix_bridge_function(None, "setPropertyStateChangeFP", c_void_p)
self._fix_bridge_function(None, "setPropertyCaretChangeFP", c_void_p)
self._fix_bridge_function(None, "setPropertyActiveDescendentChangeFP", c_void_p)
self._fix_bridge_function(None, "releaseJavaObject", long, JOBJECT64)
self._fix_bridge_function(
BOOL,
"getVersionInfo",
long,
ctypes.POINTER(AccessBridgeVersionInfo),
errorcheck=True,
)
self._fix_bridge_function(BOOL, "isJavaWindow", HWND)
self._fix_bridge_function(BOOL, "isSameObject", long, JOBJECT64, JOBJECT64)
self._fix_bridge_function(
BOOL,
"getAccessibleContextFromHWND",
HWND,
POINTER(long),
POINTER(JOBJECT64),
errorcheck=True,
)
self._fix_bridge_function(
HWND, "getHWNDFromAccessibleContext", long, JOBJECT64, errorcheck=True
)
self._fix_bridge_function(
BOOL,
"getAccessibleContextAt",
long,
JOBJECT64,
jint,
jint,
POINTER(JOBJECT64),
errorcheck=True,
)
self._fix_bridge_function(
BOOL,
"getAccessibleContextWithFocus",
HWND,
POINTER(long),
POINTER(JOBJECT64),
errorcheck=True,
)
self._fix_bridge_function(
BOOL,
"getAccessibleContextInfo",
long,
JOBJECT64,
POINTER(AccessibleContextInfo),
errorcheck=True,
)
self._fix_bridge_function(
JOBJECT64,
"getAccessibleChildFromContext",
long,
JOBJECT64,
jint,
errorcheck=True,
)
self._fix_bridge_function(
JOBJECT64, "getAccessibleParentFromContext", long, JOBJECT64
)
self._fix_bridge_function(
JOBJECT64, "getParentWithRole", long, JOBJECT64, POINTER(ctypes.c_wchar)
)
self._fix_bridge_function(
BOOL,
"getAccessibleRelationSet",
long,
JOBJECT64,
POINTER(AccessibleRelationSetInfo),
errorcheck=True,
)
self._fix_bridge_function(
BOOL,
"getAccessibleTextInfo",
long,
JOBJECT64,
POINTER(AccessibleTextInfo),
jint,
jint,
errorcheck=True,
)
self._fix_bridge_function(
BOOL,
"getAccessibleTextItems",
long,
JOBJECT64,
POINTER(AccessibleTextItemsInfo),
jint,
errorcheck=True,
)
self._fix_bridge_function(
BOOL,
"getAccessibleTextSelectionInfo",
long,
JOBJECT64,
POINTER(AccessibleTextSelectionInfo),
errorcheck=True,
)
self._fix_bridge_function(
BOOL,
"getAccessibleTextAttributes",
long,
JOBJECT64,
jint,
POINTER(AccessibleTextAttributesInfo),
errorcheck=True,
)
self._fix_bridge_function(
BOOL,
"getAccessibleTextRect",
long,
JOBJECT64,
POINTER(AccessibleTextRectInfo),
jint,
errorcheck=True,
)
self._fix_bridge_function(
BOOL,
"getAccessibleTextLineBounds",
long,
JOBJECT64,
jint,
POINTER(jint),
POINTER(jint),
errorcheck=True,
)
self._fix_bridge_function(
BOOL,
"getAccessibleTextRange",
long,
JOBJECT64,
jint,
jint,
POINTER(ctypes.c_wchar),
ctypes.c_short,
errorcheck=True,
)
self._fix_bridge_function(
BOOL,
"getCurrentAccessibleValueFromContext",
long,
JOBJECT64,
POINTER(ctypes.c_wchar),
ctypes.c_short,
errorcheck=True,
)
self._fix_bridge_function(
BOOL, "selectTextRange", long, JOBJECT64, jint, jint, errorcheck=True
)
self._fix_bridge_function(
BOOL,
"getTextAttributesInRange",
long,
JOBJECT64,
jint,
jint,
POINTER(AccessibleTextAttributesInfo),
POINTER(ctypes.c_short),
errorcheck=True,
)
self._fix_bridge_function(
JOBJECT64, "getTopLevelObject", long, JOBJECT64, errorcheck=True
)
self._fix_bridge_function(jint, "getObjectDepth", long, JOBJECT64)
self._fix_bridge_function(JOBJECT64, "getActiveDescendent", long, JOBJECT64)
self._fix_bridge_function(
BOOL, "requestFocus", long, JOBJECT64, errorcheck=True
)
self._fix_bridge_function(
BOOL, "setCaretPosition", long, JOBJECT64, jint, errorcheck=True
)
self._fix_bridge_function(
BOOL,
"getCaretLocation",
long,
JOBJECT64,
POINTER(AccessibleTextRectInfo),
jint,
errorcheck=True,
)
self._fix_bridge_function(
BOOL,
"getAccessibleActions",
long,
JOBJECT64,
POINTER(AccessibleActions),
errorcheck=True,
)
self._fix_bridge_function(
BOOL,
"doAccessibleActions",
long,
JOBJECT64,
POINTER(AccessibleActionsToDo),
POINTER(jint),
errorcheck=True,
)
self._fix_bridge_function(
BOOL,
"getAccessibleTableInfo",
long,
JOBJECT64,
POINTER(AccessibleTableInfo),
)
self._fix_bridge_function(
BOOL,
"getAccessibleTableCellInfo",
long,
JOBJECT64,
jint,
jint,
POINTER(AccessibleTableCellInfo),
errorcheck=True,
)
self._fix_bridge_function(
BOOL,
"getAccessibleTableRowHeader",
long,
JOBJECT64,
POINTER(AccessibleTableInfo),
)
self._fix_bridge_function(
BOOL,
"getAccessibleTableColumnHeader",
long,
JOBJECT64,
POINTER(AccessibleTableInfo),
)
self._fix_bridge_function(
JOBJECT64, "getAccessibleTableRowDescription", long, JOBJECT64, jint
)
self._fix_bridge_function(
JOBJECT64, "getAccessibleTableColumnDescription", long, JOBJECT64, jint
)
self._fix_bridge_function(
jint, "getAccessibleTableRow", long, JOBJECT64, jint
)
self._fix_bridge_function(
jint, "getAccessibleTableColumn", long, JOBJECT64, jint
)
self._fix_bridge_function(
jint, "getAccessibleTableIndex", long, JOBJECT64, jint, jint
)
self._fix_bridge_function(
BOOL,
"getAccessibleKeyBindings",
long,
JOBJECT64,
POINTER(AccessibleKeyBindings),
errorcheck=True,
)
self._fix_bridge_function(
BOOL,
"setTextContents",
long,
JOBJECT64,
POINTER(ctypes.c_wchar),
errorcheck=True,
)
self._fix_bridge_function(
None, "clearAccessibleSelectionFromContext", long, JOBJECT64
)
self._fix_bridge_function(
None, "addAccessibleSelectionFromContext", long, JOBJECT64, jint
)
self._fix_bridge_function(
JOBJECT64, "getAccessibleSelectionFromContext", long, JOBJECT64, jint
)
self._fix_bridge_function(
jint,
"getVisibleChildrenCount",
long,
JOBJECT64,
)
self._fix_bridge_function(
BOOL,
"getVisibleChildren",
long,
JOBJECT64,
jint,
POINTER(VisibleChildrenInfo),
errorcheck=True,
)
@singleton
class AccessBridge():
def __init__(self):
self.module = None
self.fixed_func = None
self.jabUtils = JABUtils()
self.initializeAccessBridge()
def run_actor_sched(self):
sched = ActorScheduler()
sched.new_actor('海豚E工', self.jabUtils.setup_msg_pump())
sched.run()
def fix_jab(self):
if self.module is None:
return
self.fixed_func = JABFixedFunc(self.module)
self.fixed_func._fix_bridge_functions()
error_code_offset = 0x00007FF892C571C5 - 0x00007FF892C50000
# Modify `movsxd rdi,r9d` to `mov rdi,r9`
fix_asm_code = (ctypes.c_ubyte * 3)(0x49,0x8B,0xF9)
dwFixAddr = self.module._handle + error_code_offset
OldProtext = ctypes.wintypes.DWORD(0)
ctypes.windll.kernel32.VirtualProtect(ctypes.c_void_p(dwFixAddr),
3,
0x40,
ctypes.byref(OldProtext))
ctypes.cdll.msvcrt.memcpy(ctypes.c_void_p(dwFixAddr),
ctypes.byref(fix_asm_code),
3)
ctypes.windll.kernel32.VirtualProtect(ctypes.c_void_p(dwFixAddr),
3,
OldProtext,
ctypes.byref(OldProtext))
def initializeAccessBridge(self):
if self.module is not None:
self.shutdownAccessBridge()
self.module = ctypes.cdll.LoadLibrary('WindowsAccessBridge-64')
self.fix_jab()
self.Windows_run()
self.run_actor_sched()
return True
def Windows_run(self):
return self.module.Windows_run()
def SetJavaShutdown(self,fp: 'AccessBridge_JavaShutdownFP') -> None:
self.module.setJavaShutdownFP(fp)
def SetFocusGained(self,fp: 'AccessBridge_FocusGainedFP') -> None:
self.module.setFocusGainedFP(fp)
def SetFocusLost(self,fp: 'AccessBridge_FocusLostFP') -> None:
self.module.setFocusLostFP(fp)
def SetCaretUpdate(self,fp: 'AccessBridge_CaretUpdateFP') -> None:
self.module.setCaretUpdateFP(fp)
def SetMouseClicked(self,fp: 'AccessBridge_MouseClickedFP') -> None:
self.module.setMouseClickedFP(fp)
def SetMouseEntered(self,fp: 'AccessBridge_MouseEnteredFP') -> None:
self.module.setMouseEnteredFP(fp)
def SetMouseExited(self,fp: 'AccessBridge_MouseExitedFP') -> None:
self.module.setMouseExitedFP(fp)
def SetMousePressed(self,fp: 'AccessBridge_MousePressedFP') -> None:
self.module.setMousePressedFP(fp)
def SetMouseReleased(self,fp: 'AccessBridge_MouseReleasedFP') -> None:
self.module.setMouseReleasedFP(fp)
def SetMenuCanceled(self,fp: 'AccessBridge_MenuCanceledFP') -> None:
self.module.setMenuCanceledFP(fp)
def SetMenuDeselected(self,fp: 'AccessBridge_MenuDeselectedFP') -> None:
self.module.setMenuDeselectedFP(fp)
def SetMenuSelected(self,fp: 'AccessBridge_MenuSelectedFP') -> None:
self.module.setMenuSelectedFP(fp)
def SetPopupMenuCanceled(self,fp: 'AccessBridge_PopupMenuCanceledFP') -> None:
self.module.setPopupMenuCanceledFP(fp)
def SetPopupMenuWillBecomeInvisible(self,fp: 'AccessBridge_PopupMenuWillBecomeInvisibleFP') -> None:
self.module.setPopupMenuWillBecomeInvisibleFP(fp)
def SetPopupMenuWillBecomeVisible(self,fp: 'AccessBridge_PopupMenuWillBecomeVisibleFP') -> None:
self.module.setPopupMenuWillBecomeVisibleFP(fp)
def SetPropertyNameChange(self,fp: 'AccessBridge_PropertyNameChangeFP') -> None:
self.module.setPropertyNameChangeFP(fp)
def SetPropertyDescriptionChange(self,fp: 'AccessBridge_PropertyDescriptionChangeFP') -> None:
self.module.setPropertyDescriptionChangeFP(fp)
def SetPropertyStateChange(self,fp: 'AccessBridge_PropertyStateChangeFP') -> None:
self.module.setPropertyStateChangeFP(fp)
def SetPropertyValueChange(self,fp: 'AccessBridge_PropertyValueChangeFP') -> None:
self.module.setPropertyValueChangeFP(fp)
def SetPropertySelectionChange(self,fp: 'AccessBridge_PropertySelectionChangeFP') -> None:
self.module.setPropertySelectionChangeFP(fp)
def SetPropertyTextChange(self,fp: 'AccessBridge_PropertyTextChangeFP') -> None:
self.module.setPropertyTextChangeFP(fp)
def SetPropertyCaretChange(self,fp: 'AccessBridge_PropertyCaretChangeFP') -> None:
self.module.setPropertyCaretChangeFP(fp)
def SetPropertyVisibleDataChange(self,fp: 'AccessBridge_PropertyVisibleDataChangeFP') -> None:
self.module.setPropertyVisibleDataChangeFP(fp)
def SetPropertyChildChange(self,fp: 'AccessBridge_PropertyChildChangeFP') -> None:
self.module.setPropertyChildChangeFP(fp)
def SetPropertyActiveDescendentChange(self,fp: 'AccessBridge_PropertyActiveDescendentChangeFP') -> None:
self.module.setPropertyActiveDescendentChangeFP(fp)
def SetPropertyTableModelChange(self,fp: 'AccessBridge_PropertyTableModelChangeFP') -> None:
self.module.setPropertyTableModelChangeFP(fp)
def ReleaseJavaObject(self,vmID,jobject):
self.module.releaseJavaObject(long(vmID),
Java_Object(jobject))
def GetVersionInfo(self,vmID):
info = AccessBridgeVersionInfo(0)
status = self.module.getVersionInfo(long(vmID),
ctypes.byref(info))
return status,info
def IsJavaWindow(self,window):
return self.module.isJavaWindow(HWND(window))
def IsSameObject(self,vmID,obj1,obj2):
return self.module.isSameObject(long(vmID),
JOBJECT64(obj1),
JOBJECT64(obj2))
def GetAccessibleContextFromHWND(self,target):
vmID = long(0)
ac = AccessibleContext(0)
status = self.module.getAccessibleContextFromHWND(HWND(target),
ctypes.byref(vmID),
ctypes.byref(ac))
return status,vmID.value,ac.value
def getHWNDFromAccessibleContext(self,vmID,ac):
return self.module.getHWNDFromAccessibleContext(long(vmID),
AccessibleContext(ac))
def GetAccessibleContextAt(self,vmID,acParent,x,y):
ac = AccessibleContext(0)
status = self.module.getAccessibleContextAt(long(vmID),
AccessibleContext(acParent),
jint(x),
jint(y),
ctypes.byref(ac))
return status,ac.value
def GetAccessibleContextWithFocus(self,window):
vmID = long(0)
ac = AccessibleContext(0)
status = self.module.getAccessibleContextWithFocus(HWND(window),
ctypes.byref(vmID),
ctypes.byref(ac))
return status,vmID.value,ac.value
def GetAccessibleContextInfo(self,vmID,ac):
info = AccessibleContextInfo()
status = self.module.getAccessibleContextInfo(long(vmID),
AccessibleContext(ac),
ctypes.byref(info))
return status,info
def GetAccessibleChildFromContext(self,vmID,ac,index):
return self.module.getAccessibleChildFromContext(long(vmID),
AccessibleContext(ac),
jint(index))
def GetAccessibleParentFromContext(self,vmID,ac):
return self.module.getAccessibleParentFromContext(long(vmID),
AccessibleContext(ac))
def getAccessibleTableInfo(self,vmID,ac):
tableinfo = AccessibleTableInfo()
status = self.module.getAccessibleTableInfo(long(vmID),
AccessibleContext(ac),
ctypes.byref(tableinfo))
return status,tableinfo
def getAccessibleTableCellInfo(self,vmID,accessibleTable,row,column):
tableCellInfo = AccessibleTableCellInfo()
status = self.module.getAccessibleTableCellInfo(long(vmID),
AccessibleTable(accessibleTable),
jint(row),
jint(column),
ctypes.byref(tableCellInfo))
return status,tableCellInfo
def getAccessibleTableRowHeader(self,vmID,acParent):
tableinfo = AccessibleTableInfo()
status = self.module.getAccessibleTableRowHeader(long(vmID),
AccessibleContext(acParent),
ctypes.byref(tableinfo))
return status,tableinfo
def getAccessibleTableColumnHeader(self,vmID,acParent):
tableinfo = AccessibleTableInfo()
status = self.module.getAccessibleTableColumnHeader(long(vmID),
AccessibleContext(acParent),
ctypes.byref(tableinfo))
return status,tableinfo
def getAccessibleTableRowDescription(self,vmID,acParent,row):
return self.module.module.getAccessibleTableRowDescription(long(vmID),
AccessibleContext(acParent),
jint(row))
def getAccessibleTableColumnDescription(self,vmID,acParent,column):
return self.module.getAccessibleTableColumnDescription(long(vmID),
AccessibleContext(acParent),
jint(column))
def getAccessibleTableRowSelectionCount(self,vmID,table):
return self.module.getAccessibleTableRowSelectionCount(long(vmID),
AccessibleTable(table))
def isAccessibleTableRowSelected(self,vmID,table,row):
return self.module.isAccessibleTableRowSelected(long(vmID),
AccessibleTable(table),
jint(row))
def getAccessibleTableRowSelections(self,vmID,table,count):
selections = (jint * count)(0)
status = self.module.getAccessibleTableRowSelections(long(vmID),
AccessibleTable(table),
jint(count),
ctypes.byref(selections))
return status,list(selections)
def getAccessibleTableColumnSelectionCount(self,vmID,table):
return self.module.getAccessibleTableColumnSelectionCount(long(vmID),
AccessibleTable(table))
def isAccessibleTableColumnSelected(self,vmID,table,column):
return self.module.isAccessibleTableColumnSelected(long(vmID),
AccessibleTable(table),
jint(column))
def getAccessibleTableColumnSelections(self,vmID,table,count):
selections = (jint * count)(0)
status = self.module.getAccessibleTableColumnSelections(long(vmID),
AccessibleTable(table),
jint(count),
ctypes.byref(selections))
return status,list(selections)
def getAccessibleTableRow(self,vmID,table,index):
return self.module.getAccessibleTableRow(long(vmID),
AccessibleTable(table),
jint(index))
def getAccessibleTableColumn(self,vmID,table,index):
return self.module.getAccessibleTableColumn(long(vmID),
AccessibleTable(table),
jint(index))
def getAccessibleTableIndex(self,vmID,table,row,column):
return self.module.getAccessibleTableIndex(long(vmID),
AccessibleTable(table),
jint(row),
jint(column))
def getAccessibleRelationSet(self,vmID,accessibleContext):
relaitionSetInfo = AccessibleRelationSetInfo()
status = self.module.getAccessibleRelationSet(long(vmID),
AccessibleContext(accessibleContext),
ctypes.byref(relaitionSetInfo))
return status,relaitionSetInfo
def getAccessibleHypertext(self,vmID,accessibleContext):
hypertextInfo = AccessibleHypertextInfo()
status = self.module.getAccessibleHypertext(long(vmID),
AccessibleContext(accessibleContext),
ctypes.byref(hypertextInfo))
return status,hypertextInfo
def activateAccessibleHyperlink(self,vmID,accessibleContext,accessibleHyperlink):
return self.module.activateAccessibleHyperlink(long(vmID),
AccessibleContext(accessibleContext),
AccessibleHyperlink(accessibleHyperlink))
def getAccessibleHyperlinkCount(self,vmID,hypertext):
return self.module.getAccessibleHyperlinkCount(long(vmID),
AccessibleHypertext(hypertext))
def getAccessibleHypertextExt(self,vmID,accessibleContext,nStartIndex):
hypertextInfo = AccessibleHypertextInfo()
status = self.module.getAccessibleHypertextExt(long(vmID),
AccessibleContext(accessibleContext),
jint(nStartIndex),
ctypes.byref(hypertextInfo))
return status,hypertextInfo
def getAccessibleHypertextLinkIndex(self,vmID,hypertext,nIndex):
return self.module.getAccessibleHypertextLinkIndex(long(vmID),
AccessibleHypertext(hypertext),
jint(nIndex))
def getAccessibleHyperlink(self,vmID,hypertext,nIndex):
hyperlinkInfo = AccessibleHyperlinkInfo()
status = self.module.getAccessibleHyperlink(long(vmID),
AccessibleHypertext(hypertext),
jint(nIndex),
ctypes.byref(hyperlinkInfo))
return status,hyperlinkInfo
def getAccessibleKeyBindings(self,vmID,accessibleContext):
keyBindings = AccessibleKeyBindings()
status = self.module.getAccessibleKeyBindings(long(vmID),
AccessibleContext(accessibleContext),
ctypes.byref(keyBindings))
return status,keyBindings
def getAccessibleIcons(self,vmID,accessibleContext):
icons = AccessibleIcons()
status = self.module.getAccessibleIcons(long(vmID),
AccessibleContext(accessibleContext),
ctypes.byref(icons))
return status,icons
def getAccessibleActions(self,vmID,accessibleContext):
actions = AccessibleActions()
status = self.module.getAccessibleActions(long(vmID),
AccessibleContext(accessibleContext),
ctypes.byref(actions))
return status,actions
def doAccessibleActions(self,vmID,accessibleContext,actionsToDo: 'AccessibleActionsToDo'):
failure = jint(0)
status = self.module.doAccessibleActions(long(vmID),
AccessibleContext(accessibleContext),
ctypes.byref(actionsToDo),
ctypes.byref(failure))
return status,failure.value
def GetAccessibleTextInfo(self,vmID, at,x, y):
textInfo = AccessibleTextInfo()
status = self.module.getAccessibleTextInfo(long(vmID),
AccessibleText(at),
ctypes.byref(textInfo),
jint(x),
jint(y))
return status,textInfo
def GetAccessibleTextItems(self,vmID,at,index):
textItems = AccessibleTextItemsInfo()
status = self.module.getAccessibleTextItems(long(vmID),
AccessibleText(at),
ctypes.byref(textItems),
jint(index))
return status,textItems
def GetAccessibleTextSelectionInfo(self,vmID,at):
textSelection = AccessibleTextSelectionInfo()
status = self.module.getAccessibleTextSelectionInfo(long(vmID),
AccessibleText(at),
ctypes.byref(textSelection))
return status,textSelection
def GetAccessibleTextAttributes(self,vmID, at,index):
attributes = AccessibleTextAttributesInfo()
status = self.module.getAccessibleTextAttributes(long(vmID),
AccessibleText(at),
jint(index),
ctypes.byref(attributes))
return status,attributes
def GetAccessibleTextRect(self,vmID, at,index):
rectInfo = AccessibleTextRectInfo()
status = self.module.getAccessibleTextRect(long(vmID),
AccessibleText(at),
ctypes.byref(rectInfo),
jint(index))
return status,rectInfo
def GetAccessibleTextLineBounds(self,vmID,at,index):
startIndex = jint(0)
endIndex = jint(0)
status = self.module.getAccessibleTextLineBounds(long(vmID),
AccessibleText(at),
jint(index),
ctypes.byref(startIndex),
ctypes.byref(endIndex))
return status,startIndex.value,endIndex.value
def GetAccessibleTextRange(self,vmID,at,start,end,s_len):
text = ctypes.create_unicode_buffer(s_len + 1)
status = self.module.getAccessibleTextRange(long(vmID),
AccessibleText(at),
jint(start),
jint(end),
text,
ctypes.c_short(s_len))
return status,text.value
def GetCurrentAccessibleValueFromContext(self,vmID,av,s_len):
value = ctypes.create_unicode_buffer(s_len + 1)
status = self.module.getCurrentAccessibleValueFromContext(long(vmID),
AccessibleValue(av),
value,
ctypes.c_short(s_len))
return status,value.value
def GetMaximumAccessibleValueFromContext(self,vmID,av,s_len):
value = ctypes.create_unicode_buffer(s_len + 1)
status = self.module.getMaximumAccessibleValueFromContext(long(vmID),
AccessibleValue(av),
value,
ctypes.c_short(s_len))
return status,value.value
def GetMinimumAccessibleValueFromContext(self,vmID,av,s_len):
value = ctypes.create_unicode_buffer(s_len + 1)
status = self.module.getMinimumAccessibleValueFromContext(long(vmID),
AccessibleValue(av),
value,
ctypes.c_short(s_len))
return status,value.value
def AddAccessibleSelectionFromContext(self,vmID,aS,i):
return self.module.addAccessibleSelectionFromContext(long(vmID),
AccessibleSelection(aS),
ctypes.c_int(i))
def ClearAccessibleSelectionFromContext(self,vmID,aS):
return self.module.clearAccessibleSelectionFromContext(long(vmID),
AccessibleSelection(aS))
def GetAccessibleSelectionFromContext(self,vmID,aS,i):
return self.module.getAccessibleSelectionFromContext(long(vmID),
AccessibleSelection(aS),
ctypes.c_int(i))
def GetAccessibleSelectionCountFromContext(self,vmID,aS):
return self.module.getAccessibleSelectionCountFromContext(long(vmID),
AccessibleSelection(aS))
def IsAccessibleChildSelectedFromContext(self,vmID,aS,i):
return self.module.isAccessibleChildSelectedFromContext(long(vmID),
AccessibleSelection(aS),
ctypes.c_int(i))
def RemoveAccessibleSelectionFromContext(self,vmID,aS,i):
return self.module.removeAccessibleSelectionFromContext(long(vmID),
AccessibleSelection(aS),
ctypes.c_int(i))
def SelectAllAccessibleSelectionFromContext(self,vmID,aS):
return self.module.selectAllAccessibleSelectionFromContext(long(vmID),
AccessibleSelection(aS))
def setTextContents(self,vmID,accessibleContext,text):
return self.module.setTextContents(long(vmID),
AccessibleContext(accessibleContext),
ctypes.c_wchar_p(text))
def getParentWithRole(self,vmID, accessibleContext,role):
return self.module.getParentWithRole(long(vmID),
AccessibleContext(accessibleContext),
ctypes.c_wchar_p(role))
def getTopLevelObject(self,vmID,accessibleContext):
return self.module.getTopLevelObject(long(vmID),
AccessibleContext(accessibleContext))
def getParentWithRoleElseRoot(self,vmID,accessibleContext,role):
return self.module.getParentWithRoleElseRoot(long(vmID),
AccessibleContext(accessibleContext),
ctypes.c_wchar_p(role))
def getObjectDepth(self,vmID,accessibleContext):
return self.module.getObjectDepth(long(vmID),
AccessibleContext(accessibleContext))
def getActiveDescendent(self,vmID,accessibleContext):
return self.module.getActiveDescendent(long(vmID),
AccessibleContext(accessibleContext))
def getVirtualAccessibleName(self,vmID,accessibleContext,i_len):
name = ctypes.create_unicode_buffer(i_len + 1)
status = self.module.getVirtualAccessibleName(long(vmID),
AccessibleContext(accessibleContext),
name,
ctypes.c_int(i_len))
return status,name.value
def requestFocus(self,vmID,accessibleContext):
return self.module.requestFocus(long(vmID),
AccessibleContext(accessibleContext))
def selectTextRange(self,vmID,accessibleContext,startIndex,endIndex):
return self.module.selectTextRange(long(vmID),
AccessibleContext(accessibleContext),
ctypes.c_int(startIndex),
ctypes.c_int(endIndex))
def getTextAttributesInRange(self,vmID,accessibleContext,startIndex,endIndex):
attributes = AccessibleTextAttributesInfo()
s_len = ctypes.c_short(0)
status = self.module.getTextAttributesInRange(long(vmID),
AccessibleContext(accessibleContext),
ctypes.c_int(startIndex),
ctypes.c_int(endIndex),
ctypes.byref(attributes),
ctypes.byref(s_len))
return status,attributes,s_len.value
def getVisibleChildrenCount(self,vmID,accessibleContext):
return self.module.getVisibleChildrenCount(long(vmID),
AccessibleContext(accessibleContext))
def getVisibleChildren(self,vmID,accessibleContext,startindex):
info = VisibleChildrenInfo()
status = self.module.getVisibleChildren(long(vmID),
AccessibleContext(accessibleContext),
ctypes.c_int(startindex),
ctypes.byref(info))
return status,info
def setCaretPosition(self,vmID,accessibleContext,position):
return self.module.setCaretPosition(long(vmID),
AccessibleContext(accessibleContext),
ctypes.c_int(position))
def getCaretLocation(self,vmID,ac,index):
rectInfo = AccessibleTextRectInfo()
status = self.module.getCaretLocation(long(vmID),
AccessibleContext(ac),
ctypes.byref(rectInfo),
jint(index))
return status,rectInfo
def getEventsWaiting(self):
return self.module.getEventsWaiting()
def shutdownAccessBridge(self):
if self.module:
FreeLibrary(ctypes.wintypes.HMODULE(self.module._handle))
self.module = None
def __del__(self):
self.shutdownAccessBridge()
写在后面
虽然WindowsAccessBridge中提供了很多接口,但用起来还是会有诸多问题,如果要十分精确的访问java元素,可能还是要用java编写jar包,然后注入到目标程序,实现事件监听。