For example, how to use JNI a little bit faster and much more safer or vice versa =) (based on SFML "setVirtualKeyboardVisible"):
#ifndef _ANDROID_VIRTUAL_KEYBOARD_H_
#define _ANDROID_VIRTUAL_KEYBOARD_H_
#include <jni.h>
class VirtualKeyboard
{
public:
VirtualKeyboard();
explicit VirtualKeyboard(JavaVM* vm, jobject activityObject);
~VirtualKeyboard();
void Init(JavaVM* vm, jobject activityObject);
bool SetVisible(bool b) const;
int GetUnicodeValue(int deviceId, int keyCode, int meta) const;
private:
void Clear();
JavaVM* m_JavaVM;
jobject m_InputMethodManager;
jobject m_DecorView;
jclass m_KeyCharacterMapClass;
jmethodID m_HideSoftInput;
jmethodID m_ShowSoftInput;
jmethodID m_GetWindowToken;
jmethodID m_LoadKeyMap;
jmethodID m_KeyMapGet;
};
#endif // _ANDROID_VIRTUAL_KEYBOARD_H_
Implementation:
#include "virtual_keyboard.h"
#include <android/native_activity.h>
static const char* CONTEXT_PATH = "android/content/Context";
static const char* INPUT_METHOD_MANAGER_PATH = "android/view/inputmethod/InputMethodManager";
static const char* WINDOW_PATH = "android/view/Window";
static const char* VIEW_PATH = "android/view/View";
static const char* KEY_CHARACTER_MAP_PATH = "android/view/KeyCharacterMap";
VirtualKeyboard::VirtualKeyboard():
m_JavaVM(NULL),
m_InputMethodManager(NULL),
m_DecorView(NULL),
m_KeyCharacterMapClass(NULL),
m_HideSoftInput(0),
m_ShowSoftInput(0),
m_GetWindowToken(0),
m_LoadKeyMap(0),
m_KeyMapGet(0)
{
}
VirtualKeyboard::VirtualKeyboard(JavaVM* vm, jobject activityObject):
m_JavaVM(NULL),
m_InputMethodManager(NULL),
m_DecorView(NULL),
m_KeyCharacterMapClass(NULL),
m_HideSoftInput(0),
m_ShowSoftInput(0),
m_GetWindowToken(0),
m_LoadKeyMap(0),
m_KeyMapGet(0)
{
Init(vm, activityObject);
}
VirtualKeyboard::~VirtualKeyboard()
{
Clear();
}
void VirtualKeyboard::Clear()
{
if (!m_JavaVM)
{
return;
}
JNIEnv* env = NULL;
Java::Thread attach(m_JavaVM, env);
env->DeleteWeakGlobalRef(m_InputMethodManager);
env->DeleteWeakGlobalRef(m_DecorView);
env->DeleteWeakGlobalRef(m_KeyCharacterMapClass);
m_JavaVM = NULL;
m_InputMethodManager = NULL;
m_DecorView = NULL;
m_KeyCharacterMapClass = NULL;
m_HideSoftInput = 0;
m_ShowSoftInput = 0;
m_GetWindowToken = 0;
m_LoadKeyMap = 0;
m_KeyMapGet = 0;
}
void VirtualKeyboard::Init(JavaVM* vm, jobject activityObject)
{
if (m_JavaVM)
{
Clear();
}
if (!vm || !activityObject)
{
return;
}
m_JavaVM = vm;
JNIEnv* env = NULL;
Java::Thread attach(m_JavaVM, env);
jclass activityClass = env->GetObjectClass(activityObject);
jclass contextClass = env->FindClass(CONTEXT_PATH);
JAVA_EXCEPTION_CHECK_AND_DO(env, m_JavaVM = NULL; return);
jfieldID fieldINPUT_METHOD_SERVICE = env->GetStaticFieldID(contextClass,
"INPUT_METHOD_SERVICE", "Ljava/lang/String;");
JAVA_EXCEPTION_CHECK_AND_DO(env, m_JavaVM = NULL; return);
jobject INPUT_METHOD_SERVICE = env->GetStaticObjectField(contextClass,
fieldINPUT_METHOD_SERVICE);
JAVA_EXCEPTION_CHECK_AND_DO(env, m_JavaVM = NULL; return);
env->DeleteLocalRef(contextClass);
jclass inputMethodManagerClass =
env->FindClass(INPUT_METHOD_MANAGER_PATH);
JAVA_EXCEPTION_CHECK_AND_DO(env, m_JavaVM = NULL; return);
jmethodID getSystemServiceMethod = env->GetMethodID(activityClass,
"getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;");
JAVA_EXCEPTION_CHECK_AND_DO(env, m_JavaVM = NULL; return);
jobject inputMethodManagerObject = env->CallObjectMethod(activityObject,
getSystemServiceMethod, INPUT_METHOD_SERVICE);
env->DeleteLocalRef(INPUT_METHOD_SERVICE);
jmethodID getWindowMethod = env->GetMethodID(activityClass,
"getWindow", "()Landroid/view/Window;");
JAVA_EXCEPTION_CHECK_AND_DO(env, m_JavaVM = NULL; return);
env->DeleteLocalRef(activityClass);
jobject windowObject = env->CallObjectMethod(activityObject, getWindowMethod);
jclass windowClass = env->FindClass(WINDOW_PATH);
JAVA_EXCEPTION_CHECK_AND_DO(env, m_JavaVM = NULL; return);
jmethodID getDecorViewMethod = env->GetMethodID(windowClass,
"getDecorView", "()Landroid/view/View;");
JAVA_EXCEPTION_CHECK_AND_DO(env, m_JavaVM = NULL; return);
env->DeleteLocalRef(windowClass);
jobject decorViewObject = env->CallObjectMethod(windowObject, getDecorViewMethod);
JAVA_EXCEPTION_CHECK_AND_DO(env, m_JavaVM = NULL; return);
env->DeleteLocalRef(windowObject);
jmethodID showSoftInputMethod = env->GetMethodID(inputMethodManagerClass,
"showSoftInput", "(Landroid/view/View;I)Z");
JAVA_EXCEPTION_CHECK_AND_DO(env, m_JavaVM = NULL; return);
jclass viewClass = env->FindClass(VIEW_PATH);
JAVA_EXCEPTION_CHECK_AND_DO(env, m_JavaVM = NULL; return);
jmethodID getWindowTokenMethod = env->GetMethodID(viewClass,
"getWindowToken", "()Landroid/os/IBinder;");
JAVA_EXCEPTION_CHECK_AND_DO(env, m_JavaVM = NULL; return);
env->DeleteLocalRef(viewClass);
jmethodID hideSoftInputMethod = env->GetMethodID(inputMethodManagerClass,
"hideSoftInputFromWindow", "(Landroid/os/IBinder;I)Z");
JAVA_EXCEPTION_CHECK_AND_DO(env, m_JavaVM = NULL; return);
env->DeleteLocalRef(inputMethodManagerClass);
jclass keyCharacterMapClass = env->FindClass(KEY_CHARACTER_MAP_PATH);
JAVA_EXCEPTION_CHECK_AND_DO(env, m_JavaVM = NULL; return);
jmethodID loadMethod = env->GetStaticMethodID(keyCharacterMapClass,
"load", "(I)Landroid/view/KeyCharacterMap;");
JAVA_EXCEPTION_CHECK_AND_DO(env, m_JavaVM = NULL; return);
jmethodID getMethod = env->GetMethodID(keyCharacterMapClass,
"get", "(II)I");
JAVA_EXCEPTION_CHECK_AND_DO(env, m_JavaVM = NULL; return);
m_InputMethodManager = env->NewWeakGlobalRef(inputMethodManagerObject);
env->DeleteLocalRef(inputMethodManagerObject);
m_DecorView = env->NewWeakGlobalRef(decorViewObject);
env->DeleteLocalRef(decorViewObject);
m_KeyCharacterMapClass = (jclass) env->NewWeakGlobalRef(keyCharacterMapClass);
env->DeleteLocalRef(keyCharacterMapClass);
m_HideSoftInput = hideSoftInputMethod;
m_ShowSoftInput = showSoftInputMethod;
m_GetWindowToken = getWindowTokenMethod;
m_LoadKeyMap = loadMethod;
m_KeyMapGet = getMethod;
}
bool VirtualKeyboard::SetVisible(bool b) const
{
if (!m_JavaVM)
{
return false;
}
JNIEnv* env = NULL;
Java::Thread attach(m_JavaVM, env);
bool res = false;
int flags = 0;
if (b)
{
res = env->CallBooleanMethod(m_InputMethodManager,
m_ShowSoftInput, m_DecorView, flags);
}
else
{
jobject binderObject = env->CallObjectMethod(m_DecorView,
m_GetWindowToken);
res = env->CallBooleanMethod(m_InputMethodManager,
m_HideSoftInput, binderObject, flags);
env->DeleteLocalRef(binderObject);
}
return res;
}
int VirtualKeyboard::GetUnicodeValue(int deviceId, int keyCode, int meta) const
{
if (!m_JavaVM || keyCode == 0)
{
return 0;
}
JNIEnv* env = NULL;
Java::Thread attach(m_JavaVM, env);
jobject kcmObject = env->CallStaticObjectMethod(m_KeyCharacterMapClass, m_LoadKeyMap, deviceId);
JAVA_EXCEPTION_CHECK_CONTINUE(env);
if (!kcmObject)
{
return 0;
}
int unicode = env->CallIntMethod(kcmObject, m_KeyMapGet, keyCode, meta);
JAVA_EXCEPTION_CHECK_CONTINUE(env);
env->DeleteLocalRef(kcmObject);
return unicode;
}
And you have to call
Init function each time "ANativeActivity_onCreate" called.