• 博客园logo
  • 会员
  • 周边
  • 新闻
  • 博问
  • 闪存
  • 众包
  • 赞助商
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
九书
博客园    首页    新随笔    联系   管理    订阅  订阅

【LVGL第02集】中文输入法的问题

实现的效果

GIF 2025-7-17 14-46-46

官方中文输入法

使用方法

  1. 打开拼音输入功能
#define LV_USE_IME_PINYIN 0
  1. 配置字典
    使用默认字典
  #define LV_IME_PINYIN_USE_DEFAULT_DICT 1

使用自定义字典

  • 创建自己的字典
lv_pinyin_dict_t lv_ime_pinyin_dict[] = {
    { "a", "啊" },
    { "ai", "愛" },
    ...
};

按照上面的方法创建字典,将所有要支持的字写进去。

  • 为拼音输法设定字典
void lv_ime_pinyin_set_dict(lv_obj_t * obj, lv_pinyin_dict_t * dict)

原理和思路

输入法依赖keyboard控件和textarea控件。通过监控keyboard的输入调整textarea的内容。

比如:输入一个字母a. keyboard将字母a输出到textarea,lv_ime_pinyin监控到keyboard的输出a,查询字典,将a相关的字“啊”显示在keyboard上方待选。当用户选择“啊”时,lv_ime_pinyin将字母a从textare中删除,并将中文字“啊”写入textarea.

官方输入法的问题

  1. 输入 法与keyboard分离。keyboard事件处理复杂,输入法与keyboard 同时操作textare,逻辑复杂。
  2. 输入法的待选是基于不是基于本节点创建,删除时可能有问题.如下为原码
    /* Init pinyin_ime->cand_panel */
    pinyin_ime->cand_panel = lv_btnmatrix_create(lv_scr_act());
  1. 输入法创建后默认一直起作用,当切换输入方式,比如从中文到英文时,很不方便。可能要修改原有的处理逻辑才能实现
  2. 中文字典创建不方便,没有直接可以用的工具
  3. keyboard的默认键盘不太好用,大多数情况下要重新布局,

输入法的优化

思路

  1. 基于lv_btnmatrix 控件,直接重造keyboard, 基于keyboard的其中一种模式下,加入中文解析
  2. 仿照拼音的控件,在需要时显示待选.
  3. 实现基于中文自建字典的脚本工具

实现

创建新的控件

const lv_obj_class_t ui_ime_class = {
    .constructor_cb = ui_ime_constructor,
    .width_def = LV_PCT(100),
    .height_def = LV_PCT(50),
    .instance_size = sizeof(ui_ime_t),
    .editable = 1,
    .base_class = &lv_obj_class
};

lv_obj_t* ui_ime_create(lv_obj_t* parent)
{
    LV_LOG_INFO("begin");
    lv_obj_t* obj = lv_obj_class_create_obj(MY_CLASS, parent);
    lv_obj_class_init_obj(obj);
    return obj;
}

static void ui_ime_constructor(const lv_obj_class_t* class_p, lv_obj_t* obj)
{
    LV_UNUSED(class_p);
    lv_obj_clear_flag(obj, LV_OBJ_FLAG_CLICK_FOCUSABLE);

    ui_ime_t* ime = (ui_ime_t*)obj;
    ime->ta = NULL;
   
    lv_obj_remove_style_all(obj);
    lv_obj_set_size(obj, ui_ime_class.width_def, ui_ime_class.height_def);

    lv_obj_set_style_base_dir(obj, LV_BASE_DIR_LTR, 0);
    lv_obj_align(obj, LV_ALIGN_BOTTOM_MID, 0, 0);

    ime->kb_map[UI_IME_MODE_LOWCASE] = ui_kb_map_lc;
    ime->kb_ctrl[UI_IME_MODE_LOWCASE] = ui_kb_ctrl_lc_map;
    ime->kb_map[UI_IME_MODE_UPCASE] = ui_kb_map_uc;
    ime->kb_ctrl[UI_IME_MODE_UPCASE] = ui_kb_ctrl_uc_map;
    ime->kb_map[UI_IME_MODE_NUMBER] = ui_kb_map_num;
    ime->kb_ctrl[UI_IME_MODE_NUMBER] = ui_kb_ctrl_num_map;
    ime->kb_map[UI_IME_MODE_CHINESE] = ui_kb_map_chs;
    ime->kb_ctrl[UI_IME_MODE_CHINESE] = ui_kb_ctrl_chs_map;

    ime->keyboard = lv_btnmatrix_create(obj);
    ...
    lv_obj_add_event_cb(ime->keyboard, ui_ime_keyboard_event_cb, LV_EVENT_VALUE_CHANGED, obj);
    ...

    ime->mode = UI_IME_MODE_LOWCASE;
    ime->cand_panel = lv_btnmatrix_create(obj);
    lv_btnmatrix_set_one_checked(ime->cand_panel, true)
    ...
    /* event handler */
    lv_obj_add_event_cb(ime->cand_panel, ui_ime_cand_panel_event_cb, LV_EVENT_VALUE_CHANGED, obj);
    lv_obj_align_to(ime->cand_panel, ime->keyboard, LV_ALIGN_OUT_TOP_MID, 0, 0);

}

事件回调

void ui_ime_keyboard_event_cb(lv_event_t* e)
{
  if(...)
  {
  }
  else
  {
      if(UI_IME_MODE_CHINESE == ime->mode)
      { 
          if (((txt[0] >= 'a') && (txt[0] <= 'z')) || ((txt[0] >= 'A') && (txt[0] <= 'Z')))
          {
              strcat(ime->input_char, txt);
              ui_ime_input_proc(obj);  /// 基于输入解析字典并显示待选项
                    
          }
      }
  }

脚本工具

# -*- coding: utf-8 -*-
import sys
import re
from collections import defaultdict

try:
    from pypinyin import pinyin, Style
except ImportError:
    print("库文件错误")
    sys.exit(1)

def main():
    if len(sys.argv) != 3:
        print("拼音字典生成器 v1.4")
        print("使用方法: python lv_pinyin.py <输入文件> <输出文件>")
        return

    input_file, output_file = sys.argv[1], sys.argv[2]

    try:
        with open(input_file, 'r', encoding='utf-8') as f:
            content = f.read()
    except FileNotFoundError:
        print(f"错误:输入文件 '{input_file}' 不存在")
        return

    hanzi_list = re.findall(r'[\u4e00-\u9fa5]', content)
    pinyin_dict = defaultdict(set)

    for hanzi in hanzi_list:
        py_list = pinyin(hanzi, style=Style.NORMAL)
        full_py = py_list[0][0].lower()
        pinyin_dict[full_py].add(hanzi)

    first_letter_groups = defaultdict(list)
    for py in pinyin_dict.keys():
        first_char = py[0].lower()
        first_letter_groups[first_char].append(py)

    for letter in first_letter_groups:
        first_letter_groups[letter].sort()

    letters = [chr(ord('a') + i) for i in range(26)]

    try:
        with open(output_file, 'w', encoding='utf-8') as f:
            f.write('#include "lvgl.h"\n\n')
            f.write('lv_pinyin_dict_t my_pinyin_dict[] = {\n')
            
            for letter in letters:
                if letter in first_letter_groups and first_letter_groups[letter]:
                    for py in first_letter_groups[letter]:
                        sorted_chars = sorted(pinyin_dict[py], 
                                            key=lambda x: pinyin(x, style=Style.NORMAL)[0][0])
                        chars_str = ''.join(sorted_chars).replace('"', '\\"')
                        f.write(f'    {{ "{py}", "{chars_str}" }},\n')
                else:
                    f.write(f'    {{ "{letter}", "" }},\n')
            
            f.write('    {NULL, NULL}\n};')
        print(f"生成成功:{output_file}")
    except IOError as e:
        print(f"写入文件失败:{str(e)}")

if __name__ == "__main__":
    main()
posted on 2025-07-17 14:35  九书  阅读(754)  评论(3)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2026
浙公网安备 33010602011771号 浙ICP备2021040463号-3