glfw库不能正常输入中文

背景

在ubuntu上编译出的鸿蒙UI框架输入框不能输入中文。分析整个输入流程没有什么问题,发现输入系统应该给UI框架返回一个unicode字符,但输入法没有返回。UI框架底层使用的glfw框架,但独对glfw框架进行中文输入测试,发现输入法也不能正常返回unicode字符。输入法是否在任何系统都会返回一个unicode字符存疑,查询资料发现在Window系统中有一个V_CHAR消息返回的就是unicode字符。后在mac系统上测试glfw,发现可以正常输入中文,这几乎就证实了输入法输入中文的规则,就是要发送一个unicode字符到UI框架。查看glfw源码,发现在Windows平台,glfw就是针对V_CHAR进行处理;在Mac系统,使用的Application的insertText来处理中文输入;在linux使用的x11窗口系统,需要单独对按键事件进行处理。

问题根因

没有正确设置语言(setlocale),无论是否使用utf8都需要设置此宏
在glfw代码中判断未定义X_HAVE_UTF8_STRING宏时进行语言的设置,代码全局搜索发现未定义此宏,认为此代码已执行,最终通过打印宏值,发现此宏已定义,猜测可能是在x11库相关的头文件已经定义好了此宏。

以下三种方式都可以将keycode转换成相关的unicode字符,都需要设置语言

  • Xutf8LookupString
  • XmbLookupString
  • XwcLookupString

以下问题可能导致不能正常输入中文:

  • 没有使用setlocate设置语言
  • 没有使用XFilterEvent来处理事件。输入法中合成的unicode字符由它来合成
  • 没有处理XBufferOverflow状态。如果将buffer状态设置过小会出现溢出问题,在glfw库中将其设置为100,防止溢出。
#if !defined(X_HAVE_UTF8_STRING)
    // HACK: If the current locale is C, apply the environment's locale
    //       This is done because the C locale breaks wide character input
    if (strcmp(setlocale(LC_CTYPE, NULL), "C") == 0)
        setlocale(LC_CTYPE, "");
#endif

在ubuntu系统上X_HAVE_UTF8_STRING 宏默认为1,导致没有使用setlocale设置语言,后续不能正常输入中文。

../third_party/flutter/glfw/src/x11_init.c:718:9: note: #pragma message: X_HAVE_UTF8_STRING=1
  718 | #pragma message(PRINT_MACRO(X_HAVE_UTF8_STRING))
      |         ^~~~~~~

相关demo

1. x11 demo

在ubuntu16.04上可正常输入中文的x11 demo
编译: gcc -o x112 x112.c -lX11

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <locale.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>

#define DEFAULT_SIZE 8

int main()
{
    Display *dpy;
    Window root, win;
    XEvent event;
    XIM xim;
    XIC xic;

    if (strcmp(setlocale(LC_CTYPE, NULL), "C") == 0)
        setlocale(LC_CTYPE, "");
    XSetLocaleModifiers("");

    dpy = XOpenDisplay(NULL);
    if (!dpy)
    {
        fprintf(stderr, "Failed to open display.\n");
        exit(1);
    }
    root = DefaultRootWindow(dpy);
    win = XCreateSimpleWindow(dpy, root, 0, 0, 400, 300, 0, 0, WhitePixel(dpy, 0));
    XMapWindow(dpy, win);

    xim = XOpenIM(dpy, NULL, NULL, NULL);
    if (!xim)
    {
        fprintf(stderr, "Failed to open input method.\n");
        exit(1);
    }
    xic = XCreateIC(xim, XNInputStyle, XIMPreeditNothing | XIMStatusNothing, XNClientWindow, win, NULL);
    if (!xic)
    {
        fprintf(stderr, "Failed to create input context.\n");
        exit(1);
    }

    XSetICFocus(xic);
    XSelectInput(dpy, win, ExposureMask | KeyPressMask);

    while (1)
    {
        XNextEvent(dpy, &event);
        XFilterEvent(&event, None);
        switch (event.type)
        {
        case KeyPress:
        {
            Status status;
            KeySym keysym;
            char *pBuff;
            int nSize = DEFAULT_SIZE;
            pBuff = (char *)malloc(nSize);
            memset(pBuff, 0, nSize);

            nSize = Xutf8LookupString(xic, &event.xkey, pBuff, nSize - 1, &keysym, &status);
            if (status == XBufferOverflow)
            {
                printf("LookupString size: %d realloc: %d\n", nSize, nSize + 1);
                pBuff = (char *)realloc(pBuff, nSize + 1);
                memset(pBuff, 0, nSize + 1);
                nSize = Xutf8LookupString(xic, &event.xkey, pBuff, nSize, &keysym, &status);
            }
            printf("LookupString:: status %d keycode %4u keysym 0x%08lx size %2d string '%s'\n", status, event.xkey.keycode, keysym, nSize, pBuff);

            break;
        }
        }
    }

    /* 进入事件循环 */
    // loopEvent(xic, dpy);

    XCloseIM(xim);
    XDestroyIC(xic);
    XDestroyWindow(dpy, win);
    XCloseDisplay(dpy);
    return 0;
}

2. glfw demo

#include <GLFW/glfw3.h>
#include <stdlib.h>
#include <stdio.h>

void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
{
    printf("Key: %i, Scancode: %i\n", key, scancode);
    printf("glfwGetKeyName: %s\n\n", glfwGetKeyName(key, scancode));
}

void char_callback(GLFWwindow* window, unsigned int codepoing)
{
    printf("---> Char: %d\n", codepoing);
   
}

int main()
{
    GLFWwindow* window;

    /* Initialize the library */
    if (!glfwInit())
        return -1;

    /* Create a windowed mode window */
    window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);
    if (!window)
    {
        glfwTerminate();
        return -1;
    }

    /* Register a callback */
    glfwSetKeyCallback(window, key_callback);
    glfwSetCharCallback(window, char_callback);

    /* Loop until the user closes the window */
    while (!glfwWindowShouldClose(window))
    {
        /* Poll for and process events */
        glfwPollEvents();
    }

    glfwTerminate();
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值