diff options
author | Shreya Pattani <shreya.pattani@crossware.io> | 2022-11-25 12:10:05 +0100 |
---|---|---|
committer | Morten Johan Sørvig <morten.sorvig@qt.io> | 2022-12-27 14:30:25 +0000 |
commit | 040b4a4b21b325995c49772a86a061249f16851c (patch) | |
tree | 9407f9b6605dc65fb724661f58e86e53027de42d /src/plugins/platforms/wasm/qwasmaccessibility.cpp | |
parent | 13c3fd959ed400396ee770d3e300778cf20a50a9 (diff) |
wasm: Work on wasm accessibility elements and events
Implement a11y support by adding html elements (Checkbox, Radio Button,
TabView,Spinbox, ScrollBar, Slider, Event for Button) and events of
the appropriate type and/or with the appropriate ARIA attribute
behind the canvas.
Pick-to: 6.5
Change-Id: I52902eae2bd4ac7a125815e1d2dd3077211fc118
Reviewed-by: Morten Johan Sørvig <morten.sorvig@qt.io>
Diffstat (limited to 'src/plugins/platforms/wasm/qwasmaccessibility.cpp')
-rw-r--r-- | src/plugins/platforms/wasm/qwasmaccessibility.cpp | 283 |
1 files changed, 274 insertions, 9 deletions
diff --git a/src/plugins/platforms/wasm/qwasmaccessibility.cpp b/src/plugins/platforms/wasm/qwasmaccessibility.cpp index 552f7846ea..e9217cbefc 100644 --- a/src/plugins/platforms/wasm/qwasmaccessibility.cpp +++ b/src/plugins/platforms/wasm/qwasmaccessibility.cpp @@ -4,6 +4,8 @@ #include "qwasmaccessibility.h" #include "qwasmscreen.h" #include "qwasmwindow.h" +#include "qwasmintegration.h" +#include <QtGui/private/qaccessiblebridgeutils_p.h> #include <QtGui/qwindow.h> @@ -111,7 +113,17 @@ emscripten::val QWasmAccessibility::getContainer(QWindow *window) emscripten::val QWasmAccessibility::getContainer(QAccessibleInterface *iface) { - return getContainer(iface->window()); + QWindow *window = iface->window(); + if (!window) { + //this is needed to add tabs as the window is not available + if (iface->parent()->window()) { + window = iface->parent()->window(); + } else { + return emscripten::val::undefined(); + } + } + + return getContainer(window); } emscripten::val QWasmAccessibility::getDocument(const emscripten::val &container) @@ -148,10 +160,88 @@ emscripten::val QWasmAccessibility::createHtmlElement(QAccessibleInterface *ifac case QAccessible::Button: { element = document.call<emscripten::val>("createElement", std::string("button")); + element.call<void>("addEventListener", emscripten::val("click"), + emscripten::val::module_property("qtEventReceived"), true); } break; case QAccessible::CheckBox: { element = document.call<emscripten::val>("createElement", std::string("input")); element.call<void>("setAttribute", std::string("type"), std::string("checkbox")); + if (iface->state().checked) { + element.call<void>("setAttribute", std::string("checked"), std::string("true")); + } + element.call<void>("addEventListener", emscripten::val("change"), + emscripten::val::module_property("qtEventReceived"), true); + + } break; + + case QAccessible::RadioButton: { + element = document.call<emscripten::val>("createElement", std::string("input")); + element.call<void>("setAttribute", std::string("type"), std::string("radio")); + if (iface->state().checked) { + element.call<void>("setAttribute", std::string("checked"), std::string("true")); + } + element.set(std::string("name"), std::string("buttonGroup")); + element.call<void>("addEventListener", emscripten::val("change"), + emscripten::val::module_property("qtEventReceived"), true); + } break; + + case QAccessible::SpinBox: { + element = document.call<emscripten::val>("createElement", std::string("input")); + element.call<void>("setAttribute", std::string("type"), std::string("number")); + std::string valueString = iface->valueInterface()->currentValue().toString().toStdString(); + element.call<void>("setAttribute", std::string("value"), valueString); + element.call<void>("addEventListener", emscripten::val("change"), + emscripten::val::module_property("qtEventReceived"), true); + } break; + + case QAccessible::Slider: { + element = document.call<emscripten::val>("createElement", std::string("input")); + element.call<void>("setAttribute", std::string("type"), std::string("range")); + std::string valueString = iface->valueInterface()->currentValue().toString().toStdString(); + element.call<void>("setAttribute", std::string("value"), valueString); + element.call<void>("addEventListener", emscripten::val("change"), + emscripten::val::module_property("qtEventReceived"), true); + } break; + + case QAccessible::PageTabList:{ + element = document.call<emscripten::val>("createElement", std::string("div")); + element.call<void>("setAttribute", std::string("role"), std::string("tablist")); + QString idName = iface->text(QAccessible::Name).replace(" ", "_"); + idName += "_tabList"; + element.call<void>("setAttribute", std::string("id"), idName.toStdString()); + + for (int i = 0; i < iface->childCount(); ++i) { + if (iface->child(i)->role() == QAccessible::PageTab){ + emscripten::val elementTab = emscripten::val::undefined(); + elementTab = ensureHtmlElement(iface->child(i)); + elementTab.call<void>("setAttribute", std::string("aria-owns"), idName.toStdString()); + setHtmlElementGeometry(iface->child(i)); + } + } + } break; + + case QAccessible::PageTab:{ + element = document.call<emscripten::val>("createElement", std::string("button")); + element.call<void>("setAttribute", std::string("role"), std::string("tab")); + QString text = iface->text(QAccessible::Name); + element.call<void>("setAttribute", std::string("title"), text.toStdString()); + element.call<void>("addEventListener", emscripten::val("click"), + emscripten::val::module_property("qtEventReceived"), true); + } break; + + case QAccessible::ScrollBar: { + element = document.call<emscripten::val>("createElement", std::string("div")); + element.call<void>("setAttribute", std::string("role"), std::string("scrollbar")); + std::string valueString = iface->valueInterface()->currentValue().toString().toStdString(); + element.call<void>("setAttribute", std::string("aria-valuenow"), valueString); + element.call<void>("addEventListener", emscripten::val("change"), + emscripten::val::module_property("qtEventReceived"), true); + } break; + + case QAccessible::StaticText: { + element = document.call<emscripten::val>("createElement", std::string("textarea")); + element.call<void>("setAttribute", std::string("readonly"), std::string("true")); + } break; case QAccessible::Dialog: { element = document.call<emscripten::val>("createElement", std::string("dialog")); @@ -261,6 +351,14 @@ void QWasmAccessibility::setHtmlElementTextName(QAccessibleInterface *iface) element.set("innerHTML", text.toStdString()); // FIXME: use something else than innerHTML } +void QWasmAccessibility::setHtmlElementTextNameLE(QAccessibleInterface *iface) { + emscripten::val element = ensureHtmlElement(iface); + QString text = iface->text(QAccessible::Name); + element.call<void>("setAttribute", std::string("name"), text.toStdString()); + QString value = iface->text(QAccessible::Value); + element.set("innerHTML", value.toStdString()); +} + void QWasmAccessibility::handleStaticTextUpdate(QAccessibleEvent *event) { switch (event->type()) { @@ -273,14 +371,6 @@ void QWasmAccessibility::handleStaticTextUpdate(QAccessibleEvent *event) } } -void QWasmAccessibility::setHtmlElementTextNameLE(QAccessibleInterface *iface) { - emscripten::val element = ensureHtmlElement(iface); - QString text = iface->text(QAccessible::Name); - element.call<void>("setAttribute", std::string("name"), text.toStdString()); - QString value = iface->text(QAccessible::Value); - element.set("innerHTML", value.toStdString()); -} - void QWasmAccessibility::handleLineEditUpdate(QAccessibleEvent *event) { switch (event->type()) { @@ -300,6 +390,41 @@ void QWasmAccessibility::handleLineEditUpdate(QAccessibleEvent *event) { } } +void QWasmAccessibility::handleEventFromHtmlElement(const emscripten::val event) +{ + + QAccessibleInterface *iface = m_elements.key(event["target"]); + + if (iface == nullptr) { + return; + } else { + QString eventType = QString::fromStdString(event["type"].as<std::string>()); + const auto& actionNames = QAccessibleBridgeUtils::effectiveActionNames(iface); + + if (actionNames.contains(QAccessibleActionInterface::pressAction())) { + + iface->actionInterface()->doAction(QAccessibleActionInterface::pressAction()); + + } else if (actionNames.contains(QAccessibleActionInterface::toggleAction())) { + + iface->actionInterface()->doAction(QAccessibleActionInterface::toggleAction()); + + } else if (actionNames.contains(QAccessibleActionInterface::increaseAction()) || + actionNames.contains(QAccessibleActionInterface::decreaseAction())) { + + QString val = QString::fromStdString(event["target"]["value"].as<std::string>()); + + iface->valueInterface()->setCurrentValue(val.toInt()); + + } else if (eventType == "input") { + + if (iface->editableTextInterface()) { + std::string insertText = event["target"]["value"].as<std::string>(); + iface->setText(QAccessible::Value, QString::fromStdString(insertText)); + } + } + } +} void QWasmAccessibility::handleButtonUpdate(QAccessibleEvent *event) { @@ -309,9 +434,16 @@ void QWasmAccessibility::handleButtonUpdate(QAccessibleEvent *event) void QWasmAccessibility::handleCheckBoxUpdate(QAccessibleEvent *event) { switch (event->type()) { + case QAccessible::Focus: case QAccessible::NameChanged: { setHtmlElementTextName(event->accessibleInterface()); } break; + case QAccessible::StateChanged: { + QAccessibleInterface *accessible = event->accessibleInterface(); + emscripten::val element = ensureHtmlElement(accessible); + bool checkedString = accessible->state().checked ? true : false; + element.call<void>("setAttribute", std::string("checked"), checkedString); + } break; default: qCDebug(lcQpaAccessibility) << "TODO: implement handleCheckBoxUpdate for event" << event->type(); break; @@ -383,6 +515,113 @@ void QWasmAccessibility::populateAccessibilityTree(QAccessibleInterface *iface) populateAccessibilityTree(iface->child(i)); } +void QWasmAccessibility::handleRadioButtonUpdate(QAccessibleEvent *event) +{ + switch (event->type()) { + case QAccessible::Focus: + case QAccessible::NameChanged: { + setHtmlElementTextName(event->accessibleInterface()); + } break; + case QAccessible::StateChanged: { + QAccessibleInterface *accessible = event->accessibleInterface(); + emscripten::val element = ensureHtmlElement(accessible); + std::string checkedString = accessible->state().checked ? "true" : "false"; + element.call<void>("setAttribute", std::string("checked"), checkedString); + } break; + default: + qDebug() << "TODO: implement handleRadioButtonUpdate for event" << event->type(); + break; + } +} + +void QWasmAccessibility::handleSpinBoxUpdate(QAccessibleEvent *event) +{ + switch (event->type()) { + case QAccessible::Focus: + case QAccessible::NameChanged: { + setHtmlElementTextName(event->accessibleInterface()); + } break; + case QAccessible::ValueChanged: { + QAccessibleInterface *accessible = event->accessibleInterface(); + emscripten::val element = ensureHtmlElement(accessible); + std::string valueString = accessible->valueInterface()->currentValue().toString().toStdString(); + element.call<void>("setAttribute", std::string("value"), valueString); + } break; + default: + qDebug() << "TODO: implement handleSpinBoxUpdate for event" << event->type(); + break; + } +} + +void QWasmAccessibility::handleSliderUpdate(QAccessibleEvent *event) +{ + switch (event->type()) { + case QAccessible::Focus: + case QAccessible::NameChanged: { + setHtmlElementTextName(event->accessibleInterface()); + } break; + case QAccessible::ValueChanged: { + QAccessibleInterface *accessible = event->accessibleInterface(); + emscripten::val element = ensureHtmlElement(accessible); + std::string valueString = accessible->valueInterface()->currentValue().toString().toStdString(); + element.call<void>("setAttribute", std::string("value"), valueString); + } break; + default: + qDebug() << "TODO: implement handleSliderUpdate for event" << event->type(); + break; + } +} + +void QWasmAccessibility::handleScrollBarUpdate(QAccessibleEvent *event) +{ + switch (event->type()) { + case QAccessible::Focus: + case QAccessible::NameChanged: { + setHtmlElementTextName(event->accessibleInterface()); + } break; + case QAccessible::ValueChanged: { + QAccessibleInterface *accessible = event->accessibleInterface(); + emscripten::val element = ensureHtmlElement(accessible); + std::string valueString = accessible->valueInterface()->currentValue().toString().toStdString(); + element.call<void>("setAttribute", std::string("aria-valuenow"), valueString); + } break; + default: + qDebug() << "TODO: implement handleSliderUpdate for event" << event->type(); + break; + } + +} + +void QWasmAccessibility::handlePageTabUpdate(QAccessibleEvent *event) +{ + switch (event->type()) { + case QAccessible::NameChanged: { + setHtmlElementTextName(event->accessibleInterface()); + } break; + case QAccessible::Focus: { + setHtmlElementTextName(event->accessibleInterface()); + } break; + default: + qDebug() << "TODO: implement handlePageTabUpdate for event" << event->type(); + break; + } +} + +void QWasmAccessibility::handlePageTabListUpdate(QAccessibleEvent *event) +{ + switch (event->type()) { + case QAccessible::NameChanged: { + setHtmlElementTextName(event->accessibleInterface()); + } break; + case QAccessible::Focus: { + setHtmlElementTextName(event->accessibleInterface()); + } break; + default: + qDebug() << "TODO: implement handlePageTabUpdate for event" << event->type(); + break; + } +} + void QWasmAccessibility::notifyAccessibilityUpdate(QAccessibleEvent *event) { if (!m_accessibilityEnabled) @@ -442,6 +681,23 @@ void QWasmAccessibility::notifyAccessibilityUpdate(QAccessibleEvent *event) case QAccessible::ToolBar: case QAccessible::ButtonMenu: handleToolUpdate(event); + case QAccessible::RadioButton: + handleRadioButtonUpdate(event); + break; + case QAccessible::SpinBox: + handleSpinBoxUpdate(event); + break; + case QAccessible::Slider: + handleSliderUpdate(event); + break; + case QAccessible::PageTab: + handlePageTabUpdate(event); + break; + case QAccessible::PageTabList: + handlePageTabListUpdate(event); + break; + case QAccessible::ScrollBar: + handleScrollBarUpdate(event); break; default: qCDebug(lcQpaAccessibility) << "TODO: implement notifyAccessibilityUpdate for role" << iface->role(); @@ -462,3 +718,12 @@ void QWasmAccessibility::cleanup() { } + +void QWasmAccessibility::onHtmlEventReceived(emscripten::val event) +{ + static_cast<QWasmAccessibility *>(QWasmIntegration::get()->accessibility())->handleEventFromHtmlElement(event); +} + +EMSCRIPTEN_BINDINGS(qtButtonEvent) { + function("qtEventReceived", &QWasmAccessibility::onHtmlEventReceived); +} |