【LVGL第02集】中文输入法的问题
实现的效果

官方中文输入法
使用方法
- 打开拼音输入功能
#define LV_USE_IME_PINYIN 0
- 配置字典
使用默认字典
#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.
官方输入法的问题
- 输入 法与keyboard分离。keyboard事件处理复杂,输入法与keyboard 同时操作textare,逻辑复杂。
- 输入法的待选是基于不是基于本节点创建,删除时可能有问题.如下为原码
/* Init pinyin_ime->cand_panel */
pinyin_ime->cand_panel = lv_btnmatrix_create(lv_scr_act());
- 输入法创建后默认一直起作用,当切换输入方式,比如从中文到英文时,很不方便。可能要修改原有的处理逻辑才能实现
- 中文字典创建不方便,没有直接可以用的工具
- keyboard的默认键盘不太好用,大多数情况下要重新布局,
输入法的优化
思路
- 基于lv_btnmatrix 控件,直接重造keyboard, 基于keyboard的其中一种模式下,加入中文解析
- 仿照拼音的控件,在需要时显示待选.
- 实现基于中文自建字典的脚本工具
实现
创建新的控件
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()
浙公网安备 33010602011771号