diff options
author | Volker Hilsheimer <volker.hilsheimer@qt.io> | 2021-10-16 13:18:04 +0200 |
---|---|---|
committer | Qt Cherry-pick Bot <cherrypick_bot@qt-project.org> | 2021-11-03 19:05:11 +0000 |
commit | 2b84f3b13688164510126bde60d16d46cc7e57cf (patch) | |
tree | 27003fe4535d53726ccf6b0ab3b5e041e2fe5718 | |
parent | 7fe94a079ba9931060f1c1d488b09e5432798a4c (diff) |
Use a containment mask to keep input panel working during modal session
Instead of reparenting the input panel to be on top of the overlay as
introduced in 4e8b3dd45ae4cc66a1b77cce901f80406b2a0f69, set a the input
context as a containment mask on the dimmer that is modally blocking the
UI elements underneath the overlay.
Since modality is a Qt Quick Control concept that doesn't exist in Qt
Quick, we have to use the dynamic property through which the dimmer
registers itself within the item hierarchy. If called, the contains()
implementation then lets all input events through that occur within the
rectangles occupied by the virtual keyboard.
Remove the documentation about the reparenting during modal sessions,
we no longer have to do that.
[ChangeLog][QtVirtualKeyboard][InputPanel] Since Qt 5.15, the virtual
keyboard's input panel has automatically been reparented to prevent the
keyboard UI from being blocked by modal dialogs. This is no longer
done; the input panel instead uses a containment mask on the dimmer
item that blocks input during modal sessions, allowing clicks through
to the keyboard UI.
Task-number: QTBUG-97075
Task-number: QTBUG-56918
Task-number: QTBUG-92881
Change-Id: I2627a4602913e29233778ed190b44a1ce47f5259
Reviewed-by: Jarkko Koivikko <jarkko.koivikko@code-q.fi>
(cherry picked from commit 1129af130964c5e0f2db6e8a6fb6dc2fe70f3bc8)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
-rw-r--r-- | src/virtualkeyboard/qvirtualkeyboardinputcontext_p.cpp | 52 | ||||
-rw-r--r-- | src/virtualkeyboard/qvirtualkeyboardinputcontext_p.h | 5 |
2 files changed, 39 insertions, 18 deletions
diff --git a/src/virtualkeyboard/qvirtualkeyboardinputcontext_p.cpp b/src/virtualkeyboard/qvirtualkeyboardinputcontext_p.cpp index 4324ffe7..96d80d68 100644 --- a/src/virtualkeyboard/qvirtualkeyboardinputcontext_p.cpp +++ b/src/virtualkeyboard/qvirtualkeyboardinputcontext_p.cpp @@ -270,6 +270,29 @@ void QVirtualKeyboardInputContextPrivate::forceCursorPosition(int anchorPosition } } +/*! \internal + The context private becomes a containment mask for a dimmer opened by a + modal QQuickPopup. The dimmer eats events, and the virtual keyboard must + continue to work during modal sessions as well. This implementation lets + all pointer events within the area of the input panel through. +*/ +bool QVirtualKeyboardInputContextPrivate::contains(const QPointF &point) const +{ + bool hit = false; + if (dimmer) { + const auto scenePoint = dimmer->mapToScene(point); + if (keyboardRectangle().contains(scenePoint)) { + hit = true; + } else if (QQuickItem *vkbPanel = qobject_cast<QQuickItem*>(inputPanel)) { + const auto vkbPanelPoint = vkbPanel->mapFromScene(scenePoint); + if (vkbPanel->contains(vkbPanelPoint)) + hit = true; + } + } + // dimmer doesn't contain points that hit the input panel + return !hit; +} + void QVirtualKeyboardInputContextPrivate::onInputItemChanged() { QObject *item = inputItem(); @@ -277,25 +300,22 @@ void QVirtualKeyboardInputContextPrivate::onInputItemChanged() if (QQuickItem *vkbPanel = qobject_cast<QQuickItem*>(inputPanel)) { if (QQuickItem *quickItem = qobject_cast<QQuickItem*>(item)) { const QVariant isDesktopPanel = vkbPanel->property("desktopPanel"); - /* - For integrated keyboards, make sure it's a sibling to the overlay. The - high z-order will make sure it gets events also during a modal session. - */ if (isDesktopPanel.isValid() && !isDesktopPanel.toBool()) { + // Integrated keyboards used in a Qt Quick Controls UI must continue to + // work during a modal session, which is implemented using an overlay + // and dimmer item. So, make use of some QQC2 internals to find out if + // there is a dimmer, and if so, make ourselves the containment mask + // that can let pointer events through to the keyboard. if (QQuickWindow *quickWindow = quickItem->window()) { - QQuickItem *overlay = quickWindow->property("_q_QQuickOverlay").value<QQuickItem*>(); - if (overlay && overlay->isVisible()) { - if (vkbPanel->parentItem() != overlay->parentItem()) { - inputPanelParentItem = vkbPanel->parentItem(); - inputPanelZ = vkbPanel->z(); - vkbPanel->setParentItem(overlay->parentItem()); - vkbPanel->setZ(overlay->z() + 1); + if (QQuickItem *overlay = quickWindow->property("_q_QQuickOverlay").value<QQuickItem*>()) { + if (dimmer && dimmer->containmentMask() == this) { + dimmer->setContainmentMask(nullptr); + dimmer = nullptr; } - } else { - if (QQuickItem *oldParentItem = qobject_cast<QQuickItem *>(inputPanelParentItem.data())) { - vkbPanel->setParentItem(oldParentItem); - vkbPanel->setZ(inputPanelZ); - inputPanelParentItem = nullptr; + if (overlay && overlay->isVisible()) { + dimmer = overlay->property("_q_dimmerItem").value<QQuickItem*>(); + if (dimmer) + dimmer->setContainmentMask(this); } } } diff --git a/src/virtualkeyboard/qvirtualkeyboardinputcontext_p.h b/src/virtualkeyboard/qvirtualkeyboardinputcontext_p.h index ab2698d5..b8258294 100644 --- a/src/virtualkeyboard/qvirtualkeyboardinputcontext_p.h +++ b/src/virtualkeyboard/qvirtualkeyboardinputcontext_p.h @@ -45,6 +45,7 @@ #include <QRectF> #include <QSet> #include <QInputMethodEvent> +#include <QQuickItem> #include <QtVirtualKeyboard/qvirtualkeyboardinputcontext.h> #include <QtVirtualKeyboard/private/shadowinputcontext_p.h> #include <QtVirtualKeyboard/qvirtualkeyboardobserver.h> @@ -117,6 +118,7 @@ public: Q_INVOKABLE bool fileExists(const QUrl &fileUrl); Q_INVOKABLE bool hasEnterKeyAction(QObject *item) const; Q_INVOKABLE void registerInputPanel(QObject *inputPanel); + Q_INVOKABLE bool contains(const QPointF &point) const; Q_SIGNALS: void focusChanged(); @@ -158,8 +160,7 @@ private: QVirtualKeyboardInputEngine *inputEngine; QtVirtualKeyboard::ShiftHandler *_shiftHandler; QPointer<QObject> inputPanel; - QPointer<QObject> inputPanelParentItem; - qreal inputPanelZ = .0; + QPointer<QQuickItem> dimmer; QRectF keyboardRect; QRectF previewRect; bool _previewVisible; |