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

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中渲染自己.

Jam*_*oag 6

我有同样的问题,我已经使用一个'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_BACKAKEYCODE_ENTER不是字符事件之类的键代码,并且仍需要进行处理(可以在主输入循环程序上进行处理)。

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


eoz*_*nul 5

我希望这对您有用,到目前为止对我有用。

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函数。