Package NVDAObjects :: Package IAccessible
[hide private]
[frames] | no frames]

Source Code for Package NVDAObjects.IAccessible

   1  #NVDAObjects/IAccessible.py 
   2  #A part of NonVisual Desktop Access (NVDA) 
   3  #Copyright (C) 2006-2007 NVDA Contributors <http://www.nvda-project.org/> 
   4  #This file is covered by the GNU General Public License. 
   5  #See the file COPYING for more details. 
   6   
   7  from comtypes import COMError, IServiceProvider, GUID 
   8  import ctypes 
   9  import os 
  10  import re 
  11  from comInterfaces.tom import ITextDocument 
  12  import tones 
  13  import languageHandler 
  14  import textInfos.offsets 
  15  import colors 
  16  import time 
  17  import displayModel 
  18  import IAccessibleHandler 
  19  import oleacc 
  20  import JABHandler 
  21  import winUser 
  22  import globalVars 
  23  from logHandler import log 
  24  import speech 
  25  import braille 
  26  import api 
  27  import config 
  28  import controlTypes 
  29  from NVDAObjects.window import Window 
  30  from NVDAObjects import NVDAObject, NVDAObjectTextInfo, InvalidNVDAObject 
  31  import NVDAObjects.JAB 
  32  import eventHandler 
  33  import queueHandler 
  34  from NVDAObjects.behaviors import ProgressBar, Dialog, EditableTextWithAutoSelectDetection 
