~stomato463/+junk/nvdajp

« back to all changes in this revision

Viewing changes to source/IAccessibleHandler.py

  • Committer: Masataka Shinke
  • Date: 2011-10-25 12:35:26 UTC
  • mfrom: (4185 jpmain)
  • mto: This revision was merged to the branch mainline in revision 4211.
  • Revision ID: mshinke@users.sourceforge.jp-20111025123526-ze527a2rl3z0g2ky
lp:~nishimotz/nvdajp/main : 4185 をマージ

Show diffs side-by-side

added added

removed removed

Lines of Context:
22
22
CLSCTX_LOCAL_SERVER=4
23
23
 
24
24
#Special Mozilla gecko MSAA constant additions
25
 
NAVRELATION_LABELLED_BY=0x1002
 
25
NAVRELATION_LABEL_FOR=0x1002
26
26
NAVRELATION_LABELLED_BY=0x1003
27
27
NAVRELATION_NODE_CHILD_OF=0x1005
 
28
NAVRELATION_EMBEDS=0x1009
 
29
 
 
30
# IAccessible2 relations (not included in the typelib)
 
31
IA2_RELATION_FLOWS_FROM = "flowsFrom"
 
32
IA2_RELATION_FLOWS_TO = "flowsTo"
28
33
 
29
34
import UIAHandler
30
35
import heapq
94
99
                @param threadID: the threadID of the winEvent
95
100
                @type threadID: integer
96
101
                """
97
 
                #Filter out any events for UIA windows
98
 
                if UIAHandler.handler and UIAHandler.handler.isUIAWindow(window):
99
 
                        return
100
 
 
101
102
                if eventID==winUser.EVENT_OBJECT_FOCUS:
102
103
                        if objectID in (winUser.OBJID_SYSMENU,winUser.OBJID_MENU) and childID==0:
103
104
                                # This is a focus event on a menu bar itself, which is just silly. Ignore it.
335
336
winEventHookIDs=[]
336
337
 
337
338
def normalizeIAccessible(pacc):
338
 
        if isinstance(pacc,comtypes.client.lazybind.Dispatch) or isinstance(pacc,comtypes.client.dynamic._Dispatch) or isinstance(pacc,IUnknown):
339
 
                pacc=pacc.QueryInterface(IAccessible)
340
 
        elif not isinstance(pacc,IAccessible):
341
 
                raise ValueError("pacc %s is not, or can not be converted to, an IAccessible"%str(pacc))
 
339
        if not isinstance(pacc,IAccessible):
 
340
                try:
 
341
                        pacc=pacc.QueryInterface(IAccessible)
 
342
                except COMError:
 
343
                        raise RuntimeError("%s Not an IAccessible"%pacc)
342
344
        if not isinstance(pacc,IAccessible2):
343
345
                try:
344
346
                        s=pacc.QueryInterface(IServiceProvider)
353
355
        return pacc
354
356
 
355
357
def accessibleObjectFromEvent(window,objectID,childID):
356
 
        wmResult=c_long()
357
 
        if windll.user32.SendMessageTimeoutW(window,winUser.WM_NULL,0,0,winUser.SMTO_ABORTIFHUNG,2000,byref(wmResult))==0:
358
 
                log.debugWarning("Window %d dead or not responding: %s" % (window, ctypes.WinError()))
359
 
                return None
360
358
        try:
361
359
                pacc,childID=oleacc.AccessibleObjectFromEvent(window,objectID,childID)
362
360
        except Exception as e:
393
391
                        new_ia=normalizeIAccessible(res)
394
392
                        new_child=0
395
393
                elif isinstance(res,int):
396
 
                        new_ia=ia
397
 
                        new_child=res
 
394
                        try:
 
395
                                new_ia=ia.accChild(res)
 
396
                        except:
 
397
                                new_ia=None
 
398
                        if new_ia:
 
399
                                new_ia=normalizeIAccessible(new_ia)
 
400
                                new_child=0
 
401
                        else:
 
402
                                new_ia=ia
 
403
                                new_child=res
398
404
                else:
399
405
                        return None
400
406
                return (new_ia,new_child)
512
518
        #Ignore any events with invalid window handles
513
519
        if not window or not winUser.isWindow(window):
514
520
                return None
 
521
        #Make sure this window does not have a ghost window if possible
 
522
        if NVDAObjects.window.GhostWindowFromHungWindow and NVDAObjects.window.GhostWindowFromHungWindow(window):
 
523
                return None
 
524
        #We do not support MSAA object proxied from native UIA
 
525
        if UIAHandler.handler and UIAHandler.handler.isUIAWindow(window):
 
526
                return None
515
527
        obj=None
516
528
        if useCache:
517
529
                #See if we already know an object by this win event info
524
536
                return None
525
537
        #SDM MSAA objects sometimes don't contain enough information to be useful
526
538
        #Sometimes there is a real window that does, so try to get the SDMChild property on the NVDAObject, and if successull use that as obj instead.
527
 
        if obj.windowClassName=='bosa_sdm':
 
539
        if 'bosa_sdm' in obj.windowClassName:
528
540
                SDMChild=getattr(obj,'SDMChild',None)
529
541
                if SDMChild: obj=SDMChild
530
542
        return (NVDAEventName,obj)
548
560
                        return
549
561
 
550
562
                if childID<0:
551
 
                        while window and not winUser.getWindowStyle(window)&winUser.WS_POPUP and winUser.getClassName(window)=="MozillaWindowClass":
552
 
                                window=winUser.getAncestor(window,winUser.GA_PARENT)
 
563
                        tempWindow=window
 
564
                        while tempWindow and not winUser.getWindowStyle(tempWindow)&winUser.WS_POPUP and winUser.getClassName(tempWindow)=="MozillaWindowClass":
 
565
                                tempWindow=winUser.getAncestor(tempWindow,winUser.GA_PARENT)
 
566
                        if tempWindow and winUser.getClassName(tempWindow).startswith('Mozilla'):
 
567
                                window=tempWindow
 
568
 
553
569
                windowClassName=winUser.getClassName(window)
554
570
                #At the moment we can't handle show, hide or reorder events on Mozilla Firefox Location bar,as there are just too many of them
555
571
                #Ignore show, hide and reorder on MozillaDropShadowWindowClass windows.
561
577
                #We never want to see foreground events for the Program Manager or Shell (task bar) 
562
578
                if eventID==winUser.EVENT_SYSTEM_FOREGROUND and windowClassName in ("Progman","Shell_TrayWnd"):
563
579
                        return
 
580
                if windowClassName=="MSNHiddenWindowClass":
 
581
                        # HACK: Events get fired by this window in Windows Live Messenger 2009 when it starts.
 
582
                        # If we send a WM_NULL to this window at this point (which happens in accessibleObjectFromEvent), Messenger will silently exit (#677).
 
583
                        # Therefore, completely ignore these events, which is useless to us anyway.
 
584
                        return
564
585
                winEventLimiter.addEvent(eventID,window,objectID,childID,threadID)
565
586
        except:
566
587
                log.error("winEventCallback", exc_info=True)
612
633
        @rtype: boolean
613
634
        """
