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

Source Code for Module NVDAObjects.IAccessible.adobeAcrobat

  1  import api 
  2  import controlTypes 
  3  import eventHandler 
  4  import winUser 
  5  from . import IAccessible, getNVDAObjectFromEvent 
  6  from NVDAObjects import NVDAObjectTextInfo 
  7  from NVDAObjects.behaviors import EditableText 
  8  from comtypes import GUID, COMError, IServiceProvider 
  9  from comtypes.gen.AcrobatAccessLib import IAccID, IGetPDDomNode, IPDDomElement 
 10  from logHandler import log 
 11   
 12  SID_AccID = GUID("{449D454B-1F46-497e-B2B6-3357AED9912B}") 
 13  SID_GetPDDomNode = GUID("{C0A1D5E9-1142-4cf3-B607-82FC3B96A4DF}") 
 14   
 15  stdNamesToRoles = { 
 16          # Part? Art? 
 17          "Sect": controlTypes.ROLE_SECTION, 
 18          "Div": controlTypes.ROLE_SECTION, 
 19          "BlockQuote": controlTypes.ROLE_BLOCKQUOTE, 
 20          "Caption": controlTypes.ROLE_CAPTION, 
 21          # Toc? Toci? Index? Nonstruct? Private?  
 22          # Table, TR, TH, TD covered by IAccessible 
 23          "L": controlTypes.ROLE_LIST, 
 24          "LI": controlTypes.ROLE_LISTITEM, 
 25          "Lbl": controlTypes.ROLE_LABEL, 
 26          # LBody 
 27          "P": controlTypes.ROLE_PARAGRAPH, 
 28          "H": controlTypes.ROLE_HEADING, 
 29          # H1 to H6 handled separately 
 30          # Span, Quote, Note, Reference, BibEntry, Code, Figure, Formula 
 31          "Form": controlTypes.ROLE_FORM, 
 32  } 
 33   
