我需要一种方法可靠地从(软)键盘接收文本输入.
解决方案可以通过Java使用NativeActivity子类或任何有效的方法.
最后我需要输入任何文本,所以我可以用OpenGL自己渲染它
一些背景:
到目前为止,我通过调用showSoftInput或hideSoftInputFromWindow来调用JNI来触发软键盘.这到目前为止从未失败过.
但是,问题是本机活动不会发送所有字符.特别是ASCII范围之外的一些unicode字符,或某些运动软键盘不起作用(AKeyEvent_getKeyCode)
以前可以获取一些其他unicode字符,以便检查KeyEvent.ACTION_MULTIPLE并读取一串字符.
但即使这样也不会再可靠.
到目前为止,我没有找到替代方法.
我尝试以编程方式添加EditText,但从未让它工作.即使尝试添加一个简单的Button也导致OpenGL视图不再被渲染.
解决方法
问题是:AKeyEvent_getKeyCode不会返回某些软键事件的KeyCode,特别是按住键时扩展的“unicode / latin”字符.这可以防止方法@Shammi和@eozgonul工作,因为在Java端重建的KeyEvent没有足够的信息来获取unicode字符.
另一个问题是在触发dispatchKeyEvent事件之前,在C / Native端排出了InputQueue.这意味着KEYDOWN / KEYUP事件在Java代码可以处理事件之前全部触发. (它们不是交错的).
我的解决方案是通过重写dispatchKeyEvent并将字符发送到Queue< Integer>来捕获Java端的unicode字符. 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); }
并发队列将让线程一起玩得很好.
我有一个Java方法返回最后一个输入字符:
// [JAVA] public int getLastUnicodeChar(){ if(!queueLastInputCharacter.isEmpty()) return queueLastInputCharacter.poll().intValue(); return 0; }
在我的looper代码结束时,我进行了额外的检查以查看队列是否保留了任何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; }
androidUnicodeCharFromKeyEvent函数与@Shammi的GetStringFromAInputEvent方法非常相似,只使用CallIntMethod来返回jint.
笔记
这确实需要修改引擎以处理与Key事件分开的字符事件. Android仍然有像AKEYCODE_BACK或AKEYCODE_ENTER这样的密钥代码,它们不是字符事件,仍然需要处理(并且可以在主输入循环器上处理).
编辑框,控制台等…可以修改期望用户输入的内容以接收构建字符串的单独字符事件.如果您在多个平台上工作,那么除了普通的键输入事件之外,您还需要生成这些新的字符事件.