From 38e889924905564a5d9ff57a5f244ac9bfa175b4 Mon Sep 17 00:00:00 2001 From: Axel Spoerl Date: Wed, 14 Aug 2024 23:27:40 +0200 Subject: [PATCH] QCompleter: Forward mouse press/release to virtual keyboard When the list view of a QCompleter is visible, it receives mouse events. A mouse press event outside the completer hid it. If a virtual keyboard was active, it did not receive mouse press/release events in case the completer's list view was active. Add a helper to QGuiApplicationPrivate, that detects a virtual keyboard under a mouse event position, and forwards the event if needed. Adapt QCompleter::eventFilter() to use the helper. If a virtual keyboard one exists and a mouse press event occurs inside it, don't hide the completer and forward the event. Add handling of mouse release events, and also forward them to the virtual keyboard, using the helper. Add logging. Fixes: QTBUG-126752 Pick-to: 6.7 6.5 6.2 Change-Id: I613523a9c83b319810397770c43b2eb4ae01c31a Reviewed-by: Richard Moe Gustavsen (cherry picked from commit 93ce8f13fc8042eac976a3c911af7d7664e8d5dc) Reviewed-by: Christian Ehrlicher --- src/gui/kernel/qguiapplication.cpp | 54 ++++++++++++++++++++++++++++++ src/gui/kernel/qguiapplication_p.h | 6 ++++ src/widgets/util/qcompleter.cpp | 6 +++- 3 files changed, 65 insertions(+), 1 deletion(-) diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp index 013993b3f88..3030e11f253 100644 --- a/src/gui/kernel/qguiapplication.cpp +++ b/src/gui/kernel/qguiapplication.cpp @@ -108,6 +108,7 @@ QT_BEGIN_NAMESPACE Q_LOGGING_CATEGORY(lcPopup, "qt.gui.popup"); +Q_LOGGING_CATEGORY(lcVirtualKeyboard, "qt.gui.virtualkeyboard"); using namespace Qt::StringLiterals; using namespace QtMiscUtils; @@ -2109,6 +2110,59 @@ bool QGuiApplicationPrivate::processNativeEvent(QWindow *window, const QByteArra return window->nativeEvent(eventType, message, result); } +bool QGuiApplicationPrivate::isUsingVirtualKeyboard() +{ + static const bool usingVirtualKeyboard = getenv("QT_IM_MODULE") == QByteArray("qtvirtualkeyboard"); + return usingVirtualKeyboard; +} + +// If a virtual keyboard exists, forward mouse event +bool QGuiApplicationPrivate::maybeForwardEventToVirtualKeyboard(QEvent *e) +{ + if (!isUsingVirtualKeyboard()) { + qCDebug(lcVirtualKeyboard) << "Virtual keyboard not supported."; + return false; + } + + static QPointer virtualKeyboard; + const QEvent::Type type = e->type(); + Q_ASSERT(type == QEvent::MouseButtonPress || type == QEvent::MouseButtonRelease); + const auto me = static_cast(e); + const QPointF posF = me->globalPosition(); + const QPoint pos = posF.toPoint(); + + // Is there a visible virtual keyboard at event position? + if (!virtualKeyboard) { + if (QWindow *win = QGuiApplication::topLevelAt(pos); + win->inherits("QtVirtualKeyboard::InputView")) { + virtualKeyboard = win; + } else { + qCDebug(lcVirtualKeyboard) << "Virtual keyboard supported, but inactive."; + return false; + } + } + + Q_ASSERT(virtualKeyboard); + const bool virtualKeyboardUnderMouse = virtualKeyboard->isVisible() + && virtualKeyboard->geometry().contains(pos); + + if (!virtualKeyboardUnderMouse) { + qCDebug(lcVirtualKeyboard) << type << "at" << pos << "is outside geometry" + << virtualKeyboard->geometry() << "of" << virtualKeyboard.data(); + return false; + } + + QMouseEvent vkbEvent(type, virtualKeyboard->mapFromGlobal(pos), pos, + me->button(), me->buttons(), me->modifiers(), + me->pointingDevice()); + + QGuiApplication::sendEvent(virtualKeyboard, &vkbEvent); + qCDebug(lcVirtualKeyboard) << "Forwarded" << type << "to" << virtualKeyboard.data() + << "at" << pos; + + return true; +} + void Q_TRACE_INSTRUMENT(qtgui) QGuiApplicationPrivate::processWindowSystemEvent(QWindowSystemInterfacePrivate::WindowSystemEvent *e) { Q_TRACE_PARAM_REPLACE(QWindowSystemInterfacePrivate::WindowSystemEvent *, int); diff --git a/src/gui/kernel/qguiapplication_p.h b/src/gui/kernel/qguiapplication_p.h index 81f616e773c..45eac1c2654 100644 --- a/src/gui/kernel/qguiapplication_p.h +++ b/src/gui/kernel/qguiapplication_p.h @@ -40,6 +40,9 @@ QT_BEGIN_NAMESPACE +Q_DECLARE_LOGGING_CATEGORY(lcPopup) +Q_DECLARE_LOGGING_CATEGORY(lcVirtualKeyboard) + class QColorTrcLut; class QPlatformIntegration; class QPlatformTheme; @@ -165,6 +168,9 @@ public: static bool sendQWindowEventToQPlatformWindow(QWindow *window, QEvent *event); + static bool maybeForwardEventToVirtualKeyboard(QEvent *e); + static bool isUsingVirtualKeyboard(); + static inline Qt::Alignment visualAlignment(Qt::LayoutDirection direction, Qt::Alignment alignment) { if (!(alignment & Qt::AlignHorizontal_Mask)) diff --git a/src/widgets/util/qcompleter.cpp b/src/widgets/util/qcompleter.cpp index 21612ad6d16..bc965806dec 100644 --- a/src/widgets/util/qcompleter.cpp +++ b/src/widgets/util/qcompleter.cpp @@ -1463,12 +1463,16 @@ bool QCompleter::eventFilter(QObject *o, QEvent *e) } #endif if (!d->popup->underMouse()) { - d->popup->hide(); + if (!QGuiApplicationPrivate::maybeForwardEventToVirtualKeyboard(e)) + d->popup->hide(); return true; } } return false; + case QEvent::MouseButtonRelease: + QGuiApplicationPrivate::maybeForwardEventToVirtualKeyboard(e); + return true; case QEvent::InputMethod: case QEvent::ShortcutOverride: QCoreApplication::sendEvent(d->widget, e);