35 36 -def getNVDAObjectFromEvent(hwnd,objectID,childID):
37 try: 38 accHandle=IAccessibleHandler.accessibleObjectFromEvent(hwnd,objectID,childID) 39 except WindowsError: 40 accHandle=None 41 if not accHandle: 42 return None 43 (pacc,accChildID)=accHandle 44 obj=IAccessible(IAccessibleObject=pacc,IAccessibleChildID=accChildID,event_windowHandle=hwnd,event_objectID=objectID,event_childID=childID) 45 return obj
46
47 -def getNVDAObjectFromPoint(x,y):
48 accHandle=IAccessibleHandler.accessibleObjectFromPoint(x,y) 49 if not accHandle: 50 return None 51 (pacc,child)=accHandle 52 obj=IAccessible(IAccessibleObject=pacc,IAccessibleChildID=child) 53 return obj
54
55 -def normalizeIA2TextFormatField(formatField):
56 try: 57 textAlign=formatField.pop("text-align") 58 except KeyError: 59 textAlign=None 60 if textAlign: 61 if "right" in textAlign: 62 textAlign="right" 63 elif "center" in textAlign: 64 textAlign="center" 65 elif "justify" in textAlign: 66 textAlign="justify" 67 formatField["text-align"]=textAlign 68 try: 69 fontWeight=formatField.pop("font-weight") 70 except KeyError: 71 fontWeight=None 72 if fontWeight is not None and (fontWeight.lower()=="bold" or (fontWeight.isdigit() and int(fontWeight)>=700)): 73 formatField["bold"]=True 74 else: 75 formatField["bold"]=False 76 try: 77 fontStyle=formatField.pop("font-style") 78 except KeyError: 79 fontStyle=None 80 if fontStyle is not None and fontStyle.lower()=="italic": 81 formatField["italic"]=True 82 else: 83 formatField["italic"]=False 84 try: 85 invalid=formatField.pop("invalid") 86 except KeyError: 87 invalid=None 88 if invalid and invalid.lower()=="spelling": 89 formatField["invalid-spelling"]=True 90 color=formatField.get('color') 91 if color: 92 try: 93 formatField['color']=colors.RGB.fromString(color) 94 except ValueError: 95 pass 96 backgroundColor=formatField.get('background-color') 97 if backgroundColor: 98 try: 99 formatField['background-color']=colors.RGB.fromString(backgroundColor) 100 except ValueError: 101 pass 102 lineStyle=formatField.get("text-underline-style") 103 lineType=formatField.get("text-underline-type") 104 if lineStyle or lineType: 105 formatField["underline"]=lineStyle!="none" and lineType!="none" 106 lineStyle=formatField.get("text-line-through-style") 107 lineType=formatField.get("text-line-through-type") 108 if lineStyle or lineType: 109 formatField["strikethrough"]=lineStyle!="none" and lineType!="none" 110 language=formatField.get('language') 111 if language: 112 formatField['language']=languageHandler.normalizeLanguage(language)
113
114 -class IA2TextTextInfo(textInfos.offsets.OffsetsTextInfo):
115 116 detectFormattingAfterCursorMaybeSlow=False 117
118 - def _getOffsetFromPoint(self,x,y):
119 if self.obj.IAccessibleTextObject.nCharacters>0: 120 return self.obj.IAccessibleTextObject.OffsetAtPoint(x,y,IAccessibleHandler.IA2_COORDTYPE_SCREEN_RELATIVE) 121 else: 122 raise NotImplementedError
123
124 - def _getPointFromOffset(self,offset):
125 try: 126 res=self.obj.IAccessibleTextObject.characterExtents(offset,IAccessibleHandler.IA2_COORDTYPE_SCREEN_RELATIVE) 127 except COMError: 128 raise NotImplementedError 129 point=textInfos.Point(res[0]+(res[2]/2),res[1]+(res[3]/2)) 130 return point
131
132 - def _get_unit_mouseChunk(self):
133 return "mouseChunk"
134
135 - def expand(self,unit):
136 if unit==self.unit_mouseChunk: 137 isMouseChunkUnit=True 138 oldStart=self._startOffset 139 oldEnd=self._endOffset 140 unit=super(IA2TextTextInfo,self).unit_mouseChunk 141 else: 142 isMouseChunkUnit=False 143 super(IA2TextTextInfo,self).expand(unit) 144 if isMouseChunkUnit: 145 text=self._getTextRange(self._startOffset,self._endOffset) 146 try: 147 self._startOffset=text.rindex(u'\ufffc',0,oldStart-self._startOffset) 148 except ValueError: 149 pass 150 try: 151 self._endOffset=text.index(u'\ufffc',oldEnd-self._startOffset) 152 except ValueError: 153 pass
154
155 - def _getCaretOffset(self):
156 try: 157 offset=self.obj.IAccessibleTextObject.caretOffset 158 except COMError: 159 log.debugWarning("IAccessibleText::caretOffset failed", exc_info=True) 160 raise RuntimeError("Retrieving caret offset failed") 161 if offset<0: 162 raise RuntimeError("no active caret in this object") 163 return offset
164
165 - def _setCaretOffset(self,offset):
166 self.obj.IAccessibleTextObject.SetCaretOffset(offset)
167
168 - def _getSelectionOffsets(self):
169 try: 170 nSelections=self.obj.IAccessibleTextObject.nSelections 171 except COMError: 172 nSelections=0 173 if nSelections: 174 (start,end)=self.obj.IAccessibleTextObject.Selection[0] 175 else: 176 start=self._getCaretOffset() 177 end=start 178 return [min(start,end),max(start,end)]
179
180 - def _setSelectionOffsets(self,start,end):
181 for selIndex in range(self.obj.IAccessibleTextObject.NSelections): 182 self.obj.IAccessibleTextObject.RemoveSelection(selIndex) 183 self.obj.IAccessibleTextObject.AddSelection(start,end)
184
185 - def _getStoryLength(self):
186 try: 187 return self.obj.IAccessibleTextObject.NCharacters 188 except COMError: 189 log.debugWarning("IAccessibleText::nCharacters failed",exc_info=True) 190 return 0
191
192 - def _getLineCount(self):
193 return -1
194
195 - def _getTextRange(self,start,end):
196 try: 197 return self.obj.IAccessibleTextObject.text(start,end) 198 except COMError: 199 return u""
200
201 - def _getFormatFieldAndOffsets(self,offset,formatConfig,calculateOffsets=True):
202 try: 203 startOffset,endOffset,attribsString=self.obj.IAccessibleTextObject.attributes(offset) 204 except COMError: 205 log.debugWarning("could not get attributes",exc_info=True) 206 return textInfos.FormatField(),(self._startOffset,self._endOffset) 207 formatField=textInfos.FormatField() 208 if not attribsString and offset>0: 209 try: 210 attribsString=self.obj.IAccessibleTextObject.attributes(offset-1)[2] 211 except COMError: 212 pass 213 if attribsString: 214 formatField.update(IAccessibleHandler.splitIA2Attribs(attribsString)) 215 normalizeIA2TextFormatField(formatField) 216 return formatField,(startOffset,endOffset)
217
218 - def _getCharacterOffsets(self,offset):
219 try: 220 if offset>=self.obj.IAccessibleTextObject.nCharacters: 221 return offset,offset+1 222 except COMError: 223 pass 224 try: 225 return self.obj.IAccessibleTextObject.TextAtOffset(offset,IAccessibleHandler.IA2_TEXT_BOUNDARY_CHAR)[0:2] 226 except COMError: 227 return super(IA2TextTextInfo,self)._getCharacterOffsets(offset)
228
229 - def _getWordOffsets(self,offset):
230 try: 231 if offset>=self.obj.IAccessibleTextObject.nCharacters: 232 return offset,offset+1 233 except COMError: 234 pass 235 try: 236 return self.obj.IAccessibleTextObject.TextAtOffset(offset,IAccessibleHandler.IA2_TEXT_BOUNDARY_WORD)[0:2] 237 except COMError: 238 return super(IA2TextTextInfo,self)._getWordOffsets(offset)
239
240 - def _getLineOffsets(self,offset):
241 try: 242 start,end,text=self.obj.IAccessibleTextObject.TextAtOffset(offset,IAccessibleHandler.IA2_TEXT_BOUNDARY_LINE) 243 return start,end 244 except COMError: 245 log.debugWarning("IAccessibleText::textAtOffset failed",exc_info=True) 246 return offset,offset+1
247
248 - def _getSentenceOffsets(self,offset):
249 try: 250 if offset>=self.obj.IAccessibleTextObject.nCharacters: 251 return offset,offset+1 252 except COMError: 253 pass 254 try: 255 start,end,text=self.obj.IAccessibleTextObject.TextAtOffset(offset,IAccessibleHandler.IA2_TEXT_BOUNDARY_SENTENCE) 256 if start==end: 257 raise NotImplementedError 258 return start,end 259 except COMError: 260 return super(IA2TextTextInfo,self)._getSentenceOffsets(offset)
261
262 - def _getParagraphOffsets(self,offset):
263 try: 264 if offset>=self.obj.IAccessibleTextObject.nCharacters: 265 return offset,offset+1 266 except COMError: 267 pass 268 try: 269 start,end,text=self.obj.IAccessibleTextObject.TextAtOffset(offset,IAccessibleHandler.IA2_TEXT_BOUNDARY_PARAGRAPH) 270 if start>=end: 271 raise RuntimeError("did not expand to paragraph correctly") 272 return start,end 273 except (RuntimeError,COMError): 274 return super(IA2TextTextInfo,self)._getParagraphOffsets(offset)
275
276 - def _lineNumFromOffset(self,offset):
277 return -1
278
279 - def getEmbeddedObject(self, offset=0):
280 offset += self._startOffset 281 282 # Mozilla uses IAccessibleHypertext to facilitate quick retrieval of embedded objects. 283 try: 284 ht = self.obj.IAccessibleTextObject.QueryInterface(IAccessibleHandler.IAccessibleHypertext) 285 hl = ht.hyperlink(ht.hyperlinkIndex(offset)) 286 return IAccessible(IAccessibleObject=hl.QueryInterface(IAccessibleHandler.IAccessible2), IAccessibleChildID=0) 287 except COMError: 288 pass 289 290 # Otherwise, we need to count the embedded objects to determine which child to use. 291 # This could possibly be optimised by caching. 292 text = self._getTextRange(0, offset + 1) 293 childIndex = text.count(u"\uFFFC") 294 try: 295 return IAccessible(IAccessibleObject=IAccessibleHandler.accChild(self.obj.IAccessibleObject, childIndex)[0], IAccessibleChildID=0) 296 except COMError: 297 pass 298 299 raise LookupError
300
301 -class IAccessible(Window):
302 """ 303 the NVDAObject for IAccessible 304 @ivar IAccessibleChildID: the IAccessible object's child ID 305 @type IAccessibleChildID: int 306 """ 307 308 IAccessibleTableUsesTableCellIndexAttrib=False #: Should the table-cell-index IAccessible2 object attribute be used rather than indexInParent? 309 IA2UniqueID=None #: The cached IAccessible2::uniqueID if its implemented 310 311 @classmethod
312 - def getPossibleAPIClasses(cls,kwargs,relation=None):
313 if not kwargs.get('IAccessibleChildID'): 314 from . import MSHTML 315 yield MSHTML.MSHTML
316 317 @classmethod
318 - def kwargsFromSuper(cls,kwargs,relation=None):
319 acc=None 320 objID=None 321 windowHandle=kwargs['windowHandle'] 322 if isinstance(relation,tuple): 323 acc=IAccessibleHandler.accessibleObjectFromPoint(relation[0],relation[1]) 324 elif relation=="focus": 325 objID=winUser.OBJID_CLIENT 326 acc=IAccessibleHandler.accessibleObjectFromEvent(windowHandle,objID,0) 327 if not acc: 328 return False 329 testAccFocus=acc 330 usedAccFocus=False 331 # Keep doing accFocus until we can't anymore or until accFocus keeps returning the same object. 332 while True: 333 testAccFocus=IAccessibleHandler.accFocus(testAccFocus[0]) 334 # Only set the acc variable if we get something useful using accFocus. 335 if testAccFocus and testAccFocus!=acc: 336 acc=testAccFocus 337 usedAccFocus=True 338 else: 339 # We can't go any further. 340 break 341 if usedAccFocus: 342 # We don't know the event parameters for this object. 343 objID=None 344 # This object may also be in a different window, so we need to recalculate the window handle. 345 kwargs['windowHandle']=None 346 elif relation in ("parent","foreground"): 347 objID=winUser.OBJID_CLIENT 348 else: 349 objID=winUser.OBJID_WINDOW 350 if not acc and objID is not None: 351 acc=IAccessibleHandler.accessibleObjectFromEvent(windowHandle,objID,0) 352 if not acc: 353 return False 354 kwargs['IAccessibleObject']=acc[0] 355 kwargs['IAccessibleChildID']=acc[1] 356 if objID: 357 # We know the event parameters, so pass them to the NVDAObject. 358 kwargs['event_windowHandle']=windowHandle 359 kwargs['event_objectID']=objID 360 kwargs['event_childID']=0 361 return True
362 363 @classmethod
364 - def windowHasExtraIAccessibles(cls,windowHandle):
365 """Finds out whether this window has things such as a system menu / titleBar / scroll bars, which would be represented as extra IAccessibles""" 366 style=winUser.getWindowStyle(windowHandle) 367 return bool(style&winUser.WS_SYSMENU)
368
369 - def findOverlayClasses(self,clsList):
370 if self.event_objectID==winUser.OBJID_CLIENT and JABHandler.isJavaWindow(self.windowHandle): 371 clsList.append(JavaVMRoot) 372 373 windowClassName=self.windowClassName 374 role=self.IAccessibleRole 375 376 if hasattr(self, "IAccessibleTextObject"): 377 if role==oleacc.ROLE_SYSTEM_TEXT: 378 isEditable=True 379 else: 380 try: 381 isEditable=bool(self.IAccessibleObject.states&IAccessibleHandler.IA2_STATE_EDITABLE) 382 except COMError: 383 isEditable=False 384 if isEditable: 385 clsList.append(EditableTextWithAutoSelectDetection) 386 387 # Use window class name and role to search for a class match in our static map. 388 keys=[(windowClassName,role),(None,role),(windowClassName,None)] 389 normalizedWindowClassName=Window.normalizeWindowClassName(windowClassName) 390 if normalizedWindowClassName!=windowClassName: 391 keys.insert(1,(normalizedWindowClassName,role)) 392 keys.append((normalizedWindowClassName,None)) 393 for key in keys: 394 newCls=None 395 classString=_staticMap.get(key,None) 396 if classString and classString.find('.')>0: 397 modString,classString=os.path.splitext(classString) 398 classString=classString[1:] 399 mod=__import__(modString,globals(),locals(),[]) 400 newCls=getattr(mod,classString) 401 elif classString: 402 newCls=globals()[classString] 403 if newCls: 404 clsList.append(newCls) 405 406 # Some special cases. 407 if windowClassName=="GeckoPluginWindow" and self.event_objectID==0 and self.IAccessibleChildID==0: 408 from mozilla import GeckoPluginWindowRoot 409 clsList.append(GeckoPluginWindowRoot) 410 if (windowClassName in ("MozillaWindowClass", "GeckoPluginWindow") and not isinstance(self.IAccessibleObject, IAccessibleHandler.IAccessible2)) or windowClassName in ("MacromediaFlashPlayerActiveX", "ApolloRuntimeContentWindow", "ShockwaveFlash", "ShockwaveFlashLibrary"): 411 # This is possibly a Flash object. 412 from . import adobeFlash 413 adobeFlash.findExtraOverlayClasses(self, clsList) 414 elif windowClassName.startswith('Mozilla'): 415 from . import mozilla 416 mozilla.findExtraOverlayClasses(self, clsList) 417 elif windowClassName.startswith('bosa_sdm'): 418 from .msOffice import SDM 419 clsList.append(SDM) 420 elif windowClassName == "DirectUIHWND" and role == oleacc.ROLE_SYSTEM_TEXT: 421 from NVDAObjects.window import DisplayModelEditableText 422 clsList.append(DisplayModelEditableText) 423 elif windowClassName in ("ListBox","ComboLBox") and role == oleacc.ROLE_SYSTEM_LISTITEM: 424 windowStyle = self.windowStyle 425 if (windowStyle & winUser.LBS_OWNERDRAWFIXED or windowStyle & winUser.LBS_OWNERDRAWVARIABLE) and not windowStyle & winUser.LBS_HASSTRINGS: 426 # This is an owner drawn ListBox and text has not been set for the items. 427 # See http://msdn.microsoft.com/en-us/library/ms971352.aspx#msaa_sa_listbxcntrls 428 clsList.append(InaccessibleListBoxItem) 429 elif windowClassName == "ComboBox" and role == oleacc.ROLE_SYSTEM_COMBOBOX: 430 windowStyle = self.windowStyle 431 if (windowStyle & winUser.CBS_OWNERDRAWFIXED or windowStyle & winUser.CBS_OWNERDRAWVARIABLE) and not windowStyle & winUser.CBS_HASSTRINGS: 432 # This is an owner drawn ComboBox and text has not been set for the items. 433 # See http://msdn.microsoft.com/en-us/library/ms971352.aspx#msaa_sa_listbxcntrls 434 clsList.append(InaccessibleComboBox) 435 elif windowClassName == "MsoCommandBar": 436 from .msOffice import BrokenMsoCommandBar 437 if BrokenMsoCommandBar.appliesTo(self): 438 clsList.append(BrokenMsoCommandBar) 439 elif windowClassName.startswith("Internet Explorer_"): 440 from . import MSHTML 441 MSHTML.findExtraIAccessibleOverlayClasses(self, clsList) 442 elif windowClassName == "AVL_AVView": 443 from . import adobeAcrobat 444 adobeAcrobat.findExtraOverlayClasses(self, clsList) 445 446 #Support for Windowless richEdit 447 if not hasattr(IAccessible,"IID_ITextServices"): 448 try: 449 IAccessible.IID_ITextServices=ctypes.cast(ctypes.windll.msftedit.IID_ITextServices,ctypes.POINTER(GUID)).contents 450 except WindowsError: 451 log.debugWarning("msftedit not available, couldn't retrieve IID_ITextServices") 452 IAccessible.IID_ITextServices=None 453 if IAccessible.IID_ITextServices: 454 try: 455 pDoc=self.IAccessibleObject.QueryInterface(IServiceProvider).QueryService(IAccessible.IID_ITextServices,ITextDocument) 456 except COMError: 457 pDoc=None 458 if pDoc: 459 self._ITextDocumentObject=pDoc 460 self.useITextDocumentSupport=True 461 self.editAPIVersion=2 462 from NVDAObjects.window.edit import Edit 463 clsList.append(Edit) 464 465 #Window root IAccessibles 466 if self.event_childID==0 and self.IAccessibleRole==oleacc.ROLE_SYSTEM_WINDOW: 467 clsList.append(WindowRoot if self.event_objectID==winUser.OBJID_WINDOW else GenericWindow) 468 469 if self.event_objectID==winUser.OBJID_TITLEBAR and self.event_childID==0: 470 clsList.append(Titlebar) 471 472 clsList.append(IAccessible) 473 474 475 if self.event_objectID==winUser.OBJID_CLIENT and self.event_childID==0: 476 # This is the main (client) area of the window, so we can use other classes at the window level. 477 super(IAccessible,self).findOverlayClasses(clsList) 478 #Generic client IAccessibles with no children should be classed as content and should use displayModel 479 if clsList[0]==IAccessible and len(clsList)==3 and self.IAccessibleRole==oleacc.ROLE_SYSTEM_CLIENT and self.childCount==0: 480 clsList.insert(0,ContentGenericClient)
481
482 - def __init__(self,windowHandle=None,IAccessibleObject=None,IAccessibleChildID=None,event_windowHandle=None,event_objectID=None,event_childID=None):
483 """ 484 @param pacc: a pointer to an IAccessible object 485 @type pacc: ctypes.POINTER(IAccessible) 486 @param child: A child ID that will be used on all methods of the IAccessible pointer 487 @type child: int 488 @param hwnd: the window handle, if known 489 @type hwnd: int 490 @param objectID: the objectID for the IAccessible Object, if known 491 @type objectID: int 492 """ 493 # Try every trick in the book to get the window handle if we don't have it. 494 if not windowHandle and isinstance(IAccessibleObject,IAccessibleHandler.IAccessible2): 495 try: 496 windowHandle=IAccessibleObject.windowHandle 497 except COMError, e: 498 log.debugWarning("IAccessible2::windowHandle failed: %s" % e) 499 #Mozilla Gecko: we can never use a MozillaWindowClass window for Gecko 1.9 500 tempWindow=windowHandle 501 while tempWindow and winUser.getClassName(tempWindow)=="MozillaWindowClass": 502 tempWindow=winUser.getAncestor(tempWindow,winUser.GA_PARENT) 503 if tempWindow and winUser.getClassName(tempWindow).startswith('Mozilla'): 504 windowHandle=tempWindow 505 try: 506 Identity=IAccessibleHandler.getIAccIdentity(IAccessibleObject,IAccessibleChildID) 507 except COMError: 508 Identity=None 509 if event_windowHandle is None and Identity and 'windowHandle' in Identity: 510 event_windowHandle=Identity['windowHandle'] 511 if event_objectID is None and Identity and 'objectID' in Identity: 512 event_objectID=Identity['objectID'] 513 if event_childID is None and Identity and 'childID' in Identity: 514 event_childID=Identity['childID'] 515 if not windowHandle and event_windowHandle: 516 windowHandle=event_windowHandle 517 if not windowHandle: 518 windowHandle=IAccessibleHandler.windowFromAccessibleObject(IAccessibleObject) 519 if not windowHandle: 520 log.debugWarning("Resorting to WindowFromPoint on accLocation") 521 try: 522 left,top,width,height = IAccessibleObject.accLocation(0) 523 windowHandle=winUser.user32.WindowFromPoint(winUser.POINT(left,top)) 524 except COMError, e: 525 log.debugWarning("accLocation failed: %s" % e) 526 if not windowHandle: 527 raise InvalidNVDAObject("Can't get a window handle from IAccessible") 528 529 if isinstance(IAccessibleObject,IAccessibleHandler.IAccessible2): 530 try: 531 self.IA2UniqueID=IAccessibleObject.uniqueID 532 except COMError: 533 log.debugWarning("could not get IAccessible2::uniqueID to use as IA2UniqueID",exc_info=True) 534 535 # Set the event params based on our calculated/construction info if we must. 536 if event_windowHandle is None: 537 event_windowHandle=windowHandle 538 if event_objectID is None and isinstance(IAccessibleObject,IAccessibleHandler.IAccessible2): 539 event_objectID=winUser.OBJID_CLIENT 540 if event_childID is None: 541 if self.IA2UniqueID is not None: 542 event_childID=self.IA2UniqueID 543 else: 544 event_childID=IAccessibleChildID 545 546 self.IAccessibleObject=IAccessibleObject 547 self.IAccessibleChildID=IAccessibleChildID 548 self.event_windowHandle=event_windowHandle 549 self.event_objectID=event_objectID 550 self.event_childID=event_childID 551 super(IAccessible,self).__init__(windowHandle=windowHandle) 552 553 try: 554 self.IAccessibleActionObject=IAccessibleObject.QueryInterface(IAccessibleHandler.IAccessibleAction) 555 except COMError: 556 pass 557 try: 558 self.IAccessibleTableObject=self.IAccessibleObject.QueryInterface(IAccessibleHandler.IAccessibleTable) 559 except COMError: 560 pass 561 try: 562 self.IAccessibleTextObject=IAccessibleObject.QueryInterface(IAccessibleHandler.IAccessibleText) 563 except COMError: 564 pass 565 if None not in (event_windowHandle,event_objectID,event_childID): 566 IAccessibleHandler.liveNVDAObjectTable[(event_windowHandle,event_objectID,event_childID)]=self
567
568 - def isDuplicateIAccessibleEvent(self,obj):
569 """Compaires the object of an event to self to see if the event should be treeted as duplicate.""" 570 #MSAA child elements do not have unique winEvent params as a childID could be reused if an element was deleted etc 571 if self.IAccessibleChildID>0: 572 return False 573 return obj.event_windowHandle==self.event_windowHandle and obj.event_objectID==self.event_objectID and obj.event_childID==self.event_childID
574
576 """Determine whether a focus event should be allowed for this object. 577 Normally, this checks for the focused state to help eliminate redundant or invalid focus events. 578 However, some implementations do not correctly set the focused state, so this must be overridden. 579 @return: C{True} if the focus event should be allowed. 580 @rtype: bool 581 """ 582 #this object or one of its ancestors must have state_focused. 583 testObj = self 584 while testObj: 585 if controlTypes.STATE_FOCUSED in testObj.states: 586 break 587 parent = testObj.parent 588 # Cache the parent. 589 testObj.parent = parent 590 testObj = parent 591 else: 592 return False 593 return True
594
595 - def _get_TextInfo(self):
596 if hasattr(self,'IAccessibleTextObject'): 597 return IA2TextTextInfo 598 return super(IAccessible,self).TextInfo
599
600 - def _isEqual(self,other):
601 if self.IAccessibleChildID!=other.IAccessibleChildID: 602 return False 603 if self.IAccessibleObject==other.IAccessibleObject: 604 return True 605 try: 606 if isinstance(self.IAccessibleObject,IAccessibleHandler.IAccessible2) and isinstance(other.IAccessibleObject,IAccessibleHandler.IAccessible2): 607 # These are both IAccessible2 objects, so we can test unique ID. 608 # Unique ID is only guaranteed to be unique within a given window, so we must check window handle as well. 609 selfIA2Window=self.IAccessibleObject.windowHandle 610 selfIA2ID=self.IA2UniqueID 611 otherIA2Window=other.IAccessibleObject.windowHandle 612 otherIA2ID=other.IA2UniqueID 613 if selfIA2Window!=otherIA2Window: 614 # The window handles are different, so these are definitely different windows. 615 return False 616 # At this point, we know that the window handles are equal. 617 if selfIA2Window and (selfIA2ID or otherIA2ID): 618 # The window handles are valid and one of the objects has a valid unique ID. 619 # Therefore, we can safely determine equality or inequality based on unique ID. 620 return selfIA2ID==otherIA2ID 621 except COMError: 622 pass 623 if self.event_windowHandle is not None and other.event_windowHandle is not None and self.event_windowHandle!=other.event_windowHandle: 624 return False 625 if self.event_objectID is not None and other.event_objectID is not None and self.event_objectID!=other.event_objectID: 626 return False 627 if self.event_childID is not None and other.event_childID is not None and self.event_childID!=other.event_childID: 628 return False 629 if not super(IAccessible,self)._isEqual(other): 630 return False 631 selfIden=self.IAccessibleIdentity 632 otherIden=other.IAccessibleIdentity 633 if selfIden!=otherIden: 634 return False 635 if self.location!=other.location: 636 return False 637 if self.IAccessibleRole!=other.IAccessibleRole: 638 return False 639 if self.name!=other.name: 640 return False 641 return True
642
643 - def _get_name(self):
644 #The edit field in a combo box should not have a label 645 if self.role==controlTypes.ROLE_EDITABLETEXT: 646 # Make sure to cache the parents. 647 parent=self.parent=self.parent 648 if parent and parent.role==controlTypes.ROLE_WINDOW: 649 # The parent of the edit field is a window, so try the next ancestor. 650 parent=self.parent.parent=self.parent.parent 651 # Only scrap the label on the edit field if the parent combo box has a label. 652 if parent and parent.role==controlTypes.ROLE_COMBOBOX and parent.name: 653 return "" 654 655 try: 656 res=self.IAccessibleObject.accName(self.IAccessibleChildID) 657 except COMError: 658 res=None 659 if not res and hasattr(self,'IAccessibleTextObject'): 660 try: 661 res=self.makeTextInfo(textInfos.POSITION_CARET).text 662 if res: 663 return 664 except (NotImplementedError, RuntimeError): 665 try: 666 res=self.makeTextInfo(textInfos.POSITION_ALL).text 667 except (NotImplementedError, RuntimeError): 668 res=None 669 return res if isinstance(res,basestring) and not res.isspace() else None
670
671 - def _get_value(self):
672 try: 673 res=self.IAccessibleObject.accValue(self.IAccessibleChildID) 674 except COMError: 675 res=None 676 return res if isinstance(res,basestring) and not res.isspace() else None
677
678 - def _get_actionCount(self):
679 if hasattr(self,'IAccessibleActionObject'): 680 try: 681 return self.IAccessibleActionObject.nActions() 682 except COMError: 683 return 0 684 return 1
685
686 - def getActionName(self,index=None):
687 if not index: 688 index=self.defaultActionIndex 689 if hasattr(self,'IAccessibleActionObject'): 690 try: 691 return self.IAccessibleActionObject.name(index) 692 except COMError: 693 raise NotImplementedError 694 elif index==0: 695 try: 696 action=self.IAccessibleObject.accDefaultAction(self.IAccessibleChildID) 697 except COMError: 698 action=None 699 if action: 700 return action 701 raise NotImplementedError
702
703 - def doAction(self,index=None):
704 if not index: 705 index=self.defaultActionIndex 706 if hasattr(self,'IAccessibleActionObject'): 707 try: 708 self.IAccessibleActionObject.doAction(index) 709 return 710 except COMError: 711 raise NotImplementedError 712 elif index==0: 713 try: 714 self.IAccessibleObject.accDoDefaultAction(self.IAccessibleChildID) 715 return 716 except COMError: 717 raise NotImplementedError 718 raise NotImplementedError
719
720 - def _get_IAccessibleIdentity(self):
721 if not hasattr(self,'_IAccessibleIdentity'): 722 try: 723 self._IAccessibleIdentity=IAccessibleHandler.getIAccIdentity(self.IAccessibleObject,self.IAccessibleChildID) 724 except COMError: 725 self._IAccessibleIdentity=None 726 return self._IAccessibleIdentity
727
728 - def _get_IAccessibleRole(self):
729 if isinstance(self.IAccessibleObject,IAccessibleHandler.IAccessible2): 730 try: 731 role=self.IAccessibleObject.role() 732 except COMError: 733 role=0 734 else: 735 role=0 736 if role==0: 737 try: 738 role=self.IAccessibleObject.accRole(self.IAccessibleChildID) 739 except COMError: 740 role=0 741 return role
742 743
744 - def _get_role(self):
745 IARole=self.IAccessibleRole 746 if IARole==oleacc.ROLE_SYSTEM_CLIENT: 747 superRole=super(IAccessible,self).role 748 if superRole!=controlTypes.ROLE_WINDOW: 749 return superRole 750 if isinstance(IARole,basestring): 751 IARole=IARole.split(',')[0].lower() 752 log.debug("IARole: %s"%IARole) 753 return IAccessibleHandler.IAccessibleRolesToNVDARoles.get(IARole,controlTypes.ROLE_UNKNOWN)
754
755 - def _get_IAccessibleStates(self):
756 try: 757 res=self.IAccessibleObject.accState(self.IAccessibleChildID) 758 except COMError: 759 return 0 760 return res if isinstance(res,int) else 0
761
762 - def _get_states(self):
763 states=set() 764 if self.event_objectID in (winUser.OBJID_CLIENT, winUser.OBJID_WINDOW) and self.event_childID == 0: 765 states.update(super(IAccessible, self).states) 766 try: 767 IAccessibleStates=self.IAccessibleStates 768 except COMError: 769 log.debugWarning("could not get IAccessible states",exc_info=True) 770 else: 771 states.update(IAccessibleHandler.IAccessibleStatesToNVDAStates[x] for x in (y for y in (1<<z for z in xrange(32)) if y&IAccessibleStates) if IAccessibleHandler.IAccessibleStatesToNVDAStates.has_key(x)) 772 if not hasattr(self.IAccessibleObject,'states'): 773 # Not an IA2 object. 774 return states 775 try: 776 IAccessible2States=self.IAccessibleObject.states 777 except COMError: 778 log.debugWarning("could not get IAccessible2 states",exc_info=True) 779 IAccessible2States=IAccessibleHandler.IA2_STATE_DEFUNCT 780 states=states|set(IAccessibleHandler.IAccessible2StatesToNVDAStates[x] for x in (y for y in (1<<z for z in xrange(32)) if y&IAccessible2States) if IAccessibleHandler.IAccessible2StatesToNVDAStates.has_key(x)) 781 try: 782 IA2Attribs=self.IA2Attributes 783 except COMError: 784 log.debugWarning("could not get IAccessible2 attributes",exc_info=True) 785 IA2Attribs=None 786 if IA2Attribs: 787 grabbed = IA2Attribs.get("grabbed") 788 if grabbed == "false": 789 states.add(controlTypes.STATE_DRAGGABLE) 790 elif grabbed == "true": 791 states.add(controlTypes.STATE_DRAGGING) 792 if IA2Attribs.get("dropeffect", "none") != "none": 793 states.add(controlTypes.STATE_DROPTARGET) 794 sorted = IA2Attribs.get("sort") 795 if sorted=="ascending": 796 states.add(controlTypes.STATE_SORTED_ASCENDING) 797 elif sorted=="descending": 798 states.add(controlTypes.STATE_SORTED_DESCENDING) 799 elif sorted=="other": 800 states.add(controlTypes.STATE_SORTED) 801 if controlTypes.STATE_HASPOPUP in states and controlTypes.STATE_AUTOCOMPLETE in states: 802 states.remove(controlTypes.STATE_HASPOPUP) 803 if controlTypes.STATE_HALFCHECKED in states: 804 states.discard(controlTypes.STATE_CHECKED) 805 return states
806 807 re_positionInfoEncodedAccDescription=re.compile(r"L(?P<level>\d+)(?:, (?P<indexInGroup>\d+) of (?P<similarItemsInGroup>\d+))?") 808
809 - def _get_decodedAccDescription(self):
810 try: 811 description=self.IAccessibleObject.accDescription(self.IAccessibleChildID) 812 except COMError: 813 return None 814 if not description: 815 return None 816 if description.lower().startswith('description:'): 817 return description[12:].strip() 818 m=self.re_positionInfoEncodedAccDescription.match(description) 819 if m: 820 return m 821 return description
822 823 hasEncodedAccDescription=False #:If true, accDescription contains info such as level, and number of items etc. 824
825 - def _get_description(self):
826 if self.hasEncodedAccDescription: 827 d=self.decodedAccDescription 828 if isinstance(d,basestring): 829 return d 830 else: 831 return "" 832 try: 833 res=self.IAccessibleObject.accDescription(self.IAccessibleChildID) 834 except COMError: 835 res=None 836 return res if isinstance(res,basestring) and not res.isspace() else None
837
838 - def _get_keyboardShortcut(self):
839 try: 840 res=self.IAccessibleObject.accKeyboardShortcut(self.IAccessibleChildID) 841 except COMError: 842 res=None 843 return res if isinstance(res,basestring) and not res.isspace() else None
844
845 - def _get_childCount(self):
846 if self.IAccessibleChildID!=0: 847 return 0 848 try: 849 return max(self.IAccessibleObject.accChildCount,0) 850 except COMError: 851 return 0
852
853 - def _get_location(self):
854 try: 855 return self.IAccessibleObject.accLocation(self.IAccessibleChildID) 856 except COMError: 857 return None
858
859 - def isPointInObject(self,x,y):
860 if self.windowHandle and not super(IAccessible,self).isPointInObject(x,y): 861 return False 862 res=IAccessibleHandler.accHitTest(self.IAccessibleObject,self.IAccessibleChildID,x,y) 863 if not res or res[0]!=self.IAccessibleObject or res[1]!=self.IAccessibleChildID: 864 return False 865 return True
866
867 - def _get_labeledBy(self):
868 try: 869 (pacc,accChild)=IAccessibleHandler.accNavigate(self.IAccessibleObject,self.IAccessibleChildID,IAccessibleHandler.NAVRELATION_LABELLED_BY) 870 obj=IAccessible(IAccessibleObject=pacc,IAccessibleChildID=accChild) 871 return obj 872 except COMError: 873 return None
874
875 - def _get_parent(self):
876 if self.IAccessibleChildID!=0: 877 return IAccessible(windowHandle=self.windowHandle,IAccessibleObject=self.IAccessibleObject,IAccessibleChildID=0,event_windowHandle=self.event_windowHandle,event_objectID=self.event_objectID,event_childID=0) or super(IAccessible,self).parent 878 res=IAccessibleHandler.accParent(self.IAccessibleObject,self.IAccessibleChildID) 879 if res: 880 parentObj=IAccessible(IAccessibleObject=res[0],IAccessibleChildID=res[1]) 881 if parentObj: 882 #Hack around bad MSAA implementations that deliberately skip the window root IAccessible in the ancestry (Skype, iTunes) 883 if parentObj.windowHandle!=self.windowHandle and self.IAccessibleRole!=oleacc.ROLE_SYSTEM_WINDOW and winUser.getAncestor(self.windowHandle,winUser.GA_PARENT)==parentObj.windowHandle: 884 windowObj=Window(windowHandle=self.windowHandle) 885 if windowObj and windowObj.IAccessibleRole==oleacc.ROLE_SYSTEM_WINDOW and windowObj.parent==parentObj: 886 return windowObj 887 return self.correctAPIForRelation(parentObj,relation="parent") or super(IAccessible,self).parent 888 return super(IAccessible,self).parent
889
890 - def _get_next(self):
891 res=IAccessibleHandler.accNavigate(self.IAccessibleObject,self.IAccessibleChildID,oleacc.NAVDIR_NEXT) 892 if not res: 893 return None 894 if res[0]==self.IAccessibleObject: 895 #A sanity check for childIDs. 896 if self.IAccessibleChildID>0 and res[1]>self.IAccessibleChildID: 897 return IAccessible(windowHandle=self.windowHandle,IAccessibleObject=self.IAccessibleObject,IAccessibleChildID=res[1],event_windowHandle=self.event_windowHandle,event_objectID=self.event_objectID,event_childID=res[1]) 898 else: 899 return self.correctAPIForRelation(IAccessible(IAccessibleObject=res[0],IAccessibleChildID=res[1]))
900
901 - def _get_previous(self):
902 res=IAccessibleHandler.accNavigate(self.IAccessibleObject,self.IAccessibleChildID,oleacc.NAVDIR_PREVIOUS) 903 if not res: 904 return None 905 if res[0]==self.IAccessibleObject: 906 #A sanity check for childIDs. 907 if self.IAccessibleChildID>1 and res[1]<self.IAccessibleChildID: 908 return IAccessible(windowHandle=self.windowHandle,IAccessibleObject=self.IAccessibleObject,IAccessibleChildID=res[1],event_windowHandle=self.event_windowHandle,event_objectID=self.event_objectID,event_childID=res[1]) 909 else: 910 return self.correctAPIForRelation(IAccessible(IAccessibleObject=res[0],IAccessibleChildID=res[1]))
911
912 - def _get_firstChild(self):
913 child=IAccessibleHandler.accNavigate(self.IAccessibleObject,self.IAccessibleChildID,oleacc.NAVDIR_FIRSTCHILD) 914 if not child and self.IAccessibleChildID==0: 915 children=IAccessibleHandler.accessibleChildren(self.IAccessibleObject,0,1) 916 if len(children)>0: 917 child=children[0] 918 if child and child[0]==self.IAccessibleObject: 919 #A sanity check for childIDs. 920 if self.IAccessibleChildID==0 and child[1]>0: 921 return IAccessible(windowHandle=self.windowHandle,IAccessibleObject=self.IAccessibleObject,IAccessibleChildID=child[1],event_windowHandle=self.event_windowHandle,event_objectID=self.event_objectID,event_childID=child[1]) 922 elif child: 923 obj=IAccessible(IAccessibleObject=child[0],IAccessibleChildID=child[1]) 924 if (obj and winUser.isDescendantWindow(self.windowHandle,obj.windowHandle)) or self.windowHandle==winUser.getDesktopWindow(): 925 return self.correctAPIForRelation(obj)
926
927 - def _get_lastChild(self):
928 child=IAccessibleHandler.accNavigate(self.IAccessibleObject,self.IAccessibleChildID,oleacc.NAVDIR_LASTCHILD) 929 if not child and self.IAccessibleChildID==0: 930 try: 931 childCount=self.IAccessibleObject.accChildCount 932 except COMError: 933 childCount=0 934 if childCount>0: 935 children=IAccessibleHandler.accessibleChildren(self.IAccessibleObject,childCount-1,1) 936 if len(children)>0: 937 child=children[-1] 938 if child and child[0]==self.IAccessibleObject: 939 #A sanity check for childIDs. 940 if self.IAccessibleChildID==0 and child[1]>0: 941 return IAccessible(windowHandle=self.windowHandle,IAccessibleObject=self.IAccessibleObject,IAccessibleChildID=child[1],event_windowHandle=self.event_windowHandle,event_objectID=self.event_objectID,event_childID=child[1]) 942 elif child: 943 obj=IAccessible(IAccessibleObject=child[0],IAccessibleChildID=child[1]) 944 if (obj and winUser.isDescendantWindow(self.windowHandle,obj.windowHandle)) or self.windowHandle==winUser.getDesktopWindow(): 945 return self.correctAPIForRelation(obj)
946
947 - def _get_children(self):
948 if self.IAccessibleChildID!=0: 949 return [] 950 try: 951 childCount= self.IAccessibleObject.accChildCount 952 except COMError: 953 childCount=0 954 if childCount<=0: 955 return [] 956 children=[] 957 for IAccessibleObject,IAccessibleChildID in IAccessibleHandler.accessibleChildren(self.IAccessibleObject,0,childCount): 958 if IAccessibleObject==self.IAccessibleObject: 959 children.append(IAccessible(windowHandle=self.windowHandle,IAccessibleObject=self.IAccessibleObject,IAccessibleChildID=IAccessibleChildID,event_windowHandle=self.event_windowHandle,event_objectID=self.event_objectID,event_childID=IAccessibleChildID)) 960 continue 961 try: 962 identity=IAccessibleHandler.getIAccIdentity(IAccessibleObject,0) 963 except COMError: 964 identity=None 965 #For Window root IAccessibles, we just want to use the new window handle, but use the best API for that window, rather than IAccessible 966 #If it does happen to be IAccessible though, we only want the client, not the window root IAccessible 967 if identity and identity.get('objectID',None)==0 and identity.get('childID',None)==0: 968 windowHandle=identity.get('windowHandle',None) 969 if windowHandle: 970 kwargs=dict(windowHandle=windowHandle) 971 APIClass=Window.findBestAPIClass(kwargs,relation="parent") #Need a better relation type for this, but parent works ok -- gives the client 972 children.append(APIClass(**kwargs)) 973 continue 974 children.append(IAccessible(IAccessibleObject=IAccessibleObject,IAccessibleChildID=IAccessibleChildID)) 975 children=[x for x in children if x and winUser.isDescendantWindow(self.windowHandle,x.windowHandle)] 976 return children
977
978 - def _get_IA2Attributes(self):
979 try: 980 attribs = self.IAccessibleObject.attributes 981 except COMError as e: 982 log.debugWarning("IAccessibleObject.attributes COMError %s"%e) 983 attribs=None 984 if attribs: 985 return IAccessibleHandler.splitIA2Attribs(attribs) 986 return {}
987
988 - def event_IA2AttributeChange(self):
989 # We currently only care about changes to the accessible drag and drop attributes, which we map to states, so treat this as a stateChange. 990 self.event_stateChange()
991
992 - def _get_rowNumber(self):
993 table=self.table 994 if table: 995 if self.IAccessibleTableUsesTableCellIndexAttrib: 996 try: 997 index=self.IA2Attributes['table-cell-index'] 998 except KeyError: 999 raise NotImplementedError 1000 else: 1001 index=self.IAccessibleObject.indexInParent 1002 index=int(index) 1003 try: 1004 return table.IAccessibleTableObject.rowIndex(index)+1 1005 except COMError: 1006 log.debugWarning("IAccessibleTable::rowIndex failed", exc_info=True) 1007 raise NotImplementedError
1008
1009 - def _get_columnNumber(self):
1010 table=self.table 1011 if table: 1012 if self.IAccessibleTableUsesTableCellIndexAttrib: 1013 try: 1014 index=self.IA2Attributes['table-cell-index'] 1015 except KeyError: 1016 raise NotImplementedError 1017 else: 1018 index=self.IAccessibleObject.indexInParent 1019 index=int(index) 1020 try: 1021 return table.IAccessibleTableObject.columnIndex(index)+1 1022 except COMError: 1023 log.debugWarning("IAccessibleTable::columnIndex failed", exc_info=True) 1024 raise NotImplementedError
1025
1026 - def _get_rowCount(self):
1027 if hasattr(self,'IAccessibleTableObject'): 1028 try: 1029 return self.IAccessibleTableObject.nRows 1030 except COMError: 1031 log.debugWarning("IAccessibleTable::nRows failed", exc_info=True) 1032 raise NotImplementedError
1033
1034 - def _get_columnCount(self):
1035 if hasattr(self,'IAccessibleTableObject'): 1036 try: 1037 return self.IAccessibleTableObject.nColumns 1038 except COMError: 1039 log.debugWarning("IAccessibleTable::nColumns failed", exc_info=True) 1040 raise NotImplementedError
1041
1042 - def _get_table(self):
1043 if not isinstance(self.IAccessibleObject,IAccessibleHandler.IAccessible2): 1044 return None 1045 table=getattr(self,'_table',None) 1046 if table: 1047 return table 1048 checkAncestors=False 1049 if self.IAccessibleTableUsesTableCellIndexAttrib: 1050 try: 1051 attribs=self.IAccessibleObject.attributes 1052 except COMError: 1053 attribs=None 1054 if attribs and 'table-cell-index:' in attribs: 1055 checkAncestors=True 1056 obj=self.parent 1057 while checkAncestors and obj and not hasattr(obj,'IAccessibleTableObject'): 1058 parent=obj.parent=obj.parent 1059 obj=parent 1060 if not obj or not hasattr(obj,'IAccessibleTableObject'): 1061 return None 1062 self._table=obj 1063 return obj
1064
1065 - def _get_activeChild(self):
1066 if self.IAccessibleChildID==0: 1067 res=IAccessibleHandler.accFocus(self.IAccessibleObject) 1068 if res: 1069 if res[0]==self.IAccessibleObject: 1070 return IAccessible(windowHandle=self.windowHandle,IAccessibleObject=self.IAccessibleObject,IAccessibleChildID=res[1],event_windowHandle=self.event_windowHandle,event_objectID=self.event_objectID,event_childID=res[1]) 1071 return IAccessible(IAccessibleObject=res[0],IAccessibleChildID=res[1])
1072
1073 - def _get_hasFocus(self):
1074 if (self.IAccessibleStates&oleacc.STATE_SYSTEM_FOCUSED): 1075 return True 1076 else: 1077 return False
1078
1079 - def setFocus(self):
1080 try: 1081 self.IAccessibleObject.accSelect(1,self.IAccessibleChildID) 1082 except COMError: 1083 pass
1084
1085 - def scrollIntoView(self):
1086 if isinstance(self.IAccessibleObject, IAccessibleHandler.IAccessible2): 1087 try: 1088 self.IAccessibleObject.scrollTo(IAccessibleHandler.IA2_SCROLL_TYPE_ANYWHERE) 1089 except COMError: 1090 log.debugWarning("IAccessible2::scrollTo failed", exc_info=True)
1091
1093 """if true position info should fall back to using the childID and the parent's accChildCount for position information if there is nothing better available.""" 1094 return config.conf["presentation"]["guessObjectPositionInformationWhenUnavailable"]
1095
1096 - def _get_positionInfo(self):
1097 if isinstance(self.IAccessibleObject,IAccessibleHandler.IAccessible2): 1098 try: 1099 info={} 1100 info["level"],info["similarItemsInGroup"],info["indexInGroup"]=self.IAccessibleObject.groupPosition 1101 # 0 means not applicable, so remove it. 1102 for key, val in info.items(): 1103 if not val: 1104 del info[key] 1105 return info 1106 except COMError: 1107 pass 1108 if self.hasEncodedAccDescription: 1109 d=self.decodedAccDescription 1110 if d and not isinstance(d,basestring): 1111 groupdict=d.groupdict() 1112 return {x:int(y) for x,y in groupdict.iteritems() if y is not None} 1113 if self.allowIAccessibleChildIDAndChildCountForPositionInfo and self.IAccessibleChildID>0: 1114 indexInGroup=self.IAccessibleChildID 1115 parent=self.parent 1116 if parent: 1117 similarItemsInGroup=parent.childCount 1118 return dict(indexInGroup=indexInGroup,similarItemsInGroup=similarItemsInGroup) 1119 return {}
1120
1121 - def _get_indexInParent(self):
1122 if isinstance(self.IAccessibleObject, IAccessibleHandler.IAccessible2): 1123 try: 1124 return self.IAccessibleObject.indexInParent 1125 except COMError: 1126 pass 1127 raise NotImplementedError
1128
1129 - def _get__IA2Relations(self):
1130 if not isinstance(self.IAccessibleObject, IAccessibleHandler.IAccessible2): 1131 raise NotImplementedError 1132 import ctypes 1133 import comtypes.hresult 1134 try: 1135 size = self.IAccessibleObject.nRelations 1136 except COMError: 1137 raise NotImplementedError 1138 if size <= 0: 1139 return () 1140 relations = (ctypes.POINTER(IAccessibleHandler.IAccessibleRelation) * size)() 1141 count = ctypes.c_int() 1142 # The client allocated relations array is an [out] parameter instead of [in, out], so we need to use the raw COM method. 1143 res = self.IAccessibleObject._IAccessible2__com__get_relations(size, relations, ctypes.byref(count)) 1144 if res != comtypes.hresult.S_OK: 1145 raise NotImplementedError 1146 return list(relations)
1147
1148 - def _getIA2RelationFirstTarget(self, relationType):
1149 for relation in self._IA2Relations: 1150 try: 1151 if relation.relationType == relationType: 1152 return IAccessible(IAccessibleObject=IAccessibleHandler.normalizeIAccessible(relation.target(0)), IAccessibleChildID=0) 1153 except COMError: 1154 pass 1155 return None
1156
1157 - def _get_flowsTo(self):
1159
1160 - def _get_flowsFrom(self):
1162
1163 - def _get_embeddingTextInfo(self):
1164 if not hasattr(self, "IAccessibleTextObject"): 1165 raise NotImplementedError 1166 try: 1167 hl = self.IAccessibleTextObject.QueryInterface(IAccessibleHandler.IAccessibleHyperlink) 1168 hlOffset = hl.startIndex 1169 return self.parent.makeTextInfo(textInfos.offsets.Offsets(hlOffset, hlOffset + 1)) 1170 except COMError: 1171 pass 1172 return None
1173
1174 - def event_valueChange(self):
1175 if hasattr(self,'IAccessibleTextObject'): 1176 self.hasContentChangedSinceLastSelection=True 1177 return 1178 return super(IAccessible,self).event_valueChange()
1179
1180 - def event_alert(self):
1181 if self.role != controlTypes.ROLE_ALERT: 1182 # Ignore alert events on objects that aren't alerts. 1183 return 1184 # If the focus is within the alert object, don't report anything for it. 1185 if eventHandler.isPendingEvents("gainFocus"): 1186 # The alert event might be fired before the focus. 1187 api.processPendingEvents() 1188 if self in api.getFocusAncestors(): 1189 return 1190 speech.cancelSpeech() 1191 speech.speakObject(self, reason=speech.REASON_FOCUS) 1192 for child in self.recursiveDescendants: 1193 if controlTypes.STATE_FOCUSABLE in child.states: 1194 speech.speakObject(child, reason=speech.REASON_FOCUS)
1195
1196 - def event_caret(self):
1197 super(IAccessible, self).event_caret() 1198 if self.IAccessibleRole==oleacc.ROLE_SYSTEM_CARET: 1199 return 1200 focusObject=api.getFocusObject() 1201 if self!=focusObject and not self.treeInterceptor and hasattr(self,'IAccessibleTextObject'): 1202 inDocument=None 1203 for ancestor in reversed(api.getFocusAncestors()+[focusObject]): 1204 if ancestor.role==controlTypes.ROLE_DOCUMENT: 1205 inDocument=ancestor 1206 break 1207 if not inDocument: 1208 return 1209 parent=self 1210 caretInDocument=False 1211 while parent: 1212 if parent==inDocument: 1213 caretInDocument=True 1214 break 1215 parent=parent.parent 1216 if not caretInDocument: 1217 return 1218 try: 1219 info=self.makeTextInfo(textInfos.POSITION_CARET) 1220 except RuntimeError: 1221 return 1222 info.expand(textInfos.UNIT_CHARACTER) 1223 try: 1224 char=ord(info.text) 1225 except TypeError: 1226 char=0 1227 if char!=0xfffc: 1228 IAccessibleHandler.processFocusNVDAEvent(self)
1229
1230 - def _get_groupName(self):
1231 return None 1232 if self.IAccessibleChildID>0: 1233 return None 1234 else: 1235 return super(IAccessible,self)._get_groupName()
1236
1237 - def event_selection(self):
1238 return self.event_stateChange()
1239
1240 - def event_selectionAdd(self):
1241 return self.event_stateChange()
1242
1243 - def event_selectionRemove(self):
1244 return self.event_stateChange()
1245
1246 - def event_selectionWithIn(self):
1247 return self.event_stateChange()
1248
1249 - def _get_presentationType(self):
1250 if not self.windowHasExtraIAccessibles(self.windowHandle) and self.role==controlTypes.ROLE_WINDOW: 1251 return self.presType_layout 1252 return super(IAccessible,self).presentationType
1253
1255 IARole = self.IAccessibleRole 1256 if IARole == oleacc.ROLE_SYSTEM_CLIENT and self.windowStyle & winUser.WS_SYSMENU: 1257 return True 1258 if IARole == oleacc.ROLE_SYSTEM_WINDOW: 1259 return False 1260 return super(IAccessible, self).isPresentableFocusAncestor
1261
1262 - def _get_devInfo(self):
1263 info = super(IAccessible, self).devInfo 1264 iaObj = self.IAccessibleObject 1265 info.append("IAccessibleObject: %r" % iaObj) 1266 childID = self.IAccessibleChildID 1267 info.append("IAccessibleChildID: %r" % childID) 1268 info.append("IAccessible event parameters: windowHandle=%r, objectID=%r, childID=%r" % (self.event_windowHandle, self.event_objectID, self.event_childID)) 1269 try: 1270 ret = iaObj.accRole(childID) 1271 for name, const in oleacc.__dict__.iteritems(): 1272 if not name.startswith("ROLE_"): 1273 continue 1274 if ret == const: 1275 ret = name 1276 break 1277 else: 1278 ret = repr(ret) 1279 except Exception as e: 1280 ret = "exception: %s" % e 1281 info.append("IAccessible accRole: %s" % ret) 1282 try: 1283 temp = iaObj.accState(childID) 1284 ret = ", ".join( 1285 name for name, const in oleacc.__dict__.iteritems() 1286 if name.startswith("STATE_") and temp & const 1287 ) + " (%d)" % temp 1288 except Exception as e: 1289 ret = "exception: %s" % e 1290 info.append("IAccessible accState: %s" % ret) 1291 return info
1292
1293 -class ContentGenericClient(IAccessible):
1294 1295 TextInfo=displayModel.DisplayModelTextInfo 1296 presentationType=IAccessible.presType_content 1297 role=controlTypes.ROLE_UNKNOWN 1298
1299 - def _get_value(self):
1300 val=self.displayText 1301 truncate=len(val)>200 1302 if truncate: 1303 return u"%s\u2026"%val[:200] 1304 return val
1305
1306 -class GenericWindow(IAccessible):
1307 TextInfo=displayModel.DisplayModelTextInfo
1308
1309 -class WindowRoot(GenericWindow):
1310 1311 parentUsesSuperOnWindowRootIAccessible=True #: on a window root IAccessible, super should be used instead of accParent 1312
1313 - def _get_parent(self):
1314 if self.parentUsesSuperOnWindowRootIAccessible: 1315 return super(IAccessible,self).parent 1316 return super(WindowRoot,self).parent
1317
1318 - def _get_next(self):
1319 return super(IAccessible,self).next
1320
1321 - def _get_previous(self):
1322 return super(IAccessible,self).previous
1323
1324 - def _get_container(self):
1325 #Support for groupbox windows 1326 groupboxObj=IAccessibleHandler.findGroupboxObject(self) 1327 if groupboxObj: 1328 return groupboxObj 1329 return super(WindowRoot,self).container
1330
1331 -class ShellDocObjectView(IAccessible):
1332
1333 - def event_gainFocus(self):
1334 #Sometimes Shell DocObject View gets focus, when really the document inside it should 1335 #Adobe Reader 9 licence agreement 1336 if eventHandler.isPendingEvents("gainFocus") or self.childCount!=1: 1337 return super(ShellDocObjectView,self).event_gainFocus() 1338 child=self.firstChild 1339 if not child or child.windowClassName!="Internet Explorer_Server" or child.role!=controlTypes.ROLE_PANE: 1340 return super(ShellDocObjectView,self).event_gainFocus() 1341 child=child.firstChild 1342 if not child or child.windowClassName!="Internet Explorer_Server" or child.role!=controlTypes.ROLE_DOCUMENT: 1343 return super(ShellDocObjectView,self).event_gainFocus() 1344 eventHandler.queueEvent("gainFocus",child)
1345
1346 -class JavaVMRoot(IAccessible):
1347
1348 - def _get_firstChild(self):
1349 jabContext=JABHandler.JABContext(hwnd=self.windowHandle) 1350 return NVDAObjects.JAB.JAB(jabContext=jabContext)
1351
1352 - def _get_lastChild(self):
1353 jabContext=JABHandler.JABContext(hwnd=self.windowHandle) 1354 return NVDAObjects.JAB.JAB(jabContext=jabContext)
1355
1356 - def _get_children(self):
1357 children=[] 1358 jabContext=JABHandler.JABContext(hwnd=self.windowHandle) 1359 obj=NVDAObjects.JAB.JAB(jabContext=jabContext) 1360 if obj: 1361 children.append(obj) 1362 return children
1363
1364 -class NUIDialogClient(Dialog):
1365 role=controlTypes.ROLE_DIALOG
1366
1367 -class Groupbox(IAccessible):
1368
1369 - def _get_description(self):
1370 next=self.next 1371 if next and next.name==self.name and next.role==controlTypes.ROLE_GRAPHIC: 1372 next=next.next 1373 if next and next.role==controlTypes.ROLE_STATICTEXT: 1374 nextNext=next.next 1375 if nextNext and nextNext.name!=next.name: 1376 return next.name 1377 return super(Groupbox,self)._get_description()
1378
1379 -class TrayClockWClass(IAccessible):
1380 """ 1381 Based on NVDAObject but the role is changed to clock. 1382 """ 1383
1384 - def _get_role(self):
1386
1387 -class OutlineItem(IAccessible):
1388
1389 - def _get_value(self):
1390 val=super(OutlineItem,self)._get_value() 1391 try: 1392 int(val) 1393 except (ValueError, TypeError): 1394 return val
1395
1396 -class Tooltip(IAccessible):
1397
1398 - def event_show(self):
1399 # TODO: Abstract this somehow. 1400 if (config.conf["presentation"]["reportTooltips"] and (self.IAccessibleRole==oleacc.ROLE_SYSTEM_TOOLTIP)) or (config.conf["presentation"]["reportHelpBalloons"] and (self.IAccessibleRole==oleacc.ROLE_SYSTEM_HELPBALLOON)): 1401 speech.speakObject(self,reason=speech.REASON_FOCUS) 1402 # TODO: Don't use getBrailleTextForProperties directly. 1403 braille.handler.message(braille.getBrailleTextForProperties(name=self.name, role=self.role))
1404
1405 -class List(IAccessible):
1406
1407 - def _get_role(self):
1408 return controlTypes.ROLE_LIST
1409
1410 -class SysLinkClient(IAccessible):
1411
1412 - def reportFocus(self):
1413 pass
1414
1415 - def _get_role(self):
1416 if self.childCount==0: 1417 return controlTypes.ROLE_LINK 1418 return super(SysLinkClient,self).role
1419 1430
1431 -class TaskList(IAccessible):
1432 isPresentableFocusAncestor = False 1433
1434 - def event_gainFocus(self):
1435 # Normally, we don't want to act on this focus event. 1436 if self.childCount == 0: 1437 # However, in Windows 7, the task list gets focus even if alt+tab is pressed with no applications open. 1438 # In this case, we must report the focus so the user knows where the focus has landed. 1439 return super(TaskList, self).event_gainFocus()
1440
1441 -class TaskListIcon(IAccessible):
1442 1443 allowIAccessibleChildIDAndChildCountForPositionInfo=True 1444
1445 - def _get_role(self):
1446 return controlTypes.ROLE_ICON
1447
1448 - def reportFocus(self):
1449 if controlTypes.STATE_INVISIBLE in self.states: 1450 return 1451 super(TaskListIcon,self).reportFocus()
1452 1470
1471 -class Taskbar(IAccessible):
1472 name = _("Taskbar")
1473
1474 -class Button(IAccessible):
1475
1476 - def _get_name(self):
1477 name=super(Button,self).name 1478 if not name or name.isspace(): 1479 name=self.displayText 1480 return name
1481
1482 -class InaccessibleListBoxItem(IAccessible):
1483 """ 1484 Used for list item IAccessibles in inaccessible owner drawn ListBox controls. 1485 Overrides name to use display model text as MSAA doesn't provide a suitable name (it's usually either empty or contains garbage). 1486 """ 1487
1488 - def _get_name(self):
1489 return self.displayText
1490
1491 -class InaccessibleComboBox(IAccessible):
1492 """ 1493 Used for inaccessible owner drawn ComboBox controls. 1494 Overrides value to use display model text as MSAA doesn't provide a suitable vale (it's usually either empty or contains garbage). 1495 """ 1496
1497 - def _get_value(self):
1498 return self.displayText
1499
1500 -class StaticText(IAccessible):
1501 """Support for owner-drawn staticText controls where accName is empty.""" 1502
1503 - def _get_name(self):
1504 name=super(StaticText,self).name 1505 if not name or name.isspace(): 1506 name=self.displayText 1507 return name
1508
1509 1510 -class Titlebar(IAccessible):
1511 """A class for the standard MSAA titlebar, which shortcuts presentationType to be layout (for performance) and makes the description property empty, as the standard accDescription is rather annoying.""" 1512 1513 presentationType=IAccessible.presType_layout 1514
1515 - def _get_description(self):
1516 return ""
1517
1518 -class ReBarWindow32Client(IAccessible):
1519 """ 1520 The client IAccessible for a ReBarWindow32 window. 1521 Overrides firstChild/lastChild as accNavigate is not implemented, and IEnumVariant (children) gives back some strange buttons beside each child window with no accNavigate. 1522 """ 1523
1524 - def _get_firstChild(self):
1525 return super(IAccessible,self).firstChild
1526
1527 - def _get_lastChild(self):
1528 return super(IAccessible,self).lastChild
1529
1530 #A class for the listview window class, found sof ar only in the Cygwin Setup program. 1531 #Makes sure its available in simple review mode, and uses display model 1532 -class ListviewPane(IAccessible):
1533 presentationType=IAccessible.presType_content 1534 role=controlTypes.ROLE_LIST 1535 TextInfo=displayModel.DisplayModelTextInfo 1536 name=""
1537 1538 ###class mappings 1539 1540 _staticMap={ 1541 ("ReBarWindow32",oleacc.ROLE_SYSTEM_CLIENT):"ReBarWindow32Client", 1542 ("Static",oleacc.ROLE_SYSTEM_STATICTEXT):"StaticText", 1543 ("msctls_statusbar32",oleacc.ROLE_SYSTEM_STATICTEXT):"StaticText", 1544 (None,oleacc.ROLE_SYSTEM_PUSHBUTTON):"Button", 1545 ("tooltips_class32",oleacc.ROLE_SYSTEM_TOOLTIP):"Tooltip", 1546 ("tooltips_class32",oleacc.ROLE_SYSTEM_HELPBALLOON):"Tooltip", 1547 (None,oleacc.ROLE_SYSTEM_DIALOG):"Dialog", 1548 (None,oleacc.ROLE_SYSTEM_ALERT):"Dialog", 1549 (None,oleacc.ROLE_SYSTEM_PROPERTYPAGE):"Dialog", 1550 (None,oleacc.ROLE_SYSTEM_GROUPING):"Groupbox", 1551 ("TrayClockWClass",oleacc.ROLE_SYSTEM_CLIENT):"TrayClockWClass", 1552 ("TRxRichEdit",oleacc.ROLE_SYSTEM_CLIENT):"delphi.TRxRichEdit", 1553 (None,oleacc.ROLE_SYSTEM_OUTLINEITEM):"OutlineItem", 1554 (None,oleacc.ROLE_SYSTEM_LIST):"List", 1555 (None,oleacc.ROLE_SYSTEM_PROGRESSBAR):"ProgressBar", 1556 ("TRichView",oleacc.ROLE_SYSTEM_CLIENT):"delphi.TRichView", 1557 ("TRichViewEdit",oleacc.ROLE_SYSTEM_CLIENT):"delphi.TRichViewEdit", 1558 ("TTntDrawGrid.UnicodeClass",oleacc.ROLE_SYSTEM_CLIENT):"List", 1559 ("SysListView32",oleacc.ROLE_SYSTEM_LIST):"sysListView32.List", 1560 ("SysListView32",oleacc.ROLE_SYSTEM_LISTITEM):"sysListView32.ListItem", 1561 ("SysListView32",oleacc.ROLE_SYSTEM_MENUITEM):"sysListView32.ListItem", 1562 ("SysTreeView32",oleacc.ROLE_SYSTEM_OUTLINE):"sysTreeView32.TreeView", 1563 ("SysTreeView32",oleacc.ROLE_SYSTEM_OUTLINEITEM):"sysTreeView32.TreeViewItem", 1564 ("SysTreeView32",oleacc.ROLE_SYSTEM_MENUITEM):"sysTreeView32.TreeViewItem", 1565 ("SysTreeView32",0):"sysTreeView32.BrokenCommctrl5Item", 1566 ("ATL:SysListView32",oleacc.ROLE_SYSTEM_LISTITEM):"sysListView32.ListItem", 1567 ("TWizardForm",oleacc.ROLE_SYSTEM_CLIENT):"delphi.Form", 1568 ("SysLink",oleacc.ROLE_SYSTEM_CLIENT):"SysLinkClient", 1569 ("SysLink",oleacc.ROLE_SYSTEM_LINK):"SysLink", 1570 ("#32771",oleacc.ROLE_SYSTEM_LIST):"TaskList", 1571 ("TaskSwitcherWnd",oleacc.ROLE_SYSTEM_LIST):"TaskList", 1572 ("#32771",oleacc.ROLE_SYSTEM_LISTITEM):"TaskListIcon", 1573 ("TaskSwitcherWnd",oleacc.ROLE_SYSTEM_LISTITEM):"TaskListIcon", 1574 ("TGroupBox",oleacc.ROLE_SYSTEM_CLIENT):"delphi.TGroupBox", 1575 ("TFormOptions",oleacc.ROLE_SYSTEM_CLIENT):"delphi.Form", 1576 ("TMessageForm",oleacc.ROLE_SYSTEM_CLIENT):"delphi.Form", 1577 ("TFormOptions",oleacc.ROLE_SYSTEM_WINDOW):"delphi.Form", 1578 ("TTabSheet",oleacc.ROLE_SYSTEM_CLIENT):"delphi.TabSheet", 1579 ("MsiDialogCloseClass",oleacc.ROLE_SYSTEM_CLIENT):"Dialog", 1580 (None,oleacc.ROLE_SYSTEM_MENUITEM):"MenuItem", 1581 ("TPTShellList",oleacc.ROLE_SYSTEM_LISTITEM):"sysListView32.ListItem", 1582 ("TProgressBar",oleacc.ROLE_SYSTEM_PROGRESSBAR):"ProgressBar", 1583 ("AcrobatSDIWindow",oleacc.ROLE_SYSTEM_CLIENT):"adobeAcrobat.AcrobatSDIWindowClient", 1584 ("mscandui21.candidate",oleacc.ROLE_SYSTEM_PUSHBUTTON):"IME.IMECandidate", 1585 ("SysMonthCal32",oleacc.ROLE_SYSTEM_CLIENT):"SysMonthCal32.SysMonthCal32", 1586 ("hh_kwd_vlist",oleacc.ROLE_SYSTEM_LIST):"hh.KeywordList", 1587 ("Scintilla",oleacc.ROLE_SYSTEM_CLIENT):"scintilla.Scintilla", 1588 ("TScintilla",oleacc.ROLE_SYSTEM_CLIENT):"scintilla.Scintilla", 1589 ("AkelEditW",oleacc.ROLE_SYSTEM_CLIENT):"akelEdit.AkelEdit", 1590 ("AkelEditA",oleacc.ROLE_SYSTEM_CLIENT):"akelEdit.AkelEdit", 1591 ("MSOUNISTAT",oleacc.ROLE_SYSTEM_CLIENT):"msOffice.MSOUNISTAT", 1592 ("QWidget",oleacc.ROLE_SYSTEM_CLIENT):"qt.Client", 1593 ("QWidget",oleacc.ROLE_SYSTEM_LIST):"qt.Container", 1594 ("QWidget",oleacc.ROLE_SYSTEM_OUTLINE):"qt.Container", 1595 ("QWidget",oleacc.ROLE_SYSTEM_MENUBAR):"qt.Container", 1596 ("QWidget",oleacc.ROLE_SYSTEM_ROW):"qt.TableRow", 1597 ("QWidget",oleacc.ROLE_SYSTEM_CELL):"qt.TableCell", 1598 ("QWidget",oleacc.ROLE_SYSTEM_OUTLINEITEM):"qt.TreeViewItem", 1599 ("QPopup",oleacc.ROLE_SYSTEM_MENUPOPUP):"qt.Menu", 1600 ("QWidget",oleacc.ROLE_SYSTEM_IPADDRESS):"qt.LayeredPane", 1601 ("QWidget",oleacc.ROLE_SYSTEM_APPLICATION):"qt.Application", 1602 ("Shell_TrayWnd",oleacc.ROLE_SYSTEM_CLIENT):"Taskbar", 1603 ("Shell DocObject View",oleacc.ROLE_SYSTEM_CLIENT):"ShellDocObjectView", 1604 ("listview",oleacc.ROLE_SYSTEM_CLIENT):"ListviewPane", 1605 ("NUIDialog",oleacc.ROLE_SYSTEM_CLIENT):"NUIDialogClient", 1606 1607 } 1608