#javaAccessBridgeHandler.py #A part of NonVisual Desktop Access (NVDA) #Copyright (C) 2006-2007 NVDA Contributors #This file is covered by the GNU General Public License. #See the file COPYING for more details. import Queue from ctypes import * from ctypes.wintypes import * import time import queueHandler import speech import globalVars from logHandler import log import winUser import api import eventHandler import controlTypes import NVDAObjects.JAB import core #Some utility functions to help with function defines def _errcheck(res, func, args): if not res: raise RuntimeError("Result %s" % res) return res def _fixBridgeFunc(restype,name,*argtypes,**kwargs): try: func=getattr(bridgeDll,name) except AttributeError: log.warning("%s not found in Java Access Bridge dll"%name) return func.restype=restype func.argtypes=argtypes if kwargs.get('errcheck'): func.errcheck=_errcheck #Load the first available access bridge dll legacyAccessBridge=True try: bridgeDll=getattr(cdll,'windowsAccessBridge-32') legacyAccessBridge=False except WindowsError: try: bridgeDll=cdll.windowsAccessBridge except WindowsError: bridgeDll=None #Definitions of access bridge types, structs and prototypes jchar=c_wchar jint=c_int jfloat=c_float jboolean=c_bool class JOBJECT64(c_int if legacyAccessBridge else c_int64): pass AccessibleTable=JOBJECT64 MAX_STRING_SIZE=1024 SHORT_STRING_SIZE=256 class AccessBridgeVersionInfo(Structure): _fields_=[ ('VMVersion',WCHAR*SHORT_STRING_SIZE), ('bridgeJavaClassVersion',WCHAR*SHORT_STRING_SIZE), ('bridgeJavaDLLVersion',WCHAR*SHORT_STRING_SIZE), ('bridgeWinDLLVersion',WCHAR*SHORT_STRING_SIZE), ] class AccessibleContextInfo(Structure): _fields_=[ ('name',WCHAR*MAX_STRING_SIZE), ('description',WCHAR*MAX_STRING_SIZE), ('role',WCHAR*SHORT_STRING_SIZE), ('role_en_US',WCHAR*SHORT_STRING_SIZE), ('states',WCHAR*SHORT_STRING_SIZE), ('states_en_US',WCHAR*SHORT_STRING_SIZE), ('indexInParent',jint), ('childrenCount',jint), ('x',jint), ('y',jint), ('width',jint), ('height',jint), ('accessibleComponent',BOOL), ('accessibleAction',BOOL), ('accessibleSelection',BOOL), ('accessibleText',BOOL), ('accessibleValue',BOOL), ] class AccessibleTextInfo(Structure): _fields_=[ ('charCount',jint), ('caretIndex',jint), ('indexAtPoint',jint), ] class AccessibleTextItemsInfo(Structure): _fields_=[ ('letter',WCHAR), ('word',WCHAR*SHORT_STRING_SIZE), ('sentence',WCHAR*MAX_STRING_SIZE), ] class AccessibleTextSelectionInfo(Structure): _fields_=[ ('selectionStartIndex',jint), ('selectionEndIndex',jint), ('selectedText',WCHAR*MAX_STRING_SIZE), ] class AccessibleTextRectInfo(Structure): _fields_=[ ('x',jint), ('y',jint), ('width',jint), ('height',jint), ] class AccessibleTextAttributesInfo(Structure): _fields_=[ ('bold',BOOL), ('italic',BOOL), ('underline',BOOL), ('strikethrough',BOOL), ('superscript',BOOL), ('subscript',BOOL), ('backgroundColor',WCHAR*SHORT_STRING_SIZE), ('foregroundColor',WCHAR*SHORT_STRING_SIZE), ('fontFamily',WCHAR*SHORT_STRING_SIZE), ('fontSize',jint), ('alignment',jint), ('bidiLevel',jint), ('firstLineIndent',jfloat), ('LeftIndent',jfloat), ('rightIndent',jfloat), ('lineSpacing',jfloat), ('spaceAbove',jfloat), ('spaceBelow',jfloat), ('fullAttributesString',WCHAR*MAX_STRING_SIZE), ] MAX_RELATION_TARGETS = 25 MAX_RELATIONS = 5 class AccessibleRelationInfo(Structure): _fields_ = [ ("key", WCHAR * SHORT_STRING_SIZE), ("targetCount", jint), ("targets", JOBJECT64 * MAX_RELATION_TARGETS), ] class AccessibleRelationSetInfo(Structure): _fields_ = [ ("relationCount", jint), ("relations", AccessibleRelationInfo * MAX_RELATIONS), ] MAX_ACTION_INFO = 256 MAX_ACTIONS_TO_DO = 32 class AccessibleActionInfo(Structure): _fields_ = ( ("name", c_wchar * SHORT_STRING_SIZE), ) class AccessibleActions(Structure): _fields_ = ( ("actionsCount", jint), ("actionInfo", AccessibleActionInfo * MAX_ACTION_INFO), ) class AccessibleActionsToDo(Structure): _fields_ = ( ("actionsCount", jint), ("actions", AccessibleActionInfo * MAX_ACTIONS_TO_DO), ) class AccessibleTableInfo(Structure): _fields_=[ ('caption',JOBJECT64), ('summary',JOBJECT64), ('rowCount',jint), ('columnCount',jint), ('accessibleContext',JOBJECT64), ('accessibleTable',JOBJECT64), ] class AccessibleTableCellInfo(Structure): _fields_=[ ('accessibleContext',JOBJECT64), ('index',jint), ('row',jint), ('column',jint), ('rowExtent',jint), ('columnExtent',jint), ('isSelected',jboolean), ] MAX_KEY_BINDINGS=50 ACCESSIBLE_SHIFT_KEYSTROKE=1 ACCESSIBLE_CONTROL_KEYSTROKE=2 ACCESSIBLE_META_KEYSTROKE=4 ACCESSIBLE_ALT_KEYSTROKE=8 ACCESSIBLE_ALT_GRAPH_KEYSTROKE=16 ACCESSIBLE_BUTTON1_KEYSTROKE=32 ACCESSIBLE_BUTTON2_KEYSTROKE=64 ACCESSIBLE_BUTTON3_KEYSTROKE=128 class AccessibleKeyBindingInfo(Structure): _fields_=[ ('character',jchar), ('modifiers',jint), ] class AccessibleKeyBindings(Structure): _fields_=[ ('keyBindingsCount',c_int), ('keyBindingInfo',AccessibleKeyBindingInfo*MAX_KEY_BINDINGS), ] AccessBridge_FocusGainedFP=CFUNCTYPE(None,c_long,JOBJECT64,JOBJECT64) AccessBridge_PropertyNameChangeFP=CFUNCTYPE(None,c_long,JOBJECT64,JOBJECT64,c_wchar_p,c_wchar_p) AccessBridge_PropertyDescriptionChangeFP=CFUNCTYPE(None,c_long,JOBJECT64,JOBJECT64,c_wchar_p,c_wchar_p) AccessBridge_PropertyValueChangeFP=CFUNCTYPE(None,c_long,JOBJECT64,JOBJECT64,c_wchar_p,c_wchar_p) AccessBridge_PropertyStateChangeFP=CFUNCTYPE(None,c_long,JOBJECT64,JOBJECT64,c_wchar_p,c_wchar_p) AccessBridge_PropertyCaretChangeFP=CFUNCTYPE(None,c_long,JOBJECT64,JOBJECT64,c_int,c_int) AccessBridge_PropertyActiveDescendentChangeFP=CFUNCTYPE(None,c_long,JOBJECT64,JOBJECT64,JOBJECT64,JOBJECT64) #Appropriately set the return and argument types of all the access bridge dll functions if bridgeDll: _fixBridgeFunc(None,'Windows_run') _fixBridgeFunc(None,'setFocusGainedFP',c_void_p) _fixBridgeFunc(None,'setPropertyNameChangeFP',c_void_p) _fixBridgeFunc(None,'setPropertyDescriptionChangeFP',c_void_p) _fixBridgeFunc(None,'setPropertyValueChangeFP',c_void_p) _fixBridgeFunc(None,'setPropertyStateChangeFP',c_void_p) _fixBridgeFunc(None,'setPropertyCaretChangeFP',c_void_p) _fixBridgeFunc(None,'setPropertyActiveDescendentChangeFP',c_void_p) _fixBridgeFunc(None,'releaseJavaObject',c_long,JOBJECT64) _fixBridgeFunc(BOOL,'getVersionInfo',POINTER(AccessBridgeVersionInfo),errcheck=True) _fixBridgeFunc(BOOL,'isJavaWindow',HWND) _fixBridgeFunc(BOOL,'isSameObject',c_long,JOBJECT64,JOBJECT64) _fixBridgeFunc(BOOL,'getAccessibleContextFromHWND',HWND,POINTER(c_long),POINTER(JOBJECT64),errcheck=True) _fixBridgeFunc(HWND,'getHWNDFromAccessibleContext',c_long,JOBJECT64,errcheck=True) _fixBridgeFunc(BOOL,'getAccessibleContextAt',c_long,JOBJECT64,jint,jint,POINTER(JOBJECT64),errcheck=True) _fixBridgeFunc(BOOL,'getAccessibleContextWithFocus',HWND,POINTER(c_long),POINTER(JOBJECT64),errcheck=True) _fixBridgeFunc(BOOL,'getAccessibleContextInfo',c_long,JOBJECT64,POINTER(AccessibleContextInfo),errcheck=True) _fixBridgeFunc(JOBJECT64,'getAccessibleChildFromContext',c_long,JOBJECT64,jint,errcheck=True) _fixBridgeFunc(JOBJECT64,'getAccessibleParentFromContext',c_long,JOBJECT64) _fixBridgeFunc(JOBJECT64,'getParentWithRole',c_long,JOBJECT64,POINTER(c_wchar)) _fixBridgeFunc(BOOL,'getAccessibleRelationSet',c_long,JOBJECT64,POINTER(AccessibleRelationSetInfo),errcheck=True) _fixBridgeFunc(BOOL,'getAccessibleTextInfo',c_long,JOBJECT64,POINTER(AccessibleTextInfo),jint,jint,errcheck=True) _fixBridgeFunc(BOOL,'getAccessibleTextItems',c_long,JOBJECT64,POINTER(AccessibleTextItemsInfo),jint,errcheck=True) _fixBridgeFunc(BOOL,'getAccessibleTextSelectionInfo',c_long,JOBJECT64,POINTER(AccessibleTextSelectionInfo),errcheck=True) _fixBridgeFunc(BOOL,'getAccessibleTextAttributes',c_long,JOBJECT64,jint,POINTER(AccessibleTextAttributesInfo),errcheck=True) _fixBridgeFunc(BOOL,'getAccessibleTextLineBounds',c_long,JOBJECT64,jint,POINTER(jint),POINTER(jint),errcheck=True) _fixBridgeFunc(BOOL,'getAccessibleTextRange',c_long,JOBJECT64,jint,jint,POINTER(c_wchar),c_short,errcheck=True) _fixBridgeFunc(BOOL,'getCurrentAccessibleValueFromContext',c_long,JOBJECT64,POINTER(c_wchar),c_short,errcheck=True) _fixBridgeFunc(BOOL,'selectTextRange',c_long,JOBJECT64,c_int,c_int,errcheck=True) _fixBridgeFunc(BOOL,'getTextAttributesInRange',c_long,JOBJECT64,c_int,c_int,POINTER(AccessibleTextAttributesInfo),POINTER(c_short),errcheck=True) _fixBridgeFunc(JOBJECT64,'getTopLevelObject',c_long,JOBJECT64,errcheck=True) _fixBridgeFunc(c_int,'getObjectDepth',c_long,JOBJECT64) _fixBridgeFunc(JOBJECT64,'getActiveDescendent',c_long,JOBJECT64) _fixBridgeFunc(BOOL,'requestFocus',c_long,JOBJECT64,errcheck=True) _fixBridgeFunc(BOOL,'setCaretPosition',c_long,JOBJECT64,c_int,errcheck=True) _fixBridgeFunc(BOOL,'getCaretLocation',c_long,JOBJECT64,POINTER(AccessibleTextRectInfo),jint,errcheck=True) _fixBridgeFunc(BOOL,'getAccessibleActions',c_long,JOBJECT64,POINTER(AccessibleActions),errcheck=True) _fixBridgeFunc(BOOL,'doAccessibleActions',c_long,JOBJECT64,POINTER(AccessibleActionsToDo),POINTER(jint),errcheck=True) _fixBridgeFunc(BOOL,'getAccessibleTableInfo',c_long,JOBJECT64,POINTER(AccessibleTableInfo)) _fixBridgeFunc(BOOL,'getAccessibleTableCellInfo',c_long,AccessibleTable,jint,jint,POINTER(AccessibleTableCellInfo),errcheck=True) _fixBridgeFunc(BOOL,'getAccessibleTableRowHeader',c_long,JOBJECT64,POINTER(AccessibleTableInfo)) _fixBridgeFunc(BOOL,'getAccessibleTableColumnHeader',c_long,JOBJECT64,POINTER(AccessibleTableInfo)) _fixBridgeFunc(JOBJECT64,'getAccessibleTableRowDescription',c_long,JOBJECT64,jint) _fixBridgeFunc(JOBJECT64,'getAccessibleTableColumnDescription',c_long,JOBJECT64,jint) _fixBridgeFunc(jint,'getAccessibleTableRow',c_long,AccessibleTable,jint) _fixBridgeFunc(jint,'getAccessibleTableColumn',c_long,AccessibleTable,jint) _fixBridgeFunc(jint,'getAccessibleTableIndex',c_long,AccessibleTable,jint,jint) _fixBridgeFunc(BOOL,'getAccessibleKeyBindings',c_long,JOBJECT64,POINTER(AccessibleKeyBindings),errcheck=True) #NVDA specific code isRunning=False # Cache of the last active window handle for a given JVM ID. In theory, this # cache should not be needed, as it should always be possible to retrieve the # window handle of a given accessible context by calling getTopLevelObject then # getHWNDFromAccessibleContext. However, getTopLevelObject sometimes returns # accessible contexts that make getHWNDFromAccessibleContext fail. To workaround # the issue, we use this cache as a fallback when either getTopLevelObject or # getHWNDFromAccessibleContext fails. vmIDsToWindowHandles={} internalFunctionQueue=Queue.Queue(1000) internalFunctionQueue.__name__="JABHandler.internalFunctionQueue" def internalQueueFunction(func,*args,**kwargs): internalFunctionQueue.put_nowait((func,args,kwargs)) core.requestPump() def internal_getWindowHandleFromAccContext(vmID,accContext): try: topAC=bridgeDll.getTopLevelObject(vmID,accContext) try: return bridgeDll.getHWNDFromAccessibleContext(vmID,topAC) finally: bridgeDll.releaseJavaObject(vmID,topAC) except: return None def getWindowHandleFromAccContext(vmID,accContext): hwnd=internal_getWindowHandleFromAccContext(vmID,accContext) if hwnd: vmIDsToWindowHandles[vmID]=hwnd return hwnd else: return vmIDsToWindowHandles.get(vmID) class JABContext(object): def __init__(self,hwnd=None,vmID=None,accContext=None): if hwnd and not vmID: vmID=c_long() accContext=JOBJECT64() bridgeDll.getAccessibleContextFromHWND(hwnd,byref(vmID),byref(accContext)) #Record this vm ID and window handle for later use with other objects vmID=vmID.value vmIDsToWindowHandles[vmID]=hwnd elif vmID and not hwnd: hwnd = getWindowHandleFromAccContext(vmID,accContext) self.hwnd=hwnd self.vmID=vmID self.accContext=accContext def __del__(self): if isRunning: try: bridgeDll.releaseJavaObject(self.vmID,self.accContext) except: log.debugWarning("Error releasing java object",exc_info=True) def __eq__(self,jabContext): if self.vmID==jabContext.vmID and bridgeDll.isSameObject(self.vmID,self.accContext,jabContext.accContext): return True else: return False def __ne__(self,jabContext): if self.vmID!=jabContext.vmID or not bridgeDll.isSameObject(self.vmID,self.accContext,jabContext.accContext): return True else: return False def getVersionInfo(self): info=AccessBridgeVersionInfo() bridgeDll.getVersionInfo(self.vmID,byref(info)) return info def getObjectDepth(self): return bridgeDll.getObjectDepth(self.vmID,self.accContext) def getAccessibleContextInfo(self): info=AccessibleContextInfo() bridgeDll.getAccessibleContextInfo(self.vmID,self.accContext,byref(info)) return info def getAccessibleTextInfo(self,x,y): textInfo=AccessibleTextInfo() bridgeDll.getAccessibleTextInfo(self.vmID,self.accContext,byref(textInfo),x,y) return textInfo def getAccessibleTextItems(self,index): textItemsInfo=AccessibleTextItemsInfo() bridgeDll.getAccessibleTextItems(self.vmID,self.accContext,byref(textItemsInfo),index) return textItemsInfo def getAccessibleTextSelectionInfo(self): textSelectionInfo=AccessibleTextSelectionInfo() bridgeDll.getAccessibleTextSelectionInfo(self.vmID,self.accContext,byref(textSelectionInfo)) return textSelectionInfo def getAccessibleTextRange(self,start,end): length=((end+1)-start) if length<=0: return u"" text=create_unicode_buffer(length+1) bridgeDll.getAccessibleTextRange(self.vmID,self.accContext,start,end,text,length) return text.value def getAccessibleTextLineBounds(self,index): index=max(index,0) log.debug("lineBounds: index %s"%index) #Java returns end as the last character, not end as past the last character startIndex=c_int() endIndex=c_int() bridgeDll.getAccessibleTextLineBounds(self.vmID,self.accContext,index,byref(startIndex),byref(endIndex)) start=startIndex.value end=endIndex.value log.debug("line bounds: start %s, end %s"%(start,end)) if end(index+1): # This line starts after the requested index, so set end to point at the line before. end=tempStart-1 else: ok=True ok=False # Try to retract the start. while not ok: bridgeDll.getAccessibleTextLineBounds(self.vmID,self.accContext,start,byref(startIndex),byref(endIndex)) tempStart=max(startIndex.value,0) tempEnd=max(endIndex.value,0) log.debug("line bounds: tempStart %s, tempEnd %s"%(tempStart,tempEnd)) if tempEnd<(index-1): # This line ends before the requested index, so set start to point at the line after. start=tempEnd+1 else: ok=True log.debug("line bounds: returning %s, %s"%(start,end)) return (start,end) def getAccessibleParentFromContext(self): accContext=bridgeDll.getAccessibleParentFromContext(self.vmID,self.accContext) if accContext: return self.__class__(self.hwnd,self.vmID,accContext) else: return None def getAccessibleParentWithRole(self, role): accContext=bridgeDll.getParentWithRole(self.vmID,self.accContext, role) if accContext: return self.__class__(self.hwnd,self.vmID,accContext) else: return None def getAccessibleChildFromContext(self,index): accContext=bridgeDll.getAccessibleChildFromContext(self.vmID,self.accContext,index) if accContext: return self.__class__(self.hwnd,self.vmID,accContext) else: return None def getActiveDescendent(self): accContext=bridgeDll.getActiveDescendent(self.vmID,self.accContext) if accContext: return self.__class__(self.hwnd,self.vmID,accContext) else: return None def getAccessibleContextAt(self,x,y): newAccContext=JOBJECT64() res=bridgeDll.getAccessibleContextAt(self.vmID,self.accContext,x,y,byref(newAccContext)) if not res or not newAccContext: return None if not bridgeDll.isSameObject(self.vmID,newAccContext,self.accContext): return self.__class__(self.hwnd,self.vmID,newAccContext) elif newAccContext!=self.accContext: bridgeDll.releaseJavaObject(self.vmID,newAccContext) return None def getCurrentAccessibleValueFromContext(self): buf=create_unicode_buffer(SHORT_STRING_SIZE+1) bridgeDll.getCurrentAccessibleValueFromContext(self.vmID,self.accContext,buf,SHORT_STRING_SIZE) return buf.value def selectTextRange(self,start,end): bridgeDll.selectTextRange(start,end) def setCaretPosition(self,offset): bridgeDll.setCaretPosition(self.vmID,self.accContext,offset) def getTextAttributesInRange(self, startIndex, endIndex): attributes = AccessibleTextAttributesInfo() length = c_short() bridgeDll.getTextAttributesInRange(self.vmID, self.accContext, startIndex, endIndex, byref(attributes), byref(length)) return attributes, length.value def getAccessibleRelationSet(self): relations = AccessibleRelationSetInfo() bridgeDll.getAccessibleRelationSet(self.vmID, self.accContext, byref(relations)) return relations def getAccessibleTableInfo(self): info=AccessibleTableInfo() if bridgeDll.getAccessibleTableInfo(self.vmID,self.accContext,byref(info)): info.jabCaption=JABContext(vmID=self.vmID,accContext=info.caption) if info.caption else None info.jabSummary=JABContext(vmID=self.vmID,accContext=info.summary) if info.summary else None info.jabContext=JABContext(vmID=self.vmID,accContext=info.accessibleContext) if info.accessibleContext else None info.jabTable=JABContext(vmID=self.vmID,accContext=info.accessibleTable) if info.accessibleTable else None return info def getAccessibleTableCellInfo(self,row,col): info=AccessibleTableCellInfo() if bridgeDll.getAccessibleTableCellInfo(self.vmID,self.accContext,row,col,byref(info)): info.jabContext=JABContext(vmID=self.vmID,accContext=info.accessibleContext) if info.accessibleContext else None return info def getAccessibleTableRow(self,index): return bridgeDll.getAccessibleTableRow(self.vmID,self.accContext,index) def getAccessibleTableColumn(self,index): return bridgeDll.getAccessibleTableColumn(self.vmID,self.accContext,index) def getAccessibleTableRowHeader(self): info=AccessibleTableInfo() if bridgeDll.getAccessibleTableRowHeader(self.vmID,self.accContext,byref(info)): info.jabCaption=JABContext(vmID=self.vmID,accContext=info.caption) if info.caption else None info.jabSummary=JABContext(vmID=self.vmID,accContext=info.summary) if info.summary else None info.jabContext=JABContext(vmID=self.vmID,accContext=info.accessibleContext) if info.accessibleContext else None info.jabTable=JABContext(vmID=self.vmID,accContext=info.accessibleTable) if info.accessibleTable else None return info def getAccessibleTableRowDescription(self,row): accContext=bridgeDll.getAccessibleTableRowDescription(self.vmID,self.accContext,row) if accContext: return JabContext(vmID=self.vmID,accContext=accContext) def getAccessibleTableColumnHeader(self): info=AccessibleTableInfo() if bridgeDll.getAccessibleTableColumnHeader(self.vmID,self.accContext,byref(info)): info.jabCaption=JABContext(vmID=self.vmID,accContext=info.caption) if info.caption else None info.jabSummary=JABContext(vmID=self.vmID,accContext=info.summary) if info.summary else None info.jabContext=JABContext(vmID=self.vmID,accContext=info.accessibleContext) if info.accessibleContext else None info.jabTable=JABContext(vmID=self.vmID,accContext=info.accessibleTable) if info.accessibleTable else None return info def getAccessibleTableColumnDescription(self,column): accContext=bridgeDll.getAccessibleTableColumnDescription(self.vmID,self.accContext,column) if accContext: return JabContext(vmID=self.vmID,accContext=accContext) def getAccessibleKeyBindings(self): bindings=AccessibleKeyBindings() if bridgeDll.getAccessibleKeyBindings(self.vmID,self.accContext,byref(bindings)): return bindings @AccessBridge_FocusGainedFP def internal_event_focusGained(vmID, event,source): hwnd=getWindowHandleFromAccContext(vmID,source) internalQueueFunction(event_gainFocus,vmID,source,hwnd) bridgeDll.releaseJavaObject(vmID,event) def event_gainFocus(vmID,accContext,hwnd): jabContext=JABContext(hwnd=hwnd,vmID=vmID,accContext=accContext) if not winUser.isDescendantWindow(winUser.getForegroundWindow(),jabContext.hwnd): return focus=eventHandler.lastQueuedFocusObject if (isinstance(focus,NVDAObjects.JAB.JAB) and focus.jabContext==jabContext): return obj=NVDAObjects.JAB.JAB(jabContext=jabContext) if obj.role==controlTypes.ROLE_UNKNOWN: return eventHandler.queueEvent("gainFocus",obj) @AccessBridge_PropertyActiveDescendentChangeFP def internal_event_activeDescendantChange(vmID, event,source,oldDescendant,newDescendant): hwnd=getWindowHandleFromAccContext(vmID,source) internalQueueFunction(event_gainFocus,vmID,newDescendant,hwnd) for accContext in [event,oldDescendant]: bridgeDll.releaseJavaObject(vmID,accContext) @AccessBridge_PropertyNameChangeFP def event_nameChange(vmID,event,source,oldVal,newVal): jabContext=JABContext(vmID=vmID,accContext=source) focus=api.getFocusObject() if isinstance(focus, NVDAObjects.JAB.JAB) and focus.jabContext == jabContext: obj = focus else: obj = NVDAObjects.JAB.JAB(jabContext=jabContext) if obj: eventHandler.queueEvent("nameChange", obj) bridgeDll.releaseJavaObject(vmID,event) @AccessBridge_PropertyDescriptionChangeFP def event_descriptionChange(vmID,event,source,oldVal,newVal): jabContext=JABContext(vmID=vmID,accContext=source) focus=api.getFocusObject() if isinstance(focus, NVDAObjects.JAB.JAB) and focus.jabContext == jabContext: obj = focus else: obj = NVDAObjects.JAB.JAB(jabContext=jabContext) if obj: eventHandler.queueEvent("descriptionChange", obj) bridgeDll.releaseJavaObject(vmID,event) @AccessBridge_PropertyValueChangeFP def event_valueChange(vmID,event,source,oldVal,newVal): jabContext=JABContext(vmID=vmID,accContext=source) focus=api.getFocusObject() if isinstance(focus, NVDAObjects.JAB.JAB) and focus.jabContext == jabContext: obj = focus else: obj = NVDAObjects.JAB.JAB(jabContext=jabContext) if obj: eventHandler.queueEvent("valueChange", obj) bridgeDll.releaseJavaObject(vmID,event) @AccessBridge_PropertyStateChangeFP def internal_event_stateChange(vmID,event,source,oldState,newState): internalQueueFunction(event_stateChange,vmID,source,oldState,newState) bridgeDll.releaseJavaObject(vmID,event) def event_stateChange(vmID,accContext,oldState,newState): jabContext=JABContext(vmID=vmID,accContext=accContext) focus=api.getFocusObject() #For broken tabs and menus, we need to watch for things being selected and pretend its a focus change stateList=newState.split(',') if "focused" in stateList or "selected" in stateList: obj=NVDAObjects.JAB.JAB(jabContext=jabContext) if not obj: return if focus!=obj and eventHandler.lastQueuedFocusObject!=obj and obj.role in (controlTypes.ROLE_MENUITEM,controlTypes.ROLE_TAB,controlTypes.ROLE_MENU): eventHandler.queueEvent("gainFocus",obj) return if isinstance(focus,NVDAObjects.JAB.JAB) and focus.jabContext==jabContext: obj=focus else: obj=NVDAObjects.JAB.JAB(jabContext=jabContext) if not obj: return eventHandler.queueEvent("stateChange",obj) @AccessBridge_PropertyCaretChangeFP def internal_event_caretChange(vmID, event,source,oldPos,newPos): hwnd=getWindowHandleFromAccContext(vmID,source) if oldPos<0 and newPos>=0: internalQueueFunction(event_gainFocus,vmID,source,hwnd) else: internalQueueFunction(event_caret,vmID,source,hwnd) bridgeDll.releaseJavaObject(vmID,event) def event_caret(vmID, accContext, hwnd): jabContext = JABContext(hwnd=hwnd, vmID=vmID, accContext=accContext) focus = api.getFocusObject() if isinstance(focus, NVDAObjects.JAB.JAB) and focus.jabContext == jabContext: obj = focus else: obj = NVDAObjects.JAB.JAB(jabContext=jabContext) if not obj: return eventHandler.queueEvent("caret", obj) def event_enterJavaWindow(hwnd): internalQueueFunction(enterJavaWindow_helper,hwnd) def enterJavaWindow_helper(hwnd): vmID=c_long() accContext=JOBJECT64() gotFocus=False timeout=time.time()+0.2 while time.time()