Pie*_*rre 7 c++ unicode android opengl-es android-ndk
(Android,NDK,C++,OpenGL ES)
我需要一种方法可靠地从(软)键盘接收文本输入.解决方案可以通过Java使用NativeActivity子类或任何有效的方法.最后我需要输入任何文本,所以我可以用OpenGL自己渲染它
一些背景: 到目前为止,我通过调用showSoftInput或hideSoftInputFromWindow来调用JNI来触发软键盘.这到目前为止从未失败过.但是,问题是本机活动不会发送所有字符.特别是ASCII范围之外的一些unicode字符,或某些运动软键盘不起作用(AKeyEvent_getKeyCode)
以前可以获取一些其他unicode字符,以便检查KeyEvent.ACTION_MULTIPLE并读取一串字符.但即使这样也不会再可靠.
到目前为止,我没有找到替代方法.我尝试以编程方式添加EditText,但从未让它工作.即使尝试添加一个简单的Button也导致OpenGL视图不再被渲染.
在iOS上我通过隐藏编辑框来解决它,我只是激活它以使键盘显示.然后我会读出编辑框并使用字符串在OpenGL中渲染自己.
我有同样的问题,我已经使用一个'Character'事件解决了它,该事件与InputEvent分开处理。
问题是这样的:AKeyEvent_getKeyCode在某些软键事件中,尤其是在您按住某个键时,扩展的“ unicode / latin”字符不会返回KeyCode。这会阻止方法@Shammi和@eozgonul起作用,因为KeyEventJava方面的重构没有足够的信息来获取Unicode字符。
另一个问题是,在触发事件InputQueue之前,C ++ / Native端已经耗尽dispatchKeyEvent了。这意味着KEYDOWN / KEYUP事件都在Java代码可以处理事件之前触发。(它们没有交错)。
我的解决方案是通过覆盖dispatchKeyEvent字符并将其发送到Java端来捕获Java端的unicode字符Queue<Integer> queueLastInputCharacter = new ConcurrentLinkedQueue<Integer>();
// [JAVA]
@Override
public boolean dispatchKeyEvent (KeyEvent event)
{
int metaState = event.getMetaState();
int unichar = event.getUnicodeChar(metaState);
// We are queuing the Unicode version of the characters for
// sending to the app during processEvents() call.
// We Queue the KeyDown and ActionMultiple Event UnicodeCharacters
if(event.getAction()==KeyEvent.ACTION_DOWN){
if(unichar != 0){
queueLastInputCharacter.offer(Integer.valueOf(unichar));
}
else{
unichar = event.getUnicodeChar();
if(unichar != 0){
queueLastInputCharacter.offer(Integer.valueOf(unichar));
}
else if (event.getDisplayLabel() != 0){
String aText = new String();
aText = "";
aText += event.getDisplayLabel();
queueLastInputCharacter.offer(Integer.valueOf(Character.codePointAt(aText, 0)));
}
else
queueLastInputCharacter.offer(Integer.valueOf(0));
}
}
else if(event.getAction()==KeyEvent.ACTION_MULTIPLE){
unichar = (Character.codePointAt(event.getCharacters(), 0));
queueLastInputCharacter.offer(Integer.valueOf(unichar));
}
return super.dispatchKeyEvent(event);
}
Run Code Online (Sandbox Code Playgroud)
并发队列将使线程一起运行。
我有一个Java端方法,该方法返回最后一个输入字符:
// [JAVA]
public int getLastUnicodeChar(){
if(!queueLastInputCharacter.isEmpty())
return queueLastInputCharacter.poll().intValue();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
在循环代码的结尾,我进行了额外的检查,以查看队列是否保留了任何unicode字符:
// [C++]
int ident;
int events;
struct android_poll_source* source;
// If not rendering, we will block 250ms waiting for events.
// If animating, we loop until all events are read, then continue
// to draw the next frame of animation.
while ((ident = ALooper_pollAll(((nv_app_status_focused(_lpApp)) ? 1 : 250),
NULL,
&events,
(void**)&source)) >= 0)
{
// Process this event.
if (source != NULL)
source->process(_lpApp, source);
// Check if we are exiting. If so, dump out
if (!nv_app_status_running(_lpApp))
return;
}
static int modtime = 10; // let's not run on every call
if(--modtime == 0) {
long uniChar = androidUnicodeCharFromKeyEvent();
while (uniChar != 0) {
KEvent kCharEvent; // Game engine event
kCharEvent.ptkKey = K_VK_ERROR;
kCharEvent.unicodeChar = uniChar;
kCharEvent.character = uniChar;
/* Send unicode char */
kCharEvent.type = K_EVENT_UNICHAR;
_lpPortableHandler(&kCharEvent);
if (kCharEvent.character < 127) {
/* Send ascii char for source compatibility as well */
kCharEvent.type = K_EVENT_CHAR;
_lpPortableHandler(&kCharEvent);
}
uniChar = androidUnicodeCharFromKeyEvent();
}
modtime = 10;
}
Run Code Online (Sandbox Code Playgroud)
该androidUnicodeCharFromKeyEvent功能与@Shammi的GetStringFromAInputEvent方法非常相似,仅用于CallIntMethod返回jint。
注意
这确实需要修改引擎以处理与按键事件分开的字符事件。Android仍具有诸如AKEYCODE_BACK或AKEYCODE_ENTER不是字符事件之类的键代码,并且仍需要进行处理(可以在主输入循环程序上进行处理)。
编辑框,控制台等...可以修改期望用户输入的内容,以接收构建字符串的单独字符事件。如果您在多个平台上工作,那么除了正常的按键输入事件之外,您还需要生成这些新的字符事件。
我希望这对您有用,到目前为止对我有用。
int GetUnicodeChar(struct android_app* app, int eventType, int keyCode, int metaState)
{
JavaVM* javaVM = app->activity->vm;
JNIEnv* jniEnv = app->activity->env;
JavaVMAttachArgs attachArgs;
attachArgs.version = JNI_VERSION_1_6;
attachArgs.name = "NativeThread";
attachArgs.group = NULL;
jint result = javaVM->AttachCurrentThread(&jniEnv, &attachArgs);
if(result == JNI_ERR)
{
return 0;
}
jclass class_key_event = jniEnv->FindClass("android/view/KeyEvent");
int unicodeKey;
if(metaState == 0)
{
jmethodID method_get_unicode_char = jniEnv->GetMethodID(class_key_event, "getUnicodeChar", "()I");
jmethodID eventConstructor = jniEnv->GetMethodID(class_key_event, "<init>", "(II)V");
jobject eventObj = jniEnv->NewObject(class_key_event, eventConstructor, eventType, keyCode);
unicodeKey = jniEnv->CallIntMethod(eventObj, method_get_unicode_char);
}
else
{
jmethodID method_get_unicode_char = jniEnv->GetMethodID(class_key_event, "getUnicodeChar", "(I)I");
jmethodID eventConstructor = jniEnv->GetMethodID(class_key_event, "<init>", "(II)V");
jobject eventObj = jniEnv->NewObject(class_key_event, eventConstructor, eventType, keyCode);
unicodeKey = jniEnv->CallIntMethod(eventObj, method_get_unicode_char, metaState);
}
javaVM->DetachCurrentThread();
LOGI("Unicode key is: %d", unicodeKey);
return unicodeKey;
}
Run Code Online (Sandbox Code Playgroud)
只需从您的输入处理程序调用它,我的结构大致如下:
switch (AInputEvent_getType(event))
{
case AINPUT_EVENT_TYPE_KEY:
switch (AKeyEvent_getAction(event))
{
case AKEY_EVENT_ACTION_DOWN:
int key = AKeyEvent_getKeyCode(event);
int metaState = AKeyEvent_getMetaState(event);
int uniValue;
if(metaState != 0)
uniValue = GetUnicodeChar(app, AKEY_EVENT_ACTION_DOWN, key, metaState);
else
uniValue = GetUnicodeChar(app, AKEY_EVENT_ACTION_DOWN, key, 0);
Run Code Online (Sandbox Code Playgroud)
既然您说过您已经打开了软键盘,所以我不再赘述,但是代码很简单。我基本上使用具有GetUnicodeChar函数的KeyEvent类的Java函数。
| 归档时间: |
|
| 查看次数: |
2494 次 |
| 最近记录: |