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
quiaccessibilityelement.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 "private/qaccessiblecache_p.h"
10#include "private/qcore_mac_p.h"
11#include "uistrings_p.h"
12#include "qioswindow.h"
13
14#include <QtGui/private/qaccessiblebridgeutils_p.h>
15
16QT_NAMESPACE_ALIAS_OBJC_CLASS(QMacAccessibilityElement);
17
18@implementation QMacAccessibilityElement
19
20- (instancetype)initWithId:(QAccessible::Id)anId withAccessibilityContainer:(id)view
21{
22 Q_ASSERT((int)anId < 0);
23 self = [super initWithAccessibilityContainer:view];
24 if (self)
25 _axid = anId;
26
27 return self;
28}
29
30+ (instancetype)elementWithId:(QAccessible::Id)anId
31{
32 Q_ASSERT(anId);
33 if (!anId)
34 return nil;
35
36 QAccessibleCache *cache = QAccessibleCache::instance();
37
38 QMacAccessibilityElement *element = cache->elementForId(anId);
39 if (!element) {
40 QWindow *window = nullptr;
41 auto *iface = QAccessible::accessibleInterface(anId);
42 while (iface) {
43 if ((window = iface->window()))
44 break;
45 iface = iface->parent();
46 }
47
48 if (window && window->handle()) {
49 auto *platformWindow = static_cast<QIOSWindow*>(window->handle());
50 element = [[self alloc] initWithId:anId withAccessibilityContainer:platformWindow->view()];
51 if (cache->insertElement(anId, element))
52 [element release];
53 } else {
54 qWarning() << "Could not create a11y element for" << iface
55 << "with window" << window
56 << "and platform window" << (window ? window->handle() : nullptr);
57 }
58 }
59 return element;
60}
61
62- (void)invalidate
63{
64}
65
66- (BOOL)isAccessibilityElement
67{
68 return YES;
69}
70
71- (NSString*)accessibilityLabel
72{
73 QAccessibleInterface *iface = QAccessible::accessibleInterface(self.axid);
74 if (!iface || !iface->isValid()) {
75 qWarning() << "invalid accessible interface for: " << self.axid;
76 return @"";
77 }
78
79 return iface->text(QAccessible::Name).toNSString();
80}
81
82
83- (NSString*)accessibilityIdentifier
84{
85 QAccessibleInterface *iface = QAccessible::accessibleInterface(self.axid);
86 if (!iface || !iface->isValid()) {
87 qWarning() << "invalid accessible interface for: " << self.axid;
88 return @"";
89 }
90 return QAccessibleBridgeUtils::accessibleId(iface).toNSString();
91}
92
93- (NSString*)accessibilityHint
94{
95 QAccessibleInterface *iface = QAccessible::accessibleInterface(self.axid);
96 if (!iface || !iface->isValid()) {
97 qWarning() << "invalid accessible interface for: " << self.axid;
98 return @"";
99 }
100 return iface->text(QAccessible::Description).toNSString();
101}
102
103- (NSString*)accessibilityValue
104{
105 QAccessibleInterface *iface = QAccessible::accessibleInterface(self.axid);
106 if (!iface || !iface->isValid()) {
107 qWarning() << "invalid accessible interface for: " << self.axid;
108 return @"";
109 }
110
111 QAccessible::State state = iface->state();
112
113 if (state.checkable) {
114 if (iface->role() == QAccessible::CheckBox
115 || iface->role() == QAccessible::RadioButton)
116 return @"";
117
118 if (iface->role() == QAccessible::Switch)
119 return state.checked ? @"1" : @"0";
120
121 return state.checked
122 ? QCoreApplication::translate(ACCESSIBILITY_ELEMENT, AE_CHECKED).toNSString()
123 : QCoreApplication::translate(ACCESSIBILITY_ELEMENT, AE_UNCHECKED).toNSString();
124 }
125
126 QAccessibleValueInterface *val = iface->valueInterface();
127 if (val) {
128 return val->currentValue().toString().toNSString();
129 } else if (iface->editableTextInterface()) {
130 if (QAccessibleTextInterface *text = iface->textInterface())
131 return text->text(0, text->characterCount()).toNSString();
132 }
133
134 return [super accessibilityHint];
135}
136
137- (CGRect)accessibilityFrame
138{
139 QAccessibleInterface *iface = QAccessible::accessibleInterface(self.axid);
140 if (!iface || !iface->isValid()) {
141 qWarning() << "invalid accessible interface for: " << self.axid;
142 return CGRect();
143 }
144
145 QRect rect = iface->rect();
146 return CGRectMake(rect.x(), rect.y(), rect.width(), rect.height());
147}
148
149- (UIAccessibilityTraits)accessibilityTraits
150{
151 UIAccessibilityTraits traits = UIAccessibilityTraitNone;
152
153 QAccessibleInterface *iface = QAccessible::accessibleInterface(self.axid);
154 if (!iface || !iface->isValid()) {
155 qWarning() << "invalid accessible interface for: " << self.axid;
156 return traits;
157 }
158 QAccessible::State state = iface->state();
159 if (state.disabled)
160 traits |= UIAccessibilityTraitNotEnabled;
161
162 if (state.searchEdit)
163 traits |= UIAccessibilityTraitSearchField;
164
165 if (state.selected)
166 traits |= UIAccessibilityTraitSelected;
167
168 const auto accessibleRole = iface->role();
169 if (accessibleRole == QAccessible::Button) {
170 traits |= UIAccessibilityTraitButton;
171 } else if (accessibleRole == QAccessible::CheckBox
172 || accessibleRole == QAccessible::RadioButton) {
173 if (state.checked)
174 traits |= UIAccessibilityTraitSelected;
175 } else if (accessibleRole == QAccessible::Switch) {
176 traits |= UIAccessibilityTraitToggleButton;
177 } else if (accessibleRole == QAccessible::EditableText) {
178 static auto defaultTextFieldTraits = []{
179 auto *textField = [[[UITextField alloc] initWithFrame:CGRectZero] autorelease];
180 return textField.accessibilityTraits;
181 }();
182 traits |= defaultTextFieldTraits;
183 } else if (accessibleRole == QAccessible::Graphic) {
184 traits |= UIAccessibilityTraitImage;
185 } else if (accessibleRole == QAccessible::Heading) {
186 traits |= UIAccessibilityTraitHeader;
187 } else if (accessibleRole == QAccessible::Link) {
188 traits |= UIAccessibilityTraitLink;
189 } else if (accessibleRole == QAccessible::StaticText) {
190 traits |= UIAccessibilityTraitStaticText;
191 }
192
193 if (iface->valueInterface() && iface->role() != QAccessible::ProgressBar)
194 traits |= UIAccessibilityTraitAdjustable;
195
196 return traits;
197}
198
199- (BOOL)accessibilityActivate
200{
201 QAccessibleInterface *iface = QAccessible::accessibleInterface(self.axid);
202 if (!iface || !iface->isValid()) {
203 qWarning() << "invalid accessible interface for: " << self.axid;
204 return NO;
205 }
206
207 if (QAccessibleActionInterface *action = iface->actionInterface()) {
208 if (action->actionNames().contains(QAccessibleActionInterface::pressAction())) {
209 action->doAction(QAccessibleActionInterface::pressAction());
210 return YES;
211 } else if (action->actionNames().contains(QAccessibleActionInterface::showMenuAction())) {
212 action->doAction(QAccessibleActionInterface::showMenuAction());
213 return YES;
214 }
215 }
216 return NO; // fall back to sending mouse clicks
217}
218
219- (void)accessibilityIncrement
220{
221 QAccessibleInterface *iface = QAccessible::accessibleInterface(self.axid);
222 if (!iface || !iface->isValid()) {
223 qWarning() << "invalid accessible interface for: " << self.axid;
224 return;
225 }
226
227 if (QAccessibleActionInterface *action = iface->actionInterface())
228 action->doAction(QAccessibleActionInterface::increaseAction());
229}
230
231- (void)accessibilityDecrement
232{
233 QAccessibleInterface *iface = QAccessible::accessibleInterface(self.axid);
234 if (!iface || !iface->isValid()) {
235 qWarning() << "invalid accessible interface for: " << self.axid;
236 return;
237 }
238
239 if (QAccessibleActionInterface *action = iface->actionInterface())
240 action->doAction(QAccessibleActionInterface::decreaseAction());
241}
242
243- (BOOL)accessibilityScroll:(UIAccessibilityScrollDirection)direction
244{
245 QAccessibleInterface *iface = QAccessible::accessibleInterface(self.axid);
246 if (!iface || !iface->isValid()) {
247 qWarning() << "invalid accessible interface for: " << self.axid;
248 return NO;
249 }
250
251 QAccessibleActionInterface *action = iface->actionInterface();
252 if (!action)
253 return NO;
254 switch (direction) {
255 case UIAccessibilityScrollDirectionRight:
256 action->doAction(QAccessibleActionInterface::scrollRightAction());
257 return YES;
258 case UIAccessibilityScrollDirectionLeft:
259 action->doAction(QAccessibleActionInterface::scrollLeftAction());
260 return YES;
261 case UIAccessibilityScrollDirectionUp:
262 action->doAction(QAccessibleActionInterface::scrollUpAction());
263 return YES;
264 case UIAccessibilityScrollDirectionDown:
265 action->doAction(QAccessibleActionInterface::scrollDownAction());
266 return YES;
267 case UIAccessibilityScrollDirectionNext:
268 action->doAction(QAccessibleActionInterface::nextPageAction());
269 return YES;
270 case UIAccessibilityScrollDirectionPrevious:
271 action->doAction(QAccessibleActionInterface::previousPageAction());
272 return YES;
273 }
274 return NO;
275}
276
277@end
278
279#endif