Skip to content

Commit

Permalink
soffice: Report keyboard-triggered font size change (#17147)
Browse files Browse the repository at this point in the history
Partially implements feature requests from #6915

Summary of the issue:
commit 46a3436
("soffice: Report keyboard-triggered formatting toggles in Writer (#16413)") implemented announcement of formatting changes
triggered by keyboard shortcuts for formatting attributes whose state is represented by toggle buttons in Writer's formatting toolbar.
Issue #6915 requests announcement of further text formatting attributes that are not represented by simple toggle buttons. This includes decreasing/increasing the font size, which can be done using the Ctrl+[ and Ctrl+] shortcuts when using an English (US) UI and keyboard layout.

Description of user facing changes
When decreasing or increasing the font size in LibreOffice Writer using the corresponding keyboard shortcuts, NVDA announces the new font size.

Description of development approach
Extend the solution from the above-mentioned
commit 46a3436
to not only cover toggle buttons, but also
UI controls implementing the IAccessibleText
interface and handle the gestures/keyboard shortcuts for changing the font size:

Rename methods and variables introduced earlier to not have button-specific names.
Extract some logic to helper methods/classes to avoid duplication in SymphonyButton and the newly introduced SymphonyText logic.
Add Ctrl+[ and Ctrl+] to the list of keyboard gestures to handle.
Add SymphonyText.event_valueChange override that announces the new value. This gets triggered when the value of the "Font Size" editable combobox in Writer's formatting toolbar changes after using the keyboard shortcut, and results in the new value being announced, e.g. "14 pt". This is comparable to the handling in SymphonyButton.event_stateChange introduced in the earlier above-mentioned commit.
Increase the timeout for announcement of events from 0.15 to 2 seconds, as 0.15 seconds wasn't always sufficient when testing the new feature.
  • Loading branch information
michaelweghorn committed Sep 10, 2024
1 parent a4ebfcd commit 20bdb39
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 17 deletions.
62 changes: 45 additions & 17 deletions source/appModules/soffice.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,20 @@
import vision


class SymphonyUtils:
"""Helper class providing utility methods."""

@staticmethod
def is_toolbar_item(obj: NVDAObject) -> bool:
"""Whether the given object is part of a toolbar."""
parent = obj.parent
while parent:
if parent.role == controlTypes.Role.TOOLBAR:
return True
parent = parent.parent
return False


class SymphonyTextInfo(IA2TextTextInfo):
# C901 '_getFormatFieldFromLegacyAttributesString' is too complex
# Note: when working on _getFormatFieldFromLegacyAttributesString, look for opportunities to simplify
Expand Down Expand Up @@ -235,6 +249,17 @@ def _get_positionInfo(self):
return {"level": int(level)}
return super(SymphonyText, self).positionInfo

def event_valueChange(self) -> None:
# announce new value to indicate formatting change if registered gesture
# triggered the change in toolbar item's value/text
if SymphonyDocument.isFormattingChangeAnnouncementEnabled() and SymphonyUtils.is_toolbar_item(self):
message = self.IAccessibleTextObject.text(0, -1)
ui.message(message)
# disable announcement until next registered keypress enables it again
SymphonyDocument.announceFormattingGestureChange = False

return super().event_valueChange()


class SymphonyTableCell(IAccessible):
"""Silences particular states, and redundant column/row numbers"""
Expand Down Expand Up @@ -355,16 +380,7 @@ class SymphonyButton(IAccessible):
def event_stateChange(self) -> None:
# announce new state of toggled toolbar button to indicate formatting change
# if registered gesture resulted in button state change
if (
SymphonyDocument.announceToolbarButtonToggle
and self.parent
and self.parent.role == controlTypes.Role.TOOLBAR
and time.time()
< (
SymphonyDocument.lastFormattingGestureEventTime
+ SymphonyDocument.GESTURE_ANNOUNCEMENT_TIMEOUT
)
):
if SymphonyDocument.isFormattingChangeAnnouncementEnabled() and SymphonyUtils.is_toolbar_item(self):
states = self.states
enabled = controlTypes.State.PRESSED in states or controlTypes.State.CHECKED in states
# button's accessible name is the font attribute, e.g. "Bold", "Italic"
Expand All @@ -376,7 +392,7 @@ def event_stateChange(self) -> None:
message = _("{textAttribute} off").format(textAttribute=self.name)
ui.message(message)
# disable announcement until next registered keypress enables it again
SymphonyDocument.announceToolbarButtonToggle = False
SymphonyDocument.announceFormattingGestureChange = False

return super().event_stateChange()

Expand Down Expand Up @@ -431,10 +447,16 @@ class SymphonyDocument(CompoundDocument):
TextInfo = SymphonyDocumentTextInfo

# variables used for handling announcements resulting from gestures
GESTURE_ANNOUNCEMENT_TIMEOUT = 0.15
announceToolbarButtonToggle = False
GESTURE_ANNOUNCEMENT_TIMEOUT = 2.0
announceFormattingGestureChange = False
lastFormattingGestureEventTime = 0

@staticmethod
def isFormattingChangeAnnouncementEnabled() -> bool:
return SymphonyDocument.announceFormattingGestureChange and time.time() < (
SymphonyDocument.lastFormattingGestureEventTime + SymphonyDocument.GESTURE_ANNOUNCEMENT_TIMEOUT
)

# override base class implementation because that one assumes
# that the text retrieved from the text info for the text unit
# is the same as the text that actually gets removed, which at
Expand Down Expand Up @@ -489,13 +511,19 @@ def _backspaceScriptHelper(self, unit: str, gesture: inputCore.InputGesture):
"kb:control+r",
# justified
"kb:control+j",
# decrease font size
"kb:control+[",
# increase font size
"kb:control+]",
],
)
def script_toggleTextAttribute(self, gesture: inputCore.InputGesture):
"""Reset time and enable announcement of toggled toolbar buttons.
See :func:`SymphonyButton.event_stateChange`
def script_changeTextFormatting(self, gesture: inputCore.InputGesture):
"""Reset time and enable announcement of newly changed state/text of toolbar
items related to text formatting.
See also :func:`SymphonyButton.event_stateChange` and
:func:`SymphonyText.event_valueChange`.
"""
SymphonyDocument.announceToolbarButtonToggle = True
SymphonyDocument.announceFormattingGestureChange = True
SymphonyDocument.lastFormattingGestureEventTime = time.time()
# send gesture
gesture.send()
Expand Down
4 changes: 4 additions & 0 deletions user_docs/en/changes.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ In order to use this feature, the application volume adjuster needs to be enable
* Added an action in the Add-on Store to cancel the install of add-ons. (#15578, @hwf1324)
* Added an action in the Add-on Store to retry the installation if the download/installation of an add-on fails. (#17090, @hwf1324)
* It is now possible to specify a mirror URL to use for the Add-on Store. (#14974)
* When decreasing or increasing the font size in LibreOffice Writer using the corresponding keyboard shortcuts, NVDA announces the new font size. (#6915, @michaelweghorn)

### Changes

Expand Down Expand Up @@ -60,6 +61,9 @@ Please open a GitHub issue if your add-on has an issue with updating to the new
As the Add-on Store base URL is now configurable directly within NVDA, no replacement is planned. (#17099)
* `NVDAObjects.UIA.winConsoleUIA.WinTerminalUIA` has been removed with no public replacement. (#14047, #16820, @codeofdusk)
* `NVDAObjects.IAccessible.ia2TextMozilla.FakeEmbeddingTextInfo` has been removed. (#16768, @jcsteh)
* The following symbols in `appModules.soffice` have been renamed (#6915, @michaelweghorn):
* `SymphonyDocument.announceToolbarButtonToggle` to `SymphonyDocument.announceFormattingGestureChange`
* `SymphonyDocument.script_toggleTextAttribute` to `SymphonyDocument.script_changeTextFormatting`

#### Deprecations

Expand Down

0 comments on commit 20bdb39

Please sign in to comment.