Skip to content

Commit

Permalink
Merge c8fc7a4 into 33694a0
Browse files Browse the repository at this point in the history
  • Loading branch information
burmancomp committed Jul 25, 2023
2 parents 33694a0 + c8fc7a4 commit 0c530a1
Showing 1 changed file with 101 additions and 1 deletion.
102 changes: 101 additions & 1 deletion source/braille.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
Tuple,
Union,
Type,
Callable,
)
from locale import strxfrm

Expand All @@ -42,6 +43,7 @@
TetherTo,
ReportTableHeaders,
)
from config.featureFlag import FeatureFlag
from config.featureFlagEnums import ReviewRoutingMovesSystemCaretFlag
from logHandler import log
import controlTypes
Expand All @@ -53,6 +55,7 @@
import re
import scriptHandler
import collections
from collections import deque
import extensionPoints
import hwPortUtils
import bdDetect
Expand Down Expand Up @@ -1569,6 +1572,7 @@ def bufferPosToRegionPos(self, bufferPos):
raise LookupError("No such position")

def regionPosToBufferPos(self, region, pos, allowNearest=False):
start: int = 0
for testRegion, start, end in self.regionsWithPositions:
if region == testRegion:
if pos < end - start:
Expand Down Expand Up @@ -2003,6 +2007,44 @@ def formatCellsForLog(cells: List[int]) -> str:
"""


class UpdateTimer:
"""Repeating timer for keeping display content always up to date."""

def __init__(
self,
interval: float,
updateFunction: Callable[[], None]
):
"""Constructor.
@param interval: Checking frequency
@param updateFunction: Update display
"""
self._interval = interval
self._timer = threading.Timer(self._interval, self._run)
self._updateFunction = updateFunction
self.is_running = False
self.start()

def _run(self):
self.is_running = False
self.start()
self._updateFunction()

def start(self):
if not self.is_running:
self._timer = threading.Timer(self._interval, self._run)
self._timer.start()
self.is_running = True

def stop(self):
self._timer.cancel()
self.is_running = False


BRAILLE_UPDATE_CHECK_INTERVAL: float = 0.5
"""Timer interval in milliseconds for L{BrailleHandler._enqueueBrailleUpdateCheck}."""


class BrailleHandler(baseObject.AutoPropertyObject):
# TETHER_AUTO, TETHER_FOCUS, TETHER_REVIEW and tetherValues
# are deprecated, but remain to retain API backwards compatibility
Expand Down Expand Up @@ -2042,6 +2084,17 @@ def __init__(self):
self._cursorPos = None
self._cursorBlinkUp = True
self._cells = []
self._oldCells: List[int] = []
self._showSelection: FeatureFlag = config.conf["braille"]["showSelection"]
self._showCursor: bool = config.conf["braille"]["showCursor"]
# Was braille line updated during previous timer cycle.
self._alreadyUpdated: bool = False
self._handleUpdateQueue = deque(maxlen=1)
self._updateTimer = UpdateTimer(
BRAILLE_UPDATE_CHECK_INTERVAL,
self._enqueueBrailleUpdateCheck
)
self._updateTimer.start()
self._cursorBlinkTimer = None
config.post_configProfileSwitch.register(self.handlePostConfigProfileSwitch)
if config.conf["braille"]["tetherTo"] == TetherTo.AUTO.value:
Expand All @@ -2064,6 +2117,9 @@ def terminate(self):
if self._cursorBlinkTimer:
self._cursorBlinkTimer.Stop()
self._cursorBlinkTimer = None
if self._updateTimer:
self._updateTimer.stop()
self._updateTimer = None
config.post_configProfileSwitch.unregister(self.handlePostConfigProfileSwitch)
if self.display:
self.display.terminate()
Expand Down Expand Up @@ -2341,6 +2397,10 @@ def update(self):
self._cells = cells + [0] * (self.displaySize - len(cells))
self._cursorPos = self.buffer.cursorWindowPos
self._updateDisplay()
self._oldCells = self.buffer.windowBrailleCells.copy()
self._showSelection = config.conf["braille"]["showSelection"]
self._showCursor = config.conf["braille"]["showCursor"]
self._alreadyUpdated = True

def scrollForward(self):
self.buffer.scrollForward()
Expand Down Expand Up @@ -2468,6 +2528,12 @@ def handleCaretMove(
if shouldAutoTether:
self.setTether(TetherTo.FOCUS.value, auto=True)
if self._tether != TetherTo.FOCUS.value:
# Braille display content is updated in case where:
# braille is tethered to review, review cursor does not follow system caret,
# and focus object is navigator object.
if not config.conf["reviewCursor"]["followCaret"]:
if obj == api.getNavigatorObject():
self.handleUpdate(obj)
return
region = self.mainBuffer.regions[-1] if self.mainBuffer.regions else None
if region and region.obj==obj:
Expand Down Expand Up @@ -2552,6 +2618,8 @@ def handleUpdate(self, obj: "NVDAObject") -> None:
region.update()
self.mainBuffer.update()
self.mainBuffer.restoreWindow()
if self._oldCells == self.buffer.windowBrailleCells:
return
if self.buffer is self.mainBuffer:
self.update()
elif self.buffer is self.messageBuffer and keyboardHandler.keyCounter>self._keyCountForLastMessage:
Expand Down Expand Up @@ -2686,6 +2754,35 @@ def _ackTimeoutResetter(self, param: int):
self.display._awaitingAck = False
self._writeCellsInBackground()

def _brailleUpdateCheck(self) -> None:
"""Braille may need update when show cursor or show selection state change or when in terminal window."""
if self.buffer is not self.mainBuffer:
return
if self._alreadyUpdated:
self._alreadyUpdated = False
return
obj: NVDAObject
if api.isObjectInActiveTreeInterceptor(api.getNavigatorObject()):
obj = api.getCaretObject()
elif self.getTether() == TetherTo.FOCUS.value:
obj = api.getFocusObject()
else:
obj = api.getNavigatorObject()
# Handles updates in terminal windows, and also "show selection" state
# change in all appropriate windows.
if (
hasattr(obj, "role") and obj.role == controlTypes.Role.TERMINAL
or self._showSelection != config.conf["braille"]["showSelection"]
):
self.handleUpdate(obj)
# Toggles braille cursor in other appropriate windows.
if self._showCursor != config.conf["braille"]["showCursor"]:
self.update()

def _enqueueBrailleUpdateCheck(self) -> None:
"""Enques braille update check."""
self._handleUpdateQueue.append(self._brailleUpdateCheck)


# Maps old braille display driver names to new drivers that supersede old drivers.
# Ensure that if a user has set a preferred driver which has changed name, the new
Expand Down Expand Up @@ -2720,14 +2817,17 @@ def initialize():
handler.setDisplayByName(config.conf["braille"]["display"])

def pumpAll():
"""Runs tasks at the end of each core cycle. For now just caret updates."""
"""Runs tasks at the end of each core cycle."""
if len(handler._handleUpdateQueue):
handler._handleUpdateQueue.popleft()()
handler.handlePendingCaretUpdate()

def terminate():
global handler
handler.terminate()
handler = None


class BrailleDisplayDriver(driverHandler.Driver):
"""Abstract base braille display driver.
Each braille display driver should be a separate Python module in the root brailleDisplayDrivers directory
Expand Down

0 comments on commit 0c530a1

Please sign in to comment.