Skip to content
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

BrowseMode: don't refuse to report focus changes for replaced controls or focused ancestors #8869

Merged
merged 5 commits into from
Oct 25, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 41 additions & 7 deletions source/browseMode.py
Original file line number Diff line number Diff line change
Expand Up @@ -1230,15 +1230,37 @@ def _set_selection(self, info, reason=controlTypes.REASON_CARET):
return
if obj==self.rootNVDAObject:
return
if focusObj and not eventHandler.isPendingEvents("gainFocus") and focusObj!=self.rootNVDAObject and focusObj != api.getFocusObject() and self._shouldSetFocusToObj(focusObj):
focusObj.setFocus()
# Set focus to this object, if
if (
# We actually found an object to set focus to.
focusObj
# And there are no future focus events already queued:
# If there were then setting focus here would be a waste of time as the focus would be replaced anyway.
and not eventHandler.isPendingEvents("gainFocus")
# And this object is not the root of the document:
# Setting focus to the document itself is not what the user would ever expect.
and focusObj!=self.rootNVDAObject
# This object does not already have focus
and focusObj != api.getFocusObject()
# And Only if this browseMode implementation actually wants to set focus to this kind of object:
# For instance, we may wish to set focus to a button, but not a div (if it does not have a tabindex).
and self._shouldSetFocusToObj(focusObj)
):
self.setFocusToObj(focusObj)
obj.scrollIntoView()
if self.programmaticScrollMayFireEvent:
self._lastProgrammaticScrollTime = time.time()
self.passThrough=self.shouldPassThrough(focusObj,reason=reason)
# Queue the reporting of pass through mode so that it will be spoken after the actual content.
queueHandler.queueFunction(queueHandler.eventQueue, reportPassThrough, self)

def setFocusToObj(self,obj):
"""
Sets focus to the given object in this browseMode document.
"""
self._lastFocusObj=obj
obj.setFocus()

def _shouldSetFocusToObj(self, obj):
"""Determine whether an object should receive focus.
Subclasses may extend or override this method.
Expand Down Expand Up @@ -1393,6 +1415,7 @@ def _replayFocusEnteredEvents(self):
log.exception("Error executing focusEntered event: %s" % parent)

def event_gainFocus(self, obj, nextHandler):
lastFocusObj=self._lastFocusObj
enteringFromOutside=self._enteringFromOutside
self._enteringFromOutside=False
if not self.isReady:
Expand Down Expand Up @@ -1436,12 +1459,23 @@ def event_gainFocus(self, obj, nextHandler):
self._replayFocusEnteredEvents()
return nextHandler()

try:
lastFocusInfo=self.makeTextInfo(lastFocusObj) if lastFocusObj else None
except LookupError:
lastFocusInfo=None
#We only want to update the caret and speak the field if we're not in the same one as before
caretInfo=self.makeTextInfo(textInfos.POSITION_CARET)
# Expand to one character, as isOverlapping() doesn't treat, for example, (4,4) and (4,5) as overlapping.
caretInfo.expand(textInfos.UNIT_CHARACTER)
if not self._hadFirstGainFocus or not focusInfo.isOverlapping(caretInfo):
# The virtual caret is not within the focus node.
if (
# We always want to report and update if this is the very first focus event.
not self._hadFirstGainFocus
# We should alrways report and update if the last focus no longer exists (I.e. it no longer has a position in the document):
or not lastFocusInfo
# We should report and update if The new focus starts at a different position to the last focus
or focusInfo.compareEndPoints(lastFocusInfo,"startToStart")!=0
# We should report and update if the new focus ends after the last focus:
# It is either at an entirely different position, or it is wider.
or focusInfo.compareEndPoints(lastFocusInfo,"endToEnd")>0
):
# The newly focused node is not due to the caret moving.
oldPassThrough=self.passThrough
passThrough=self.shouldPassThrough(obj,reason=controlTypes.REASON_FOCUS)
if not oldPassThrough and (passThrough or sayAllHandler.isRunning()):
Expand Down
1 change: 1 addition & 0 deletions user_docs/en/changes.t2t
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ What's New in NVDA
- Braille no longer shows font attributes if they have been disabled in Document Formatting settings. (#7615)
- NVDA no longer fails to track focus in File Explorer and other applications using UI Automation when another app is busy (such as batch processing audio). (#7345)
- In ARIA menus on the web, the Escape key will now be passed through to the menu and no longer turn off focus mode unconditionally. (#3215)
- NVDA no longer refuses to report the focus on web pages where the new focus replaces a control that no longer exists. (#6606, #8341)


== Changes for Developers ==
Expand Down