Skip to content

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

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

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

Conversation

@LeonarddeR

Copy link
Copy Markdown
Collaborator

Link to issue number:

Closes #18901.
Depends on #20603.

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 from the previous PR in this stack.

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. Input help now describes the sentence commands. The user guide no longer limits sentence navigation to Word and Outlook. A changelog entry is added.

Description of developer facing changes:

BrowseModeDocumentTreeInterceptor overrides the sentence scripts with script_moveBySentence_back and script_moveBySentence_forward. A new helper, _isExpandableControlAtCaret, decides which behaviour applies. The two static gesture bindings to collapseOrExpandControl are removed.

Description of development approach:

The keys are no longer bound to one fixed command. Instead, the sentence scripts decide per key press which action applies. The decision 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 script collapses or expands it. Otherwise the caret moves by sentence. In documents without sentence support, the keys do nothing instead of raising an error. The SentenceNav add-on resolves the same conflict in the same way.

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 and Chrome browse mode confirmed that plain text moves by sentence and that comboboxes still collapse or expand.

Known issues with pull request:

Sentence navigation is still unavailable in documents that do not use offsets-based TextInfos, such as UIA-based browse mode documents and edit controls.

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.

Copilot AI review requested due to automatic review settings July 31, 2026 16:34

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 the alt+upArrow / alt+downArrow gesture conflict in browse mode by dispatching per keypress between collapse/expand behavior for relevant controls and sentence navigation for document content, backed by ICU-based sentence segmentation for OffsetsTextInfo. It also updates end-user documentation and adds targeted unit tests for the new segmentation and dispatch logic.

Changes:

  • Add ICU sentence boundary support (UBRK.SENTENCE, calculateSentenceOffsets, and OffsetsTextInfo._getSentenceOffsets) and reuse a shared encoding-conversion helper.
  • Update browse mode to route alt+upArrow / alt+downArrow to sentence navigation unless the caret is on an “expandable / popup / focus-mode” control.
  • Add/adjust unit tests and documentation (User Guide + changelog) to reflect the new sentence navigation behavior.

Reviewed changes

Copilot reviewed 11 out of 15 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
user_docs/en/userGuide.md Updates the sentence navigation key command description to include browse mode support.
user_docs/en/changes.md Adds a changelog entry announcing sentence navigation support beyond Word/Outlook.
tests/unit/test_textUtils/test_wordSegIcu.py Adds unit tests for ICU word segmentation strategy behavior.
tests/unit/test_textUtils/test_wordSeg.py Adds broader unit tests for word segmentation initialization/selection and converters.
tests/unit/test_textUtils/test_sentenceSegIcu.py Adds unit tests for ICU sentence segmentation and tiling invariants.
tests/unit/test_textUtils/test_offsetConverters.py Adds unit tests for offset converters and related utilities.
tests/unit/test_textUtils/test_hyphenation.py Adds unit tests for hyphenation behavior on known/unknown languages.
tests/unit/test_textUtils/test_backendComparison.py Switches ICU skipping to use the shared skipIfNoICU helper.
tests/unit/test_textUtils/init.py Introduces skipIfNoICU for reuse across test_textUtils modules.
tests/unit/test_browseModeSentenceDispatch.py Adds unit tests for browse mode dispatch discriminator _isExpandableControlAtCaret.
source/winBindings/icu.py Adds UBRK.SENTENCE to the ICU break iterator enum.
source/textUtils/icu.py Adds ICU sentence segmentation and a shared calculateOffsetsForEncoding helper.
source/textUtils/_wordSeg/wordSegStrategy.py Refactors ICU word strategy to use calculateOffsetsForEncoding.
source/textInfos/offsets.py Implements sentence offsets for OffsetsTextInfo using ICU sentence boundaries.
source/browseMode.py Implements per-press dispatch between collapse/expand and sentence navigation; removes gesture shadowing.

Comment on lines +13 to +14
skipIfNoICU = unittest.skipUnless(ICU_AVAILABLE, "ICU library not available on this system")
"""Decorator skipping tests that need the Windows built-in ICU library."""
LeonarddeR and others added 2 commits August 3, 2026 08:29
textUtils.icu gains _containingSegment and calculateOffsetsForEncoding.
IcuWordSegmentationStrategy.getSegmentForOffset now delegates its
encoding conversion to calculateOffsetsForEncoding.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
textUtils.icu gains calculateSentenceOffsets using the SENTENCE break
iterator. OffsetsTextInfo._getSentenceOffsets segments the containing
paragraph with it instead of raising NotImplementedError.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@LeonarddeR
LeonarddeR force-pushed the browseModeSentenceNav branch from 8b7d545 to fd83472 Compare August 3, 2026 06:29
Copilot AI review requested due to automatic review settings August 3, 2026 06:29

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

