Skip to content

Add a native selection mode to Gecko virtualBuffers#15830

Merged
seanbudd merged 52 commits into
masterfrom
DOMSelections
Dec 12, 2023
Merged

Add a native selection mode to Gecko virtualBuffers#15830
seanbudd merged 52 commits into
masterfrom
DOMSelections

Conversation

@michaelDCurran

@michaelDCurran michaelDCurran commented Nov 27, 2023

Copy link
Copy Markdown
Member

Link to issue number:

None

Summary of the issue:

NVDA allows the user to select text in browse mode. In web browsers where NVDA uses a virtualBuffer to make the content accessible, the selected text is only a plain text representation, and thus copying this text to another application such as MS Word looses all rich formatting. It is also impossible for the user to perform a web page specific action on the selected text, as the web page / application is unaware of NVDA's selection. E.g. Hypothesis's annotation and highlighting features.

Description of user facing changes

A new Native Selection mode (toggled by NVDA+shift+f10) is now available in NVDA's browse mode for Mozilla Firefox. When turned on, selecting text in browse mode will also manipulate Firefox's own native selection. And copying text with control+c will pass straight through to Firefox, thus copying the rich content, rather than NvDA's plain text representation.

Description of development approach

  • Added an updateAppSelection method to the Gecko virtualBuffer Python class, which updates the native selection to mirror NVDA's current browse mode selection, by using the new IAccessibleTextSelectionContainer interface in IAccessible2. This change also required the following:
    • The gecko virtualBuffer backend exposes needed attributes such as IAccessible2 uniqueID on all text runs, so it can be later used to update the native selection via IAccessibleTextSelectionContainer.
    • The base virtualBuffer storage generated XML also includes offsetFromStartOfNode and offsetFromEndOfNode on text tags, so that it is clear how far in the range starts from the real start and end of the text node.
    • XMLTextParser in NvDA now maintains a controlField stack and controlEnd fields now include a reference to the same attribs dictionary that was used on the controlStart. This is so we have all the information about a field by only looking at its controlEnd. Such as when traversing through fields backwards.
  • The Gecko virtualBuffer textInfo's updateSelection method calls updateAppSelection if native selection mode is toggled on.

Testing strategy:

  • Opened Mozilla Firefox.
  • Browsed to https://www.nvaccess.org/
  • Turned on native seleciton mode by pressing NVDA+shift+f10.
  • Selected the links on the top navbar (home, about, download etc).
  • Copied by pressing control+c.
  • Opened a blank document in MS Word.
  • Pasted the clipboard into MS Word. Confirmed that the content of the navbar was pasted into the document, formatted as a list of links.

Known issues with pull request:

Chromium implemented IAccessibleTextSelectionContainer, however much of the time its offset calculation seems to be wrong, thus the wrong native selection is made, thus this cannot be supported in Chromium at this point in time.

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.

michaelDCurran and others added 27 commits August 9, 2021 11:16
…Accessible2_4 which provides SetSelectionRanges, already implemented in google Chrome.
… virtualBuffer xml content so that it is possible to know how frar into a node the requested offsets actually cover. Assists in converting a virtaulBuffer offset to an IAccessible2 text offset.
…rmatFields to assist in looking up an IAccessible2 object + text offset from a given formatField, needed for performing DOM selections.
…om the current browse mode selection. This makes use of a new updateAppSelection method on browseMode documents.

Implement updateAppSelection for Chromium virtualBuffers (which uses IAccessible2_4::SetSelectionRanges) and UIA which uses IUIAutomationTextRange::Select.
…unction as this is now in gecko_ia2's vbuf which is a super class.
…windowHandle on controlFields that represent embedded objects within an IAccessibleText run.

Gecko_ia2 virtualBuffer: support looking for IAccessible2 text start offset, uniqueID and windowHandle attributes on controlFields, not just formatChanges, so that we can select embedded objects, where the vbufBackend has not rendered the specific IAccessibleText run within the embedded object as  it had an overriding name or did not support IAccessibleText (E.g. a graphic).
… toggled on and off with NVDA+shift+f10. When on, the app selection mirrors the virtualBuffer selection, and copy (control+c) is handled entirely by the app.
…and UIA for now. Just leaving it in the Gecko_ia2 virtualBuffer. It can be abstracted more broadly once we have an acceptable implementation in one browser.
@AppVeyorBot

