@@ -1569,6 +1569,7 @@ def bufferPosToRegionPos(self, bufferPos):
15691569 raise LookupError ("No such position" )
15701570
15711571 def regionPosToBufferPos (self , region , pos , allowNearest = False ):
1572+ start : int = 0
15721573 for testRegion , start , end in self .regionsWithPositions :
15731574 if region == testRegion :
15741575 if pos < end - start :
@@ -2003,6 +2004,10 @@ def formatCellsForLog(cells: List[int]) -> str:
20032004"""
20042005
20052006
2007+ UPDATE_DISPLAY_PERIODICALLY_INTERVAL : int = 250
2008+ """Timer interval for L{BrailleHandler._updateDisplayPeriodically}."""
2009+
2010+
20062011class BrailleHandler (baseObject .AutoPropertyObject ):
20072012 # TETHER_AUTO, TETHER_FOCUS, TETHER_REVIEW and tetherValues
20082013 # are deprecated, but remain to retain API backwards compatibility
@@ -2042,6 +2047,10 @@ def __init__(self):
20422047 self ._cursorPos = None
20432048 self ._cursorBlinkUp = True
20442049 self ._cells = []
2050+ self ._oldCells : List [int ] = []
2051+ self ._updateTimer = gui .NonReEntrantTimer (self ._updateDisplayPeriodically )
2052+ # Start from main thread
2053+ wx .CallAfter (self ._updateTimer .Start , UPDATE_DISPLAY_PERIODICALLY_INTERVAL )
20452054 self ._cursorBlinkTimer = None
20462055 config .post_configProfileSwitch .register (self .handlePostConfigProfileSwitch )
20472056 if config .conf ["braille" ]["tetherTo" ] == TetherTo .AUTO .value :
@@ -2064,6 +2073,9 @@ def terminate(self):
20642073 if self ._cursorBlinkTimer :
20652074 self ._cursorBlinkTimer .Stop ()
20662075 self ._cursorBlinkTimer = None
2076+ if self ._updateTimer :
2077+ self ._updateTimer .Stop ()
2078+ self ._updateTimer = None
20672079 config .post_configProfileSwitch .unregister (self .handlePostConfigProfileSwitch )
20682080 if self .display :
20692081 self .display .terminate ()
@@ -2468,6 +2480,12 @@ def handleCaretMove(
24682480 if shouldAutoTether :
24692481 self .setTether (TetherTo .FOCUS .value , auto = True )
24702482 if self ._tether != TetherTo .FOCUS .value :
2483+ # Braille display content is updated in case where:
2484+ # braille is tethered to review, review cursor does not follow system caret,
2485+ # and focus object is navigator object.
2486+ if not config .conf ["reviewCursor" ]["followCaret" ]:
2487+ if obj == api .getNavigatorObject ():
2488+ self .handleUpdate (obj )
24712489 return
24722490 region = self .mainBuffer .regions [- 1 ] if self .mainBuffer .regions else None
24732491 if region and region .obj == obj :
@@ -2552,10 +2570,13 @@ def handleUpdate(self, obj: "NVDAObject") -> None:
25522570 region .update ()
25532571 self .mainBuffer .update ()
25542572 self .mainBuffer .restoreWindow ()
2573+ if self ._oldCells == self .buffer .windowBrailleCells :
2574+ return
25552575 if self .buffer is self .mainBuffer :
25562576 self .update ()
25572577 elif self .buffer is self .messageBuffer and keyboardHandler .keyCounter > self ._keyCountForLastMessage :
25582578 self ._dismissMessage ()
2579+ self ._oldCells = self .buffer .windowBrailleCells .copy ()
25592580
25602581 def handleReviewMove (self , shouldAutoTether = True ):
25612582 if not self .enabled :
@@ -2686,6 +2707,19 @@ def _ackTimeoutResetter(self, param: int):
26862707 self .display ._awaitingAck = False
26872708 self ._writeCellsInBackground ()
26882709
2710+ def _updateDisplayPeriodically (self ):
2711+ """Timer runs this function periodically to check if braille needs update."""
2712+ if self .buffer is not self .mainBuffer :
2713+ return
2714+ obj : NVDAObject
2715+ if api .isObjectInActiveTreeInterceptor (api .getNavigatorObject ()):
2716+ obj = api .getCaretObject ()
2717+ elif handler .getTether () == TetherTo .FOCUS .value :
2718+ obj = api .getFocusObject ()
2719+ else :
2720+ obj = api .getNavigatorObject ()
2721+ self .handleUpdate (obj )
2722+
26892723
26902724# Maps old braille display driver names to new drivers that supersede old drivers.
26912725# Ensure that if a user has set a preferred driver which has changed name, the new
@@ -2728,6 +2762,7 @@ def terminate():
27282762 handler .terminate ()
27292763 handler = None
27302764
2765+
27312766class BrailleDisplayDriver (driverHandler .Driver ):
27322767 """Abstract base braille display driver.
27332768 Each braille display driver should be a separate Python module in the root brailleDisplayDrivers directory
0 commit comments