1 /**
2  * @file lv_ime_pinyin.c
3  *
4  */
5 
6 /*********************
7  *      INCLUDES
8  *********************/
9 #include "lv_ime_pinyin_private.h"
10 #include "../../core/lv_obj_class_private.h"
11 #if LV_USE_IME_PINYIN != 0
12 
13 #include "../../lvgl.h"
14 #include "../../core/lv_global.h"
15 
16 /*********************
17  *      DEFINES
18  *********************/
19 #define MY_CLASS (&lv_ime_pinyin_class)
20 #define cand_len LV_GLOBAL_DEFAULT()->ime_cand_len
21 
22 /**********************
23  *      TYPEDEFS
24  **********************/
25 
26 /**********************
27  *  STATIC PROTOTYPES
28  **********************/
29 static void lv_ime_pinyin_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj);
30 static void lv_ime_pinyin_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj);
31 static void lv_ime_pinyin_style_change_event(lv_event_t * e);
32 static void lv_ime_pinyin_kb_event(lv_event_t * e);
33 static void lv_ime_pinyin_cand_panel_event(lv_event_t * e);
34 
35 static void init_pinyin_dict(lv_obj_t * obj, const lv_pinyin_dict_t * dict);
36 static void pinyin_input_proc(lv_obj_t * obj);
37 static void pinyin_page_proc(lv_obj_t * obj, uint16_t btn);
38 static char * pinyin_search_matching(lv_obj_t * obj, char * py_str, uint16_t * cand_num);
39 static void pinyin_ime_clear_data(lv_obj_t * obj);
40 
41 #if LV_IME_PINYIN_USE_K9_MODE
42     static void pinyin_k9_init_data(lv_obj_t * obj);
43     static void pinyin_k9_get_legal_py(lv_obj_t * obj, char * k9_input, const char * py9_map[]);
44     static bool pinyin_k9_is_valid_py(lv_obj_t * obj, char * py_str);
45     static void pinyin_k9_fill_cand(lv_obj_t * obj);
46     static void pinyin_k9_cand_page_proc(lv_obj_t * obj, uint16_t dir);
47 #endif
48 
49 /**********************
50  *  STATIC VARIABLES
51  **********************/
52 
53 const lv_obj_class_t lv_ime_pinyin_class = {
54     .constructor_cb = lv_ime_pinyin_constructor,
55     .destructor_cb  = lv_ime_pinyin_destructor,
56     .width_def      = LV_SIZE_CONTENT,
57     .height_def     = LV_SIZE_CONTENT,
58     .group_def      = LV_OBJ_CLASS_GROUP_DEF_TRUE,
59     .instance_size  = sizeof(lv_ime_pinyin_t),
60     .base_class     = &lv_obj_class,
61     .name = "ime-pinyin",
62 };
63 
64 #if LV_IME_PINYIN_USE_K9_MODE
65 static const char * lv_btnm_def_pinyin_k9_map[LV_IME_PINYIN_K9_CAND_TEXT_NUM + 21] = {\
66                                                                                       ",\0", "123\0",  "abc \0", "def\0",  LV_SYMBOL_BACKSPACE"\0", "\n\0",
67                                                                                       ".\0", "ghi\0", "jkl\0", "mno\0",  LV_SYMBOL_KEYBOARD"\0", "\n\0",
68                                                                                       "?\0", "pqrs\0", "tuv\0", "wxyz\0",  LV_SYMBOL_NEW_LINE"\0", "\n\0",
69                                                                                       LV_SYMBOL_LEFT"\0", "\0"
70                                                                                      };
71 
72 static lv_buttonmatrix_ctrl_t default_kb_ctrl_k9_map[LV_IME_PINYIN_K9_CAND_TEXT_NUM + 17] = { 1 };
73 static char   lv_pinyin_k9_cand_str[LV_IME_PINYIN_K9_CAND_TEXT_NUM + 2][LV_IME_PINYIN_K9_MAX_INPUT] = {0};
74 #endif
75 
76 static char   lv_pinyin_cand_str[LV_IME_PINYIN_CAND_TEXT_NUM][4];
77 static char * lv_btnm_def_pinyin_sel_map[LV_IME_PINYIN_CAND_TEXT_NUM + 3];
78 
79 #if LV_IME_PINYIN_USE_DEFAULT_DICT
80 static const lv_pinyin_dict_t lv_ime_pinyin_def_dict[] = {
81     { "a", "啊" },
82     { "ai", "愛" },
83     { "an", "安暗案" },
84     { "ba", "吧把爸八" },
85     { "bai", "百白敗" },
86     { "ban", "半般辦" },
87     { "bang", "旁" },
88     { "bao", "保薄包報" },
89     { "bei", "被背悲北杯備" },
90     { "ben", "本" },
91     { "bi", "必比避鼻彼筆秘閉" },
92     { "bian", "便邊變変辺" },
93     { "biao", "表標" },
94     { "bie", "別" },
95     { "bing", "病並氷" },
96     { "bo", "波薄泊" },
97     { "bu", "不布步部捕補歩" },
98     { "ca", "察" },
99     { "cai", "才材菜財採" },
100     { "can", "参残參" },
101     { "ce", "策側" },
102     { "ceng", "曾" },
103     { "cha", "差查茶" },
104     { "chai", "差" },
105     { "chan", "產産單" },
106     { "chang", "場廠" },
107     { "chao", "超朝" },
108     { "che", "車" },
109     { "cheng", "成程乗" },
110     { "chi", "尺吃持赤池遅歯" },
111     { "chong", "充种重種" },
112     { "chu", "出初楚触處処" },
113     { "chuan", "川船傳" },
114     { "chuang", "創窓" },
115     { "chun", "春" },
116     { "ci", "此次辞差" },
117     { "cong", "從従" },
118     { "cu", "卒" },
119     { "cun", "存村" },
120     { "cuo", "錯" },
121     { "da", "大打答達" },
122     { "dai", "代待帯帶貸" },
123     { "dan", "但担擔誕單単" },
124     { "dang", "当党當黨" },
125     { "dao", "到道盗導島辺" },
126     { "de", "的得" },
127     { "dei", "" },
128     { "deng", "等" },
129     { "di", "地得低底弟第締" },
130     { "dian", "点电店點電" },
131     { "diao", "調" },
132     { "ding", "定町" },
133     { "dong", "冬東動働凍" },
134     { "du", "独度都渡読" },
135     { "duan", "段断短斷" },
136     { "dui", "對対" },
137     { "duo", "多駄" },
138     { "e", "嗯悪" },
139     { "en", "嗯" },
140     { "er", "而耳二兒" },
141     { "fa", "乏法發発髪" },
142     { "fan", "反返犯番仮販飯範払" },
143     { "fang", "方放房坊訪" },
144     { "fei", "非飛費" },
145     { "fen", "分份" },
146     { "feng", "風豐" },
147     { "fou", "否不" },
148     { "fu", "父夫富服符付附府幅婦復複負払" },
149     { "gai", "改概該" },
150     { "gan", "甘感敢" },
151     { "gang", "港剛" },
152     { "gao", "告高" },
153     { "ge", "各格歌革割個" },
154     { "gei", "給" },
155     { "gen", "跟根" },
156     { "geng", "更" },
157     { "gong", "工共供功公" },
158     { "gou", "夠構溝" },
159     { "gu", "古故鼓" },
160     { "guai", "掛" },
161     { "guan", "官管慣館觀関關" },
162     { "guang", "光広" },
163     { "gui", "規帰" },
164     { "guo", "果国裏菓國過" },
165     { "hai", "孩海害還" },
166     { "han", "寒漢" },
167     { "hang", "航行" },
168     { "hao", "好号" },
169     { "he", "合和喝何荷" },
170     { "hei", "黒" },
171     { "hen", "很" },
172     { "heng", "行横" },
173     { "hou", "厚喉候後" },
174     { "hu", "乎呼湖護" },
175     { "hua", "化画花話畫劃" },
176     { "huai", "壊劃" },
177     { "huan", "緩環歡還換" },
178     { "huang", "黄" },
179     { "hui", "回会慧絵揮會" },
180     { "hun", "混婚" },
181     { "huo", "活或火獲" },
182     { "i", "" },
183     { "ji", "己计及机既急季寄技即集基祭系奇紀積計記済幾際極繼績機濟" },
184     { "jia", "家加價" },
185     { "jian", "件建健肩見減間検簡漸" },
186     { "jiang", "降強講將港" },
187     { "jiao", "叫教交角覚覺較學" },
188     { "jie", "介借接姐皆届界解結階節價" },
189     { "jin", "今近禁金僅進" },
190     { "jing", "京境景静精經経" },
191     { "jiu", "就久九酒究" },
192     { "ju", "句具局居決挙據舉" },
193     { "jue", "角覚覺" },
194     { "jun", "均" },
195     { "kai", "開" },
196     { "kan", "看刊" },
197     { "kang", "康" },
198     { "kao", "考" },
199     { "ke", "可刻科克客渇課" },
200     { "ken", "肯" },
201     { "kong", "空控" },
202     { "kou", "口" },
203     { "ku", "苦庫" },
204     { "kuai", "快塊会會" },
205     { "kuang", "況" },
206     { "kun", "困" },
207     { "kuo", "括拡適" },
208     { "la", "拉啦落" },
209     { "lai", "来來頼" },
210     { "lao", "老絡落" },
211     { "le", "了楽樂" },
212     { "lei", "類" },
213     { "leng", "冷" },
214     { "li", "力立利理例礼離麗裡勵歷" },
215     { "lian", "連練臉聯" },
216     { "liang", "良量涼兩両" },
217     { "liao", "料" },
218     { "lie", "列" },
219     { "lin", "林隣賃" },
220     { "ling", "另令領" },
221     { "liu", "六留流" },
222     { "lu", "律路録緑陸履慮" },
223     { "lv", "旅" },
224     { "lun", "輪論" },
225     { "luo", "落絡" },
226     { "ma", "媽嗎嘛" },
227     { "mai", "買売" },
228     { "man", "滿" },
229     { "mang", "忙" },
230     { "mao", "毛猫貿" },
231     { "me", "麼" },
232     { "mei", "美妹每沒毎媒" },
233     { "men", "們" },
234     { "mi", "米密秘" },
235     { "mian", "免面勉眠" },
236     { "miao", "描" },
237     { "min", "民皿" },
238     { "ming", "命明名" },
239     { "mo", "末模麼" },
240     { "mou", "某" },
241     { "mu", "母木目模" },
242     { "na", "那哪拿內南" },
243     { "nan", "男南難" },
244     { "nao", "腦" },
245     { "ne", "那哪呢" },
246     { "nei", "内那哪內" },
247     { "neng", "能" },
248     { "ni", "你妳呢" },
249     { "nian", "年念" },
250     { "niang", "娘" },
251     { "nin", "您" },
252     { "ning", "凝" },
253     { "niu", "牛" },
254     { "nong", "農濃" },
255     { "nu", "女努" },
256     { "nuan", "暖" },
257     { "o", "" },
258     { "ou", "歐" },
259     { "pa", "怕" },
260     { "pai", "迫派排" },
261     { "pan", "判番" },
262     { "pang", "旁" },
263     { "pei", "配" },
264     { "peng", "朋" },
265     { "pi", "疲否" },
266     { "pian", "片便" },
267     { "pin", "品貧" },
268     { "ping", "平評" },
269     { "po", "迫破泊頗" },
270     { "pu", "普僕" },
271     { "qi", "起其奇七气期泣企妻契気" },
272     { "qian", "嵌浅千前鉛錢針" },
273     { "qiang", "強將" },
274     { "qiao", "橋繰" },
275     { "qie", "且切契" },
276     { "qin", "寝勤親" },
277     { "qing", "青清情晴輕頃請軽" },
278     { "qiu", "求秋球" },
279     { "qu", "去取趣曲區" },
280     { "quan", "全犬券" },
281     { "que", "缺確卻" },
282     { "ran", "然" },
283     { "rang", "讓" },
284     { "re", "熱" },
285     { "ren", "人任認" },
286     { "reng", "仍" },
287     { "ri", "日" },
288     { "rong", "容" },
289     { "rou", "弱若肉" },
290     { "ru", "如入" },
291     { "ruan", "軟" },
292     { "sai", "賽" },
293     { "san", "三" },
294     { "sao", "騒繰" },
295     { "se", "色" },
296     { "sen", "森" },
297     { "sha", "砂" },
298     { "shan", "善山單" },
299     { "shang", "上尚商" },
300     { "shao", "少紹" },
301     { "shaung", "雙" },
302     { "she", "社射設捨渉" },
303     { "shei", "誰" },
304     { "shen", "什申深甚身伸沈神" },
305     { "sheng", "生声昇勝乗聲" },
306     { "shi", "是失示食时事式十石施使世实史室市始柿氏士仕拭時視師試適実實識" },
307     { "shou", "手首守受授" },
308     { "shu", "束数暑殊樹書屬輸術" },
309     { "shui", "水説說誰" },
310     { "shuo", "数説說" },
311     { "si", "思寺司四私似死価" },
312     { "song", "送" },
313     { "su", "速宿素蘇訴" },
314     { "suan", "算酸" },
315     { "sui", "隨雖歲歳" },
316     { "sun", "孫" },
317     { "suo", "所" },
318     { "ta", "她他它牠" },
319     { "tai", "太台態臺" },
320     { "tan", "探談曇" },
321     { "tang", "糖" },
322     { "tao", "桃逃套討" },
323     { "te", "特" },
324     { "ti", "体提替題體戻" },
325     { "tian", "天田" },
326     { "tiao", "条條調" },
327     { "tie", "鉄" },
328     { "ting", "停庭聽町" },
329     { "tong", "同童通痛统統" },
330     { "tou", "投透頭" },
331     { "tu", "土徒茶図" },
332     { "tuan", "團" },
333     { "tui", "推退" },
334     { "tuo", "脱駄" },
335     { "u", "" },
336     { "v", "" },
337     { "wai", "外" },
338     { "wan", "完万玩晩腕灣" },
339     { "wang", "忘望亡往網" },
340     { "wei", "危位未味委為謂維違圍" },
341     { "wen", "文温問聞" },
342     { "wo", "我" },
343     { "wu", "午物五無屋亡鳥務汚" },
344     { "xi", "夕息西洗喜系昔席希析嬉膝細習係" },
345     { "xia", "下夏狭暇" },
346     { "xian", "先限嫌洗現見線顯" },
347     { "xiang", "向相香像想象降項詳響" },
348     { "xiao", "小笑消效校削咲" },
349     { "xie", "写携些解邪械協謝寫契" },
350     { "xin", "心信新辛" },
351     { "xing", "行形性幸型星興" },
352     { "xiong", "兄胸" },
353     { "xiu", "休秀修" },
354     { "xu", "須需許續緒続" },
355     { "xuan", "選懸" },
356     { "xue", "学雪削靴學" },
357     { "xun", "訓訊" },
358     { "ya", "呀押壓" },
359     { "yan", "言顔研煙嚴厳験驗塩" },
360     { "yang", "央洋陽樣様" },
361     { "yao", "要揺腰薬曜" },
362     { "ye", "也野夜邪業葉" },
363     { "yi", "一已亦依以移意医易伊役異億義議藝醫訳" },
364     { "yin", "因引音飲銀" },
365     { "ying", "英迎影映應營営" },
366     { "yong", "永用泳擁" },
367     { "you", "又有右友由尤油遊郵誘優" },
368     { "yu", "予育余雨浴欲愈御宇域語於魚與込" },
369     { "yuan", "元原源院員円園遠猿願" },
370     { "yue", "月越約楽" },
371     { "yun", "雲伝運" },
372     { "za", "雑" },
373     { "zai", "在再載災" },
374     { "zang", "蔵" },
375     { "zao", "早造" },
376     { "ze", "則擇責" },
377     { "zen", "怎" },
378     { "zeng", "曾增増" },
379     { "zha", "札" },
380     { "zhai", "宅擇" },
381     { "zhan", "站展戰戦" },
382     { "zhang", "丈長障帳張" },
383     { "zhao", "找着朝招" },
384     { "zhe", "者這" },
385     { "zhen", "真震針" },
386     { "zheng", "正整争政爭" },
387     { "zhi", "之只知支止制至治直指值置智値紙製質誌織隻識職執" },
388     { "zhong", "中种終重種眾" },
389     { "zhou", "周州昼宙洲週" },
390     { "zhu", "助主住柱株祝逐注著諸屬術" },
391     { "zhuan", "专專転" },
392     { "zhuang", "状狀" },
393     { "zhui", "追" },
394     { "zhun", "準" },
395     { "zhuo", "着" },
396     { "zi", "子自字姉資" },
397     { "zong", "總" },
398     { "zuo", "左做昨坐座作" },
399     { "zu", "足祖族卒組" },
400     { "zui", "最酔" },
401     { "zou", "走" },
402     {NULL, NULL}
403 };
404 #endif
405 
406 /**********************
407  *      MACROS
408  **********************/
409 
410 /**********************
411  *   GLOBAL FUNCTIONS
412  **********************/
lv_ime_pinyin_create(lv_obj_t * parent)413 lv_obj_t * lv_ime_pinyin_create(lv_obj_t * parent)
414 {
415     LV_LOG_INFO("begin");
416     lv_obj_t * obj = lv_obj_class_create_obj(MY_CLASS, parent);
417     lv_obj_class_init_obj(obj);
418     return obj;
419 }
420 
421 /*=====================
422  * Setter functions
423  *====================*/
424 
lv_ime_pinyin_set_keyboard(lv_obj_t * obj,lv_obj_t * kb)425 void lv_ime_pinyin_set_keyboard(lv_obj_t * obj, lv_obj_t * kb)
426 {
427     if(kb) {
428         LV_ASSERT_OBJ(kb, &lv_keyboard_class);
429     }
430 
431     LV_ASSERT_OBJ(obj, MY_CLASS);
432     lv_ime_pinyin_t * pinyin_ime = (lv_ime_pinyin_t *)obj;
433 
434     pinyin_ime->kb = kb;
435     lv_obj_set_parent(obj, lv_obj_get_parent(kb));
436     lv_obj_set_parent(pinyin_ime->cand_panel, lv_obj_get_parent(kb));
437     lv_obj_add_event_cb(pinyin_ime->kb, lv_ime_pinyin_kb_event, LV_EVENT_VALUE_CHANGED, obj);
438     lv_obj_align_to(pinyin_ime->cand_panel, pinyin_ime->kb, LV_ALIGN_OUT_TOP_MID, 0, 0);
439 }
440 
lv_ime_pinyin_set_dict(lv_obj_t * obj,lv_pinyin_dict_t * dict)441 void lv_ime_pinyin_set_dict(lv_obj_t * obj, lv_pinyin_dict_t * dict)
442 {
443     LV_ASSERT_OBJ(obj, MY_CLASS);
444 
445     init_pinyin_dict(obj, dict);
446 }
447 
lv_ime_pinyin_set_mode(lv_obj_t * obj,lv_ime_pinyin_mode_t mode)448 void lv_ime_pinyin_set_mode(lv_obj_t * obj, lv_ime_pinyin_mode_t mode)
449 {
450     LV_ASSERT_OBJ(obj, MY_CLASS);
451     lv_ime_pinyin_t * pinyin_ime = (lv_ime_pinyin_t *)obj;
452 
453     LV_ASSERT_OBJ(pinyin_ime->kb, &lv_keyboard_class);
454 
455     pinyin_ime->mode = mode;
456 
457 #if LV_IME_PINYIN_USE_K9_MODE
458     if(pinyin_ime->mode == LV_IME_PINYIN_MODE_K9) {
459         pinyin_k9_init_data(obj);
460         lv_keyboard_set_map(pinyin_ime->kb, LV_KEYBOARD_MODE_USER_1, (const char **)lv_btnm_def_pinyin_k9_map,
461                             default_kb_ctrl_k9_map);
462         lv_keyboard_set_mode(pinyin_ime->kb, LV_KEYBOARD_MODE_USER_1);
463     }
464 #endif
465 }
466 
467 /*=====================
468  * Getter functions
469  *====================*/
470 
lv_ime_pinyin_get_kb(lv_obj_t * obj)471 lv_obj_t * lv_ime_pinyin_get_kb(lv_obj_t * obj)
472 {
473     LV_ASSERT_OBJ(obj, MY_CLASS);
474 
475     lv_ime_pinyin_t * pinyin_ime = (lv_ime_pinyin_t *)obj;
476 
477     return pinyin_ime->kb;
478 }
479 
lv_ime_pinyin_get_cand_panel(lv_obj_t * obj)480 lv_obj_t * lv_ime_pinyin_get_cand_panel(lv_obj_t * obj)
481 {
482     LV_ASSERT_OBJ(obj, MY_CLASS);
483 
484     lv_ime_pinyin_t * pinyin_ime = (lv_ime_pinyin_t *)obj;
485 
486     return pinyin_ime->cand_panel;
487 }
488 
lv_ime_pinyin_get_dict(lv_obj_t * obj)489 const lv_pinyin_dict_t * lv_ime_pinyin_get_dict(lv_obj_t * obj)
490 {
491     LV_ASSERT_OBJ(obj, MY_CLASS);
492 
493     lv_ime_pinyin_t * pinyin_ime = (lv_ime_pinyin_t *)obj;
494 
495     return pinyin_ime->dict;
496 }
497 
498 /*=====================
499  * Other functions
500  *====================*/
501 
502 /**********************
503  *   STATIC FUNCTIONS
504  **********************/
505 
lv_ime_pinyin_constructor(const lv_obj_class_t * class_p,lv_obj_t * obj)506 static void lv_ime_pinyin_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj)
507 {
508     LV_UNUSED(class_p);
509     LV_TRACE_OBJ_CREATE("begin");
510 
511     lv_ime_pinyin_t * pinyin_ime = (lv_ime_pinyin_t *)obj;
512 
513     uint16_t py_str_i = 0;
514     uint16_t btnm_i = 0;
515     for(btnm_i = 0; btnm_i < (LV_IME_PINYIN_CAND_TEXT_NUM + 3); btnm_i++) {
516         if(btnm_i == 0) {
517             lv_btnm_def_pinyin_sel_map[btnm_i] = "<";
518         }
519         else if(btnm_i == (LV_IME_PINYIN_CAND_TEXT_NUM + 1)) {
520             lv_btnm_def_pinyin_sel_map[btnm_i] = ">";
521         }
522         else if(btnm_i == (LV_IME_PINYIN_CAND_TEXT_NUM + 2)) {
523             lv_btnm_def_pinyin_sel_map[btnm_i] = "";
524         }
525         else {
526             lv_pinyin_cand_str[py_str_i][0] = ' ';
527             lv_btnm_def_pinyin_sel_map[btnm_i] = lv_pinyin_cand_str[py_str_i];
528             py_str_i++;
529         }
530     }
531 
532     pinyin_ime->mode = LV_IME_PINYIN_MODE_K26;
533     pinyin_ime->py_page = 0;
534     pinyin_ime->ta_count = 0;
535     pinyin_ime->cand_num = 0;
536     lv_memzero(pinyin_ime->input_char, sizeof(pinyin_ime->input_char));
537     lv_memzero(pinyin_ime->py_num, sizeof(pinyin_ime->py_num));
538     lv_memzero(pinyin_ime->py_pos, sizeof(pinyin_ime->py_pos));
539 
540     lv_obj_add_flag(obj, LV_OBJ_FLAG_HIDDEN);
541 
542 #if LV_IME_PINYIN_USE_DEFAULT_DICT
543     init_pinyin_dict(obj, lv_ime_pinyin_def_dict);
544 #endif
545 
546     /* Init pinyin_ime->cand_panel */
547     pinyin_ime->cand_panel = lv_buttonmatrix_create(lv_obj_get_parent(obj));
548     lv_buttonmatrix_set_map(pinyin_ime->cand_panel, (const char **)lv_btnm_def_pinyin_sel_map);
549     lv_obj_set_size(pinyin_ime->cand_panel, LV_PCT(100), LV_PCT(5));
550     lv_obj_add_flag(pinyin_ime->cand_panel, LV_OBJ_FLAG_HIDDEN);
551 
552     lv_buttonmatrix_set_one_checked(pinyin_ime->cand_panel, true);
553     lv_obj_remove_flag(pinyin_ime->cand_panel, LV_OBJ_FLAG_CLICK_FOCUSABLE);
554 
555     /* Set cand_panel style*/
556     // Default style
557     lv_obj_set_style_bg_opa(pinyin_ime->cand_panel, LV_OPA_0, 0);
558     lv_obj_set_style_border_width(pinyin_ime->cand_panel, 0, 0);
559     lv_obj_set_style_pad_all(pinyin_ime->cand_panel, 8, 0);
560     lv_obj_set_style_pad_gap(pinyin_ime->cand_panel, 0, 0);
561     lv_obj_set_style_radius(pinyin_ime->cand_panel, 0, 0);
562     lv_obj_set_style_pad_gap(pinyin_ime->cand_panel, 0, 0);
563     lv_obj_set_style_base_dir(pinyin_ime->cand_panel, LV_BASE_DIR_LTR, 0);
564 
565     // LV_PART_ITEMS style
566     lv_obj_set_style_radius(pinyin_ime->cand_panel, 12, LV_PART_ITEMS);
567     lv_obj_set_style_bg_color(pinyin_ime->cand_panel, lv_color_white(), LV_PART_ITEMS);
568     lv_obj_set_style_bg_opa(pinyin_ime->cand_panel, LV_OPA_0, LV_PART_ITEMS);
569     lv_obj_set_style_shadow_opa(pinyin_ime->cand_panel, LV_OPA_0, LV_PART_ITEMS);
570 
571     // LV_PART_ITEMS | LV_STATE_PRESSED style
572     lv_obj_set_style_bg_opa(pinyin_ime->cand_panel, LV_OPA_COVER, LV_PART_ITEMS | LV_STATE_PRESSED);
573     lv_obj_set_style_bg_color(pinyin_ime->cand_panel, lv_color_white(), LV_PART_ITEMS | LV_STATE_PRESSED);
574 
575     /* event handler */
576     lv_obj_add_event_cb(pinyin_ime->cand_panel, lv_ime_pinyin_cand_panel_event, LV_EVENT_VALUE_CHANGED, obj);
577     lv_obj_add_event_cb(obj, lv_ime_pinyin_style_change_event, LV_EVENT_STYLE_CHANGED, NULL);
578 
579 #if LV_IME_PINYIN_USE_K9_MODE
580     pinyin_ime->k9_input_str_len = 0;
581     pinyin_ime->k9_py_ll_pos = 0;
582     pinyin_ime->k9_legal_py_count = 0;
583     lv_memzero(pinyin_ime->k9_input_str, LV_IME_PINYIN_K9_MAX_INPUT);
584 
585     pinyin_k9_init_data(obj);
586 
587     lv_ll_init(&(pinyin_ime->k9_legal_py_ll), sizeof(ime_pinyin_k9_py_str_t));
588 #endif
589 }
590 
lv_ime_pinyin_destructor(const lv_obj_class_t * class_p,lv_obj_t * obj)591 static void lv_ime_pinyin_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj)
592 {
593     LV_UNUSED(class_p);
594 
595     lv_ime_pinyin_t * pinyin_ime = (lv_ime_pinyin_t *)obj;
596 
597     if(lv_obj_is_valid(pinyin_ime->kb))
598         lv_obj_delete(pinyin_ime->kb);
599 
600     if(lv_obj_is_valid(pinyin_ime->cand_panel))
601         lv_obj_delete(pinyin_ime->cand_panel);
602 }
603 
lv_ime_pinyin_kb_event(lv_event_t * e)604 static void lv_ime_pinyin_kb_event(lv_event_t * e)
605 {
606     lv_event_code_t code = lv_event_get_code(e);
607     lv_obj_t * kb = lv_event_get_current_target(e);
608     lv_obj_t * obj = lv_event_get_user_data(e);
609 
610     lv_ime_pinyin_t * pinyin_ime = (lv_ime_pinyin_t *)obj;
611 
612 #if LV_IME_PINYIN_USE_K9_MODE
613     static const char * k9_py_map[8] = {"abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"};
614 #endif
615 
616     if(code == LV_EVENT_VALUE_CHANGED) {
617         uint16_t btn_id  = lv_buttonmatrix_get_selected_button(kb);
618         if(btn_id == LV_BUTTONMATRIX_BUTTON_NONE) return;
619 
620         const char * txt = lv_buttonmatrix_get_button_text(kb, lv_buttonmatrix_get_selected_button(kb));
621         if(txt == NULL) return;
622 
623         lv_obj_t * ta = lv_keyboard_get_textarea(pinyin_ime->kb);
624 
625 #if LV_IME_PINYIN_USE_K9_MODE
626         if(pinyin_ime->mode == LV_IME_PINYIN_MODE_K9) {
627 
628             uint16_t tmp_button_str_len = lv_strlen(pinyin_ime->input_char);
629             if((btn_id >= 16) && (tmp_button_str_len > 0) && (btn_id < (16 + LV_IME_PINYIN_K9_CAND_TEXT_NUM))) {
630                 lv_memzero(pinyin_ime->input_char, sizeof(pinyin_ime->input_char));
631                 lv_strcat(pinyin_ime->input_char, txt);
632                 pinyin_input_proc(obj);
633 
634                 for(int index = 0; index < (pinyin_ime->ta_count + tmp_button_str_len); index++) {
635                     lv_textarea_delete_char(ta);
636                 }
637 
638                 pinyin_ime->ta_count = tmp_button_str_len;
639                 pinyin_ime->k9_input_str_len = tmp_button_str_len;
640                 lv_textarea_add_text(ta, pinyin_ime->input_char);
641 
642                 return;
643             }
644         }
645 #endif
646 
647         if(lv_strcmp(txt, "Enter") == 0 || lv_strcmp(txt, LV_SYMBOL_NEW_LINE) == 0) {
648             pinyin_ime_clear_data(obj);
649             lv_obj_add_flag(pinyin_ime->cand_panel, LV_OBJ_FLAG_HIDDEN);
650         }
651         else if(lv_strcmp(txt, LV_SYMBOL_BACKSPACE) == 0) {
652             // del input char
653             if(pinyin_ime->ta_count > 0) {
654                 if(pinyin_ime->mode == LV_IME_PINYIN_MODE_K26)
655                     pinyin_ime->input_char[pinyin_ime->ta_count - 1] = '\0';
656 #if LV_IME_PINYIN_USE_K9_MODE
657                 else
658                     pinyin_ime->k9_input_str[pinyin_ime->ta_count - 1] = '\0';
659 #endif
660 
661                 pinyin_ime->ta_count--;
662                 if(pinyin_ime->ta_count <= 0) {
663                     pinyin_ime_clear_data(obj);
664                     lv_obj_add_flag(pinyin_ime->cand_panel, LV_OBJ_FLAG_HIDDEN);
665                 }
666                 else if(pinyin_ime->mode == LV_IME_PINYIN_MODE_K26) {
667                     pinyin_input_proc(obj);
668                 }
669 #if LV_IME_PINYIN_USE_K9_MODE
670                 else if(pinyin_ime->mode == LV_IME_PINYIN_MODE_K9) {
671                     pinyin_ime->k9_input_str_len = lv_strlen(pinyin_ime->input_char) - 1;
672                     pinyin_k9_get_legal_py(obj, pinyin_ime->k9_input_str, k9_py_map);
673                     pinyin_k9_fill_cand(obj);
674                     pinyin_input_proc(obj);
675                     pinyin_ime->ta_count--;
676                 }
677 #endif
678             }
679         }
680         else if((lv_strcmp(txt, "ABC") == 0) || (lv_strcmp(txt, "abc") == 0) || (lv_strcmp(txt, "1#") == 0) ||
681                 (lv_strcmp(txt, LV_SYMBOL_OK) == 0)) {
682             pinyin_ime_clear_data(obj);
683             return;
684         }
685         else if(lv_strcmp(txt, "123") == 0) {
686             for(uint16_t i = 0; i < lv_strlen(txt); i++)
687                 lv_textarea_delete_char(ta);
688 
689             pinyin_ime_clear_data(obj);
690             lv_textarea_set_cursor_pos(ta, LV_TEXTAREA_CURSOR_LAST);
691             lv_ime_pinyin_set_mode(obj, LV_IME_PINYIN_MODE_K9_NUMBER);
692             lv_keyboard_set_mode(kb, LV_KEYBOARD_MODE_NUMBER);
693             lv_obj_add_flag(pinyin_ime->cand_panel, LV_OBJ_FLAG_HIDDEN);
694         }
695         else if(lv_strcmp(txt, LV_SYMBOL_KEYBOARD) == 0) {
696             if(pinyin_ime->mode == LV_IME_PINYIN_MODE_K26) {
697                 lv_ime_pinyin_set_mode(obj, LV_IME_PINYIN_MODE_K9);
698             }
699             else if(pinyin_ime->mode == LV_IME_PINYIN_MODE_K9) {
700                 lv_ime_pinyin_set_mode(obj, LV_IME_PINYIN_MODE_K26);
701                 lv_keyboard_set_mode(pinyin_ime->kb, LV_KEYBOARD_MODE_TEXT_LOWER);
702             }
703             else if(pinyin_ime->mode == LV_IME_PINYIN_MODE_K9_NUMBER) {
704                 lv_ime_pinyin_set_mode(obj, LV_IME_PINYIN_MODE_K9);
705             }
706             pinyin_ime_clear_data(obj);
707         }
708         else if((pinyin_ime->mode == LV_IME_PINYIN_MODE_K26) && ((txt[0] >= 'a' && txt[0] <= 'z') || (txt[0] >= 'A' &&
709                                                                                                       txt[0] <= 'Z'))) {
710             uint16_t len = lv_strlen(pinyin_ime->input_char);
711             lv_snprintf(pinyin_ime->input_char + len, sizeof(pinyin_ime->input_char) - len, "%s", txt);
712             pinyin_input_proc(obj);
713             pinyin_ime->ta_count++;
714         }
715 #if LV_IME_PINYIN_USE_K9_MODE
716         else if((pinyin_ime->mode == LV_IME_PINYIN_MODE_K9) && (txt[0] >= 'a' && txt[0] <= 'z')) {
717             for(uint16_t i = 0; i < 8; i++) {
718                 if((lv_strcmp(txt, k9_py_map[i]) == 0) || (lv_strcmp(txt, "abc ") == 0)) {
719                     if(lv_strcmp(txt, "abc ") == 0)    pinyin_ime->k9_input_str_len += lv_strlen(k9_py_map[i]) + 1;
720                     else                            pinyin_ime->k9_input_str_len += lv_strlen(k9_py_map[i]);
721                     pinyin_ime->k9_input_str[pinyin_ime->ta_count] = 50 + i;
722                     pinyin_ime->k9_input_str[pinyin_ime->ta_count + 1] = '\0';
723 
724                     break;
725                 }
726             }
727             pinyin_k9_get_legal_py(obj, pinyin_ime->k9_input_str, k9_py_map);
728             pinyin_k9_fill_cand(obj);
729             pinyin_input_proc(obj);
730         }
731         else if(lv_strcmp(txt, LV_SYMBOL_LEFT) == 0) {
732             pinyin_k9_cand_page_proc(obj, 0);
733         }
734         else if(lv_strcmp(txt, LV_SYMBOL_RIGHT) == 0) {
735             pinyin_k9_cand_page_proc(obj, 1);
736         }
737 #endif
738     }
739 }
740 
lv_ime_pinyin_cand_panel_event(lv_event_t * e)741 static void lv_ime_pinyin_cand_panel_event(lv_event_t * e)
742 {
743     lv_event_code_t code = lv_event_get_code(e);
744     lv_obj_t * cand_panel = lv_event_get_current_target(e);
745     lv_obj_t * obj = (lv_obj_t *)lv_event_get_user_data(e);
746 
747     lv_ime_pinyin_t * pinyin_ime = (lv_ime_pinyin_t *)obj;
748 
749     if(code == LV_EVENT_VALUE_CHANGED) {
750         lv_obj_t * ta = lv_keyboard_get_textarea(pinyin_ime->kb);
751         if(ta == NULL) return;
752 
753         uint32_t id = lv_buttonmatrix_get_selected_button(cand_panel);
754         if(id == LV_BUTTONMATRIX_BUTTON_NONE) {
755             return;
756         }
757         else if(id == 0) {
758             pinyin_page_proc(obj, 0);
759             return;
760         }
761         else if(id == (LV_IME_PINYIN_CAND_TEXT_NUM + 1)) {
762             pinyin_page_proc(obj, 1);
763             return;
764         }
765 
766         const char * txt = lv_buttonmatrix_get_button_text(cand_panel, id);
767         uint16_t index = 0;
768         for(index = 0; index < pinyin_ime->ta_count; index++)
769             lv_textarea_delete_char(ta);
770 
771         lv_textarea_add_text(ta, txt);
772 
773         pinyin_ime_clear_data(obj);
774     }
775 }
776 
pinyin_input_proc(lv_obj_t * obj)777 static void pinyin_input_proc(lv_obj_t * obj)
778 {
779     lv_ime_pinyin_t * pinyin_ime = (lv_ime_pinyin_t *)obj;
780 
781     pinyin_ime->cand_str = pinyin_search_matching(obj, pinyin_ime->input_char, &pinyin_ime->cand_num);
782     if(pinyin_ime->cand_str == NULL) {
783         return;
784     }
785 
786     pinyin_ime->py_page = 0;
787 
788     for(uint8_t i = 0; i < LV_IME_PINYIN_CAND_TEXT_NUM; i++) {
789         lv_memset(lv_pinyin_cand_str[i], 0x00, sizeof(lv_pinyin_cand_str[i]));
790         lv_pinyin_cand_str[i][0] = ' ';
791     }
792 
793     // fill buf
794     for(uint8_t i = 0; (i < pinyin_ime->cand_num && i < LV_IME_PINYIN_CAND_TEXT_NUM); i++) {
795         for(uint8_t j = 0; j < 3; j++) {
796             lv_pinyin_cand_str[i][j] = pinyin_ime->cand_str[i * 3 + j];
797         }
798     }
799 
800     lv_obj_remove_flag(pinyin_ime->cand_panel, LV_OBJ_FLAG_HIDDEN);
801 }
802 
pinyin_page_proc(lv_obj_t * obj,uint16_t dir)803 static void pinyin_page_proc(lv_obj_t * obj, uint16_t dir)
804 {
805     lv_ime_pinyin_t * pinyin_ime = (lv_ime_pinyin_t *)obj;
806     uint16_t page_num = pinyin_ime->cand_num / LV_IME_PINYIN_CAND_TEXT_NUM;
807     uint16_t remainder = pinyin_ime->cand_num % LV_IME_PINYIN_CAND_TEXT_NUM;
808 
809     if(!pinyin_ime->cand_str) return;
810 
811     if(dir == 0) {
812         if(pinyin_ime->py_page) {
813             pinyin_ime->py_page--;
814         }
815     }
816     else {
817         if(remainder == 0) {
818             page_num -= 1;
819         }
820         if(pinyin_ime->py_page < page_num) {
821             pinyin_ime->py_page++;
822         }
823         else return;
824     }
825 
826     for(uint8_t i = 0; i < LV_IME_PINYIN_CAND_TEXT_NUM; i++) {
827         lv_memset(lv_pinyin_cand_str[i], 0x00, sizeof(lv_pinyin_cand_str[i]));
828         lv_pinyin_cand_str[i][0] = ' ';
829     }
830 
831     // fill buf
832     uint16_t offset = pinyin_ime->py_page * (3 * LV_IME_PINYIN_CAND_TEXT_NUM);
833     for(uint8_t i = 0; (i < pinyin_ime->cand_num && i < LV_IME_PINYIN_CAND_TEXT_NUM); i++) {
834         if((remainder > 0) && (pinyin_ime->py_page == page_num)) {
835             if(i >= remainder)
836                 break;
837         }
838         for(uint8_t j = 0; j < 3; j++) {
839             lv_pinyin_cand_str[i][j] = pinyin_ime->cand_str[offset + (i * 3) + j];
840         }
841     }
842 }
843 
lv_ime_pinyin_style_change_event(lv_event_t * e)844 static void lv_ime_pinyin_style_change_event(lv_event_t * e)
845 {
846     lv_event_code_t code = lv_event_get_code(e);
847     lv_obj_t * obj = lv_event_get_current_target(e);
848 
849     lv_ime_pinyin_t * pinyin_ime = (lv_ime_pinyin_t *)obj;
850 
851     if(code == LV_EVENT_STYLE_CHANGED) {
852         const lv_font_t * font = lv_obj_get_style_text_font(obj, LV_PART_MAIN);
853         lv_obj_set_style_text_font(pinyin_ime->cand_panel, font, 0);
854     }
855 }
856 
init_pinyin_dict(lv_obj_t * obj,const lv_pinyin_dict_t * dict)857 static void init_pinyin_dict(lv_obj_t * obj, const lv_pinyin_dict_t * dict)
858 {
859     lv_ime_pinyin_t * pinyin_ime = (lv_ime_pinyin_t *)obj;
860 
861     char headletter = 'a';
862     uint16_t offset_sum = 0;
863     uint16_t offset_count = 0;
864     uint16_t letter_calc = 0;
865 
866     pinyin_ime->dict = dict;
867 
868     for(uint16_t i = 0; ; i++) {
869         if((NULL == (dict[i].py)) || (NULL == (dict[i].py_mb))) {
870             headletter = dict[i - 1].py[0];
871             letter_calc = headletter - 'a';
872             pinyin_ime->py_num[letter_calc] = offset_count;
873             break;
874         }
875 
876         if(headletter == (dict[i].py[0])) {
877             offset_count++;
878         }
879         else {
880             headletter = dict[i].py[0];
881             pinyin_ime->py_num[letter_calc] = offset_count;
882             letter_calc = headletter - 'a';
883             offset_sum += offset_count;
884             pinyin_ime->py_pos[letter_calc] = offset_sum;
885 
886             offset_count = 1;
887         }
888     }
889 }
890 
pinyin_search_matching(lv_obj_t * obj,char * py_str,uint16_t * cand_num)891 static char * pinyin_search_matching(lv_obj_t * obj, char * py_str, uint16_t * cand_num)
892 {
893     lv_ime_pinyin_t * pinyin_ime = (lv_ime_pinyin_t *)obj;
894 
895     const lv_pinyin_dict_t * cpHZ;
896     uint8_t index, len = 0, offset;
897     volatile uint8_t count = 0;
898 
899     if(*py_str == '\0')    return NULL;
900     if(*py_str == 'i')     return NULL;
901     if(*py_str == 'u')     return NULL;
902     if(*py_str == 'v')     return NULL;
903     if(*py_str == ' ')     return NULL;
904 
905     offset = py_str[0] - 'a';
906     len = lv_strlen(py_str);
907 
908     cpHZ  = &pinyin_ime->dict[pinyin_ime->py_pos[offset]];
909     count = pinyin_ime->py_num[offset];
910 
911     while(count--) {
912         for(index = 0; index < len; index++) {
913             if(*(py_str + index) != *((cpHZ->py) + index)) {
914                 break;
915             }
916         }
917 
918         // perfect match
919         if(len == 1 || index == len) {
920             // The Chinese character in UTF-8 encoding format is 3 bytes
921             * cand_num = lv_strlen((const char *)(cpHZ->py_mb)) / 3;
922             return (char *)(cpHZ->py_mb);
923         }
924         cpHZ++;
925     }
926     return NULL;
927 }
928 
pinyin_ime_clear_data(lv_obj_t * obj)929 static void pinyin_ime_clear_data(lv_obj_t * obj)
930 {
931     lv_ime_pinyin_t * pinyin_ime = (lv_ime_pinyin_t *)obj;
932 
933 #if LV_IME_PINYIN_USE_K9_MODE
934     if(pinyin_ime->mode == LV_IME_PINYIN_MODE_K9) {
935         pinyin_ime->k9_input_str_len = 0;
936         pinyin_ime->k9_py_ll_pos = 0;
937         pinyin_ime->k9_legal_py_count = 0;
938         lv_memzero(pinyin_ime->k9_input_str,  LV_IME_PINYIN_K9_MAX_INPUT);
939         lv_memzero(lv_pinyin_k9_cand_str, sizeof(lv_pinyin_k9_cand_str));
940         for(uint8_t i = 0; i < LV_IME_PINYIN_CAND_TEXT_NUM; i++) {
941             lv_strcpy(lv_pinyin_k9_cand_str[i], " ");
942         }
943         lv_strcpy(lv_pinyin_k9_cand_str[LV_IME_PINYIN_K9_CAND_TEXT_NUM], LV_SYMBOL_RIGHT"\0");
944         lv_strcpy(lv_pinyin_k9_cand_str[LV_IME_PINYIN_K9_CAND_TEXT_NUM + 1], "\0");
945         lv_buttonmatrix_set_map(pinyin_ime->kb, (const char **)lv_btnm_def_pinyin_k9_map);
946     }
947 #endif
948 
949     pinyin_ime->ta_count = 0;
950     for(uint8_t i = 0; i < LV_IME_PINYIN_CAND_TEXT_NUM; i++) {
951         lv_memset(lv_pinyin_cand_str[i], 0x00, sizeof(lv_pinyin_cand_str[i]));
952         lv_pinyin_cand_str[i][0] = ' ';
953     }
954     lv_memzero(pinyin_ime->input_char, sizeof(pinyin_ime->input_char));
955 
956     lv_obj_add_flag(pinyin_ime->cand_panel, LV_OBJ_FLAG_HIDDEN);
957 }
958 
959 #if LV_IME_PINYIN_USE_K9_MODE
pinyin_k9_init_data(lv_obj_t * obj)960 static void pinyin_k9_init_data(lv_obj_t * obj)
961 {
962     LV_UNUSED(obj);
963 
964     uint16_t py_str_i = 0;
965     uint16_t btnm_i = 0;
966     for(btnm_i = 19; btnm_i < (LV_IME_PINYIN_K9_CAND_TEXT_NUM + 21); btnm_i++) {
967         if(py_str_i == LV_IME_PINYIN_K9_CAND_TEXT_NUM) {
968             lv_strcpy(lv_pinyin_k9_cand_str[py_str_i], LV_SYMBOL_RIGHT"\0");
969         }
970         else if(py_str_i == LV_IME_PINYIN_K9_CAND_TEXT_NUM + 1) {
971             lv_strcpy(lv_pinyin_k9_cand_str[py_str_i], "\0");
972         }
973         else {
974             lv_strcpy(lv_pinyin_k9_cand_str[py_str_i], " \0");
975         }
976 
977         lv_btnm_def_pinyin_k9_map[btnm_i] = lv_pinyin_k9_cand_str[py_str_i];
978         py_str_i++;
979     }
980 
981     default_kb_ctrl_k9_map[0]  = LV_BUTTONMATRIX_CTRL_CHECKED | 1;
982     default_kb_ctrl_k9_map[1]  = LV_BUTTONMATRIX_CTRL_NO_REPEAT | LV_BUTTONMATRIX_CTRL_CLICK_TRIG | 1;
983     default_kb_ctrl_k9_map[4]  = LV_BUTTONMATRIX_CTRL_CHECKED | 1;
984     default_kb_ctrl_k9_map[5]  = LV_BUTTONMATRIX_CTRL_CHECKED | 1;
985     default_kb_ctrl_k9_map[9]  = LV_KEYBOARD_CTRL_BUTTON_FLAGS | 1;
986     default_kb_ctrl_k9_map[10] = LV_BUTTONMATRIX_CTRL_CHECKED | 1;
987     default_kb_ctrl_k9_map[14] = LV_BUTTONMATRIX_CTRL_CHECKED | 1;
988     default_kb_ctrl_k9_map[15] = LV_BUTTONMATRIX_CTRL_CHECKED | 1;
989     default_kb_ctrl_k9_map[LV_IME_PINYIN_K9_CAND_TEXT_NUM + 16] = LV_BUTTONMATRIX_CTRL_CHECKED | 1;
990 }
991 
pinyin_k9_get_legal_py(lv_obj_t * obj,char * k9_input,const char * py9_map[])992 static void pinyin_k9_get_legal_py(lv_obj_t * obj, char * k9_input, const char * py9_map[])
993 {
994     lv_ime_pinyin_t * pinyin_ime = (lv_ime_pinyin_t *)obj;
995 
996     uint16_t len = lv_strlen(k9_input);
997 
998     if((len == 0) || (len >= LV_IME_PINYIN_K9_MAX_INPUT)) {
999         return;
1000     }
1001 
1002     char py_comp[LV_IME_PINYIN_K9_MAX_INPUT] = {0};
1003     int mark[LV_IME_PINYIN_K9_MAX_INPUT] = {0};
1004     int index = 0;
1005     int flag = 0;
1006     uint16_t count = 0;
1007 
1008     uint32_t ll_len = 0;
1009     ime_pinyin_k9_py_str_t * ll_index = NULL;
1010 
1011     ll_len = lv_ll_get_len(&pinyin_ime->k9_legal_py_ll);
1012     ll_index = lv_ll_get_head(&pinyin_ime->k9_legal_py_ll);
1013 
1014     while(index != -1) {
1015         if(index == len) {
1016             if(pinyin_k9_is_valid_py(obj, py_comp)) {
1017                 if((count >= ll_len) || (ll_len == 0)) {
1018                     ll_index = lv_ll_ins_tail(&pinyin_ime->k9_legal_py_ll);
1019                     lv_strcpy(ll_index->py_str, py_comp);
1020                 }
1021                 else if((count < ll_len)) {
1022                     lv_strcpy(ll_index->py_str, py_comp);
1023                     ll_index = lv_ll_get_next(&pinyin_ime->k9_legal_py_ll, ll_index);
1024                 }
1025                 count++;
1026             }
1027             index--;
1028         }
1029         else {
1030             flag = mark[index];
1031             if((size_t)flag < lv_strlen(py9_map[k9_input[index] - '2'])) {
1032                 py_comp[index] = py9_map[k9_input[index] - '2'][flag];
1033                 mark[index] = mark[index] + 1;
1034                 index++;
1035             }
1036             else {
1037                 mark[index] = 0;
1038                 index--;
1039             }
1040         }
1041     }
1042 
1043     if(count > 0) {
1044         pinyin_ime->ta_count++;
1045         pinyin_ime->k9_legal_py_count = count;
1046     }
1047 }
1048 
1049 /*true: visible; false: not visible*/
pinyin_k9_is_valid_py(lv_obj_t * obj,char * py_str)1050 static bool pinyin_k9_is_valid_py(lv_obj_t * obj, char * py_str)
1051 {
1052     lv_ime_pinyin_t * pinyin_ime = (lv_ime_pinyin_t *)obj;
1053 
1054     const lv_pinyin_dict_t * cpHZ = NULL;
1055     uint8_t index = 0, len = 0, offset = 0;
1056     volatile uint8_t count = 0;
1057 
1058     if(*py_str == '\0')    return false;
1059     if(*py_str == 'i')     return false;
1060     if(*py_str == 'u')     return false;
1061     if(*py_str == 'v')     return false;
1062 
1063     offset = py_str[0] - 'a';
1064     len = lv_strlen(py_str);
1065 
1066     cpHZ  = &pinyin_ime->dict[pinyin_ime->py_pos[offset]];
1067     count = pinyin_ime->py_num[offset];
1068 
1069     while(count--) {
1070         for(index = 0; index < len; index++) {
1071             if(*(py_str + index) != *((cpHZ->py) + index)) {
1072                 break;
1073             }
1074         }
1075 
1076         // perfect match
1077         if(len == 1 || index == len) {
1078             return true;
1079         }
1080         cpHZ++;
1081     }
1082     return false;
1083 }
1084 
pinyin_k9_fill_cand(lv_obj_t * obj)1085 static void pinyin_k9_fill_cand(lv_obj_t * obj)
1086 {
1087     uint16_t index = 0, tmp_len = 0;
1088     ime_pinyin_k9_py_str_t * ll_index = NULL;
1089 
1090     lv_ime_pinyin_t * pinyin_ime = (lv_ime_pinyin_t *)obj;
1091 
1092     tmp_len = pinyin_ime->k9_legal_py_count;
1093 
1094     if(tmp_len != cand_len) {
1095         lv_memzero(lv_pinyin_k9_cand_str, sizeof(lv_pinyin_k9_cand_str));
1096         lv_strcpy(lv_pinyin_k9_cand_str[LV_IME_PINYIN_K9_CAND_TEXT_NUM], LV_SYMBOL_RIGHT"\0");
1097         lv_strcpy(lv_pinyin_k9_cand_str[LV_IME_PINYIN_K9_CAND_TEXT_NUM + 1], "\0");
1098         cand_len = tmp_len;
1099     }
1100 
1101     ll_index = lv_ll_get_head(&pinyin_ime->k9_legal_py_ll);
1102     lv_strcpy(pinyin_ime->input_char, ll_index->py_str);
1103 
1104     for(uint8_t i = 0; i < LV_IME_PINYIN_K9_CAND_TEXT_NUM; i++) {
1105         lv_strcpy(lv_pinyin_k9_cand_str[i], " ");
1106     }
1107 
1108     while(ll_index) {
1109         if(index >= LV_IME_PINYIN_K9_CAND_TEXT_NUM)
1110             break;
1111 
1112         if(index < pinyin_ime->k9_legal_py_count) {
1113             lv_strcpy(lv_pinyin_k9_cand_str[index], ll_index->py_str);
1114         }
1115 
1116         ll_index = lv_ll_get_next(&pinyin_ime->k9_legal_py_ll, ll_index); /*Find the next list*/
1117         index++;
1118     }
1119     pinyin_ime->k9_py_ll_pos = index;
1120 
1121     lv_obj_t * ta = lv_keyboard_get_textarea(pinyin_ime->kb);
1122     for(index = 0; index < pinyin_ime->k9_input_str_len; index++) {
1123         lv_textarea_delete_char(ta);
1124     }
1125     pinyin_ime->k9_input_str_len = lv_strlen(pinyin_ime->input_char);
1126     lv_textarea_add_text(ta, pinyin_ime->input_char);
1127 }
1128 
pinyin_k9_cand_page_proc(lv_obj_t * obj,uint16_t dir)1129 static void pinyin_k9_cand_page_proc(lv_obj_t * obj, uint16_t dir)
1130 {
1131     lv_ime_pinyin_t * pinyin_ime = (lv_ime_pinyin_t *)obj;
1132 
1133     lv_obj_t * ta = lv_keyboard_get_textarea(pinyin_ime->kb);
1134     uint16_t ll_len =  lv_ll_get_len(&pinyin_ime->k9_legal_py_ll);
1135 
1136     if((ll_len > LV_IME_PINYIN_K9_CAND_TEXT_NUM) && (pinyin_ime->k9_legal_py_count > LV_IME_PINYIN_K9_CAND_TEXT_NUM)) {
1137         ime_pinyin_k9_py_str_t * ll_index = NULL;
1138         int count = 0;
1139 
1140         ll_index = lv_ll_get_head(&pinyin_ime->k9_legal_py_ll);
1141         while(ll_index) {
1142             if(count >= pinyin_ime->k9_py_ll_pos)   break;
1143 
1144             ll_index = lv_ll_get_next(&pinyin_ime->k9_legal_py_ll, ll_index); /*Find the next list*/
1145             count++;
1146         }
1147 
1148         if((NULL == ll_index) && (dir == 1))   return;
1149 
1150         lv_memzero(lv_pinyin_k9_cand_str, sizeof(lv_pinyin_k9_cand_str));
1151         lv_strcpy(lv_pinyin_k9_cand_str[LV_IME_PINYIN_K9_CAND_TEXT_NUM], LV_SYMBOL_RIGHT"\0");
1152         lv_strcpy(lv_pinyin_k9_cand_str[LV_IME_PINYIN_K9_CAND_TEXT_NUM + 1], "\0");
1153 
1154         // next page
1155         if(dir == 1) {
1156             for(uint8_t i = 0; i < LV_IME_PINYIN_K9_CAND_TEXT_NUM; i++) {
1157                 lv_strcpy(lv_pinyin_k9_cand_str[i], " ");
1158             }
1159 
1160             count = 0;
1161             while(ll_index) {
1162                 if(count >= (LV_IME_PINYIN_K9_CAND_TEXT_NUM - 1))
1163                     break;
1164 
1165                 lv_strcpy(lv_pinyin_k9_cand_str[count], ll_index->py_str);
1166                 ll_index = lv_ll_get_next(&pinyin_ime->k9_legal_py_ll, ll_index); /*Find the next list*/
1167                 count++;
1168             }
1169             pinyin_ime->k9_py_ll_pos += count - 1;
1170 
1171         }
1172         // previous page
1173         else {
1174             for(uint8_t i = 0; i < LV_IME_PINYIN_K9_CAND_TEXT_NUM; i++) {
1175                 lv_strcpy(lv_pinyin_k9_cand_str[i], " ");
1176             }
1177             count = LV_IME_PINYIN_K9_CAND_TEXT_NUM - 1;
1178             ll_index = lv_ll_get_prev(&pinyin_ime->k9_legal_py_ll, ll_index);
1179             while(ll_index) {
1180                 if(count < 0)  break;
1181 
1182                 lv_strcpy(lv_pinyin_k9_cand_str[count], ll_index->py_str);
1183                 ll_index = lv_ll_get_prev(&pinyin_ime->k9_legal_py_ll, ll_index); /*Find the previous list*/
1184                 count--;
1185             }
1186 
1187             if(pinyin_ime->k9_py_ll_pos > LV_IME_PINYIN_K9_CAND_TEXT_NUM)
1188                 pinyin_ime->k9_py_ll_pos -= 1;
1189         }
1190 
1191         lv_textarea_set_cursor_pos(ta, LV_TEXTAREA_CURSOR_LAST);
1192     }
1193 }
1194 
1195 #endif  /*LV_IME_PINYIN_USE_K9_MODE*/
1196 
1197 #endif  /*LV_USE_IME_PINYIN*/
1198