7#if QT_CONFIG(accessibility)
9#include "private/qaccessiblecache_p.h"
10#include "private/qcore_mac_p.h"
11#include "uistrings_p.h"
12#include "qioswindow.h"
14#include <QtGui/private/qaccessiblebridgeutils_p.h>
16QT_NAMESPACE_ALIAS_OBJC_CLASS(QMacAccessibilityElement);
18@implementation QMacAccessibilityElement
20- (instancetype)initWithId:(QAccessible::Id)anId withAccessibilityContainer:(id)view
22 Q_ASSERT((
int)anId < 0);
23 self = [super initWithAccessibilityContainer:view];
30+ (instancetype)elementWithId:(QAccessible::Id)anId
36 QAccessibleCache *cache = QAccessibleCache::instance();
38 QMacAccessibilityElement *element = cache->elementForId(anId);
40 QWindow *window =
nullptr;
41 auto *iface = QAccessible::accessibleInterface(anId);
43 if ((window = iface->window()))
45 iface = iface->parent();
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))
54 qWarning() <<
"Could not create a11y element for" << iface
55 <<
"with window" << window
56 <<
"and platform window" << (window ? window->handle() :
nullptr);
66- (BOOL)isAccessibilityElement
71- (NSString*)accessibilityLabel
73 QAccessibleInterface *iface = QAccessible::accessibleInterface(self.axid);
74 if (!iface || !iface->isValid()) {
75 qWarning() <<
"invalid accessible interface for: " << self.axid;
79 return iface->text(QAccessible::Name).toNSString();
83- (NSString*)accessibilityIdentifier
85 QAccessibleInterface *iface = QAccessible::accessibleInterface(self.axid);
86 if (!iface || !iface->isValid()) {
87 qWarning() <<
"invalid accessible interface for: " << self.axid;
90 return QAccessibleBridgeUtils::accessibleId(iface).toNSString();
93- (NSString*)accessibilityHint
95 QAccessibleInterface *iface = QAccessible::accessibleInterface(self.axid);
96 if (!iface || !iface->isValid()) {
97 qWarning() <<
"invalid accessible interface for: " << self.axid;
100 return iface->text(QAccessible::Description).toNSString();
103- (NSString*)accessibilityValue
105 QAccessibleInterface *iface = QAccessible::accessibleInterface(self.axid);
106 if (!iface || !iface->isValid()) {
107 qWarning() <<
"invalid accessible interface for: " << self.axid;
111 QAccessible::State state = iface->state();
113 if (state.checkable) {
114 if (iface->role() == QAccessible::CheckBox
115 || iface->role() == QAccessible::RadioButton)
118 if (iface->role() == QAccessible::Switch)
119 return state.checked ? @
"1" : @
"0";
122 ? QCoreApplication::translate(ACCESSIBILITY_ELEMENT, AE_CHECKED).toNSString()
123 : QCoreApplication::translate(ACCESSIBILITY_ELEMENT, AE_UNCHECKED).toNSString();
126 QAccessibleValueInterface *val = iface->valueInterface();
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();
134 return [super accessibilityHint];
137- (CGRect)accessibilityFrame
139 QAccessibleInterface *iface = QAccessible::accessibleInterface(self.axid);
140 if (!iface || !iface->isValid()) {
141 qWarning() <<
"invalid accessible interface for: " << self.axid;
145 QRect rect = iface->rect();
146 return CGRectMake(rect.x(), rect.y(), rect.width(), rect.height());
149- (UIAccessibilityTraits)accessibilityTraits
151 UIAccessibilityTraits traits = UIAccessibilityTraitNone;
153 QAccessibleInterface *iface = QAccessible::accessibleInterface(self.axid);
154 if (!iface || !iface->isValid()) {
155 qWarning() <<
"invalid accessible interface for: " << self.axid;
158 QAccessible::State state = iface->state();
160 traits |= UIAccessibilityTraitNotEnabled;
162 if (state.searchEdit)
163 traits |= UIAccessibilityTraitSearchField;
166 traits |= UIAccessibilityTraitSelected;
168 const auto accessibleRole = iface->role();
169 if (accessibleRole == QAccessible::Button) {
170 traits |= UIAccessibilityTraitButton;
171 }
else if (accessibleRole == QAccessible::CheckBox
172 || accessibleRole == QAccessible::RadioButton) {
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;
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;
193 if (iface->valueInterface() && iface->role() != QAccessible::ProgressBar)
194 traits |= UIAccessibilityTraitAdjustable;
199- (BOOL)accessibilityActivate
201 QAccessibleInterface *iface = QAccessible::accessibleInterface(self.axid);
202 if (!iface || !iface->isValid()) {
203 qWarning() <<
"invalid accessible interface for: " << self.axid;
207 if (QAccessibleActionInterface *action = iface->actionInterface()) {
208 if (action->actionNames().contains(QAccessibleActionInterface::pressAction())) {
209 action->doAction(QAccessibleActionInterface::pressAction());
211 }
else if (action->actionNames().contains(QAccessibleActionInterface::showMenuAction())) {
212 action->doAction(QAccessibleActionInterface::showMenuAction());
219- (
void)accessibilityIncrement
221 QAccessibleInterface *iface = QAccessible::accessibleInterface(self.axid);
222 if (!iface || !iface->isValid()) {
223 qWarning() <<
"invalid accessible interface for: " << self.axid;
227 if (QAccessibleActionInterface *action = iface->actionInterface())
228 action->doAction(QAccessibleActionInterface::increaseAction());
231- (
void)accessibilityDecrement
233 QAccessibleInterface *iface = QAccessible::accessibleInterface(self.axid);
234 if (!iface || !iface->isValid()) {
235 qWarning() <<
"invalid accessible interface for: " << self.axid;
239 if (QAccessibleActionInterface *action = iface->actionInterface())
240 action->doAction(QAccessibleActionInterface::decreaseAction());
243- (BOOL)accessibilityScroll:(UIAccessibilityScrollDirection)direction
245 QAccessibleInterface *iface = QAccessible::accessibleInterface(self.axid);
246 if (!iface || !iface->isValid()) {
247 qWarning() <<
"invalid accessible interface for: " << self.axid;
251 QAccessibleActionInterface *action = iface->actionInterface();
255 case UIAccessibilityScrollDirectionRight:
256 action->doAction(QAccessibleActionInterface::scrollRightAction());
258 case UIAccessibilityScrollDirectionLeft:
259 action->doAction(QAccessibleActionInterface::scrollLeftAction());
261 case UIAccessibilityScrollDirectionUp:
262 action->doAction(QAccessibleActionInterface::scrollUpAction());
264 case UIAccessibilityScrollDirectionDown:
265 action->doAction(QAccessibleActionInterface::scrollDownAction());
267 case UIAccessibilityScrollDirectionNext:
268 action->doAction(QAccessibleActionInterface::nextPageAction());
270 case UIAccessibilityScrollDirectionPrevious:
271 action->doAction(QAccessibleActionInterface::previousPageAction());