Skip to content

Dispatch browse mode alt+arrow gestures between collapse or expand and sentence navigation - #20751

Open
LeonarddeR wants to merge 4 commits into
nvaccess:masterfrom
LeonarddeR:browseModeSentenceNav
Open

Dispatch browse mode alt+arrow gestures between collapse or expand and sentence navigation#20751
LeonarddeR wants to merge 4 commits into
nvaccess:masterfrom
LeonarddeR:browseModeSentenceNav

Conversation

@LeonarddeR

@LeonarddeR LeonarddeR commented Aug 27, 2026

Copy link
Copy Markdown
Collaborator

Link to issue number:

Part of #18901.
Follow up for #20603.
Supersedes #16384.

Summary of the issue:

NVDA binds alt+upArrow and alt+downArrow to sentence navigation commands. Browse mode inherits these commands from the cursor manager. Browse mode also bound the same keys to the command that collapses or expands the current control. Bindings from more derived classes win, so the collapse or expand binding shadowed the sentence commands. Sentence navigation was therefore unreachable in browse mode, even with the working backend added in #20603.

Description of user facing changes:

In browse mode, alt+upArrow and alt+downArrow now move the caret by sentence in document content. Controls that use these keys themselves keep the old behaviour: they still collapse or expand. This covers comboboxes and other controls that are collapsed, expanded, have a popup, or offer autocompletion. Where a document does not support sentences at all, NVDA now says so rather than doing nothing. Microsoft Word already reported this, and the same message is now used everywhere. The user guide no longer limits sentence navigation to Word and Outlook. A changelog entry is added.

Description of developer facing changes:

BrowseModeDocumentTreeInterceptor overrides getAlternativeScript. It returns script_collapseOrExpandControl in place of the sentence script when a control at the caret takes these keys itself. A new helper, _isExpandableControlAtCaret, makes that decision. The two static gesture bindings to collapseOrExpandControl are removed. The sentence scripts themselves are not overridden. Instead the ones in cursorManager route through a new _moveBySentence_scriptHelper. It catches a NotImplementedError from the text info and reports it, reusing the message Microsoft Word already shows. Every cursor manager gains this, not only browse mode. This also has the advantage that PowerPoint slideshows no longer raise NotImplementedError when pressing sentence navigation gestures.

Description of development approach:

The keys are no longer bound to one fixed command. Instead the choice is made while NVDA is still working out which command a key press belongs to. Browse mode already has a hook for that, used today for single letter navigation. The hook looks at the focusable control at the caret. That is the same object the collapse or expand script acts on. If that control takes these keys itself, the hook hands the key to the collapse or expand command. Otherwise the sentence command runs unchanged. Choosing this early means the command NVDA reports is the command that runs. It also means only sentence navigation resumes say all. In documents without sentence support, the keys say so instead of raising an error. The SentenceNav add-on resolves the same conflict in the same way.

Comparison with the earlier attempt in #16384:

Sentence navigation was attempted before in #16384 by @mltony. It was closed in September 2024 because it had stalled, not because the approach was rejected.

That work found sentence boundaries with a regular expression. It carried a list of non-breaking prefixes, so that abbreviations did not end a sentence. Users could edit that list per language from the Document Navigation panel. During review, a stale value of such an expression in an existing configuration file made sentence navigation raise an error. Reviewers also asked whether a prefix list can be maintained for every language and every language variant.

This work asks the Windows built-in ICU library for the boundaries instead. The rules come from the Unicode standard and are the same for every language. There is nothing to configure, so nothing can be misconfigured, and no language needs its own list. The cost is that an abbreviation such as "Dr." ends a sentence. Only locale specific tailoring avoids that, which is left for later.

#16384 also allowed a sentence to span several paragraphs, with a setting to choose how far it may reach. This work segments within the containing paragraph only.

#16384 changed browse mode, offsets based TextInfos, UIA TextInfos and editable text controls in one pull request. This work is split. The backend landed in #20603. This pull request only routes the browse mode gestures. One thing from #16384 is not carried over: a command to speak the current sentence in an editable text control.

