|
| 1 | +From a3203542dced8b679633e666ff008ba5f017e827 Mon Sep 17 00:00:00 2001 |
| 2 | +From: Andrew Forrest < [email protected]> |
| 3 | +Date: Mon, 3 Feb 2025 16:10:15 +0000 |
| 4 | +Subject: [PATCH] Android: Fix mouse button processing |
| 5 | + |
| 6 | +Fixes clicking UI elements with a mouse on Android. |
| 7 | + |
| 8 | +8d8cbe87e21f05b7d611ed4be47299977288b267 introduced changes to support |
| 9 | +mouse buttons other than Qt::LeftButton, but the release always looked |
| 10 | +like no buttons changed, nor were they tracked (m_buttons is always |
| 11 | +Qt::NoButton). Qt was not notified of mouse up, so nothing was clickable. |
| 12 | + |
| 13 | +Now all mouse events go through sendMouseButtonEvents, and the last seen |
| 14 | +button state is tracked for every event. If a mouse up with no buttons |
| 15 | +occurs, the last seen set of buttons is used instead, so Qt correctly |
| 16 | +handles the event. Also adds the mouse button state information to |
| 17 | +mouse move events from Android, so the workaround for delivering |
| 18 | +Qt::LeftButton when a window is tracking a move while a button is |
| 19 | +pressed has been removed. |
| 20 | + |
| 21 | +Tested on a Samsung A1 with a Bluetooth mouse. |
| 22 | + |
| 23 | +Fixes: QTBUG-132700 |
| 24 | +Fixes: QTBUG-130297 |
| 25 | +Change-Id: I241282c2915d7e6cf99db7f0bc1ad2d541349077 |
| 26 | +Reviewed-by: Assam Boudjelthia < [email protected]> |
| 27 | +(cherry picked from commit d908e043984dcfed3aa80e30cd1cafacd13b644d) |
| 28 | +Reviewed-by: Qt Cherry-pick Bot < [email protected]> |
| 29 | +(cherry picked from commit 65e9eca63b3f522065018777ac07c5a71c08ff37) |
| 30 | +--- |
| 31 | + .../org/qtproject/qt/android/QtInputDelegate.java | 6 ++-- |
| 32 | + src/plugins/platforms/android/androidjniinput.cpp | 32 +++++++++++----------- |
| 33 | + 2 files changed, 19 insertions(+), 19 deletions(-) |
| 34 | + |
| 35 | +diff --git a/src/android/jar/src/org/qtproject/qt/android/QtInputDelegate.java b/src/android/jar/src/org/qtproject/qt/android/QtInputDelegate.java |
| 36 | +index 89f2529ab870..2531942de565 100644 |
| 37 | +--- a/src/android/jar/src/org/qtproject/qt/android/QtInputDelegate.java |
| 38 | ++++ b/src/android/jar/src/org/qtproject/qt/android/QtInputDelegate.java |
| 39 | +@@ -517,7 +517,7 @@ class QtInputDelegate implements QtInputConnection.QtInputConnectionListener, Qt |
| 40 | + // pointer methods |
| 41 | + static native void mouseDown(int winId, int x, int y, int mouseButtonState); |
| 42 | + static native void mouseUp(int winId, int x, int y, int mouseButtonState); |
| 43 | +- static native void mouseMove(int winId, int x, int y); |
| 44 | ++ static native void mouseMove(int winId, int x, int y, int mouseButtonState); |
| 45 | + static native void mouseWheel(int winId, int x, int y, float hDelta, float vDelta); |
| 46 | + static native void touchBegin(int winId); |
| 47 | + static native void touchAdd(int winId, int pointerId, int action, boolean primary, |
| 48 | +@@ -643,12 +643,12 @@ class QtInputDelegate implements QtInputConnection.QtInputConnectionListener, Qt |
| 49 | + case MotionEvent.ACTION_HOVER_MOVE: |
| 50 | + case MotionEvent.ACTION_MOVE: |
| 51 | + if (event.getToolType(0) == MotionEvent.TOOL_TYPE_MOUSE) { |
| 52 | +- mouseMove(id, (int) event.getX(), (int) event.getY()); |
| 53 | ++ mouseMove(id, (int) event.getX(), (int) event.getY(), event.getButtonState()); |
| 54 | + } else { |
| 55 | + int dx = (int) (event.getX() - m_oldX); |
| 56 | + int dy = (int) (event.getY() - m_oldY); |
| 57 | + if (Math.abs(dx) > 5 || Math.abs(dy) > 5) { |
| 58 | +- mouseMove(id, (int) event.getX(), (int) event.getY()); |
| 59 | ++ mouseMove(id, (int) event.getX(), (int) event.getY(), event.getButtonState()); |
| 60 | + m_oldX = (int) event.getX(); |
| 61 | + m_oldY = (int) event.getY(); |
| 62 | + } |
| 63 | +diff --git a/src/plugins/platforms/android/androidjniinput.cpp b/src/plugins/platforms/android/androidjniinput.cpp |
| 64 | +index a0faedcc5b2f..461b2da51c96 100644 |
| 65 | +--- a/src/plugins/platforms/android/androidjniinput.cpp |
| 66 | ++++ b/src/plugins/platforms/android/androidjniinput.cpp |
| 67 | +@@ -28,7 +28,7 @@ Q_DECLARE_JNI_CLASS(QtInputInterface, "org/qtproject/qt/android/QtInputInterface |
| 68 | + namespace QtAndroidInput |
| 69 | + { |
| 70 | + static bool m_ignoreMouseEvents = false; |
| 71 | +- static Qt::MouseButtons m_buttons = Qt::NoButton; |
| 72 | ++ static Qt::MouseButtons m_lastSeenButtons = Qt::NoButton; |
| 73 | + |
| 74 | + static QRect m_softwareKeyboardRect; |
| 75 | + |
| 76 | +@@ -143,19 +143,22 @@ namespace QtAndroidInput |
| 77 | + static void sendMouseButtonEvents(QWindow *topLevel, QPoint localPos, QPoint globalPos, |
| 78 | + jint mouseButtonState, QEvent::Type type) |
| 79 | + { |
| 80 | +- const Qt::MouseButtons mouseButtons = toMouseButtons(mouseButtonState); |
| 81 | +- const Qt::MouseButtons changedButtons = mouseButtons & ~m_buttons; |
| 82 | ++ const Qt::MouseButtons qtButtons = toMouseButtons(mouseButtonState); |
| 83 | ++ const bool mouseReleased = type == QEvent::MouseButtonRelease && qtButtons == Qt::NoButton; |
| 84 | ++ const Qt::MouseButtons eventButtons = mouseReleased ? m_lastSeenButtons : qtButtons; |
| 85 | ++ m_lastSeenButtons = qtButtons; |
| 86 | + |
| 87 | +- if (changedButtons == Qt::NoButton) |
| 88 | +- return; |
| 89 | +- |
| 90 | +- static_assert (sizeof(changedButtons) <= sizeof(uint), "Qt::MouseButtons size changed. Adapt code."); |
| 91 | ++ static_assert (sizeof(eventButtons) <= sizeof(uint), "Qt::MouseButtons size changed. Adapt code."); |
| 92 | + |
| 93 | +- for (uint buttonInt = 0x1; static_cast<uint>(changedButtons) >= buttonInt; buttonInt <<= 1) { |
| 94 | ++ if (eventButtons == Qt::NoButton) { |
| 95 | ++ QWindowSystemInterface::handleMouseEvent(topLevel, localPos, globalPos, qtButtons, Qt::NoButton, type); |
| 96 | ++ return; |
| 97 | ++ } |
| 98 | ++ for (uint buttonInt = 0x1; static_cast<uint>(eventButtons) >= buttonInt; buttonInt <<= 1) { |
| 99 | + const auto button = static_cast<Qt::MouseButton>(buttonInt); |
| 100 | +- if (changedButtons.testFlag(button)) { |
| 101 | ++ if (eventButtons.testFlag(button)) { |
| 102 | + QWindowSystemInterface::handleMouseEvent(topLevel, localPos, globalPos, |
| 103 | +- mouseButtons, button, type); |
| 104 | ++ qtButtons, button, type); |
| 105 | + } |
| 106 | + } |
| 107 | + } |
| 108 | +@@ -188,9 +191,8 @@ namespace QtAndroidInput |
| 109 | + m_mouseGrabber.clear(); |
| 110 | + } |
| 111 | + |
| 112 | +- static void mouseMove(JNIEnv */*env*/, jobject /*thiz*/, jint winId, jint x, jint y) |
| 113 | ++ static void mouseMove(JNIEnv */*env*/, jobject /*thiz*/, jint winId, jint x, jint y, jint mouseButtonState) |
| 114 | + { |
| 115 | +- |
| 116 | + if (m_ignoreMouseEvents) |
| 117 | + return; |
| 118 | + |
| 119 | +@@ -200,9 +202,7 @@ namespace QtAndroidInput |
| 120 | + window = windowFromId(winId); |
| 121 | + const QPoint localPos = window && window->handle() ? |
| 122 | + window->handle()->mapFromGlobal(globalPos) : globalPos; |
| 123 | +- QWindowSystemInterface::handleMouseEvent(window, localPos, globalPos, |
| 124 | +- Qt::MouseButtons(m_mouseGrabber ? Qt::LeftButton : Qt::NoButton), |
| 125 | +- Qt::NoButton, QEvent::MouseMove); |
| 126 | ++ sendMouseButtonEvents(window, localPos, globalPos, mouseButtonState, QEvent::MouseMove); |
| 127 | + } |
| 128 | + |
| 129 | + static void mouseWheel(JNIEnv */*env*/, jobject /*thiz*/, jint winId, jint x, jint y, jfloat hdelta, jfloat vdelta) |
| 130 | +@@ -909,7 +909,7 @@ namespace QtAndroidInput |
| 131 | + {"touchCancel", "(I)V", (void *)touchCancel}, |
| 132 | + {"mouseDown", "(IIII)V", (void *)mouseDown}, |
| 133 | + {"mouseUp", "(IIII)V", (void *)mouseUp}, |
| 134 | +- {"mouseMove", "(III)V", (void *)mouseMove}, |
| 135 | ++ {"mouseMove", "(IIII)V", (void *)mouseMove}, |
| 136 | + {"mouseWheel", "(IIIFF)V", (void *)mouseWheel}, |
| 137 | + {"longPress", "(III)V", (void *)longPress}, |
| 138 | + {"isTabletEventSupported", "()Z", (void *)isTabletEventSupported}, |
| 139 | +-- |
| 140 | +2.16.3 |
| 141 | + |
0 commit comments