diff options
author | Oliver Eftevaag <[email protected]> | 2024-05-07 13:24:37 +0200 |
---|---|---|
committer | Oliver Eftevaag <[email protected]> | 2024-05-29 14:01:24 +0200 |
commit | 2393c588bc9a5368c013952a4fb195c5b4017543 (patch) | |
tree | 1e29ba686b1faf9853fabf3fb7d77beec78f36cf | |
parent | 523b6a5eb0aef0e4b0ca86eca99161c2e9619871 (diff) |
Forward keyboard events to the active popup window
Popup windows will never become the focus window of the application.
Meaning that window system events will be send directly to the "main"
window, and then forwarded to any potential popup windows, if any.
But since popup windows don't become "active", they won't receive the
focus in event, and thus never call setFocus on their contentItem.
This could cause setFocusInScope() to skip assigning the activeFocusItem
to be the new focus item. Effectively breaking keyboard navigation for
things like menus that are inside a menubar.
Change-Id: Id1345aee09ed4dd31017781f5e0e6f5f925551e6
Reviewed-by: Richard Moe Gustavsen <[email protected]>
3 files changed, 42 insertions, 1 deletions
diff --git a/src/quick/util/qquickdeliveryagent.cpp b/src/quick/util/qquickdeliveryagent.cpp index 34032d4801..ed2112fa0d 100644 --- a/src/quick/util/qquickdeliveryagent.cpp +++ b/src/quick/util/qquickdeliveryagent.cpp @@ -428,7 +428,7 @@ void QQuickDeliveryAgentPrivate::setFocusInScope(QQuickItem *scope, QQuickItem * } } - if (newActiveFocusItem && rootItem->hasFocus()) { + if (newActiveFocusItem && (rootItem->hasFocus() || (rootItem->window()->type() == Qt::Popup))) { activeFocusItem = newActiveFocusItem; QQuickItemPrivate::get(newActiveFocusItem)->activeFocus = true; diff --git a/tests/auto/quickcontrols/qquickpopup/data/popupWindowFocusHandling.qml b/tests/auto/quickcontrols/qquickpopup/data/popupWindowFocusHandling.qml index 60033d34a3..1477db047e 100644 --- a/tests/auto/quickcontrols/qquickpopup/data/popupWindowFocusHandling.qml +++ b/tests/auto/quickcontrols/qquickpopup/data/popupWindowFocusHandling.qml @@ -19,6 +19,7 @@ Window { Popup { id: simplepopup + popupType: Popup.Window TextField { id: innerTextField focus: true diff --git a/tests/auto/quickcontrols/qquickpopup/tst_qquickpopup.cpp b/tests/auto/quickcontrols/qquickpopup/tst_qquickpopup.cpp index 8b9e8aa976..f5a4212d91 100644 --- a/tests/auto/quickcontrols/qquickpopup/tst_qquickpopup.cpp +++ b/tests/auto/quickcontrols/qquickpopup/tst_qquickpopup.cpp @@ -120,6 +120,7 @@ private slots: void popupWindowModality(); void popupWindowClosesOnParentWindowClosing(); void popupWindowChangingParent(); + void popupWindowFocus(); private: QScopedPointer<QPointingDevice> touchScreen = QScopedPointer<QPointingDevice>(QTest::createTouchDevice()); @@ -2639,6 +2640,45 @@ void tst_QQuickPopup::popupWindowChangingParent() VERIFY_LOCAL_POS(popup, initialPos); } +void tst_QQuickPopup::popupWindowFocus() +{ + QSKIP("Enable this test once the PopupType property has been merged"); + QQuickApplicationHelper helper(this, "popupWindowFocusHandling.qml"); + QVERIFY2(helper.ready, helper.failureMessage()); + QQuickWindow *window = helper.window; + QVERIFY(window); + auto *popup = window->contentItem()->findChild<QQuickPopup *>(); + QVERIFY(popup); + auto *popupPrivate = QQuickPopupPrivate::get(popup); + QVERIFY(popupPrivate); + QQuickTextInput *textField1 = window->property("textField1").value<QQuickTextInput *>(); + QVERIFY(textField1); + QQuickTextInput *textField2 = window->property("textField2").value<QQuickTextInput *>(); + QVERIFY(textField2); + if (!popupPrivate->usePopupWindow()) + QSKIP("The platform doesn't support native popup windows. Skipping test."); + + window->show(); + QVERIFY(QTest::qWaitForWindowFocused(window)); + QVERIFY(QGuiApplication::focusObject() == textField1); + QTest::keyClick(helper.window, Qt::Key_Q); + QTRY_COMPARE(textField1->text(), "q"); + popup->open(); + QTRY_VERIFY(popup->isVisible()); + auto *popupWindow = popupPrivate->popupWindow; + QVERIFY(popupWindow); + QVERIFY(popupWindow->isVisible()); + // The focusWindow should still be the main window, + // the popup window should get its event forwarded via the delivery agent + QVERIFY(QGuiApplication::focusWindow() == helper.window); + QVERIFY(popupWindow->focusObject() == textField2); + QTest::keyClick(popupWindow, Qt::Key_T); + QTRY_COMPARE(textField2->text(), "t"); + popup->close(); + QTRY_VERIFY(!popup->isVisible()); + QVERIFY(QGuiApplication::focusObject() == textField1); +} + QTEST_QUICKCONTROLS_MAIN(tst_QQuickPopup) #include "tst_qquickpopup.moc" |