Copy link
Copy Markdown
  • FAIL: Translation comments check. Translation comments missing or unexpectedly included. See build log for more information.
  • PASS: Unit tests.
  • FAIL: Lint check. See test results for more information.
  • FAIL: System tests (tags: installer NVDA). See test results for more information.
  • Build (for testing PR): https://ci.appveyor.com/api/buildjobs/67jx9479o4wh4dve/artifacts/output/nvda_snapshot_pr15830-30064,dd3480c4.exe
  • CI timing (mins):
    INIT 0.0,
    INSTALL_START 0.9,
    INSTALL_END 1.1,
    BUILD_START 0.0,
    BUILD_END 27.4,
    TESTSETUP_START 0.0,
    TESTSETUP_END 0.3,
    TEST_START 0.0,
    TEST_END 15.3,
    FINISH_END 0.1

See test results for failed build of commit dd3480c493

Comment thread .gitmodules Outdated
@hwf1324

hwf1324 commented Dec 10, 2023

Copy link
Copy Markdown
Contributor

Because this operation encountered a DLL that is being referenced by another process, see #15884.

The fastest way is to log out the current user of Windows

@nvdaes

nvdaes commented Dec 10, 2023

Copy link
Copy Markdown
Collaborator

After restarting the computer, the procedure suggested by @lukaszgo1 worked to build NVDA, and now the native selection mode works as expected.
Thanks all.

@CyrilleB79

Copy link
Copy Markdown
Contributor

This PR adds a native selection mode where possible, adds a script to toggle the native selection mode, and allows copy (control+c) to go through to the app during native selection mode. This is is as far as this PR is going to go. I think This is already a useful feature, and there are interested parties keen to see this in NVDA as soon as it is ready.

Yes, this PR is already more than useful in the current state. It should not be blocked by other questions (including mine),
even related.

@Adriani90

Adriani90 commented Dec 10, 2023

Copy link
Copy Markdown
Collaborator

@hwf1324 wrote:

Yes, in this PR, you can directly copy the content selected by the mouse

So you can read the mouse selection out by pressing nvda+shift+up arrow in desktop or nvda+shift+s in laptop keyboard layout both while you are in browse mode and in focus mode?

@seanbudd seanbudd added this to the 2024.1 milestone Dec 10, 2023
Comment thread user_docs/en/userGuide.t2t
Comment thread source/virtualBuffers/gecko_ia2.py Outdated
)
def script_copyToClipboard(self, gesture):
if self._nativeAppSelectionMode:
ui.message(_("native copy"))

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.

@michaelDCurran - thoughts on naming this?
Ideas:

  • application copy
  • rich copy
  • formatted copy

@Qchristensen

Copy link
Copy Markdown
Member

Thinking of the messages to the user, "Copy with formatting" is probably about as intuitive as I can think of.

@hwf1324

hwf1324 commented Dec 11, 2023

Copy link
Copy Markdown
Contributor

So you can read the mouse selection out by pressing nvda+shift+up arrow in desktop or nvda+shift+s in laptop keyboard layout both while you are in browse mode and in focus mode?

Unfortunately, in this PR situation: in browsing mode, it reports "no text selected"; in focus mode, it reports "text selected".
NVDA did not report specific content

@CyrilleB79

Copy link
Copy Markdown
Contributor

Thinking of the messages to the user, "Copy with formatting" is probably about as intuitive as I can think of.

The legacy copy message reportes "Copied to clipboard" followed by either the copied text, or the number of characters of this text if it is high enough. I do not see any reason to have a different message for formatted copy.
Why in this specific case should the configuration (formatted vs raw copy) be recorded to the user?

@seanbudd

Copy link
Copy Markdown
Member

If there's negative feedback with "native copy" we can consider changing it in future, or removing the message entirely

@seanbudd seanbudd merged commit 4519b89 into master Dec 12, 2023
@seanbudd seanbudd deleted the DOMSelections branch December 12, 2023 03:54
@Adriani90

Adriani90 commented Dec 12, 2023

Copy link
Copy Markdown
Collaborator

Actually I find the message quite useful, I know that the setting is enabled at least. Note that the native selection turns off automatically when you switch to a new tab or a new website in Firefox. Is this intended behavior?

Adriani90 pushed a commit to Adriani90/nvda that referenced this pull request Mar 13, 2024
Summary of the issue:
NVDA allows the user to select text in browse mode. In web browsers where NVDA uses a virtualBuffer to make the content accessible, the selected text is only a plain text representation, and thus copying this text to another application such as MS Word looses all rich formatting. It is also impossible for the user to perform a web page specific action on the selected text, as the web page / application is unaware of NVDA's selection. E.g. Hypothesis's annotation and highlighting features.