Both resolve the same gesture conflict, but at different moments. #16384 made the choice inside the collapse or expand command. That command therefore ran even when the caret moved by sentence, so its description and its say all behaviour applied to both outcomes. This pull request makes the choice before a command is picked, so the command that runs is the command that acts. The object tested is the one the collapse or expand script acts on. The test also covers autocomplete fields and controls with a popup, which #16384 did not.

Testing strategy:

New unit tests cover the decision helper. Controls such as comboboxes, sliders, autocomplete fields, and collapsed controls keep collapse or expand. Plain content, links, and buttons fall through to sentence navigation. The binding order was also checked to confirm the sentence scripts now receive the keys. Manual verification in Firefox, Chrome and Word browse mode confirmed that plain text moves by sentence and (for browsers) that comboboxes still collapse or expand.

Known issues with pull request:

The current approach binds alt+upArrow and alt+downArrow to two different outcomes. Personally I don't think this is ideal, but I have no idea how to do this elsewhere and this wasn't a show stopper in #16384

Code Review Checklist:

  • Documentation:
    • Change log entry
    • User Documentation
    • Developer / Technical Documentation
    • Context sensitive help for GUI changes
  • Testing:
    • Unit tests
    • System (end to end) tests
    • Manual testing
  • UX of all users considered:
    • Speech
    • Braille
    • Low Vision
    • Different web browsers
    • Localization in other languages / culture than English
  • API is compatible with existing add-ons.
  • Security precautions taken.

@LeonarddeR
LeonarddeR force-pushed the browseModeSentenceNav branch 5 times, most recently from 720118c to 0b60882 Compare August 27, 2026 13:22
@LeonarddeR
LeonarddeR marked this pull request as ready for review August 27, 2026 13:42
Copilot AI lite review requested due to automatic review settings August 27, 2026 13:42
@LeonarddeR
LeonarddeR requested review from a team as code owners August 27, 2026 13:42
…d sentence navigation

alt+upArrow and alt+downArrow now run script_moveBySentence_back/forward,
which collapse or expand the focusable control at the caret when it takes
these keys itself and navigate by sentence otherwise.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR resolves a long-standing key gesture conflict in browse mode so alt+upArrow / alt+downArrow can perform sentence navigation in document content while still allowing interactive controls (e.g. comboboxes/popups) to use those keys for collapse/expand behavior.

Changes:

  • Adds browse mode dispatch logic (_isExpandableControlAtCaret + getAlternativeScript) to choose between sentence navigation and collapse/expand at gesture resolution time.
  • Improves sentence navigation scripts in cursorManager by handling missing sentence support (NotImplementedError) with a consistent user-facing message.
  • Updates user documentation and changelog, and adds unit tests for the browse mode dispatch decision.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
user_docs/en/userGuide.md Updates sentence navigation documentation and “say all reads by” wording to reflect broader availability.
user_docs/en/changes.md Adds a changelog entry for expanded sentence navigation support.
tests/unit/test_browseModeSentenceDispatch.py Adds unit coverage for the new browse mode sentence-vs-collapse/expand dispatch logic.
source/NVDAObjects/UIA/wordDocument.py Generalizes the translator comment to match the new cross-document messaging.
source/cursorManager.py Routes sentence scripts through a helper that reports unsupported documents consistently.
source/browseMode.py Implements browse mode alternative-script dispatch and removes the conflicting fixed gesture bindings.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread source/browseMode.py
Comment thread source/browseMode.py
Comment on lines +2093 to +2103
if (
not self.passThrough
and script
in (
self.script_moveBySentence_back,
self.script_moveBySentence_forward,
)
and self._isExpandableControlAtCaret()
):
return self.script_collapseOrExpandControl
return super().getAlternativeScript(gesture, script)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thoughts on this comment?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is possible without hacking. Because the script_moveBySentence scripts don't have descriptions, they can't be rebound from NVDA's input gestures dialog. Of course someone can hack in gestures.ini by hand, but he could also have done that for the previous script in current master.

@seanbudd seanbudd left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @LeonarddeR

Comment thread user_docs/en/userGuide.md Outdated

@Qchristensen Qchristensen left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

User Guide changes read well. I like Sean's second option for line 791/2 but either is fine.

Comment thread user_docs/en/userGuide.md Outdated
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants