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
6
7#if QT_CONFIG(accessibility)
8
9#include <QtGui/QtGui>
10#include "qioswindow.h"
11#include "quiaccessibilityelement.h"
12
13QT_NAMESPACE_ALIAS_OBJC_CLASS(QMacAccessibilityElement);
14
15QIOSPlatformAccessibility::QIOSPlatformAccessibility()
16{
17 m_focusObserver = QMacNotificationObserver(
18 nil, UIAccessibilityElementFocusedNotification, [&](NSNotification *notification) {
19 id element = notification.userInfo[UIAccessibilityFocusedElementKey];
20 m_focusElement = static_cast<QMacAccessibilityElement *>(element);
21 });
22}
23
24QIOSPlatformAccessibility::~QIOSPlatformAccessibility()
25{}
26
27
28void invalidateCache(QAccessibleInterface *iface)
29{
30 if (!iface || !iface->isValid()) {
31 qWarning() << "invalid accessible interface: " << iface;
32 return;
33 }
34
35 // This will invalidate everything regardless of what window the
36 // interface belonged to. We might want to revisit this strategy later.
37 // (Therefore this function still takes the interface as argument)
38 //
39 // Clear every window, not just the top levels, as each view vends the
40 // elements of its own window only, so a child window's cache is the one
41 // holding the elements that a change below a native view boundary affects.
42 const auto windows = QGuiApplication::allWindows();
43 for (QWindow *win : windows) {
44 if (win && win->handle()) {
45 auto *window = static_cast<QIOSWindow *>(win->handle());
46 window->clearAccessibleCache();
47 }
48 }
49}
50
51
52void QIOSPlatformAccessibility::notifyAccessibilityUpdate(QAccessibleEvent *event)
53{
54 auto *accessibleInterface = event->accessibleInterface();
55 if (!isActive() || !accessibleInterface)
56 return;
57 switch (event->type()) {
58 case QAccessible::Announcement: {
59 auto *announcementEvent = static_cast<QAccessibleAnnouncementEvent *>(event);
60 const bool queueAnnouncement =
61 (announcementEvent->politeness() == QAccessible::AnnouncementPoliteness::Polite);
62 NSAttributedString *message = [[NSAttributedString alloc]
63 initWithString:announcementEvent->message().toNSString()
64 attributes:@{UIAccessibilitySpeechAttributeQueueAnnouncement: @(queueAnnouncement)}];
65 UIAccessibilityPostNotification(UIAccessibilityAnnouncementNotification, [message autorelease]);
66 break;
67 }
68 case QAccessible::Focus: {
69 auto *element = [QMacAccessibilityElement elementWithId:event->uniqueId()];
70 Q_ASSERT(element);
71 // There's no NSAccessibilityFocusedUIElementChangedNotification, like we have on
72 // macOS. Instead, the documentation for UIAccessibilityLayoutChangedNotification
73 // specifies that the optional argument to UIAccessibilityPostNotification is the
74 // accessibility element for VoiceOver to move to after processing the notification.
75 UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, element);
76 break;
77 }
78 case QAccessible::DescriptionChanged:
79 case QAccessible::NameChanged: {
80 auto *element = [QMacAccessibilityElement elementWithId:event->uniqueId()];
81 if (element == m_focusElement)
82 UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, element);
83 break;
84 }
85 case QAccessible::StateChanged:
86 case QAccessible::ValueChanged: {
87 auto *element = [QMacAccessibilityElement elementWithId:event->uniqueId()];
88 if (element)
89 UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, element);
90 break;
91 }
92 case QAccessible::ObjectCreated:
93 case QAccessible::ObjectShow:
94 case QAccessible::ObjectHide:
95 case QAccessible::ObjectDestroyed:
96 invalidateCache(accessibleInterface);
97 switch (accessibleInterface->role()) {
98 case QAccessible::Window:
99 case QAccessible::Dialog:
100 // Bigger changes to the UI require a full reset of VoiceOver
101 UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, nil);
102 break;
103 default:
104 // While smaller changes can be handled by re-reading the layout
105 UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, nil);
106 }
107 break;
108 default:
109 break;
110 }
111}
112
113#endif