New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add the ability to automatically tether to focus or review #7489
Changes from 2 commits
33caa88
f1c59f9
3b20c56
ab56024
c630521
e862e36
57491c1
60fc8da
a3839c4
962d2dc
2bcff2e
7702a4e
2948aa4
d8fc25f
9742223
f93175b
2c43bed
5898a5e
73aebb5
2e29741
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -177,13 +177,14 @@ def getReviewPosition(): | |
globalVars.reviewPosition,globalVars.reviewPositionObj=review.getPositionForCurrentMode(obj) | ||
return globalVars.reviewPosition | ||
|
||
def setReviewPosition(reviewPosition,clearNavigatorObject=True): | ||
def setReviewPosition(reviewPosition,clearNavigatorObject=True, isCaret=False): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Comma police. :) Also, the docstring needs updating. |
||
"""Sets a TextInfo instance as the review position. if clearNavigatorObject is true, It sets the current navigator object to None so that the next time the navigator object is asked for it fetches it from the review position. | ||
""" | ||
globalVars.reviewPosition=reviewPosition.copy() | ||
globalVars.reviewPositionObj=reviewPosition.obj | ||
if clearNavigatorObject: globalVars.navigatorObject=None | ||
braille.handler.handleReviewMove() | ||
eventHandler.lastReviewMoveDueToFollowing = isCaret | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we be sure that this line and the one below it are only ever executed in one thread at a time? |
||
braille.handler.handleReviewMove(shouldAutoTether=not isCaret) | ||
|
||
def getNavigatorObject(): | ||
"""Gets the current navigator object. Navigator objects can be used to navigate around the operating system (with the number pad) with out moving the focus. If the navigator object is not set, it fetches it from the review position. | ||
|
@@ -227,6 +228,7 @@ def setNavigatorObject(obj,isFocus=False): | |
if isFocus: | ||
globalVars.reviewPosition=obj.treeInterceptor.makeTextInfo(textInfos.POSITION_CARET) | ||
globalVars.reviewPositionObj=globalVars.reviewPosition | ||
eventHandler.lastReviewMoveDueToFollowing = isFocus | ||
eventHandler.executeEvent("becomeNavigatorObject",obj) | ||
|
||
def isTypingProtected(): | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -90,10 +90,10 @@ def event_appModule_gainFocus(self): | |
# Move the review cursor so others can't access its previous position. | ||
self._oldReviewPos = api.getReviewPosition() | ||
self._oldReviewObj = self._oldReviewPos.obj | ||
api.setNavigatorObject(eventHandler.lastQueuedFocusObject) | ||
api.setNavigatorObject(eventHandler.lastQueuedFocusObject, isFocus=True) | ||
|
||
def event_appModule_loseFocus(self): | ||
if not config.conf["reviewCursor"]["followFocus"]: | ||
api.setReviewPosition(self._oldReviewPos) | ||
api.setReviewPosition(self._oldReviewPos, isCaret=False) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As isCaret is False by default, explicitly specifying isCaret=False here is not needed, and is perhaps a little confusing. I'd prefer that anywhere in the codebase that isCaret is only ever specified if it needs to be set to true. Mirroring that of isFocus for setNavigatorObject. |
||
del self._oldReviewPos, self._oldReviewObj | ||
inputCore.manager._captureFunc = None |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -28,6 +28,7 @@ | |
from collections import namedtuple | ||
import re | ||
import scriptHandler | ||
import eventHandler | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not too happy with another circular dependency, but I know we discussed this before and all solutions we came up with were hacky. |
||
|
||
roleLabels = { | ||
# Translators: Displayed in braille for an object which is a | ||
|
@@ -1450,6 +1451,7 @@ def __init__(self): | |
self._cells = [] | ||
self._cursorBlinkTimer = None | ||
config.configProfileSwitched.register(self.handleConfigProfileSwitch) | ||
self._tether = config.conf["braille"]["tetherTo"] | ||
|
||
def terminate(self): | ||
if self._messageCallLater: | ||
|
@@ -1464,18 +1466,34 @@ def terminate(self): | |
self.display = None | ||
_BgThread.stop() | ||
|
||
def getTether(self): | ||
return self._tether | ||
|
||
def _get_tether(self): | ||
return config.conf["braille"]["tetherTo"] | ||
"""@deprecated: Use L{getTether instead.""" | ||
return self.getTether() | ||
|
||
def _set_tether(self, tether): | ||
if tether == config.conf["braille"]["tetherTo"]: | ||
def setTether(self, tether, auto=False): | ||
if auto and not self.shouldAutoTether: | ||
return | ||
if auto and tether == self.TETHER_REVIEW and eventHandler.lastReviewMoveDueToFollowing: | ||
return | ||
config.conf["braille"]["tetherTo"] = tether | ||
if not auto: | ||
config.conf["braille"]["tetherTo"] = tether | ||
if tether == self._tether: | ||
return | ||
self._tether = tether | ||
self.mainBuffer.clear() | ||
if tether == self.TETHER_REVIEW: | ||
self.handleReviewMove() | ||
else: | ||
self.handleGainFocus(api.getFocusObject()) | ||
|
||
def _set_tether(self, tether): | ||
"""@deprecated: Use L{setTether instead.""" | ||
self.setTether(tether, auto=False) | ||
|
||
def _get_isAutoTethered(self): | ||
return self._tether is not config.conf["braille"]["tetherTo"] | ||
|
||
def _get_shouldAutoTether(self): | ||
return self.enabled and config.conf["braille"]["autoTether"] | ||
|
||
def setDisplayByName(self, name, isFallback=False): | ||
if not name: | ||
|
@@ -1640,10 +1658,12 @@ def _dismissMessage(self): | |
self._messageCallLater = None | ||
self.update() | ||
|
||
def handleGainFocus(self, obj): | ||
def handleGainFocus(self, obj, shouldAutoTether=True): | ||
if not self.enabled: | ||
return | ||
if self.tether != self.TETHER_FOCUS: | ||
if shouldAutoTether: | ||
self.setTether(self.TETHER_FOCUS, auto=True) | ||
elif self._tether != self.TETHER_FOCUS: | ||
return | ||
self._doNewObject(itertools.chain(getFocusContextRegions(obj, oldFocusRegions=self.mainBuffer.regions), getFocusRegions(obj))) | ||
|
||
|
@@ -1672,12 +1692,12 @@ def _doNewObject(self, regions): | |
elif self.buffer is self.messageBuffer and keyboardHandler.keyCounter>self._keyCountForLastMessage: | ||
self._dismissMessage() | ||
|
||
def handleCaretMove(self, obj): | ||
def handleCaretMove(self, obj, shouldAutoTether=True): | ||
if not self.enabled: | ||
return | ||
if self.tether != self.TETHER_FOCUS: | ||
return | ||
if not self.mainBuffer.regions: | ||
if shouldAutoTether: | ||
self.setTether(self.TETHER_FOCUS, auto=True) | ||
elif self._tether != self.TETHER_FOCUS or not self.mainBuffer.regions: | ||
return | ||
region = self.mainBuffer.regions[-1] | ||
if region.obj is not obj: | ||
|
@@ -1742,7 +1762,7 @@ def handleUpdate(self, obj): | |
# There are some objects that require special update behavior even if they have no region. | ||
# This only applies when tethered to focus, because tethering to review shows only one object at a time, | ||
# which always has a braille region associated with it. | ||
if self.tether != self.TETHER_FOCUS: | ||
if self._tether != self.TETHER_FOCUS: | ||
return | ||
# Late import to avoid circular import. | ||
from NVDAObjects import NVDAObject | ||
|
@@ -1758,12 +1778,16 @@ def handleUpdate(self, obj): | |
elif self.buffer is self.messageBuffer and keyboardHandler.keyCounter>self._keyCountForLastMessage: | ||
self._dismissMessage() | ||
|
||
def handleReviewMove(self): | ||
def handleReviewMove(self, shouldAutoTether=True): | ||
if not self.enabled: | ||
return | ||
if self.tether != self.TETHER_REVIEW: | ||
if not shouldAutoTether and self._tether != self.TETHER_REVIEW: | ||
return | ||
reviewPos = api.getReviewPosition() | ||
#if reviewPos.obj == api.getFocusObject() and config.conf["reviewCursor"]["followFocus"]: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would say just remove these two lines. |
||
#return | ||
if shouldAutoTether: | ||
self.setTether(self.TETHER_REVIEW, auto=True) | ||
region = self.mainBuffer.regions[-1] if self.mainBuffer.regions else None | ||
if region and region.obj == reviewPos.obj: | ||
self._doCursorMove(region) | ||
|
@@ -1851,9 +1875,9 @@ def initialize(): | |
# Braille is disabled or focus/review hasn't yet been initialised. | ||
return | ||
if handler.tether == handler.TETHER_FOCUS: | ||
handler.handleGainFocus(api.getFocusObject()) | ||
handler.handleGainFocus(api.getFocusObject(), shouldAutoTether=False) | ||
else: | ||
handler.handleReviewMove() | ||
handler.handleReviewMove(shouldAutoTether=False) | ||
|
||
def pumpAll(): | ||
"""Runs tasks at the end of each core cycle. For now just caret updates.""" | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -61,6 +61,7 @@ | |
noMessageTimeout = boolean(default=false) | ||
messageTimeout = integer(default=4,min=0,max=20) | ||
tetherTo = string(default="focus") | ||
autoTether= boolean(default=false) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Space. |
||
readByParagraph = boolean(default=false) | ||
wordWrap = boolean(default=true) | ||
focusContextPresentation = option("changedContext", "fill", "scroll", default="changedContext") | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This variable name isn't very clear if you don't have the surrounding context of this PR. Maybe choose another name?