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 return state.checked
119 ? QCoreApplication::translate(ACCESSIBILITY_ELEMENT, AE_CHECKED).toNSString()
120 : QCoreApplication::translate(ACCESSIBILITY_ELEMENT, AE_UNCHECKED).toNSString();
121 }
122
123 QAccessibleValueInterface *val = iface->valueInterface();
124 if (val) {
125 return val->currentValue().toString().toNSString();
126 } else if (iface->editableTextInterface()) {
127 if (QAccessibleTextInterface *text = iface->textInterface())
128 return text->text(0, text->characterCount()).toNSString();
129 }
130
131 return [super accessibilityHint];
132}
133
134- (CGRect)accessibilityFrame
135{
136 QAccessibleInterface *iface = QAccessible::accessibleInterface(self.axid);
137 if (!iface || !iface->isValid()) {
138 qWarning() << "invalid accessible interface for: " << self.axid;
139 return CGRect();
140 }
141
142 QRect rect = iface->rect();
143 return CGRectMake(rect.x(), rect.y(), rect.width(), rect.height());
144}
145
146- (UIAccessibilityTraits)accessibilityTraits
147{
148 UIAccessibilityTraits traits = UIAccessibilityTraitNone;
149
150 QAccessibleInterface *iface = QAccessible::accessibleInterface(self.axid);
151 if (!iface || !iface->isValid()) {
152 qWarning() << "invalid accessible interface for: " << self.axid;
153 return traits;
154 }
155 QAccessible::State state = iface->state();
156 if (state.disabled)
157 traits |= UIAccessibilityTraitNotEnabled;
158
159 if (state.searchEdit)
160 traits |= UIAccessibilityTraitSearchField;
161
162 if (state.selected)
163 traits |= UIAccessibilityTraitSelected;
164
165 const auto accessibleRole = iface->role();
166 if (accessibleRole == QAccessible::Button) {
167 traits |= UIAccessibilityTraitButton;
168 } else if (accessibleRole == QAccessible::CheckBox
169 || accessibleRole == QAccessible::RadioButton) {
170 if (state.checked)
171 traits |= UIAccessibilityTraitSelected;
172 } else if (accessibleRole == QAccessible::EditableText) {
173 static auto defaultTextFieldTraits = []{
174 auto *textField = [[[UITextField alloc] initWithFrame:CGRectZero] autorelease];
175 return textField.accessibilityTraits;
176 }();
177 traits |= defaultTextFieldTraits;
178 } else if (accessibleRole == QAccessible::Graphic) {
179 traits |= UIAccessibilityTraitImage;
180 } else if (accessibleRole == QAccessible::Heading) {
181 traits |= UIAccessibilityTraitHeader;
182 } else if (accessibleRole == QAccessible::Link) {
183 traits |= UIAccessibilityTraitLink;
184 } else if (accessibleRole == QAccessible::StaticText) {
185 traits |= UIAccessibilityTraitStaticText;
186 }
187
188 if (iface->valueInterface() && iface->role() != QAccessible::ProgressBar)
189 traits |= UIAccessibilityTraitAdjustable;
190
191 return traits;
192}
193
194- (BOOL)accessibilityActivate
195{
196 QAccessibleInterface *iface = QAccessible::accessibleInterface(self.axid);
197 if (!iface || !iface->isValid()) {
198 qWarning() << "invalid accessible interface for: " << self.axid;
199 return NO;
200 }
201
202 if (QAccessibleActionInterface *action = iface->actionInterface()) {
203 if (action->actionNames().contains(QAccessibleActionInterface::pressAction())) {
204 action->doAction(QAccessibleActionInterface::pressAction());
205 return YES;
206 } else if (action->actionNames().contains(QAccessibleActionInterface::showMenuAction())) {
207 action->doAction(QAccessibleActionInterface::showMenuAction());
208 return YES;
209 }
210 }
211 return NO; // fall back to sending mouse clicks
212}
213
214- (void)accessibilityIncrement
215{
216 QAccessibleInterface *iface = QAccessible::accessibleInterface(self.axid);
217 if (!iface || !iface->isValid()) {
218 qWarning() << "invalid accessible interface for: " << self.axid;
219 return;
220 }
221
222 if (QAccessibleActionInterface *action = iface->actionInterface())
223 action->doAction(QAccessibleActionInterface::increaseAction());
224}
225
226- (void)accessibilityDecrement
227{
228 QAccessibleInterface *iface = QAccessible::accessibleInterface(self.axid);
229 if (!iface || !iface->isValid()) {
230 qWarning() << "invalid accessible interface for: " << self.axid;
231 return;
232 }
233
234 if (QAccessibleActionInterface *action = iface->actionInterface())
235 action->doAction(QAccessibleActionInterface::decreaseAction());
236}
237
238- (BOOL)accessibilityScroll:(UIAccessibilityScrollDirection)direction
239{
240 QAccessibleInterface *iface = QAccessible::accessibleInterface(self.axid);
241 if (!iface || !iface->isValid()) {
242 qWarning() << "invalid accessible interface for: " << self.axid;
243 return NO;
244 }
245
246 QAccessibleActionInterface *action = iface->actionInterface();
247 if (!action)
248 return NO;
249 switch (direction) {
250 case UIAccessibilityScrollDirectionRight:
251 action->doAction(QAccessibleActionInterface::scrollRightAction());
252 return YES;
253 case UIAccessibilityScrollDirectionLeft:
254 action->doAction(QAccessibleActionInterface::scrollLeftAction());
255 return YES;
256 case UIAccessibilityScrollDirectionUp:
257 action->doAction(QAccessibleActionInterface::scrollUpAction());
258 return YES;
259 case UIAccessibilityScrollDirectionDown:
260 action->doAction(QAccessibleActionInterface::scrollDownAction());
261 return YES;
262 case UIAccessibilityScrollDirectionNext:
263 action->doAction(QAccessibleActionInterface::nextPageAction());
264 return YES;
265 case UIAccessibilityScrollDirectionPrevious:
266 action->doAction(QAccessibleActionInterface::previousPageAction());
267 return YES;
268 }
269 return NO;
270}
271
272@end
273
274#endif