Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 31 additions & 2 deletions ui/accessible/ui_accessible_item.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -198,20 +198,49 @@ QAccessibleInterface *Item::parent() const {
}

void *Item::interface_cast(QAccessible::InterfaceType type) {
const auto parent = _parent.get();
const auto index = parent ? currentIndex() : -1;
if (type == QAccessible::ActionInterface) {
// Expose the action interface only when the owner opted in for this
// child. Otherwise the Windows UIA bridge would advertise Invoke /
// SetFocus / SelectionItem and report success while doing nothing.
const auto parent = _parent.get();
const auto index = parent ? currentIndex() : -1;
if (index >= 0
&& parent->accessibilityChildSupportsActions(index)) {
return static_cast<QAccessibleActionInterface*>(this);
}
} else if (type == QAccessible::AttributesInterface) {
// Only a row that is one of the set reports a position, a divider
// between the rows has none - see accessibilityChildSetPosition.
if (index >= 0
&& parent->accessibilityChildSetPosition(index).position > 0) {
return static_cast<QAccessibleAttributesInterface*>(this);
}
}
return nullptr;
}

QList<QAccessible::Attribute> Item::attributeKeys() const {
return {
QAccessible::Attribute::PositionInSet,
QAccessible::Attribute::SizeOfSet,
};
}

QVariant Item::attributeValue(QAccessible::Attribute key) const {
const auto parent = _parent.get();
const auto index = parent ? currentIndex() : -1;
if (index < 0) {
return QVariant();
}
const auto position = parent->accessibilityChildSetPosition(index);
if (key == QAccessible::Attribute::PositionInSet) {
return position.position;
} else if (key == QAccessible::Attribute::SizeOfSet) {
return position.size;
}
return QVariant();
}

QStringList Item::actionNames() const {
const auto parent = _parent.get();
const auto index = parent ? currentIndex() : -1;
Expand Down
7 changes: 6 additions & 1 deletion ui/accessible/ui_accessible_item.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,8 @@ struct SubItems {

class Item final
: public QAccessibleInterface
, public QAccessibleActionInterface {
, public QAccessibleActionInterface
, public QAccessibleAttributesInterface {
public:
Item(not_null<RpWidget*> parent, int index);

Expand Down Expand Up @@ -131,6 +132,10 @@ class Item final
QStringList keyBindingsForAction(
const QString &actionName) const override;

// QAccessibleAttributesInterface.
QList<QAccessible::Attribute> attributeKeys() const override;
QVariant attributeValue(QAccessible::Attribute key) const override;

private:
base::weak_qptr<RpWidget> _parent;
mutable std::unique_ptr<SubItems> _subitems;
Expand Down
5 changes: 5 additions & 0 deletions ui/rp_widget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,11 @@ QAccessible::Role RpWidget::accessibilityChildRole() const {
return QAccessible::Role::NoRole;
}

AccessibilitySetPosition RpWidget::accessibilityChildSetPosition(
int index) const {
return { index + 1, accessibilityChildCount() };
}

QString RpWidget::accessibilityChildName(int index) const {
return QString();
}
Expand Down
15 changes: 15 additions & 0 deletions ui/rp_widget.h
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,15 @@ class RpWidgetBase : public Widget, public RpWidgetWrap {
// Add required fields from QAccessible::State when necessary.
// Don't forget to amend the AccessibilityState::writeTo implementation.
// This one allows universal initialization, like { .checkable = true }.
// The "x of y" of a child of a painted list, reported to a screen reader
// as PositionInSet / SizeOfSet: the 1-based position of the child within
// the set of its siblings and the size of that set. A zero position means
// the child is not one of the set, like a divider row between the items.
struct AccessibilitySetPosition {
int position = 0;
int size = 0;
};

struct AccessibilityState {
bool checkable : 1 = false;
bool checked : 1 = false;
Expand Down Expand Up @@ -458,6 +467,12 @@ class RpWidget : public RpWidgetBase<QWidget> {
[[nodiscard]] virtual QAccessible::State accessibilityChildState(int index) const;
void accessibilityChildStateChanged(int index, AccessibilityState changes);
[[nodiscard]] virtual QAccessible::Role accessibilityChildRole() const;

// By default every child is one of the set; a list with rows outside
// it overrides this to skip them, see AccessibilitySetPosition.
[[nodiscard]] virtual AccessibilitySetPosition accessibilityChildSetPosition(
int index) const;

[[nodiscard]] virtual QRect accessibilityChildRect(int index) const;
[[nodiscard]] virtual int accessibilityChildColumnCount(int row) const;
[[nodiscard]] virtual QAccessible::Role accessibilityChildSubItemRole() const;
Expand Down