在C/C++中接收完整的android unicode输入

 失憶壹瞬間_533 发布于 2023-02-02 19:43

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

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

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

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

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

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

2 个回答
  • 我有同样的问题,我已经使用一个'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);
    }
    

    并发队列将使线程一起运行。

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

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

    在循环代码的结尾,我进行了额外的检查,以查看队列是否保留了任何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

    注意 这确实需要修改引擎以处理与按键事件分开的字符事件。Android仍具有诸如AKEYCODE_BACKAKEYCODE_ENTER不是字符事件之类的键代码,并且仍需要进行处理(可以在主输入循环程序上进行处理)。

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

    2023-02-02 19:45 回答
  • 我希望这对您有用,到目前为止对我有用。

    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;
    }
    

    只需从您的输入处理程序调用它,我的结构大致如下:

    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);
    

    既然您说过您已经打开了软键盘,所以我不再赘述,但是代码很简单。我基本上使用具有GetUnicodeChar函数的KeyEvent类的Java函数。

    2023-02-02 19:47 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有