Issue type
Bug (accessibility, all platforms; most visible on Windows through UI Automation)
Description
Every accessible item in the framework exposes a text interface, whatever its role. Buttons, check boxes, list items, groups and non-text score elements all report that they are text.
Qt decides per platform whether an element is a text control by asking the accessible interface for its text interface. On Windows, the UI Automation backend offers the Text pattern to assistive technology exactly when that call returns a non-null pointer (QWindowsUiaMainProvider::GetPatternProvider, case UIA_TextPatternId). The AT-SPI backend on Linux uses the same call to add the Text interface to every element.
The framework's AccessibleItemInterface::interface_cast returns the text interface unconditionally:
|
void* AccessibleItemInterface::interface_cast(QAccessible::InterfaceType type) |
|
{ |
|
QAccessible::Role itemRole = role(); |
|
if (type == QAccessible::InterfaceType::ValueInterface && itemRole == QAccessible::Slider) { |
|
return static_cast<QAccessibleValueInterface*>(this); |
|
} else if (type == QAccessible::InterfaceType::TextInterface) { |
|
return static_cast<QAccessibleTextInterface*>(this); |
|
} |
|
|
As a result every control reports IsTextPatternAvailable = true in UIA. For non-text controls the exposed text document is empty, because the item's text hooks return an empty string and a character count of zero.
Screen readers such as NVDA treat any element with a Text pattern as a text container. Buttons and list items then behave like empty text documents instead of like buttons and list items: text review, braille routing and caret tracking operate on an empty document instead of on the control's name.
Steps to reproduce
- Start MuseScore Studio on Windows.
- Open Accessibility Insights for Windows or Inspect.exe.
- Move keyboard focus to any button, or to an item in a list.
- Look at the patterns reported for the focused element.
Expected: no Text pattern on a button or list item.
Actual: IsTextPatternAvailable is true, and the Text pattern's document range is empty.
Root cause
The unconditional branch dates from the commit that added screen reader access to score text (musescore/MuseScore#10371). It was never restricted to text items. It did not need to be unconditional: score text elements already register with the EditableText role (TextBase::createAccessible), and the only QML consumer of the accessible.text property is the braille view, which also uses EditableText.
Qt's own reference implementation for Quick items limits the text interface to text roles (QAccessibleQuickItem::interface_cast returns it only for EditableText, StaticText and Heading).
Proposed fix
Return the text interface only when the framework role of the item is EditableText. The check must use the framework role, not the Qt role. On Windows the framework maps Group, Information and ElementOnScore to QAccessible::StaticText, so a check on the Qt role would still leak the Text pattern to every non-text score element.
if (type == QAccessible::InterfaceType::ValueInterface && itemRole == QAccessible::Slider) {
return static_cast<QAccessibleValueInterface*>(this);
- } else if (type == QAccessible::InterfaceType::TextInterface) {
+ } else if (type == QAccessible::InterfaceType::TextInterface
+ && m_object->item()->accessibleRole() == IAccessible::Role::EditableText) {
return static_cast<QAccessibleTextInterface*>(this);
}
StaticText is deliberately left out. No item with that role sets accessible text today, so including it would keep exposing empty text documents on labels.
The comment at lines 542 and 547 says "Without Action and Text interfaces NVDA doesn't work" for list items. That comment was added a year after the text interface became unconditional, so the Text half of that claim was never observed in isolation. NVDA announces UIA list items from their Name property and does not need a Text pattern for that.
Issue type
Bug (accessibility, all platforms; most visible on Windows through UI Automation)
Description
Every accessible item in the framework exposes a text interface, whatever its role. Buttons, check boxes, list items, groups and non-text score elements all report that they are text.
Qt decides per platform whether an element is a text control by asking the accessible interface for its text interface. On Windows, the UI Automation backend offers the Text pattern to assistive technology exactly when that call returns a non-null pointer (
QWindowsUiaMainProvider::GetPatternProvider, caseUIA_TextPatternId). The AT-SPI backend on Linux uses the same call to add the Text interface to every element.The framework's
AccessibleItemInterface::interface_castreturns the text interface unconditionally:muse_framework/framework/accessibility/internal/accessibleiteminterface.cpp
Lines 531 to 539 in a908ba7
As a result every control reports
IsTextPatternAvailable = truein UIA. For non-text controls the exposed text document is empty, because the item's text hooks return an empty string and a character count of zero.Screen readers such as NVDA treat any element with a Text pattern as a text container. Buttons and list items then behave like empty text documents instead of like buttons and list items: text review, braille routing and caret tracking operate on an empty document instead of on the control's name.
Steps to reproduce
Expected: no Text pattern on a button or list item.
Actual:
IsTextPatternAvailableis true, and the Text pattern's document range is empty.Root cause
The unconditional branch dates from the commit that added screen reader access to score text (musescore/MuseScore#10371). It was never restricted to text items. It did not need to be unconditional: score text elements already register with the
EditableTextrole (TextBase::createAccessible), and the only QML consumer of theaccessible.textproperty is the braille view, which also usesEditableText.Qt's own reference implementation for Quick items limits the text interface to text roles (
QAccessibleQuickItem::interface_castreturns it only forEditableText,StaticTextandHeading).Proposed fix
Return the text interface only when the framework role of the item is
EditableText. The check must use the framework role, not the Qt role. On Windows the framework mapsGroup,InformationandElementOnScoretoQAccessible::StaticText, so a check on the Qt role would still leak the Text pattern to every non-text score element.if (type == QAccessible::InterfaceType::ValueInterface && itemRole == QAccessible::Slider) { return static_cast<QAccessibleValueInterface*>(this); - } else if (type == QAccessible::InterfaceType::TextInterface) { + } else if (type == QAccessible::InterfaceType::TextInterface + && m_object->item()->accessibleRole() == IAccessible::Role::EditableText) { return static_cast<QAccessibleTextInterface*>(this); }StaticTextis deliberately left out. No item with that role sets accessible text today, so including it would keep exposing empty text documents on labels.The comment at lines 542 and 547 says "Without Action and Text interfaces NVDA doesn't work" for list items. That comment was added a year after the text interface became unconditional, so the Text half of that claim was never observed in isolation. NVDA announces UIA list items from their Name property and does not need a Text pattern for that.