From 56495cdefc45c242a9ca8a9a3b2427d67286ea11 Mon Sep 17 00:00:00 2001 From: Michael Curran Date: Wed, 11 Dec 2024 10:57:21 +1000 Subject: [PATCH 1/8] MS Word documents: report when headings are collapsed in both speech and braille. --- source/NVDAObjects/UIA/wordDocument.py | 16 ++++++++++++++++ source/braille.py | 4 ++++ source/speech/speech.py | 15 +++++++++++++++ 3 files changed, 35 insertions(+) diff --git a/source/NVDAObjects/UIA/wordDocument.py b/source/NVDAObjects/UIA/wordDocument.py index 41ec251d524..f68036bc87d 100644 --- a/source/NVDAObjects/UIA/wordDocument.py +++ b/source/NVDAObjects/UIA/wordDocument.py @@ -51,6 +51,13 @@ class UIACustomAttributeID(enum.IntEnum): COLUMN_NUMBER = 2 SECTION_NUMBER = 3 BOOKMARK_NAME = 4 + COLUMNS_IN_SECTION = 5 + EXPAND_COLLAPSE_STATE = 6 + + +class EXPAND_COLLAPSE_STATE(enum.IntEnum): + COLLAPSED = 0 + EXPANDED = 1 #: the non-printable unicode character that represents the end of cell or end of row mark in Microsoft Word @@ -483,6 +490,15 @@ def _getFormatFieldAtRange(self, textRange, formatConfig, ignoreMixedValues=Fals ) if isinstance(textColumnNumber, int): formatField.field["text-column-number"] = textColumnNumber + expandCollapseState = UIARemote.msWord_getCustomAttributeValue( + docElement, + textRange, + UIACustomAttributeID.EXPAND_COLLAPSE_STATE, + ) + if expandCollapseState == EXPAND_COLLAPSE_STATE.COLLAPSED: + formatField.field["collapsed"] = True + elif expandCollapseState == EXPAND_COLLAPSE_STATE.EXPANDED: + formatField.field["collapsed"] = False return formatField def _getIndentValueDisplayString(self, val: float) -> str: diff --git a/source/braille.py b/source/braille.py index ba44325c07b..ea5e11c21c0 100644 --- a/source/braille.py +++ b/source/braille.py @@ -1160,6 +1160,10 @@ def getFormatFieldBraille(field, fieldCache, isAtStart, formatConfig): # Translators: Displayed in braille for a heading with a level. # %s is replaced with the level. textList.append(_("h%s") % headingLevel) + collapsed = field.get("collapsed") + if collapsed: + # Translators: Displayed in braille for collapsed text + textList.append(_("+")) if formatConfig["reportLinks"]: link = field.get("link") oldLink = fieldCache.get("link") diff --git a/source/speech/speech.py b/source/speech/speech.py index 49992c0b03f..3c30188004b 100644 --- a/source/speech/speech.py +++ b/source/speech/speech.py @@ -2620,6 +2620,21 @@ def getFormatFieldSpeech( # noqa: C901 # Translators: Speaks the heading level (example output: heading level 2). text = _("heading level %d") % headingLevel textList.append(text) + collapsed = attrs.get("collapsed") + oldCollapsed = attrsCache.get("collapsed") if attrsCache is not None else None + # collapsed state should be spoken when beginning to speak lines or paragraphs + # Ensuring a similar experience to if it was a state on a controlField + if collapsed and ( + initialFormat + and ( + reason in [OutputReason.FOCUS, OutputReason.QUICKNAV] + or unit in (textInfos.UNIT_LINE, textInfos.UNIT_PARAGRAPH) + ) + or collapsed != oldCollapsed + ): + # Translators: collapsed text (E.g. a collapsed heading in MS Word) + text = _("collapsed") + textList.append(text) if formatConfig["reportStyle"]: style = attrs.get("style") oldStyle = attrsCache.get("style") if attrsCache is not None else None From df29f40ce4d4e75bf31286b1ec4ce6b79f5abf06 Mon Sep 17 00:00:00 2001 From: Michael Curran Date: Wed, 11 Dec 2024 11:18:11 +1000 Subject: [PATCH 2/8] Update what's new --- user_docs/en/changes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/user_docs/en/changes.md b/user_docs/en/changes.md index 7071a44cf51..6a585db6ad9 100644 --- a/user_docs/en/changes.md +++ b/user_docs/en/changes.md @@ -27,6 +27,7 @@ To use this feature, "allow NVDA to control the volume of other applications" mu * 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) +* In Word 16.0.18226 and higher, NVDA will now report if a heading is collapsed in both speech and braille. (#17499) ### Changes From 5c0923c7390dee4c4ea2a640c990add9630d746f Mon Sep 17 00:00:00 2001 From: Michael Curran Date: Wed, 11 Dec 2024 16:44:17 +1000 Subject: [PATCH 3/8] Apply suggestions from code review Co-authored-by: Sascha Cowley <16543535+SaschaCowley@users.noreply.github.com> --- source/braille.py | 3 +-- source/speech/speech.py | 4 +--- user_docs/en/changes.md | 2 +- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/source/braille.py b/source/braille.py index ea5e11c21c0..2ae36ba3b12 100644 --- a/source/braille.py +++ b/source/braille.py @@ -1162,8 +1162,7 @@ def getFormatFieldBraille(field, fieldCache, isAtStart, formatConfig): textList.append(_("h%s") % headingLevel) collapsed = field.get("collapsed") if collapsed: - # Translators: Displayed in braille for collapsed text - textList.append(_("+")) + textList.append(positiveStateLabels[controlTypes.State.COLLAPSED]) if formatConfig["reportLinks"]: link = field.get("link") oldLink = fieldCache.get("link") diff --git a/source/speech/speech.py b/source/speech/speech.py index 3c30188004b..5f4bebdbd55 100644 --- a/source/speech/speech.py +++ b/source/speech/speech.py @@ -2632,9 +2632,7 @@ def getFormatFieldSpeech( # noqa: C901 ) or collapsed != oldCollapsed ): - # Translators: collapsed text (E.g. a collapsed heading in MS Word) - text = _("collapsed") - textList.append(text) + textList.append(State.COLLAPSED.displayString) if formatConfig["reportStyle"]: style = attrs.get("style") oldStyle = attrsCache.get("style") if attrsCache is not None else None diff --git a/user_docs/en/changes.md b/user_docs/en/changes.md index 6a585db6ad9..29316e609c3 100644 --- a/user_docs/en/changes.md +++ b/user_docs/en/changes.md @@ -27,7 +27,7 @@ To use this feature, "allow NVDA to control the volume of other applications" mu * 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) -* In Word 16.0.18226 and higher, NVDA will now report if a heading is collapsed in both speech and braille. (#17499) +* In Microsoft Word 16.0.18226 and higher, NVDA will now report if a heading is collapsed in both speech and braille. (#17499) ### Changes From 4a5b8f952c6f821fc271d38935c144a83425e6d1 Mon Sep 17 00:00:00 2001 From: Michael Curran Date: Thu, 12 Dec 2024 09:38:18 +1000 Subject: [PATCH 4/8] MS word via object model: report collapsed state on headings. --- nvdaHelper/remote/WinWord/Constants.h | 1 + nvdaHelper/remote/winword.cpp | 6 ++++++ source/NVDAObjects/window/winword.py | 5 +++++ 3 files changed, 12 insertions(+) diff --git a/nvdaHelper/remote/WinWord/Constants.h b/nvdaHelper/remote/WinWord/Constants.h index d59bbc6489b..68202efcffd 100644 --- a/nvdaHelper/remote/WinWord/Constants.h +++ b/nvdaHelper/remote/WinWord/Constants.h @@ -79,6 +79,7 @@ constexpr int wdDISPID_PAGESETUP_PAGEWIDTH = 105; constexpr int wdDISPID_PAGESETUP_SECTIONSTART = 114; constexpr int wdDISPID_PAGESETUP_TEXTCOLUMNS = 119; constexpr int wdDISPID_PARAGRAPH_OUTLINELEVEL = 202; +constexpr int wdDISPID_PARAGRAPH_COLLAPSED_STATE = 1203; constexpr int wdDISPID_PARAGRAPH_RANGE = 0; constexpr int wdDISPID_PARAGRAPH_STYLE = 100; constexpr int wdDISPID_PARAGRAPHFORMAT_ALIGNMENT = 101; diff --git a/nvdaHelper/remote/winword.cpp b/nvdaHelper/remote/winword.cpp index bd05584a0ee..6954f458ab8 100644 --- a/nvdaHelper/remote/winword.cpp +++ b/nvdaHelper/remote/winword.cpp @@ -304,6 +304,12 @@ int generateHeadingXML(IDispatch* pDispatchParagraph, IDispatch* pDispatchParagr int headingLevel=getHeadingLevelFromParagraph(pDispatchParagraph); if(!headingLevel) return 0; XMLStream<=startOffset) { diff --git a/source/NVDAObjects/window/winword.py b/source/NVDAObjects/window/winword.py index 8a079aeb130..33d278a64a0 100755 --- a/source/NVDAObjects/window/winword.py +++ b/source/NVDAObjects/window/winword.py @@ -1112,6 +1112,11 @@ def _normalizeControlField(self, field): field["name"] = name field["alwaysReportName"] = True field["role"] = controlTypes.Role.FRAME + collapsedState = field.pop("collapsedState", None) == "true" + if collapsedState: + if 'states' not in field: + field['states'] = set() + field["states"].add(controlTypes.State.COLLAPSED) newField = LazyControlField_RowAndColumnHeaderText(self) newField.update(field) return newField From d0a3fe018ee197862b7d876a89ca036701eee2b8 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 11 Dec 2024 23:39:03 +0000 Subject: [PATCH 5/8] Pre-commit auto-fix --- source/NVDAObjects/window/winword.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/NVDAObjects/window/winword.py b/source/NVDAObjects/window/winword.py index 33d278a64a0..ad0f5b3e2ca 100755 --- a/source/NVDAObjects/window/winword.py +++ b/source/NVDAObjects/window/winword.py @@ -1114,8 +1114,8 @@ def _normalizeControlField(self, field): field["role"] = controlTypes.Role.FRAME collapsedState = field.pop("collapsedState", None) == "true" if collapsedState: - if 'states' not in field: - field['states'] = set() + if "states" not in field: + field["states"] = set() field["states"].add(controlTypes.State.COLLAPSED) newField = LazyControlField_RowAndColumnHeaderText(self) newField.update(field) From 7cd66f127e4e0879e9a7a1178d7bef96529373e7 Mon Sep 17 00:00:00 2001 From: Michael Curran Date: Thu, 12 Dec 2024 10:00:36 +1000 Subject: [PATCH 6/8] MS Word with UIA: avoid error when remote ops not available. --- source/NVDAObjects/UIA/wordDocument.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/source/NVDAObjects/UIA/wordDocument.py b/source/NVDAObjects/UIA/wordDocument.py index f68036bc87d..791132e18b2 100644 --- a/source/NVDAObjects/UIA/wordDocument.py +++ b/source/NVDAObjects/UIA/wordDocument.py @@ -490,15 +490,15 @@ def _getFormatFieldAtRange(self, textRange, formatConfig, ignoreMixedValues=Fals ) if isinstance(textColumnNumber, int): formatField.field["text-column-number"] = textColumnNumber - expandCollapseState = UIARemote.msWord_getCustomAttributeValue( - docElement, - textRange, - UIACustomAttributeID.EXPAND_COLLAPSE_STATE, - ) - if expandCollapseState == EXPAND_COLLAPSE_STATE.COLLAPSED: - formatField.field["collapsed"] = True - elif expandCollapseState == EXPAND_COLLAPSE_STATE.EXPANDED: - formatField.field["collapsed"] = False + expandCollapseState = UIARemote.msWord_getCustomAttributeValue( + docElement, + textRange, + UIACustomAttributeID.EXPAND_COLLAPSE_STATE, + ) + if expandCollapseState == EXPAND_COLLAPSE_STATE.COLLAPSED: + formatField.field["collapsed"] = True + elif expandCollapseState == EXPAND_COLLAPSE_STATE.EXPANDED: + formatField.field["collapsed"] = False return formatField def _getIndentValueDisplayString(self, val: float) -> str: From eba22499d3a72571d264c9e721463b86a7dbf5e8 Mon Sep 17 00:00:00 2001 From: Michael Curran Date: Wed, 18 Dec 2024 08:35:30 +1000 Subject: [PATCH 7/8] Update nvdaHelper/remote/winword.cpp Co-authored-by: Cyrille Bougot --- nvdaHelper/remote/winword.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nvdaHelper/remote/winword.cpp b/nvdaHelper/remote/winword.cpp index 6954f458ab8..d78f811e80e 100644 --- a/nvdaHelper/remote/winword.cpp +++ b/nvdaHelper/remote/winword.cpp @@ -305,7 +305,7 @@ int generateHeadingXML(IDispatch* pDispatchParagraph, IDispatch* pDispatchParagr if(!headingLevel) return 0; XMLStream< Date: Fri, 20 Dec 2024 09:08:12 +1000 Subject: [PATCH 8/8] Apply suggestions from code review Co-authored-by: Sascha Cowley <16543535+SaschaCowley@users.noreply.github.com> Co-authored-by: Cyrille Bougot --- nvdaHelper/remote/winword.cpp | 4 +--- source/NVDAObjects/window/winword.py | 3 +-- user_docs/en/changes.md | 2 +- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/nvdaHelper/remote/winword.cpp b/nvdaHelper/remote/winword.cpp index d78f811e80e..1f8b850d7dd 100644 --- a/nvdaHelper/remote/winword.cpp +++ b/nvdaHelper/remote/winword.cpp @@ -307,9 +307,7 @@ int generateHeadingXML(IDispatch* pDispatchParagraph, IDispatch* pDispatchParagr // Expose the collapsed state of the heading BOOL isCollapsed=false; _com_dispatch_raw_propget(pDispatchParagraph, wdDISPID_PARAGRAPH_COLLAPSED_STATE, VT_BOOL, &isCollapsed); - if(isCollapsed) { - XMLStream<=startOffset) { diff --git a/source/NVDAObjects/window/winword.py b/source/NVDAObjects/window/winword.py index ad0f5b3e2ca..77d9017cf9e 100755 --- a/source/NVDAObjects/window/winword.py +++ b/source/NVDAObjects/window/winword.py @@ -1112,8 +1112,7 @@ def _normalizeControlField(self, field): field["name"] = name field["alwaysReportName"] = True field["role"] = controlTypes.Role.FRAME - collapsedState = field.pop("collapsedState", None) == "true" - if collapsedState: + if field.pop("collapsedState", None) == "true": if "states" not in field: field["states"] = set() field["states"].add(controlTypes.State.COLLAPSED) diff --git a/user_docs/en/changes.md b/user_docs/en/changes.md index 29316e609c3..aef097a3e89 100644 --- a/user_docs/en/changes.md +++ b/user_docs/en/changes.md @@ -27,7 +27,7 @@ To use this feature, "allow NVDA to control the volume of other applications" mu * 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) -* In Microsoft Word 16.0.18226 and higher, NVDA will now report if a heading is collapsed in both speech and braille. (#17499) +* In Microsoft Word 16.0.18226 and higher or when using Word object model, NVDA will now report if a heading is collapsed in both speech and braille. (#17499) ### Changes