614
635
        windowClassName=winUser.getClassName(window)
615
 
        #We must ignore focus on child windows of SDM windows as we only want the SDM MSAA events
616
 
        if not windowClassName.startswith('bosa_sdm') and winUser.getClassName(winUser.getAncestor(window,winUser.GA_PARENT)).startswith('bosa_sdm'):
617
 
                return True
 
636
        # Generally, we must ignore focus on child windows of SDM windows as we only want the SDM MSAA events.
 
637
        # However, we don't want to ignore focus if the child ID isn't 0,
 
638
        # as this is a child control and the SDM MSAA events don't handle child controls.
 
639
        if childID==0 and not windowClassName.startswith('bosa_sdm') and winUser.getClassName(winUser.getAncestor(window,winUser.GA_PARENT)).startswith('bosa_sdm'):
 
640
                return False
618
641
        rootWindow=winUser.getAncestor(window,winUser.GA_ROOT)
619
 
        # If this window's root window is not the foreground window and this window or its root window is not a popup window:
620
 
        if rootWindow!=winUser.getForegroundWindow() and not (winUser.getWindowStyle(window) & winUser.WS_POPUP or winUser.getWindowStyle(rootWindow)&winUser.WS_POPUP):
 
642
        # If this window is not within the foreground window and this window or its root window is not a popup window, and this window's root window is not the highest in the z-order
 
643
        if not winUser.isDescendantWindow(winUser.getForegroundWindow(),window) and not (winUser.getWindowStyle(window) & winUser.WS_POPUP or winUser.getWindowStyle(rootWindow)&winUser.WS_POPUP) and winUser.getPreviousWindow(rootWindow)!=0: 
621
644
                # This is a focus event from a background window, so ignore it.
622
645
                return False
623
646
        #Notify appModuleHandler of this new foreground window
654
677
        @rtype: boolean