34 -def normalizeStdName(stdName):
35 if "H1" <= stdName <= "H6": 36 return controlTypes.ROLE_HEADING, stdName[1] 37 38 try: 39 return stdNamesToRoles[stdName], None 40 except KeyError: 41 pass 42 43 raise LookupError
44
45 -class AcrobatNode(IAccessible):
46
47 - def initOverlayClass(self):
48 try: 49 serv = self.IAccessibleObject.QueryInterface(IServiceProvider) 50 except COMError: 51 log.debugWarning("Could not get IServiceProvider") 52 return 53 54 if self.event_objectID > 0: 55 self.accID = self.event_objectID 56 elif self.event_childID > 0: 57 self.accID = self.event_childID 58 else: 59 try: 60 self.accID = serv.QueryService(SID_AccID, IAccID).get_accID() 61 except COMError: 62 log.debugWarning("Failed to get ID from IAccID", exc_info=True) 63 self.accID = None 64 65 # Get the IPDDomNode. 66 try: 67 self.pdDomNode = serv.QueryService(SID_GetPDDomNode, IGetPDDomNode).get_PDDomNode(self.IAccessibleChildID) 68 except COMError: 69 self.pdDomNode = None 70 log.debugWarning("Error getting IPDDomNode") 71 72 if self.pdDomNode: 73 # If this node has IPDDomElement, query to that. 74 try: 75 self.pdDomNode = self.pdDomNode.QueryInterface(IPDDomElement) 76 except COMError: 77 pass
78
79 - def _get_role(self):
80 try: 81 return normalizeStdName(self.pdDomNode.GetStdName())[0] 82 except (AttributeError, LookupError, COMError): 83 pass 84 85 role = super(AcrobatNode, self).role 86 if role == controlTypes.ROLE_PANE: 87 # Pane doesn't make sense for nodes in a document. 88 role = controlTypes.ROLE_TEXTFRAME 89 return role
90
91 - def scrollIntoView(self):
92 try: 93 self.pdDomNode.ScrollTo() 94 except (AttributeError, COMError): 95 log.debugWarning("IPDDomNode::ScrollTo failed", exc_info=True)
96
97 - def _isEqual(self, other):
98 if self.windowHandle == other.windowHandle and self.accID and other.accID: 99 return self.accID == other.accID 100 return super(AcrobatNode, self)._isEqual(other)
101
102 -class RootNode(AcrobatNode):
103 shouldAllowIAccessibleFocusEvent = True 104
105 - def event_valueChange(self):
106 # Acrobat has indicated that a page has died and been replaced by a new one. 107 if not self.isInForeground: 108 # If this isn't in the foreground, it doesn't matter, 109 # as focus will be fired on the correct object when it is in the foreground again. 110 return 111 # The new page has the same event params, so we must bypass NVDA's IAccessible caching. 112 obj = getNVDAObjectFromEvent(self.windowHandle, winUser.OBJID_CLIENT, 0) 113 if not obj: 114 return 115 eventHandler.queueEvent("gainFocus",obj)
116
117 -class Document(RootNode):
118 122
124 # HACK: #1659: When moving the focus, Acrobat sometimes fires focus on the document before firing it on the real focus; 125 # e.g. when tabbing through a multi-page form. 126 # This causes extraneous verbosity. 127 # Therefore, if already focused inside this document, only allow focus on the document if it has no active descendant. 128 if api.getFocusObject().windowHandle == self.windowHandle: 129 try: 130 return self.IAccessibleObject.accFocus in (None, 0) 131 except COMError: 132 pass 133 return super(Document, self).shouldAllowIAccessibleFocusEvent
134
135 -class RootTextNode(RootNode):
136 """The message text node that appears instead of the document when the document is not available. 137 """ 138
139 - def _get_parent(self):
140 #hack: This code should be taken out once the crash is fixed in Adobe Reader X. 141 #If going parent on a root text node after saying ok to the accessibility options (untagged) and before the processing document dialog appears, Reader X will crash. 142 return api.getDesktopObject()
143
144 -class AcrobatTextInfo(NVDAObjectTextInfo):
145
146 - def _getStoryText(self):
147 return self.obj.value or ""
148
149 - def _getCaretOffset(self):
150 caret = getNVDAObjectFromEvent(self.obj.windowHandle, winUser.OBJID_CARET, 0) 151 if not caret: 152 raise RuntimeError("No caret") 153 try: 154 return int(caret.description) 155 except (ValueError, TypeError): 156 raise RuntimeError("Bad caret index")
157
158 -class EditableTextNode(EditableText, AcrobatNode):
159 TextInfo = AcrobatTextInfo 160
161 - def event_valueChange(self):
162 pass
163
164 -class AcrobatSDIWindowClient(IAccessible):
165
166 - def __init__(self, **kwargs):
167 super(AcrobatSDIWindowClient, self).__init__(**kwargs) 168 if not self.name and self.parent: 169 # There are two client objects, one with a name and one without. 170 # The unnamed object (probably manufactured by Acrobat) has broken next and previous relationships. 171 # The unnamed object's parent is the named object, but when descending into the named object, the unnamed object is skipped. 172 # Given the brokenness of the unnamed object, just skip it completely and use the parent when it is encountered. 173 self.IAccessibleObject = self.IAccessibleObject.accParent
174
175 -def findExtraOverlayClasses(obj, clsList):
176 """Determine the most appropriate class(es) for Acrobat objects. 177 This works similarly to L{NVDAObjects.NVDAObject.findOverlayClasses} except that it never calls any other findOverlayClasses method. 178 """ 179 role = obj.role 180 if obj.event_childID == 0 and obj.event_objectID == winUser.OBJID_CLIENT: 181 # Root node. 182 if role in (controlTypes.ROLE_DOCUMENT,controlTypes.ROLE_PAGE): 183 clsList.append(Document) 184 elif role == controlTypes.ROLE_EDITABLETEXT: 185 clsList.append(RootTextNode) 186 else: 187 clsList.append(RootNode) 188 189 elif role == controlTypes.ROLE_EDITABLETEXT and controlTypes.STATE_FOCUSABLE in obj.states: 190 clsList.append(EditableTextNode) 191 192 clsList.append(AcrobatNode)
193