From 5d81cd2af0ad15347980693bfece4038d70a60f2 Mon Sep 17 00:00:00 2001 From: Cyrille Bougot Date: Tue, 26 Nov 2024 02:47:08 +0100 Subject: [PATCH 1/2] Report the update of the selection when using Word selection extend / reduce commmands (`f8` or `shift+f8`) (#17424) Partially fixes #3293. Summary of the issue: When using f8 (extend selection) or shift+f8 (reduce selection) in Word, the selection changes are not reported. Description of user facing changes When using f8 (extend selection) or shift+f8 (reduce selection) in Word, the selection changes will now be reported. If the selection is extended / reduced at both ends, two consecutive selection update messages are reported, as done for control+a (select all). Description of development approach In WordDocument.initOverlayClass, bind script_caret_changeSelection to f8 and shift+f8, as already done for other gestures such as alt+shift+home or alt+shift+pageDown. --- source/NVDAObjects/window/winword.py | 2 ++ user_docs/en/changes.md | 1 + 2 files changed, 3 insertions(+) diff --git a/source/NVDAObjects/window/winword.py b/source/NVDAObjects/window/winword.py index 34f3d0fdef..ea5c417d11 100755 --- a/source/NVDAObjects/window/winword.py +++ b/source/NVDAObjects/window/winword.py @@ -1975,6 +1975,8 @@ def initOverlayClass(self): self.bindGesture("kb:alt+shift+end", "caret_changeSelection") self.bindGesture("kb:alt+shift+pageUp", "caret_changeSelection") self.bindGesture("kb:alt+shift+pageDown", "caret_changeSelection") + self.bindGesture("kb:f8", "caret_changeSelection") + self.bindGesture("kb:shift+f8", "caret_changeSelection") __gestures = { "kb:control+pageUp": "caret_moveByLine", diff --git a/user_docs/en/changes.md b/user_docs/en/changes.md index 4fd9af5c4a..42deb8e4b8 100644 --- a/user_docs/en/changes.md +++ b/user_docs/en/changes.md @@ -26,6 +26,7 @@ To use this feature, "allow NVDA to control the volume of other applications" mu * When toggling double underline in LibreOffice Writer using the corresponding keyboard shortcut, NVDA announces the new state ("double underline on"/"double underline off"). (#6915, @michaelweghorn) * Automatic language switching is now supported when using Microsoft Speech API version 5 (SAPI5) and Microsoft Speech Platform voices. (#17146, @gexgd0419) * NVDA can now be configured to speak the current line or paragraph when navigating with braille navigation keys. (#17053, @nvdaes) +* In Word, the selection update is now reported when using Word commands to extend or reduce the selection (`f8` or `shift+f8`). (#3293, @CyrilleB79) ### Changes From 16cbc6f882406694337242f9a0454d33c25940a3 Mon Sep 17 00:00:00 2001 From: Cyrille Bougot Date: Tue, 26 Nov 2024 05:11:56 +0100 Subject: [PATCH 2/2] Report the result of word switch case formatting command (#17425) Fixes #10271 (last part) Also could be considered a partial fix of #3293. Summary of the issue: In Word / Outlook, nothing is reported when using the switch case command (shift+f3 in both, control+shift+a in Outlook only). Since it is a toggle/cycle command, the user needs to have the result to be reported. Description of user facing changes Using the switch case formatting command in Word or Outlook now reports its result, i.e. the type of case in which the selection has been formatted. When possible, the message being reported illustrates its own casing, as in Word menus, e.g. "lower case", "UPPERCASE", "Each Word Capitalized"; this may be useful in braille. Exception, for "Mixed case", I have not done something such as "mIxEd cAsE" because it is not correctly understandable through speech. Description of development approach Used Word object model as for other Word formatting scripts. Introduced a delay (set empirically), since the property retrieved from the object model transitions through other values (no case or lower case) before reaching its definitive value. Bind gestures according to the ones existing in Word and Outlook. Note: shift+f3 performs case switch both in Word and Outlook, whereas control+shift+A does it only in Outlook. See "Notes about various capitalization shortcuts" in #17197 for more details. --- source/NVDAObjects/window/winword.py | 77 ++++++++++++++++++++++++++++ source/appModules/outlook.py | 4 ++ 2 files changed, 81 insertions(+) diff --git a/source/NVDAObjects/window/winword.py b/source/NVDAObjects/window/winword.py index ea5c417d11..8a079aeb13 100755 --- a/source/NVDAObjects/window/winword.py +++ b/source/NVDAObjects/window/winword.py @@ -20,6 +20,7 @@ import colorsys import eventHandler import braille +import scriptHandler from scriptHandler import script import languageHandler import ui @@ -266,6 +267,54 @@ def _displayStringLabels(self) -> dict[Self, str]: wdThemeColorText1 = 13 wdThemeColorText2 = 15 + +class WdCharacterCase(DisplayStringIntEnum): + # Word enumeration that specifies the case of the text in the specified range. + # See https://docs.microsoft.com/en-us/office/vba/api/word.wdcharactercase + + # No case: Returned when the selection range contains only case-insensitive characters. + # Note: MS also uses it as a command for "next case" (Toggles between uppercase, lowercase, and sentence + # case). + NO_CASE = -1 + LOWER_CASE = 0 + UPPER_CASE = 1 + TITLE_WORD = 2 + TITLE_SENTENCE = 4 + # Mixed case: Unorganized mix of lower and upper case. + # Note: MS also uses it as a command for toggle case (Switches uppercase characters to lowercase, and + # lowercase characters to uppercase) + MIXED_CASE = 5 + HALF_WIDTH = 6 # Used for Japanese characters. + FULL_WIDTH = 7 # Used for Japanese characters. + KATAKANA = 8 # Used with Japanese text. + HIRAGANA = 9 # Used with Japanese text. + + @property + def _displayStringLabels(self) -> dict[Self, str]: + return { + # Translators: a Microsoft Word character case type + WdCharacterCase.NO_CASE: _("No case"), + # Translators: a Microsoft Word character case type + WdCharacterCase.LOWER_CASE: _("Lowercase"), + # Translators: a Microsoft Word character case type + WdCharacterCase.UPPER_CASE: _("Uppercase"), + # Translators: a Microsoft Word character case type + WdCharacterCase.TITLE_WORD: _("Each word capitalized"), + # Translators: a Microsoft Word character case type + WdCharacterCase.TITLE_SENTENCE: _("Sentence case"), + # Translators: a Microsoft Word character case type + WdCharacterCase.MIXED_CASE: _("Mixed case"), + # Translators: a Microsoft Word character case type + WdCharacterCase.HALF_WIDTH: _("Half width"), + # Translators: a Microsoft Word character case type + WdCharacterCase.FULL_WIDTH: _("Full width"), + # Translators: a Microsoft Word character case type + WdCharacterCase.KATAKANA: _("Katakana"), + # Translators: a Microsoft Word character case type + WdCharacterCase.HIRAGANA: _("Hiragana"), + } + + # Word Field types FIELD_TYPE_REF = 3 # cross reference field FIELD_TYPE_HYPERLINK = 88 # hyperlink field @@ -1697,6 +1746,34 @@ def script_toggleCaps(self, gesture: "inputCore.InputGesture"): # Translators: a message when toggling formatting to 'No capital' in Microsoft word ui.message(_("Caps off")) + @script(gesture="kb:shift+f3") + def script_changeCase(self, gesture: "inputCore.InputGesture"): + if ( + # We cannot fetch the Word object model, so we therefore cannot report the format change. + # The object model may be unavailable because this is a pure UIA implementation such as Windows 10 Mail, + # or its within Windows Defender Application Guard. + not self.WinwordSelectionObject + # Or we do not want to apply the delay due in case of multipe repetition of the script. + or scriptHandler.isScriptWaiting() + ): + # Just let the gesture through and don't report anything. + return gesture.send() + + def action(): + gesture.send() + # The object model for the "case" property is not fully reliable when using switch case command. During + # the switch, the "case" property quickly transitions through "lower case" or "no case", especially in + # Outlook. Thus we artificially add an empirical delay after the gesture has been send and before the + # first check. + time.sleep(0.15) + + val = self._WaitForValueChangeForAction( + action=action, + fetcher=lambda: self.WinwordSelectionObject.Range.Case, + ) + # Translators: a message when changing case in Microsoft Word + ui.message(WdCharacterCase(val).displayString) + @script(gestures=["kb:control+l", "kb:control+e", "kb:control+r", "kb:control+j"]) def script_toggleAlignment(self, gesture): if not self.WinwordSelectionObject: diff --git a/source/appModules/outlook.py b/source/appModules/outlook.py index 71c2559aad..0c732ba652 100644 --- a/source/appModules/outlook.py +++ b/source/appModules/outlook.py @@ -735,6 +735,10 @@ def _get_role(self): True # This includes page sections, and page columns. None of which are appropriate for outlook. ) + __gestures = { + "kb:control+shift+a": "changeCase", + } + class OutlookUIAWordDocument(UIAWordDocument, BaseOutlookWordDocument): """Forces browse mode to be used on the UI Automation Outlook message viewer if the message is being read)."""