3636import extensionPoints
3737import hwPortUtils
3838import bdDetect
39- import winUser
39+ import brailleViewer
4040import queueHandler
4141
4242roleLabels = {
@@ -1205,7 +1205,6 @@ def _get_regionsWithPositions(self):
12051205 yield RegionWithPositions (region , start , end )
12061206 start = end
12071207
1208- _cache_rawToBraillePos = True
12091208 def _get_rawToBraillePos (self ):
12101209 """@return: a list mapping positions in L{rawText} to positions in L{brailleCells} for the entire buffer.
12111210 @rtype: [int, ...]
@@ -1215,7 +1214,8 @@ def _get_rawToBraillePos(self):
12151214 rawToBraillePos .extend (p + regionStart for p in region .rawToBraillePos )
12161215 return rawToBraillePos
12171216
1218- _cache_brailleToRawPos = True
1217+ brailleToRawPos : List [int ]
1218+
12191219 def _get_brailleToRawPos (self ):
12201220 """@return: a list mapping positions in L{brailleCells} to positions in L{rawText} for the entire buffer.
12211221 @rtype: [int, ...]
@@ -1250,7 +1250,25 @@ def regionPosToBufferPos(self, region, pos, allowNearest=False):
12501250 raise LookupError ("No such position" )
12511251
12521252 def bufferPositionsToRawText (self , startPos , endPos ):
1253- return self .rawText [self .brailleToRawPos [startPos ]:self .brailleToRawPos [endPos - 1 ]+ 1 ]
1253+ brailleToRawPos = self .brailleToRawPos
1254+ if not brailleToRawPos or not self .rawText :
1255+ # if either are empty, just return an empty string.
1256+ return ""
1257+ try :
1258+ lastIndex = len (brailleToRawPos ) - 1
1259+ rawTextStart = brailleToRawPos [min (lastIndex , startPos )]
1260+ rawTextEnd = brailleToRawPos [min (lastIndex , endPos )] + 1
1261+ lastIndex = len (self .rawText )
1262+ return self .rawText [rawTextStart :min (lastIndex , rawTextEnd )]
1263+ except IndexError :
1264+ log .debugWarning (
1265+ f"Unable to get raw text for buffer positions"
1266+ f"(startPos-endPos): { startPos } -{ endPos } , "
1267+ f"for rawText: { self .rawText } , "
1268+ f"with brailleToRawPos: { brailleToRawPos } " ,
1269+ exc_info = True
1270+ )
1271+ return ""
12541272
12551273 def bufferPosToWindowPos (self , bufferPos ):
12561274 if not (self .windowStartPos <= bufferPos < self .windowEndPos ):
@@ -1589,14 +1607,13 @@ class BrailleHandler(baseObject.AutoPropertyObject):
15891607 def __init__ (self ):
15901608 louisHelper .initialize ()
15911609 self .display : Optional [BrailleDisplayDriver ] = None
1592- self .displaySize = 0
1610+ #: Number of cells the connected device (or if no device connected, what braille viewer has)
1611+ #: Zero cells disables braille. See L{_get_enabled}
1612+ self ._displaySize : int = 0
15931613 self .mainBuffer = BrailleBuffer (self )
15941614 self .messageBuffer = BrailleBuffer (self )
15951615 self ._messageCallLater = None
15961616 self .buffer = self .mainBuffer
1597- #: Whether braille is enabled.
1598- #: @type: bool
1599- self .enabled = False
16001617 self ._keyCountForLastMessage = 0
16011618 self ._cursorPos = None
16021619 self ._cursorBlinkUp = True
@@ -1606,6 +1623,8 @@ def __init__(self):
16061623 self ._tether = config .conf ["braille" ]["tetherTo" ]
16071624 self ._detectionEnabled = False
16081625 self ._detector = None
1626+ self ._rawText = u""
1627+ brailleViewer .postBrailleViewerToolToggledAction .register (self ._onBrailleViewerChangedState )
16091628
16101629 def terminate (self ):
16111630 bgThreadStopTimeout = 2.5 if self ._detectionEnabled else None
@@ -1639,6 +1658,24 @@ def setTether(self, tether, auto=False):
16391658 def _get_shouldAutoTether (self ):
16401659 return self .enabled and config .conf ["braille" ]["autoTether" ]
16411660
1661+ displaySize : int
1662+
1663+ def _get_displaySize (self ):
1664+ if self ._displaySize == 0 and brailleViewer .isBrailleViewerActive ():
1665+ return brailleViewer .DEFAULT_NUM_CELLS
1666+ return self ._displaySize
1667+
1668+ def _set_displaySize (self , numCells ):
1669+ """The display size can be changed while a display is connected, for instance
1670+ see L{brailleDisplayDrivers.alva.BrailleDisplayDriver} split point feature.
1671+ """
1672+ self ._displaySize = numCells
1673+
1674+ enabled : bool
1675+
1676+ def _get_enabled (self ):
1677+ return bool (self .displaySize )
1678+
16421679 _lastRequestedDisplayName = None #: the name of the last requested braille display driver with setDisplayByName, even if it failed and has fallen back to no braille.
16431680 def setDisplayByName (self , name , isFallback = False , detected = None ):
16441681 if not isFallback :
@@ -1666,13 +1703,14 @@ def setDisplayByName(self, name, isFallback=False, detected=None):
16661703
16671704 try :
16681705 newDisplay = _getDisplayDriver (name )
1706+ oldDisplay = self .display
16691707 if detected and bdDetect ._isDebug ():
16701708 log .debug ("Possibly detected display '%s'" % newDisplay .description )
1671- if newDisplay == self . display .__class__ :
1709+ if newDisplay == oldDisplay .__class__ :
16721710 # This is the same driver as was already set, so just re-initialise it.
16731711 log .debug ("Reinitializing %s braille display" % name )
1674- self . display .terminate ()
1675- newDisplay = self . display
1712+ oldDisplay .terminate ()
1713+ newDisplay = oldDisplay
16761714 try :
16771715 newDisplay .__init__ (** kwargs )
16781716 except TypeError :
@@ -1697,8 +1735,7 @@ def setDisplayByName(self, name, isFallback=False, detected=None):
16971735 log .error ("Error terminating previous display driver" , exc_info = True )
16981736 self .display = newDisplay
16991737 newDisplay .initSettings ()
1700- self .displaySize = newDisplay .numCells
1701- self .enabled = bool (self .displaySize )
1738+ self ._displaySize = newDisplay .numCells
17021739 if isFallback :
17031740 if self ._detectionEnabled and not self ._detector :
17041741 # As this is the fallback display, which is usually noBraille,
@@ -1723,6 +1760,11 @@ def setDisplayByName(self, name, isFallback=False, detected=None):
17231760 self .setDisplayByName ("noBraille" , isFallback = True )
17241761 return False
17251762
1763+ def _onBrailleViewerChangedState (self , created ):
1764+ if created :
1765+ self ._updateDisplay ()
1766+ log .debug ("Braille Viewer enabled: {}" .format (self .enabled ))
1767+
17261768 def _updateDisplay (self ):
17271769 if self ._cursorBlinkTimer :
17281770 self ._cursorBlinkTimer .Stop ()
@@ -1740,6 +1782,7 @@ def _updateDisplay(self):
17401782 wx .CallAfter (self ._cursorBlinkTimer .Start ,blinkRate )
17411783
17421784 def _writeCells (self , cells ):
1785+ brailleViewer .update (cells , self ._rawText )
17431786 if not self .display .isThreadSafe :
17441787 try :
17451788 self .display .display (cells )
@@ -1775,6 +1818,7 @@ def _blink(self):
17751818
17761819 def update (self ):
17771820 cells = self .buffer .windowBrailleCells
1821+ self ._rawText = self .buffer .windowRawText
17781822 if log .isEnabledFor (log .IO ):
17791823 log .io ("Braille window dots: %s" % formatCellsForLog (cells ))
17801824 # cells might not be the full length of the display.
0 commit comments