From c32e0e78a7a627a800fbf58ca3a4eade9c3c4477 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noelia=20Ruiz=20Mart=C3=ADnez?= Date: Thu, 21 Nov 2024 07:37:03 +0100 Subject: [PATCH] Add commands to move the review cursor to the first and last character of selected text (#17393) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Link to issue number: Fixes #17299 Summary of the issue: NVDA doesn't have commands to move the review cursor to start and end of selection, which may be useful to review the selected text. Description of user facing changes `NVDA+alt+home` and `NVDA+alt+end` can be used to move the review cursor to the first and last carácter of selected text. Description of development approach In globalCommands.py, GlobalCommands class, a staticmethod has been added to get the current selection. This is used to scripts added to move the review cursor to start and end of selection, similar to other scripts used to move the review cursor. Testing strategy: Tested manually in a webpage and in Notepad. --- source/globalCommands.py | 77 +++++++++++++++++++++++++++++++++++++++ user_docs/en/changes.md | 1 + user_docs/en/userGuide.md | 2 + 3 files changed, 80 insertions(+) diff --git a/source/globalCommands.py b/source/globalCommands.py index b3d16bbac9b..cceffee0c96 100755 --- a/source/globalCommands.py +++ b/source/globalCommands.py @@ -123,6 +123,8 @@ # Translators: Reported when there are no settings to configure in synth settings ring # (example: when there is no setting for language). NO_SETTINGS_MSG = _("No settings") +# Translators: Reported when there is no selection +NO_SELECTION_MESSAGE = _("No selection") def toggleBooleanValue( @@ -374,6 +376,24 @@ def script_reportCurrentSelection(self, gesture): speech.speakTextSelected(info.text) braille.handler.message(selectMessage) + @staticmethod + def _getSelection() -> textInfos.TextInfo | None: + """Gets the current selection, if any. + :return: The TextInfo corresponding to the current selection, or None if no selection is available. + """ + obj = api.getFocusObject() + treeInterceptor = obj.treeInterceptor + if ( + isinstance(treeInterceptor, treeInterceptorHandler.DocumentTreeInterceptor) + and not treeInterceptor.passThrough + ): + obj = treeInterceptor + try: + info = obj.makeTextInfo(textInfos.POSITION_SELECTION) + return info.copy() + except (RuntimeError, NotImplementedError): + return None + @script( description=_( # Translators: Input help mode message for report date and time command. @@ -2215,6 +2235,63 @@ def script_review_endOfLine(self, gesture: inputCore.InputGesture): ui.reviewMessage(gui.blockAction.Context.WINDOWS_LOCKED.translatedMessage) return + @script( + description=_( + # Translators: Input help mode message for move review cursor to start of selection command. + "Moves the review cursor to the first character of the selection, and speaks it", + ), + category=SCRCAT_TEXTREVIEW, + gesture="kb:NVDA+alt+home", + ) + def script_review_startOfSelection(self, gesture: inputCore.InputGesture): + info = self._getSelection() + if info is None or info.isCollapsed: + ui.message(NO_SELECTION_MESSAGE) + return + info.collapse() + + # This script is available on the lock screen via getSafeScripts, as such + # ensure the review position does not contain secure information + # before announcing this object + if api.setReviewPosition(info): + info.expand(textInfos.UNIT_CHARACTER) + speech.speakTextInfo( + info, + unit=textInfos.UNIT_CHARACTER, + reason=controlTypes.OutputReason.CARET, + ) + else: + ui.reviewMessage(gui.blockAction.Context.WINDOWS_LOCKED.translatedMessage) + + @script( + description=_( + # Translators: Input help mode message for move review cursor to end of selection command. + "Moves the review cursor to the last character of the selection, and speaks it", + ), + category=SCRCAT_TEXTREVIEW, + gesture="kb:NVDA+alt+end", + ) + def script_review_endOfSelection(self, gesture: inputCore.InputGesture): + info = self._getSelection() + if info is None or info.isCollapsed: + ui.message(NO_SELECTION_MESSAGE) + return + info.move(textInfos.UNIT_CHARACTER, -1, "end") + info.collapse(end=True) + + # This script is available on the lock screen via getSafeScripts, as such + # ensure the review position does not contain secure information + # before announcing this object + if api.setReviewPosition(info): + info.expand(textInfos.UNIT_CHARACTER) + speech.speakTextInfo( + info, + unit=textInfos.UNIT_CHARACTER, + reason=controlTypes.OutputReason.CARET, + ) + else: + ui.reviewMessage(gui.blockAction.Context.WINDOWS_LOCKED.translatedMessage) + def _getCurrentLanguageForTextInfo(self, info): curLanguage = None if config.conf["speech"]["autoLanguageSwitching"]: diff --git a/user_docs/en/changes.md b/user_docs/en/changes.md index 174dfe8d7a0..4fd9af5c4a2 100644 --- a/user_docs/en/changes.md +++ b/user_docs/en/changes.md @@ -41,6 +41,7 @@ To use this feature, "allow NVDA to control the volume of other applications" mu * Default input and output braille tables can now be determined based on the NVDA language. (#17306, #16390, #290, @nvdaes) * In Microsoft Word, when using the "report focus" command, the document layout will be announced if this information is available and reporting object descriptions is enabled. (#15088, @nvdaes) * NVDA will now only warn about add-on incompatibility when updating to a version which has an incompatible add-on API to the currently installed copy. (#17071) +* Added commands to move the review cursor to the first and last character of the selected text, assigned to `NVDA+alt+home` and `NVDA+alt+end`, respectively. (#17299, @nvdaes) ### Bug Fixes diff --git a/user_docs/en/userGuide.md b/user_docs/en/userGuide.md index 97ae2216ea3..cd96397c5ee 100644 --- a/user_docs/en/userGuide.md +++ b/user_docs/en/userGuide.md @@ -843,6 +843,8 @@ The following commands are available for reviewing text: |Move to end of line in review |shift+numpad3 |NVDA+end |none |Moves the review cursor to the end of the current line of text| |Move to previous page in review |`NVDA+pageUp` |`NVDA+shift+pageUp` |none |Moves the review cursor to the previous page of text if supported by the application| |Move to next page in review |`NVDA+pageDown` |`NVDA+shift+pageDown` |none |Moves the review cursor to the next page of text if supported by the application| +|Move to start of selection in review |NVDA+alt+home |NVDA+alt+home |none |Moves the review cursor to the first character of the selected text| +|Move to end of selection in review |NVDA+alt+end |NVDA+alt+end |none |Moves the review cursor to the last character of the selected text| |Say all with review |numpadPlus |NVDA+shift+a |3-finger flick down (text mode) |Reads from the current position of the review cursor, moving it as it goes| |Select then Copy from review cursor |NVDA+f9 |NVDA+f9 |none |Starts the select then copy process from the current position of the review cursor. The actual action is not performed until you tell NVDA where the end of the text range is| |Select then Copy to review cursor |NVDA+f10 |NVDA+f10 |none |On the first press, text is selected from the position previously set as start marker up to and including the review cursor's current position. If the system caret can reach the text, it will be moved to the selected text. After pressing this key stroke a second time, the text will be copied to the Windows clipboard|