From e259e5b9c5540bfa4fa28928eb3e72d5b82be9b0 Mon Sep 17 00:00:00 2001 From: Axel Spoerl Date: Mon, 15 Apr 2024 10:42:00 +0200 Subject: [PATCH] Android: Detect mouse buttons The mouseDown() and mouseUp() methods in androidjniinput.cpp hardcoded Qt::LeftButton to all mouse-press / release events. If a mouse is connected to an android device, all three buttons are mapped to the left button. Extend both mehtods' signature by a mouse button state. Add a converter method to map from Android button states to Qt::MouseButtons. Add a sendMouseButtonEvents method, that iterates through all buttons pressed/released and sends the respective events to QWSI. Adapt the mouse handler in java, to obtain and pass the button state to C++. The patch can't be verified in an autotest. Testlib's mouse emulation injects into QWSI. Fixes: QTBUG-99106 Pick-to: 6.6 6.5 6.2 Change-Id: I933f490901928db9761d2ef254ae1e5b4f473f28 Reviewed-by: Assam Boudjelthia (cherry picked from commit 8d8cbe87e21f05b7d611ed4be47299977288b267) Reviewed-by: Qt Cherry-pick Bot --- .../qtproject/qt/android/QtInputDelegate.java | 8 +- .../platforms/android/androidjniinput.cpp | 86 ++++++++++++++++--- 2 files changed, 79 insertions(+), 15 deletions(-) diff --git a/src/android/jar/src/org/qtproject/qt/android/QtInputDelegate.java b/src/android/jar/src/org/qtproject/qt/android/QtInputDelegate.java index 5327049f444..fb7b69c0dd1 100644 --- a/src/android/jar/src/org/qtproject/qt/android/QtInputDelegate.java +++ b/src/android/jar/src/org/qtproject/qt/android/QtInputDelegate.java @@ -501,8 +501,8 @@ public class QtInputDelegate implements QtInputConnection.QtInputConnectionListe // tablet methods // pointer methods - public static native void mouseDown(int winId, int x, int y); - public static native void mouseUp(int winId, int x, int y); + public static native void mouseDown(int winId, int x, int y, int mouseButtonState); + public static native void mouseUp(int winId, int x, int y, int mouseButtonState); public static native void mouseMove(int winId, int x, int y); public static native void mouseWheel(int winId, int x, int y, float hDelta, float vDelta); public static native void touchBegin(int winId); @@ -618,11 +618,11 @@ public class QtInputDelegate implements QtInputConnection.QtInputConnectionListe { switch (event.getActionMasked()) { case MotionEvent.ACTION_UP: - mouseUp(id, (int) event.getX(), (int) event.getY()); + mouseUp(id, (int) event.getX(), (int) event.getY(), event.getButtonState()); break; case MotionEvent.ACTION_DOWN: - mouseDown(id, (int) event.getX(), (int) event.getY()); + mouseDown(id, (int) event.getX(), (int) event.getY(), event.getButtonState()); m_oldX = (int) event.getX(); m_oldY = (int) event.getY(); break; diff --git a/src/plugins/platforms/android/androidjniinput.cpp b/src/plugins/platforms/android/androidjniinput.cpp index 00e6b7ca51d..d074e73b9e5 100644 --- a/src/plugins/platforms/android/androidjniinput.cpp +++ b/src/plugins/platforms/android/androidjniinput.cpp @@ -28,6 +28,8 @@ Q_DECLARE_JNI_CLASS(QtLayout, "org/qtproject/qt/android/QtLayout") namespace QtAndroidInput { static bool m_ignoreMouseEvents = false; + static Qt::MouseButtons m_buttons = Qt::NoButton; + static QRect m_softwareKeyboardRect; static QList m_touchPoints; @@ -160,7 +162,72 @@ namespace QtAndroidInput anchor.x(), anchor.y(), rtl); } - static void mouseDown(JNIEnv */*env*/, jobject /*thiz*/, jint winId, jint x, jint y) + // from https://developer.android.com/reference/android/view/MotionEvent#getButtonState() + enum AndroidMouseButton { + BUTTON_PRIMARY = 0x00000001, + BUTTON_SECONDARY = 0x00000002, + BUTTON_TERTIARY = 0x00000004, + BUTTON_BACK = 0x00000008, + BUTTON_FORWARD = 0x00000010, + BUTTON_STYLUS_PRIMARY = 0x00000020, + BUTTON_STYLUS_SECONDARY = 0x00000040, + }; + Q_DECLARE_FLAGS(AndroidMouseButtons, AndroidMouseButton) + + static Qt::MouseButtons toMouseButtons(jint j_buttons) + { + const auto buttons = static_cast(j_buttons); + Qt::MouseButtons mouseButtons; + if (buttons.testFlag(BUTTON_PRIMARY)) + mouseButtons.setFlag(Qt::LeftButton); + + if (buttons.testFlag(BUTTON_SECONDARY)) + mouseButtons.setFlag(Qt::RightButton); + + if (buttons.testFlag(BUTTON_TERTIARY)) + mouseButtons.setFlag(Qt::MiddleButton); + + if (buttons.testFlag(BUTTON_BACK)) + mouseButtons.setFlag(Qt::BackButton); + + if (buttons.testFlag(BUTTON_FORWARD)) + mouseButtons.setFlag(Qt::ForwardButton); + + if (buttons.testFlag(BUTTON_STYLUS_PRIMARY)) + mouseButtons.setFlag(Qt::LeftButton); + + if (buttons.testFlag(BUTTON_STYLUS_SECONDARY)) + mouseButtons.setFlag(Qt::RightButton); + + // Fall back to left button + if (Q_UNLIKELY(buttons != 0 && mouseButtons == Qt::NoButton)) { + qWarning() << "Unhandled button value:" << buttons << "Falling back to Qt::LeftButton"; + mouseButtons = Qt::LeftButton; + } + return mouseButtons; + } + + static void sendMouseButtonEvents(QWindow *topLevel, QPoint localPos, QPoint globalPos, + jint mouseButtonState, QEvent::Type type) + { + const Qt::MouseButtons mouseButtons = toMouseButtons(mouseButtonState); + const Qt::MouseButtons changedButtons = mouseButtons & ~m_buttons; + + if (changedButtons == Qt::NoButton) + return; + + static_assert (sizeof(changedButtons) <= sizeof(uint), "Qt::MouseButtons size changed. Adapt code."); + + for (uint buttonInt = 0x1; static_cast(changedButtons) >= buttonInt; buttonInt <<= 1) { + const auto button = static_cast(buttonInt); + if (changedButtons.testFlag(button)) { + QWindowSystemInterface::handleMouseEvent(topLevel, localPos, globalPos, + mouseButtons, button, type); + } + } + } + + static void mouseDown(JNIEnv */*env*/, jobject /*thiz*/, jint winId, jint x, jint y, jint mouseButtonState) { if (m_ignoreMouseEvents) return; @@ -169,13 +236,11 @@ namespace QtAndroidInput QWindow *window = windowFromId(winId); m_mouseGrabber = window; const QPoint localPos = window && window->handle() ? - window->handle()->mapFromGlobal(globalPos) : globalPos; - QWindowSystemInterface::handleMouseEvent(window, localPos, globalPos, - Qt::MouseButtons(Qt::LeftButton), - Qt::LeftButton, QEvent::MouseButtonPress); + window->handle()->mapFromGlobal(globalPos) : globalPos; + sendMouseButtonEvents(window, localPos, globalPos, mouseButtonState, QEvent::MouseButtonPress); } - static void mouseUp(JNIEnv */*env*/, jobject /*thiz*/, jint winId, jint x, jint y) + static void mouseUp(JNIEnv */*env*/, jobject /*thiz*/, jint winId, jint x, jint y, jint mouseButtonState) { const QPoint globalPos(x,y); QWindow *window = m_mouseGrabber.data(); @@ -184,9 +249,8 @@ namespace QtAndroidInput const QPoint localPos = window && window->handle() ? window->handle()->mapFromGlobal(globalPos) : globalPos; - QWindowSystemInterface::handleMouseEvent(window, localPos, globalPos, - Qt::MouseButtons(Qt::NoButton), - Qt::LeftButton, QEvent::MouseButtonRelease); + + sendMouseButtonEvents(window, localPos, globalPos, mouseButtonState, QEvent::MouseButtonRelease); m_ignoreMouseEvents = false; m_mouseGrabber.clear(); } @@ -900,8 +964,8 @@ namespace QtAndroidInput {"touchAdd","(IIIZIIFFFF)V",(void*)touchAdd}, {"touchEnd","(II)V",(void*)touchEnd}, {"touchCancel", "(I)V", (void *)touchCancel}, - {"mouseDown", "(III)V", (void *)mouseDown}, - {"mouseUp", "(III)V", (void *)mouseUp}, + {"mouseDown", "(IIII)V", (void *)mouseDown}, + {"mouseUp", "(IIII)V", (void *)mouseUp}, {"mouseMove", "(III)V", (void *)mouseMove}, {"mouseWheel", "(IIIFF)V", (void *)mouseWheel}, {"longPress", "(III)V", (void *)longPress},