Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qiosplatformaccessibility.mm
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
5#undef QT_NO_FOREACH // this file contains unported legacy Q_FOREACH uses
6
8
9#if QT_CONFIG(accessibility)
10
11#include <QtGui/QtGui>
12#include "qioswindow.h"
13#include "quiaccessibilityelement.h"
14
15QT_NAMESPACE_ALIAS_OBJC_CLASS(QMacAccessibilityElement);
16
17QIOSPlatformAccessibility::QIOSPlatformAccessibility()
18{
19 m_focusObserver = QMacNotificationObserver(
20 nil, UIAccessibilityElementFocusedNotification, [&](NSNotification *notification) {
21 id element = notification.userInfo[UIAccessibilityFocusedElementKey];
22 m_focusElement = static_cast<QMacAccessibilityElement *>(element);
23 });
24}
25
26QIOSPlatformAccessibility::~QIOSPlatformAccessibility()
27{}
28
29
30void invalidateCache(QAccessibleInterface *iface)
31{
32 if (!iface || !iface->isValid()) {
33 qWarning() << "invalid accessible interface: " << iface;
34 return;
35 }
36
37 // This will invalidate everything regardless of what window the
38 // interface belonged to. We might want to revisit this strategy later.
39 // (Therefore this function still takes the interface as argument)
40 foreach (QWindow *win, QGuiApplication::topLevelWindows()) {
41 if (win && win->handle()) {
42 QT_PREPEND_NAMESPACE(QIOSWindow) *window = static_cast<QT_PREPEND_NAMESPACE(QIOSWindow) *>(win->handle());
43 window->clearAccessibleCache();
44 }
45 }
46}
47
48
49void QIOSPlatformAccessibility::notifyAccessibilityUpdate(QAccessibleEvent *event)
50{
51 auto *accessibleInterface = event->accessibleInterface();
52 if (!isActive() || !accessibleInterface)
53 return;
54 switch (event->type()) {
55 case QAccessible::Announcement: {
56 auto *announcementEvent = static_cast<QAccessibleAnnouncementEvent *>(event);
57 UIAccessibilityPostNotification(UIAccessibilityAnnouncementNotification,
58 announcementEvent->message().toNSString());
59 break;
60 }
61 case QAccessible::Focus: {
62 auto *element = [QMacAccessibilityElement elementWithId:event->uniqueId()];
63 Q_ASSERT(element);
64 // There's no NSAccessibilityFocusedUIElementChangedNotification, like we have on
65 // macOS. Instead, the documentation for UIAccessibilityLayoutChangedNotification
66 // specifies that the optional argument to UIAccessibilityPostNotification is the
67 // accessibility element for VoiceOver to move to after processing the notification.
68 UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, element);
69 break;
70 }
71 case QAccessible::DescriptionChanged:
72 case QAccessible::NameChanged: {
73 auto *element = [QMacAccessibilityElement elementWithId:event->uniqueId()];
74 if (element == m_focusElement)
75 UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, element);
76 break;
77 }
78 case QAccessible::ObjectCreated:
79 case QAccessible::ObjectShow:
80 case QAccessible::ObjectHide:
81 case QAccessible::ObjectDestroyed:
82 invalidateCache(accessibleInterface);
83 switch (accessibleInterface->role()) {
84 case QAccessible::Window:
85 case QAccessible::Dialog:
86 // Bigger changes to the UI require a full reset of VoiceOver
87 UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, nil);
88 break;
89 default:
90 // While smaller changes can be handled by re-reading the layout
91 UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, nil);
92 }
93 break;
94 default:
95 break;
96 }
97}
98
99#endif