Android: Updated the JNI/event handling code

* Local Java references are now freed after use.
* SFML is now able to consider (Android) events as unhandled and pass them.
* Hovering a pen over the screen no longer triggers movement events (untested).
This commit is contained in:
Mario Liebisch 2015-06-04 16:55:58 +02:00 committed by Lukas Dürrenberger
parent cadc4d801c
commit 11357b354f
3 changed files with 55 additions and 36 deletions

View File

@ -78,6 +78,7 @@ void InputImpl::setVirtualKeyboardVisible(bool visible)
"INPUT_METHOD_SERVICE", "Ljava/lang/String;"); "INPUT_METHOD_SERVICE", "Ljava/lang/String;");
jobject INPUT_METHOD_SERVICE = lJNIEnv->GetStaticObjectField(ClassContext, jobject INPUT_METHOD_SERVICE = lJNIEnv->GetStaticObjectField(ClassContext,
FieldINPUT_METHOD_SERVICE); FieldINPUT_METHOD_SERVICE);
lJNIEnv->DeleteLocalRef(ClassContext);
// Runs getSystemService(Context.INPUT_METHOD_SERVICE) // Runs getSystemService(Context.INPUT_METHOD_SERVICE)
jclass ClassInputMethodManager = jclass ClassInputMethodManager =
@ -86,6 +87,7 @@ void InputImpl::setVirtualKeyboardVisible(bool visible)
"getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;"); "getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;");
jobject lInputMethodManager = lJNIEnv->CallObjectMethod(lNativeActivity, jobject lInputMethodManager = lJNIEnv->CallObjectMethod(lNativeActivity,
MethodGetSystemService, INPUT_METHOD_SERVICE); MethodGetSystemService, INPUT_METHOD_SERVICE);
lJNIEnv->DeleteLocalRef(INPUT_METHOD_SERVICE);
// Runs getWindow().getDecorView() // Runs getWindow().getDecorView()
jmethodID MethodGetWindow = lJNIEnv->GetMethodID(ClassNativeActivity, jmethodID MethodGetWindow = lJNIEnv->GetMethodID(ClassNativeActivity,
@ -95,6 +97,8 @@ void InputImpl::setVirtualKeyboardVisible(bool visible)
jmethodID MethodGetDecorView = lJNIEnv->GetMethodID(ClassWindow, jmethodID MethodGetDecorView = lJNIEnv->GetMethodID(ClassWindow,
"getDecorView", "()Landroid/view/View;"); "getDecorView", "()Landroid/view/View;");
jobject lDecorView = lJNIEnv->CallObjectMethod(lWindow, MethodGetDecorView); jobject lDecorView = lJNIEnv->CallObjectMethod(lWindow, MethodGetDecorView);
lJNIEnv->DeleteLocalRef(lWindow);
lJNIEnv->DeleteLocalRef(ClassWindow);
if (visible) if (visible)
{ {
@ -112,13 +116,19 @@ void InputImpl::setVirtualKeyboardVisible(bool visible)
"getWindowToken", "()Landroid/os/IBinder;"); "getWindowToken", "()Landroid/os/IBinder;");
jobject lBinder = lJNIEnv->CallObjectMethod(lDecorView, jobject lBinder = lJNIEnv->CallObjectMethod(lDecorView,
MethodGetWindowToken); MethodGetWindowToken);
lJNIEnv->DeleteLocalRef(ClassView);
// lInputMethodManager.hideSoftInput(...) // lInputMethodManager.hideSoftInput(...)
jmethodID MethodHideSoftInput = lJNIEnv->GetMethodID(ClassInputMethodManager, jmethodID MethodHideSoftInput = lJNIEnv->GetMethodID(ClassInputMethodManager,
"hideSoftInputFromWindow", "(Landroid/os/IBinder;I)Z"); "hideSoftInputFromWindow", "(Landroid/os/IBinder;I)Z");
jboolean lRes = lJNIEnv->CallBooleanMethod(lInputMethodManager, jboolean lRes = lJNIEnv->CallBooleanMethod(lInputMethodManager,
MethodHideSoftInput, lBinder, lFlags); MethodHideSoftInput, lBinder, lFlags);
lJNIEnv->DeleteLocalRef(lBinder);
} }
lJNIEnv->DeleteLocalRef(lNativeActivity);
lJNIEnv->DeleteLocalRef(ClassNativeActivity);
lJNIEnv->DeleteLocalRef(ClassInputMethodManager);
lJNIEnv->DeleteLocalRef(lDecorView);
// Finished with the JVM // Finished with the JVM
lJavaVM->DetachCurrentThread(); lJavaVM->DetachCurrentThread();

