Qt 6.x
The Qt SDK
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
qwasmaccessibility.cpp
Go to the documentation of this file.
1// Copyright (C) 2022 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
5#include "qwasmscreen.h"
6#include "qwasmwindow.h"
7#include "qwasmintegration.h"
8
9#include <QtGui/qwindow.h>
10
11#if QT_CONFIG(accessibility)
12
13#include <QtGui/private/qaccessiblebridgeutils_p.h>
14
15Q_LOGGING_CATEGORY(lcQpaAccessibility, "qt.qpa.accessibility")
16
17// Qt WebAssembly a11y backend
18//
19// This backend implements accessibility support by creating "shadowing" html
20// elements for each Qt UI element. We access the DOM by using Emscripten's
21// val.h API.
22//
23// Currently, html elements are created in response to notifyAccessibilityUpdate
24// events. In addition or alternatively, we could also walk the accessibility tree
25// from setRootObject().
26
27QWasmAccessibility::QWasmAccessibility()
28{
29
30 s_instance = this;
31}
32
33QWasmAccessibility::~QWasmAccessibility()
34{
35 s_instance = nullptr;
36}
37
38QWasmAccessibility *QWasmAccessibility::s_instance = nullptr;
39
40QWasmAccessibility* QWasmAccessibility::get()
41{
42 return s_instance;
43}
44
45void QWasmAccessibility::addAccessibilityEnableButton(QWindow *window)
46{
47 get()->addAccessibilityEnableButtonImpl(window);
48}
49
50void QWasmAccessibility::removeAccessibilityEnableButton(QWindow *window)
51{
52 get()->removeAccessibilityEnableButtonImpl(window);
53}
54
55void QWasmAccessibility::addAccessibilityEnableButtonImpl(QWindow *window)
56{
57 if (m_accessibilityEnabled)
58 return;
59
60 emscripten::val container = getContainer(window);
61 emscripten::val document = getDocument(container);
62 emscripten::val button = document.call<emscripten::val>("createElement", std::string("button"));
63 button.set("innerText", std::string("Enable Screen Reader"));
64 button["classList"].call<void>("add", emscripten::val("hidden-visually-read-by-screen-reader"));
65 container.call<void>("appendChild", button);
66
67 auto enableContext = std::make_tuple(button, std::make_unique<qstdweb::EventCallback>
68 (button, std::string("click"), [this](emscripten::val) { enableAccessibility(); }));
69 m_enableButtons.insert(std::make_pair(window, std::move(enableContext)));
70}
71
72void QWasmAccessibility::removeAccessibilityEnableButtonImpl(QWindow *window)
73{
74 auto it = m_enableButtons.find(window);
75 if (it == m_enableButtons.end())
76 return;
77
78 // Remove button
79 auto [element, callback] = it->second;
80 Q_UNUSED(callback);
81 element["parentElement"].call<void>("removeChild", element);
82 m_enableButtons.erase(it);
83}
84
85void QWasmAccessibility::enableAccessibility()
86{
87 // Enable accessibility globally for the applicaton. Remove all "enable"
88 // buttons and populate the accessibility tree, starting from the root object.
89
90 Q_ASSERT(!m_accessibilityEnabled);
91 m_accessibilityEnabled = true;
92 for (const auto& [key, value] : m_enableButtons) {
93 const auto &[element, callback] = value;
95 Q_UNUSED(callback);
96 element["parentElement"].call<void>("removeChild", element);
97 }
98 m_enableButtons.clear();
99 populateAccessibilityTree(QAccessible::queryAccessibleInterface(m_rootObject));
100}
101
102emscripten::val QWasmAccessibility::getContainer(QWindow *window)
103{
104 return window ? static_cast<QWasmWindow *>(window->handle())->a11yContainer()
105 : emscripten::val::undefined();
106}
107
108emscripten::val QWasmAccessibility::getContainer(QAccessibleInterface *iface)
109{
110 if (!iface)
111 return emscripten::val::undefined();
112 return getContainer(getWindow(iface));
113}
114
115QWindow *QWasmAccessibility::getWindow(QAccessibleInterface *iface)
116{
117 QWindow *window = iface->window();
118 // this is needed to add tabs as the window is not available
119 if (!window && iface->parent())
120 window = iface->parent()->window();
121 return window;
122}
123
124emscripten::val QWasmAccessibility::getDocument(const emscripten::val &container)
125{
126 if (container.isUndefined())
127 return emscripten::val::global("document");
128 return container["ownerDocument"];
129}
130
131emscripten::val QWasmAccessibility::getDocument(QAccessibleInterface *iface)
132{
133 return getDocument(getContainer(iface));
134}
135
136emscripten::val QWasmAccessibility::createHtmlElement(QAccessibleInterface *iface)
137{
138 // Get the html container element for the interface; this depends on which
139 // QScreen it is on. If the interface is not on a screen yet we get an undefined
140 // container, and the code below handles that case as well.
141 emscripten::val container = getContainer(iface);
142
143 // Get the correct html document for the container, or fall back
144 // to the global document. TODO: Does using the correct document actually matter?
145 emscripten::val document = getDocument(container);
146
147 // Translate the Qt a11y elemen role into html element type + ARIA role.
148 // Here we can either create <div> elements with a spesific ARIA role,
149 // or create e.g. <button> elements which should have built-in accessibility.
150 emscripten::val element = [this, iface, document] {
151
152 emscripten::val element = emscripten::val::undefined();
153
154 switch (iface->role()) {
155
156 case QAccessible::Button: {
157 element = document.call<emscripten::val>("createElement", std::string("button"));
158 element.call<void>("addEventListener", emscripten::val("click"),
159 emscripten::val::module_property("qtEventReceived"), true);
160 } break;
161 case QAccessible::CheckBox: {
162 element = document.call<emscripten::val>("createElement", std::string("input"));
163 element.call<void>("setAttribute", std::string("type"), std::string("checkbox"));
164 if (iface->state().checked) {
165 element.call<void>("setAttribute", std::string("checked"), std::string("true"));
166 }
167 element.call<void>("addEventListener", emscripten::val("change"),
168 emscripten::val::module_property("qtEventReceived"), true);
169
170 } break;
171
172 case QAccessible::RadioButton: {
173 element = document.call<emscripten::val>("createElement", std::string("input"));
174 element.call<void>("setAttribute", std::string("type"), std::string("radio"));
175 if (iface->state().checked) {
176 element.call<void>("setAttribute", std::string("checked"), std::string("true"));
177 }
178 element.set(std::string("name"), std::string("buttonGroup"));
179 element.call<void>("addEventListener", emscripten::val("change"),
180 emscripten::val::module_property("qtEventReceived"), true);
181 } break;
182
183 case QAccessible::SpinBox: {
184 element = document.call<emscripten::val>("createElement", std::string("input"));
185 element.call<void>("setAttribute", std::string("type"), std::string("number"));
186 std::string valueString = iface->valueInterface()->currentValue().toString().toStdString();
187 element.call<void>("setAttribute", std::string("value"), valueString);
188 element.call<void>("addEventListener", emscripten::val("change"),
189 emscripten::val::module_property("qtEventReceived"), true);
190 } break;
191
192 case QAccessible::Slider: {
193 element = document.call<emscripten::val>("createElement", std::string("input"));
194 element.call<void>("setAttribute", std::string("type"), std::string("range"));
195 std::string valueString = iface->valueInterface()->currentValue().toString().toStdString();
196 element.call<void>("setAttribute", std::string("value"), valueString);
197 element.call<void>("addEventListener", emscripten::val("change"),
198 emscripten::val::module_property("qtEventReceived"), true);
199 } break;
200
201 case QAccessible::PageTabList:{
202 element = document.call<emscripten::val>("createElement", std::string("div"));
203 element.call<void>("setAttribute", std::string("role"), std::string("tablist"));
204 QString idName = iface->text(QAccessible::Name).replace(" ", "_");
205 idName += "_tabList";
206 element.call<void>("setAttribute", std::string("id"), idName.toStdString());
207
208 for (int i = 0; i < iface->childCount(); ++i) {
209 if (iface->child(i)->role() == QAccessible::PageTab){
210 emscripten::val elementTab = emscripten::val::undefined();
211 elementTab = ensureHtmlElement(iface->child(i));
212 elementTab.call<void>("setAttribute", std::string("aria-owns"), idName.toStdString());
213 setHtmlElementGeometry(iface->child(i));
214 }
215 }
216 } break;
217
218 case QAccessible::PageTab:{
219 element = document.call<emscripten::val>("createElement", std::string("button"));
220 element.call<void>("setAttribute", std::string("role"), std::string("tab"));
221 QString text = iface->text(QAccessible::Name);
222 element.call<void>("setAttribute", std::string("title"), text.toStdString());
223 element.call<void>("addEventListener", emscripten::val("click"),
224 emscripten::val::module_property("qtEventReceived"), true);
225 } break;
226
227 case QAccessible::ScrollBar: {
228 element = document.call<emscripten::val>("createElement", std::string("div"));
229 element.call<void>("setAttribute", std::string("role"), std::string("scrollbar"));
230 std::string valueString = iface->valueInterface()->currentValue().toString().toStdString();
231 element.call<void>("setAttribute", std::string("aria-valuenow"), valueString);
232 element.call<void>("addEventListener", emscripten::val("change"),
233 emscripten::val::module_property("qtEventReceived"), true);
234 } break;
235
236 case QAccessible::StaticText: {
237 element = document.call<emscripten::val>("createElement", std::string("textarea"));
238 element.call<void>("setAttribute", std::string("readonly"), std::string("true"));
239
240 } break;
241 case QAccessible::Dialog: {
242 element = document.call<emscripten::val>("createElement", std::string("dialog"));
243 }break;
244 case QAccessible::ToolBar:
245 case QAccessible::ButtonMenu: {
246 element = document.call<emscripten::val>("createElement", std::string("div"));
247 QString text = iface->text(QAccessible::Name);
248
249 element.call<void>("setAttribute", std::string("role"), std::string("widget"));
250 element.call<void>("setAttribute", std::string("title"), text.toStdString());
251 element.call<void>("addEventListener", emscripten::val("click"),
252 emscripten::val::module_property("qtEventReceived"), true);
253 }break;
254 case QAccessible::MenuBar:
255 case QAccessible::PopupMenu: {
256 element = document.call<emscripten::val>("createElement",std::string("div"));
257 QString text = iface->text(QAccessible::Name);
258 element.call<void>("setAttribute", std::string("role"), std::string("widget"));
259 element.call<void>("setAttribute", std::string("title"), text.toStdString());
260 for (int i = 0; i < iface->childCount(); ++i) {
261 ensureHtmlElement(iface->child(i));
262 setHtmlElementTextName(iface->child(i));
263 setHtmlElementGeometry(iface->child(i));
264 }
265 }break;
266 case QAccessible::EditableText: {
267 element = document.call<emscripten::val>("createElement", std::string("input"));
268 element.call<void>("setAttribute", std::string("type"),std::string("text"));
269 element.call<void>("addEventListener", emscripten::val("input"),
270 emscripten::val::module_property("qtEventReceived"), true);
271 } break;
272 default:
273 qCDebug(lcQpaAccessibility) << "TODO: createHtmlElement() handle" << iface->role();
274 element = document.call<emscripten::val>("createElement", std::string("div"));
275 }
276
277 return element;
278
279 }();
280
281 // Add the html element to the container if we have one. If not there
282 // is a second chance when handling the ObjectShow event.
283 if (!container.isUndefined())
284 container.call<void>("appendChild", element);
285
286 return element;
287}
288
289void QWasmAccessibility::destroyHtmlElement(QAccessibleInterface *iface)
290{
291 Q_UNUSED(iface);
292 qCDebug(lcQpaAccessibility) << "TODO destroyHtmlElement";
293}
294
295emscripten::val QWasmAccessibility::ensureHtmlElement(QAccessibleInterface *iface)
296{
297 auto it = m_elements.find(iface);
298 if (it != m_elements.end())
299 return it.value();
300
301 emscripten::val element = createHtmlElement(iface);
302 m_elements.insert(iface, element);
303
304 return element;
305}
306
307void QWasmAccessibility::setHtmlElementVisibility(QAccessibleInterface *iface, bool visible)
308{
309 emscripten::val element = ensureHtmlElement(iface);
310 emscripten::val container = getContainer(iface);
311
312 if (container.isUndefined()) {
313 qCDebug(lcQpaAccessibility) << "TODO: setHtmlElementVisibility: unable to find html container for element" << iface;
314 return;
315 }
316
317 container.call<void>("appendChild", element);
318
319 element.set("ariaHidden", !visible); // ariaHidden mean completely hidden; maybe some sort of soft-hidden should be used.
320}
321
322void QWasmAccessibility::setHtmlElementGeometry(QAccessibleInterface *iface)
323{
324 emscripten::val element = ensureHtmlElement(iface);
325
326 // QAccessibleInterface gives us the geometry in global (screen) coordinates. Translate that
327 // to window geometry in order to position elements relative to window origin.
328 QWindow *window = getWindow(iface);
329 if (!window)
330 qCWarning(lcQpaAccessibility) << "Unable to find window for" << iface << "setting null geometry";
331 QRect screenGeometry = iface->rect();
332 QPoint windowPos = window ? window->mapFromGlobal(screenGeometry.topLeft()) : QPoint();
333 QRect windowGeometry(windowPos, screenGeometry.size());
334
335 setHtmlElementGeometry(element, windowGeometry);
336}
337
338void QWasmAccessibility::setHtmlElementGeometry(emscripten::val element, QRect geometry)
339{
340 // Position the element using "position: absolute" in order to place
341 // it under the corresponding Qt element in the screen.
342 emscripten::val style = element["style"];
343 style.set("position", std::string("absolute"));
344 style.set("z-index", std::string("-1")); // FIXME: "0" should be sufficient to order beheind the
345 // screen element, but isn't
346 style.set("left", std::to_string(geometry.x()) + "px");
347 style.set("top", std::to_string(geometry.y()) + "px");
348 style.set("width", std::to_string(geometry.width()) + "px");
349 style.set("height", std::to_string(geometry.height()) + "px");
350}
351
352void QWasmAccessibility::setHtmlElementTextName(QAccessibleInterface *iface)
353{
354 emscripten::val element = ensureHtmlElement(iface);
355 QString text = iface->text(QAccessible::Name);
356 element.set("innerHTML", text.toStdString()); // FIXME: use something else than innerHTML
357}
358
359void QWasmAccessibility::setHtmlElementTextNameLE(QAccessibleInterface *iface) {
360 emscripten::val element = ensureHtmlElement(iface);
361 QString text = iface->text(QAccessible::Name);
362 element.call<void>("setAttribute", std::string("name"), text.toStdString());
363 QString value = iface->text(QAccessible::Value);
364 element.set("innerHTML", value.toStdString());
365}
366
367void QWasmAccessibility::handleStaticTextUpdate(QAccessibleEvent *event)
368{
369 switch (event->type()) {
370 case QAccessible::NameChanged: {
371 setHtmlElementTextName(event->accessibleInterface());
372 } break;
373 default:
374 qCDebug(lcQpaAccessibility) << "TODO: implement handleStaticTextUpdate for event" << event->type();
375 break;
376 }
377}
378
379void QWasmAccessibility::handleLineEditUpdate(QAccessibleEvent *event) {
380
381 switch (event->type()) {
382 case QAccessible::NameChanged: {
383 setHtmlElementTextName(event->accessibleInterface());
384 } break;
385 case QAccessible::Focus:
386 case QAccessible::TextRemoved:
387 case QAccessible::TextInserted:
388 case QAccessible::TextCaretMoved: {
389 setHtmlElementTextNameLE(event->accessibleInterface());
390 } break;
391
392 default:
393 qCDebug(lcQpaAccessibility) << "TODO: implement handleLineEditUpdate for event" << event->type();
394 break;
395 }
396}
397
398void QWasmAccessibility::handleEventFromHtmlElement(const emscripten::val event)
399{
400
401 QAccessibleInterface *iface = m_elements.key(event["target"]);
402
403 if (iface == nullptr) {
404 return;
405 } else {
406 QString eventType = QString::fromStdString(event["type"].as<std::string>());
407 const auto& actionNames = QAccessibleBridgeUtils::effectiveActionNames(iface);
408
409 if (actionNames.contains(QAccessibleActionInterface::pressAction())) {
410
411 iface->actionInterface()->doAction(QAccessibleActionInterface::pressAction());
412
413 } else if (actionNames.contains(QAccessibleActionInterface::toggleAction())) {
414
415 iface->actionInterface()->doAction(QAccessibleActionInterface::toggleAction());
416
417 } else if (actionNames.contains(QAccessibleActionInterface::increaseAction()) ||
418 actionNames.contains(QAccessibleActionInterface::decreaseAction())) {
419
420 QString val = QString::fromStdString(event["target"]["value"].as<std::string>());
421
422 iface->valueInterface()->setCurrentValue(val.toInt());
423
424 } else if (eventType == "input") {
425
426 if (iface->editableTextInterface()) {
427 std::string insertText = event["target"]["value"].as<std::string>();
428 iface->setText(QAccessible::Value, QString::fromStdString(insertText));
429 }
430 }
431 }
432}
433
434void QWasmAccessibility::handleButtonUpdate(QAccessibleEvent *event)
435{
436 qCDebug(lcQpaAccessibility) << "TODO: implement handleButtonUpdate for event" << event->type();
437}
438
439void QWasmAccessibility::handleCheckBoxUpdate(QAccessibleEvent *event)
440{
441 switch (event->type()) {
442 case QAccessible::Focus:
443 case QAccessible::NameChanged: {
444 setHtmlElementTextName(event->accessibleInterface());
445 } break;
446 case QAccessible::StateChanged: {
447 QAccessibleInterface *accessible = event->accessibleInterface();
448 emscripten::val element = ensureHtmlElement(accessible);
449 bool checkedString = accessible->state().checked ? true : false;
450 element.call<void>("setAttribute", std::string("checked"), checkedString);
451 } break;
452 default:
453 qCDebug(lcQpaAccessibility) << "TODO: implement handleCheckBoxUpdate for event" << event->type();
454 break;
455 }
456}
457void QWasmAccessibility::handleToolUpdate(QAccessibleEvent *event)
458{
459 QAccessibleInterface *iface = event->accessibleInterface();
460 QString text = iface->text(QAccessible::Name);
461 QString desc = iface->text(QAccessible::Description);
462 switch (event->type()) {
463 case QAccessible::NameChanged:
464 case QAccessible::StateChanged:{
465 emscripten::val element = ensureHtmlElement(iface);
466 element.call<void>("setAttribute", std::string("title"), text.toStdString());
467 } break;
468 default:
469 qCDebug(lcQpaAccessibility) << "TODO: implement handleToolUpdate for event" << event->type();
470 break;
471 }
472}
473void QWasmAccessibility::handleMenuUpdate(QAccessibleEvent *event)
474{
475 QAccessibleInterface *iface = event->accessibleInterface();
476 QString text = iface->text(QAccessible::Name);
477 QString desc = iface->text(QAccessible::Description);
478 switch (event->type()) {
479 case QAccessible::NameChanged:
480 case QAccessible::MenuStart ://"TODO: To implement later
481 case QAccessible::PopupMenuStart://"TODO: To implement later
482 case QAccessible::StateChanged:{
483 emscripten::val element = ensureHtmlElement(iface);
484 element.call<void>("setAttribute", std::string("title"), text.toStdString());
485 } break;
486 default:
487 qCDebug(lcQpaAccessibility) << "TODO: implement handleMenuUpdate for event" << event->type();
488 break;
489 }
490}
491void QWasmAccessibility::handleDialogUpdate(QAccessibleEvent *event) {
492
493 switch (event->type()) {
494 case QAccessible::NameChanged:
495 case QAccessible::Focus:
496 case QAccessible::DialogStart:
497 case QAccessible::StateChanged: {
498 setHtmlElementTextName(event->accessibleInterface());
499 } break;
500
501 default:
502 qCDebug(lcQpaAccessibility) << "TODO: implement handleLineEditUpdate for event" << event->type();
503 break;
504 }
505}
506
507void QWasmAccessibility::populateAccessibilityTree(QAccessibleInterface *iface)
508{
509 if (!iface)
510 return;
511
512 // Create html element for the interface, sync up properties.
513 ensureHtmlElement(iface);
514 const bool visible = !iface->state().invisible;
515 setHtmlElementVisibility(iface, visible);
516 setHtmlElementGeometry(iface);
517 setHtmlElementTextName(iface);
518
519 for (int i = 0; i < iface->childCount(); ++i)
520 populateAccessibilityTree(iface->child(i));
521}
522
523void QWasmAccessibility::handleRadioButtonUpdate(QAccessibleEvent *event)
524{
525 switch (event->type()) {
526 case QAccessible::Focus:
527 case QAccessible::NameChanged: {
528 setHtmlElementTextName(event->accessibleInterface());
529 } break;
530 case QAccessible::StateChanged: {
531 QAccessibleInterface *accessible = event->accessibleInterface();
532 emscripten::val element = ensureHtmlElement(accessible);
533 std::string checkedString = accessible->state().checked ? "true" : "false";
534 element.call<void>("setAttribute", std::string("checked"), checkedString);
535 } break;
536 default:
537 qDebug() << "TODO: implement handleRadioButtonUpdate for event" << event->type();
538 break;
539 }
540}
541
542void QWasmAccessibility::handleSpinBoxUpdate(QAccessibleEvent *event)
543{
544 switch (event->type()) {
545 case QAccessible::Focus:
546 case QAccessible::NameChanged: {
547 setHtmlElementTextName(event->accessibleInterface());
548 } break;
549 case QAccessible::ValueChanged: {
550 QAccessibleInterface *accessible = event->accessibleInterface();
551 emscripten::val element = ensureHtmlElement(accessible);
552 std::string valueString = accessible->valueInterface()->currentValue().toString().toStdString();
553 element.call<void>("setAttribute", std::string("value"), valueString);
554 } break;
555 default:
556 qDebug() << "TODO: implement handleSpinBoxUpdate for event" << event->type();
557 break;
558 }
559}
560
561void QWasmAccessibility::handleSliderUpdate(QAccessibleEvent *event)
562{
563 switch (event->type()) {
564 case QAccessible::Focus:
565 case QAccessible::NameChanged: {
566 setHtmlElementTextName(event->accessibleInterface());
567 } break;
568 case QAccessible::ValueChanged: {
569 QAccessibleInterface *accessible = event->accessibleInterface();
570 emscripten::val element = ensureHtmlElement(accessible);
571 std::string valueString = accessible->valueInterface()->currentValue().toString().toStdString();
572 element.call<void>("setAttribute", std::string("value"), valueString);
573 } break;
574 default:
575 qDebug() << "TODO: implement handleSliderUpdate for event" << event->type();
576 break;
577 }
578}
579
580void QWasmAccessibility::handleScrollBarUpdate(QAccessibleEvent *event)
581{
582 switch (event->type()) {
583 case QAccessible::Focus:
584 case QAccessible::NameChanged: {
585 setHtmlElementTextName(event->accessibleInterface());
586 } break;
587 case QAccessible::ValueChanged: {
588 QAccessibleInterface *accessible = event->accessibleInterface();
589 emscripten::val element = ensureHtmlElement(accessible);
590 std::string valueString = accessible->valueInterface()->currentValue().toString().toStdString();
591 element.call<void>("setAttribute", std::string("aria-valuenow"), valueString);
592 } break;
593 default:
594 qDebug() << "TODO: implement handleSliderUpdate for event" << event->type();
595 break;
596 }
597
598}
599
600void QWasmAccessibility::handlePageTabUpdate(QAccessibleEvent *event)
601{
602 switch (event->type()) {
603 case QAccessible::NameChanged: {
604 setHtmlElementTextName(event->accessibleInterface());
605 } break;
606 case QAccessible::Focus: {
607 setHtmlElementTextName(event->accessibleInterface());
608 } break;
609 default:
610 qDebug() << "TODO: implement handlePageTabUpdate for event" << event->type();
611 break;
612 }
613}
614
615void QWasmAccessibility::handlePageTabListUpdate(QAccessibleEvent *event)
616{
617 switch (event->type()) {
618 case QAccessible::NameChanged: {
619 setHtmlElementTextName(event->accessibleInterface());
620 } break;
621 case QAccessible::Focus: {
622 setHtmlElementTextName(event->accessibleInterface());
623 } break;
624 default:
625 qDebug() << "TODO: implement handlePageTabUpdate for event" << event->type();
626 break;
627 }
628}
629
630void QWasmAccessibility::notifyAccessibilityUpdate(QAccessibleEvent *event)
631{
632 if (!m_accessibilityEnabled)
633 return;
634
635 QAccessibleInterface *iface = event->accessibleInterface();
636 if (!iface) {
637 qWarning() << "notifyAccessibilityUpdate with null a11y interface" ;
638 return;
639 }
640
641 // Handle some common event types. See
642 // https://doc.qt.io/qt-5/qaccessible.html#Event-enum
643 switch (event->type()) {
644 case QAccessible::ObjectShow:
645
646 setHtmlElementVisibility(iface, true);
647
648 // Sync up properties on show;
649 setHtmlElementGeometry(iface);
650 setHtmlElementTextName(iface);
651
652 return;
653 break;
654 case QAccessible::ObjectHide:
655 setHtmlElementVisibility(iface, false);
656 return;
657 break;
658 // TODO: maybe handle more types here
659 default:
660 break;
661 };
662
663 // Switch on interface role, see
664 // https://doc.qt.io/qt-5/qaccessibleinterface.html#role
665 switch (iface->role()) {
666 case QAccessible::StaticText:
667 handleStaticTextUpdate(event);
668 break;
669 case QAccessible::Button:
670 handleStaticTextUpdate(event);
671 break;
672 case QAccessible::CheckBox:
673 handleCheckBoxUpdate(event);
674 break;
675 case QAccessible::EditableText:
676 handleLineEditUpdate(event);
677 break;
678 case QAccessible::Dialog:
679 handleDialogUpdate(event);
680 break;
681 case QAccessible::MenuItem:
682 case QAccessible::MenuBar:
683 case QAccessible::PopupMenu:
684 handleMenuUpdate(event);
685 break;
686 case QAccessible::ToolBar:
687 case QAccessible::ButtonMenu:
688 handleToolUpdate(event);
689 case QAccessible::RadioButton:
690 handleRadioButtonUpdate(event);
691 break;
692 case QAccessible::SpinBox:
693 handleSpinBoxUpdate(event);
694 break;
695 case QAccessible::Slider:
696 handleSliderUpdate(event);
697 break;
698 case QAccessible::PageTab:
699 handlePageTabUpdate(event);
700 break;
701 case QAccessible::PageTabList:
702 handlePageTabListUpdate(event);
703 break;
704 case QAccessible::ScrollBar:
705 handleScrollBarUpdate(event);
706 break;
707 default:
708 qCDebug(lcQpaAccessibility) << "TODO: implement notifyAccessibilityUpdate for role" << iface->role();
709 };
710}
711
712void QWasmAccessibility::setRootObject(QObject *root)
713{
714 m_rootObject = root;
715}
716
717void QWasmAccessibility::initialize()
718{
719
720}
721
722void QWasmAccessibility::cleanup()
723{
724
725}
726
727void QWasmAccessibility::onHtmlEventReceived(emscripten::val event)
728{
729 static_cast<QWasmAccessibility *>(QWasmIntegration::get()->accessibility())->handleEventFromHtmlElement(event);
730}
731
732EMSCRIPTEN_BINDINGS(qtButtonEvent) {
733 function("qtEventReceived", &QWasmAccessibility::onHtmlEventReceived);
734}
735
736#endif // QT_CONFIG(accessibility)
\inmodule QtCore
Definition qobject.h:90
\inmodule QtCore\reentrant
Definition qpoint.h:23
\inmodule QtCore\reentrant
Definition qrect.h:30
constexpr int height() const noexcept
Returns the height of the rectangle.
Definition qrect.h:238
constexpr QPoint topLeft() const noexcept
Returns the position of the rectangle's top-left corner.
Definition qrect.h:220
constexpr int x() const noexcept
Returns the x-coordinate of the rectangle's left edge.
Definition qrect.h:184
constexpr QSize size() const noexcept
Returns the size of the rectangle.
Definition qrect.h:241
constexpr int width() const noexcept
Returns the width of the rectangle.
Definition qrect.h:235
constexpr int y() const noexcept
Returns the y-coordinate of the rectangle's top edge.
Definition qrect.h:187
iterator end()
Definition qset.h:140
iterator find(const T &value)
Definition qset.h:159
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
static QString fromStdString(const std::string &s)
Definition qstring.h:1322
std::string toStdString() const
Returns a std::string object with the data contained in this QString.
Definition qstring.h:1319
static QWasmIntegration * get()
QPlatformAccessibility * accessibility() const override
\inmodule QtGui
Definition qwindow.h:63
QString text
QPushButton * button
[2]
QSet< QString >::iterator it
QStringList effectiveActionNames(QAccessibleInterface *iface)
constexpr QBindableInterface iface
Definition qproperty.h:664
emscripten::val document()
Definition qwasmdom.h:20
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction function
static QDBusError::ErrorType get(const char *name)
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
#define qDebug
[1]
Definition qlogging.h:160
#define qWarning
Definition qlogging.h:162
#define Q_LOGGING_CATEGORY(name,...)
#define qCWarning(category,...)
#define qCDebug(category,...)
GLuint64 key
struct _cl_event * event
GLuint GLfloat * val
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define Q_UNUSED(x)
@ desc
EMSCRIPTEN_BINDINGS(qtClipboardModule)
aWidget window() -> setWindowTitle("New Window Title")
[2]