Copilot reviewed 9 out of 9 changed files in this pull request and generated no new comments.

Suppressed comments (3)

user_docs/en/changes.md:12

  • The changelog entry implies sentence navigation now works in browse mode and other documents unconditionally, but the implementation still depends on sentence support (eg OffsetsTextInfo + availability of the Windows ICU library) and won’t apply to all document types (eg UIA-based browse mode). Tightening the wording here would avoid misleading users.
* Sentence navigation (`alt+upArrow` and `alt+downArrow`) now works in browse mode and other documents, using the Windows built-in ICU library for Unicode-aware sentence boundary detection. Previously it was only supported in Microsoft Word and Outlook. (#18901, @LeonarddeR)

source/browseMode.py:2057

  • The docstring/return description for _isExpandableControlAtCaret is inaccurate: returning True doesn’t always mean the control will be collapsed/expanded; for roles in ALWAYS_SWITCH_TO_PASS_THROUGH_ROLES it primarily means the alt+up/down gesture should be passed through to the control (eg. slider/list navigation). Updating the docstring helps avoid confusion for future maintainers.
		The object tested is the one :meth:`script_collapseOrExpandControl` acts on.  For
		plain document content the focusable node is the root object, so this returns
		``False``.

		:return: ``True`` to collapse/expand the control, ``False`` to navigate by sentence.

user_docs/en/userGuide.md:791

  • This table entry now states sentence navigation is supported in “browse mode”, but per the PR description it’s still unavailable in some browse mode documents (eg UIA-based browse mode / documents without sentence-aware TextInfos). Consider wording this more narrowly so it doesn’t over-promise support in all browse mode contexts.
|Next sentence |alt+downArrow |alt+downArrow |Moves the caret to the next sentence and announces it. (supported in browse mode and in Microsoft Word and Outlook)|
|Previous sentence |alt+upArrow |alt+upArrow |Moves the caret to the previous sentence and announces it. (supported in browse mode and in Microsoft Word and Outlook)|

LeonarddeR and others added 2 commits August 3, 2026 09:31
…fsets

OffsetsTextInfo._getSentenceOffsets now applies the same encoding guard as
_getWordOffsets and _getCharacterOffsets, accepting only UTF-16 and the
encodings whose offsets are str indices.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…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>
@LeonarddeR
LeonarddeR force-pushed the browseModeSentenceNav branch from fd83472 to bdb46f0 Compare August 3, 2026 07:31
Copilot AI review requested due to automatic review settings August 3, 2026 07:31

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

Copilot reviewed 9 out of 9 changed files in this pull request and generated no new comments.

Suppressed comments (3)

user_docs/en/userGuide.md:791

  • The User Guide entry claims sentence navigation is supported in browse mode generally, but the PR description notes this is still unavailable for some browse mode documents (e.g. UIA-based) where the gesture will do nothing. Consider wording this as “supported in browse mode documents that support sentence navigation (e.g. Firefox/Chrome)” to avoid overpromising.
|Next sentence |alt+downArrow |alt+downArrow |Moves the caret to the next sentence and announces it. (supported in browse mode and in Microsoft Word and Outlook)|
|Previous sentence |alt+upArrow |alt+upArrow |Moves the caret to the previous sentence and announces it. (supported in browse mode and in Microsoft Word and Outlook)|

user_docs/en/changes.md:12

  • This changelog entry says sentence navigation “now works in browse mode”, but per the PR description it remains unavailable in UIA-based browse mode documents (and other non-offsets TextInfos). Tweaking the wording to “many browse mode documents (e.g. Firefox/Chrome)” would better match actual availability.
* Sentence navigation (`alt+upArrow` and `alt+downArrow`) now works in browse mode and other documents, using the Windows built-in ICU library for Unicode-aware sentence boundary detection. Previously it was only supported in Microsoft Word and Outlook. (#18901, @LeonarddeR)

source/textInfos/offsets.py:566

  • The docstring says sentence segmentation is done over the containing paragraph “so a sentence can span multiple lines”. In this base class, _getParagraphOffsets currently falls back to _getLineOffsets, so sentences only span multiple lines when subclasses override paragraph semantics. Adjust the wording to reflect that this depends on the TextInfo implementation.
		Sentences are segmented over the containing paragraph (:meth:`_getParagraphOffsets`)
		using the Windows built-in ICU BreakIterator (UAX#29), so a sentence can span
		multiple lines.

@LeonarddeR

Copy link
Copy Markdown
Collaborator Author

Closing until 20602 and #20603 have been merged.

@LeonarddeR LeonarddeR closed this Aug 3, 2026
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.

Universal Availability of Sentence Navigation

2 participants