在 C/C++ 中接收完整的 android unicode 输入 [英] Receive complete android unicode input in C/C++

查看:15
本文介绍了在 C/C++ 中接收完整的 android unicode 输入的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

(Android、NDK、C++、OpenGL ES)

(Android, NDK, C++, OpenGL ES)

我需要一种方法来可靠地接收来自(软)键盘的文本输入.解决方案可以通过 Java 使用 NativeActivity 子类,或者任何可行的方法.最后,我需要输入任何文本,因此我可以使用 OpenGL 自己渲染它

I need a way to reliably receive the text input from a (soft)keyboard. The solution can be through Java using a NativeActivity subclass, or anything which works. At the end I need whatever text is being typed, so I can render it myself with OpenGL

一些背景:到目前为止,我一直通过调用 showSoftInput 或 hideSoftInputFromWindow 来触发软键盘,我认为是 JNI.到目前为止,这从未失败过.但是,问题是本机活动不会发送所有字符.尤其是一些超出 ASCII 范围的 unicode 字符,或者某些运动软键盘不起作用(AKeyEvent_getKeyCode)

Some background: Up until now I was triggering the soft keyboard by calling showSoftInput or hideSoftInputFromWindow thought JNI. This never failed so far. However, the problem is the native activity will not send all characters. Especially some unicode characters outside of ASCII range, or some motion soft keyboard won't work (AKeyEvent_getKeyCode)

以前可以获取一些其他 unicode 字符,为什么要检查 KeyEvent.ACTION_MULTIPLE 并读取字符串.但即使这样也不再可靠.

It used to be possible to get some of those other unicode characters why checking for KeyEvent.ACTION_MULTIPLE and reading a string of characters. But even this won't work reliably anymore.

到目前为止,我还没有找到替代方法.我尝试以编程方式添加 EditText,但从未让它工作.即使尝试添加一个简单的 Button 也会导致 OpenGL 视图不再被渲染.

So far I failed to find an alternative method. I experimented with programmatically adding a EditText, but never got it to work. Even trying to add a simple Button resulted in the OpenGL view to no longer being rendered.

在 iOS 上,我通过隐藏编辑框来解决这个问题,我只是激活它以显示键盘.然后我会读出编辑框并使用字符串在 OpenGL 中呈现自己.

On iOS I worked around it by having a hiding edit box, which I simply activated to make the keyboard show up. I would then read out the edit box and use the string to render myself in OpenGL.

推荐答案

我也有同样的问题,我已经使用与 InputEvent 分开处理的 'Character' 事件解决了它.

I have the same issues, and I have solved it using a 'Character' event that I process separately from the InputEvent.

问题是这样的:AKeyEvent_getKeyCode 不返回某些软键事件的 KeyCode,尤其是当您按住某个键时扩展的unicode/latin"字符.这会阻止 @Shammi 和 @eozgonul 方法工作,因为在 Java 端重构的 KeyEvent 没有足够的信息来获取 unicode 字符.

The problem is this: AKeyEvent_getKeyCode doesn't return the KeyCode for some softkey events, notably the expanded 'unicode/latin' characters when you hold down a key. This prevents the methods @Shammi and @eozgonul from working because the KeyEvent reconstructed on the Java side doesn't have enough information to get a unicode character.

另一个问题是 InputQueuedispatchKeyEvent 事件被触发之前已在 C++/Native 端耗尽.这意味着 KEYDOWN/KEYUP 事件在 Java 代码可以处理事件之前全部触发.(它们没有交错).

Another issue is that the InputQueue is drained on the C++/Native side before the dispatchKeyEvent event(s) are fired. This means that the KEYDOWN/KEYUP events all fired before the Java code can process the events. (They are not interleaved).

我的解决方案是通过覆盖 dispatchKeyEvent 并将字符发送到 Queue 来捕获 Java 端的 unicode 字符.queueLastInputCharacter = new ConcurrentLinkedQueue();

My solution is to capture the unicode characters on the Java side by overriding dispatchKeyEvent and sending the characters to a 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);
}

并发队列会让线程一起玩得很好.

The concurrent queue is going to let the threads play nice together.

我有一个返回最后一个输入字符的 Java 端方法:

I have a Java side method that returns the last input character:

// [JAVA]
public int getLastUnicodeChar(){
    if(!queueLastInputCharacter.isEmpty())
        return queueLastInputCharacter.poll().intValue();
    return 0;
}

在我的 looper 代码的最后,我添加了一个额外的检查来查看队列是否保留了任何 unicode 字符:

At the end of my looper code, I tacked on an extra check to see if the queue retained any unicode characters:

// [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.

The androidUnicodeCharFromKeyEvent function is very similar to @Shammi 's GetStringFromAInputEvent method, only use CallIntMethod to return the jint.

注意事项这确实需要修改您的引擎以处理与键事件分开的角色事件.Android 仍然有像 AKEYCODE_BACKAKEYCODE_ENTER 这样的键码,它们不是字符事件,仍然需要处理(并且可以在主输入循环器上处理).

Notes This does require modifying your engine to process character events separate from Key events. Android still has key codes like AKEYCODE_BACK or AKEYCODE_ENTER that are not character events and still need to be handled (and can be handled on the main input looper).

编辑框、控制台等...可以修改期望用户输入的内容,以接收构建字符串的单独字符事件.如果您在多个平台上工作,那么除了正常的按键输入事件之外,您还需要生成这些新的字符事件.

Editboxes, consoles, etc... Things that are expecting user input can be modified to receive a separate character event that builds the string. If you are working on multiple platforms, then you will need to generate these new character events in addition to the normal key input events.

这篇关于在 C/C++ 中接收完整的 android unicode 输入的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