aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMohammadHossein Qanbari <mohammad.qanbari@qt.io>2024-07-29 18:03:39 +0200
committerDoris Verria <doris.verria@qt.io>2024-10-01 21:13:51 +0200
commitfd1f8ea4e09cc0a3c007db462db35abbf92ef54d (patch)
tree4e811d6e44fb6e24b98abea91e4c978385c4e7fc /src
parentd37583094a73ca85151f07c4570db916424d7a94 (diff)
QQuickWidget: Assign focus to offscreen window when focus chain wraps
The focus did not move from QQuickWidget to sibling widgets. Additionally, when focus moved to QQuickWidget via tab/backtab key events, the item that was focused before the focus moved out was refocused. This is expected when the focus reason is not tab or backtab. In such cases, it is expected that the first/last item should be focused due to tab/backtab focus reasons. To address this issue, QQuickWidget checks the next/previous candidate in its child items through the focusNextPrevChild() method. If QQuickWidget cannot find any candidates, it should behave like a QWidget. Otherwise, it simulates a tab/backtab focus event for the offscreen window (QQuickWindow) to determine which item should be focused. The test case demonstrates a window containing a QQuickWidget with three rectangle items, a middle widget, and another QQuickWidget with three rectangle items. It then sends some Tab and Backtab events and verifies that the expected order of items and widgets is followed. The expected order varies depending on the direction of focus change (forward if the Tab key is pressed and backward if the Backtab key is pressed). [ChangeLog][QtQuick][QQuickWidget] The first/last item must be focused when QQuickWidget receives a focus-in event due to tab/backtab reasons. In other cases, such as ActiveWindowFocusReason, the item that was focused before will be refocused. Pick-to: 6.8 Change-Id: Ie25e6c2c46e20e15a5db014e0054b8b9da2d8a21 Reviewed-by: Doris Verria <doris.verria@qt.io>
Diffstat (limited to 'src')
-rw-r--r--src/quickwidgets/qquickwidget.cpp43
1 files changed, 37 insertions, 6 deletions
diff --git a/src/quickwidgets/qquickwidget.cpp b/src/quickwidgets/qquickwidget.cpp
index d3f7e52bb6..4c5c25f455 100644
--- a/src/quickwidgets/qquickwidget.cpp
+++ b/src/quickwidgets/qquickwidget.cpp
@@ -1471,15 +1471,28 @@ void QQuickWidget::resizeEvent(QResizeEvent *e)
bool QQuickWidget::focusNextPrevChild(bool next)
{
Q_D(QQuickWidget);
- QKeyEvent event(QEvent::KeyPress, next ? Qt::Key_Tab : Qt::Key_Backtab, Qt::NoModifier);
- Q_QUICK_INPUT_PROFILE(QQuickProfiler::Key, QQuickProfiler::InputKeyPress, event.key(),
- Qt::NoModifier);
+
+ const auto *da = QQuickWindowPrivate::get(d->offscreenWindow)->deliveryAgentPrivate();
+ Q_ASSERT(da);
+
+ auto *currentTarget = da->focusTargetItem();
+ Q_ASSERT(currentTarget);
+
+ auto *nextTarget = QQuickItemPrivate::nextPrevItemInTabFocusChain(currentTarget, next, false);
+ // If no child to focus, behaves like its base class (QWidget)
+ if (!nextTarget)
+ return QWidget::focusNextPrevChild(next);
+
+ // Otherwise, simulates focus event for the offscreen window (QQuickWindow)
+ const Qt::Key k = next ? Qt::Key_Tab : Qt::Key_Backtab;
+ QKeyEvent event(QEvent::KeyPress, k, Qt::NoModifier);
+ Q_QUICK_INPUT_PROFILE(QQuickProfiler::Key, QQuickProfiler::InputKeyPress, k, Qt::NoModifier);
QCoreApplication::sendEvent(d->offscreenWindow, &event);
- QKeyEvent releaseEvent(QEvent::KeyRelease, next ? Qt::Key_Tab : Qt::Key_Backtab, Qt::NoModifier);
- Q_QUICK_INPUT_PROFILE(QQuickProfiler::Key, QQuickProfiler::InputKeyRelease, releaseEvent.key(),
- Qt::NoModifier);
+ QKeyEvent releaseEvent(QEvent::KeyRelease, k, Qt::NoModifier);
+ Q_QUICK_INPUT_PROFILE(QQuickProfiler::Key, QQuickProfiler::InputKeyRelease, k, Qt::NoModifier);
QCoreApplication::sendEvent(d->offscreenWindow, &releaseEvent);
+
return event.isAccepted();
}
@@ -1636,6 +1649,24 @@ void QQuickWidget::wheelEvent(QWheelEvent *e)
void QQuickWidget::focusInEvent(QFocusEvent * event)
{
Q_D(QQuickWidget);
+
+ using FocusTarget = QWindowPrivate::FocusTarget;
+ const Qt::FocusReason reason = event->reason();
+
+ switch (reason) {
+ // if there has been an item focused:
+ // set the first item focused, when the reason is TabFocusReason
+ // set the last item focused, when the reason is BacktabFocusReason
+ case Qt::TabFocusReason:
+ case Qt::BacktabFocusReason: {
+ const bool forward = reason == Qt::FocusReason::TabFocusReason;
+ const FocusTarget target = forward ? FocusTarget::First : FocusTarget::Last;
+ QQuickWindowPrivate::get(d->offscreenWindow)->setFocusToTarget(target, reason);
+ } break;
+ default:
+ break;
+ }
+
d->offscreenWindow->focusInEvent(event);
}