Description of user facing changes
A new Native Selection mode (toggled by NVDA+shift+f10) is now available in NVDA's browse mode for Mozilla Firefox. When turned on, selecting text in browse mode will also manipulate Firefox's own native selection. And copying text with control+c will pass straight through to Firefox, thus copying the rich content, rather than NvDA's plain text representation.

Description of development approach
Added an updateAppSelection method to the Gecko virtualBuffer Python class, which updates the native selection to mirror NVDA's current browse mode selection, by using the new IAccessibleTextSelectionContainer interface in IAccessible2. This change also required the following:
The gecko virtualBuffer backend exposes needed attributes such as IAccessible2 uniqueID on all text runs, so it can be later used to update the native selection via IAccessibleTextSelectionContainer.
The base virtualBuffer storage generated XML also includes offsetFromStartOfNode and offsetFromEndOfNode on text tags, so that it is clear how far in the range starts from the real start and end of the text node.
XMLTextParser in NvDA now maintains a controlField stack and controlEnd fields now include a reference to the same attribs dictionary that was used on the controlStart. This is so we have all the information about a field by only looking at its controlEnd. Such as when traversing through fields backwards.
The Gecko virtualBuffer textInfo's updateSelection method calls updateAppSelection if native selection mode is toggled on.
@britechguy

Copy link
Copy Markdown

Why in this specific case should the configuration (formatted vs raw copy) be recorded to the user?

Because it's only when NVDA (probably any screen reader) inserts itself into the copy process via using the virtual buffer that formatting can be stripped. When a screen reader is not in use copy from a webpage is always WYSIWYG, but not so when using NVDA in "regular" mode versus native text selection mode.

If it happens to be easy for NVDA to alert the user whether a formatted copy versus an unformatted copy has occurred, to me that has value.

@britechguy

Copy link
Copy Markdown

Just curious if there is any active pursuit of native text selection under Chromium-based browsers that's in the works?

@SuzanneTaylor

Copy link
Copy Markdown

Just wanted to mention that with Caret browsing on (F7) and NVDA manually switched to forms mode (Insert Space) native selection happens in Chrome, but it happens without NVDA speaking the selection. Perhaps this could be an avenue toward a solution for Chrome?

@aleventhal

Copy link
Copy Markdown

I believe the Chromium bugs with IAccessibleTextSelectionContainer are fixed in the latest Canary, so NVDA could try turning on support again. Let us know if there are new bugs that you see!

SaschaCowley pushed a commit that referenced this pull request Mar 18, 2025
…that can support it. (#17838)

Fixes #17591

Summary of the issue:
In #15830, NVDA browse mode gained a new native Selection Mode (toggled
on with `NVDA+shift+f10`) which caused the browser's underlying native
selection (DOM selection) to mirror the browse mode virtual selection.
Although this worked well in Firefox, it had to be forcefully disabled
for Chromium-based browsers as there were major bugs in Chromiums
implementation of IAccessibleTextSelectionContainer.
As of Chromium 134 stable, all known bugs have been addressed, thus NVDA
should allow native selection mode in Chromium-based browsers where
possible.

Description of user facing changes
NVDA browse mode's native selection mode (`NVDA+shift+f10`) can now be
enabled in any browser based on Chromium 134 or newer.

Description of development approach
* The Chromium virtualBuffer is no longer marked as not supporting
native app selection mode.
* toggling native selection mode on now firstly tries to clear the
native selection before updating it, and also catches more errors,
ensuring that native selection mode is truly supported when enabling.

Testing strategy:
* In Firefox, visited nvaccess.org, enabled native selection mode,
selected the navbar, copied to clipboard, and pasted to an editor to
verify all expected content was there.
* In Chrome134, visited nvaccess.org, enabled native selection mode,
selected the navbar, copied to clipboard, and pasted to an editor to
verify all expected content was there.
* In MS Edge 135, visited nvaccess.org, enabled native selection mode,
selected the navbar, copied to clipboard, and pasted to an editor to
verify all expected content was there.
* In VS Code February update (Chromium 132), in browse mode tried to
enable native selection mode, which reported as not supported as
expected.

Known issues with pull request:
None known.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

conceptApproved Similar 'triaged' for issues, PR accepted in theory, implementation needs review.

Projects

None yet

Development

Successfully merging this pull request may close these issues.