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 <eskil.abrahamsen-blomfeldt@theqtcompany.com>
This commit is contained in:
BogDan Vatra 2015-10-15 08:41:09 +03:00 committed by BogDan Vatra
parent 4f7e0bdc4c
commit 3674718e3d
4 changed files with 113 additions and 1 deletions

View File

@ -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;
}
}

View File

@ -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

View File

@ -34,6 +34,7 @@
#include "qjnihelpers_p.h"
#include "qmutex.h"
#include "qlist.h"
#include "qvector.h"
#include <QtCore/qrunnable.h>
QT_BEGIN_NAMESPACE
@ -56,6 +57,40 @@ static void onAndroidUiThread(JNIEnv *, jclass, jlong thiz)
delete runnable;
}
namespace {
struct GenericMotionEventListeners {
QMutex mutex;
QVector<QtAndroidPrivate::GenericMotionEventListener *> 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<QtAndroidPrivate::KeyEventListener *> 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<void *>(onAndroidUiThread)}
{"onAndroidUiThread", "(J)V", reinterpret_cast<void *>(onAndroidUiThread)},
{"dispatchGenericMotionEvent", "(Landroid/view/MotionEvent;)Z", reinterpret_cast<void *>(dispatchGenericMotionEvent)},
{"dispatchKeyEvent", "(Landroid/view/KeyEvent;)Z", reinterpret_cast<void *>(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

View File

@ -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