我需要一种方法可靠地从(软)键盘接收文本输入.
解决方案可以通过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这样的密钥代码,它们不是字符事件,仍然需要处理(并且可以在主输入循环器上处理).
编辑框,控制台等…可以修改期望用户输入的内容以接收构建字符串的单独字符事件.如果您在多个平台上工作,那么除了普通的键输入事件之外,您还需要生成这些新的字符事件.