summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms/wasm
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/platforms/wasm')
-rw-r--r--src/plugins/platforms/wasm/qwasmaccessibility.cpp218
-rw-r--r--src/plugins/platforms/wasm/qwasmaccessibility.h10
2 files changed, 160 insertions, 68 deletions
diff --git a/src/plugins/platforms/wasm/qwasmaccessibility.cpp b/src/plugins/platforms/wasm/qwasmaccessibility.cpp
index a87c33c8346..56a7c466dcd 100644
--- a/src/plugins/platforms/wasm/qwasmaccessibility.cpp
+++ b/src/plugins/platforms/wasm/qwasmaccessibility.cpp
@@ -322,6 +322,16 @@ void QWasmAccessibility::setProperty(emscripten::val element, const std::string
element.set(property, val);
}
+void QWasmAccessibility::setNamedAttribute(QAccessibleInterface *iface, const std::string &attribute, QAccessible::Text text)
+{
+ const emscripten::val element = getHtmlElement(iface);
+ setAttribute(element, attribute, iface->text(text).toStdString());
+}
+void QWasmAccessibility::setNamedProperty(QAccessibleInterface *iface, const std::string &property, QAccessible::Text text)
+{
+ const emscripten::val element = getHtmlElement(iface);
+ setProperty(element, property, iface->text(text).toStdString());
+}
void QWasmAccessibility::addEventListener(QAccessibleInterface *iface, emscripten::val element, const char *eventType)
{
@@ -331,6 +341,17 @@ void QWasmAccessibility::addEventListener(QAccessibleInterface *iface, emscripte
true);
}
+void QWasmAccessibility::sendEvent(QAccessibleInterface *iface, QAccessible::Event eventType)
+{
+ if (iface->object()) {
+ QAccessibleEvent event(iface->object(), eventType);
+ handleUpdateByInterfaceRole(&event);
+ } else {
+ QAccessibleEvent event(iface, eventType);
+ handleUpdateByInterfaceRole(&event);
+ }
+}
+
emscripten::val QWasmAccessibility::createHtmlElement(QAccessibleInterface *iface)
{
// Get the html container element for the interface; this depends on which
@@ -356,12 +377,41 @@ emscripten::val QWasmAccessibility::createHtmlElement(QAccessibleInterface *ifac
addEventListener(iface, element, "click");
} break;
+ case QAccessible::Grouping:
case QAccessible::CheckBox: {
- element = document.call<emscripten::val>("createElement", std::string("input"));
- setAttribute(element, "type", "checkbox");
- setAttribute(element, "checked", iface->state().checked);
- setProperty(element, "indeterminate", iface->state().checkStateMixed);
- addEventListener(iface, element, "change");
+ // Three cases:
+ // 1) role=CheckBox, childCount() == 0 -> Checkbox
+ // 2) role=CheckBox, childCount() > 0 -> GroupBox w/checkbox
+ // 3) role=Grouping -> GroupBox w/label
+
+ emscripten::val checkbox = emscripten::val::undefined();
+ if (iface->role() == QAccessible::CheckBox) {
+ checkbox = document.call<emscripten::val>("createElement", std::string("input"));
+ setAttribute(checkbox, "type", "checkbox");
+ setAttribute(checkbox, "checked", iface->state().checked);
+ setProperty(checkbox, "indeterminate", iface->state().checkStateMixed);
+ addEventListener(iface, checkbox, "change");
+ }
+
+ if (iface->childCount() > 0 || iface->role() == QAccessible::Grouping) {
+ auto label = document.call<emscripten::val>("createElement", std::string("span"));
+
+ const std::string id = QString::asprintf("lbid%p", iface).toStdString();
+ setAttribute(label, "id", id);
+
+ element = document.call<emscripten::val>("createElement", std::string("div"));
+ element.call<void>("appendChild", label);
+
+ setAttribute(element, "role", "group");
+ setAttribute(element, "aria-labelledby", id);
+
+ if (!checkbox.isUndefined()) {
+ element.call<void>("appendChild", checkbox);
+ addEventListener(iface, checkbox, "focus");
+ }
+ } else {
+ element = checkbox;
+ }
} break;
case QAccessible::Switch: {
@@ -484,11 +534,11 @@ emscripten::val QWasmAccessibility::createHtmlElement(QAccessibleInterface *ifac
m_elements[iface] = element;
setHtmlElementGeometry(iface);
- setHtmlElementTextName(iface);
setHtmlElementDisabled(iface);
setHtmlElementVisibility(iface, !iface->state().invisible);
handleIdentifierUpdate(iface);
handleDescriptionChanged(iface);
+ sendEvent(iface, QAccessible::NameChanged);
linkToParent(iface);
// Link in child elements
@@ -586,14 +636,7 @@ void QWasmAccessibility::linkToParent(QAccessibleInterface *iface)
void QWasmAccessibility::setHtmlElementVisibility(QAccessibleInterface *iface, bool visible)
{
emscripten::val element = getHtmlElement(iface);
-
- if (visible) {
- setAttribute(element, "aria-hidden", false);
- setAttribute(element, "tabindex", "");
- } else {
- setAttribute(element, "aria-hidden", true); // aria-hidden mean completely hidden; maybe some sort of soft-hidden should be used.
- setAttribute(element, "tabindex", "-1");
- }
+ setAttribute(element, "aria-hidden", !visible);
}
void QWasmAccessibility::setHtmlElementGeometry(QAccessibleInterface *iface)
@@ -631,28 +674,6 @@ void QWasmAccessibility::setHtmlElementGeometry(emscripten::val element, QRect g
style.set("height", std::to_string(geometry.height()) + "px");
}
-void QWasmAccessibility::setHtmlElementTextName(QAccessibleInterface *iface)
-{
- const emscripten::val element = getHtmlElement(iface);
- const QString name = iface->text(QAccessible::Name);
- const QString value = iface->text(QAccessible::Value);
-
- // A <div> cannot contain aria-label
- if (iface->role() == QAccessible::StaticText)
- setProperty(element, "innerText", name.toStdString());
- else if (iface->role() == QAccessible::EditableText)
- setProperty(element, "value", value.toStdString());
- else
- setAttribute(element, "aria-label", name.toStdString());
-}
-
-void QWasmAccessibility::setHtmlElementTextNameLE(QAccessibleInterface *iface)
-{
- const emscripten::val element = getHtmlElement(iface);
- QString value = iface->text(QAccessible::Value);
- setProperty(element, "value", value.toStdString());
-}
-
void QWasmAccessibility::setHtmlElementFocus(QAccessibleInterface *iface)
{
const auto element = getHtmlElement(iface);
@@ -684,7 +705,8 @@ void QWasmAccessibility::handleStaticTextUpdate(QAccessibleEvent *event)
{
switch (event->type()) {
case QAccessible::NameChanged: {
- setHtmlElementTextName(event->accessibleInterface());
+ // StaticText is a div
+ setNamedProperty(event->accessibleInterface(), "innerText", QAccessible::Name);
} break;
default:
qCDebug(lcQpaAccessibility) << "TODO: implement handleStaticTextUpdate for event" << event->type();
@@ -705,7 +727,7 @@ void QWasmAccessibility::handleLineEditUpdate(QAccessibleEvent *event)
setProperty(element, "type", "text");
} break;
case QAccessible::NameChanged: {
- setHtmlElementTextName(event->accessibleInterface());
+ setNamedProperty(event->accessibleInterface(), "value", QAccessible::Value);
} break;
case QAccessible::ObjectShow:
case QAccessible::Focus: {
@@ -718,12 +740,12 @@ void QWasmAccessibility::handleLineEditUpdate(QAccessibleEvent *event)
else
setProperty(element, "type", "text");
}
- setHtmlElementTextNameLE(iface);
+ setNamedProperty(event->accessibleInterface(), "value", QAccessible::Value);
} break;
case QAccessible::TextRemoved:
case QAccessible::TextInserted:
case QAccessible::TextCaretMoved: {
- setHtmlElementTextNameLE(event->accessibleInterface());
+ setNamedProperty(event->accessibleInterface(), "value", QAccessible::Value);
} break;
default:
qCDebug(lcQpaAccessibility) << "TODO: implement handleLineEditUpdate for event" << event->type();
@@ -758,7 +780,15 @@ void QWasmAccessibility::handleEventFromHtmlElement(const emscripten::val event)
void QWasmAccessibility::handleButtonUpdate(QAccessibleEvent *event)
{
- qCDebug(lcQpaAccessibility) << "TODO: implement handleButtonUpdate for event" << event->type();
+ switch (event->type()) {
+ case QAccessible::Focus:
+ case QAccessible::NameChanged: {
+ setNamedAttribute(event->accessibleInterface(), "aria-label", QAccessible::Name);
+ } break;
+ default:
+ qCDebug(lcQpaAccessibility) << "TODO: implement handleCheckBoxUpdate for event" << event->type();
+ break;
+ }
}
void QWasmAccessibility::handleCheckBoxUpdate(QAccessibleEvent *event)
@@ -766,7 +796,7 @@ void QWasmAccessibility::handleCheckBoxUpdate(QAccessibleEvent *event)
switch (event->type()) {
case QAccessible::Focus:
case QAccessible::NameChanged: {
- setHtmlElementTextName(event->accessibleInterface());
+ setNamedAttribute(event->accessibleInterface(), "aria-label", QAccessible::Name);
} break;
case QAccessible::StateChanged: {
QAccessibleInterface *accessible = event->accessibleInterface();
@@ -780,12 +810,42 @@ void QWasmAccessibility::handleCheckBoxUpdate(QAccessibleEvent *event)
}
}
+void QWasmAccessibility::handleGroupBoxUpdate(QAccessibleEvent *event)
+{
+ QAccessibleInterface *iface = event->accessibleInterface();
+
+ emscripten::val parent = getHtmlElement(iface);
+ emscripten::val label = parent["children"][0];
+ emscripten::val checkbox = emscripten::val::undefined();
+ if (iface->role() == QAccessible::CheckBox)
+ checkbox = parent["children"][1];
+
+ switch (event->type()) {
+ case QAccessible::Focus:
+ case QAccessible::NameChanged: {
+ setProperty(label, "innerText", iface->text(QAccessible::Name).toStdString());
+ if (!checkbox.isUndefined())
+ setAttribute(checkbox, "aria-label", iface->text(QAccessible::Name).toStdString());
+ } break;
+ case QAccessible::StateChanged: {
+ if (!checkbox.isUndefined()) {
+ setAttribute(checkbox, "checked", iface->state().checked);
+ setProperty(checkbox, "indeterminate", iface->state().checkStateMixed);
+ }
+ } break;
+ default:
+ qCDebug(lcQpaAccessibility) << "TODO: implement handleCheckBoxUpdate for event" << event->type();
+ break;
+ }
+}
+
void QWasmAccessibility::handleSwitchUpdate(QAccessibleEvent *event)
{
switch (event->type()) {
case QAccessible::Focus:
case QAccessible::NameChanged: {
- setHtmlElementTextName(event->accessibleInterface());
+ /* A switch is like a button in this regard */
+ setNamedAttribute(event->accessibleInterface(), "aria-label", QAccessible::Name);
} break;
case QAccessible::StateChanged: {
QAccessibleInterface *accessible = event->accessibleInterface();
@@ -848,7 +908,7 @@ void QWasmAccessibility::handleDialogUpdate(QAccessibleEvent *event) {
case QAccessible::Focus:
case QAccessible::DialogStart:
case QAccessible::StateChanged: {
- setHtmlElementTextName(event->accessibleInterface());
+ setNamedAttribute(event->accessibleInterface(), "aria-label", QAccessible::Name);
} break;
default:
qCDebug(lcQpaAccessibility) << "TODO: implement handleLineEditUpdate for event" << event->type();
@@ -876,10 +936,10 @@ void QWasmAccessibility::populateAccessibilityTree(QAccessibleInterface *iface)
linkToParent(iface);
setHtmlElementVisibility(iface, !iface->state().invisible);
setHtmlElementGeometry(iface);
- setHtmlElementTextName(iface);
setHtmlElementDisabled(iface);
handleIdentifierUpdate(iface);
handleDescriptionChanged(iface);
+ sendEvent(iface, QAccessible::NameChanged);
}
}
for (int i = 0; i < iface->childCount(); ++i)
@@ -891,7 +951,7 @@ void QWasmAccessibility::handleRadioButtonUpdate(QAccessibleEvent *event)
switch (event->type()) {
case QAccessible::Focus:
case QAccessible::NameChanged: {
- setHtmlElementTextName(event->accessibleInterface());
+ setNamedAttribute(event->accessibleInterface(), "aria-label", QAccessible::Name);
} break;
case QAccessible::StateChanged: {
QAccessibleInterface *accessible = event->accessibleInterface();
@@ -912,7 +972,7 @@ void QWasmAccessibility::handleSpinBoxUpdate(QAccessibleEvent *event)
} break;
case QAccessible::Focus:
case QAccessible::NameChanged: {
- setHtmlElementTextName(event->accessibleInterface());
+ setNamedAttribute(event->accessibleInterface(), "aria-label", QAccessible::Name);
} break;
case QAccessible::ValueChanged: {
QAccessibleInterface *accessible = event->accessibleInterface();
@@ -934,7 +994,7 @@ void QWasmAccessibility::handleSliderUpdate(QAccessibleEvent *event)
} break;
case QAccessible::Focus:
case QAccessible::NameChanged: {
- setHtmlElementTextName(event->accessibleInterface());
+ setNamedAttribute(event->accessibleInterface(), "aria-label", QAccessible::Name);
} break;
case QAccessible::ValueChanged: {
QAccessibleInterface *accessible = event->accessibleInterface();
@@ -953,7 +1013,7 @@ void QWasmAccessibility::handleScrollBarUpdate(QAccessibleEvent *event)
switch (event->type()) {
case QAccessible::Focus:
case QAccessible::NameChanged: {
- setHtmlElementTextName(event->accessibleInterface());
+ setNamedAttribute(event->accessibleInterface(), "aria-label", QAccessible::Name);
} break;
case QAccessible::ValueChanged: {
QAccessibleInterface *accessible = event->accessibleInterface();
@@ -972,10 +1032,10 @@ void QWasmAccessibility::handlePageTabUpdate(QAccessibleEvent *event)
{
switch (event->type()) {
case QAccessible::NameChanged: {
- setHtmlElementTextName(event->accessibleInterface());
+ setNamedAttribute(event->accessibleInterface(), "aria-label", QAccessible::Name);
} break;
case QAccessible::Focus: {
- setHtmlElementTextName(event->accessibleInterface());
+ setNamedAttribute(event->accessibleInterface(), "aria-label", QAccessible::Name);
} break;
default:
qDebug() << "TODO: implement handlePageTabUpdate for event" << event->type();
@@ -987,10 +1047,10 @@ void QWasmAccessibility::handlePageTabListUpdate(QAccessibleEvent *event)
{
switch (event->type()) {
case QAccessible::NameChanged: {
- setHtmlElementTextName(event->accessibleInterface());
+ setNamedAttribute(event->accessibleInterface(), "aria-label", QAccessible::Name);
} break;
case QAccessible::Focus: {
- setHtmlElementTextName(event->accessibleInterface());
+ setNamedAttribute(event->accessibleInterface(), "aria-label", QAccessible::Name);
} break;
default:
qDebug() << "TODO: implement handlePageTabUpdate for event" << event->type();
@@ -1113,13 +1173,19 @@ void QWasmAccessibility::relinkParentForChildren(QAccessibleInterface *iface)
void QWasmAccessibility::notifyAccessibilityUpdate(QAccessibleEvent *event)
{
+ if (handleUpdateByEventType(event))
+ handleUpdateByInterfaceRole(event);
+}
+
+bool QWasmAccessibility::handleUpdateByEventType(QAccessibleEvent *event)
+{
if (!m_accessibilityEnabled)
- return;
+ return false;
QAccessibleInterface *iface = event->accessibleInterface();
if (!iface) {
- qWarning() << "notifyAccessibilityUpdate with null a11y interface" << event->type() << event->object();
- return;
+ qWarning() << "handleUpdateByEventType with null a11y interface" << event->type() << event->object();
+ return false;
}
// Handle event types that creates/removes objects.
@@ -1127,13 +1193,13 @@ void QWasmAccessibility::notifyAccessibilityUpdate(QAccessibleEvent *event)
case QAccessible::ObjectCreated:
// Do nothing, there are too many changes to the interface
// before ObjectShow is called
- return;
+ return false;
case QAccessible::ObjectDestroyed:
// The object might be under destruction, and the interface is not valid
// but we can look at the pointer,
removeObject(iface);
- return;
+ return false;
case QAccessible::ObjectShow: // We do not get ObjectCreated from widgets, we get ObjectShow
createObject(iface);
@@ -1149,7 +1215,7 @@ void QWasmAccessibility::notifyAccessibilityUpdate(QAccessibleEvent *event)
};
if (getHtmlElement(iface).isUndefined())
- return;
+ return false;
// Handle some common event types. See
// https://doc.qt.io/qt-5/qaccessible.html#Event-enum
@@ -1162,7 +1228,7 @@ void QWasmAccessibility::notifyAccessibilityUpdate(QAccessibleEvent *event)
case QAccessible::DescriptionChanged:
handleDescriptionChanged(iface);
- return;
+ return false;
case QAccessible::Focus:
// We do not get all callbacks for the geometry
@@ -1173,7 +1239,7 @@ void QWasmAccessibility::notifyAccessibilityUpdate(QAccessibleEvent *event)
case QAccessible::IdentifierChanged:
handleIdentifierUpdate(iface);
- return;
+ return false;
case QAccessible::ObjectShow:
linkToParent(iface);
@@ -1181,23 +1247,37 @@ void QWasmAccessibility::notifyAccessibilityUpdate(QAccessibleEvent *event)
// Sync up properties on show;
setHtmlElementGeometry(iface);
- setHtmlElementTextName(iface);
+ sendEvent(iface, QAccessible::NameChanged);
break;
case QAccessible::ObjectHide:
linkToParent(iface);
setHtmlElementVisibility(iface, false);
- return;
+ return false;
case QAccessible::LocationChanged:
setHtmlElementGeometry(iface);
- return;
+ return false;
// TODO: maybe handle more types here
default:
break;
};
+ return true;
+}
+
+void QWasmAccessibility::handleUpdateByInterfaceRole(QAccessibleEvent *event)
+{
+ if (!m_accessibilityEnabled)
+ return;
+
+ QAccessibleInterface *iface = event->accessibleInterface();
+ if (!iface) {
+ qWarning() << "handleUpdateByInterfaceRole with null a11y interface" << event->type() << event->object();
+ return;
+ }
+
// Switch on interface role, see
// https://doc.qt.io/qt-5/qaccessibleinterface.html#role
switch (iface->role()) {
@@ -1205,10 +1285,13 @@ void QWasmAccessibility::notifyAccessibilityUpdate(QAccessibleEvent *event)
handleStaticTextUpdate(event);
break;
case QAccessible::Button:
- handleStaticTextUpdate(event);
+ handleButtonUpdate(event);
break;
case QAccessible::CheckBox:
- handleCheckBoxUpdate(event);
+ if (iface->childCount() > 0)
+ handleGroupBoxUpdate(event);
+ else
+ handleCheckBoxUpdate(event);
break;
case QAccessible::Switch:
handleSwitchUpdate(event);
@@ -1245,6 +1328,9 @@ void QWasmAccessibility::notifyAccessibilityUpdate(QAccessibleEvent *event)
case QAccessible::ScrollBar:
handleScrollBarUpdate(event);
break;
+ case QAccessible::Grouping:
+ handleGroupBoxUpdate(event);
+ break;
default:
qCDebug(lcQpaAccessibility) << "TODO: implement notifyAccessibilityUpdate for role" << iface->role();
};
diff --git a/src/plugins/platforms/wasm/qwasmaccessibility.h b/src/plugins/platforms/wasm/qwasmaccessibility.h
index ddbfec918d6..2fff281b0d6 100644
--- a/src/plugins/platforms/wasm/qwasmaccessibility.h
+++ b/src/plugins/platforms/wasm/qwasmaccessibility.h
@@ -73,8 +73,6 @@ private:
void setHtmlElementVisibility(QAccessibleInterface *iface, bool visible);
void setHtmlElementGeometry(QAccessibleInterface *iface);
void setHtmlElementGeometry(emscripten::val element, QRect geometry);
- void setHtmlElementTextName(QAccessibleInterface *iface);
- void setHtmlElementTextNameLE(QAccessibleInterface *iface);
void setHtmlElementFocus(QAccessibleInterface *iface);
void setHtmlElementDisabled(QAccessibleInterface *iface);
void setHtmlElementOrientation(emscripten::val element, QAccessibleInterface *iface);
@@ -82,6 +80,7 @@ private:
void handleStaticTextUpdate(QAccessibleEvent *event);
void handleButtonUpdate(QAccessibleEvent *event);
void handleCheckBoxUpdate(QAccessibleEvent *event);
+ void handleGroupBoxUpdate(QAccessibleEvent *event);
void handleSwitchUpdate(QAccessibleEvent *event);
void handleDialogUpdate(QAccessibleEvent *event);
void handleMenuUpdate(QAccessibleEvent *event);
@@ -105,6 +104,9 @@ private:
void relinkParentForChildren(QAccessibleInterface *iface);
void notifyAccessibilityUpdate(QAccessibleEvent *event) override;
+ bool handleUpdateByEventType(QAccessibleEvent *event);
+ void handleUpdateByInterfaceRole(QAccessibleEvent *event);
+
void setRootObject(QObject *o) override;
void initialize() override;
void cleanup() override;
@@ -117,7 +119,11 @@ private:
void setProperty(emscripten::val element, const std::string &attr, const char *val);
void setProperty(emscripten::val element, const std::string &attr, bool val);
+ void setNamedAttribute(QAccessibleInterface *iface, const std::string &attribute, QAccessible::Text text);
+ void setNamedProperty(QAccessibleInterface *iface, const std::string &property, QAccessible::Text text);
+
void addEventListener(QAccessibleInterface *, emscripten::val element, const char *eventType);
+ void sendEvent(QAccessibleInterface *iface, QAccessible::Event eventType);
private:
static QWasmAccessibility *s_instance;