diff options
Diffstat (limited to 'src/plugins/platforms/android/androidjniinput.cpp')
-rw-r--r-- | src/plugins/platforms/android/androidjniinput.cpp | 200 |
1 files changed, 102 insertions, 98 deletions
diff --git a/src/plugins/platforms/android/androidjniinput.cpp b/src/plugins/platforms/android/androidjniinput.cpp index 00e6b7ca51..07f2786cc6 100644 --- a/src/plugins/platforms/android/androidjniinput.cpp +++ b/src/plugins/platforms/android/androidjniinput.cpp @@ -24,120 +24,64 @@ Q_LOGGING_CATEGORY(lcQpaInputMethods, "qt.qpa.input.methods"); using namespace QtAndroid; Q_DECLARE_JNI_CLASS(QtLayout, "org/qtproject/qt/android/QtLayout") +Q_DECLARE_JNI_CLASS(QtLayoutInterface, "org/qtproject/qt/android/QtLayoutInterface") +Q_DECLARE_JNI_CLASS(QtInputInterface, "org/qtproject/qt/android/QtInputInterface") namespace QtAndroidInput { static bool m_ignoreMouseEvents = false; + static Qt::MouseButtons m_buttons = Qt::NoButton; + static QRect m_softwareKeyboardRect; static QList<QWindowSystemInterface::TouchPoint> m_touchPoints; static QPointer<QWindow> m_mouseGrabber; - GenericMotionEventListener::~GenericMotionEventListener() {} - namespace { - struct GenericMotionEventListeners { - QMutex mutex; - QList<QtAndroidInput::GenericMotionEventListener *> listeners; - }; - } - Q_GLOBAL_STATIC(GenericMotionEventListeners, g_genericMotionEventListeners) - - static jboolean dispatchGenericMotionEvent(JNIEnv *, jclass, jobject event) - { - jboolean ret = JNI_FALSE; - QMutexLocker locker(&g_genericMotionEventListeners()->mutex); - for (auto *listener : std::as_const(g_genericMotionEventListeners()->listeners)) - ret |= listener->handleGenericMotionEvent(event); - return ret; - } - - KeyEventListener::~KeyEventListener() {} - namespace { - struct KeyEventListeners { - QMutex mutex; - QList<QtAndroidInput::KeyEventListener *> listeners; - }; - } - Q_GLOBAL_STATIC(KeyEventListeners, g_keyEventListeners) - - static jboolean dispatchKeyEvent(JNIEnv *, jclass, jobject event) - { - jboolean ret = JNI_FALSE; - QMutexLocker locker(&g_keyEventListeners()->mutex); - for (auto *listener : std::as_const(g_keyEventListeners()->listeners)) - ret |= listener->handleKeyEvent(event); - return ret; - } - - void registerGenericMotionEventListener(QtAndroidInput::GenericMotionEventListener *listener) - { - QMutexLocker locker(&g_genericMotionEventListeners()->mutex); - g_genericMotionEventListeners()->listeners.push_back(listener); - } - - void unregisterGenericMotionEventListener(QtAndroidInput::GenericMotionEventListener *listener) - { - QMutexLocker locker(&g_genericMotionEventListeners()->mutex); - g_genericMotionEventListeners()->listeners.removeOne(listener); - } - - void registerKeyEventListener(QtAndroidInput::KeyEventListener *listener) - { - QMutexLocker locker(&g_keyEventListeners()->mutex); - g_keyEventListeners()->listeners.push_back(listener); - } - - void unregisterKeyEventListener(QtAndroidInput::KeyEventListener *listener) - { - QMutexLocker locker(&g_keyEventListeners()->mutex); - g_keyEventListeners()->listeners.removeOne(listener); - } - QJniObject qtLayout() { - return qtActivityDelegate().callMethod<QtJniTypes::QtLayout>("getQtLayout"); + AndroidBackendRegister *reg = QtAndroid::backendRegister(); + return reg->callInterface<QtJniTypes::QtLayoutInterface, QtJniTypes::QtLayout>( + "getQtLayout"); } void updateSelection(int selStart, int selEnd, int candidatesStart, int candidatesEnd) { qCDebug(lcQpaInputMethods) << ">>> UPDATESELECTION" << selStart << selEnd << candidatesStart << candidatesEnd; - qtInputDelegate().callMethod<void>("updateSelection", - selStart, - selEnd, - candidatesStart, - candidatesEnd); + AndroidBackendRegister *reg = QtAndroid::backendRegister(); + reg->callInterface<QtJniTypes::QtInputInterface, void>("updateSelection", selStart, selEnd, + candidatesStart, candidatesEnd); } void showSoftwareKeyboard(int left, int top, int width, int height, int inputHints, int enterKeyType) { - qtInputDelegate().callMethod<void>("showSoftwareKeyboard", - QtAndroidPrivate::activity(), - qtLayout().object<QtJniTypes::QtLayout>(), - left, - top, - width, - height, - inputHints, - enterKeyType); + AndroidBackendRegister *reg = QtAndroid::backendRegister(); + reg->callInterface<QtJniTypes::QtInputInterface, void>( + "showSoftwareKeyboard", QtAndroidPrivate::activity(), + qtLayout().object<QtJniTypes::QtLayout>(), left, top, width, height, inputHints, + enterKeyType); qCDebug(lcQpaInputMethods) << "@@@ SHOWSOFTWAREKEYBOARD" << left << top << width << height << inputHints << enterKeyType; } void resetSoftwareKeyboard() { - qtInputDelegate().callMethod<void>("resetSoftwareKeyboard"); + AndroidBackendRegister *reg = QtAndroid::backendRegister(); + reg->callInterface<QtJniTypes::QtInputInterface, void>("resetSoftwareKeyboard"); qCDebug(lcQpaInputMethods) << "@@@ RESETSOFTWAREKEYBOARD"; } void hideSoftwareKeyboard() { - qtInputDelegate().callMethod<void>("hideSoftwareKeyboard"); + AndroidBackendRegister *reg = QtAndroid::backendRegister(); + reg->callInterface<QtJniTypes::QtInputInterface, void>("hideSoftwareKeyboard"); qCDebug(lcQpaInputMethods) << "@@@ HIDESOFTWAREKEYBOARD"; } bool isSoftwareKeyboardVisible() { - return qtInputDelegate().callMethod<jboolean>("isSoftwareKeyboardVisible"); + AndroidBackendRegister *reg = QtAndroid::backendRegister(); + return reg->callInterface<QtJniTypes::QtInputInterface, jboolean>( + "isSoftwareKeyboardVisible"); } QRect softwareKeyboardRect() @@ -147,20 +91,85 @@ namespace QtAndroidInput int getSelectHandleWidth() { - return qtInputDelegate().callMethod<jint>("getSelectHandleWidth"); + AndroidBackendRegister *reg = QtAndroid::backendRegister(); + return reg->callInterface<QtJniTypes::QtInputInterface, jint>("getSelectHandleWidth"); } void updateHandles(int mode, QPoint editMenuPos, uint32_t editButtons, QPoint cursor, QPoint anchor, bool rtl) { - qtInputDelegate().callMethod<void>("updateHandles", - QtAndroidPrivate::activity(), - qtLayout().object<QtJniTypes::QtLayout>(), - mode, editMenuPos.x(), editMenuPos.y(), editButtons, - cursor.x(), cursor.y(), - anchor.x(), anchor.y(), rtl); + AndroidBackendRegister *reg = QtAndroid::backendRegister(); + reg->callInterface<QtJniTypes::QtInputInterface, void>( + "updateHandles", QtAndroidPrivate::activity(), + qtLayout().object<QtJniTypes::QtLayout>(), mode, editMenuPos.x(), editMenuPos.y(), + editButtons, cursor.x(), cursor.y(), anchor.x(), anchor.y(), rtl); + } + + // 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<AndroidMouseButtons>(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<uint>(changedButtons) >= buttonInt; buttonInt <<= 1) { + const auto button = static_cast<Qt::MouseButton>(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) + static void mouseDown(JNIEnv */*env*/, jobject /*thiz*/, jint winId, jint x, jint y, jint mouseButtonState) { if (m_ignoreMouseEvents) return; @@ -169,13 +178,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 +191,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 +906,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}, @@ -912,8 +918,6 @@ namespace QtAndroidInput {"keyboardVisibilityChanged", "(Z)V", (void *)keyboardVisibilityChanged}, {"keyboardGeometryChanged", "(IIII)V", (void *)keyboardGeometryChanged}, {"handleLocationChanged", "(III)V", (void *)handleLocationChanged}, - {"dispatchGenericMotionEvent", "(Landroid/view/MotionEvent;)Z", reinterpret_cast<void *>(dispatchGenericMotionEvent)}, - {"dispatchKeyEvent", "(Landroid/view/KeyEvent;)Z", reinterpret_cast<void *>(dispatchKeyEvent)}, }; bool registerNatives(QJniEnvironment &env) |