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 <richard.gustavsen@qt.io>
(cherry picked from commit 93ce8f13fc8042eac976a3c911af7d7664e8d5dc)
Reviewed-by: Christian Ehrlicher <ch.ehrlicher@gmx.de>
This commit is contained in:
Axel Spoerl 2024-08-14 23:27:40 +02:00
parent 9c032ad5fe
commit 38e8899249
3 changed files with 65 additions and 1 deletions

View File

@ -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<QWindow> virtualKeyboard;
const QEvent::Type type = e->type();
Q_ASSERT(type == QEvent::MouseButtonPress || type == QEvent::MouseButtonRelease);
const auto me = static_cast<QMouseEvent *>(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);

View File

@ -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))

View File

@ -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);