655
678
        """
656
679
        if not force and isinstance(obj,NVDAObjects.IAccessible.IAccessible):
657
 
                focus=api.getFocusObject()
 
680
                focus=eventHandler.lastQueuedFocusObject
658
681
                if isinstance(focus,NVDAObjects.IAccessible.IAccessible) and focus.isDuplicateIAccessibleEvent(obj):
659
682
                        return True
660
683
                if not obj.shouldAllowIAccessibleFocusEvent:
783
806
#Register internal object event with IAccessible
784
807
cWinEventCallback=WINFUNCTYPE(None,c_int,c_int,c_int,c_int,c_int,c_int,c_int)(winEventCallback)
785
808
 
 
809
accPropServices=None
 
810
 
786
811
def initialize():
 
812
        global accPropServices
 
813
        try:
 
814
                accPropServices=comtypes.client.CreateObject(CAccPropServices)
 
815
        except (WindowsError,COMError) as e:
 
816
                log.debugWarning("AccPropServices is not available: %s"%e)
787
817
        for eventType in winEventIDsToNVDAEventNames.keys():
788
818
                hookID=winUser.setWinEventHook(eventType,eventType,0,cWinEventCallback,0,0,0)
789
819
                if hookID:
842
872
        IAccIdentityObject=pacc.QueryInterface(IAccIdentity)
843
873
        stringPtr,stringSize=IAccIdentityObject.getIdentityString(childID)
844
874
        try:
 
875
                if accPropServices:
 
876
                        hwnd,objectID,childID=accPropServices.DecomposeHwndIdentityString(stringPtr,stringSize)
 
877
                        return dict(windowHandle=hwnd,objectID=c_int(objectID).value,childID=childID)
845
878
                stringPtr=cast(stringPtr,POINTER(c_char*stringSize))
846
879
                fields=struct.unpack('IIiI',stringPtr.contents.raw)
 
880
                d={}
 
881
                d['childID']=fields[3]
 
882
                if fields[0]&2:
 
883
                        d['menuHandle']=fields[2]
 
884
                else:
 
885
                        d['objectID']=fields[2]
 
886
                        d['windowHandle']=fields[1]
 
887
                return d
847
888
        finally:
848
889
                windll.ole32.CoTaskMemFree(stringPtr)
849
 
        d={}
850
 
        d['childID']=fields[3]
851
 
        if fields[0]&2:
852
 
                d['menuHandle']=fields[2]
853
 
        else:
854
 
                d['objectID']=fields[2]
855
 
                d['windowHandle']=fields[1]
856
 
        return d
 
890
 
857
891
 
858
892
def findGroupboxObject(obj):
859
893
        prevWindow=winUser.getPreviousWindow(obj.windowHandle)
958
992
                elif char == ";":
959
993
                        # We're about to move on to a new attribute.
960
994
                        if subkey:
 
995
                                # Add the last subattribute key/value pair to the dict.
 
996
                                subattr[subkey] = tmp
 
997
                                subkey = ""
 
998
                        if subattr:
961
999
                                # This attribute had subattributes.
962
 
                                # Add the last subattribute key/value pair to the dict.
963
 
                                subattr[subkey] = tmp
964
1000
                                # Add the key/subattribute pair to the dict.
965
1001
                                attribsDict[key] = subattr
966
 
                                subkey = ""
967
1002
                                subattr = {}
968
1003
                        elif key:
969
1004
                                # Add this key/value pair to the dict.
974
1009
                        tmp += char
975
1010
        # If there was no trailing semi-colon, we need to handle the last attribute.
976
1011
        if subkey:
977
 
                # This attribute had subattributes.
978
1012
                # Add the last subattribute key/value pair to the dict.
979
1013
                subattr[subkey] = tmp
 
1014
        if subattr:
 
1015
                # This attribute had subattributes.
980
1016
                # Add the key/subattribute pair to the dict.
981
1017
                attribsDict[key] = subattr
982
1018
        elif key:
983
1019
                # Add this key/value pair to the dict.
984
1020
                attribsDict[key] = tmp
985
1021
        return attribsDict
 
1022
 
 
1023
def isMarshalledIAccessible(IAccessibleObject):
 
1024
        """Looks at the location of the first function in the IAccessible object's vtable (IUnknown::AddRef) to see if it was implemented in oleacc.dll (its local) or ole32.dll (its marshalled)."""
 
1025
        if not isinstance(IAccessibleObject,IAccessible):
 
1026
                raise TypeError("object should be of type IAccessible, not %s"%IAccessibleObject)
 
1027
        buf=create_unicode_buffer(1024)
 
1028
        from comtypes import _compointer_base
 
1029
        addr=POINTER(c_void_p).from_address(super(_compointer_base,IAccessibleObject).value).contents.value
 
1030
        handle=HANDLE()
 
1031
        windll.kernel32.GetModuleHandleExW(6,addr,byref(handle))
 
1032
        windll.kernel32.GetModuleFileNameW(handle,buf,1024)
 
1033
        return not buf.value.lower().endswith('oleacc.dll')