From f16d690a2f8c6ff1830a15794950c8564ae18a29 Mon Sep 17 00:00:00 2001 From: Frederik Gladhorn Date: Wed, 26 Mar 2014 10:14:45 +0100 Subject: Accessibility Mac: Fix handling of top level widget MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This simplifies how we handle QNSView for accessibility purposes. Instead of trying to half-merge the top level widget (window->accessibleRoot) into the view, just have the view always return it as child. This makes the accessibility implementation for QNSView simpler and makes applications that show a top level widget such as a button possible. (We would return accessibility ignored for the button before). As a side effect finding the active focus and hit-testing should be more reliable as well. Task-number: QTBUG-37794 Change-Id: Ib52037f88da8887a0bdc77204b0f3daddfe7709d Reviewed-by: Morten Johan Sørvig Reviewed-by: Jan Arve Sæther --- .../qaccessibilitymac/tst_qaccessibilitymac.cpp | 20 +++++- .../tst_qaccessibilitymac_helpers.h | 3 +- .../tst_qaccessibilitymac_helpers.mm | 83 ++++++++++++++++++---- 3 files changed, 91 insertions(+), 15 deletions(-) (limited to 'tests') diff --git a/tests/auto/other/qaccessibilitymac/tst_qaccessibilitymac.cpp b/tests/auto/other/qaccessibilitymac/tst_qaccessibilitymac.cpp index 25dd0d39dd..25b47ee836 100644 --- a/tests/auto/other/qaccessibilitymac/tst_qaccessibilitymac.cpp +++ b/tests/auto/other/qaccessibilitymac/tst_qaccessibilitymac.cpp @@ -79,6 +79,7 @@ private slots: void init(); void cleanup(); + void singleWidgetTest(); void lineEditTest(); void hierarchyTest(); private: @@ -101,6 +102,16 @@ void tst_QAccessibilityMac::cleanup() delete m_window; } +void tst_QAccessibilityMac::singleWidgetTest() +{ + if (!macNativeAccessibilityEnabled()) + return; + + delete m_window; + m_window = 0; + + QVERIFY(singleWidget()); +} void tst_QAccessibilityMac::lineEditTest() { @@ -122,14 +133,19 @@ void tst_QAccessibilityMac::hierarchyTest() QWidget *w = new QWidget(m_window); m_window->addWidget(w); - QPushButton *b = new QPushButton(w); + w->setLayout(new QVBoxLayout()); + QPushButton *b = new QPushButton(w); w->layout()->addWidget(b); b->setText("I am a button"); + QPushButton *b2 = new QPushButton(w); + w->layout()->addWidget(b2); + b2->setText("Button 2"); + QVERIFY(QTest::qWaitForWindowExposed(m_window)); QCoreApplication::processEvents(); - QVERIFY(testHierarchy()); + QVERIFY(testHierarchy(w)); } QTEST_MAIN(tst_QAccessibilityMac) diff --git a/tests/auto/other/qaccessibilitymac/tst_qaccessibilitymac_helpers.h b/tests/auto/other/qaccessibilitymac/tst_qaccessibilitymac_helpers.h index ec5beab125..635b6383ab 100644 --- a/tests/auto/other/qaccessibilitymac/tst_qaccessibilitymac_helpers.h +++ b/tests/auto/other/qaccessibilitymac/tst_qaccessibilitymac_helpers.h @@ -48,4 +48,5 @@ bool macNativeAccessibilityEnabled(); bool trusted(); bool testLineEdit(); -bool testHierarchy(); +bool testHierarchy(QWidget *w); +bool singleWidget(); diff --git a/tests/auto/other/qaccessibilitymac/tst_qaccessibilitymac_helpers.mm b/tests/auto/other/qaccessibilitymac/tst_qaccessibilitymac_helpers.mm index 8620b7dd2f..bc89ac858b 100644 --- a/tests/auto/other/qaccessibilitymac/tst_qaccessibilitymac_helpers.mm +++ b/tests/auto/other/qaccessibilitymac/tst_qaccessibilitymac_helpers.mm @@ -43,8 +43,10 @@ #define QT_NO_KEYWORDS #include "tst_qaccessibilitymac_helpers.h" -#include -#include +#include +#include +#include +#include #include #import @@ -148,9 +150,41 @@ bool trusted() return p; } ++ (TestAXObject *) getApplicationAXObject +{ + pid_t pid = getpid(); + AXUIElementRef appRef = AXUIElementCreateApplication(pid); + TestAXObject *appObject = [[TestAXObject alloc] initWithAXUIElementRef: appRef]; + return appObject; +} + @end +bool singleWidget() +{ + QLineEdit le; + le.setText("button"); + le.show(); + EXPECT(QTest::qWaitForWindowExposed(&le)); + QCoreApplication::processEvents(); + + TestAXObject *appObject = [TestAXObject getApplicationAXObject]; + EXPECT(appObject); + + NSArray *windows = [appObject windowList]; + EXPECT([windows count] == 1); + + AXUIElementRef windowRef = (AXUIElementRef) [windows objectAtIndex: 0]; + EXPECT(windowRef != nil); + TestAXObject *window = [[TestAXObject alloc] initWithAXUIElementRef: windowRef]; + + AXUIElementRef lineEdit = [window findDirectChildByRole: kAXTextFieldRole]; + EXPECT(lineEdit != nil); + + return true; +} + bool testLineEdit() { // not sure if this is needed. on my machine the calls succeed. @@ -159,10 +193,8 @@ bool testLineEdit() // AXError e = AXMakeProcessTrusted((CFStringRef) path); // NSLog(@"error: %i", e); - pid_t pid = getpid(); - AXUIElementRef app = AXUIElementCreateApplication(pid); - EXPECT(app != nil); - TestAXObject *appObject = [[TestAXObject alloc] initWithAXUIElementRef: app]; + TestAXObject *appObject = [TestAXObject getApplicationAXObject]; + EXPECT(appObject); NSArray *windowList = [appObject windowList]; // one window @@ -184,12 +216,10 @@ bool testLineEdit() return true; } -bool testHierarchy() +bool testHierarchy(QWidget *w) { - pid_t pid = getpid(); - AXUIElementRef app = AXUIElementCreateApplication(pid); - EXPECT(app != nil); - TestAXObject *appObject = [[TestAXObject alloc] initWithAXUIElementRef: app]; + TestAXObject *appObject = [TestAXObject getApplicationAXObject]; + EXPECT(appObject); NSArray *windowList = [appObject windowList]; // one window @@ -207,7 +237,36 @@ bool testHierarchy() TestAXObject *parentObject = [[TestAXObject alloc] initWithAXUIElementRef: [buttonObject parent]]; // check that the parent is a window - EXPECT([[parentObject role] isEqualToString: (NSString *)kAXWindowRole]); + EXPECT([[parentObject role] isEqualToString: NSAccessibilityWindowRole]); + + // test the focus + // child 0 is the layout, then button1 and 2 + QPushButton *button1 = qobject_cast(w->children().at(1)); + EXPECT(button1); + QPushButton *button2 = qobject_cast(w->children().at(2)); + EXPECT(button2); + button2->setFocus(); + + AXUIElementRef systemWideElement = AXUIElementCreateSystemWide(); + AXUIElementRef focussedElement = NULL; + AXError error = AXUIElementCopyAttributeValue(systemWideElement, + (CFStringRef)NSAccessibilityFocusedUIElementAttribute, (CFTypeRef*)&focussedElement); + EXPECT(!error); + EXPECT(focussedElement); + TestAXObject *focusButton2 = [[TestAXObject alloc] initWithAXUIElementRef: focussedElement]; + + EXPECT([[focusButton2 role] isEqualToString: NSAccessibilityButtonRole]); + EXPECT([[focusButton2 description] isEqualToString: @"Button 2"]); + + + button1->setFocus(); + error = AXUIElementCopyAttributeValue(systemWideElement, + (CFStringRef)NSAccessibilityFocusedUIElementAttribute, (CFTypeRef*)&focussedElement); + EXPECT(!error); + EXPECT(focussedElement); + TestAXObject *focusButton1 = [[TestAXObject alloc] initWithAXUIElementRef: focussedElement]; + EXPECT([[focusButton1 role] isEqualToString: NSAccessibilityButtonRole]); + EXPECT([[focusButton1 description] isEqualToString: @"I am a button"]); return true; } -- cgit v1.2.3