11# A part of NonVisual Desktop Access (NVDA)
2- # Copyright (C) 2008-2021 NV Access Limited, Joseph Lee, Babbage B.V., Leonard de Ruijter, Bill Dengler
2+ # Copyright (C) 2008-2022 NV Access Limited, Joseph Lee, Babbage B.V., Leonard de Ruijter, Bill Dengler
33# This file is covered by the GNU General Public License.
44# See the file COPYING for more details.
55
9999 "Shell_SystemDialog" , # Various dialogs in Windows 10 Settings app
100100]
101101
102+ textChangeUIAAutomationIDs = (
103+ "Text Area" , # Windows Console Host
104+ )
105+
106+ textChangeUIAClassNames = (
107+ "_WwG" , # Microsoft Word
108+ "TermControl" ,
109+ "TermControl2"
110+ )
111+
102112NVDAUnitsToUIAUnits : Dict [str , int ] = {
103113 textInfos .UNIT_CHARACTER : UIA .TextUnit_Character ,
104114 textInfos .UNIT_WORD : UIA .TextUnit_Word ,
206216autoSelectDetectionAvailable = False
207217if winVersion .getWinVer () >= winVersion .WIN10 :
208218 UIAEventIdsToNVDAEventNames .update ({
209- UIA .UIA_Text_TextChangedEventId : "textChange" ,
210219 UIA .UIA_Text_TextSelectionChangedEventId : "caret" ,
211220 })
212221 localEventHandlerGroupUIAEventIds .update ({
213- UIA .UIA_Text_TextChangedEventId ,
214222 UIA .UIA_Text_TextSelectionChangedEventId ,
215223 })
216224 autoSelectDetectionAvailable = True
@@ -268,6 +276,7 @@ def __init__(self):
268276 super (UIAHandler ,self ).__init__ ()
269277 self .globalEventHandlerGroup = None
270278 self .localEventHandlerGroup = None
279+ self .localEventHandlerGroupWithTextChanges = None
271280 self ._localEventHandlerGroupElements = set ()
272281 self .MTAThreadInitEvent = threading .Event ()
273282 self .MTAThreadQueue = Queue ()
@@ -403,6 +412,17 @@ def _registerGlobalEventHandlers(self):
403412 self .baseCacheRequest ,
404413 self
405414 )
415+ if (
416+ not utils ._shouldSelectivelyRegister ()
417+ and winVersion .getWinVer () >= winVersion .WIN10
418+ ):
419+ # #14067: Due to poor performance, textChange requires special handling
420+ self .globalEventHandlerGroup .AddAutomationEventHandler (
421+ UIA .UIA_Text_TextChangedEventId ,
422+ UIA .TreeScope_Subtree ,
423+ self .baseCacheRequest ,
424+ self
425+ )
406426 # #7984: add support for notification event (IUIAutomation5, part of Windows 10 build 16299 and later).
407427 if isinstance (self .clientObject , UIA .IUIAutomation5 ):
408428 self .globalEventHandlerGroup .AddNotificationEventHandler (
@@ -421,21 +441,41 @@ def _registerGlobalEventHandlers(self):
421441 def _createLocalEventHandlerGroup (self ):
422442 if isinstance (self .clientObject , UIA .IUIAutomation6 ):
423443 self .localEventHandlerGroup = self .clientObject .CreateEventHandlerGroup ()
444+ self .localEventHandlerGroupWithTextChanges = self .clientObject .CreateEventHandlerGroup ()
424445 else :
425446 self .localEventHandlerGroup = utils .FakeEventHandlerGroup (self .clientObject )
447+ self .localEventHandlerGroupWithTextChanges = utils .FakeEventHandlerGroup (self .clientObject )
426448 self .localEventHandlerGroup .AddPropertyChangedEventHandler (
427449 UIA .TreeScope_Ancestors | UIA .TreeScope_Element ,
428450 self .baseCacheRequest ,
429451 self ,
430452 * self .clientObject .IntSafeArrayToNativeArray (localEventHandlerGroupUIAPropertyIds )
431453 )
454+ self .localEventHandlerGroupWithTextChanges .AddPropertyChangedEventHandler (
455+ UIA .TreeScope_Ancestors | UIA .TreeScope_Element ,
456+ self .baseCacheRequest ,
457+ self ,
458+ * self .clientObject .IntSafeArrayToNativeArray (localEventHandlerGroupUIAPropertyIds )
459+ )
432460 for eventId in localEventHandlerGroupUIAEventIds :
433461 self .localEventHandlerGroup .AddAutomationEventHandler (
434462 eventId ,
435463 UIA .TreeScope_Ancestors | UIA .TreeScope_Element ,
436464 self .baseCacheRequest ,
437465 self
438466 )
467+ self .localEventHandlerGroupWithTextChanges .AddAutomationEventHandler (
468+ eventId ,
469+ UIA .TreeScope_Ancestors | UIA .TreeScope_Element ,
470+ self .baseCacheRequest ,
471+ self
472+ )
473+ self .localEventHandlerGroupWithTextChanges .AddAutomationEventHandler (
474+ UIA .UIA_Text_TextChangedEventId ,
475+ UIA .TreeScope_Ancestors | UIA .TreeScope_Element ,
476+ self .baseCacheRequest ,
477+ self
478+ )
439479
440480 def addEventHandlerGroup (self , element , eventHandlerGroup ):
441481 if isinstance (eventHandlerGroup , UIA .IUIAutomationEventHandlerGroup ):
@@ -466,7 +506,23 @@ def func():
466506 if not isStillFocus :
467507 return
468508 try :
469- self .addEventHandlerGroup (element , self .localEventHandlerGroup )
509+ if (
510+ element .currentClassName in textChangeUIAClassNames
511+ or element .CachedAutomationID in textChangeUIAAutomationIDs
512+ ):
513+ group = self .localEventHandlerGroupWithTextChanges
514+ logPrefix = "Explicitly"
515+ else :
516+ group = self .localEventHandlerGroup
517+ logPrefix = "Not"
518+
519+ if _isDebug ():
520+ log .debugWarning (
521+ f"{ logPrefix } registering for textChange events from UIA element "
522+ f"with class name { repr (element .currentClassName )} "
523+ f"and automation ID { repr (element .CachedAutomationID )} "
524+ )
525+ self .addEventHandlerGroup (element , group )
470526 except COMError :
471527 log .error ("Could not register for UIA events for element" , exc_info = True )
472528 else :
@@ -500,7 +556,22 @@ def IUIAutomationEventHandler_HandleAutomationEvent(self,sender,eventID):
500556 if _isDebug ():
501557 log .debug ("HandleAutomationEvent: Ignored MenuOpenedEvent while focus event pending" )
502558 return
503- NVDAEventName = UIAEventIdsToNVDAEventNames .get (eventID ,None )
559+ if eventID == UIA .UIA_Text_TextChangedEventId :
560+ if (
561+ sender .currentClassName in textChangeUIAClassNames
562+ or sender .CachedAutomationID in textChangeUIAAutomationIDs
563+ ):
564+ NVDAEventName = "textChange"
565+ else :
566+ if _isDebug ():
567+ log .debugWarning (
568+ "HandleAutomationEvent: Dropping textChange event from element "
569+ f"with class name { repr (sender .currentClassName )} "
570+ f"and automation ID { repr (sender .CachedAutomationID )} "
571+ )
572+ return
573+ else :
574+ NVDAEventName = UIAEventIdsToNVDAEventNames .get (eventID , None )
504575 if not NVDAEventName :
505576 if _isDebug ():
506577 log .debugWarning (f"HandleAutomationEvent: Don't know how to handle event { eventID } " )
0 commit comments