Android: Fix mouse button processing

Fixes clicking UI elements with a mouse on Android.

8d8cbe87e21f05b7d611ed4be47299977288b267 introduced changes to support
mouse buttons other than Qt::LeftButton, but the release always looked
like no buttons changed, nor were they tracked (m_buttons is always
Qt::NoButton). Qt was not notified of mouse up, so nothing was clickable.

Now all mouse events go through sendMouseButtonEvents, and the last seen
button state is tracked for every event. If a mouse up with no buttons
occurs, the last seen set of buttons is used instead, so Qt correctly
handles the event. Also adds the mouse button state information to
mouse move events from Android, so the workaround for delivering
Qt::LeftButton when a window is tracking a move while a button is
pressed has been removed.

Tested on a Samsung A1 with a Bluetooth mouse.

Fixes: QTBUG-132700
Fixes: QTBUG-130297
Pick-to: 6.8 6.9
Change-Id: I241282c2915d7e6cf99db7f0bc1ad2d541349077
Reviewed-by: Assam Boudjelthia <assam.boudjelthia@qt.io>
This commit is contained in:
Andrew Forrest 2025-02-03 16:10:15 +00:00
parent 9704927844
commit d908e04398
2 changed files with 19 additions and 19 deletions

View File

@ -515,7 +515,7 @@ class QtInputDelegate implements QtInputConnection.QtInputConnectionListener, Qt
// pointer methods // pointer methods
static native void mouseDown(int winId, int x, int y, int mouseButtonState); static native void mouseDown(int winId, int x, int y, int mouseButtonState);
static native void mouseUp(int winId, int x, int y, int mouseButtonState); static native void mouseUp(int winId, int x, int y, int mouseButtonState);
static native void mouseMove(int winId, int x, int y); static native void mouseMove(int winId, int x, int y, int mouseButtonState);
static native void mouseWheel(int winId, int x, int y, float hDelta, float vDelta); static native void mouseWheel(int winId, int x, int y, float hDelta, float vDelta);
static native void touchBegin(int winId); static native void touchBegin(int winId);
static native void touchAdd(int winId, int pointerId, int action, boolean primary, static native void touchAdd(int winId, int pointerId, int action, boolean primary,
@ -641,12 +641,12 @@ class QtInputDelegate implements QtInputConnection.QtInputConnectionListener, Qt
case MotionEvent.ACTION_HOVER_MOVE: case MotionEvent.ACTION_HOVER_MOVE:
case MotionEvent.ACTION_MOVE: case MotionEvent.ACTION_MOVE:
if (event.getToolType(0) == MotionEvent.TOOL_TYPE_MOUSE) { if (event.getToolType(0) == MotionEvent.TOOL_TYPE_MOUSE) {
mouseMove(id, (int) event.getX(), (int) event.getY()); mouseMove(id, (int) event.getX(), (int) event.getY(), event.getButtonState());
} else { } else {
int dx = (int) (event.getX() - m_oldX); int dx = (int) (event.getX() - m_oldX);
int dy = (int) (event.getY() - m_oldY); int dy = (int) (event.getY() - m_oldY);
if (Math.abs(dx) > 5 || Math.abs(dy) > 5) { if (Math.abs(dx) > 5 || Math.abs(dy) > 5) {
mouseMove(id, (int) event.getX(), (int) event.getY()); mouseMove(id, (int) event.getX(), (int) event.getY(), event.getButtonState());
m_oldX = (int) event.getX(); m_oldX = (int) event.getX();
m_oldY = (int) event.getY(); m_oldY = (int) event.getY();
} }

View File

@ -28,7 +28,7 @@ Q_DECLARE_JNI_CLASS(QtInputInterface, "org/qtproject/qt/android/QtInputInterface
namespace QtAndroidInput namespace QtAndroidInput
{ {
static bool m_ignoreMouseEvents = false; static bool m_ignoreMouseEvents = false;
static Qt::MouseButtons m_buttons = Qt::NoButton; static Qt::MouseButtons m_lastSeenButtons = Qt::NoButton;
static QRect m_softwareKeyboardRect; static QRect m_softwareKeyboardRect;
@ -143,19 +143,22 @@ namespace QtAndroidInput
static void sendMouseButtonEvents(QWindow *topLevel, QPoint localPos, QPoint globalPos, static void sendMouseButtonEvents(QWindow *topLevel, QPoint localPos, QPoint globalPos,
jint mouseButtonState, QEvent::Type type) jint mouseButtonState, QEvent::Type type)
{ {
const Qt::MouseButtons mouseButtons = toMouseButtons(mouseButtonState); const Qt::MouseButtons qtButtons = toMouseButtons(mouseButtonState);
const Qt::MouseButtons changedButtons = mouseButtons & ~m_buttons; const bool mouseReleased = type == QEvent::MouseButtonRelease && qtButtons == Qt::NoButton;
const Qt::MouseButtons eventButtons = mouseReleased ? m_lastSeenButtons : qtButtons;
m_lastSeenButtons = qtButtons;
if (changedButtons == Qt::NoButton) static_assert (sizeof(eventButtons) <= sizeof(uint), "Qt::MouseButtons size changed. Adapt code.");
if (eventButtons == Qt::NoButton) {
QWindowSystemInterface::handleMouseEvent(topLevel, localPos, globalPos, qtButtons, Qt::NoButton, type);
return; return;
}
static_assert (sizeof(changedButtons) <= sizeof(uint), "Qt::MouseButtons size changed. Adapt code."); for (uint buttonInt = 0x1; static_cast<uint>(eventButtons) >= buttonInt; buttonInt <<= 1) {
for (uint buttonInt = 0x1; static_cast<uint>(changedButtons) >= buttonInt; buttonInt <<= 1) {
const auto button = static_cast<Qt::MouseButton>(buttonInt); const auto button = static_cast<Qt::MouseButton>(buttonInt);
if (changedButtons.testFlag(button)) { if (eventButtons.testFlag(button)) {
QWindowSystemInterface::handleMouseEvent(topLevel, localPos, globalPos, QWindowSystemInterface::handleMouseEvent(topLevel, localPos, globalPos,
mouseButtons, button, type); qtButtons, button, type);
} }
} }
} }
@ -188,9 +191,8 @@ namespace QtAndroidInput
m_mouseGrabber.clear(); m_mouseGrabber.clear();
} }
static void mouseMove(JNIEnv */*env*/, jobject /*thiz*/, jint winId, jint x, jint y) static void mouseMove(JNIEnv */*env*/, jobject /*thiz*/, jint winId, jint x, jint y, jint mouseButtonState)
{ {
if (m_ignoreMouseEvents) if (m_ignoreMouseEvents)
return; return;
@ -200,9 +202,7 @@ namespace QtAndroidInput
window = windowFromId(winId); window = windowFromId(winId);
const QPoint localPos = window && window->handle() ? const QPoint localPos = window && window->handle() ?
window->handle()->mapFromGlobal(globalPos) : globalPos; window->handle()->mapFromGlobal(globalPos) : globalPos;
QWindowSystemInterface::handleMouseEvent(window, localPos, globalPos, sendMouseButtonEvents(window, localPos, globalPos, mouseButtonState, QEvent::MouseMove);
Qt::MouseButtons(m_mouseGrabber ? Qt::LeftButton : Qt::NoButton),
Qt::NoButton, QEvent::MouseMove);
} }
static void mouseWheel(JNIEnv */*env*/, jobject /*thiz*/, jint winId, jint x, jint y, jfloat hdelta, jfloat vdelta) static void mouseWheel(JNIEnv */*env*/, jobject /*thiz*/, jint winId, jint x, jint y, jfloat hdelta, jfloat vdelta)
@ -914,7 +914,7 @@ namespace QtAndroidInput
{"touchCancel", "(I)V", (void *)touchCancel}, {"touchCancel", "(I)V", (void *)touchCancel},
{"mouseDown", "(IIII)V", (void *)mouseDown}, {"mouseDown", "(IIII)V", (void *)mouseDown},
{"mouseUp", "(IIII)V", (void *)mouseUp}, {"mouseUp", "(IIII)V", (void *)mouseUp},
{"mouseMove", "(III)V", (void *)mouseMove}, {"mouseMove", "(IIII)V", (void *)mouseMove},
{"mouseWheel", "(IIIFF)V", (void *)mouseWheel}, {"mouseWheel", "(IIIFF)V", (void *)mouseWheel},
{"longPress", "(III)V", (void *)longPress}, {"longPress", "(III)V", (void *)longPress},
{"isTabletEventSupported", "()Z", (void *)isTabletEventSupported}, {"isTabletEventSupported", "()Z", (void *)isTabletEventSupported},