View File

@ -33,9 +33,11 @@
#include <SFML/System/Err.hpp> #include <SFML/System/Err.hpp>
#include <android/looper.h> #include <android/looper.h>
// Define missing constants // Define missing constants for older API levels
#define AMOTION_EVENT_ACTION_HOVER_MOVE 0x00000007 #if __ANDROID_API__ < 13
#define AMOTION_EVENT_ACTION_SCROLL 0x00000008 #define AMOTION_EVENT_ACTION_HOVER_MOVE 0x00000007
#define AMOTION_EVENT_ACTION_SCROLL 0x00000008
#endif
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
// Private data // Private data
@ -232,7 +234,7 @@ int WindowImplAndroid::processEvent(int fd, int events, void* data)
if (AInputQueue_preDispatchEvent(states->inputQueue, _event)) if (AInputQueue_preDispatchEvent(states->inputQueue, _event))
return 1; return 1;
int32_t handled = 0; int handled = 0;
int32_t type = AInputEvent_getType(_event); int32_t type = AInputEvent_getType(_event);
@ -244,8 +246,7 @@ int WindowImplAndroid::processEvent(int fd, int events, void* data)
if ((action == AKEY_EVENT_ACTION_DOWN || action == AKEY_EVENT_ACTION_UP || action == AKEY_EVENT_ACTION_MULTIPLE) && if ((action == AKEY_EVENT_ACTION_DOWN || action == AKEY_EVENT_ACTION_UP || action == AKEY_EVENT_ACTION_MULTIPLE) &&
key != AKEYCODE_VOLUME_UP && key != AKEYCODE_VOLUME_DOWN) key != AKEYCODE_VOLUME_UP && key != AKEYCODE_VOLUME_DOWN)
{ {
processKeyEvent(_event, states); handled = processKeyEvent(_event, states);
handled = 1;
} }
} }
else if (type == AINPUT_EVENT_TYPE_MOTION) else if (type == AINPUT_EVENT_TYPE_MOTION)
@ -256,16 +257,15 @@ int WindowImplAndroid::processEvent(int fd, int events, void* data)
{ {
case AMOTION_EVENT_ACTION_SCROLL: case AMOTION_EVENT_ACTION_SCROLL:
{ {
processScrollEvent(_event, states); handled = processScrollEvent(_event, states);
handled = 1;
break; break;
} }
case AMOTION_EVENT_ACTION_HOVER_MOVE: // todo: should hover_move indeed trigger the event?
// case AMOTION_EVENT_ACTION_HOVER_MOVE:
case AMOTION_EVENT_ACTION_MOVE: case AMOTION_EVENT_ACTION_MOVE:
{ {
processMotionEvent(_event, states); handled = processMotionEvent(_event, states);
handled = 1;
break; break;
} }
@ -273,8 +273,7 @@ int WindowImplAndroid::processEvent(int fd, int events, void* data)
case AMOTION_EVENT_ACTION_POINTER_DOWN: case AMOTION_EVENT_ACTION_POINTER_DOWN:
case AMOTION_EVENT_ACTION_DOWN: case AMOTION_EVENT_ACTION_DOWN:
{ {
processPointerEvent(true, _event, states); handled = processPointerEvent(true, _event, states);
handled = 1;
break; break;
} }
@ -282,8 +281,7 @@ int WindowImplAndroid::processEvent(int fd, int events, void* data)
case AMOTION_EVENT_ACTION_UP: case AMOTION_EVENT_ACTION_UP:
case AMOTION_EVENT_ACTION_CANCEL: case AMOTION_EVENT_ACTION_CANCEL:
{ {
processPointerEvent(false, _event, states); handled = processPointerEvent(false, _event, states);
handled = 1;
break; break;
} }
} }
@ -298,7 +296,7 @@ int WindowImplAndroid::processEvent(int fd, int events, void* data)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void WindowImplAndroid::processScrollEvent(AInputEvent* _event, ActivityStates* states) int WindowImplAndroid::processScrollEvent(AInputEvent* _event, ActivityStates* states)
{ {
// Prepare the Java virtual machine // Prepare the Java virtual machine
jint lResult; jint lResult;
@ -314,8 +312,10 @@ void WindowImplAndroid::processScrollEvent(AInputEvent* _event, ActivityStates*
lResult=lJavaVM->AttachCurrentThread(&lJNIEnv, &lJavaVMAttachArgs); lResult=lJavaVM->AttachCurrentThread(&lJNIEnv, &lJavaVMAttachArgs);
if (lResult == JNI_ERR) if (lResult == JNI_ERR) {
err() << "Failed to initialize JNI, couldn't get the Unicode value" << std::endl; err() << "Failed to initialize JNI, couldn't get the Unicode value" << std::endl;
return 0;
}
// Retrieve everything we need to create this MotionEvent in Java // Retrieve everything we need to create this MotionEvent in Java
jlong downTime = AMotionEvent_getDownTime(_event); jlong downTime = AMotionEvent_getDownTime(_event);
@ -340,6 +340,9 @@ void WindowImplAndroid::processScrollEvent(AInputEvent* _event, ActivityStates*
jmethodID MethodGetAxisValue = lJNIEnv->GetMethodID(ClassMotionEvent, "getAxisValue", "(I)F"); jmethodID MethodGetAxisValue = lJNIEnv->GetMethodID(ClassMotionEvent, "getAxisValue", "(I)F");
jfloat delta = lJNIEnv->CallFloatMethod(ObjectMotionEvent, MethodGetAxisValue, 0x00000001); jfloat delta = lJNIEnv->CallFloatMethod(ObjectMotionEvent, MethodGetAxisValue, 0x00000001);
lJNIEnv->DeleteLocalRef(ClassMotionEvent);
lJNIEnv->DeleteLocalRef(ObjectMotionEvent);
// Create and send our mouse wheel event // Create and send our mouse wheel event
Event event; Event event;
event.type = Event::MouseWheelMoved; event.type = Event::MouseWheelMoved;
@ -351,11 +354,13 @@ void WindowImplAndroid::processScrollEvent(AInputEvent* _event, ActivityStates*
// Detach this thread from the JVM // Detach this thread from the JVM
lJavaVM->DetachCurrentThread(); lJavaVM->DetachCurrentThread();
return 1;
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void WindowImplAndroid::processKeyEvent(AInputEvent* _event, ActivityStates* states) int WindowImplAndroid::processKeyEvent(AInputEvent* _event, ActivityStates* states)
{ {
int32_t device = AInputEvent_getSource(_event); int32_t device = AInputEvent_getSource(_event);
int32_t action = AKeyEvent_getAction(_event); int32_t action = AKeyEvent_getAction(_event);
@ -374,7 +379,7 @@ void WindowImplAndroid::processKeyEvent(AInputEvent* _event, ActivityStates* sta
case AKEY_EVENT_ACTION_DOWN: case AKEY_EVENT_ACTION_DOWN:
event.type = Event::KeyPressed; event.type = Event::KeyPressed;
forwardEvent(event); forwardEvent(event);
break; return 1;
case AKEY_EVENT_ACTION_UP: case AKEY_EVENT_ACTION_UP:
event.type = Event::KeyReleased; event.type = Event::KeyReleased;
forwardEvent(event); forwardEvent(event);
@ -385,7 +390,7 @@ void WindowImplAndroid::processKeyEvent(AInputEvent* _event, ActivityStates* sta
event.text.unicode = unicode; event.text.unicode = unicode;
forwardEvent(event); forwardEvent(event);
} }
break; return 1;
case AKEY_EVENT_ACTION_MULTIPLE: case AKEY_EVENT_ACTION_MULTIPLE:
// Since complex inputs don't get separate key down/up events // Since complex inputs don't get separate key down/up events
// both have to be faked at once // both have to be faked at once
@ -400,27 +405,26 @@ void WindowImplAndroid::processKeyEvent(AInputEvent* _event, ActivityStates* sta
{ {
// This is a unique sequence, which is not yet exposed in the NDK // This is a unique sequence, which is not yet exposed in the NDK
// http://code.google.com/p/android/issues/detail?id=33998 // http://code.google.com/p/android/issues/detail?id=33998
return 0;
} }
else else if (int unicode = getUnicode(_event)) // This is a repeated sequence
{ {
// This is a repeated sequence event.type = Event::TextEntered;
if (int unicode = getUnicode(_event)) event.text.unicode = unicode;
{
event.type = Event::TextEntered;
event.text.unicode = unicode;
int32_t repeats = AKeyEvent_getRepeatCount(_event); int32_t repeats = AKeyEvent_getRepeatCount(_event);
for (int32_t i = 0; i < repeats; ++i) for (int32_t i = 0; i < repeats; ++i)
forwardEvent(event); forwardEvent(event);
} return 1;
} }
break; break;
} }
return 0;
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void WindowImplAndroid::processMotionEvent(AInputEvent* _event, ActivityStates* states) int WindowImplAndroid::processMotionEvent(AInputEvent* _event, ActivityStates* states)
{ {
int32_t device = AInputEvent_getSource(_event); int32_t device = AInputEvent_getSource(_event);
int32_t action = AMotionEvent_getAction(_event); int32_t action = AMotionEvent_getAction(_event);
@ -462,11 +466,12 @@ void WindowImplAndroid::processMotionEvent(AInputEvent* _event, ActivityStates*
forwardEvent(event); forwardEvent(event);
} }
return 1;
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void WindowImplAndroid::processPointerEvent(bool isDown, AInputEvent* _event, ActivityStates* states) int WindowImplAndroid::processPointerEvent(bool isDown, AInputEvent* _event, ActivityStates* states)
{ {
int32_t device = AInputEvent_getSource(_event); int32_t device = AInputEvent_getSource(_event);
int32_t action = AMotionEvent_getAction(_event); int32_t action = AMotionEvent_getAction(_event);
@ -525,6 +530,7 @@ void WindowImplAndroid::processPointerEvent(bool isDown, AInputEvent* _event, Ac
} }
forwardEvent(event); forwardEvent(event);
return 1;
} }
@ -693,6 +699,9 @@ int WindowImplAndroid::getUnicode(AInputEvent* event)
jmethodID MethodGetUnicode = lJNIEnv->GetMethodID(ClassKeyEvent, "getUnicodeChar", "(I)I"); jmethodID MethodGetUnicode = lJNIEnv->GetMethodID(ClassKeyEvent, "getUnicodeChar", "(I)I");
int unicode = lJNIEnv->CallIntMethod(ObjectKeyEvent, MethodGetUnicode, metaState); int unicode = lJNIEnv->CallIntMethod(ObjectKeyEvent, MethodGetUnicode, metaState);
lJNIEnv->DeleteLocalRef(ClassKeyEvent);
lJNIEnv->DeleteLocalRef(ObjectKeyEvent);
// Detach this thread from the JVM // Detach this thread from the JVM
lJavaVM->DetachCurrentThread(); lJavaVM->DetachCurrentThread();

View File

@ -194,10 +194,10 @@ private:
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
static int processEvent(int fd, int events, void* data); static int processEvent(int fd, int events, void* data);
static void processScrollEvent(AInputEvent* _event, ActivityStates* states); static int processScrollEvent(AInputEvent* _event, ActivityStates* states);
static void processKeyEvent(AInputEvent* _event, ActivityStates* states); static int processKeyEvent(AInputEvent* _event, ActivityStates* states);
static void processMotionEvent(AInputEvent* _event, ActivityStates* states); static int processMotionEvent(AInputEvent* _event, ActivityStates* states);
static void processPointerEvent(bool isDown, AInputEvent* event, ActivityStates* states); static int processPointerEvent(bool isDown, AInputEvent* event, ActivityStates* states);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Convert a Android key to SFML key code /// \brief Convert a Android key to SFML key code