Skip to content

Commit

Permalink
iOS: Propagate focus changes to VoiceOver
Browse files Browse the repository at this point in the history
Changing the focus object should update the VoiceOver focused element,
the same way we do it on macOS.

There's no NSAccessibilityFocusedUIElementChangedNotification on iOS,
but we can pass the focused element as an argument when posting the
UIAccessibilityLayoutChangedNotification.

The class method on QMacAccessibilityElement to get an element for
an QAccessible::Id was not used by any callers, and has been modified
to resolve the container from the QAccessibleInterface, so that we
don't need to plumb that all the way from the focus change event.

Inspired-by: Jan Möller <jan.moeller@governikus.de>
Fixes: QTBUG-114608
Pick-to: 6.5
Change-Id: I2e43ae649bc7e3a44c1e1200e8de66bf420b1949
Reviewed-by: Lars Schmertmann <lars.schmertmann@governikus.de>
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
(cherry picked from commit 7a512d1)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
(cherry picked from commit 1c8cb94)
  • Loading branch information
torarnv authored and Qt Cherry-pick Bot committed Feb 16, 2024
1 parent f2c016c commit 6e434de
Show file tree
Hide file tree
Showing 5 changed files with 31 additions and 5 deletions.
11 changes: 11 additions & 0 deletions src/plugins/platforms/ios/qiosplatformaccessibility.mm
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

#include <QtGui/QtGui>
#include "qioswindow.h"
#include "quiaccessibilityelement.h"

QIOSPlatformAccessibility::QIOSPlatformAccessibility()
{}
Expand Down Expand Up @@ -40,6 +41,16 @@ void invalidateCache(QAccessibleInterface *iface)
if (!isActive() || !accessibleInterface)
return;
switch (event->type()) {
case QAccessible::Focus: {
auto *element = [QMacAccessibilityElement elementWithId:event->uniqueId()];
Q_ASSERT(element);
// There's no NSAccessibilityFocusedUIElementChangedNotification, like we have on
// macOS. Instead, the documentation for UIAccessibilityLayoutChangedNotification
// specifies that the optional argument to UIAccessibilityPostNotification is the
// accessibility element for VoiceOver to move to after processing the notification.
UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, element);
break;
}
case QAccessible::ObjectCreated:
case QAccessible::ObjectShow:
case QAccessible::ObjectHide:
Expand Down
1 change: 1 addition & 0 deletions src/plugins/platforms/ios/qioswindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ class QIOSWindow : public QObject, public QPlatformWindow
#endif

bool isForeignWindow() const override;
UIView *view() const;

private:
void applicationStateChanged(Qt::ApplicationState state);
Expand Down
5 changes: 5 additions & 0 deletions src/plugins/platforms/ios/qioswindow.mm
Original file line number Diff line number Diff line change
Expand Up @@ -456,6 +456,11 @@
return ![m_view isKindOfClass:QUIView.class];
}

UIView *QIOSWindow::view() const
{
return m_view;
}

QT_END_NAMESPACE

#include "moc_qioswindow.cpp"
2 changes: 1 addition & 1 deletion src/plugins/platforms/ios/quiaccessibilityelement.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
@property (readonly) QAccessible::Id axid;

- (instancetype)initWithId:(QAccessible::Id)anId withAccessibilityContainer:(id)view;
+ (instancetype)elementWithId:(QAccessible::Id)anId withAccessibilityContainer:(id)view;
+ (instancetype)elementWithId:(QAccessible::Id)anId;

@end

Expand Down
17 changes: 13 additions & 4 deletions src/plugins/platforms/ios/quiaccessibilityelement.mm
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "private/qaccessiblecache_p.h"
#include "private/qcore_mac_p.h"
#include "uistrings_p.h"
#include "qioswindow.h"

QT_NAMESPACE_ALIAS_OBJC_CLASS(QMacAccessibilityElement);

Expand All @@ -23,7 +24,7 @@ - (instancetype)initWithId:(QAccessible::Id)anId withAccessibilityContainer:(id)
return self;
}

+ (instancetype)elementWithId:(QAccessible::Id)anId withAccessibilityContainer:(id)view
+ (instancetype)elementWithId:(QAccessible::Id)anId
{
Q_ASSERT(anId);
if (!anId)
Expand All @@ -33,9 +34,17 @@ + (instancetype)elementWithId:(QAccessible::Id)anId withAccessibilityContainer:(

QMacAccessibilityElement *element = cache->elementForId(anId);
if (!element) {
Q_ASSERT(QAccessible::accessibleInterface(anId));
element = [[self alloc] initWithId:anId withAccessibilityContainer:view];
cache->insertElement(anId, element);
auto *a11yInterface = QAccessible::accessibleInterface(anId);
Q_ASSERT(a11yInterface);
auto *window = a11yInterface->window();
if (window && window->handle()) {
auto *platformWindow = static_cast<QIOSWindow*>(window->handle());
element = [[self alloc] initWithId:anId withAccessibilityContainer:platformWindow->view()];
cache->insertElement(anId, element);
} else {
qWarning() << "Could not create a11y element for" << window
<< "with platform window" << (window ? window->handle() : nullptr);
}
}
return element;
}
Expand Down

0 comments on commit 6e434de

Please sign in to comment.