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

View File

@ -33,9 +33,11 @@
#include <SFML/System/Err.hpp>
#include <android/looper.h>
// Define missing constants
#define AMOTION_EVENT_ACTION_HOVER_MOVE 0x00000007
#define AMOTION_EVENT_ACTION_SCROLL 0x00000008
// Define missing constants for older API levels
#if __ANDROID_API__ < 13
#define AMOTION_EVENT_ACTION_HOVER_MOVE 0x00000007
#define AMOTION_EVENT_ACTION_SCROLL 0x00000008
#endif
////////////////////////////////////////////////////////////
// Private data
@ -232,7 +234,7 @@ int WindowImplAndroid::processEvent(int fd, int events, void* data)
if (AInputQueue_preDispatchEvent(states->inputQueue, _event))
return 1;
int32_t handled = 0;
int handled = 0;
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) &&
key != AKEYCODE_VOLUME_UP && key != AKEYCODE_VOLUME_DOWN)
{
processKeyEvent(_event, states);
handled = 1;
handled = processKeyEvent(_event, states);
}
}
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:
{
processScrollEvent(_event, states);
handled = 1;
handled = processScrollEvent(_event, states);
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:
{
processMotionEvent(_event, states);
handled = 1;
handled = processMotionEvent(_event, states);
break;
}
@ -273,8 +273,7 @@ int WindowImplAndroid::processEvent(int fd, int events, void* data)
case AMOTION_EVENT_ACTION_POINTER_DOWN:
case AMOTION_EVENT_ACTION_DOWN:
{
processPointerEvent(true, _event, states);
handled = 1;
handled = processPointerEvent(true, _event, states);
break;
}
@ -282,8 +281,7 @@ int WindowImplAndroid::processEvent(int fd, int events, void* data)
case AMOTION_EVENT_ACTION_UP:
case AMOTION_EVENT_ACTION_CANCEL:
{
processPointerEvent(false, _event, states);
handled = 1;
handled = processPointerEvent(false, _event, states);
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
jint lResult;
@ -314,8 +312,10 @@ void WindowImplAndroid::processScrollEvent(AInputEvent* _event, ActivityStates*
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;
return 0;
}
// Retrieve everything we need to create this MotionEvent in Java
jlong downTime = AMotionEvent_getDownTime(_event);
@ -340,6 +340,9 @@ void WindowImplAndroid::processScrollEvent(AInputEvent* _event, ActivityStates*
jmethodID MethodGetAxisValue = lJNIEnv->GetMethodID(ClassMotionEvent, "getAxisValue", "(I)F");
jfloat delta = lJNIEnv->CallFloatMethod(ObjectMotionEvent, MethodGetAxisValue, 0x00000001);
lJNIEnv->DeleteLocalRef(ClassMotionEvent);
lJNIEnv->DeleteLocalRef(ObjectMotionEvent);
// Create and send our mouse wheel event
Event event;
event.type = Event::MouseWheelMoved;
@ -351,11 +354,13 @@ void WindowImplAndroid::processScrollEvent(AInputEvent* _event, ActivityStates*
// Detach this thread from the JVM
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 action = AKeyEvent_getAction(_event);
@ -374,7 +379,7 @@ void WindowImplAndroid::processKeyEvent(AInputEvent* _event, ActivityStates* sta
case AKEY_EVENT_ACTION_DOWN:
event.type = Event::KeyPressed;
forwardEvent(event);
break;
return 1;
case AKEY_EVENT_ACTION_UP:
event.type = Event::KeyReleased;
forwardEvent(event);
@ -385,7 +390,7 @@ void WindowImplAndroid::processKeyEvent(AInputEvent* _event, ActivityStates* sta
event.text.unicode = unicode;
forwardEvent(event);
}
break;
return 1;
case AKEY_EVENT_ACTION_MULTIPLE:
// Since complex inputs don't get separate key down/up events
// 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
// 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
if (int unicode = getUnicode(_event))
{
event.type = Event::TextEntered;
event.text.unicode = unicode;
event.type = Event::TextEntered;
event.text.unicode = unicode;
int32_t repeats = AKeyEvent_getRepeatCount(_event);
for (int32_t i = 0; i < repeats; ++i)
forwardEvent(event);
}
int32_t repeats = AKeyEvent_getRepeatCount(_event);
for (int32_t i = 0; i < repeats; ++i)
forwardEvent(event);
return 1;
}
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 action = AMotionEvent_getAction(_event);
@ -462,11 +466,12 @@ void WindowImplAndroid::processMotionEvent(AInputEvent* _event, ActivityStates*
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 action = AMotionEvent_getAction(_event);
@ -525,6 +530,7 @@ void WindowImplAndroid::processPointerEvent(bool isDown, AInputEvent* _event, Ac
}
forwardEvent(event);
return 1;
}
@ -693,6 +699,9 @@ int WindowImplAndroid::getUnicode(AInputEvent* event)
jmethodID MethodGetUnicode = lJNIEnv->GetMethodID(ClassKeyEvent, "getUnicodeChar", "(I)I");
int unicode = lJNIEnv->CallIntMethod(ObjectKeyEvent, MethodGetUnicode, metaState);
lJNIEnv->DeleteLocalRef(ClassKeyEvent);
lJNIEnv->DeleteLocalRef(ObjectKeyEvent);
// Detach this thread from the JVM
lJavaVM->DetachCurrentThread();

View File

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