Skip to content

Commit

Permalink
Android: Updated the JNI/event handling code
Browse files Browse the repository at this point in the history
* 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).
  • Loading branch information
MarioLiebisch authored and eXpl0it3r committed Jun 11, 2015
1 parent cadc4d8 commit 11357b3
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 36 deletions.
10 changes: 10 additions & 0 deletions src/SFML/Window/Android/InputImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
Expand All @@ -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,
Expand All @@ -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)
{
Expand All @@ -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();
Expand Down
73 changes: 41 additions & 32 deletions src/SFML/Window/Android/WindowImplAndroid.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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);

Expand All @@ -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)
Expand All @@ -256,34 +257,31 @@ 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;
}

// todo: investigate AMOTION_EVENT_OUTSIDE
case AMOTION_EVENT_ACTION_POINTER_DOWN:
case AMOTION_EVENT_ACTION_DOWN:
{
processPointerEvent(true, _event, states);
handled = 1;
handled = processPointerEvent(true, _event, states);
break;
}

case AMOTION_EVENT_ACTION_POINTER_UP:
case AMOTION_EVENT_ACTION_UP:
case AMOTION_EVENT_ACTION_CANCEL:
{
processPointerEvent(false, _event, states);
handled = 1;
handled = processPointerEvent(false, _event, states);
break;
}
}
Expand All @@ -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;
Expand All @@ -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);
Expand All @@ -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;
Expand All @@ -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);
Expand All @@ -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);
Expand All @@ -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
Expand All @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -525,6 +530,7 @@ void WindowImplAndroid::processPointerEvent(bool isDown, AInputEvent* _event, Ac
}

forwardEvent(event);
return 1;
}


Expand Down Expand Up @@ -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();

Expand Down
8 changes: 4 additions & 4 deletions src/SFML/Window/Android/WindowImplAndroid.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -194,10 +194,10 @@ class WindowImplAndroid : public WindowImpl
////////////////////////////////////////////////////////////
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
Expand Down

0 comments on commit 11357b3

Please sign in to comment.