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:
parent
cadc4d801c
commit
11357b354f
@ -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();
|
||||||
|
@ -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
|
||||||
|
#if __ANDROID_API__ < 13
|
||||||
#define AMOTION_EVENT_ACTION_HOVER_MOVE 0x00000007
|
#define AMOTION_EVENT_ACTION_HOVER_MOVE 0x00000007
|
||||||
#define AMOTION_EVENT_ACTION_SCROLL 0x00000008
|
#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,11 +405,9 @@ 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
|
|
||||||
if (int unicode = getUnicode(_event))
|
|
||||||
{
|
{
|
||||||
event.type = Event::TextEntered;
|
event.type = Event::TextEntered;
|
||||||
event.text.unicode = unicode;
|
event.text.unicode = unicode;
|
||||||
@ -412,15 +415,16 @@ void WindowImplAndroid::processKeyEvent(AInputEvent* _event, ActivityStates* sta
|
|||||||
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();
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user