Make braille and vision follow caret in browse mode#20465
Conversation
In say all with the caret cursor, _CaretTextReader.updateCaret called updater.updateCaret(). In browse mode and other cursor managers this sets the caret without firing an OS caret event, so braille and vision were never notified and the display stayed on the starting line (unless braille happened to be tethered to review). Route the caret update through the object's selection property when supported, so its _set_selection notifies review/braille/vision handleCaretMove handlers. The updater is a collapsed position, so setting the selection is equivalent to moving the caret; objects without a selection setter keep the previous path. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR fixes an NVDA browse mode “say all” regression where the caret was moved virtually (via cursor managers) without generating an OS caret event, so braille and the vision/magnifier stack weren’t notified and didn’t track the spoken line.
Changes:
- Update
_CaretTextReader.updateCaretto explicitly notify braille and vision caret-move handlers when the caret object is a cursor manager (virtual caret). - Leave the existing behavior unchanged for non-cursor-manager caret moves (which should still be driven by OS caret events).
- Add a user-facing change log entry documenting the improved braille/magnifier tracking during browse mode say all.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| user_docs/en/changes.md | Documents the user-visible improvement: braille and magnifier track browse mode say all. |
| source/speech/sayAll.py | Notifies braille/vision handlers after virtual caret moves (cursor managers) so output follows spoken text. |
|
@LeonarddeR I have locally modified the appearance of the browse mode cursor to be able to see / follow it and test. Would you like to update the change log? Or do we expect your work in #20467 to add it? |
|
I can change it in #20467, but of course that relies on how that will be approved. |
Link to issue number:
Closes #3287
Summary of the issue:
During say all with the caret cursor in browse mode, braille and vision framework did not follow the spoken text. The display stayed on the line where say all started, and only moved if braille happened to be tethered to review.
This happens because
_CaretTextReader.updateCaretmoved the caret viaupdater.updateCaret(). In browse mode the caret is virtual, so this does not fire an OS caret event. Braille and the vision handlers are normally notified off that event, so they were never told the caret had moved.Description of user facing changes:
During say all in browse mode, braille and the magnifier now follow the spoken text line by line, regardless of the braille tether setting.
Description of developer facing changes:
None. No public API changes.
Description of development approach:
_CaretTextReader.updateCaretnow detects cursor managers viaapi.isCursorManager(obj)and, for those, explicitly callsbraille.handler.handleCaretMove(obj)andvision.handler.handleCaretMove(obj)after moving the caret. Objects that fire an OS caret event are left on the existing path, since that event already drives the handlers.Testing strategy:
Say all in browse mode (Firefox, Chrome) with a braille display tethered to focus: braille now follows the spoken line.
Known issues with pull request:
None.
Code Review Checklist: