9#include <QtCore/private/qwasmsuspendresumecontrol_p.h>
10#include <QtGui/qguiapplication.h>
11#include <QtGui/qwindow.h>
15 QWasmAccessibility::enable();
18#if QT_CONFIG(accessibility)
20#include <QtGui/private/qaccessiblebridgeutils_p.h>
22Q_LOGGING_CATEGORY(lcQpaAccessibility,
"qt.qpa.accessibility")
25EM_JS(emscripten::EM_VAL, getActiveElement_js, (emscripten::EM_VAL undefHandle), {
26 var activeEl = document.activeElement;
30 }
else if (activeEl.shadowRoot) {
31 activeEl = activeEl.shadowRoot.activeElement;
33 return Emval.toHandle(activeEl);
38static emscripten::val getActiveElement()
40 return emscripten::val::take_ownership(
41 getActiveElement_js(emscripten::val::undefined().as_handle()));
45static void logElement(emscripten::val element)
47 emscripten::val::global(
"console").call<
void>(
"log", element);
63QWasmAccessibility::QWasmAccessibility()
65 if (qEnvironmentVariableIntValue(
"QT_WASM_ENABLE_ACCESSIBILITY") == 1)
66 enableAccessibility();
69 QWasmSuspendResumeControl *suspendResume = QWasmSuspendResumeControl::get();
71 m_eventHandlerIndex = suspendResume->registerEventHandler([
this](
const emscripten::val event){
72 this->handleEventFromHtmlElement(event);
76QWasmAccessibility::~QWasmAccessibility()
79 QWasmSuspendResumeControl *suspendResume = QWasmSuspendResumeControl::get();
80 suspendResume->removeEventHandler(m_eventHandlerIndex);
83QWasmAccessibility *QWasmAccessibility::instance()
85 QWasmIntegration *integration = QWasmIntegration::get();
86 return integration ?
static_cast<QWasmAccessibility *>(integration->accessibility()) :
nullptr;
89void QWasmAccessibility::addAccessibilityEnableButton(QWindow *window)
91 if (QWasmAccessibility *accessibility = instance(); accessibility && !accessibility->isActive())
92 accessibility->addEnableButton(window);
95void QWasmAccessibility::onShowWindow(QWindow *window)
97 if (QWasmAccessibility *accessibility = instance(); accessibility && accessibility->isActive())
98 accessibility->populateAccessibilityTree(window->accessibleRoot());
101void QWasmAccessibility::onRemoveWindow(QWindow *window)
103 if (QWasmAccessibility *accessibility = instance())
104 accessibility->removeWindow(window);
107bool QWasmAccessibility::isEnabled()
109 const QWasmAccessibility *accessibility = instance();
110 return accessibility && accessibility->isActive();
113void QWasmAccessibility::enable()
115 if (QWasmAccessibility *accessibility = instance(); accessibility && !accessibility->isActive())
116 accessibility->enableAccessibility();
119bool QWasmAccessibility::setFocusObject(QObject *object)
121 QWasmAccessibility *accessibility = instance();
122 return accessibility && accessibility->setFocusObjectImpl(object);
125void QWasmAccessibility::addEnableButton(QWindow *window)
127 emscripten::val container = getElementContainer(window);
128 if (container.isUndefined())
131 emscripten::val document = getDocument(container);
132 emscripten::val button = document.call<emscripten::val>(
"createElement", std::string(
"button"));
133 setProperty(button,
"innerText",
"Enable Screen Reader");
134 button[
"classList"].call<
void>(
"add", emscripten::val(
"hidden-visually-read-by-screen-reader"));
135 button.set(
"tabIndex", -1);
136 container.call<
void>(
"appendChild", button);
138 auto enableContext = std::make_tuple(button, std::make_unique<qstdweb::EventCallback>
139 (button, std::string(
"click"), [
this](emscripten::val) { enableAccessibility(); }));
140 m_enableButtons.insert(std::make_pair(window, std::move(enableContext)));
143void QWasmAccessibility::removeWindow(QWindow *window)
146 const auto it = m_enableButtons.find(window);
147 if (it != m_enableButtons.end()) {
149 auto [element, callback] = it->second;
151 element[
"parentElement"].call<
void>(
"removeChild", element);
152 m_enableButtons.erase(it);
155 const QWasmWindow *wasmWindow = QWasmWindow::fromWindow(window);
156 if (!isActive() || !wasmWindow)
159 const emscripten::val a11yContainer = wasmWindow->a11yContainer();
162 for (
auto it = m_elements.begin(); it != m_elements.end();) {
163 if (a11yContainer.call<
bool>(
"contains", it.value()))
164 it = m_elements.erase(it);
168 getElementContainer(window).call<
void>(
"replaceChildren");
169 getDescribedByContainer(window).call<
void>(
"replaceChildren");
173std::string QWasmAccessibility::logElementParentChain(emscripten::val element, QAccessibleInterface *iface, std::string tab)
175 if (element.isUndefined())
176 element = getHtmlElement(iface);
178 QAccessibleInterface *parentIface =
nullptr;
179 if (!element[
"parentElement"].isUndefined() &&
180 !element[
"parentElement"].isNull() &&
181 !element[
"parentElement"][
"qtA11yId"].isUndefined()) {
182 parentIface = QAccessible::accessibleInterface(
183 element[
"parentElement"][
"qtA11yId"].as<QAccessible::Id>());
186 emscripten::val parent = emscripten::val::undefined();
187 if (!element.isUndefined())
188 parent = element[
"parentElement"];
190 parent = emscripten::val::undefined();
192 if (!parent.isUndefined())
193 tab = logElementParentChain(parent, parentIface, tab);
195 QString outerHTML = QStringLiteral(
"No html");
196 if (!element.isUndefined())
197 outerHTML = QString::fromStdString(element[
"outerHTML"].as<std::string>()).left(40);
200 qCDebug(lcQpaAccessibility) << tab << outerHTML <<
"No Role" <<
"No parent role"
201 << element.isUndefined() << parent.isUndefined();
203 qCDebug(lcQpaAccessibility) << tab << outerHTML << iface->role()
204 << (iface->parent() ? iface->parent()->role() : QAccessible::NoRole)
205 << element.isUndefined() << parent.isUndefined();
210void QWasmAccessibility::enableAccessibility()
215 Q_ASSERT(!isActive());
217 for (
const auto& [key, value] : m_enableButtons) {
218 const auto &[element, callback] = value;
220 if (
auto wasmWindow = QWasmWindow::fromWindow(key))
221 wasmWindow->onAccessibilityEnable();
222 populateAccessibilityTree(key->accessibleRoot());
223 element[
"parentElement"].call<
void>(
"removeChild", element);
225 m_enableButtons.clear();
228bool QWasmAccessibility::setFocusObjectImpl(QObject *object)
230 auto iface = QAccessible::queryAccessibleInterface(object);
233 return setHtmlElementFocus(iface);
236bool QWasmAccessibility::isWindowNode(QAccessibleInterface *iface)
238 return (iface && !getWindow(iface->parent()) && getWindow(iface));
241emscripten::val QWasmAccessibility::getDescribedByContainer(QWindow *window)
243 const QWasmWindow *wasmWindow = QWasmWindow::fromWindow(window);
244 return wasmWindow ? wasmWindow->a11yDescribedByContainer() : emscripten::val::undefined();
247emscripten::val QWasmAccessibility::getDescribedByContainer(QAccessibleInterface *iface)
249 return getDescribedByContainer(getWindow(iface));
252emscripten::val QWasmAccessibility::getElementContainer(QWindow *window)
254 const QWasmWindow *wasmWindow = QWasmWindow::fromWindow(window);
255 return wasmWindow ? wasmWindow->a11yElementContainer() : emscripten::val::undefined();
258emscripten::val QWasmAccessibility::getElementContainer(QAccessibleInterface *iface)
265 if (!getWindow(iface))
266 return emscripten::val::undefined();
268 if (isWindowNode(iface))
269 return emscripten::val::undefined();
271 if (isWindowNode(iface->parent()))
272 return getElementContainer(getWindow(iface->parent()));
275 return getHtmlElement(iface->parent());
278QWindow *QWasmAccessibility::getWindow(QAccessibleInterface *iface)
283 QWindow *window = iface->window();
285 if (!window && iface->parent())
286 window = iface->parent()->window();
292bool QWasmAccessibility::isFocusInChildWindow(QAccessibleInterface *iface)
294 const QWindow *window = getWindow(iface);
295 const QWindow *focusWindow = QGuiApplication::focusWindow();
296 return window && focusWindow && focusWindow != window
297 && window->isAncestorOf(focusWindow, QWindow::ExcludeTransients);
300emscripten::val QWasmAccessibility::getDocument(
const emscripten::val &container)
302 if (container.isUndefined())
303 return emscripten::val::global(
"document");
304 return container[
"ownerDocument"];
307void QWasmAccessibility::setAttribute(emscripten::val element,
const std::string &attr,
308 const std::string &val)
311 element.call<
void>(
"setAttribute", attr, val);
313 element.call<
void>(
"removeAttribute", attr);
316void QWasmAccessibility::setAttribute(emscripten::val element,
const std::string &attr,
319 setAttribute(element, attr, std::string(val));
322void QWasmAccessibility::setAttribute(emscripten::val element,
const std::string &attr,
bool val)
325 element.call<
void>(
"setAttribute", attr, val);
327 element.call<
void>(
"removeAttribute", attr);
330void QWasmAccessibility::setProperty(emscripten::val element,
const std::string &property,
331 const std::string &val)
333 element.set(property, val);
336void QWasmAccessibility::setProperty(emscripten::val element,
const std::string &property,
const char *val)
338 setProperty(element, property, std::string(val));
341void QWasmAccessibility::setProperty(emscripten::val element,
const std::string &property,
bool val)
343 element.set(property, val);
346void QWasmAccessibility::setNamedAttribute(QAccessibleInterface *iface,
const std::string &attribute, QAccessible::Text text)
348 const emscripten::val element = getHtmlElement(iface);
349 setAttribute(element, attribute, iface->text(text).toStdString());
351void QWasmAccessibility::setNamedProperty(QAccessibleInterface *iface,
const std::string &property, QAccessible::Text text)
353 const emscripten::val element = getHtmlElement(iface);
354 setProperty(element, property, iface->text(text).toStdString());
357void QWasmAccessibility::addEventListener(QAccessibleInterface *iface, emscripten::val element,
const char *eventType)
359 element.set(
"qtA11yId", QAccessible::uniqueId(iface));
360 element.call<
void>(
"addEventListener", emscripten::val(eventType),
361 QWasmSuspendResumeControl::get()->jsEventHandlerAt(m_eventHandlerIndex),
365void QWasmAccessibility::sendEvent(QAccessibleInterface *iface, QAccessible::Event eventType)
367 if (iface->object()) {
368 QAccessibleEvent event(iface->object(), eventType);
369 handleUpdateByInterfaceRole(&event);
371 QAccessibleEvent event(iface, eventType);
372 handleUpdateByInterfaceRole(&event);
376emscripten::val QWasmAccessibility::createHtmlElement(QAccessibleInterface *iface)
381 emscripten::val container = getElementContainer(iface);
385 emscripten::val document = getDocument(container);
390 emscripten::val element = [
this, iface, document] {
392 emscripten::val element = emscripten::val::undefined();
394 switch (iface->role()) {
396 case QAccessible::Button: {
397 element = document.call<emscripten::val>(
"createElement", std::string(
"button"));
398 addEventListener(iface, element,
"click");
401 case QAccessible::Grouping:
402 case QAccessible::CheckBox: {
408 emscripten::val checkbox = emscripten::val::undefined();
409 if (iface->role() == QAccessible::CheckBox) {
410 checkbox = document.call<emscripten::val>(
"createElement", std::string(
"input"));
411 setAttribute(checkbox,
"type",
"checkbox");
414 setProperty(checkbox,
"checked", iface->state().checked);
415 setProperty(checkbox,
"indeterminate", iface->state().checkStateMixed);
416 addEventListener(iface, checkbox,
"change");
419 if (iface->childCount() > 0 || iface->role() == QAccessible::Grouping) {
420 auto label = document.call<emscripten::val>(
"createElement", std::string(
"span"));
422 const std::string id =
"lbid_" + std::to_string(QAccessible::uniqueId(iface));
423 setAttribute(label,
"id", id);
425 element = document.call<emscripten::val>(
"createElement", std::string(
"div"));
426 element.call<
void>(
"appendChild", label);
428 setAttribute(element,
"role",
"group");
429 setAttribute(element,
"aria-labelledby", id);
431 if (!checkbox.isUndefined()) {
432 element.call<
void>(
"appendChild", checkbox);
433 addEventListener(iface, checkbox,
"focus");
440 case QAccessible::Switch: {
441 element = document.call<emscripten::val>(
"createElement", std::string(
"button"));
442 setAttribute(element,
"type",
"button");
443 setAttribute(element,
"role",
"switch");
444 if (iface->state().checked)
445 setAttribute(element,
"aria-checked",
"true");
447 setAttribute(element,
"aria-checked",
"false");
448 addEventListener(iface, element,
"click");
451 case QAccessible::RadioButton: {
452 element = document.call<emscripten::val>(
"createElement", std::string(
"input"));
453 setAttribute(element,
"type",
"radio");
454 setProperty(element,
"checked", iface->state().checked);
457 if (QAccessibleInterface *parentInterface = iface->parent()) {
458 setProperty(element,
"name",
459 "qt-radio-group-" + std::to_string(QAccessible::uniqueId(parentInterface)));
461 addEventListener(iface, element,
"change");
464 case QAccessible::Dial: {
467 element = document.call<emscripten::val>(
"createElement", std::string(
"div"));
468 setAttribute(element,
"tabindex",
"0");
469 setAttribute(element,
"role",
"slider");
470 if (QAccessibleValueInterface *valueInterface = iface->valueInterface()) {
471 setAttribute(element,
"aria-valuemin",
472 valueInterface->minimumValue().toString().toStdString());
473 setAttribute(element,
"aria-valuemax",
474 valueInterface->maximumValue().toString().toStdString());
475 setAttribute(element,
"aria-valuenow",
476 valueInterface->currentValue().toString().toStdString());
481 case QAccessible::SpinBox: {
484 element = document.call<emscripten::val>(
"createElement", std::string(
"div"));
485 setAttribute(element,
"tabindex",
"0");
486 setAttribute(element,
"role",
"spinbutton");
487 if (QAccessibleValueInterface *valueInterface = iface->valueInterface()) {
488 setAttribute(element,
"aria-valuemin",
489 valueInterface->minimumValue().toString().toStdString());
490 setAttribute(element,
"aria-valuemax",
491 valueInterface->maximumValue().toString().toStdString());
492 setAttribute(element,
"aria-valuenow",
493 valueInterface->currentValue().toString().toStdString());
496 setAttribute(element,
"aria-valuetext",
497 iface->text(QAccessible::Value).toStdString());
500 case QAccessible::Slider: {
503 element = document.call<emscripten::val>(
"createElement", std::string(
"div"));
504 setAttribute(element,
"tabindex",
"0");
505 setAttribute(element,
"role",
"slider");
506 if (QAccessibleValueInterface *valueInterface = iface->valueInterface()) {
507 setAttribute(element,
"aria-valuemin",
508 valueInterface->minimumValue().toString().toStdString());
509 setAttribute(element,
"aria-valuemax",
510 valueInterface->maximumValue().toString().toStdString());
511 setAttribute(element,
"aria-valuenow",
512 valueInterface->currentValue().toString().toStdString());
514 setHtmlElementOrientation(element, iface);
517 case QAccessible::PageTabList:{
518 element = document.call<emscripten::val>(
"createElement", std::string(
"div"));
519 setAttribute(element,
"role",
"tablist");
520 setHtmlElementOrientation(element, iface);
522 m_elements[QAccessible::uniqueId(iface)] = element;
524 for (
int i = 0; i < iface->childCount(); ++i)
525 createHtmlElement(iface->child(i));
529 case QAccessible::PageTab:{
530 const QString text = iface->text(QAccessible::Name);
531 element = document.call<emscripten::val>(
"createElement", std::string(
"button"));
532 setAttribute(element,
"role",
"tab");
533 setAttribute(element,
"title", text.toStdString());
534 addEventListener(iface, element,
"click");
537 case QAccessible::ScrollBar: {
540 element = document.call<emscripten::val>(
"createElement", std::string(
"div"));
541 setAttribute(element,
"tabindex",
"0");
542 setAttribute(element,
"role",
"scrollbar");
543 if (QAccessibleValueInterface *valueInterface = iface->valueInterface()) {
544 setAttribute(element,
"aria-valuemin",
545 valueInterface->minimumValue().toString().toStdString());
546 setAttribute(element,
"aria-valuemax",
547 valueInterface->maximumValue().toString().toStdString());
548 setAttribute(element,
"aria-valuenow",
549 valueInterface->currentValue().toString().toStdString());
551 setHtmlElementOrientation(element, iface);
552 addEventListener(iface, element,
"change");
555 case QAccessible::StaticText: {
556 element = document.call<emscripten::val>(
"createElement", std::string(
"div"));
558 case QAccessible::AlertMessage:
559 case QAccessible::Dialog: {
560 element = document.call<emscripten::val>(
"createElement", std::string(
"dialog"));
561 setAttribute(element,
"open",
true);
563 case QAccessible::ToolBar:{
564 const QString text = iface->text(QAccessible::Name);
565 element = document.call<emscripten::val>(
"createElement", std::string(
"div"));
566 setAttribute(element,
"role",
"toolbar");
567 setAttribute(element,
"title", text.toStdString());
568 setHtmlElementOrientation(element, iface);
569 addEventListener(iface, element,
"click");
571 case QAccessible::MenuItem:
572 case QAccessible::ButtonDropDown:
573 case QAccessible::ButtonMenu: {
574 const QString text = iface->text(QAccessible::Name);
575 element = document.call<emscripten::val>(
"createElement", std::string(
"button"));
576 setAttribute(element,
"role",
"menuitem");
577 setAttribute(element,
"title", text.toStdString());
578 addEventListener(iface, element,
"click");
579 element[
"classList"].call<
void>(
"add", emscripten::val(
"menu-item"));
581 case QAccessible::MenuBar:
582 case QAccessible::PopupMenu: {
583 const QString text = iface->text(QAccessible::Name);
584 element = document.call<emscripten::val>(
"createElement", std::string(
"div"));
585 setAttribute(element,
"role",
586 iface->role() == QAccessible::PopupMenu ?
"menu" :
"menubar");
587 setAttribute(element,
"tabindex",
"-1");
588 setAttribute(element,
"title", text.toStdString());
589 setHtmlElementOrientation(element, iface);
590 m_elements[QAccessible::uniqueId(iface)] = element;
594 for (
int i = 0; i < iface->childCount(); ++i)
595 createHtmlElement(iface->child(i));
597 case QAccessible::EditableText: {
598 element = document.call<emscripten::val>(
"createElement", std::string(
"input"));
599 setAttribute(element,
"type",
"text");
600 setAttribute(element,
"contenteditable",
"true");
601 setAttribute(element,
"readonly", iface->state().readOnly);
602 setAttribute(element,
"autocorrect",
"off");
603 setProperty(element,
"inputMode",
"text");
605 case QAccessible::List: {
606 element = document.call<emscripten::val>(
"createElement", std::string(
"div"));
607 setAttribute(element,
"tabindex",
"0");
608 setAttribute(element,
"role",
"list");
610 case QAccessible::ListItem: {
611 element = document.call<emscripten::val>(
"createElement", std::string(
"div"));
612 setAttribute(element,
"tabindex",
"0");
613 setAttribute(element,
"role",
"listitem");
615 case QAccessible::ProgressBar: {
616 element = document.call<emscripten::val>(
"createElement", std::string(
"div"));
617 setAttribute(element,
"tabindex",
"0");
618 setAttribute(element,
"role",
"progressbar");
619 setAttribute(element,
"aria-live",
"polite");
620 if (
auto valueInterface = iface->valueInterface()) {
621 const auto name = iface->text(QAccessible::Name).toStdString();
622 const auto min = valueInterface->minimumValue().toInt();
623 const auto max = valueInterface->maximumValue().toInt();
624 const auto cur = valueInterface->currentValue().toInt();
627 const auto totalSteps = qint64(max) - min;
628 const auto progress = (totalSteps == 0) ? 0 :
static_cast<
int>((qint64(cur) - min) * 100.0 / totalSteps);
631 setAttribute(element,
"aria-valuenow",
"0");
633 setAttribute(element,
"aria-valuenow",
"100");
635 setAttribute(element,
"aria-valuenow", std::to_string(progress));
636 setAttribute(element,
"aria-valuemin",
"0");
637 setAttribute(element,
"aria-valuemax",
"100");
638 setAttribute(element,
"aria-label", name);
642 qCDebug(lcQpaAccessibility) <<
"TODO: createHtmlElement() handle" << iface->role();
643 element = document.call<emscripten::val>(
"createElement", std::string(
"div"));
646 addEventListener(iface, element,
"focus");
651 m_elements[QAccessible::uniqueId(iface)] = element;
653 setHtmlElementGeometry(iface);
654 setHtmlElementDisabled(iface);
655 setHtmlElementVisibility(iface, !iface->state().invisible);
656 handleIdentifierUpdate(iface);
657 handleDescriptionChanged(iface);
658 sendEvent(iface, QAccessible::NameChanged);
662 element.set(
"tabIndex", -1);
666 for (
int i = 0; i < iface->childCount(); ++i) {
667 if (!getHtmlElement(iface->child(i)).isUndefined())
668 linkToParent(iface->child(i));
674void QWasmAccessibility::destroyHtmlElement(QAccessibleInterface *iface)
677 qCDebug(lcQpaAccessibility) <<
"TODO destroyHtmlElement";
680emscripten::val QWasmAccessibility::getHtmlElement(QAccessibleInterface *iface)
683 return emscripten::val::undefined();
684 return m_elements.value(QAccessible::uniqueId(iface), emscripten::val::undefined());
687void QWasmAccessibility::repairLinks(QAccessibleInterface *iface)
692 for (
int i = 0; i < iface->childCount(); ++i) {
693 const auto elementI = getHtmlElement(iface->child(i));
694 const auto containerI = getElementContainer(iface->child(i));
696 if (!elementI.isUndefined() &&
697 !containerI.isUndefined() &&
698 !elementI[
"parentElement"].isUndefined() &&
699 !elementI[
"parentElement"].isNull() &&
700 elementI[
"parentElement"] != containerI) {
706 for (
int i = 0; i < iface->childCount(); ++i) {
707 const auto elementI = getHtmlElement(iface->child(i));
708 const auto containerI = getElementContainer(iface->child(i));
709 if (!elementI.isUndefined() && !containerI.isUndefined())
710 containerI.call<
void>(
"appendChild", elementI);
715void QWasmAccessibility::linkToParent(QAccessibleInterface *iface)
717 emscripten::val element = getHtmlElement(iface);
718 emscripten::val container = getElementContainer(iface);
720 if (container.isUndefined() || element.isUndefined())
724 const auto activeElementBefore = getActiveElement();
726 repairLinks(iface->parent());
728 emscripten::val next = emscripten::val::undefined();
729 const int thisIndex = iface->parent()->indexOfChild(iface);
730 if (thisIndex >= 0) {
731 Q_ASSERT(thisIndex < iface->parent()->childCount());
732 for (
int i = thisIndex + 1; i < iface->parent()->childCount(); ++i) {
733 const auto elementI = getHtmlElement(iface->parent()->child(i));
734 if (!elementI.isUndefined() &&
735 elementI[
"parentElement"] == container) {
740 if (next.isUndefined())
741 container.call<
void>(
"appendChild", element);
743 container.call<
void>(
"insertBefore", element, next);
745 const auto activeElementAfter = getActiveElement();
746 if (activeElementBefore != activeElementAfter) {
747 if (!activeElementBefore.isUndefined() && !activeElementBefore.isNull())
748 activeElementBefore.call<
void>(
"focus");
752void QWasmAccessibility::setHtmlElementVisibility(QAccessibleInterface *iface,
bool visible)
754 emscripten::val element = getHtmlElement(iface);
755 setAttribute(element,
"inert", !visible);
758void QWasmAccessibility::setHtmlElementGeometry(QAccessibleInterface *iface)
760 const emscripten::val element = getHtmlElement(iface);
762 QRect windowGeometry = iface->rect();
763 if (iface->parent()) {
767 const QRect parentRect = iface->parent()->rect();
768 const QRect thisRect = iface->rect();
769 const QRect result(thisRect.topLeft() - parentRect.topLeft(), thisRect.size());
770 windowGeometry = result;
774 Q_ASSERT(!getWindow(iface));
776 setHtmlElementGeometry(element, windowGeometry);
779void QWasmAccessibility::setHtmlElementGeometry(emscripten::val element, QRect geometry)
783 emscripten::val style = element[
"style"];
784 style.set(
"position", std::string(
"absolute"));
785 style.set(
"z-index", std::string(
"-1"));
787 style.set(
"left", std::to_string(geometry.x()) +
"px");
788 style.set(
"top", std::to_string(geometry.y()) +
"px");
789 style.set(
"width", std::to_string(geometry.width()) +
"px");
790 style.set(
"height", std::to_string(geometry.height()) +
"px");
793bool QWasmAccessibility::setHtmlElementFocus(QAccessibleInterface *iface)
795 m_focusId = QAccessible::uniqueId(iface);
796 const auto element = getHtmlElement(iface);
798 if (element.isUndefined())
802 if (element == m_isSettingFocusIface)
805 m_isFollowingQtFocus =
true;
806 element.call<
void>(
"focus");
807 m_isFollowingQtFocus =
false;
810 if (lcQpaAccessibility().isDebugEnabled()) {
811 const auto activeElementAfter = getActiveElement();
813 if (element != activeElementAfter) {
814 qCDebug(lcQpaAccessibility) <<
"Focus failed" << iface;
816 logElement(activeElementAfter);
817 logElementParentChain(element, iface);
822 return element == getActiveElement();
825void QWasmAccessibility::setHtmlElementDisabled(QAccessibleInterface *iface)
827 auto element = getHtmlElement(iface);
828 setAttribute(element,
"aria-disabled", iface->state().disabled);
831void QWasmAccessibility::setHtmlElementOrientation(emscripten::val element, QAccessibleInterface *iface)
834 if (QAccessibleAttributesInterface *attributesIface = iface->attributesInterface()) {
835 const QVariant orientationVariant =
836 attributesIface->attributeValue(QAccessible::Attribute::Orientation);
837 if (orientationVariant.isValid()) {
838 Q_ASSERT(orientationVariant.canConvert<Qt::Orientation>());
839 const Qt::Orientation orientation = orientationVariant.value<Qt::Orientation>();
840 const std::string value = orientation == Qt::Horizontal ?
"horizontal" :
"vertical";
841 setAttribute(element,
"aria-orientation", value);
846void QWasmAccessibility::handleListItemUpdate(QAccessibleEvent *event)
848 auto iface = event->accessibleInterface();
850 switch (event->type()) {
851 case QAccessible::NameChanged: {
853 setNamedProperty(iface,
"innerText", QAccessible::Name);
856 qCDebug(lcQpaAccessibility) <<
"TODO: implement handleListItemUpdate for event" << event->type();
861void QWasmAccessibility::handleDialUpdate(QAccessibleEvent *event)
863 switch (event->type()) {
864 case QAccessible::ObjectCreated:
865 case QAccessible::StateChanged: {
867 case QAccessible::Focus:
868 case QAccessible::NameChanged: {
869 setNamedAttribute(event->accessibleInterface(),
"aria-label", QAccessible::Name);
871 case QAccessible::ValueChanged: {
872 QAccessibleInterface *accessible = event->accessibleInterface();
873 if (QAccessibleValueInterface *valueInterface = accessible->valueInterface()) {
874 setAttribute(getHtmlElement(accessible),
"aria-valuenow",
875 valueInterface->currentValue().toString().toStdString());
879 qCDebug(lcQpaAccessibility) <<
"TODO: implement handleDialUpdate for event" << event->type();
884void QWasmAccessibility::handleStaticTextUpdate(QAccessibleEvent *event)
886 switch (event->type()) {
887 case QAccessible::NameChanged: {
889 setNamedProperty(event->accessibleInterface(),
"innerText", QAccessible::Name);
892 qCDebug(lcQpaAccessibility) <<
"TODO: implement handleStaticTextUpdate for event" << event->type();
897void QWasmAccessibility::handleLineEditUpdate(QAccessibleEvent *event)
899 switch (event->type()) {
900 case QAccessible::StateChanged: {
901 auto iface = event->accessibleInterface();
902 auto element = getHtmlElement(iface);
903 setAttribute(element,
"readonly", iface->state().readOnly);
904 if (iface->state().passwordEdit)
905 setProperty(element,
"type",
"password");
907 setProperty(element,
"type",
"text");
909 case QAccessible::ValueChanged:
910 case QAccessible::NameChanged: {
911 setNamedProperty(event->accessibleInterface(),
"value", QAccessible::Value);
913 case QAccessible::ObjectShow:
914 case QAccessible::Focus: {
915 auto iface = event->accessibleInterface();
916 auto element = getHtmlElement(iface);
917 if (!element.isUndefined()) {
918 setAttribute(element,
"readonly", iface->state().readOnly);
919 if (iface->state().passwordEdit)
920 setProperty(element,
"type",
"password");
922 setProperty(element,
"type",
"text");
924 setNamedProperty(event->accessibleInterface(),
"value", QAccessible::Value);
926 case QAccessible::TextRemoved:
927 case QAccessible::TextInserted:
928 case QAccessible::TextUpdated: {
929 setNamedProperty(event->accessibleInterface(),
"value", QAccessible::Value);
931 case QAccessible::TextCaretMoved: {
933 setNamedProperty(event->accessibleInterface(),
"value", QAccessible::Value);
936 qCDebug(lcQpaAccessibility) <<
"TODO: implement handleLineEditUpdate for event" << event->type();
941void QWasmAccessibility::handleEventFromHtmlElement(
const emscripten::val event)
943 const emscripten::val target = event[
"target"];
944 if (target.isNull() || target.isUndefined() || target[
"qtA11yId"].isUndefined())
948 QAccessibleInterface *iface =
949 QAccessible::accessibleInterface(target[
"qtA11yId"].as<QAccessible::Id>());
950 if (!iface || !iface->isValid())
953 const auto eventType = QString::fromStdString(event[
"type"].as<std::string>());
954 const auto& actionNames = QAccessibleBridgeUtils::effectiveActionNames(iface);
955 bool handled =
false;
957 if (eventType ==
"focus") {
960 if (m_isFollowingQtFocus)
962 m_isSettingFocusIface = event[
"target"];
963 if (actionNames.contains(QAccessibleActionInterface::setFocusAction()))
964 iface->actionInterface()->doAction(QAccessibleActionInterface::setFocusAction());
965 m_isSettingFocusIface = emscripten::val::undefined();
966 }
else if (eventType ==
"click") {
968 if (actionNames.contains(QAccessibleActionInterface::pressAction()))
969 iface->actionInterface()->doAction(QAccessibleActionInterface::pressAction());
970 else if (actionNames.contains(QAccessibleActionInterface::showMenuAction()))
971 iface->actionInterface()->doAction(QAccessibleActionInterface::showMenuAction());
972 }
else if (eventType ==
"change") {
976 if (actionNames.contains(QAccessibleActionInterface::pressAction()))
977 iface->actionInterface()->doAction(QAccessibleActionInterface::pressAction());
978 else if (actionNames.contains(QAccessibleActionInterface::toggleAction()))
979 iface->actionInterface()->doAction(QAccessibleActionInterface::toggleAction());
981 qCDebug(lcQpaAccessibility) <<
"Unknown event" << eventType;
985 event.call<
void>(
"preventDefault");
986 event.call<
void>(
"stopPropagation");
990void QWasmAccessibility::handleButtonUpdate(QAccessibleEvent *event)
992 switch (event->type()) {
993 case QAccessible::Focus:
994 case QAccessible::NameChanged: {
995 setNamedAttribute(event->accessibleInterface(),
"aria-label", QAccessible::Name);
998 qCDebug(lcQpaAccessibility) <<
"TODO: implement handleCheckBoxUpdate for event" << event->type();
1003void QWasmAccessibility::handleCheckBoxUpdate(QAccessibleEvent *event)
1005 switch (event->type()) {
1006 case QAccessible::Focus:
1007 case QAccessible::NameChanged: {
1008 setNamedAttribute(event->accessibleInterface(),
"aria-label", QAccessible::Name);
1010 case QAccessible::StateChanged: {
1011 QAccessibleInterface *accessible = event->accessibleInterface();
1012 const emscripten::val element = getHtmlElement(accessible);
1013 setProperty(element,
"checked", accessible->state().checked);
1014 setProperty(element,
"indeterminate", accessible->state().checkStateMixed);
1017 qCDebug(lcQpaAccessibility) <<
"TODO: implement handleCheckBoxUpdate for event" << event->type();
1022void QWasmAccessibility::handleGroupBoxUpdate(QAccessibleEvent *event)
1024 QAccessibleInterface *iface = event->accessibleInterface();
1026 emscripten::val parent = getHtmlElement(iface);
1027 emscripten::val label = parent[
"children"][0];
1028 emscripten::val checkbox = emscripten::val::undefined();
1029 if (iface->role() == QAccessible::CheckBox)
1030 checkbox = parent[
"children"][1];
1032 switch (event->type()) {
1033 case QAccessible::Focus:
1034 case QAccessible::NameChanged: {
1035 setProperty(label,
"innerText", iface->text(QAccessible::Name).toStdString());
1036 if (!checkbox.isUndefined())
1037 setAttribute(checkbox,
"aria-label", iface->text(QAccessible::Name).toStdString());
1039 case QAccessible::StateChanged: {
1040 if (!checkbox.isUndefined()) {
1041 setProperty(checkbox,
"checked", iface->state().checked);
1042 setProperty(checkbox,
"indeterminate", iface->state().checkStateMixed);
1046 qCDebug(lcQpaAccessibility) <<
"TODO: implement handleCheckBoxUpdate for event" << event->type();
1051void QWasmAccessibility::handleSwitchUpdate(QAccessibleEvent *event)
1053 switch (event->type()) {
1054 case QAccessible::Focus:
1055 case QAccessible::NameChanged: {
1057 setNamedAttribute(event->accessibleInterface(),
"aria-label", QAccessible::Name);
1059 case QAccessible::StateChanged: {
1060 QAccessibleInterface *accessible = event->accessibleInterface();
1061 const emscripten::val element = getHtmlElement(accessible);
1062 if (accessible->state().checked)
1063 setAttribute(element,
"aria-checked",
"true");
1065 setAttribute(element,
"aria-checked",
"false");
1068 qCDebug(lcQpaAccessibility) <<
"TODO: implement handleSwitchUpdate for event" << event->type();
1073void QWasmAccessibility::handleToolUpdate(QAccessibleEvent *event)
1075 QAccessibleInterface *iface = event->accessibleInterface();
1076 QString text = iface->text(QAccessible::Name);
1077 QString desc = iface->text(QAccessible::Description);
1078 switch (event->type()) {
1079 case QAccessible::NameChanged:
1080 case QAccessible::StateChanged:{
1081 const emscripten::val element = getHtmlElement(iface);
1082 setAttribute(element,
"title", text.toStdString());
1085 qCDebug(lcQpaAccessibility) <<
"TODO: implement handleToolUpdate for event" << event->type();
1089void QWasmAccessibility::handleMenuUpdate(QAccessibleEvent *event)
1091 QAccessibleInterface *iface = event->accessibleInterface();
1092 QString text = iface->text(QAccessible::Name);
1093 QString desc = iface->text(QAccessible::Description);
1094 switch (event->type()) {
1095 case QAccessible::Focus:
1096 case QAccessible::NameChanged:
1097 case QAccessible::MenuStart :
1098 case QAccessible::StateChanged:{
1099 const emscripten::val element = getHtmlElement(iface);
1100 setAttribute(element,
"title", text.toStdString());
1102 case QAccessible::PopupMenuStart: {
1103 if (iface->childCount() > 0)
1104 setHtmlElementFocus(iface->child(0));
1107 qCDebug(lcQpaAccessibility) <<
"TODO: implement handleMenuUpdate for event" << event->type();
1111void QWasmAccessibility::handleDialogUpdate(QAccessibleEvent *event) {
1113 switch (event->type()) {
1114 case QAccessible::ObjectShow:
1116 if (QAccessibleInterface *focusInterface = QAccessible::accessibleInterface(m_focusId))
1117 setHtmlElementFocus(focusInterface);
1120 case QAccessible::NameChanged:
1121 case QAccessible::Focus:
1122 case QAccessible::DialogStart:
1123 case QAccessible::StateChanged: {
1124 setNamedAttribute(event->accessibleInterface(),
"aria-label", QAccessible::Name);
1127 qCDebug(lcQpaAccessibility) <<
"TODO: implement handleLineEditUpdate for event" << event->type();
1132void QWasmAccessibility::populateAccessibilityTree(QAccessibleInterface *iface)
1139 const QWindow *window1 = getWindow(iface);
1140 const QWindow *window0 = (iface->parent()) ? getWindow(iface->parent()) :
nullptr;
1142 if (window1 && window0 == window1) {
1144 bool exists = !getHtmlElement(iface).isUndefined();
1146 exists = !createHtmlElement(iface).isUndefined();
1149 linkToParent(iface);
1150 setHtmlElementVisibility(iface, !iface->state().invisible);
1151 setHtmlElementGeometry(iface);
1152 setHtmlElementDisabled(iface);
1153 handleIdentifierUpdate(iface);
1154 handleDescriptionChanged(iface);
1155 sendEvent(iface, QAccessible::NameChanged);
1158 for (
int i = 0; i < iface->childCount(); ++i)
1159 populateAccessibilityTree(iface->child(i));
1162void QWasmAccessibility::handleRadioButtonUpdate(QAccessibleEvent *event)
1164 switch (event->type()) {
1165 case QAccessible::Focus:
1166 case QAccessible::NameChanged: {
1167 setNamedAttribute(event->accessibleInterface(),
"aria-label", QAccessible::Name);
1169 case QAccessible::StateChanged: {
1170 QAccessibleInterface *accessible = event->accessibleInterface();
1171 const emscripten::val element = getHtmlElement(accessible);
1172 setProperty(element,
"checked", accessible->state().checked);
1175 qCDebug(lcQpaAccessibility) <<
"TODO: implement handleRadioButtonUpdate for event" << event->type();
1180void QWasmAccessibility::handleSpinBoxUpdate(QAccessibleEvent *event)
1182 switch (event->type()) {
1183 case QAccessible::ObjectCreated:
1184 case QAccessible::StateChanged: {
1186 case QAccessible::Focus:
1187 case QAccessible::NameChanged: {
1188 setNamedAttribute(event->accessibleInterface(),
"aria-label", QAccessible::Name);
1190 case QAccessible::ValueChanged: {
1191 QAccessibleInterface *accessible = event->accessibleInterface();
1192 if (QAccessibleValueInterface *valueInterface = accessible->valueInterface()) {
1193 setAttribute(getHtmlElement(accessible),
"aria-valuenow",
1194 valueInterface->currentValue().toString().toStdString());
1196 setNamedAttribute(accessible,
"aria-valuetext", QAccessible::Value);
1199 qCDebug(lcQpaAccessibility) <<
"TODO: implement handleSpinBoxUpdate for event" << event->type();
1204void QWasmAccessibility::handleSliderUpdate(QAccessibleEvent *event)
1206 switch (event->type()) {
1207 case QAccessible::ObjectCreated:
1208 case QAccessible::StateChanged: {
1210 case QAccessible::Focus:
1211 case QAccessible::NameChanged: {
1212 setNamedAttribute(event->accessibleInterface(),
"aria-label", QAccessible::Name);
1214 case QAccessible::ValueChanged: {
1215 QAccessibleInterface *accessible = event->accessibleInterface();
1216 if (QAccessibleValueInterface *valueInterface = accessible->valueInterface()) {
1217 setAttribute(getHtmlElement(accessible),
"aria-valuenow",
1218 valueInterface->currentValue().toString().toStdString());
1222 qCDebug(lcQpaAccessibility) <<
"TODO: implement handleSliderUpdate for event" << event->type();
1227void QWasmAccessibility::handleScrollBarUpdate(QAccessibleEvent *event)
1229 switch (event->type()) {
1230 case QAccessible::Focus:
1231 case QAccessible::NameChanged: {
1232 setNamedAttribute(event->accessibleInterface(),
"aria-label", QAccessible::Name);
1234 case QAccessible::ValueChanged: {
1235 QAccessibleInterface *accessible = event->accessibleInterface();
1236 if (QAccessibleValueInterface *valueInterface = accessible->valueInterface()) {
1237 setAttribute(getHtmlElement(accessible),
"aria-valuenow",
1238 valueInterface->currentValue().toString().toStdString());
1242 qCDebug(lcQpaAccessibility) <<
"TODO: implement handleScrollBarUpdate for event" << event->type();
1247void QWasmAccessibility::handlePageTabUpdate(QAccessibleEvent *event)
1249 switch (event->type()) {
1250 case QAccessible::NameChanged: {
1251 setNamedAttribute(event->accessibleInterface(),
"aria-label", QAccessible::Name);
1253 case QAccessible::Focus: {
1254 setNamedAttribute(event->accessibleInterface(),
"aria-label", QAccessible::Name);
1257 qCDebug(lcQpaAccessibility) <<
"TODO: implement handlePageTabUpdate for event" << event->type();
1262void QWasmAccessibility::handlePageTabListUpdate(QAccessibleEvent *event)
1264 switch (event->type()) {
1265 case QAccessible::NameChanged: {
1266 setNamedAttribute(event->accessibleInterface(),
"aria-label", QAccessible::Name);
1268 case QAccessible::Focus: {
1269 setNamedAttribute(event->accessibleInterface(),
"aria-label", QAccessible::Name);
1272 qCDebug(lcQpaAccessibility) <<
"TODO: implement handlePageTabListUpdate for event" << event->type();
1277void QWasmAccessibility::handleIdentifierUpdate(QAccessibleInterface *iface)
1281 const emscripten::val element = getHtmlElement(iface);
1283 QString id = iface->text(QAccessible::Identifier).replace(
" ",
"_");
1285 id = QStringLiteral(
"qt-a11y-") + QString::number(QAccessible::uniqueId(iface));
1286 setAttribute(element,
"id", id.toStdString());
1289void QWasmAccessibility::handleDescriptionChanged(QAccessibleInterface *iface)
1293 const auto desc = iface->text(QAccessible::Description).toStdString();
1294 auto element = getHtmlElement(iface);
1295 auto container = getDescribedByContainer(iface);
1296 if (element.isUndefined() || container.isUndefined())
1299 auto describedBy = element[
"qtA11yDescribedBy"];
1301 if (!describedBy.isUndefined())
1302 describedBy.call<
void>(
"remove");
1303 element.set(
"qtA11yDescribedBy", emscripten::val::undefined());
1304 setAttribute(element,
"aria-describedby",
"");
1306 const std::string id =
"dbid_" + std::to_string(QAccessible::uniqueId(iface));
1307 if (describedBy.isUndefined()) {
1308 describedBy = getDocument(container).call<emscripten::val>(
"createElement",
1310 container.call<
void>(
"appendChild", describedBy);
1311 element.set(
"qtA11yDescribedBy", describedBy);
1313 setAttribute(describedBy,
"id", id);
1314 setAttribute(describedBy,
"inert",
true);
1315 setAttribute(element,
"aria-describedby", id);
1316 setProperty(describedBy,
"innerText", desc);
1320void QWasmAccessibility::handleAnnouncement(QAccessibleInterface *iface,
1321 QAccessibleAnnouncementEvent *announcementEvent)
1323 emscripten::val element = getHtmlElement(iface);
1324 if (element[
"ariaNotify"].isUndefined())
1327 const std::string message = announcementEvent->message().toStdString();
1328 const std::string prio(announcementEvent->politeness()
1329 == QAccessible::AnnouncementPoliteness::Assertive
1332 emscripten::val options = emscripten::val::object();
1333 options.set(
"priority", prio);
1334 element.call<
void>(
"ariaNotify", message, options);
1337void QWasmAccessibility::handleProgressBarUpdate(QAccessibleEvent *event)
1339 auto iface = event->accessibleInterface();
1340 auto valueInterface = iface->valueInterface();
1341 auto element = getHtmlElement(iface);
1343 switch (event->type()) {
1344 case QAccessible::Focus:
1345 case QAccessible::NameChanged: {
1346 const auto name = iface->text(QAccessible::Name).toStdString();
1347 setAttribute(element,
"aria-label", name);
1349 case QAccessible::ValueChanged: {
1350 if (valueInterface) {
1351 const auto min = valueInterface->minimumValue().toInt();
1352 const auto max = valueInterface->maximumValue().toInt();
1353 const auto cur = valueInterface->currentValue().toInt();
1356 const auto totalSteps = qint64(max) - min;
1357 const auto progress = (totalSteps == 0) ? 0 :
static_cast<
int>((qint64(cur) - min) * 100.0 / totalSteps);
1360 setAttribute(element,
"aria-valuenow",
"0");
1361 else if (cur >= max)
1362 setAttribute(element,
"aria-valuenow",
"100");
1364 setAttribute(element,
"aria-valuenow", std::to_string(progress));
1372void QWasmAccessibility::createObject(QAccessibleInterface *iface)
1374 if (getHtmlElement(iface).isUndefined())
1375 createHtmlElement(iface);
1378void QWasmAccessibility::removeObject(QAccessible::Id id)
1383 const auto it = m_elements.find(id);
1384 if (it == m_elements.end())
1387 const emscripten::val element = it.value();
1388 if (!element[
"qtA11yDescribedBy"].isUndefined())
1389 element[
"qtA11yDescribedBy"].call<
void>(
"remove");
1390 element.call<
void>(
"remove");
1391 m_elements.erase(it);
1394void QWasmAccessibility::unlinkParentForChildren(QAccessibleInterface *iface)
1396 auto element = getHtmlElement(iface);
1397 if (!element.isUndefined()) {
1398 auto oldContainer = element[
"parentElement"];
1399 auto newContainer = getElementContainer(iface);
1400 if (!oldContainer.isUndefined() &&
1401 !oldContainer.isNull() &&
1402 oldContainer != newContainer) {
1403 oldContainer.call<
void>(
"removeChild", element);
1406 for (
int i = 0; i < iface->childCount(); ++i)
1407 unlinkParentForChildren(iface->child(i));
1410void QWasmAccessibility::relinkParentForChildren(QAccessibleInterface *iface)
1412 auto element = getHtmlElement(iface);
1413 if (!element.isUndefined()) {
1414 if (element[
"parentElement"].isUndefined() ||
1415 element[
"parentElement"].isNull()) {
1416 linkToParent(iface);
1419 for (
int i = 0; i < iface->childCount(); ++i)
1420 relinkParentForChildren(iface->child(i));
1423void QWasmAccessibility::notifyAccessibilityUpdate(QAccessibleEvent *event)
1425 if (handleUpdateByEventType(event))
1426 handleUpdateByInterfaceRole(event);
1429bool QWasmAccessibility::handleUpdateByEventType(QAccessibleEvent *event)
1434 QAccessibleInterface *iface = event->accessibleInterface();
1436 qWarning() <<
"handleUpdateByEventType with null a11y interface" << event->type() << event->object();
1441 switch (event->type()) {
1442 case QAccessible::ObjectCreated:
1447 case QAccessible::ObjectDestroyed:
1449 removeObject(event->uniqueId());
1452 case QAccessible::ObjectShow:
1453 createObject(iface);
1456 case QAccessible::ParentChanged:
1457 unlinkParentForChildren(iface);
1458 relinkParentForChildren(iface);
1467 if (event->type() == QAccessible::Focus)
1468 m_focusId = event->uniqueId();
1470 if (getHtmlElement(iface).isUndefined())
1475 switch (event->type()) {
1476 case QAccessible::Announcement:
1477 handleAnnouncement(iface,
static_cast<QAccessibleAnnouncementEvent *>(event));
1480 case QAccessible::StateChanged: {
1481 QAccessibleStateChangeEvent *stateChangeEvent = (QAccessibleStateChangeEvent *)event;
1482 if (stateChangeEvent->changedStates().disabled)
1483 setHtmlElementDisabled(iface);
1486 case QAccessible::DescriptionChanged:
1487 handleDescriptionChanged(iface);
1490 case QAccessible::Focus:
1493 setHtmlElementGeometry(iface);
1498 if (!isFocusInChildWindow(iface))
1499 setHtmlElementFocus(iface);
1502 case QAccessible::IdentifierChanged:
1503 handleIdentifierUpdate(iface);
1506 case QAccessible::ObjectShow:
1507 linkToParent(iface);
1508 setHtmlElementVisibility(iface,
true);
1511 setHtmlElementGeometry(iface);
1512 sendEvent(iface, QAccessible::NameChanged);
1516 if (QAccessible::uniqueId(iface) == m_focusId)
1517 setHtmlElementFocus(iface);
1520 case QAccessible::ObjectHide:
1522 setHtmlElementVisibility(iface,
false);
1525 case QAccessible::LocationChanged:
1526 setHtmlElementGeometry(iface);
1537void QWasmAccessibility::handleUpdateByInterfaceRole(QAccessibleEvent *event)
1542 QAccessibleInterface *iface = event->accessibleInterface();
1544 qWarning() <<
"handleUpdateByInterfaceRole with null a11y interface" << event->type() << event->object();
1550 switch (iface->role()) {
1551 case QAccessible::List:
1553 case QAccessible::ListItem:
1554 handleListItemUpdate(event);
1556 case QAccessible::StaticText:
1557 handleStaticTextUpdate(event);
1559 case QAccessible::Button:
1560 handleButtonUpdate(event);
1562 case QAccessible::CheckBox:
1563 if (iface->childCount() > 0)
1564 handleGroupBoxUpdate(event);
1566 handleCheckBoxUpdate(event);
1568 case QAccessible::Switch:
1569 handleSwitchUpdate(event);
1571 case QAccessible::EditableText:
1572 handleLineEditUpdate(event);
1574 case QAccessible::Dialog:
1575 case QAccessible::AlertMessage:
1576 handleDialogUpdate(event);
1578 case QAccessible::MenuItem:
1579 case QAccessible::MenuBar:
1580 case QAccessible::PopupMenu:
1581 handleMenuUpdate(event);
1583 case QAccessible::ToolBar:
1584 case QAccessible::ButtonMenu:
1585 handleToolUpdate(event);
1587 case QAccessible::RadioButton:
1588 handleRadioButtonUpdate(event);
1590 case QAccessible::Dial:
1591 handleDialUpdate(event);
1593 case QAccessible::SpinBox:
1594 handleSpinBoxUpdate(event);
1596 case QAccessible::Slider:
1597 handleSliderUpdate(event);
1599 case QAccessible::PageTab:
1600 handlePageTabUpdate(event);
1602 case QAccessible::PageTabList:
1603 handlePageTabListUpdate(event);
1605 case QAccessible::ScrollBar:
1606 handleScrollBarUpdate(event);
1608 case QAccessible::Grouping:
1609 handleGroupBoxUpdate(event);
1611 case QAccessible::ProgressBar:
1612 handleProgressBarUpdate(event);
1615 qCDebug(lcQpaAccessibility) <<
"TODO: implement notifyAccessibilityUpdate for role" << iface->role();
void QWasmAccessibilityEnable()