9999 IA2_ROLE_FOOTER ,
100100 IA2_ROLE_MARK ,
101101)
102+ import config
103+
104+
105+ _winEventNameCache = {}
106+
107+
108+ def getWinEventName (eventID ):
109+ """ Looks up the name of an EVENT_* winEvent constant. """
110+ global _winEventNameCache
111+ if not _winEventNameCache :
112+ _winEventNameCache = {y : x for x , y in vars (winUser ).items () if x .startswith ('EVENT_' )}
113+ _winEventNameCache .update ({y : x for x , y in vars (IA2 ).items () if x .startswith ('IA2_EVENT_' )})
114+ name = _winEventNameCache .get (eventID )
115+ if not name :
116+ name = "unknown event ({eventID})"
117+ return name
118+
119+
120+ _objectIDNameCache = {}
121+
122+
123+ def getObjectIDName (objectID ):
124+ """ Looks up the name of an OBJID_* winEvent constant. """
125+ global _objectIDNameCache
126+ if not _objectIDNameCache :
127+ _objectIDNameCache = {y : x for x , y in vars (winUser ).items () if x .startswith ('OBJID_' )}
128+ name = _objectIDNameCache .get (objectID )
129+ if not name :
130+ name = str (objectID )
131+ return name
132+
133+
134+ def getWinEventLogInfo (window , objectID , childID , eventID = None , threadID = None ):
135+ """
136+ Formats the given winEvent parameters into a printable string.
137+ window, objectID and childID are mandatory,
138+ but eventID and threadID are optional.
139+ """
140+ windowClassName = winUser .getClassName (window ) or "unknown"
141+ objectIDName = getObjectIDName (objectID )
142+ processID = winUser .getWindowThreadProcessID (window )[0 ]
143+ if processID :
144+ processName = appModuleHandler .getAppModuleFromProcessID (processID ).appName
145+ else :
146+ processName = "unknown application"
147+ messageList = []
148+ if eventID is not None :
149+ eventName = getWinEventName (eventID )
150+ messageList .append (f"{ eventName } " )
151+ messageList .append (
152+ f"window { window } ({ windowClassName } ), objectID { objectIDName } , childID { childID } , "
153+ f"from process { processID } ({ processName } )"
154+ )
155+ if threadID is not None :
156+ messageList .append (f"thread { threadID } " )
157+ return ", " .join (messageList )
158+
159+ def isMSAADebugLoggingEnabled ():
160+ """ Whether the user has configured NVDA to log extra information about MSAA events. """
161+ return config .conf ["debugLog" ]["MSAA" ]
162+
102163
103164from . import internalWinEventHandler
104165# Imported for backwards compat
@@ -344,10 +405,11 @@ def accessibleObjectFromEvent(window, objectID, childID):
344405 try :
345406 pacc , childID = oleacc .AccessibleObjectFromEvent (window , objectID , childID )
346407 except Exception as e :
347- log .debug (
348- f"oleacc.AccessibleObjectFromEvent with"
349- f" window { window } , objectID { objectID } and childID { childID } : { e } "
350- )
408+ if isMSAADebugLoggingEnabled ():
409+ log .debugWarning (
410+ f"oleacc.AccessibleObjectFromEvent failed with { e } ."
411+ f" WinEvent: { getWinEventLogInfo (window , objectID , childID )} "
412+ )
351413 return None
352414 return normalizeIAccessible (pacc , childID ), childID
353415
@@ -522,27 +584,51 @@ def winEventToNVDAEvent(eventID, window, objectID, childID, useCache=True):
522584 @returns: the NVDA event name and the NVDAObject the event is for
523585 @rtype: tuple of string and L{NVDAObjects.IAccessible.IAccessible}
524586 """
587+ if isMSAADebugLoggingEnabled ():
588+ log .debug (
589+ f"Creating NVDA event from winEvent: { getWinEventLogInfo (window , objectID , childID , eventID )} , "
590+ f"use cache { useCache } "
591+ )
525592 NVDAEventName = winEventIDsToNVDAEventNames .get (eventID , None )
526593 if not NVDAEventName :
594+ log .debugWarning (f"No NVDA event name for { getWinEventName (eventID )} " )
527595 return None
596+ if isMSAADebugLoggingEnabled ():
597+ log .debug (f"winEvent mapped to NVDA event: { NVDAEventName } " )
528598 # Ignore any events with invalid window handles
529599 if not window or not winUser .isWindow (window ):
600+ if isMSAADebugLoggingEnabled ():
601+ log .debug ("Dropping winEvent for invalid window" )
530602 return None
531603 # Make sure this window does not have a ghost window if possible
532604 if NVDAObjects .window .GhostWindowFromHungWindow and NVDAObjects .window .GhostWindowFromHungWindow (window ):
605+ if isMSAADebugLoggingEnabled ():
606+ log .debug ("Dropping winEvent for ghosted hung window" )
533607 return None
534608 # We do not support MSAA object proxied from native UIA
535609 if UIAHandler .handler and UIAHandler .handler .isUIAWindow (window ):
610+ if isMSAADebugLoggingEnabled ():
611+ log .debug (f"Dropping winEvent for native UIA window { window } ({ winUser .getClassName (window )} )" )
536612 return None
537613 obj = None
538614 if useCache :
539615 # See if we already know an object by this win event info
540616 obj = liveNVDAObjectTable .get ((window , objectID , childID ), None )
617+ if isMSAADebugLoggingEnabled () and obj :
618+ log .debug (
619+ "Fetched existing NVDAObject for winEvent from liveNVDAObjectTable: "
620+ f"{ getWinEventLogInfo (window , objectID , childID )} "
621+ )
541622 # If we don't yet have the object, then actually instanciate it.
542623 if not obj :
543624 obj = NVDAObjects .IAccessible .getNVDAObjectFromEvent (window , objectID , childID )
544625 # At this point if we don't have an object then we can't do any more
545626 if not obj :
627+ if isMSAADebugLoggingEnabled ():
628+ log .debug (
629+ "Could not instantiate an NVDAObject for winEvent: "
630+ f"{ getWinEventLogInfo (window , objectID , childID , eventID )} "
631+ )
546632 return None
547633 # SDM MSAA objects sometimes don't contain enough information to be useful Sometimes there is a real
548634 # window that does, so try to get the SDMChild property on the NVDAObject, and if successull use that as
@@ -569,6 +655,10 @@ def processGenericWinEvent(eventID, window, objectID, childID):
569655 @returns: True if the event was processed, False otherwise.
570656 @rtype: boolean
571657 """
658+ if isMSAADebugLoggingEnabled ():
659+ log .debug (
660+ f"Processing generic winEvent: { getWinEventLogInfo (window , objectID , childID , eventID )} "
661+ )
572662 # Notify appModuleHandler of this new window
573663 appModuleHandler .update (winUser .getWindowThreadProcessID (window )[0 ])
574664 # Handle particular events for the special MSAA caret object just as if they were for the focus object
@@ -577,15 +667,21 @@ def processGenericWinEvent(eventID, window, objectID, childID):
577667 winUser .EVENT_OBJECT_LOCATIONCHANGE ,
578668 winUser .EVENT_OBJECT_SHOW
579669 ):
670+ if isMSAADebugLoggingEnabled ():
671+ log .debug ("handling winEvent as caret event on focus" )
580672 NVDAEvent = ("caret" , focus )
581673 else :
582674 NVDAEvent = winEventToNVDAEvent (eventID , window , objectID , childID )
583675 if not NVDAEvent :
584676 return False
585677 if NVDAEvent [0 ] == "nameChange" and objectID == winUser .OBJID_CURSOR :
678+ if isMSAADebugLoggingEnabled ():
679+ log .debug ("Handling winEvent as mouse shape change" )
586680 mouseHandler .updateMouseShape (NVDAEvent [1 ].name )
587681 return
588682 if NVDAEvent [1 ] == focus :
683+ if isMSAADebugLoggingEnabled ():
684+ log .debug ("Directing winEvent to focus object" )
589685 NVDAEvent = (NVDAEvent [0 ], focus )
590686 eventHandler .queueEvent (* NVDAEvent )
591687 return True
@@ -605,6 +701,11 @@ def processFocusWinEvent(window, objectID, childID, force=False):
605701 @returns: True if the focus is valid and was handled, False otherwise.
606702 @rtype: boolean
607703 """
704+ if isMSAADebugLoggingEnabled ():
705+ log .debug (
706+ f"Processing focus winEvent: { getWinEventLogInfo (window , objectID , childID )} , "
707+ f"force { force } "
708+ )
608709 windowClassName = winUser .getClassName (window )
609710 # Generally, we must ignore focus on child windows of SDM windows as we only want the SDM MSAA events.
610711 # However, we don't want to ignore focus if the child ID isn't 0,
@@ -693,6 +794,10 @@ def event_gainFocus(self):
693794
694795
695796def processDesktopSwitchWinEvent (window , objectID , childID ):
797+ if isMSAADebugLoggingEnabled ():
798+ log .debug (
799+ f"Processing desktopSwitch winEvent: { getWinEventLogInfo (window , objectID , childID )} "
800+ )
696801 hDesk = windll .user32 .OpenInputDesktop (0 , False , 0 )
697802 if hDesk != 0 :
698803 windll .user32 .CloseDesktop (hDesk )
@@ -724,6 +829,10 @@ def processForegroundWinEvent(window, objectID, childID):
724829 @returns: True if the foreground was processed, False otherwise.
725830 @rtype: boolean
726831 """
832+ if isMSAADebugLoggingEnabled ():
833+ log .debug (
834+ f"Processing foreground winEvent: { getWinEventLogInfo (window , objectID , childID )} "
835+ )
727836 # Ignore foreground events on windows that aren't the current foreground window
728837 if window != winUser .getForegroundWindow ():
729838 return False
@@ -758,6 +867,10 @@ def processForegroundWinEvent(window, objectID, childID):
758867
759868
760869def processShowWinEvent (window , objectID , childID ):
870+ if isMSAADebugLoggingEnabled ():
871+ log .debug (
872+ f"Processing show winEvent: { getWinEventLogInfo (window , objectID , childID )} "
873+ )
761874 # eventHandler.shouldAcceptEvent only accepts show events for a few specific cases.
762875 # Narrow this further to only accept events for clients or custom objects.
763876 if objectID == winUser .OBJID_CLIENT or objectID > 0 :
@@ -771,6 +884,10 @@ def processDestroyWinEvent(window, objectID, childID):
771884 This removes the object associated with the event parameters from L{liveNVDAObjectTable} if
772885 such an object exists.
773886 """
887+ if isMSAADebugLoggingEnabled ():
888+ log .debug (
889+ f"Processing destroy winEvent: { getWinEventLogInfo (window , objectID , childID )} "
890+ )
774891 try :
775892 del liveNVDAObjectTable [(window , objectID , childID )]
776893 except KeyError :
@@ -796,6 +913,11 @@ def processMenuStartWinEvent(eventID, window, objectID, childID, validFocus):
796913 """Process a menuStart win event.
797914 @postcondition: Focus will be directed to the menu if appropriate.
798915 """
916+ if isMSAADebugLoggingEnabled ():
917+ log .debug (
918+ f"Processing menuStart winEvent: { getWinEventLogInfo (window , objectID , childID )} , "
919+ f"validFocus { validFocus } "
920+ )
799921 if validFocus :
800922 lastFocus = eventHandler .lastQueuedFocusObject
801923 if (
0 commit comments