Package virtualBuffers :: Module MSHTML
[hide private]
[frames] | no frames]

Source Code for Module virtualBuffers.MSHTML

  1  from comtypes import COMError 
  2  import eventHandler 
  3  from . import VirtualBuffer, VirtualBufferTextInfo, VBufStorage_findMatch_word 
  4  import controlTypes 
  5  import NVDAObjects.IAccessible.MSHTML 
  6  import winUser 
  7  import NVDAHelper 
  8  import ctypes 
  9  import IAccessibleHandler 
 10  import languageHandler 
 11  import oleacc 
 12  from logHandler import log 
 13  import textInfos 
 14  import api 
 15  import aria 
 16  import config 
 17  import watchdog 
 18   
19 -class MSHTMLTextInfo(VirtualBufferTextInfo):
20
21 - def _normalizeFormatField(self, attrs):
22 language=attrs.get('language') 23 if language: 24 attrs['language']=languageHandler.normalizeLanguage(language) 25 return attrs
26
27 - def _normalizeControlField(self,attrs):
28 level=None 29 accRole=attrs.get('IAccessible::role',0) 30 accRole=int(accRole) if isinstance(accRole,basestring) and accRole.isdigit() else accRole 31 nodeName=attrs.get('IHTMLDOMNode::nodeName',"") 32 ariaRoles=attrs.get("HTMLAttrib::role", "").split(" ") 33 #choose role 34 #Priority is aria role -> HTML tag name -> IAccessible role 35 role=next((aria.ariaRolesToNVDARoles[ar] for ar in ariaRoles if ar in aria.ariaRolesToNVDARoles),controlTypes.ROLE_UNKNOWN) 36 if not role and nodeName: 37 role=NVDAObjects.IAccessible.MSHTML.nodeNamesToNVDARoles.get(nodeName,controlTypes.ROLE_UNKNOWN) 38 if not role: 39 role=IAccessibleHandler.IAccessibleRolesToNVDARoles.get(accRole,controlTypes.ROLE_UNKNOWN) 40 states=set(IAccessibleHandler.IAccessibleStatesToNVDAStates[x] for x in [1<<y for y in xrange(32)] if int(attrs.get('IAccessible::state_%s'%x,0)) and x in IAccessibleHandler.IAccessibleStatesToNVDAStates) 41 #IE exposes destination anchors as links, this is wrong 42 if nodeName=="A" and role==controlTypes.ROLE_LINK and controlTypes.STATE_LINKED not in states: 43 role=controlTypes.ROLE_TEXTFRAME 44 if 'IHTMLElement::isContentEditable' in attrs: 45 states.add(controlTypes.STATE_EDITABLE) 46 if 'HTMLAttrib::onclick' in attrs or 'HTMLAttrib::onmousedown' in attrs or 'HTMLAttrib::onmouseup' in attrs: 47 states.add(controlTypes.STATE_CLICKABLE) 48 if attrs.get('HTMLAttrib::aria-required','false')=='true': 49 states.add(controlTypes.STATE_REQUIRED) 50 name=None 51 ariaLabelledBy=attrs.get('HTMLAttrib::aria-labelledBy') 52 if ariaLabelledBy: 53 try: 54 labelNode=self.obj.rootNVDAObject.HTMLNode.document.getElementById(ariaLabelledBy) 55 except (COMError,NameError): 56 labelNode=None 57 if labelNode: 58 try: 59 name=self.obj.makeTextInfo(NVDAObjects.IAccessible.MSHTML.MSHTML(HTMLNode=labelNode)).text 60 except: 61 pass 62 description=None 63 ariaDescribedBy=attrs.get('HTMLAttrib::aria-describedBy') 64 if ariaDescribedBy: 65 try: 66 descNode=self.obj.rootNVDAObject.HTMLNode.document.getElementById(ariaDescribedBy) 67 except (COMError,NameError): 68 descNode=None 69 if descNode: 70 try: 71 description=self.obj.makeTextInfo(NVDAObjects.IAccessible.MSHTML.MSHTML(HTMLNode=descNode)).text 72 except: 73 pass 74 ariaSort=attrs.get('HTMLAttrib::aria-sort') 75 state=aria.ariaSortValuesToNVDAStates.get(ariaSort) 76 if state is not None: 77 states.add(state) 78 ariaSelected=attrs.get('HTMLAttrib::aria-selected') 79 if ariaSelected=="true": 80 states.add(controlTypes.STATE_SELECTED) 81 elif ariaSelected=="false": 82 states.discard(controlTypes.STATE_SELECTED) 83 ariaExpanded=attrs.get('HTMLAttrib::aria-expanded') 84 if ariaExpanded=="true": 85 states.add(controlTypes.STATE_EXPANDED) 86 elif ariaExpanded=="false": 87 states.add(controlTypes.STATE_COLLAPSED) 88 if attrs.get('HTMLAttrib::aria-invalid','false')=='true': 89 states.add(controlTypes.STATE_INVALID) 90 if attrs.get('HTMLAttrib::aria-multiline','false')=='true': 91 states.add(controlTypes.STATE_MULTILINE) 92 if attrs.get('HTMLAttrib::aria-dropeffect','none')!='none': 93 states.add(controlTypes.STATE_DROPTARGET) 94 ariaGrabbed=attrs.get('HTMLAttrib::aria-grabbed',None) 95 if ariaGrabbed=='false': 96 states.add(controlTypes.STATE_DRAGGABLE) 97 elif ariaGrabbed=='true': 98 states.add(controlTypes.STATE_DRAGGING) 99 if nodeName=="TEXTAREA": 100 states.add(controlTypes.STATE_MULTILINE) 101 if "H1"<=nodeName<="H6": 102 level=nodeName[1:] 103 if nodeName in ("UL","OL","DL"): 104 states.add(controlTypes.STATE_READONLY) 105 if role==controlTypes.ROLE_UNKNOWN: 106 role=controlTypes.ROLE_TEXTFRAME 107 if role==controlTypes.ROLE_GRAPHIC: 108 # MSHTML puts the unavailable state on all graphics when the showing of graphics is disabled. 109 # This is rather annoying and irrelevant to our users, so discard it. 110 states.discard(controlTypes.STATE_UNAVAILABLE) 111 # Get the first landmark role, if any. 112 landmark=next((ar for ar in ariaRoles if ar in aria.landmarkRoles),None) 113 ariaLevel=attrs.get('HTMLAttrib::aria-level',None) 114 ariaLevel=int(ariaLevel) if ariaLevel is not None else None 115 if ariaLevel: 116 level=ariaLevel 117 if role: 118 attrs['role']=role 119 attrs['states']=states 120 if level: 121 attrs["level"] = level 122 if landmark: 123 attrs["landmark"]=landmark 124 if name: 125 attrs["name"]=name 126 if description: 127 attrs["description"]=description 128 return super(MSHTMLTextInfo,self)._normalizeControlField(attrs)
129
130 -class MSHTML(VirtualBuffer):
131 132 TextInfo=MSHTMLTextInfo 133
134 - def __init__(self,rootNVDAObject):
135 super(MSHTML,self).__init__(rootNVDAObject,backendName="mshtml")
136
137 - def _getInitialCaretPos(self):
138 initialPos = super(MSHTML,self)._getInitialCaretPos() 139 if initialPos: 140 return initialPos 141 try: 142 url=getattr(self.rootNVDAObject.HTMLNode.document,'url',"").split('#') 143 except COMError as e: 144 log.debugWarning("Error getting URL from document: %s" % e) 145 return None 146 if not url or len(url)!=2: 147 return None 148 anchorName=url[-1] 149 if not anchorName: 150 return None 151 return self._getNVDAObjectByAnchorName(anchorName)
152
153 - def __contains__(self,obj):
154 if not obj.windowClassName.startswith("Internet Explorer_"): 155 return False 156 #'select' tag lists have MSAA list items which do not relate to real HTML nodes. 157 #Go up one parent for these and use it instead 158 if isinstance(obj,NVDAObjects.IAccessible.IAccessible) and not isinstance(obj,NVDAObjects.IAccessible.MSHTML.MSHTML) and obj.role==controlTypes.ROLE_LISTITEM: 159 parent=obj.parent 160 if parent and isinstance(parent,NVDAObjects.IAccessible.MSHTML.MSHTML): 161 obj=parent 162 #Combo box lists etc are popup windows, so rely on accessibility hierarchi instead of window hierarchi for those. 163 #However only helps in IE8. 164 if obj.windowStyle&winUser.WS_POPUP: 165 parent=obj.parent 166 obj.parent=parent 167 while parent and parent.windowHandle==obj.windowHandle: 168 newParent=parent.parent 169 parent.parent=newParent 170 parent=newParent 171 if parent and parent.windowClassName.startswith('Internet Explorer_'): 172 obj=parent 173 if not winUser.isDescendantWindow(self.rootDocHandle,obj.windowHandle) and obj.windowHandle!=self.rootDocHandle: 174 return False 175 newObj=obj 176 while isinstance(newObj,NVDAObjects.IAccessible.MSHTML.MSHTML) and newObj.role not in (controlTypes.ROLE_APPLICATION,controlTypes.ROLE_DIALOG): 177 if newObj==self.rootNVDAObject: 178 return True 179 newObj=newObj.parent 180 return False
181
182 - def _get_isAlive(self):
183 if self.isLoading: 184 return True 185 root=self.rootNVDAObject 186 if not root: 187 return False 188 try: 189 if not root.IAccessibleRole: 190 # The root object is dead. 191 return False 192 except watchdog.CallCancelled: 193 # #1831: If the root object isn't responding, treat the buffer as dead. 194 # Otherwise, we'll keep querying it on every focus change and freezing. 195 return False 196 states=root.states 197 if not winUser.isWindow(root.windowHandle) or controlTypes.STATE_EDITABLE in states: 198 return False 199 return True
200
201 - def getNVDAObjectFromIdentifier(self, docHandle, ID):
202 HTMLNode=NVDAObjects.IAccessible.MSHTML.locateHTMLElementByID(self.rootNVDAObject.HTMLNode.document,'ms__id%d'%ID) 203 if not HTMLNode: 204 return self.rootNVDAObject 205 return NVDAObjects.IAccessible.MSHTML.MSHTML(HTMLNode=HTMLNode)
206
207 - def getIdentifierFromNVDAObject(self,obj):
208 if not isinstance(obj,NVDAObjects.IAccessible.MSHTML.MSHTML): 209 raise LookupError 210 docHandle=obj.windowHandle 211 ID=obj.HTMLNodeUniqueNumber 212 return docHandle,ID
213
214 - def _searchableAttribsForNodeType(self,nodeType):
215 if nodeType=="link": 216 attrs={"IAccessible::role":[oleacc.ROLE_SYSTEM_LINK],"IAccessible::state_%d"%oleacc.STATE_SYSTEM_LINKED:[1]} 217 elif nodeType=="visitedLink": 218 attrs={"IAccessible::role":[oleacc.ROLE_SYSTEM_LINK],"IAccessible::state_%d"%oleacc.STATE_SYSTEM_TRAVERSED:[1]} 219 elif nodeType=="unvisitedLink": 220 attrs={"IAccessible::role":[oleacc.ROLE_SYSTEM_LINK],"IAccessible::state_%d"%oleacc.STATE_SYSTEM_LINKED:[1],"IAccessible::state_%d"%oleacc.STATE_SYSTEM_TRAVERSED:[None]} 221 elif nodeType=="formField": 222 attrs={"IAccessible::role":[oleacc.ROLE_SYSTEM_PUSHBUTTON,oleacc.ROLE_SYSTEM_RADIOBUTTON,oleacc.ROLE_SYSTEM_CHECKBUTTON,oleacc.ROLE_SYSTEM_COMBOBOX,oleacc.ROLE_SYSTEM_LIST,oleacc.ROLE_SYSTEM_OUTLINE,oleacc.ROLE_SYSTEM_TEXT],"IAccessible::state_%s"%oleacc.STATE_SYSTEM_READONLY:[None],"IAccessible::state_%s"%oleacc.STATE_SYSTEM_FOCUSABLE:[1]} 223 elif nodeType=="button": 224 attrs={"IAccessible::role":[oleacc.ROLE_SYSTEM_PUSHBUTTON],"IAccessible::state_%s"%oleacc.STATE_SYSTEM_FOCUSABLE:[1]} 225 elif nodeType=="edit": 226 attrs={"IAccessible::role":[oleacc.ROLE_SYSTEM_TEXT],"IAccessible::state_%s"%oleacc.STATE_SYSTEM_READONLY:[None],"IAccessible::state_%s"%oleacc.STATE_SYSTEM_FOCUSABLE:[1]} 227 elif nodeType=="radioButton": 228 attrs={"IAccessible::role":[oleacc.ROLE_SYSTEM_RADIOBUTTON],"IAccessible::state_%s"%oleacc.STATE_SYSTEM_FOCUSABLE:[1]} 229 elif nodeType=="comboBox": 230 attrs={"IAccessible::role":[oleacc.ROLE_SYSTEM_COMBOBOX],"IAccessible::state_%s"%oleacc.STATE_SYSTEM_FOCUSABLE:[1]} 231 elif nodeType=="checkBox": 232 attrs={"IAccessible::role":[oleacc.ROLE_SYSTEM_CHECKBUTTON],"IAccessible::state_%s"%oleacc.STATE_SYSTEM_FOCUSABLE:[1]} 233 elif nodeType=="table": 234 attrs={"IHTMLDOMNode::nodeName":["TABLE"]} 235 if not config.conf["documentFormatting"]["includeLayoutTables"]: 236 attrs["table-layout"]=[None] 237 elif nodeType.startswith("heading") and nodeType[7:].isdigit(): 238 attrs = {"IHTMLDOMNode::nodeName": ["H%s" % nodeType[7:]]} 239 elif nodeType == "heading": 240 attrs = {"IHTMLDOMNode::nodeName": ["H1", "H2", "H3", "H4", "H5", "H6"]} 241 elif nodeType == "list": 242 attrs = {"IHTMLDOMNode::nodeName": ["UL","OL","DL"]} 243 elif nodeType == "listItem": 244 attrs = {"IHTMLDOMNode::nodeName": ["LI","DD","DT"]} 245 elif nodeType == "blockQuote": 246 attrs = {"IHTMLDOMNode::nodeName": ["BLOCKQUOTE"]} 247 elif nodeType == "graphic": 248 attrs = {"IHTMLDOMNode::nodeName": ["IMG"]} 249 elif nodeType == "frame": 250 attrs = {"IHTMLDOMNode::nodeName": ["FRAME","IFRAME"]} 251 elif nodeType=="focusable": 252 attrs={"IAccessible::state_%s"%oleacc.STATE_SYSTEM_FOCUSABLE:[1]} 253 elif nodeType=="landmark": 254 attrs={"HTMLAttrib::role":[VBufStorage_findMatch_word(lr) for lr in aria.landmarkRoles]} 255 elif nodeType == "embeddedObject": 256 attrs = {"IHTMLDOMNode::nodeName": ["OBJECT","EMBED","APPLET"]} 257 else: 258 return None 259 return attrs
260
261 - def _activateNVDAObject(self,obj):
262 super(MSHTML,self)._activateNVDAObject(obj) 263 #If we activated a same-page link, then scroll to its anchor 264 if obj.HTMLNodeName=="A": 265 anchorName=getattr(obj.HTMLNode,'hash') 266 if not anchorName: 267 return 268 obj=self._getNVDAObjectByAnchorName(anchorName[1:],HTMLDocument=obj.HTMLNode.document) 269 if not obj: 270 return 271 self._handleScrollTo(obj)
272
273 - def _getNVDAObjectByAnchorName(self,name,HTMLDocument=None):
274 if not HTMLDocument: 275 HTMLDocument=self.rootNVDAObject.HTMLNode.document 276 HTMLNode=HTMLDocument.getElementById(name) 277 if not HTMLNode: 278 log.debugWarning("GetElementById can't find node with ID %s"%name) 279 return None 280 obj=NVDAObjects.IAccessible.MSHTML.MSHTML(HTMLNode=HTMLNode) 281 return obj
282
284 try: 285 return self.rootNVDAObject.HTMLNode.document.url 286 except COMError: 287 return None
288
289 - def shouldPassThrough(self, obj, reason=None):
290 try: 291 if not reason and not self.passThrough and obj.HTMLNodeName == "INPUT" and obj.HTMLNode.type == "file": 292 # #1720: The user is activating a file input control in browse mode. 293 # The NVDAObject for this is an editable text field, 294 # but we want to activate the browse button instead of editing the field. 295 return False 296 except COMError: 297 pass 298 return super(MSHTML, self).shouldPassThrough(obj, reason)
299