From 3674718e3d7a030a774d53630888e424139df79b Mon Sep 17 00:00:00 2001 From: BogDan Vatra Date: Thu, 15 Oct 2015 08:41:09 +0300 Subject: [PATCH] Dispatch all key and all generic motion events java objects to QtCore These events are needed to enable the usage of all input methods available on Android e.g. gamepads, stylus, etc. In orer to get GenericMotionEvents your application min API version must be at least 12, otherwise the application will receive only key events. Change-Id: I7564fccaf5423aa318ba4f62317eaf101ba6e97e Reviewed-by: Eskil Abrahamsen Blomfeldt --- .../qt5/android/QtActivityDelegate.java | 25 ++++++++ .../org/qtproject/qt5/android/QtNative.java | 6 ++ src/corelib/kernel/qjnihelpers.cpp | 63 ++++++++++++++++++- src/corelib/kernel/qjnihelpers_p.h | 20 ++++++ 4 files changed, 113 insertions(+), 1 deletion(-) diff --git a/src/android/jar/src/org/qtproject/qt5/android/QtActivityDelegate.java b/src/android/jar/src/org/qtproject/qt5/android/QtActivityDelegate.java index ee196f1aef..871f9ae2c2 100644 --- a/src/android/jar/src/org/qtproject/qt5/android/QtActivityDelegate.java +++ b/src/android/jar/src/org/qtproject/qt5/android/QtActivityDelegate.java @@ -59,6 +59,7 @@ import android.view.KeyCharacterMap; import android.view.KeyEvent; import android.view.Menu; import android.view.MenuItem; +import android.view.MotionEvent; import android.view.Surface; import android.view.View; import android.view.ViewConfiguration; @@ -89,6 +90,7 @@ public class QtActivityDelegate private Method m_super_onKeyUp = null; private Method m_super_onConfigurationChanged = null; private Method m_super_onActivityResult = null; + private Method m_super_dispatchGenericMotionEvent = null; private static final String NATIVE_LIBRARIES_KEY = "native.libraries"; private static final String BUNDLED_LIBRARIES_KEY = "bundled.libraries"; @@ -475,6 +477,13 @@ public class QtActivityDelegate m_super_onKeyUp = m_activity.getClass().getMethod("super_onKeyUp", Integer.TYPE, KeyEvent.class); m_super_onConfigurationChanged = m_activity.getClass().getMethod("super_onConfigurationChanged", Configuration.class); m_super_onActivityResult = m_activity.getClass().getMethod("super_onActivityResult", Integer.TYPE, Integer.TYPE, Intent.class); + if (Build.VERSION.SDK_INT >= 12) { + try { + m_super_dispatchGenericMotionEvent = m_activity.getClass().getMethod("super_dispatchGenericMotionEvent", MotionEvent.class); + } catch (Exception e) { + } + } + } catch (Exception e) { e.printStackTrace(); return false; @@ -1043,6 +1052,9 @@ public class QtActivityDelegate QtNative.keyUp(0, event.getCharacters().charAt(0), event.getMetaState(), event.getRepeatCount() > 0); } + if (QtNative.dispatchKeyEvent(event)) + return true; + try { return (Boolean) m_super_dispatchKeyEvent.invoke(m_activity, event); } catch (Exception e) { @@ -1311,4 +1323,17 @@ public class QtActivityDelegate m_layout.moveChild(view, index); } } + + public boolean dispatchGenericMotionEvent (MotionEvent ev) + { + if (m_started && QtNative.dispatchGenericMotionEvent(ev)) + return true; + + try { + return (Boolean) m_super_dispatchGenericMotionEvent.invoke(m_activity, ev); + } catch (Exception e) { + e.printStackTrace(); + } + return false; + } } diff --git a/src/android/jar/src/org/qtproject/qt5/android/QtNative.java b/src/android/jar/src/org/qtproject/qt5/android/QtNative.java index 0c01e67637..94e0e4e92b 100644 --- a/src/android/jar/src/org/qtproject/qt5/android/QtNative.java +++ b/src/android/jar/src/org/qtproject/qt5/android/QtNative.java @@ -48,6 +48,7 @@ import android.text.ClipboardManager; import android.os.Build; import android.util.Log; import android.view.ContextMenu; +import android.view.KeyEvent; import android.view.Menu; import android.view.MotionEvent; import android.view.View; @@ -633,6 +634,11 @@ public class QtNative public static native void keyboardVisibilityChanged(boolean visibility); // keyboard methods + // dispatch events methods + public static native boolean dispatchGenericMotionEvent(MotionEvent ev); + public static native boolean dispatchKeyEvent(KeyEvent event); + // dispatch events methods + // surface methods public static native void setSurface(int id, Object surface, int w, int h); // surface methods diff --git a/src/corelib/kernel/qjnihelpers.cpp b/src/corelib/kernel/qjnihelpers.cpp index f77fc4220c..0a5a5dffb9 100644 --- a/src/corelib/kernel/qjnihelpers.cpp +++ b/src/corelib/kernel/qjnihelpers.cpp @@ -34,6 +34,7 @@ #include "qjnihelpers_p.h" #include "qmutex.h" #include "qlist.h" +#include "qvector.h" #include QT_BEGIN_NAMESPACE @@ -56,6 +57,40 @@ static void onAndroidUiThread(JNIEnv *, jclass, jlong thiz) delete runnable; } +namespace { + struct GenericMotionEventListeners { + QMutex mutex; + QVector listeners; + }; +} +Q_GLOBAL_STATIC(GenericMotionEventListeners, g_genericMotionEventListeners) + +static jboolean dispatchGenericMotionEvent(JNIEnv *, jclass, jobject event) +{ + jboolean ret = JNI_FALSE; + QMutexLocker locker(&g_genericMotionEventListeners()->mutex); + foreach (auto listener, g_genericMotionEventListeners()->listeners) + ret |= listener->handleGenericMotionEvent(event); + return ret; +} + +namespace { + struct KeyEventListeners { + QMutex mutex; + QVector listeners; + }; +} +Q_GLOBAL_STATIC(KeyEventListeners, g_keyEventListeners) + +static jboolean dispatchKeyEvent(JNIEnv *, jclass, jobject event) +{ + jboolean ret = JNI_FALSE; + QMutexLocker locker(&g_keyEventListeners()->mutex); + foreach (auto listener, g_keyEventListeners()->listeners) + ret |= listener->handleKeyEvent(event); + return ret; +} + namespace { class ActivityResultListeners { @@ -227,7 +262,9 @@ jint QtAndroidPrivate::initJNI(JavaVM *vm, JNIEnv *env) g_javaVM = vm; static const JNINativeMethod methods[] = { - {"onAndroidUiThread", "(J)V", reinterpret_cast(onAndroidUiThread)} + {"onAndroidUiThread", "(J)V", reinterpret_cast(onAndroidUiThread)}, + {"dispatchGenericMotionEvent", "(Landroid/view/MotionEvent;)Z", reinterpret_cast(dispatchGenericMotionEvent)}, + {"dispatchKeyEvent", "(Landroid/view/KeyEvent;)Z", reinterpret_cast(dispatchKeyEvent)}, }; const bool regOk = (env->RegisterNatives(jQtNative, methods, sizeof(methods) / sizeof(methods[0])) == JNI_OK); @@ -274,4 +311,28 @@ void QtAndroidPrivate::runOnUiThread(QRunnable *runnable, JNIEnv *env) delete runnable; } +void QtAndroidPrivate::registerGenericMotionEventListener(QtAndroidPrivate::GenericMotionEventListener *listener) +{ + QMutexLocker locker(&g_genericMotionEventListeners()->mutex); + g_genericMotionEventListeners()->listeners.push_back(listener); +} + +void QtAndroidPrivate::unregisterGenericMotionEventListener(QtAndroidPrivate::GenericMotionEventListener *listener) +{ + QMutexLocker locker(&g_genericMotionEventListeners()->mutex); + g_genericMotionEventListeners()->listeners.removeOne(listener); +} + +void QtAndroidPrivate::registerKeyEventListener(QtAndroidPrivate::KeyEventListener *listener) +{ + QMutexLocker locker(&g_keyEventListeners()->mutex); + g_keyEventListeners()->listeners.push_back(listener); +} + +void QtAndroidPrivate::unregisterKeyEventListener(QtAndroidPrivate::KeyEventListener *listener) +{ + QMutexLocker locker(&g_keyEventListeners()->mutex); + g_keyEventListeners()->listeners.removeOne(listener); +} + QT_END_NAMESPACE diff --git a/src/corelib/kernel/qjnihelpers_p.h b/src/corelib/kernel/qjnihelpers_p.h index 883b08ef60..536989b4fc 100644 --- a/src/corelib/kernel/qjnihelpers_p.h +++ b/src/corelib/kernel/qjnihelpers_p.h @@ -76,6 +76,20 @@ namespace QtAndroidPrivate virtual void handleResume() {}; }; + class Q_CORE_EXPORT GenericMotionEventListener + { + public: + virtual ~GenericMotionEventListener() {} + virtual bool handleGenericMotionEvent(jobject event) = 0; + }; + + class Q_CORE_EXPORT KeyEventListener + { + public: + virtual ~KeyEventListener() {} + virtual bool handleKeyEvent(jobject event) = 0; + }; + Q_CORE_EXPORT jobject activity(); Q_CORE_EXPORT JavaVM *javaVM(); Q_CORE_EXPORT jint initJNI(JavaVM *vm, JNIEnv *env); @@ -95,6 +109,12 @@ namespace QtAndroidPrivate Q_CORE_EXPORT void handleResume(); Q_CORE_EXPORT void registerResumePauseListener(ResumePauseListener *listener); Q_CORE_EXPORT void unregisterResumePauseListener(ResumePauseListener *listener); + + Q_CORE_EXPORT void registerGenericMotionEventListener(GenericMotionEventListener *listener); + Q_CORE_EXPORT void unregisterGenericMotionEventListener(GenericMotionEventListener *listener); + + Q_CORE_EXPORT void registerKeyEventListener(KeyEventListener *listener); + Q_CORE_EXPORT void unregisterKeyEventListener(KeyEventListener *listener); } QT_END_NAMESPACE