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)
119 ? QCoreApplication::translate(ACCESSIBILITY_ELEMENT, AE_CHECKED).toNSString()
120 : QCoreApplication::translate(ACCESSIBILITY_ELEMENT, AE_UNCHECKED).toNSString();
123 QAccessibleValueInterface *val = iface->valueInterface();
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();
131 return [super accessibilityHint];
134- (CGRect)accessibilityFrame
136 QAccessibleInterface *iface = QAccessible::accessibleInterface(self.axid);
137 if (!iface || !iface->isValid()) {
138 qWarning() <<
"invalid accessible interface for: " << self.axid;
142 QRect rect = iface->rect();
143 return CGRectMake(rect.x(), rect.y(), rect.width(), rect.height());
146- (UIAccessibilityTraits)accessibilityTraits
148 UIAccessibilityTraits traits = UIAccessibilityTraitNone;
150 QAccessibleInterface *iface = QAccessible::accessibleInterface(self.axid);
151 if (!iface || !iface->isValid()) {
152 qWarning() <<
"invalid accessible interface for: " << self.axid;
155 QAccessible::State state = iface->state();
157 traits |= UIAccessibilityTraitNotEnabled;
159 if (state.searchEdit)
160 traits |= UIAccessibilityTraitSearchField;
163 traits |= UIAccessibilityTraitSelected;
165 const auto accessibleRole = iface->role();
166 if (accessibleRole == QAccessible::Button) {
167 traits |= UIAccessibilityTraitButton;
168 }
else if (accessibleRole == QAccessible::CheckBox
169 || accessibleRole == QAccessible::RadioButton) {
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;
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;
188 if (iface->valueInterface() && iface->role() != QAccessible::ProgressBar)
189 traits |= UIAccessibilityTraitAdjustable;
194- (BOOL)accessibilityActivate
196 QAccessibleInterface *iface = QAccessible::accessibleInterface(self.axid);
197 if (!iface || !iface->isValid()) {
198 qWarning() <<
"invalid accessible interface for: " << self.axid;
202 if (QAccessibleActionInterface *action = iface->actionInterface()) {
203 if (action->actionNames().contains(QAccessibleActionInterface::pressAction())) {
204 action->doAction(QAccessibleActionInterface::pressAction());
206 }
else if (action->actionNames().contains(QAccessibleActionInterface::showMenuAction())) {
207 action->doAction(QAccessibleActionInterface::showMenuAction());
214- (
void)accessibilityIncrement
216 QAccessibleInterface *iface = QAccessible::accessibleInterface(self.axid);
217 if (!iface || !iface->isValid()) {
218 qWarning() <<
"invalid accessible interface for: " << self.axid;
222 if (QAccessibleActionInterface *action = iface->actionInterface())
223 action->doAction(QAccessibleActionInterface::increaseAction());
226- (
void)accessibilityDecrement
228 QAccessibleInterface *iface = QAccessible::accessibleInterface(self.axid);
229 if (!iface || !iface->isValid()) {
230 qWarning() <<
"invalid accessible interface for: " << self.axid;
234 if (QAccessibleActionInterface *action = iface->actionInterface())
235 action->doAction(QAccessibleActionInterface::decreaseAction());
238- (BOOL)accessibilityScroll:(UIAccessibilityScrollDirection)direction
240 QAccessibleInterface *iface = QAccessible::accessibleInterface(self.axid);
241 if (!iface || !iface->isValid()) {
242 qWarning() <<
"invalid accessible interface for: " << self.axid;
246 QAccessibleActionInterface *action = iface->actionInterface();
250 case UIAccessibilityScrollDirectionRight:
251 action->doAction(QAccessibleActionInterface::scrollRightAction());
253 case UIAccessibilityScrollDirectionLeft:
254 action->doAction(QAccessibleActionInterface::scrollLeftAction());
256 case UIAccessibilityScrollDirectionUp:
257 action->doAction(QAccessibleActionInterface::scrollUpAction());
259 case UIAccessibilityScrollDirectionDown:
260 action->doAction(QAccessibleActionInterface::scrollDownAction());
262 case UIAccessibilityScrollDirectionNext:
263 action->doAction(QAccessibleActionInterface::nextPageAction());
265 case UIAccessibilityScrollDirectionPrevious:
266 action->doAction(QAccessibleActionInterface::previousPageAction());