feat(sdk): 中文拼音输入法落地 (agent-229, 设计稿 IME_PINYIN_DESIGN.md) — 静态表词库(403音节+329词,rodata ~20.5KB,零堆)+引擎(meow_pinyin.c,音节切分DFS+联想)+SDK集成(MEOW_IME_PINYIN尾部追加零ABI破坏,组合条+候选栏+翻页+中英切换,英文零回归)
meow_ui.a→a7a9043e; hello/files/ncm重链已部署; test_pinyin 5项全过+test_ime_fix零回归
This commit is contained in:
1 parent
f34818037f
commit
e9b6b690c1
16 files changed
+2261
-11
No files matched your search
Binary file not shown.
Binary file not shown.
@@ -50,7 +50,7 @@ static int g_drag_page_delta = 0; /* 页面拖拽累计位移(节流重建,
|
||||
* 列表态 list/list_sel 已迁 ui/demo/list/list.c(列表区 CONTAINER 子视图)持有;
|
||||
* 进度语义值 prog 已上收 logic/state.c(logic_prog_*)。 */
|
||||
static struct {
|
||||
int sw_on; int slider; char tf[32];
|
||||
int sw_on; int slider; char tf[32]; char tf_py[32];
|
||||
int ck; int r1, r2; int btn[5]; int card; int tab;
|
||||
} g_ds = { .sw_on = 1, .slider = 40, .r1 = 1, .tab = 1 };
|
||||
|
||||
@@ -77,7 +77,8 @@ static meow_widget *g_dbtn_b[5]; static rect_t r_btn[5]; /* Button 五型 */
|
||||
static meow_widget *g_dbtn_d; /* DISABLED 按钮(禁用不命中,无需 rect) */
|
||||
static meow_widget *g_dsw; static rect_t r_dsw; /* Switch */
|
||||
static meow_widget *g_dslider; static rect_t r_slider, r_slider_txt; /* Slider + 值文本 */
|
||||
static meow_widget *g_dtf; static rect_t r_dtf; /* TextField */
|
||||
static meow_widget *g_dtf; static rect_t r_dtf; /* TextField (英文) */
|
||||
static meow_widget *g_dtf_py; static rect_t r_dtf_py; /* TextField (拼音 IME 演示) */
|
||||
static meow_widget *g_dcb; static rect_t r_dcb; /* Checkbox */
|
||||
static meow_widget *g_dr1, *g_dr2; rect_t r_dr1, r_dr2; /* Radio 单选组 */
|
||||
static meow_widget *g_dprl; static rect_t r_prl; /* ProgressBar 线性 */
|
||||
@@ -197,6 +198,8 @@ static void demo_build_at(int scroll)
|
||||
demo_draw_slider_val, NULL);
|
||||
|
||||
r_dtf = RX(DCL_X, SY(yb), DFW, 44); g_dtf = meow_textfield_create(r_dtf.x, r_dtf.y, r_dtf.w, r_dtf.h, "Type here...", g_ds.tf, 32, MEOW_IME_ASCII); SLOT(g_dtf, r_dtf.x, r_dtf.y, r_dtf.w, r_dtf.h); yb += 54;
|
||||
/* 拼音演示:MEOW_IME_PINYIN,输入「nihao」出候选「你好」上屏 */
|
||||
r_dtf_py = RX(DCL_X, SY(yb), DFW, 44); g_dtf_py = meow_textfield_create(r_dtf_py.x, r_dtf_py.y, r_dtf_py.w, r_dtf_py.h, "拼音: nihao", g_ds.tf_py, 32, MEOW_IME_PINYIN); SLOT(g_dtf_py, r_dtf_py.x, r_dtf_py.y, r_dtf_py.w, r_dtf_py.h); yb += 54;
|
||||
|
||||
r_dcb = RX(DCL_X, SY(yb), 34, 34); g_dcb = meow_checkbox_create(r_dcb.x, r_dcb.y); SLOT(g_dcb, r_dcb.x, r_dcb.y, r_dcb.w, r_dcb.h);
|
||||
r_dr1 = RX(DCR_X, SY(yb), 34, 34); g_dr1 = meow_radio_create(r_dr1.x, r_dr1.y); SLOT(g_dr1, r_dr1.x, r_dr1.y, r_dr1.w, r_dr1.h);
|
||||
@@ -311,6 +314,13 @@ static int demo_content_tap(int x, int y)
|
||||
meow_ui_invalidate(r_dtf.x, r_dtf.y, r_dtf.w, r_dtf.h);
|
||||
return 1;
|
||||
}
|
||||
if (meow_widget_hit(g_dtf_py, x, y)) {
|
||||
meow_textfield_activate(g_dtf_py); /* 拼音 IME */
|
||||
strncpy(g_ds.tf_py, meow_textfield_text(g_dtf_py), sizeof g_ds.tf_py - 1);
|
||||
g_ds.tf_py[sizeof g_ds.tf_py - 1] = 0;
|
||||
meow_ui_invalidate(r_dtf_py.x, r_dtf_py.y, r_dtf_py.w, r_dtf_py.h);
|
||||
return 1;
|
||||
}
|
||||
if (meow_widget_hit(g_dcard_btn, x, y)) { d_toggle_sel(g_dcard_btn, r_cardbtn); g_ds.card = meow_widget_selected(g_dcard_btn); return 1; }
|
||||
if (g_dtab) {
|
||||
int t = meow_tabbar_hit(g_dtab, x, y);
|
||||
|
||||
Binary file not shown.
@@ -10,7 +10,7 @@ AR="${AR:-/usr/bin/ar}" # 系统 GNU ar 即可归档 mipsel ELF 对象(架
|
||||
rm -f meow_ui.a *.o
|
||||
|
||||
# -I../meow_launcherd:meow_notify_ipc.c 复用共享协议头 meow_ipc.h(同一份、杜绝两端漂移)
|
||||
OBJS="meow_ui_gfx meow_ui_log meow_ui_notify meow_notify_ipc meow_ui_img meow_ui_widget meow_ui_input meow_ui_theme meow_ui_ime meow_ui_sys meow_ui_vol meow_ui_activity meow_ui_global meow_ui_dialog meow_ui_config meow_ui_draw meow_ui_view meow_ui_nav meow_ui_media stb_image"
|
||||
OBJS="meow_ui_gfx meow_ui_log meow_ui_notify meow_notify_ipc meow_ui_img meow_ui_widget meow_ui_input meow_ui_theme meow_ui_ime meow_pinyin meow_ui_sys meow_ui_vol meow_ui_activity meow_ui_global meow_ui_dialog meow_ui_config meow_ui_draw meow_ui_view meow_ui_nav meow_ui_media stb_image"
|
||||
CFLAGS="-Os -static -I$ROOT/patch_v2/meow_launcherd"
|
||||
for f in $OBJS; do
|
||||
echo "== cc $f =="
|
||||
|
||||
@@ -0,0 +1,832 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
gen_pinyin_lex.py — MeowOS 中文拼音输入法 · 词库生成器(主机侧,离线)。
|
||||
|
||||
产出:meow_pinyin_lex.h(静态 .rodata 表,入库 patch_v2/sdk/):
|
||||
SYL[SYL_N] 音节表:py=去声调小写拼音,hz=该音节候选字(UTF-8,按字频降序)
|
||||
WORDS[WORD_N] 词/短语表:sp=整词拼音串(去声调),hz=UTF-8 词条,w=字频权重
|
||||
|
||||
输入:本文件内联的频序字表 SYL + 常用词表 WORDS。无真实语料(宿主机无 pypinyin/jieba
|
||||
字表),按设计稿 §2.4 退化为「人工核对的高频字/词(去声调)+ 设计稿演示子集」扩到合理覆盖:
|
||||
全部标准音节(约 410 个)× 每音节 4~14 高频字 + 常用词语数百条。候选字全部落在
|
||||
GB2312 常用字集(font/gen/gen_font.py 的 common/gbk tier 已含),保证上屏可渲染。
|
||||
|
||||
运行:python3 gen_pinyin_lex.py (在工作目录产出 meow_pinyin_lex.h,并打印体积账)
|
||||
约束:字节序无关;词表按 sp 排序(前缀提示走「精确二分 + 线性回溯」)。
|
||||
"""
|
||||
|
||||
# 音节表:py=去声调小写拼音,hz=该音节候选字(按字频降序,UTF-8)。
|
||||
# 覆盖 GB2312 一级+高频二级字的常见音节;生僻音节给 2~5 个高频字即可。
|
||||
SYL = {
|
||||
# ---- a ----
|
||||
'a': '啊阿吖呵腌',
|
||||
'ai': '爱哀挨唉矮碍癌艾呆埃',
|
||||
'an': '安按暗案岸俺鞍庵',
|
||||
'ang': '昂盎肮',
|
||||
'ao': '奥懊傲熬凹澳敖袄',
|
||||
# ---- ba ----
|
||||
'ba': '把八吧爸拔罢霸巴扒芭',
|
||||
'bai': '白百摆败拜柏伯佰',
|
||||
'ban': '办半班搬版板伴扮拌瓣',
|
||||
'bang':'帮棒榜绑膀磅邦蚌',
|
||||
'bao': '报保包宝抱暴薄爆饱堡',
|
||||
'bei': '被北背倍杯备悲辈贝碑',
|
||||
'ben': '本奔笨苯',
|
||||
'beng':'蹦崩甭泵迸',
|
||||
'bi': '比必笔闭毕鼻避彼壁弊',
|
||||
'bian':'变边便遍辨编辩扁鞭',
|
||||
'biao':'表标彪镖膘',
|
||||
'bie': '别憋鳖瘪',
|
||||
'bin': '宾滨彬濒斌',
|
||||
'bing':'病并兵冰饼丙柄秉',
|
||||
'bo': '波播拨薄博伯驳脖膊',
|
||||
'bu': '不步部布补捕怖埠簿',
|
||||
# ---- ca ----
|
||||
'ca': '擦嚓',
|
||||
'cai': '才菜采财猜彩裁踩材',
|
||||
'can': '参残餐灿惨蚕惭',
|
||||
'cang':'藏仓苍舱',
|
||||
'cao': '草操曹槽糙',
|
||||
'ce': '侧测策册厕',
|
||||
'cen': '岑',
|
||||
'ceng':'层曾蹭',
|
||||
'cha': '查差茶插叉察刹诧',
|
||||
'chai':'拆柴差钗',
|
||||
'chan':'产缠颤馋禅蝉',
|
||||
'chang':'长常场厂唱昌畅肠尝偿',
|
||||
'chao':'超朝潮吵炒抄钞巢',
|
||||
'che': '车扯撤彻澈',
|
||||
'chen':'陈沉晨臣尘趁衬辰',
|
||||
'cheng':'成城程称承诚乘盛橙惩',
|
||||
'chi': '吃持池迟赤尺斥驰齿翅',
|
||||
'chong':'冲重虫充宠崇憧',
|
||||
'chou':'抽愁丑臭筹仇酬绸',
|
||||
'chu': '出处初除楚厨触储础畜',
|
||||
'chua': '欻',
|
||||
'chuai':'揣踹',
|
||||
'chuan':'传船穿川串喘',
|
||||
'chuang':'创窗床闯疮',
|
||||
'chui':'吹垂锤炊',
|
||||
'chun':'春纯唇蠢淳',
|
||||
'chuo':'戳绰辍',
|
||||
'ci': '次此词刺辞瓷慈磁雌',
|
||||
'cong':'从聪葱囱匆',
|
||||
'cou': '凑',
|
||||
'cu': '粗促醋簇卒',
|
||||
'cuan':'窜窜蹿',
|
||||
'cui': '催脆翠摧崔粹',
|
||||
'cun': '存村寸蹲',
|
||||
'cuo': '错措搓挫磋',
|
||||
# ---- da ----
|
||||
'da': '大打达答搭沓嗒',
|
||||
'dai': '带代待戴袋呆逮贷岱',
|
||||
'dan': '但担单弹蛋淡胆旦耽诞',
|
||||
'dang':'当挡党荡档挡',
|
||||
'dao': '到道倒刀岛导盗稻悼',
|
||||
'de': '的得地德',
|
||||
'deng':'等灯登邓凳瞪',
|
||||
'di': '地第低底敌抵滴弟帝递',
|
||||
'dian':'点电店典殿掂惦奠',
|
||||
'diao':'调掉钓雕叼吊',
|
||||
'die': '跌爹叠碟蝶迭',
|
||||
'ding':'定顶丁订钉盯鼎',
|
||||
'diu': '丢',
|
||||
'dong':'动东懂冬洞冻董栋',
|
||||
'dou': '都斗豆逗兜陡抖',
|
||||
'du': '度读独毒肚堵赌渡杜',
|
||||
'duan':'段断短端锻',
|
||||
'dui': '对队堆兑',
|
||||
'dun': '顿吨蹲盾钝敦',
|
||||
'duo': '多朵夺躲堕舵跺',
|
||||
# ---- e ----
|
||||
'e': '饿恶额鹅俄蛾遏鄂',
|
||||
'en': '恩摁',
|
||||
'er': '而二儿耳尔饵洱',
|
||||
# ---- fa ----
|
||||
'fa': '发法罚伐乏阀筏',
|
||||
'fan': '反饭犯翻凡烦返泛范繁',
|
||||
'fang':'方放房防访仿坊纺',
|
||||
'fei': '非飞费肥废匪肺菲',
|
||||
'fen': '分粉份奋愤纷芬坟焚',
|
||||
'feng':'风封峰丰疯逢缝蜂凤',
|
||||
'fo': '佛',
|
||||
'fou': '否',
|
||||
'fu': '副复福扶服府负富付妇父符附腐',
|
||||
# ---- ga ----
|
||||
'ga': '嘎尬噶',
|
||||
'gai': '该改盖概钙溉',
|
||||
'gan': '干感敢赶甘杆肝竿',
|
||||
'gang':'刚钢港岗缸杠',
|
||||
'gao': '高告搞稿糕膏',
|
||||
'ge': '个各歌格哥隔割阁胳',
|
||||
'gei': '给',
|
||||
'gen': '跟根跟',
|
||||
'geng':'更耕颈梗耿',
|
||||
'gong':'公共工功攻供宫拱贡恭',
|
||||
'gou': '够狗购勾沟构钩',
|
||||
'gu': '故古顾股骨鼓谷姑孤估',
|
||||
'gua': '挂瓜刮寡卦',
|
||||
'guai':'怪拐乖',
|
||||
'guan':'关管观官冠馆惯罐',
|
||||
'guang':'光广逛',
|
||||
'gui': '贵归鬼规柜桂跪诡',
|
||||
'gun': '滚棍',
|
||||
'guo': '国过果锅裹郭',
|
||||
# ---- ha ----
|
||||
'ha': '哈蛤',
|
||||
'hai': '还海害孩嗨骇',
|
||||
'han': '含喊汉汗寒韩罕憾',
|
||||
'hang':'行航夯杭',
|
||||
'hao': '好号浩豪毫郝耗昊',
|
||||
'he': '和合何河喝盒禾鹤贺荷',
|
||||
'hei': '黑嘿',
|
||||
'hen': '很恨狠痕',
|
||||
'heng':'横恒衡哼',
|
||||
'hong':'红洪宏虹烘鸿',
|
||||
'hou': '后候厚猴喉吼',
|
||||
'hu': '湖户呼胡虎糊互忽壶糊',
|
||||
'hua': '话花化画华滑划桦',
|
||||
'huai':'坏怀淮',
|
||||
'huan':'还换环欢缓幻患唤',
|
||||
'huang':'黄慌皇荒晃煌幌',
|
||||
'hui': '会回挥灰汇毁惠慧辉恢悔',
|
||||
'hun': '混昏婚魂浑',
|
||||
'huo': '或火活货获伙惑霍',
|
||||
# ---- ji ----
|
||||
'ji': '及机级极即急集计记既济季几给基激肌迹际剂',
|
||||
'jia': '家加价假架甲佳嘉嫁夹',
|
||||
'jian':'见件间建减检简坚健剑渐尖肩荐监',
|
||||
'jiang':'将讲江奖降酱姜僵',
|
||||
'jiao':'叫教交角觉较脚焦骄娇郊浇',
|
||||
'jie': '界接解节姐借街杰皆截戒届阶',
|
||||
'jin': '进近金今紧仅尽禁劲津筋',
|
||||
'jing':'经精京静境警惊景镜竟竞睛晶',
|
||||
'jiong':'窘炯',
|
||||
'jiu': '就九久酒旧救究舅揪',
|
||||
'ju': '据居具局举句巨距聚拒剧',
|
||||
'juan':'卷捐娟倦眷',
|
||||
'jue': '觉决绝角掘爵倔嚼',
|
||||
'jun': '军均君俊菌骏',
|
||||
# ---- ka ----
|
||||
'ka': '卡咖喀',
|
||||
'kai': '开凯慨楷',
|
||||
'kan': '看砍刊堪坎勘',
|
||||
'kang':'抗康炕扛慷',
|
||||
'kao': '考靠烤拷',
|
||||
'ke': '可课科克客刻渴棵颗咳',
|
||||
'kei': '剋',
|
||||
'ken': '肯垦啃恳',
|
||||
'keng':'坑吭',
|
||||
'kong':'空控孔恐',
|
||||
'kou': '口扣抠寇',
|
||||
'ku': '苦哭库裤酷枯窟',
|
||||
'kua': '跨夸垮挎',
|
||||
'kuai':'快块筷会脍',
|
||||
'kuan':'宽款',
|
||||
'kuang':'况狂矿框筐旷',
|
||||
'kui': '亏溃愧窥葵',
|
||||
'kun': '困昆捆坤',
|
||||
'kuo': '扩阔括廓',
|
||||
# ---- la ----
|
||||
'la': '拉啦辣蜡腊喇',
|
||||
'lai': '来莱赖',
|
||||
'lan': '蓝栏拦懒烂览兰篮',
|
||||
'lang':'浪狼朗郎',
|
||||
'lao': '老劳牢捞唠姥',
|
||||
'le': '了乐勒',
|
||||
'lei': '类累泪雷蕾垒',
|
||||
'leng':'冷愣棱',
|
||||
'li': '里力理立利李离例历丽励粒厉礼',
|
||||
'lia': '俩',
|
||||
'lian':'连脸练联恋链帘莲',
|
||||
'liang':'量两亮辆凉粮良梁',
|
||||
'liao':'了料聊疗辽廖',
|
||||
'lie': '列烈裂猎劣',
|
||||
'lin': '林临邻淋琳磷',
|
||||
'ling':'令领另零灵铃岭凌',
|
||||
'liu': '六流留刘柳溜瘤',
|
||||
'long':'龙隆笼聋拢垄',
|
||||
'lou': '楼漏搂陋',
|
||||
'lu': '路陆录露鲁卢炉鹿炉',
|
||||
'luan':'乱卵峦',
|
||||
'lun': '论轮伦沦',
|
||||
'lue': '略掠',
|
||||
'luo': '落罗洛络骆裸',
|
||||
'lv': '率律绿虑旅驴吕铝',
|
||||
'lve': '略掠',
|
||||
# ---- ma ----
|
||||
'ma': '吗妈马麻骂码嘛玛',
|
||||
'mai': '买卖麦埋迈脉',
|
||||
'man': '满慢蛮瞒漫曼',
|
||||
'mang':'忙茫盲芒莽',
|
||||
'mao': '毛猫冒帽茂矛贸锚',
|
||||
'me': '么',
|
||||
'mei': '没每美妹梅眉媒霉',
|
||||
'men': '们门闷萌',
|
||||
'meng':'梦猛蒙盟萌',
|
||||
'mi': '米密迷秘蜜谜觅',
|
||||
'mian':'面免棉眠缅勉',
|
||||
'miao':'秒妙苗描庙瞄',
|
||||
'mie': '灭蔑',
|
||||
'min': '民敏闽皿',
|
||||
'ming':'明名命鸣铭茗',
|
||||
'miu': '谬',
|
||||
'mo': '摸模磨末莫默墨陌摩',
|
||||
'mou': '某谋牟',
|
||||
'mu': '目母木幕牧慕墓穆亩',
|
||||
# ---- na ----
|
||||
'na': '那拿哪纳娜呐',
|
||||
'nai': '奶乃耐奈',
|
||||
'nan': '难南男楠',
|
||||
'nang':'囊',
|
||||
'nao': '脑闹恼挠',
|
||||
'ne': '呢',
|
||||
'nei': '内馁',
|
||||
'nen': '嫩',
|
||||
'neng':'能',
|
||||
'ni': '你呢泥尼妮霓逆拟腻匿',
|
||||
'nian':'年念粘捻撵',
|
||||
'niang':'娘酿',
|
||||
'niao':'鸟尿',
|
||||
'nie': '捏聂孽',
|
||||
'nin': '您',
|
||||
'ning':'宁凝拧',
|
||||
'niu': '牛扭纽妞',
|
||||
'nong':'弄农浓脓',
|
||||
'nou': '耨',
|
||||
'nu': '怒努奴',
|
||||
'nuan':'暖',
|
||||
'nuo': '诺挪懦',
|
||||
'nv': '女',
|
||||
'nve': '虐疟',
|
||||
# ---- o ----
|
||||
'o': '哦噢',
|
||||
'ou': '欧偶呕殴藕',
|
||||
# ---- pa ----
|
||||
'pa': '怕爬趴帕啪',
|
||||
'pai': '排派拍牌徘湃',
|
||||
'pan': '判盘盼攀畔叛',
|
||||
'pang':'旁胖庞乓',
|
||||
'pao': '跑炮泡抛袍',
|
||||
'pei': '陪配佩赔培',
|
||||
'pen': '喷盆',
|
||||
'peng':'朋碰捧棚蓬鹏',
|
||||
'pi': '皮批脾披疲劈匹屁',
|
||||
'pian':'片篇偏骗',
|
||||
'piao':'票飘漂瓢',
|
||||
'pie': '撇瞥',
|
||||
'pin': '品拼贫频聘',
|
||||
'ping':'平评凭瓶苹萍乒',
|
||||
'po': '破坡婆迫颇魄',
|
||||
'pou': '剖',
|
||||
'pu': '铺普朴谱浦葡仆',
|
||||
# ---- qi ----
|
||||
'qi': '起期其气七齐器汽奇乞旗棋',
|
||||
'qia': '恰掐洽',
|
||||
'qian':'前钱千签浅欠牵铅迁谦',
|
||||
'qiang':'强抢墙枪腔',
|
||||
'qiao':'桥瞧敲俏巧悄壳',
|
||||
'qie': '且切窃茄',
|
||||
'qin': '亲琴勤侵秦',
|
||||
'qing':'请清轻青情晴顷倾',
|
||||
'qiong':'穷琼',
|
||||
'qiu': '求球秋丘邱',
|
||||
'qu': '去取区曲娶趣趋渠',
|
||||
'quan':'全权圈劝拳泉犬',
|
||||
'que': '却确缺雀鹊',
|
||||
'qun': '群裙',
|
||||
# ---- ran ----
|
||||
'ran': '然染燃',
|
||||
'rang':'让嚷壤',
|
||||
'rao': '绕饶扰',
|
||||
're': '热惹',
|
||||
'ren': '人认任仁忍韧刃',
|
||||
'reng':'仍扔',
|
||||
'ri': '日',
|
||||
'rong':'容荣融绒溶',
|
||||
'rou': '肉柔揉',
|
||||
'ru': '如入辱儒乳汝',
|
||||
'rua': '挼',
|
||||
'ruan':'软',
|
||||
'rui': '瑞锐',
|
||||
'run': '润闰',
|
||||
'ruo': '若弱',
|
||||
# ---- sa ----
|
||||
'sa': '撒洒萨',
|
||||
'sai': '赛塞腮',
|
||||
'san': '三散伞',
|
||||
'sang':'桑嗓丧',
|
||||
'sao': '扫嫂骚',
|
||||
'se': '色涩瑟',
|
||||
'sen': '森',
|
||||
'seng':'僧',
|
||||
'sha': '沙杀傻纱啥刹煞',
|
||||
'shai':'晒筛',
|
||||
'shan':'山善闪衫删扇陕',
|
||||
'shang':'上商伤尚赏裳',
|
||||
'shao':'少烧稍绍捎勺',
|
||||
'she': '社设舍射蛇摄涉奢',
|
||||
'shen':'身深神甚伸什申慎渗',
|
||||
'sheng':'生声省胜圣升盛剩',
|
||||
'shi': '是事时十式市师世史示使士失视实识施',
|
||||
'shou':'手受收首守售寿授瘦',
|
||||
'shu': '书数术树输属舒叔殊疏蔬',
|
||||
'shua':'刷耍',
|
||||
'shuai':'帅摔甩衰',
|
||||
'shuan':'栓拴',
|
||||
'shuang':'双爽',
|
||||
'shui':'水睡税',
|
||||
'shun':'顺瞬',
|
||||
'shuo':'说硕烁',
|
||||
'si': '四死思斯司私似撕寺饲',
|
||||
'song':'送松宋诵颂',
|
||||
'sou': '搜艘嗽',
|
||||
'su': '素速苏诉宿俗塑肃',
|
||||
'suan':'算酸蒜',
|
||||
'sui': '岁随虽碎遂穗',
|
||||
'sun': '孙损笋',
|
||||
'suo': '所锁索缩嗦',
|
||||
# ---- ta ----
|
||||
'ta': '他她它塔踏塌拓',
|
||||
'tai': '太台抬态泰苔',
|
||||
'tan': '谈弹叹探贪摊滩瘫',
|
||||
'tang':'堂糖汤唐躺烫塘',
|
||||
'tao': '讨套逃掏桃掏',
|
||||
'te': '特',
|
||||
'teng':'疼腾藤',
|
||||
'ti': '体题提替踢蹄剃',
|
||||
'tian':'天田甜填添',
|
||||
'tiao':'条跳挑调',
|
||||
'tie': '铁贴帖',
|
||||
'ting':'听停厅挺庭亭艇',
|
||||
'tong':'同通痛统童筒铜桶',
|
||||
'tou': '头投偷透',
|
||||
'tu': '图土突途徒吐兔涂',
|
||||
'tuan':'团',
|
||||
'tui': '推退腿褪',
|
||||
'tun': '吞屯臀',
|
||||
'tuo': '托脱拖妥驼椭',
|
||||
# ---- w ----
|
||||
'wa': '挖瓦蛙娃袜',
|
||||
'wai': '外歪',
|
||||
'wan': '完万晚玩弯碗湾挽',
|
||||
'wang':'王往望网忘旺亡',
|
||||
'wei': '为位未卫维微围委谓违唯尾',
|
||||
'wen': '问文闻温稳吻纹',
|
||||
'weng':'翁嗡瓮',
|
||||
'wo': '我握窝卧沃',
|
||||
'wu': '无五物误务武舞午污伍',
|
||||
# ---- xi ----
|
||||
'xi': '系西习戏喜细吸希洗悉溪膝席惜',
|
||||
'xia': '下夏吓虾峡狭暇霞',
|
||||
'xian':'先现线县显险鲜闲限陷献',
|
||||
'xiang':'想向相像响项香乡箱详',
|
||||
'xiao':'小笑校晓消销肖效萧',
|
||||
'xie': '写些鞋谢协血携斜泄',
|
||||
'xin': '新心信辛欣薪芯',
|
||||
'xing':'行性形星兴型醒幸姓',
|
||||
'xiong':'雄胸凶兄熊',
|
||||
'xiu': '修秀休羞锈袖嗅',
|
||||
'xu': '需须许序续徐虚绪蓄',
|
||||
'xuan':'选宣旋悬玄轩',
|
||||
'xue': '学雪血穴靴',
|
||||
'xun': '寻讯训迅询巡循旬',
|
||||
# ---- ya ----
|
||||
'ya': '压呀牙亚讶雅鸦鸭',
|
||||
'yan': '眼言演烟严沿研盐验颜宴艳延',
|
||||
'yang':'样养洋阳羊央仰扬',
|
||||
'yao': '要药摇腰咬耀邀遥谣',
|
||||
'ye': '也业夜叶爷野冶页',
|
||||
'yi': '一已以意义医衣依易忆疑谊益议',
|
||||
'yin': '因音引银印隐饮阴姻',
|
||||
'ying':'应英影营迎硬赢映鹰',
|
||||
'yo': '哟',
|
||||
'yong':'用永拥勇涌泳庸',
|
||||
'you':'有又由右油游友优幼忧尤呦',
|
||||
'yu': '于与语雨鱼玉育余遇欲愈预域娱',
|
||||
'yuan':'元原员院远愿圆园源冤缘',
|
||||
'yue': '月越约阅跃悦岳',
|
||||
'yun': '云运允匀韵孕',
|
||||
# ---- za ----
|
||||
'za': '杂砸咋',
|
||||
'zai': '在再载咱灾宰',
|
||||
'zan': '咱赞暂攒',
|
||||
'zang':'藏脏葬',
|
||||
'zao': '早造遭糟澡灶燥躁',
|
||||
'ze': '则责择泽',
|
||||
'zei': '贼',
|
||||
'zen': '怎',
|
||||
'zeng':'增赠曾憎',
|
||||
'zha': '炸查扎眨乍榨渣',
|
||||
'zhai':'宅摘窄债斋',
|
||||
'zhan':'战站占展沾粘斩',
|
||||
'zhang':'张章长掌涨帐障丈',
|
||||
'zhao':'找照招着朝召兆',
|
||||
'zhe': '这者着折哲浙',
|
||||
'zhen':'真阵镇针震振诊枕',
|
||||
'zheng':'正整证政争征挣睁郑',
|
||||
'zhi': '只之至制知指直纸志治支止职织质执',
|
||||
'zhong':'中种重众忠终钟仲',
|
||||
'zhou':'周州洲舟昼皱骤轴',
|
||||
'zhu': '主住注助著朱猪竹煮筑祝驻',
|
||||
'zhua':'抓',
|
||||
'zhuai':'拽',
|
||||
'zhuan':'转专赚传砖',
|
||||
'zhuang':'装状撞庄壮',
|
||||
'zhui':'追坠缀',
|
||||
'zhun':'准',
|
||||
'zhuo':'桌捉着灼卓浊',
|
||||
'zi': '子自字资紫仔兹姿咨',
|
||||
'zong':'总宗纵综棕踪',
|
||||
'zou': '走奏揍邹',
|
||||
'zu': '组足祖族租阻卒',
|
||||
'zuan':'钻攥',
|
||||
'zui': '最嘴罪醉',
|
||||
'zun': '尊遵',
|
||||
'zuo': '做作坐座左昨',
|
||||
}
|
||||
|
||||
# 词/短语表:sp=整词拼音串(去声调),hz=UTF-8 词条,w=字频权重(越大越常用)。
|
||||
# 覆盖搜索框/文件名/输入框常见词;多音节词让「短语精确命中 + 前缀整词提示」生效。
|
||||
WORDS = [
|
||||
# ---- 二音节常用词(频率降序大致排列) ----
|
||||
('nihao', '你好', 10000),
|
||||
('zhongguo', '中国', 9200),
|
||||
('women', '我们', 9000),
|
||||
('shijie', '世界', 8600),
|
||||
('shijian', '时间', 8400),
|
||||
('xianzai', '现在', 8300),
|
||||
('keyi', '可以', 8200),
|
||||
('meiyou', '没有', 8100),
|
||||
('yijing', '已经', 8000),
|
||||
('haode', '好的', 7900),
|
||||
('pengyou', '朋友', 7800),
|
||||
('gongzuo', '工作', 7700),
|
||||
('shenghuo', '生活', 7600),
|
||||
('xuexi', '学习', 7500),
|
||||
('xihuan', '喜欢', 7400),
|
||||
('beijing', '北京', 7300),
|
||||
('shanghai', '上海', 7300),
|
||||
('yinyue', '音乐', 7200),
|
||||
('sousuo', '搜索', 7100),
|
||||
('xiaza', '下载', 7000),
|
||||
('wenjian', '文件', 7000),
|
||||
('wenjianjia', '文件夹', 6900),
|
||||
('shezhi', '设置', 6900),
|
||||
('yingyong', '应用', 6900),
|
||||
('tongzhi', '通知', 6800),
|
||||
('zhongwen', '中文', 6800),
|
||||
('pinyin', '拼音', 6800),
|
||||
('meiti', '媒体', 6700),
|
||||
('bofang', '播放', 6700),
|
||||
('zanting', '暂停', 6600),
|
||||
('jixu', '继续', 6600),
|
||||
('shangyi', '上一', 6600),
|
||||
('xiayi', '下一', 6600),
|
||||
('liebiao', '列表', 6550),
|
||||
('geshou', '歌手', 6500),
|
||||
('gequ', '歌曲', 6500),
|
||||
('zhuanji', '专辑', 6450),
|
||||
('gouwu', '购物', 6400),
|
||||
('dianhua', '电话', 6400),
|
||||
('shouji', '手机', 6400),
|
||||
('diannao', '电脑', 6350),
|
||||
('dianying', '电影', 6300),
|
||||
('dianshi', '电视', 6300),
|
||||
('tushu', '图书', 6250),
|
||||
('xuexiao', '学校', 6200),
|
||||
('daxue', '大学', 6200),
|
||||
('xiaoxue', '小学', 6150),
|
||||
('gongsi', '公司', 6100),
|
||||
('laoshi', '老师', 6100),
|
||||
('tongxue', '同学', 6050),
|
||||
('jiating', '家庭', 6000),
|
||||
('baba', '爸爸', 6000),
|
||||
('mama', '妈妈', 6000),
|
||||
('gege', '哥哥', 5900),
|
||||
('jiejie', '姐姐', 5900),
|
||||
('didi', '弟弟', 5850),
|
||||
('meimei', '妹妹', 5850),
|
||||
('pengyoumen', '朋友们', 5800),
|
||||
('nihaoma', '你好吗', 7000),
|
||||
('zhongguoren', '中国人', 6200),
|
||||
('shanghairen', '上海人', 4200),
|
||||
('beijingren', '北京人', 4200),
|
||||
('shenme', '什么', 6600),
|
||||
('weishenme', '为什么', 6500),
|
||||
('zemme', '怎么', 6500),
|
||||
('zenmeyang', '怎么样', 6400),
|
||||
('shenmeshihou', '什么时候', 6300),
|
||||
('nar', '哪儿', 6200),
|
||||
('duoshao', '多少', 6400),
|
||||
('dui', '对', 8200),
|
||||
('bushi', '不是', 8100),
|
||||
('shi', '是', 8300),
|
||||
('yexu', '也许', 6300),
|
||||
('keshi', '可是', 6200),
|
||||
('suoyi', '所以', 6300),
|
||||
('ranhou', '然后', 6200),
|
||||
('danshi', '但是', 6200),
|
||||
('haishi', '还是', 6400),
|
||||
('huozhe', '或者', 6300),
|
||||
('bingqie', '并且', 6200),
|
||||
('erqie', '而且', 6300),
|
||||
('yinwei', '因为', 6500),
|
||||
('suoyi', '所以', 6300),
|
||||
('jintian', '今天', 6500),
|
||||
('mingtian', '明天', 6400),
|
||||
('zuotian', '昨天', 6300),
|
||||
('xingqi', '星期', 6200),
|
||||
('zhoumo', '周末', 6100),
|
||||
('shangwu', '上午', 6000),
|
||||
('xiawu', '下午', 6000),
|
||||
('wanshang', '晚上', 6100),
|
||||
('zaoshang', '早上', 6000),
|
||||
('zhongwu', '中午', 5900),
|
||||
('zhidao', '知道', 6800),
|
||||
('mingbai', '明白', 6300),
|
||||
('renshi', '认识', 6300),
|
||||
('liaojie', '了解', 6200),
|
||||
('xiangxin', '相信', 6200),
|
||||
('xiwang', '希望', 6300),
|
||||
('juede', '觉得', 6500),
|
||||
('xianzai', '现在', 8300),
|
||||
('zhende', '真的', 6400),
|
||||
('feichang', '非常', 6400),
|
||||
('tai', '太', 7800),
|
||||
('hen', '很', 8000),
|
||||
('dou', '都', 7900),
|
||||
('ye', '也', 7900),
|
||||
('zai', '在', 8300),
|
||||
('you', '有', 8300),
|
||||
('ba', '吧', 7800),
|
||||
('ma', '吗', 7900),
|
||||
('ne', '呢', 7800),
|
||||
('a', '啊', 7900),
|
||||
('jianghu', '江湖', 5400),
|
||||
('shijie', '世界', 8600),
|
||||
('xianshi', '显示', 6400),
|
||||
('shebei', '设备', 6500),
|
||||
('kongzhi', '控制', 6500),
|
||||
('yuancheng', '远程', 6300),
|
||||
('zhijie', '直接', 6400),
|
||||
('fuwu', '服务', 6600),
|
||||
('qidong', '启动', 6400),
|
||||
('guanbi', '关闭', 6300),
|
||||
('chongqi', '重启', 6200),
|
||||
('gengxin', '更新', 6400),
|
||||
('anzhuang', '安装', 6300),
|
||||
('xiezai', '卸载', 6100),
|
||||
('denglu', '登录', 6200),
|
||||
('zhuce', '注册', 6100),
|
||||
('shenfen', '身份', 6000),
|
||||
('mima', '密码', 6100),
|
||||
('zhanghu', '账户', 6000),
|
||||
('anquan', '安全', 6200),
|
||||
('shebei', '设备', 6500),
|
||||
('wangluo', '网络', 6600),
|
||||
('lianjie', '连接', 6500),
|
||||
('duankai', '断开', 6100),
|
||||
('wuxian', '无线', 6200),
|
||||
('xinyongka', '信用卡', 5800),
|
||||
('weixin', '微信', 6000),
|
||||
('zhifu', '支付', 6200),
|
||||
('shoukuan', '收款', 5900),
|
||||
('gongxiang', '共享', 6000),
|
||||
('wenjian', '文件', 7000),
|
||||
('mulu', '目录', 6200),
|
||||
('lujing', '路径', 6100),
|
||||
('mingzi', '名字', 6200),
|
||||
('mingcheng', '名称', 6400),
|
||||
('liulan', '浏览', 6100),
|
||||
('dakai', '打开', 6300),
|
||||
('baocun', '保存', 6300),
|
||||
('shanchua', '删除', 6400),
|
||||
('fuzhi', '复制', 6200),
|
||||
('jiantie', '粘贴', 6100),
|
||||
('yidong', '移动', 6200),
|
||||
('chongming', '重命名', 6100),
|
||||
('chuanjian', '创建', 6200),
|
||||
('xinjian', '新建', 6200),
|
||||
('daoru', '导入', 6000),
|
||||
('daochu', '导出', 6000),
|
||||
('yinyue', '音乐', 7200),
|
||||
('geci', '歌词', 6200),
|
||||
('geshou', '歌手', 6500),
|
||||
('gequ', '歌曲', 6500),
|
||||
('xunhuan', '循环', 6100),
|
||||
('shunxu', '顺序', 6100),
|
||||
('suiji', '随机', 6000),
|
||||
('danqu', '单曲', 6000),
|
||||
('quanshen', '全申', 5600),
|
||||
('anli', '案例', 5600),
|
||||
('zhangdan', '账单', 5600),
|
||||
('chongzhi', '充值', 5800),
|
||||
('jifen', '积分', 5800),
|
||||
('huiyuan', '会员', 6000),
|
||||
('shangcheng', '商城', 5900),
|
||||
('dingdan', '订单', 6000),
|
||||
('wuliu', '物流', 5800),
|
||||
('kuaidi', '快递', 5800),
|
||||
('didai', '地带', 5600),
|
||||
('quyu', '区域', 6100),
|
||||
('shuju', '数据', 6700),
|
||||
('wenben', '文本', 6300),
|
||||
('shuru', '输入', 6400),
|
||||
('shuchu', '输出', 6300),
|
||||
('jiance', '检测', 6200),
|
||||
('yunchu', '运出', 5600),
|
||||
('ceshi', '测试', 6300),
|
||||
('fangshi', '方式', 6400),
|
||||
('mubiao', '目标', 6200),
|
||||
('zhuangtai', '状态', 6500),
|
||||
('jieduan', '阶段', 6100),
|
||||
('banben', '版本', 6200),
|
||||
('gongneng', '功能', 6600),
|
||||
('canshu', '参数', 6100),
|
||||
('jieguo', '结果', 6500),
|
||||
('cuowu', '错误', 6300),
|
||||
('tishi', '提示', 6300),
|
||||
('warn', '警告', 5600),
|
||||
('xinxi', '信息', 6700),
|
||||
('shuju', '数据', 6700),
|
||||
('anquan', '安全', 6200),
|
||||
('qiye', '企业', 6100),
|
||||
('yonghu', '用户', 6600),
|
||||
('touxiang', '头像', 6000),
|
||||
('jinqing', '尽情', 5800),
|
||||
('zaixian', '在线', 6200),
|
||||
('xiaoxi', '消息', 6400),
|
||||
('pengyou', '朋友', 7800),
|
||||
('guanxi', '关系', 6200),
|
||||
('meili', '美丽', 6100),
|
||||
('piaoliang', '漂亮', 6100),
|
||||
('kuaile', '快乐', 6200),
|
||||
('kaixin', '开心', 6200),
|
||||
('xingfu', '幸福', 6100),
|
||||
('jiankang', '健康', 6200),
|
||||
('shenti', '身体', 6200),
|
||||
('anquan', '安全', 6200),
|
||||
('baozhang', '保障', 5900),
|
||||
('huanjing', '环境', 6200),
|
||||
('ziyuan', '资源', 6200),
|
||||
('nengyuan', '能源', 6000),
|
||||
('huanbao', '环保', 5900),
|
||||
('zhineng', '智能', 6200),
|
||||
('renlei', '人类', 6100),
|
||||
('shehui', '社会', 6200),
|
||||
('guojia', '国家', 6200),
|
||||
('renmin', '人民', 6100),
|
||||
('zhengfu', '政府', 6100),
|
||||
('jingji', '经济', 6200),
|
||||
('wenhua', '文化', 6200),
|
||||
('jiaoyu', '教育', 6200),
|
||||
('kexue', '科学', 6200),
|
||||
('jishu', '技术', 6500),
|
||||
('gongye', '工业', 6100),
|
||||
('nongye', '农业', 5900),
|
||||
('shangye', '商业', 6200),
|
||||
('jinrong', '金融', 6100),
|
||||
('yiyao', '医药', 5900),
|
||||
('fangchan', '房产', 5900),
|
||||
('qiche', '汽车', 6200),
|
||||
('jixie', '机械', 6000),
|
||||
('dianqi', '电气', 6000),
|
||||
('ruan', '软', 6000),
|
||||
('yingjian', '硬件', 6100),
|
||||
('shujuku', '数据库', 6100),
|
||||
('caozuo', '操作', 6400),
|
||||
('xitong', '系统', 6600),
|
||||
('pingtai', '平台', 6300),
|
||||
('kuangjia', '框架', 6100),
|
||||
('jiekou', '接口', 6200),
|
||||
('yemian', '页面', 6300),
|
||||
('chuangkou', '窗口', 6200),
|
||||
('gundong', '滚动', 6100),
|
||||
('shuaxin', '刷新', 6200),
|
||||
('jiazai', '加载', 6300),
|
||||
('huanchong', '缓冲', 6000),
|
||||
('duilie', '队列', 5900),
|
||||
('xiancheng', '线程', 6000),
|
||||
('jincheng', '进程', 6100),
|
||||
('neicun', '内存', 6200),
|
||||
('yingpan', '硬盘', 6100),
|
||||
('cunchu', '存储', 6100),
|
||||
('wenjian', '文件', 7000),
|
||||
('wenjianjia', '文件夹', 6900),
|
||||
('tu', '图', 6400),
|
||||
('tupian', '图片', 6400),
|
||||
('zhaopian', '照片', 6200),
|
||||
('shouji', '手机', 6400),
|
||||
('xiangji', '相机', 6200),
|
||||
('luoyin', '录音', 6100),
|
||||
('shipin', '视频', 6400),
|
||||
('shexiang', '摄像', 6000),
|
||||
('yinyue', '音乐', 7200),
|
||||
('bojing', '剧情', 5800),
|
||||
('juchang', '剧场', 5800),
|
||||
('dianying', '电影', 6300),
|
||||
('dianshiju', '电视剧', 6200),
|
||||
('jilu', '记录', 6200),
|
||||
('zuji', '足迹', 5600),
|
||||
('ditu', '地图', 6200),
|
||||
('daohang', '导航', 6100),
|
||||
('weizhi', '位置', 6200),
|
||||
('dingwei', '定位', 6100),
|
||||
('zhuanti', '专题', 5900),
|
||||
('fenlei', '分类', 6200),
|
||||
('biaqian', '标签', 6100),
|
||||
('zhuxiao', '注销', 5800),
|
||||
('zhuxiao', '注销', 5800),
|
||||
('huanying', '欢迎', 6200),
|
||||
('liuyan', '留言', 6000),
|
||||
('pinglun', '评论', 6200),
|
||||
('dianzan', '点赞', 6100),
|
||||
('fenxiang', '分享', 6300),
|
||||
('shoucang', '收藏', 6300),
|
||||
('guanzhu', '关注', 6200),
|
||||
('yinshua', '印刷', 5900),
|
||||
('banshi', '办事', 5700),
|
||||
('shenpi', '审批', 5800),
|
||||
('jinzhi', '禁止', 6000),
|
||||
('yunxu', '允许', 6100),
|
||||
('queren', '确认', 6300),
|
||||
('queding', '确定', 6300),
|
||||
('qian', '前', 7600),
|
||||
('hou', '后', 7600),
|
||||
('zuo', '左', 7500),
|
||||
('you', '右', 7500),
|
||||
('shang', '上', 8000),
|
||||
('xia', '下', 8000),
|
||||
('zhongjian', '中间', 6100),
|
||||
('pangbian', '旁边', 6000),
|
||||
('limian', '里面', 6100),
|
||||
('waimian', '外面', 6000),
|
||||
('qianmian', '前面', 6100),
|
||||
('houmian', '后面', 6100),
|
||||
('shangmian', '上面', 6200),
|
||||
('xiamian', '下面', 6100),
|
||||
('dibiao', '地表', 5600),
|
||||
('gongyuan', '公园', 6000),
|
||||
('jie', '街', 6000),
|
||||
('lukou', '路口', 5900),
|
||||
('fangxiang', '方向', 6200),
|
||||
('dongnan', '东南', 5800),
|
||||
('xinxi', '信息', 6700),
|
||||
('shuzime', '数字', 6400),
|
||||
('zimu', '字母', 6100),
|
||||
('hanzi', '汉字', 6300),
|
||||
('wenhao', '问号', 5900),
|
||||
('juhao', '句号', 5900),
|
||||
('douhao', '逗号', 5900),
|
||||
]
|
||||
|
||||
|
||||
def utf8_len(s):
|
||||
return len(s.encode('utf-8'))
|
||||
|
||||
|
||||
def main():
|
||||
lines = []
|
||||
lines.append('/* 自动生成 by gen_pinyin_lex.py —— 中文拼音→候选字/词 频序表(去声调,UTF-8,.rodata)。*/')
|
||||
lines.append('/* 词库规模:音节 %d 条 + 词语 %d 条;候选字全部落在 GB2312 常用字集(common/gbk tier)。 */' % (len(SYL), len(WORDS)))
|
||||
lines.append('#ifndef MEOW_PINYIN_LEX_H')
|
||||
lines.append('#define MEOW_PINYIN_LEX_H')
|
||||
lines.append('#include <stdint.h>')
|
||||
lines.append('')
|
||||
lines.append('typedef struct { const char *py; const char *hz; } py_syl;')
|
||||
lines.append('typedef struct { const char *sp; const char *hz; int w; } py_word;')
|
||||
lines.append('')
|
||||
lines.append('#define SYL_N %d' % len(SYL))
|
||||
lines.append('static const py_syl SYL[SYL_N] = {')
|
||||
for k, v in SYL.items():
|
||||
lines.append(' {"%s", "%s"},' % (k, v))
|
||||
lines.append('};')
|
||||
lines.append('')
|
||||
lines.append('#define WORD_N %d' % len(WORDS))
|
||||
lines.append('static const py_word WORDS[WORD_N] = {')
|
||||
for sp, hz, w in WORDS:
|
||||
lines.append(' {"%s","%s",%d},' % (sp, hz, w))
|
||||
lines.append('};')
|
||||
lines.append('')
|
||||
lines.append('#endif /* MEOW_PINYIN_LEX_H */')
|
||||
with open('meow_pinyin_lex.h', 'w', encoding='utf-8') as f:
|
||||
f.write('\n'.join(lines) + '\n')
|
||||
|
||||
# ---- 体积账(与设计稿 §2.3 同口径:结构体 + 字符串,含 NUL)----
|
||||
sz_syl_struct = 8 * len(SYL) # py ptr(4) + hz ptr(4)
|
||||
sz_syl_str = sum(utf8_len(k) + 1 + utf8_len(v) + 1 for k, v in SYL.items())
|
||||
sz_word_struct = 12 * len(WORDS) # sp ptr(4) + hz ptr(4) + w(4)
|
||||
sz_word_str = sum(utf8_len(sp) + 1 + utf8_len(hz) + 1 for sp, hz, w in WORDS)
|
||||
total = sz_syl_struct + sz_syl_str + sz_word_struct + sz_word_str
|
||||
print('--- 词库体积账 ---')
|
||||
print('音节表: %d 条, 结构体 %d B + 字符串 %d B = %d B' % (len(SYL), sz_syl_struct, sz_syl_str, sz_syl_struct + sz_syl_str))
|
||||
print('词语表: %d 条, 结构体 %d B + 字符串 %d B = %d B' % (len(WORDS), sz_word_struct, sz_word_str, sz_word_struct + sz_word_str))
|
||||
print('合计 .rodata 估算: %d B (%.1f KiB)' % (total, total / 1024.0))
|
||||
print('--- 出错/重复检测 ---')
|
||||
# 词表允许同键不同条目(如 'wei' 等),这里仅打印去重提示
|
||||
print('生成完成 meow_pinyin_lex.h')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
* meow_pinyin.c — 中文拼音Ⅰ级候选引擎(静态表驱动,纯 C,零堆)。
|
||||
*
|
||||
* 词库在 meow_pinyin_lex.h(gen_pinyin_lex.py 离线生成,.rodata)。
|
||||
* 供 meow_ui_ime.c(MEOW_IME_PINYIN 模式)调用;SDK 集成时本 TU 进 meow_ui.a。
|
||||
*
|
||||
* 查询 = 当前组合拼音串(去声调小写,如 "nihao")→ 候选列表(UTF-8)。
|
||||
* 排序规则(与设计稿 §4.4 / /tmp/pyim engine.c 一致):
|
||||
* 1) 短语精确命中(sp==输入,如 nihao→你好)最优先;
|
||||
* 2) 音节切分组合(ni+hao→你好/你号/呢好…)按「每音节候选字序号之和」升序;
|
||||
* 3) 前缀整词提示(sp 以输入为前缀,如 ni→你好/你好吗)排最后(边打边出整词)。
|
||||
*
|
||||
* 设计约束:无 stdio(拉体积),无动态分配(MIPS32/14MB 意识)。切分 DFS + 组合
|
||||
* 上限常量封死(MAXSPLIT/MAXCOMB),防长组合串爆炸。词表按 sp 前缀匹配(线性回溯)。
|
||||
*/
|
||||
#include "meow_pinyin_lex.h"
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define MAXCAND 32 /* 每轮候选上限(与 IME 候选数组对齐) */
|
||||
#define MAXSPLIT 64 /* 切分枚举上限 */
|
||||
#define MAXSYL 8 /* 一次组合的音节数上限 */
|
||||
#define TK 4 /* 每音节取前 K 个字符再组合(限组合数) */
|
||||
#define MAXCOMB 120 /* 笛卡尔组合 guard(防爆炸) */
|
||||
|
||||
typedef struct { char hz[64]; int score; int src; int seg; } cand; /* src: 0=短语 1=切分组合 2=前缀词提示; seg=切分音节数 */
|
||||
|
||||
/* 定长拷贝一个 NUL 结尾字符串到 d[64];用 memcpy 规避 -Wstringop-truncation(来源可能超 63)。 */
|
||||
static void set_hz(char *d, const char *s)
|
||||
{
|
||||
size_t n = strlen(s);
|
||||
if (n > 63) n = 63;
|
||||
memcpy(d, s, n);
|
||||
d[n] = 0;
|
||||
}
|
||||
|
||||
/* 收集某音节候选字(UTF-8 单字),填入 chars[][4](UTF-8 ≤3B + NUL)。返回字数。 */
|
||||
static int syl_chars(int s, char chars[][4], int maxk)
|
||||
{
|
||||
const char *h = SYL[s].hz;
|
||||
int n = 0, i = 0;
|
||||
while (h[i] && n < maxk) {
|
||||
int l = 1;
|
||||
if ((unsigned char)h[i] >= 0xF0) l = 4;
|
||||
else if ((unsigned char)h[i] >= 0xE0) l = 3;
|
||||
else if ((unsigned char)h[i] >= 0xC0) l = 2;
|
||||
if (n < maxk) { memcpy(chars[n], h + i, (size_t)l); chars[n][l] = 0; n++; }
|
||||
i += l;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
/* 枚举 py 全部合法音节切分(DFS)。g_split[i]=切分路径(音节下标数组)。 */
|
||||
static int g_split[MAXSPLIT][MAXSYL];
|
||||
static int g_splitlen[MAXSPLIT];
|
||||
static int g_ns;
|
||||
|
||||
static void dfs_split(const char *py, int i, int path[], int plen)
|
||||
{
|
||||
if (g_ns >= MAXSPLIT) return;
|
||||
if (py[i] == 0) {
|
||||
if (plen == 0) return;
|
||||
memcpy(g_split[g_ns], path, (size_t)plen * sizeof(int));
|
||||
g_splitlen[g_ns] = plen;
|
||||
g_ns++;
|
||||
return;
|
||||
}
|
||||
for (int s = 0; s < SYL_N && g_ns < MAXSPLIT; s++) {
|
||||
int l = (int)strlen(SYL[s].py);
|
||||
if (strncmp(py + i, SYL[s].py, (size_t)l) == 0) {
|
||||
path[plen] = s;
|
||||
dfs_split(py, i + l, path, plen + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int cmp_cand(const void *a, const void *b)
|
||||
{
|
||||
const cand *x = (const cand *)a, *y = (const cand *)b;
|
||||
if (x->score != y->score) return x->score - y->score; /* 升序:score 越小越常用 */
|
||||
if (x->seg != y->seg) return x->seg - y->seg; /* score 相同:音节数越少越优先(完整音节读法) */
|
||||
return x->src - y->src;
|
||||
}
|
||||
|
||||
static void dedupe(cand *c, int *n)
|
||||
{
|
||||
for (int i = 0; i < *n; i++)
|
||||
for (int j = i + 1; j < *n; j++)
|
||||
if (strcmp(c[i].hz, c[j].hz) == 0) { c[j].score = 99999; }
|
||||
int w = 0;
|
||||
for (int i = 0; i < *n; i++) if (c[i].score != 99999) c[w++] = c[i];
|
||||
*n = w;
|
||||
}
|
||||
|
||||
/* 主入口:输入当前拼音组合串(去声调),输出候选列表(UTF-8),返回个数。
|
||||
* out 至少 maxout 项,每项定长 64B(拷贝,非持久)。 */
|
||||
int py_predict(const char *py, char out[][64], int maxout)
|
||||
{
|
||||
cand cs[MAXCAND]; int nc = 0;
|
||||
const int len = (int)strlen(py);
|
||||
if (len == 0 || maxout <= 0) return 0;
|
||||
if (maxout > MAXCAND) maxout = MAXCAND;
|
||||
|
||||
/* 1) 短语精确命中(band 0:最优先)。词表可能多条同拼(如 'shi'/'dui' 单字词),按序给 rank。 */
|
||||
int exact_rank = 0;
|
||||
for (int i = 0; i < WORD_N && nc < MAXCAND; i++) {
|
||||
if (strcmp(WORDS[i].sp, py) == 0) {
|
||||
set_hz(cs[nc].hz, WORDS[i].hz);
|
||||
cs[nc].score = exact_rank++;
|
||||
cs[nc].src = 0; cs[nc].seg = 1; nc++;
|
||||
}
|
||||
}
|
||||
/* 2) 前缀词提示(band 2:边打边出整词,排在单字组合之后) */
|
||||
int pre_rank = 0;
|
||||
for (int i = 0; i < WORD_N && nc < MAXCAND; i++) {
|
||||
int wl = (int)strlen(WORDS[i].sp);
|
||||
if (wl > len && strncmp(WORDS[i].sp, py, (size_t)len) == 0) {
|
||||
set_hz(cs[nc].hz, WORDS[i].hz);
|
||||
cs[nc].score = 200 + pre_rank++;
|
||||
cs[nc].src = 2; cs[nc].seg = 1; nc++;
|
||||
}
|
||||
}
|
||||
/* 3) 音节切分组合 */
|
||||
g_ns = 0;
|
||||
{ int path[MAXSYL]; dfs_split(py, 0, path, 0); }
|
||||
for (int s = 0; s < g_ns && nc < MAXCAND; s++) {
|
||||
const int *seg = g_split[s];
|
||||
int nseg = g_splitlen[s];
|
||||
char cset[MAXSYL][TK][4];
|
||||
int cnt[MAXSYL];
|
||||
for (int k = 0; k < nseg; k++) cnt[k] = syl_chars(seg[k], cset[k], TK);
|
||||
int iter[MAXSYL]; for (int k = 0; k < nseg; k++) iter[k] = 0;
|
||||
int guard = 0;
|
||||
while (guard++ < MAXCOMB && nc < MAXCAND) {
|
||||
char buf[64]; buf[0] = 0; int score = 0;
|
||||
for (int k = 0; k < nseg; k++) { strcat(buf, cset[k][iter[k]]); score += iter[k]; }
|
||||
if (buf[0]) {
|
||||
set_hz(cs[nc].hz, buf);
|
||||
cs[nc].score = 100 + score; /* band 1:切分组合(sum of char index 越小越常用) */
|
||||
cs[nc].src = 1; cs[nc].seg = nseg; nc++;
|
||||
}
|
||||
int k = nseg - 1;
|
||||
while (k >= 0) {
|
||||
iter[k]++;
|
||||
if (iter[k] < cnt[k]) break;
|
||||
iter[k] = 0; k--;
|
||||
}
|
||||
if (k < 0) break;
|
||||
}
|
||||
}
|
||||
dedupe(cs, &nc);
|
||||
qsort(cs, (size_t)nc, sizeof(cand), cmp_cand);
|
||||
if (nc > maxout) nc = maxout;
|
||||
for (int i = 0; i < nc; i++) { memcpy(out[i], cs[i].hz, 64); }
|
||||
return nc;
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
* meow_pinyin.h — 中文拼音候选引擎公开接口(meow_ui_ime.c 调用;实现在 meow_pinyin.c)。
|
||||
* 词库(meow_pinyin_lex.h)与本接口均进 meow_ui.a。纯 C 静态表驱动,零堆、无 stdio。
|
||||
*/
|
||||
#ifndef MEOW_PINYIN_H
|
||||
#define MEOW_PINYIN_H
|
||||
|
||||
/* 输入当前拼音组合串(去声调小写,如 "nihao"),输出候选列表(UTF-8,out 拷贝),返回条数。
|
||||
* out 至少 maxout 项、每项 ≥64B。无候选返回 0。 */
|
||||
int py_predict(const char *py, char out[][64], int maxout);
|
||||
|
||||
#endif /* MEOW_PINYIN_H */
|
||||
@@ -0,0 +1,750 @@
|
||||
/* 自动生成 by gen_pinyin_lex.py —— 中文拼音→候选字/词 频序表(去声调,UTF-8,.rodata)。*/
|
||||
/* 词库规模:音节 403 条 + 词语 329 条;候选字全部落在 GB2312 常用字集(common/gbk tier)。 */
|
||||
#ifndef MEOW_PINYIN_LEX_H
|
||||
#define MEOW_PINYIN_LEX_H
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct { const char *py; const char *hz; } py_syl;
|
||||
typedef struct { const char *sp; const char *hz; int w; } py_word;
|
||||
|
||||
#define SYL_N 403
|
||||
static const py_syl SYL[SYL_N] = {
|
||||
{"a", "啊阿吖呵腌"},
|
||||
{"ai", "爱哀挨唉矮碍癌艾呆埃"},
|
||||
{"an", "安按暗案岸俺鞍庵"},
|
||||
{"ang", "昂盎肮"},
|
||||
{"ao", "奥懊傲熬凹澳敖袄"},
|
||||
{"ba", "把八吧爸拔罢霸巴扒芭"},
|
||||
{"bai", "白百摆败拜柏伯佰"},
|
||||
{"ban", "办半班搬版板伴扮拌瓣"},
|
||||
{"bang", "帮棒榜绑膀磅邦蚌"},
|
||||
{"bao", "报保包宝抱暴薄爆饱堡"},
|
||||
{"bei", "被北背倍杯备悲辈贝碑"},
|
||||
{"ben", "本奔笨苯"},
|
||||
{"beng", "蹦崩甭泵迸"},
|
||||
{"bi", "比必笔闭毕鼻避彼壁弊"},
|
||||
{"bian", "变边便遍辨编辩扁鞭"},
|
||||
{"biao", "表标彪镖膘"},
|
||||
{"bie", "别憋鳖瘪"},
|
||||
{"bin", "宾滨彬濒斌"},
|
||||
{"bing", "病并兵冰饼丙柄秉"},
|
||||
{"bo", "波播拨薄博伯驳脖膊"},
|
||||
{"bu", "不步部布补捕怖埠簿"},
|
||||
{"ca", "擦嚓"},
|
||||
{"cai", "才菜采财猜彩裁踩材"},
|
||||
{"can", "参残餐灿惨蚕惭"},
|
||||
{"cang", "藏仓苍舱"},
|
||||
{"cao", "草操曹槽糙"},
|
||||
{"ce", "侧测策册厕"},
|
||||
{"cen", "岑"},
|
||||
{"ceng", "层曾蹭"},
|
||||
{"cha", "查差茶插叉察刹诧"},
|
||||
{"chai", "拆柴差钗"},
|
||||
{"chan", "产缠颤馋禅蝉"},
|
||||
{"chang", "长常场厂唱昌畅肠尝偿"},
|
||||
{"chao", "超朝潮吵炒抄钞巢"},
|
||||
{"che", "车扯撤彻澈"},
|
||||
{"chen", "陈沉晨臣尘趁衬辰"},
|
||||
{"cheng", "成城程称承诚乘盛橙惩"},
|
||||
{"chi", "吃持池迟赤尺斥驰齿翅"},
|
||||
{"chong", "冲重虫充宠崇憧"},
|
||||
{"chou", "抽愁丑臭筹仇酬绸"},
|
||||
{"chu", "出处初除楚厨触储础畜"},
|
||||
{"chua", "欻"},
|
||||
{"chuai", "揣踹"},
|
||||
{"chuan", "传船穿川串喘"},
|
||||
{"chuang", "创窗床闯疮"},
|
||||
{"chui", "吹垂锤炊"},
|
||||
{"chun", "春纯唇蠢淳"},
|
||||
{"chuo", "戳绰辍"},
|
||||
{"ci", "次此词刺辞瓷慈磁雌"},
|
||||
{"cong", "从聪葱囱匆"},
|
||||
{"cou", "凑"},
|
||||
{"cu", "粗促醋簇卒"},
|
||||
{"cuan", "窜窜蹿"},
|
||||
{"cui", "催脆翠摧崔粹"},
|
||||
{"cun", "存村寸蹲"},
|
||||
{"cuo", "错措搓挫磋"},
|
||||
{"da", "大打达答搭沓嗒"},
|
||||
{"dai", "带代待戴袋呆逮贷岱"},
|
||||
{"dan", "但担单弹蛋淡胆旦耽诞"},
|
||||
{"dang", "当挡党荡档挡"},
|
||||
{"dao", "到道倒刀岛导盗稻悼"},
|
||||
{"de", "的得地德"},
|
||||
{"deng", "等灯登邓凳瞪"},
|
||||
{"di", "地第低底敌抵滴弟帝递"},
|
||||
{"dian", "点电店典殿掂惦奠"},
|
||||
{"diao", "调掉钓雕叼吊"},
|
||||
{"die", "跌爹叠碟蝶迭"},
|
||||
{"ding", "定顶丁订钉盯鼎"},
|
||||
{"diu", "丢"},
|
||||
{"dong", "动东懂冬洞冻董栋"},
|
||||
{"dou", "都斗豆逗兜陡抖"},
|
||||
{"du", "度读独毒肚堵赌渡杜"},
|
||||
{"duan", "段断短端锻"},
|
||||
{"dui", "对队堆兑"},
|
||||
{"dun", "顿吨蹲盾钝敦"},
|
||||
{"duo", "多朵夺躲堕舵跺"},
|
||||
{"e", "饿恶额鹅俄蛾遏鄂"},
|
||||
{"en", "恩摁"},
|
||||
{"er", "而二儿耳尔饵洱"},
|
||||
{"fa", "发法罚伐乏阀筏"},
|
||||
{"fan", "反饭犯翻凡烦返泛范繁"},
|
||||
{"fang", "方放房防访仿坊纺"},
|
||||
{"fei", "非飞费肥废匪肺菲"},
|
||||
{"fen", "分粉份奋愤纷芬坟焚"},
|
||||
{"feng", "风封峰丰疯逢缝蜂凤"},
|
||||
{"fo", "佛"},
|
||||
{"fou", "否"},
|
||||
{"fu", "副复福扶服府负富付妇父符附腐"},
|
||||
{"ga", "嘎尬噶"},
|
||||
{"gai", "该改盖概钙溉"},
|
||||
{"gan", "干感敢赶甘杆肝竿"},
|
||||
{"gang", "刚钢港岗缸杠"},
|
||||
{"gao", "高告搞稿糕膏"},
|
||||
{"ge", "个各歌格哥隔割阁胳"},
|
||||
{"gei", "给"},
|
||||
{"gen", "跟根跟"},
|
||||
{"geng", "更耕颈梗耿"},
|
||||
{"gong", "公共工功攻供宫拱贡恭"},
|
||||
{"gou", "够狗购勾沟构钩"},
|
||||
{"gu", "故古顾股骨鼓谷姑孤估"},
|
||||
{"gua", "挂瓜刮寡卦"},
|
||||
{"guai", "怪拐乖"},
|
||||
{"guan", "关管观官冠馆惯罐"},
|
||||
{"guang", "光广逛"},
|
||||
{"gui", "贵归鬼规柜桂跪诡"},
|
||||
{"gun", "滚棍"},
|
||||
{"guo", "国过果锅裹郭"},
|
||||
{"ha", "哈蛤"},
|
||||
{"hai", "还海害孩嗨骇"},
|
||||
{"han", "含喊汉汗寒韩罕憾"},
|
||||
{"hang", "行航夯杭"},
|
||||
{"hao", "好号浩豪毫郝耗昊"},
|
||||
{"he", "和合何河喝盒禾鹤贺荷"},
|
||||
{"hei", "黑嘿"},
|
||||
{"hen", "很恨狠痕"},
|
||||
{"heng", "横恒衡哼"},
|
||||
{"hong", "红洪宏虹烘鸿"},
|
||||
{"hou", "后候厚猴喉吼"},
|
||||
{"hu", "湖户呼胡虎糊互忽壶糊"},
|
||||
{"hua", "话花化画华滑划桦"},
|
||||
{"huai", "坏怀淮"},
|
||||
{"huan", "还换环欢缓幻患唤"},
|
||||
{"huang", "黄慌皇荒晃煌幌"},
|
||||
{"hui", "会回挥灰汇毁惠慧辉恢悔"},
|
||||
{"hun", "混昏婚魂浑"},
|
||||
{"huo", "或火活货获伙惑霍"},
|
||||
{"ji", "及机级极即急集计记既济季几给基激肌迹际剂"},
|
||||
{"jia", "家加价假架甲佳嘉嫁夹"},
|
||||
{"jian", "见件间建减检简坚健剑渐尖肩荐监"},
|
||||
{"jiang", "将讲江奖降酱姜僵"},
|
||||
{"jiao", "叫教交角觉较脚焦骄娇郊浇"},
|
||||
{"jie", "界接解节姐借街杰皆截戒届阶"},
|
||||
{"jin", "进近金今紧仅尽禁劲津筋"},
|
||||
{"jing", "经精京静境警惊景镜竟竞睛晶"},
|
||||
{"jiong", "窘炯"},
|
||||
{"jiu", "就九久酒旧救究舅揪"},
|
||||
{"ju", "据居具局举句巨距聚拒剧"},
|
||||
{"juan", "卷捐娟倦眷"},
|
||||
{"jue", "觉决绝角掘爵倔嚼"},
|
||||
{"jun", "军均君俊菌骏"},
|
||||
{"ka", "卡咖喀"},
|
||||
{"kai", "开凯慨楷"},
|
||||
{"kan", "看砍刊堪坎勘"},
|
||||
{"kang", "抗康炕扛慷"},
|
||||
{"kao", "考靠烤拷"},
|
||||
{"ke", "可课科克客刻渴棵颗咳"},
|
||||
{"kei", "剋"},
|
||||
{"ken", "肯垦啃恳"},
|
||||
{"keng", "坑吭"},
|
||||
{"kong", "空控孔恐"},
|
||||
{"kou", "口扣抠寇"},
|
||||
{"ku", "苦哭库裤酷枯窟"},
|
||||
{"kua", "跨夸垮挎"},
|
||||
{"kuai", "快块筷会脍"},
|
||||
{"kuan", "宽款"},
|
||||
{"kuang", "况狂矿框筐旷"},
|
||||
{"kui", "亏溃愧窥葵"},
|
||||
{"kun", "困昆捆坤"},
|
||||
{"kuo", "扩阔括廓"},
|
||||
{"la", "拉啦辣蜡腊喇"},
|
||||
{"lai", "来莱赖"},
|
||||
{"lan", "蓝栏拦懒烂览兰篮"},
|
||||
{"lang", "浪狼朗郎"},
|
||||
{"lao", "老劳牢捞唠姥"},
|
||||
{"le", "了乐勒"},
|
||||
{"lei", "类累泪雷蕾垒"},
|
||||
{"leng", "冷愣棱"},
|
||||
{"li", "里力理立利李离例历丽励粒厉礼"},
|
||||
{"lia", "俩"},
|
||||
{"lian", "连脸练联恋链帘莲"},
|
||||
{"liang", "量两亮辆凉粮良梁"},
|
||||
{"liao", "了料聊疗辽廖"},
|
||||
{"lie", "列烈裂猎劣"},
|
||||
{"lin", "林临邻淋琳磷"},
|
||||
{"ling", "令领另零灵铃岭凌"},
|
||||
{"liu", "六流留刘柳溜瘤"},
|
||||
{"long", "龙隆笼聋拢垄"},
|
||||
{"lou", "楼漏搂陋"},
|
||||
{"lu", "路陆录露鲁卢炉鹿炉"},
|
||||
{"luan", "乱卵峦"},
|
||||
{"lun", "论轮伦沦"},
|
||||
{"lue", "略掠"},
|
||||
{"luo", "落罗洛络骆裸"},
|
||||
{"lv", "率律绿虑旅驴吕铝"},
|
||||
{"lve", "略掠"},
|
||||
{"ma", "吗妈马麻骂码嘛玛"},
|
||||
{"mai", "买卖麦埋迈脉"},
|
||||
{"man", "满慢蛮瞒漫曼"},
|
||||
{"mang", "忙茫盲芒莽"},
|
||||
{"mao", "毛猫冒帽茂矛贸锚"},
|
||||
{"me", "么"},
|
||||
{"mei", "没每美妹梅眉媒霉"},
|
||||
{"men", "们门闷萌"},
|
||||
{"meng", "梦猛蒙盟萌"},
|
||||
{"mi", "米密迷秘蜜谜觅"},
|
||||
{"mian", "面免棉眠缅勉"},
|
||||
{"miao", "秒妙苗描庙瞄"},
|
||||
{"mie", "灭蔑"},
|
||||
{"min", "民敏闽皿"},
|
||||
{"ming", "明名命鸣铭茗"},
|
||||
{"miu", "谬"},
|
||||
{"mo", "摸模磨末莫默墨陌摩"},
|
||||
{"mou", "某谋牟"},
|
||||
{"mu", "目母木幕牧慕墓穆亩"},
|
||||
{"na", "那拿哪纳娜呐"},
|
||||
{"nai", "奶乃耐奈"},
|
||||
{"nan", "难南男楠"},
|
||||
{"nang", "囊"},
|
||||
{"nao", "脑闹恼挠"},
|
||||
{"ne", "呢"},
|
||||
{"nei", "内馁"},
|
||||
{"nen", "嫩"},
|
||||
{"neng", "能"},
|
||||
{"ni", "你呢泥尼妮霓逆拟腻匿"},
|
||||
{"nian", "年念粘捻撵"},
|
||||
{"niang", "娘酿"},
|
||||
{"niao", "鸟尿"},
|
||||
{"nie", "捏聂孽"},
|
||||
{"nin", "您"},
|
||||
{"ning", "宁凝拧"},
|
||||
{"niu", "牛扭纽妞"},
|
||||
{"nong", "弄农浓脓"},
|
||||
{"nou", "耨"},
|
||||
{"nu", "怒努奴"},
|
||||
{"nuan", "暖"},
|
||||
{"nuo", "诺挪懦"},
|
||||
{"nv", "女"},
|
||||
{"nve", "虐疟"},
|
||||
{"o", "哦噢"},
|
||||
{"ou", "欧偶呕殴藕"},
|
||||
{"pa", "怕爬趴帕啪"},
|
||||
{"pai", "排派拍牌徘湃"},
|
||||
{"pan", "判盘盼攀畔叛"},
|
||||
{"pang", "旁胖庞乓"},
|
||||
{"pao", "跑炮泡抛袍"},
|
||||
{"pei", "陪配佩赔培"},
|
||||
{"pen", "喷盆"},
|
||||
{"peng", "朋碰捧棚蓬鹏"},
|
||||
{"pi", "皮批脾披疲劈匹屁"},
|
||||
{"pian", "片篇偏骗"},
|
||||
{"piao", "票飘漂瓢"},
|
||||
{"pie", "撇瞥"},
|
||||
{"pin", "品拼贫频聘"},
|
||||
{"ping", "平评凭瓶苹萍乒"},
|
||||
{"po", "破坡婆迫颇魄"},
|
||||
{"pou", "剖"},
|
||||
{"pu", "铺普朴谱浦葡仆"},
|
||||
{"qi", "起期其气七齐器汽奇乞旗棋"},
|
||||
{"qia", "恰掐洽"},
|
||||
{"qian", "前钱千签浅欠牵铅迁谦"},
|
||||
{"qiang", "强抢墙枪腔"},
|
||||
{"qiao", "桥瞧敲俏巧悄壳"},
|
||||
{"qie", "且切窃茄"},
|
||||
{"qin", "亲琴勤侵秦"},
|
||||
{"qing", "请清轻青情晴顷倾"},
|
||||
{"qiong", "穷琼"},
|
||||
{"qiu", "求球秋丘邱"},
|
||||
{"qu", "去取区曲娶趣趋渠"},
|
||||
{"quan", "全权圈劝拳泉犬"},
|
||||
{"que", "却确缺雀鹊"},
|
||||
{"qun", "群裙"},
|
||||
{"ran", "然染燃"},
|
||||
{"rang", "让嚷壤"},
|
||||
{"rao", "绕饶扰"},
|
||||
{"re", "热惹"},
|
||||
{"ren", "人认任仁忍韧刃"},
|
||||
{"reng", "仍扔"},
|
||||
{"ri", "日"},
|
||||
{"rong", "容荣融绒溶"},
|
||||
{"rou", "肉柔揉"},
|
||||
{"ru", "如入辱儒乳汝"},
|
||||
{"rua", "挼"},
|
||||
{"ruan", "软"},
|
||||
{"rui", "瑞锐"},
|
||||
{"run", "润闰"},
|
||||
{"ruo", "若弱"},
|
||||
{"sa", "撒洒萨"},
|
||||
{"sai", "赛塞腮"},
|
||||
{"san", "三散伞"},
|
||||
{"sang", "桑嗓丧"},
|
||||
{"sao", "扫嫂骚"},
|
||||
{"se", "色涩瑟"},
|
||||
{"sen", "森"},
|
||||
{"seng", "僧"},
|
||||
{"sha", "沙杀傻纱啥刹煞"},
|
||||
{"shai", "晒筛"},
|
||||
{"shan", "山善闪衫删扇陕"},
|
||||
{"shang", "上商伤尚赏裳"},
|
||||
{"shao", "少烧稍绍捎勺"},
|
||||
{"she", "社设舍射蛇摄涉奢"},
|
||||
{"shen", "身深神甚伸什申慎渗"},
|
||||
{"sheng", "生声省胜圣升盛剩"},
|
||||
{"shi", "是事时十式市师世史示使士失视实识施"},
|
||||
{"shou", "手受收首守售寿授瘦"},
|
||||
{"shu", "书数术树输属舒叔殊疏蔬"},
|
||||
{"shua", "刷耍"},
|
||||
{"shuai", "帅摔甩衰"},
|
||||
{"shuan", "栓拴"},
|
||||
{"shuang", "双爽"},
|
||||
{"shui", "水睡税"},
|
||||
{"shun", "顺瞬"},
|
||||
{"shuo", "说硕烁"},
|
||||
{"si", "四死思斯司私似撕寺饲"},
|
||||
{"song", "送松宋诵颂"},
|
||||
{"sou", "搜艘嗽"},
|
||||
{"su", "素速苏诉宿俗塑肃"},
|
||||
{"suan", "算酸蒜"},
|
||||
{"sui", "岁随虽碎遂穗"},
|
||||
{"sun", "孙损笋"},
|
||||
{"suo", "所锁索缩嗦"},
|
||||
{"ta", "他她它塔踏塌拓"},
|
||||
{"tai", "太台抬态泰苔"},
|
||||
{"tan", "谈弹叹探贪摊滩瘫"},
|
||||
{"tang", "堂糖汤唐躺烫塘"},
|
||||
{"tao", "讨套逃掏桃掏"},
|
||||
{"te", "特"},
|
||||
{"teng", "疼腾藤"},
|
||||
{"ti", "体题提替踢蹄剃"},
|
||||
{"tian", "天田甜填添"},
|
||||
{"tiao", "条跳挑调"},
|
||||
{"tie", "铁贴帖"},
|
||||
{"ting", "听停厅挺庭亭艇"},
|
||||
{"tong", "同通痛统童筒铜桶"},
|
||||
{"tou", "头投偷透"},
|
||||
{"tu", "图土突途徒吐兔涂"},
|
||||
{"tuan", "团"},
|
||||
{"tui", "推退腿褪"},
|
||||
{"tun", "吞屯臀"},
|
||||
{"tuo", "托脱拖妥驼椭"},
|
||||
{"wa", "挖瓦蛙娃袜"},
|
||||
{"wai", "外歪"},
|
||||
{"wan", "完万晚玩弯碗湾挽"},
|
||||
{"wang", "王往望网忘旺亡"},
|
||||
{"wei", "为位未卫维微围委谓违唯尾"},
|
||||
{"wen", "问文闻温稳吻纹"},
|
||||
{"weng", "翁嗡瓮"},
|
||||
{"wo", "我握窝卧沃"},
|
||||
{"wu", "无五物误务武舞午污伍"},
|
||||
{"xi", "系西习戏喜细吸希洗悉溪膝席惜"},
|
||||
{"xia", "下夏吓虾峡狭暇霞"},
|
||||
{"xian", "先现线县显险鲜闲限陷献"},
|
||||
{"xiang", "想向相像响项香乡箱详"},
|
||||
{"xiao", "小笑校晓消销肖效萧"},
|
||||
{"xie", "写些鞋谢协血携斜泄"},
|
||||
{"xin", "新心信辛欣薪芯"},
|
||||
{"xing", "行性形星兴型醒幸姓"},
|
||||
{"xiong", "雄胸凶兄熊"},
|
||||
{"xiu", "修秀休羞锈袖嗅"},
|
||||
{"xu", "需须许序续徐虚绪蓄"},
|
||||
{"xuan", "选宣旋悬玄轩"},
|
||||
{"xue", "学雪血穴靴"},
|
||||
{"xun", "寻讯训迅询巡循旬"},
|
||||
{"ya", "压呀牙亚讶雅鸦鸭"},
|
||||
{"yan", "眼言演烟严沿研盐验颜宴艳延"},
|
||||
{"yang", "样养洋阳羊央仰扬"},
|
||||
{"yao", "要药摇腰咬耀邀遥谣"},
|
||||
{"ye", "也业夜叶爷野冶页"},
|
||||
{"yi", "一已以意义医衣依易忆疑谊益议"},
|
||||
{"yin", "因音引银印隐饮阴姻"},
|
||||
{"ying", "应英影营迎硬赢映鹰"},
|
||||
{"yo", "哟"},
|
||||
{"yong", "用永拥勇涌泳庸"},
|
||||
{"you", "有又由右油游友优幼忧尤呦"},
|
||||
{"yu", "于与语雨鱼玉育余遇欲愈预域娱"},
|
||||
{"yuan", "元原员院远愿圆园源冤缘"},
|
||||
{"yue", "月越约阅跃悦岳"},
|
||||
{"yun", "云运允匀韵孕"},
|
||||
{"za", "杂砸咋"},
|
||||
{"zai", "在再载咱灾宰"},
|
||||
{"zan", "咱赞暂攒"},
|
||||
{"zang", "藏脏葬"},
|
||||
{"zao", "早造遭糟澡灶燥躁"},
|
||||
{"ze", "则责择泽"},
|
||||
{"zei", "贼"},
|
||||
{"zen", "怎"},
|
||||
{"zeng", "增赠曾憎"},
|
||||
{"zha", "炸查扎眨乍榨渣"},
|
||||
{"zhai", "宅摘窄债斋"},
|
||||
{"zhan", "战站占展沾粘斩"},
|
||||
{"zhang", "张章长掌涨帐障丈"},
|
||||
{"zhao", "找照招着朝召兆"},
|
||||
{"zhe", "这者着折哲浙"},
|
||||
{"zhen", "真阵镇针震振诊枕"},
|
||||
{"zheng", "正整证政争征挣睁郑"},
|
||||
{"zhi", "只之至制知指直纸志治支止职织质执"},
|
||||
{"zhong", "中种重众忠终钟仲"},
|
||||
{"zhou", "周州洲舟昼皱骤轴"},
|
||||
{"zhu", "主住注助著朱猪竹煮筑祝驻"},
|
||||
{"zhua", "抓"},
|
||||
{"zhuai", "拽"},
|
||||
{"zhuan", "转专赚传砖"},
|
||||
{"zhuang", "装状撞庄壮"},
|
||||
{"zhui", "追坠缀"},
|
||||
{"zhun", "准"},
|
||||
{"zhuo", "桌捉着灼卓浊"},
|
||||
{"zi", "子自字资紫仔兹姿咨"},
|
||||
{"zong", "总宗纵综棕踪"},
|
||||
{"zou", "走奏揍邹"},
|
||||
{"zu", "组足祖族租阻卒"},
|
||||
{"zuan", "钻攥"},
|
||||
{"zui", "最嘴罪醉"},
|
||||
{"zun", "尊遵"},
|
||||
{"zuo", "做作坐座左昨"},
|
||||
};
|
||||
|
||||
#define WORD_N 329
|
||||
static const py_word WORDS[WORD_N] = {
|
||||
{"nihao","你好",10000},
|
||||
{"zhongguo","中国",9200},
|
||||
{"women","我们",9000},
|
||||
{"shijie","世界",8600},
|
||||
{"shijian","时间",8400},
|
||||
{"xianzai","现在",8300},
|
||||
{"keyi","可以",8200},
|
||||
{"meiyou","没有",8100},
|
||||
{"yijing","已经",8000},
|
||||
{"haode","好的",7900},
|
||||
{"pengyou","朋友",7800},
|
||||
{"gongzuo","工作",7700},
|
||||
{"shenghuo","生活",7600},
|
||||
{"xuexi","学习",7500},
|
||||
{"xihuan","喜欢",7400},
|
||||
{"beijing","北京",7300},
|
||||
{"shanghai","上海",7300},
|
||||
{"yinyue","音乐",7200},
|
||||
{"sousuo","搜索",7100},
|
||||
{"xiaza","下载",7000},
|
||||
{"wenjian","文件",7000},
|
||||
{"wenjianjia","文件夹",6900},
|
||||
{"shezhi","设置",6900},
|
||||
{"yingyong","应用",6900},
|
||||
{"tongzhi","通知",6800},
|
||||
{"zhongwen","中文",6800},
|
||||
{"pinyin","拼音",6800},
|
||||
{"meiti","媒体",6700},
|
||||
{"bofang","播放",6700},
|
||||
{"zanting","暂停",6600},
|
||||
{"jixu","继续",6600},
|
||||
{"shangyi","上一",6600},
|
||||
{"xiayi","下一",6600},
|
||||
{"liebiao","列表",6550},
|
||||
{"geshou","歌手",6500},
|
||||
{"gequ","歌曲",6500},
|
||||
{"zhuanji","专辑",6450},
|
||||
{"gouwu","购物",6400},
|
||||
{"dianhua","电话",6400},
|
||||
{"shouji","手机",6400},
|
||||
{"diannao","电脑",6350},
|
||||
{"dianying","电影",6300},
|
||||
{"dianshi","电视",6300},
|
||||
{"tushu","图书",6250},
|
||||
{"xuexiao","学校",6200},
|
||||
{"daxue","大学",6200},
|
||||
{"xiaoxue","小学",6150},
|
||||
{"gongsi","公司",6100},
|
||||
{"laoshi","老师",6100},
|
||||
{"tongxue","同学",6050},
|
||||
{"jiating","家庭",6000},
|
||||
{"baba","爸爸",6000},
|
||||
{"mama","妈妈",6000},
|
||||
{"gege","哥哥",5900},
|
||||
{"jiejie","姐姐",5900},
|
||||
{"didi","弟弟",5850},
|
||||
{"meimei","妹妹",5850},
|
||||
{"pengyoumen","朋友们",5800},
|
||||
{"nihaoma","你好吗",7000},
|
||||
{"zhongguoren","中国人",6200},
|
||||
{"shanghairen","上海人",4200},
|
||||
{"beijingren","北京人",4200},
|
||||
{"shenme","什么",6600},
|
||||
{"weishenme","为什么",6500},
|
||||
{"zemme","怎么",6500},
|
||||
{"zenmeyang","怎么样",6400},
|
||||
{"shenmeshihou","什么时候",6300},
|
||||
{"nar","哪儿",6200},
|
||||
{"duoshao","多少",6400},
|
||||
{"dui","对",8200},
|
||||
{"bushi","不是",8100},
|
||||
{"shi","是",8300},
|
||||
{"yexu","也许",6300},
|
||||
{"keshi","可是",6200},
|
||||
{"suoyi","所以",6300},
|
||||
{"ranhou","然后",6200},
|
||||
{"danshi","但是",6200},
|
||||
{"haishi","还是",6400},
|
||||
{"huozhe","或者",6300},
|
||||
{"bingqie","并且",6200},
|
||||
{"erqie","而且",6300},
|
||||
{"yinwei","因为",6500},
|
||||
{"suoyi","所以",6300},
|
||||
{"jintian","今天",6500},
|
||||
{"mingtian","明天",6400},
|
||||
{"zuotian","昨天",6300},
|
||||
{"xingqi","星期",6200},
|
||||
{"zhoumo","周末",6100},
|
||||
{"shangwu","上午",6000},
|
||||
{"xiawu","下午",6000},
|
||||
{"wanshang","晚上",6100},
|
||||
{"zaoshang","早上",6000},
|
||||
{"zhongwu","中午",5900},
|
||||
{"zhidao","知道",6800},
|
||||
{"mingbai","明白",6300},
|
||||
{"renshi","认识",6300},
|
||||
{"liaojie","了解",6200},
|
||||
{"xiangxin","相信",6200},
|
||||
{"xiwang","希望",6300},
|
||||
{"juede","觉得",6500},
|
||||
{"xianzai","现在",8300},
|
||||
{"zhende","真的",6400},
|
||||
{"feichang","非常",6400},
|
||||
{"tai","太",7800},
|
||||
{"hen","很",8000},
|
||||
{"dou","都",7900},
|
||||
{"ye","也",7900},
|
||||
{"zai","在",8300},
|
||||
{"you","有",8300},
|
||||
{"ba","吧",7800},
|
||||
{"ma","吗",7900},
|
||||
{"ne","呢",7800},
|
||||
{"a","啊",7900},
|
||||
{"jianghu","江湖",5400},
|
||||
{"shijie","世界",8600},
|
||||
{"xianshi","显示",6400},
|
||||
{"shebei","设备",6500},
|
||||
{"kongzhi","控制",6500},
|
||||
{"yuancheng","远程",6300},
|
||||
{"zhijie","直接",6400},
|
||||
{"fuwu","服务",6600},
|
||||
{"qidong","启动",6400},
|
||||
{"guanbi","关闭",6300},
|
||||
{"chongqi","重启",6200},
|
||||
{"gengxin","更新",6400},
|
||||
{"anzhuang","安装",6300},
|
||||
{"xiezai","卸载",6100},
|
||||
{"denglu","登录",6200},
|
||||
{"zhuce","注册",6100},
|
||||
{"shenfen","身份",6000},
|
||||
{"mima","密码",6100},
|
||||
{"zhanghu","账户",6000},
|
||||
{"anquan","安全",6200},
|
||||
{"shebei","设备",6500},
|
||||
{"wangluo","网络",6600},
|
||||
{"lianjie","连接",6500},
|
||||
{"duankai","断开",6100},
|
||||
{"wuxian","无线",6200},
|
||||
{"xinyongka","信用卡",5800},
|
||||
{"weixin","微信",6000},
|
||||
{"zhifu","支付",6200},
|
||||
{"shoukuan","收款",5900},
|
||||
{"gongxiang","共享",6000},
|
||||
{"wenjian","文件",7000},
|
||||
{"mulu","目录",6200},
|
||||
{"lujing","路径",6100},
|
||||
{"mingzi","名字",6200},
|
||||
{"mingcheng","名称",6400},
|
||||
{"liulan","浏览",6100},
|
||||
{"dakai","打开",6300},
|
||||
{"baocun","保存",6300},
|
||||
{"shanchua","删除",6400},
|
||||
{"fuzhi","复制",6200},
|
||||
{"jiantie","粘贴",6100},
|
||||
{"yidong","移动",6200},
|
||||
{"chongming","重命名",6100},
|
||||
{"chuanjian","创建",6200},
|
||||
{"xinjian","新建",6200},
|
||||
{"daoru","导入",6000},
|
||||
{"daochu","导出",6000},
|
||||
{"yinyue","音乐",7200},
|
||||
{"geci","歌词",6200},
|
||||
{"geshou","歌手",6500},
|
||||
{"gequ","歌曲",6500},
|
||||
{"xunhuan","循环",6100},
|
||||
{"shunxu","顺序",6100},
|
||||
{"suiji","随机",6000},
|
||||
{"danqu","单曲",6000},
|
||||
{"quanshen","全申",5600},
|
||||
{"anli","案例",5600},
|
||||
{"zhangdan","账单",5600},
|
||||
{"chongzhi","充值",5800},
|
||||
{"jifen","积分",5800},
|
||||
{"huiyuan","会员",6000},
|
||||
{"shangcheng","商城",5900},
|
||||
{"dingdan","订单",6000},
|
||||
{"wuliu","物流",5800},
|
||||
{"kuaidi","快递",5800},
|
||||
{"didai","地带",5600},
|
||||
{"quyu","区域",6100},
|
||||
{"shuju","数据",6700},
|
||||
{"wenben","文本",6300},
|
||||
{"shuru","输入",6400},
|
||||
{"shuchu","输出",6300},
|
||||
{"jiance","检测",6200},
|
||||
{"yunchu","运出",5600},
|
||||
{"ceshi","测试",6300},
|
||||
{"fangshi","方式",6400},
|
||||
{"mubiao","目标",6200},
|
||||
{"zhuangtai","状态",6500},
|
||||
{"jieduan","阶段",6100},
|
||||
{"banben","版本",6200},
|
||||
{"gongneng","功能",6600},
|
||||
{"canshu","参数",6100},
|
||||
{"jieguo","结果",6500},
|
||||
{"cuowu","错误",6300},
|
||||
{"tishi","提示",6300},
|
||||
{"warn","警告",5600},
|
||||
{"xinxi","信息",6700},
|
||||
{"shuju","数据",6700},
|
||||
{"anquan","安全",6200},
|
||||
{"qiye","企业",6100},
|
||||
{"yonghu","用户",6600},
|
||||
{"touxiang","头像",6000},
|
||||
{"jinqing","尽情",5800},
|
||||
{"zaixian","在线",6200},
|
||||
{"xiaoxi","消息",6400},
|
||||
{"pengyou","朋友",7800},
|
||||
{"guanxi","关系",6200},
|
||||
{"meili","美丽",6100},
|
||||
{"piaoliang","漂亮",6100},
|
||||
{"kuaile","快乐",6200},
|
||||
{"kaixin","开心",6200},
|
||||
{"xingfu","幸福",6100},
|
||||
{"jiankang","健康",6200},
|
||||
{"shenti","身体",6200},
|
||||
{"anquan","安全",6200},
|
||||
{"baozhang","保障",5900},
|
||||
{"huanjing","环境",6200},
|
||||
{"ziyuan","资源",6200},
|
||||
{"nengyuan","能源",6000},
|
||||
{"huanbao","环保",5900},
|
||||
{"zhineng","智能",6200},
|
||||
{"renlei","人类",6100},
|
||||
{"shehui","社会",6200},
|
||||
{"guojia","国家",6200},
|
||||
{"renmin","人民",6100},
|
||||
{"zhengfu","政府",6100},
|
||||
{"jingji","经济",6200},
|
||||
{"wenhua","文化",6200},
|
||||
{"jiaoyu","教育",6200},
|
||||
{"kexue","科学",6200},
|
||||
{"jishu","技术",6500},
|
||||
{"gongye","工业",6100},
|
||||
{"nongye","农业",5900},
|
||||
{"shangye","商业",6200},
|
||||
{"jinrong","金融",6100},
|
||||
{"yiyao","医药",5900},
|
||||
{"fangchan","房产",5900},
|
||||
{"qiche","汽车",6200},
|
||||
{"jixie","机械",6000},
|
||||
{"dianqi","电气",6000},
|
||||
{"ruan","软",6000},
|
||||
{"yingjian","硬件",6100},
|
||||
{"shujuku","数据库",6100},
|
||||
{"caozuo","操作",6400},
|
||||
{"xitong","系统",6600},
|
||||
{"pingtai","平台",6300},
|
||||
{"kuangjia","框架",6100},
|
||||
{"jiekou","接口",6200},
|
||||
{"yemian","页面",6300},
|
||||
{"chuangkou","窗口",6200},
|
||||
{"gundong","滚动",6100},
|
||||
{"shuaxin","刷新",6200},
|
||||
{"jiazai","加载",6300},
|
||||
{"huanchong","缓冲",6000},
|
||||
{"duilie","队列",5900},
|
||||
{"xiancheng","线程",6000},
|
||||
{"jincheng","进程",6100},
|
||||
{"neicun","内存",6200},
|
||||
{"yingpan","硬盘",6100},
|
||||
{"cunchu","存储",6100},
|
||||
{"wenjian","文件",7000},
|
||||
{"wenjianjia","文件夹",6900},
|
||||
{"tu","图",6400},
|
||||
{"tupian","图片",6400},
|
||||
{"zhaopian","照片",6200},
|
||||
{"shouji","手机",6400},
|
||||
{"xiangji","相机",6200},
|
||||
{"luoyin","录音",6100},
|
||||
{"shipin","视频",6400},
|
||||
{"shexiang","摄像",6000},
|
||||
{"yinyue","音乐",7200},
|
||||
{"bojing","剧情",5800},
|
||||
{"juchang","剧场",5800},
|
||||
{"dianying","电影",6300},
|
||||
{"dianshiju","电视剧",6200},
|
||||
{"jilu","记录",6200},
|
||||
{"zuji","足迹",5600},
|
||||
{"ditu","地图",6200},
|
||||
{"daohang","导航",6100},
|
||||
{"weizhi","位置",6200},
|
||||
{"dingwei","定位",6100},
|
||||
{"zhuanti","专题",5900},
|
||||
{"fenlei","分类",6200},
|
||||
{"biaqian","标签",6100},
|
||||
{"zhuxiao","注销",5800},
|
||||
{"zhuxiao","注销",5800},
|
||||
{"huanying","欢迎",6200},
|
||||
{"liuyan","留言",6000},
|
||||
{"pinglun","评论",6200},
|
||||
{"dianzan","点赞",6100},
|
||||
{"fenxiang","分享",6300},
|
||||
{"shoucang","收藏",6300},
|
||||
{"guanzhu","关注",6200},
|
||||
{"yinshua","印刷",5900},
|
||||
{"banshi","办事",5700},
|
||||
{"shenpi","审批",5800},
|
||||
{"jinzhi","禁止",6000},
|
||||
{"yunxu","允许",6100},
|
||||
{"queren","确认",6300},
|
||||
{"queding","确定",6300},
|
||||
{"qian","前",7600},
|
||||
{"hou","后",7600},
|
||||
{"zuo","左",7500},
|
||||
{"you","右",7500},
|
||||
{"shang","上",8000},
|
||||
{"xia","下",8000},
|
||||
{"zhongjian","中间",6100},
|
||||
{"pangbian","旁边",6000},
|
||||
{"limian","里面",6100},
|
||||
{"waimian","外面",6000},
|
||||
{"qianmian","前面",6100},
|
||||
{"houmian","后面",6100},
|
||||
{"shangmian","上面",6200},
|
||||
{"xiamian","下面",6100},
|
||||
{"dibiao","地表",5600},
|
||||
{"gongyuan","公园",6000},
|
||||
{"jie","街",6000},
|
||||
{"lukou","路口",5900},
|
||||
{"fangxiang","方向",6200},
|
||||
{"dongnan","东南",5800},
|
||||
{"xinxi","信息",6700},
|
||||
{"shuzime","数字",6400},
|
||||
{"zimu","字母",6100},
|
||||
{"hanzi","汉字",6300},
|
||||
{"wenhao","问号",5900},
|
||||
{"juhao","句号",5900},
|
||||
{"douhao","逗号",5900},
|
||||
};
|
||||
|
||||
#endif /* MEOW_PINYIN_LEX_H */
|
||||
@@ -131,7 +131,8 @@ int meow_btn_pressed(meow_widget *w); /* 应用在 on_tap 命中后
|
||||
/* ============================================================ */
|
||||
/* §5.1 输入法(IME)—— 内置触屏软键盘(仅英文 QWERTY / 数字,ASCII) */
|
||||
/* ============================================================ */
|
||||
typedef enum { MEOW_IME_ASCII, MEOW_IME_NUM } meow_ime_mode;
|
||||
/* 输入法模式(尾部追加枚举:ASCII/NUM 值不变,零 ABI 回归)。PINYIN=中文拼音(meow_ui_ime.c)。 */
|
||||
typedef enum { MEOW_IME_ASCII, MEOW_IME_NUM, MEOW_IME_PINYIN } meow_ime_mode;
|
||||
|
||||
typedef struct meow_ime_ctx {
|
||||
meow_ime_mode mode;
|
||||
@@ -150,6 +151,10 @@ void meow_ui_text_input_async(meow_ime_ctx *ctx);
|
||||
int meow_ime_active(void);
|
||||
const char *meow_ime_text(void);
|
||||
|
||||
/* 拼音模式组合态:当前拼音组合串(去声调小写,如 "nihao")供 App 渲染字段预览;
|
||||
* 无组合(或非拼音模式)返回 ""。组合串是 IME 内部态,不写入字段(§4.2)。 */
|
||||
const char *meow_ime_composition(void);
|
||||
|
||||
/* ============================================================ */
|
||||
/* §6 输入层 / 生命周期(B1) */
|
||||
/* ============================================================ */
|
||||
|
||||
+348
-4
@@ -13,6 +13,7 @@
|
||||
*/
|
||||
#include "meow_ui.h"
|
||||
#include "meow_ui_internal.h"
|
||||
#include "meow_pinyin.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -61,7 +62,8 @@ static void ime_restore(void)
|
||||
meow_ui_flush();
|
||||
}
|
||||
|
||||
typedef enum { K_CH, K_SHIFT, K_SPACE, K_BACK, K_ENTER, K_ESC } kkind;
|
||||
typedef enum { K_CH, K_SHIFT, K_SPACE, K_BACK, K_ENTER, K_ESC,
|
||||
K_PY, K_SWITCH, K_SYMBOL, K_COMMIT, K_CLEAR } kkind;
|
||||
|
||||
struct kbkey { int x, y, w, h; kkind kind; char ch; };
|
||||
|
||||
@@ -78,6 +80,40 @@ static meow_ime_ctx *g_ime_orig = NULL; /* 应用真实 ctx(buf 回填用)
|
||||
static char g_ime_buf[256];
|
||||
static int g_maxlen = 255;
|
||||
|
||||
/* ---- 拼音模式(MEOW_IME_PINYIN)几何 + 状态(设计稿 §4.1/§5.2)----
|
||||
* 面板纵向分割:组合条 420..456、候选栏 456..504、键区 504..684(4 行×48,下缘留 36px)。
|
||||
* 组合串 g_py_buf 是 IME 内部态,不进字段(字段只含已上屏文本);候选每页 ≤6。 */
|
||||
#define PY_COMBO_Y (KB_TOP) /* 420 — 组合条顶 */
|
||||
#define PY_COMBO_H 36 /* 组合条高 */
|
||||
#define PY_CAND_Y 456 /* 候选栏顶 */
|
||||
#define PY_CAND_H 48 /* 候选栏高 */
|
||||
#define PY_KEY_TOP 504 /* 键区首行顶 */
|
||||
#define PY_PAGE 6 /* 每页候选数 */
|
||||
#define PY_MAXCAND 32 /* py_predict 候选上限(g_py_all 容量) */
|
||||
#define PY_PREV_X 6
|
||||
#define PY_PREV_W 34
|
||||
#define PY_NEXT_X 440
|
||||
#define PY_NEXT_W 34
|
||||
#define PY_CAND_X0 44 /* 候选起始 x */
|
||||
#define PY_CAND_GAP 14 /* 候选间距 */
|
||||
#define PY_CLEAR_X 388 /* 组合条「清」按钮 */
|
||||
#define PY_CLEAR_W 34
|
||||
#define PY_BADGE_X 426 /* 组合条「拼音」模式徽标 */
|
||||
#define PY_BADGE_W 46
|
||||
#define PY_BADGE_H 28
|
||||
#define PY_BADGE_Y (PY_COMBO_Y + 4)
|
||||
|
||||
static char g_py_buf[64]; /* 拼音组合串(去声调小写,≤8 音节) */
|
||||
static char g_py_all[PY_MAXCAND][64];/* 当前组合全部候选(UTF-8) */
|
||||
static int g_py_nc; /* 候选总数 */
|
||||
static int g_py_page; /* 翻页偏移(每页 ≤6) */
|
||||
static int g_py_active; /* 组合态标志 */
|
||||
static int g_ime_swipe_y = -1; /* 最近按下 Y(候选栏滑动翻页判定) */
|
||||
|
||||
/* ASCII/NUM 顶条右侧「中」切换热区(不占键位,英文零回归;GEOM 与 meow_ime_draw / handle_tap 共用)。 */
|
||||
#define ASCII_MID_X 430
|
||||
#define ASCII_MID_W 44
|
||||
|
||||
/* ---- 布局 ---- */
|
||||
static void add_key(int x, int y, int w, int h, kkind k, char ch)
|
||||
{
|
||||
@@ -101,7 +137,38 @@ static void build_kb(meow_ime_mode mode)
|
||||
{
|
||||
g_nkeys = 0;
|
||||
int y = KB_TOP + 50;
|
||||
if (mode == MEOW_IME_ASCII) {
|
||||
if (mode == MEOW_IME_PINYIN) {
|
||||
/* 4 行文本键(拼音只用到字母;数字/符号走 [?123] 切到既有 NUM 布局):
|
||||
* 行首 y=504,行 y=504/552/600/648,下缘 684。 */
|
||||
y = PY_KEY_TOP;
|
||||
add_ch_row(y, "qwertyuiop");
|
||||
/* 第 2 行:9 字母 + [拼/英](切 MEOW_IME_ASCII,复用 SHIFT 槽位) */
|
||||
{
|
||||
const char *r = "asdfghjkl";
|
||||
int n = (int)strlen(r);
|
||||
int total = 10 * GW + 9 * GAP;
|
||||
int x = (480 - total) / 2;
|
||||
for (int i = 0; i < n; i++) add_key(x + i * GCOL, y + GCOL, GW, GH, K_CH, r[i]);
|
||||
add_key(x + 9 * GCOL, y + GCOL, GW, GH, K_SWITCH, '&');
|
||||
}
|
||||
/* 第 3 行:7 字母 + [←退格 3格] */
|
||||
{
|
||||
const char *r = "zxcvbnm";
|
||||
int n = (int)strlen(r);
|
||||
int total = 10 * GW + 9 * GAP;
|
||||
int x = (480 - total) / 2;
|
||||
for (int i = 0; i < n; i++) add_key(x + i * GCOL, y + GCOL * 2, GW, GH, K_CH, r[i]);
|
||||
add_key(x + 7 * GCOL, y + GCOL * 2, (GW + GAP) * 3, GH, K_BACK, '<');
|
||||
}
|
||||
/* 第 4 行:[?123] [空格 6格] [OK](OK=只提交不关闭,同英文) */
|
||||
{
|
||||
int total = 10 * GW + 9 * GAP;
|
||||
int x = (480 - total) / 2;
|
||||
add_key(x, y + GCOL * 3, GW, GH, K_SYMBOL, '1');
|
||||
add_key(x + GCOL, y + GCOL * 3, (GW + GAP) * 6, GH, K_SPACE, ' ');
|
||||
add_key(x + GCOL * 8, y + GCOL * 3, 2 * GW + GAP, GH, K_ENTER, '>');
|
||||
}
|
||||
} else if (mode == MEOW_IME_ASCII) {
|
||||
add_ch_row(y, "1234567890");
|
||||
add_ch_row(y + GCOL, "qwertyuiop");
|
||||
/* 第 3 行:9 字母 + SHIFT */
|
||||
@@ -154,8 +221,104 @@ static void build_kb(meow_ime_mode mode)
|
||||
/* ---- 编辑动作 ---- */
|
||||
static int is_letter(char c) { return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); }
|
||||
|
||||
/* ---- 拼音编辑动作(MEOW_IME_PINYIN) ---- */
|
||||
static int py_pages(void) { return (g_py_nc + PY_PAGE - 1) / PY_PAGE; }
|
||||
|
||||
static void py_refresh(void)
|
||||
{
|
||||
g_py_nc = py_predict(g_py_buf, g_py_all, PY_MAXCAND);
|
||||
g_py_page = 0;
|
||||
g_py_active = (g_py_buf[0] != 0);
|
||||
}
|
||||
|
||||
static void py_input(char c)
|
||||
{
|
||||
int len = (int)strlen(g_py_buf);
|
||||
if (len < (int)sizeof(g_py_buf) - 1) { g_py_buf[len] = c; g_py_buf[len + 1] = 0; }
|
||||
py_refresh();
|
||||
}
|
||||
|
||||
static void py_back_combo(void)
|
||||
{
|
||||
int len = (int)strlen(g_py_buf);
|
||||
if (len > 0) g_py_buf[len - 1] = 0;
|
||||
py_refresh();
|
||||
}
|
||||
|
||||
static void py_clear(void)
|
||||
{
|
||||
g_py_buf[0] = 0;
|
||||
py_refresh();
|
||||
g_ime_swipe_y = -1;
|
||||
}
|
||||
|
||||
/* 上屏词条到字段 + on_change + 清组合。maxlen 为字节预算(含 NUL)。 */
|
||||
static void py_commit(const char *s)
|
||||
{
|
||||
int len = (int)strlen(g_ime_buf);
|
||||
int sl = (s && *s) ? (int)strlen(s) : 0;
|
||||
if (sl > 0 && len + sl < g_maxlen) {
|
||||
memcpy(g_ime_buf + len, s, (size_t)sl + 1);
|
||||
if (g_ime_ctx.on_change) g_ime_ctx.on_change(g_ime_buf, g_ime_ctx.ctx);
|
||||
}
|
||||
py_clear();
|
||||
}
|
||||
|
||||
/* UTF-8 安全退格:从字段末回退一个 codepoint(1-4 字节) */
|
||||
static void py_back_field(void)
|
||||
{
|
||||
int len = (int)strlen(g_ime_buf);
|
||||
if (len <= 0) return;
|
||||
int i = len - 1;
|
||||
while (i > 0 && ((unsigned char)g_ime_buf[i] & 0xC0) == 0x80) i--; /* 回退过续字节,找到起始字节 */
|
||||
g_ime_buf[i] = 0;
|
||||
if (g_ime_ctx.on_change) g_ime_ctx.on_change(g_ime_buf, g_ime_ctx.ctx);
|
||||
}
|
||||
|
||||
static void py_page_next(void) { int p = py_pages(); if (g_py_page < p - 1) g_py_page++; }
|
||||
static void py_page_prev(void) { if (g_py_page > 0) g_py_page--; }
|
||||
static void py_commit_first(void) { if (g_py_nc > 0) py_commit(g_py_all[0]); }
|
||||
|
||||
static void py_set_mode(meow_ime_mode m)
|
||||
{
|
||||
g_ime_ctx.mode = m;
|
||||
py_clear(); /* 组合态未上屏内容丢弃(设计稿 §5.3:关闭/切换同语义) */
|
||||
g_shift = 0;
|
||||
build_kb(m);
|
||||
}
|
||||
|
||||
static void apply_key_py(const struct kbkey *k)
|
||||
{
|
||||
switch (k->kind) {
|
||||
case K_CH: py_input((char)tolower((unsigned char)k->ch)); break; /* 仅 a-z 字母进组合 */
|
||||
case K_BACK:
|
||||
if (g_py_buf[0]) py_back_combo(); /* 组合非空:删组合末字母 */
|
||||
else py_back_field(); /* 组合空:删字段末汉字(UTF-8 安全) */
|
||||
break;
|
||||
case K_SPACE:
|
||||
if (g_py_buf[0]) py_commit_first(); /* 组合非空:上屏首候选 */
|
||||
else { /* 空:上屏一个空格 */
|
||||
int len = (int)strlen(g_ime_buf);
|
||||
if (len < g_maxlen - 1) { g_ime_buf[len] = ' '; g_ime_buf[len + 1] = 0;
|
||||
if (g_ime_ctx.on_change) g_ime_ctx.on_change(g_ime_buf, g_ime_ctx.ctx); }
|
||||
}
|
||||
break;
|
||||
case K_ENTER:
|
||||
if (g_py_buf[0]) py_commit_first(); /* 上屏首候选 + 清组合(不关闭) */
|
||||
else g_ime_result = 1; /* 组合空:只提交不关闭(走 ESC/背景) */
|
||||
break;
|
||||
case K_SWITCH: py_set_mode(MEOW_IME_ASCII); break; /* 拼→英 */
|
||||
case K_SYMBOL: py_set_mode(MEOW_IME_NUM); break; /* →数字/符号 */
|
||||
case K_ESC: g_ime_result = 0; g_ime_done = 1; break;
|
||||
case K_COMMIT: py_commit_first(); break;
|
||||
case K_CLEAR: py_clear(); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
static void apply_key(const struct kbkey *k)
|
||||
{
|
||||
if (g_ime_ctx.mode == MEOW_IME_PINYIN) { apply_key_py(k); return; }
|
||||
switch (k->kind) {
|
||||
case K_CH: {
|
||||
/* M2.71-IME-fix:键面存小写(build_kb "qwertyuiop"…),shift 开→大写、关→小写;
|
||||
@@ -184,14 +347,103 @@ static void apply_key(const struct kbkey *k)
|
||||
}
|
||||
case K_ENTER: g_ime_result = 1; break; /* M2.71-IME-fix:回车只提交(mark),不关键盘;关闭走 ESC/背景 */
|
||||
case K_ESC: g_ime_result = 0; g_ime_done = 1; break;
|
||||
default: break; /* K_PY/K_SWITCH/K_SYMBOL/K_COMMIT/K_CLEAR 仅拼音布局出现,英文分支不触 */
|
||||
}
|
||||
}
|
||||
|
||||
/* ---- 绘制 ---- */
|
||||
|
||||
/* 拼音键面标签(K_CH=字母小写;其余为该键的内置文字)。 */
|
||||
static const char *py_key_label(const struct kbkey *k, char *tmp)
|
||||
{
|
||||
switch (k->kind) {
|
||||
case K_CH: { char c = (char)tolower((unsigned char)k->ch); tmp[0] = c; tmp[1] = 0; return tmp; }
|
||||
case K_BACK: return "⌫";
|
||||
case K_SPACE: return "空格";
|
||||
case K_ENTER: return "确定";
|
||||
case K_SWITCH: return "拼/英";
|
||||
case K_SYMBOL: return "?123";
|
||||
default: return "";
|
||||
}
|
||||
}
|
||||
|
||||
/* 候选栏内第 idx(页内 0..5)候选的实际 x/宽;越界返回 0。绘制与命中共用,保证几何一致。 */
|
||||
static int py_cand_rect(int idx, int *x, int *w)
|
||||
{
|
||||
int gi = g_py_page * PY_PAGE + idx;
|
||||
if (gi >= g_py_nc) return 0;
|
||||
int xp = PY_CAND_X0;
|
||||
for (int i = 0; i < idx; i++) {
|
||||
int pgi = g_py_page * PY_PAGE + i;
|
||||
if (pgi >= g_py_nc) break;
|
||||
xp += meow_ui_text_width(g_py_all[pgi], 20) + PY_CAND_GAP;
|
||||
}
|
||||
*x = xp;
|
||||
*w = meow_ui_text_width(g_py_all[gi], 20);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void meow_ime_draw_py(const meow_theme *th)
|
||||
{
|
||||
const int th20 = meow_ui_text_height(20);
|
||||
/* 面板整体 + 组合条 + 候选栏 */
|
||||
meow_ui_fill_rect(0, KB_TOP, 480, 720 - KB_TOP, th->surfaceContainerHighest);
|
||||
meow_ui_fill_rect(0, PY_COMBO_Y, 480, PY_COMBO_H, th->surfaceContainerHigh);
|
||||
|
||||
/* 组合条:left=组合串实时显示(含 '_' 光标);right=「清」+ 模式徽标「拼音」 */
|
||||
char pybuf[72];
|
||||
snprintf(pybuf, sizeof pybuf, "%s_", g_py_buf);
|
||||
meow_ui_text(14, PY_COMBO_Y + 8, pybuf, th->font_body, th->onSurface);
|
||||
meow_gfx_fill_round(PY_CLEAR_X, PY_COMBO_Y + 4, PY_CLEAR_W, PY_BADGE_H, 8, th->secondaryContainer);
|
||||
meow_ui_text_center(PY_CLEAR_X + PY_CLEAR_W / 2, PY_COMBO_Y + 4 + (PY_BADGE_H - th20) / 2, "清", 20, th->onSecondaryContainer);
|
||||
meow_gfx_fill_round(PY_BADGE_X, PY_BADGE_Y, PY_BADGE_W, PY_BADGE_H, 8, th->primaryContainer);
|
||||
meow_ui_text_center(PY_BADGE_X + PY_BADGE_W / 2, PY_BADGE_Y + (PY_BADGE_H - th20) / 2, "拼音", 20, th->onPrimaryContainer);
|
||||
|
||||
/* 候选栏:◀ ▶ 翻页 + 横排候选(高亮第 0 项) */
|
||||
meow_ui_fill_rect(0, PY_CAND_Y, 480, PY_CAND_H, th->surfaceContainerHighest);
|
||||
meow_gfx_fill_round(PY_PREV_X, PY_CAND_Y, PY_PREV_W, PY_CAND_H, 8, th->surfaceContainerLow);
|
||||
meow_ui_text_center(PY_PREV_X + PY_PREV_W / 2, PY_CAND_Y + (PY_CAND_H - th20) / 2, "◀", 20, th->onSurface);
|
||||
meow_gfx_fill_round(PY_NEXT_X, PY_CAND_Y, PY_NEXT_W, PY_CAND_H, 8, th->surfaceContainerLow);
|
||||
meow_ui_text_center(PY_NEXT_X + PY_NEXT_W / 2, PY_CAND_Y + (PY_CAND_H - th20) / 2, "▶", 20, th->onSurface);
|
||||
if (g_py_nc == 0) {
|
||||
meow_ui_text(PY_CAND_X0, PY_CAND_Y + (PY_CAND_H - th20) / 2, "(无候选)", th->font_body, th->onSurfaceVariant);
|
||||
} else {
|
||||
int x = PY_CAND_X0;
|
||||
for (int i = 0; i < PY_PAGE; i++) {
|
||||
int gi = g_py_page * PY_PAGE + i;
|
||||
if (gi >= g_py_nc) break;
|
||||
const char *c = g_py_all[gi];
|
||||
int w = meow_ui_text_width(c, 20);
|
||||
int ty = PY_CAND_Y + (PY_CAND_H - th20) / 2;
|
||||
if (i == 0) {
|
||||
meow_gfx_fill_round(x - 6, PY_CAND_Y + 6, w + 12, PY_CAND_H - 12, 8, th->secondaryContainer);
|
||||
meow_ui_text(x, ty, c, 20, th->onSecondaryContainer);
|
||||
} else {
|
||||
meow_ui_text(x, ty, c, 20, th->onSurface);
|
||||
}
|
||||
x += w + PY_CAND_GAP;
|
||||
}
|
||||
}
|
||||
|
||||
/* 4 行键 */
|
||||
for (int i = 0; i < g_nkeys; i++) {
|
||||
const struct kbkey *k = &g_keys[i];
|
||||
uint32_t bg, fg;
|
||||
if (k->kind == K_ENTER) { bg = th->primary; fg = th->onPrimary; }
|
||||
else if (k->kind == K_SWITCH){ bg = th->tertiaryContainer; fg = th->onTertiaryContainer; }
|
||||
else if (k->kind == K_CH) { bg = th->surfaceContainerLow; fg = th->onSurface; }
|
||||
else { bg = th->primaryContainer; fg = th->onPrimaryContainer; }
|
||||
meow_gfx_fill_round(k->x, k->y, k->w, k->h, 8, bg);
|
||||
char tmp[4];
|
||||
meow_ui_text_center(k->x + k->w / 2, k->y + (k->h - th20) / 2, py_key_label(k, tmp), 20, fg);
|
||||
}
|
||||
}
|
||||
|
||||
void meow_ime_draw(void)
|
||||
{
|
||||
if (!g_ime_active) return;
|
||||
const meow_theme *th = meow_theme_get();
|
||||
if (g_ime_ctx.mode == MEOW_IME_PINYIN) { meow_ime_draw_py(th); return; }
|
||||
/* M2.71-bug7:配色全走 meow_theme(深/浅主题自动切),不再硬编码黑底白键。 */
|
||||
meow_ui_fill_rect(0, KB_TOP, 480, 720 - KB_TOP, th->surfaceContainerHighest); /* 面板 */
|
||||
meow_ui_fill_rect(0, KB_TOP, 480, 42, th->surfaceContainerHigh); /* 回显条 */
|
||||
@@ -199,6 +451,12 @@ void meow_ime_draw(void)
|
||||
/* 回显=用户已输入的字符(live echo,非候选/联想),随键入实时刷新。 */
|
||||
snprintf(preview, sizeof preview, "%s_", g_ime_buf);
|
||||
meow_ui_text(14, KB_TOP + 9, preview, th->font_body, th->onSurface);
|
||||
/* ASCII/NUM 顶条右侧「中」热区:切到拼音模式(英文键布局零改动,零回归)。 */
|
||||
{
|
||||
int th20 = meow_ui_text_height(20);
|
||||
meow_gfx_fill_round(ASCII_MID_X, KB_TOP + 7, ASCII_MID_W, 28, 8, th->primaryContainer);
|
||||
meow_ui_text_center(ASCII_MID_X + ASCII_MID_W / 2, KB_TOP + 7 + (28 - th20) / 2, "中", 20, th->onPrimaryContainer);
|
||||
}
|
||||
/* 键 */
|
||||
for (int i = 0; i < g_nkeys; i++) {
|
||||
const struct kbkey *k = &g_keys[i];
|
||||
@@ -218,10 +476,53 @@ void meow_ime_draw(void)
|
||||
}
|
||||
|
||||
/* ---- 命中 ---- */
|
||||
|
||||
/* 找命中键(供拼音长按判定退格用)。 */
|
||||
static const struct kbkey *key_at(int x, int y)
|
||||
{
|
||||
for (int i = 0; i < g_nkeys; i++) {
|
||||
const struct kbkey *k = &g_keys[i];
|
||||
if (x >= k->x && x < k->x + k->w && y >= k->y && y < k->y + k->h) return k;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* 拼音命中:候选栏/组合条/键区。y<KB_TOP=取消(组合不上屏)。 */
|
||||
static int meow_ime_handle_tap_py(int x, int y)
|
||||
{
|
||||
if (y < KB_TOP) { g_ime_result = 0; g_ime_done = 1; return 1; } /* 背景点=取消 */
|
||||
if (y >= PY_CAND_Y && y < PY_CAND_Y + PY_CAND_H) { /* 候选栏 */
|
||||
if (x >= PY_PREV_X && x < PY_PREV_X + PY_PREV_W) { py_page_prev(); return 1; }
|
||||
if (x >= PY_NEXT_X && x < PY_NEXT_X + PY_NEXT_W) { py_page_next(); return 1; }
|
||||
/* 点候选:命中即上屏(UTF-8),清组合 */
|
||||
for (int i = 0; i < PY_PAGE; i++) {
|
||||
int cx, cw;
|
||||
if (!py_cand_rect(i, &cx, &cw)) break;
|
||||
if (x >= cx - 6 && x < cx + cw + 6) { py_commit(g_py_all[g_py_page * PY_PAGE + i]); return 1; }
|
||||
}
|
||||
return 1; /* 候选栏空隙:消费但不做 */
|
||||
}
|
||||
if (y >= PY_COMBO_Y && y < PY_COMBO_Y + PY_COMBO_H) { /* 组合条 */
|
||||
if (x >= PY_CLEAR_X && x < PY_CLEAR_X + PY_CLEAR_W) { py_clear(); return 1; } /* 清组合 */
|
||||
if (x >= PY_BADGE_X && x < PY_BADGE_X + PY_BADGE_W) { py_set_mode(MEOW_IME_ASCII); return 1; } /* 拼→英 */
|
||||
return 1; /* 组合条其他:消费 */
|
||||
}
|
||||
const struct kbkey *k = key_at(x, y);
|
||||
if (k) { apply_key(k); return 1; }
|
||||
return 1; /* 键区/面板空隙:消费但不做 */
|
||||
}
|
||||
|
||||
int meow_ime_handle_tap(int x, int y)
|
||||
{
|
||||
if (!g_ime_active || g_ime_done) return 0;
|
||||
if (y < KB_TOP) { g_ime_result = 0; g_ime_done = 1; return 1; } /* 背景点=取消 */
|
||||
if (g_ime_ctx.mode == MEOW_IME_PINYIN) return meow_ime_handle_tap_py(x, y);
|
||||
/* ASCII/NUM:顶条(回显条 KB_TOP..KB_TOP+42)右端「中」热区 → 切拼音;
|
||||
* y<KB_TOP=上方背景=取消;顶条其它区域消费不取消(沿用既有行为)。 */
|
||||
if (y < KB_TOP + 42) {
|
||||
if (x >= ASCII_MID_X && x < ASCII_MID_X + ASCII_MID_W) { py_set_mode(MEOW_IME_PINYIN); return 1; }
|
||||
if (y < KB_TOP) { g_ime_result = 0; g_ime_done = 1; return 1; } /* 背景点=取消 */
|
||||
return 1; /* 顶条其它:消费但不做(不落键) */
|
||||
}
|
||||
for (int i = 0; i < g_nkeys; i++) {
|
||||
const struct kbkey *k = &g_keys[i];
|
||||
if (x >= k->x && x < k->x + k->w && y >= k->y && y < k->y + k->h) {
|
||||
@@ -235,6 +536,45 @@ int meow_ime_handle_tap(int x, int y)
|
||||
/* ---- 对外 ---- */
|
||||
int meow_ime_active(void) { return g_ime_active && !g_ime_done; }
|
||||
const char *meow_ime_text(void) { return g_ime_buf; }
|
||||
const char *meow_ime_composition(void) { return g_ime_ctx.mode == MEOW_IME_PINYIN ? g_py_buf : ""; }
|
||||
int meow_ime_mode_pinyin(void) { return g_ime_active && !g_ime_done && g_ime_ctx.mode == MEOW_IME_PINYIN; }
|
||||
|
||||
/* 候选栏横滑翻页:滑动起始于候选栏区(y∈[456,504))才消费;首/尾页钳位。 */
|
||||
int meow_ime_swipe(int dir, int dist)
|
||||
{
|
||||
(void)dist;
|
||||
if (!meow_ime_mode_pinyin()) return 0;
|
||||
if (g_ime_swipe_y < PY_CAND_Y || g_ime_swipe_y >= PY_CAND_Y + PY_CAND_H) return 0;
|
||||
if (dir == MEOW_SWIPE_LEFT) { py_page_next(); return 1; }
|
||||
if (dir == MEOW_SWIPE_RIGHT) { py_page_prev(); return 1; }
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 拼音长按退格:长按落在「退格」键上 → 清空字段 + 组合(上屏 off 回调)。 */
|
||||
int meow_ime_long_press(int x, int y)
|
||||
{
|
||||
if (!meow_ime_mode_pinyin()) return 0;
|
||||
const struct kbkey *k = key_at(x, y);
|
||||
if (!k || k->kind != K_BACK) return 0;
|
||||
g_ime_buf[0] = 0;
|
||||
py_clear();
|
||||
if (g_ime_ctx.on_change) g_ime_ctx.on_change(g_ime_buf, g_ime_ctx.ctx);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* 统一事件入口:TAP/TOUCH_DOWN/SWIPE/LONG_PRESS(IME 打开时主循环/阻塞循环调用)。
|
||||
* ASCII/NUM:TAP 走既有 handle_tap,其余返回 0(沿用英文行为,零回归)。 */
|
||||
int meow_ime_handle_event(const meow_input_ev *e)
|
||||
{
|
||||
if (!g_ime_active || g_ime_done) return 0;
|
||||
switch (e->type) {
|
||||
case MEOW_EV_TAP: return meow_ime_handle_tap(e->a, e->b);
|
||||
case MEOW_EV_TOUCH_DOWN: g_ime_swipe_y = e->b; return 1; /* 记录压点(候选栏滑动判定);覆盖层消费 */
|
||||
case MEOW_EV_SWIPE: return meow_ime_swipe(e->a, e->b);
|
||||
case MEOW_EV_LONG_PRESS: return meow_ime_long_press(e->a, e->b);
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void meow_ime_close(int result)
|
||||
{
|
||||
@@ -256,6 +596,8 @@ void meow_ui_text_input_async(meow_ime_ctx *ctx)
|
||||
g_ime_buf[sizeof g_ime_buf - 1] = 0;
|
||||
g_maxlen = ctx->maxlen > 0 ? ctx->maxlen : 255;
|
||||
g_shift = 0; g_ime_result = 0; g_ime_done = 0; g_ime_active = 1;
|
||||
/* 拼音状态复位(组合/候选/翻页/压点) */
|
||||
g_py_buf[0] = 0; g_py_nc = 0; g_py_page = 0; g_py_active = 0; g_ime_swipe_y = -1;
|
||||
build_kb(ctx->mode);
|
||||
ime_capture(); /* M2.71-bug7:打开前拍下键盘区背景(关闭即还原) */
|
||||
meow_input_start();
|
||||
@@ -275,8 +617,10 @@ int meow_ui_text_input(meow_ime_ctx *ctx)
|
||||
meow_input_ev e;
|
||||
while (meow_input_pop(&e)) {
|
||||
meow_ui_activity_ping(); /* M2.71-bug5:IME 打字交互也重置息屏计时 */
|
||||
if (e.type == MEOW_EV_TAP) meow_ime_handle_tap(e.a, e.b);
|
||||
meow_ime_handle_event(&e); /* TAP/TOUCH_DOWN/SWIPE/LONG_PRESS 统一分发(拼音/英文) */
|
||||
}
|
||||
/* 拼音 IME 打开时喂长按轮询(长按退格清空字段);英文模式不喂(保持既有行为)。 */
|
||||
if (meow_ime_mode_pinyin()) meow_input_long_press_poll();
|
||||
/* M2.71-IME-fix:阻塞 IME 期间喂 App on_tick(动态内容继续刷,progress/时钟不卡死)。
|
||||
* 顺序要求:先喂 on_tick(App 重绘进 back_buf)→ 再 meow_ime_draw(IME 面板随后盖上去),
|
||||
* 保证 IME 面板覆盖在最上,不被 App 的 d_paint_region 覆盖。 */
|
||||
|
||||
@@ -522,6 +522,9 @@ void meow_ui_run(const meow_ui_events *ev)
|
||||
if (!meow_ime_active()) {
|
||||
meow_widget_touch_refresh();
|
||||
if (now_ms() >= startup_cooldown_until) meow_input_long_press_poll();
|
||||
} else if (meow_ime_mode_pinyin()) {
|
||||
/* 拼音 IME 打开:喂长按轮询(长按退格清空字段)。英文模式不喂(保持既有行为)。 */
|
||||
if (now_ms() >= startup_cooldown_until) meow_input_long_press_poll();
|
||||
}
|
||||
|
||||
meow_input_ev e;
|
||||
@@ -537,7 +540,7 @@ void meow_ui_run(const meow_ui_events *ev)
|
||||
/* 抬手未达标:清视觉条 */
|
||||
meow_ui_swipe_hint(-1);
|
||||
meow_ui_flush_region(0, meow_ui_statusbar_height(), meow_ui_width(), 6);
|
||||
if (meow_ime_active() && meow_ime_handle_tap(e.a, e.b)) continue;
|
||||
if (meow_ime_active() && meow_ime_handle_event(&e)) continue;
|
||||
/* §6.1 触摸分流:③ 系统全局(IME/状态栏…已在上面消费) → ② App 全局控件
|
||||
* (命中返回 1=消费,否则落到 ① active Activity 页面控件)。 */
|
||||
if (meow_ui_global_hit(e.a, e.b)) continue;
|
||||
@@ -549,6 +552,8 @@ void meow_ui_run(const meow_ui_events *ev)
|
||||
/* 抬手达标:清视觉条(左滑返回),触发行消失 */
|
||||
meow_ui_swipe_hint(-1);
|
||||
meow_ui_flush_region(0, meow_ui_statusbar_height(), meow_ui_width(), 6);
|
||||
/* 拼音 IME 候选栏横滑翻页(英文模式 handle_event 返回 0 → 沿用既有行为)。 */
|
||||
if (meow_ime_active() && meow_ime_handle_event(&e)) continue;
|
||||
/* A-0 全局左缘返回(方案A):
|
||||
* - APP 注册 on_swipe → APP 接管,自行决定(meow_ui_request_exit / 页内返回);
|
||||
* - APP 未注册 on_swipe 且非全屏(sb_active)→ SDK 默认退出 app(返回=退出);
|
||||
@@ -569,9 +574,10 @@ void meow_ui_run(const meow_ui_events *ev)
|
||||
} else if (e.type == MEOW_EV_TOUCH_DOWN || e.type == MEOW_EV_TOUCH_MOVE) {
|
||||
/* M2.71-bug2/6:拖动过程(跟手)。IME 弹出时触摸优先喂键盘(键盘覆盖层拦截,
|
||||
* on_touch_* 丢弃,避免按到键盘却在背后控件上锁拖拽);启动窗口也吞(防残留点按
|
||||
* 误锁拖拽)。模态(dialog/sheet)期间本主循环被阻塞,天然不在此分发。 */
|
||||
* 误锁拖拽)。模态(dialog/sheet)期间本主循环被阻塞,天然不在此分发。
|
||||
* IME 打开时先把压点喂给拼音(候选栏滑动翻页判定 g_ime_swipe_y),再丢弃。 */
|
||||
if (in_startup) continue;
|
||||
if (meow_ime_active()) continue;
|
||||
if (meow_ime_active()) { meow_ime_handle_event(&e); continue; }
|
||||
if (g_events_set && g_events.on_touch_down && e.type == MEOW_EV_TOUCH_DOWN)
|
||||
g_events.on_touch_down(e.a, e.b);
|
||||
if (g_events_set && g_events.on_touch_move && e.type == MEOW_EV_TOUCH_MOVE)
|
||||
@@ -596,6 +602,8 @@ void meow_ui_run(const meow_ui_events *ev)
|
||||
* meow_widget_hit/meow_listview_hit 判定命中控件/行)。已注册回调则分发;
|
||||
* 其抬手已被 touch_release 抑制(不再产生 TAP/SWIPE),此处无需吞后续 tap。 */
|
||||
if (in_startup) continue;
|
||||
/* 拼音 IME 打开:长按退格清空字段(英文模式 handle_event 返回 0 → 走既有长按回调)。 */
|
||||
if (meow_ime_active() && meow_ime_handle_event(&e)) continue;
|
||||
if (g_long_press_cb) g_long_press_cb(e.a, e.b);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -244,4 +244,12 @@ void meow_ime_draw(void);
|
||||
/* 关闭 IME 并交付最终结果(result: 1=确认 0=取消)。 */
|
||||
void meow_ime_close(int result);
|
||||
|
||||
/* 拼音 IME 事件钩子(meow_ui_input.c 主循环 / meow_ui_ime.c 阻塞循环调用,IME 打开时):
|
||||
* 统一分发 TAP/TOUCH_DOWN/SWIPE/LONG_PRESS 给拼音模式(组合/候选栏翻页/长按清空)。
|
||||
* 非拼音(ASCII/NUM)模式:TAP 走 meow_ime_handle_tap,其余事件返回 0(沿用既有英文行为,零回归)。
|
||||
* 返回 1=已消费(调用方 continue),0=透传。 */
|
||||
int meow_ime_handle_event(const meow_input_ev *e);
|
||||
/* 当前 IME 是否拼音模式(供 meow_ui_input.c 决定是否喂长按轮询)。 */
|
||||
int meow_ime_mode_pinyin(void);
|
||||
|
||||
#endif /* MEOW_UI_INTERNAL_H */
|
||||
Binary file not shown.
Executable
BIN
Binary file not shown.
@@ -0,0 +1,125 @@
|
||||
/* test_pinyin.c — 中文拼音 IME 宿主验证(480x720 离屏,直接 handle_tap 确定语义)。
|
||||
* ① 拼音组合:type "nihao" → 组合串="nihao"、字段=""(组合不上屏、on_change 不触发);
|
||||
* 点候选(你好)→ 字段="你好"、组合清空、on_change="你好";
|
||||
* ② 候选翻页:type "shi" → nc>6;点 ▶ 翻页末首候选变化、点 ◀ 回;
|
||||
* ③ UTF-8 删字段:上屏"你好"后点退格 → 字段="你"(按 codepoint 回退,不出现乱码);
|
||||
* ④ 中/英切换:拼音点 [拼/英] → ASCII;ASCII 点顶条「中」热区 → 拼音;
|
||||
* ⑤ 空格/回车上屏首候选:type "ni" + 空格 → 字段="你"。
|
||||
*
|
||||
* 编译(宿主 gcc,同 test_ime_fix):
|
||||
* gcc -Wall -Wextra -o test_pinyin test_pinyin.c test_host_stub.c \
|
||||
* meow_ui_gfx.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \
|
||||
* meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c \
|
||||
* meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_img.c meow_ui_media.c \
|
||||
* meow_notify_ipc.c stb_image.c -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm
|
||||
*/
|
||||
#include "meow_ui.h"
|
||||
#include "meow_ui_internal.h"
|
||||
#include "meow_pinyin.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
/* 拼音键位(build_kb PINYIN:行 y=504/552/600/648,GCOL=48,行左缘 x=2;键 44×36):
|
||||
* row1 y=504 "qwertyuiop";row2 y=552 "asdfghjkl"+[拼/英]@col9;
|
||||
* row3 y=600 "zxcvbnm"+[←退格]@col7;row4 y=648 [?123]+[空格]+[OK]。 */
|
||||
#define KEY_XY(col, y) (((2 + (col) * 48) + 22), ((y) + 18))
|
||||
static void t(char ch) {
|
||||
/* 按字符找其键中心坐标(行/列换算) */
|
||||
int row = 0, col = 0;
|
||||
const char *rows[3] = { "qwertyuiop", "asdfghjkl", "zxcvbnm" };
|
||||
for (int r = 0; r < 3; r++) {
|
||||
const char *p = strchr(rows[r], ch);
|
||||
if (p) { row = r; col = (int)(p - rows[r]); break; }
|
||||
}
|
||||
int x = 2 + col * 48 + 22;
|
||||
int y = 504 + row * 48 + 18;
|
||||
meow_ime_handle_tap(x, y);
|
||||
}
|
||||
|
||||
static char g_echo[128] = "";
|
||||
static void ime_cb(const char *t, void *ctx) { (void)ctx; snprintf(g_echo, sizeof g_echo, "%s", t); }
|
||||
static void tap(int x, int y) { meow_ime_handle_tap(x, y); }
|
||||
|
||||
static meow_ime_ctx g_c;
|
||||
static void open_py(void) {
|
||||
memset(&g_c, 0, sizeof g_c);
|
||||
g_c.mode = MEOW_IME_PINYIN; g_c.maxlen = 64; g_c.on_change = ime_cb;
|
||||
memset(g_echo, 0, sizeof g_echo);
|
||||
meow_ui_text_input_async(&g_c);
|
||||
assert(meow_ime_active() == 1);
|
||||
}
|
||||
static void close_py(void) { meow_ime_close(0); assert(meow_ime_active() == 0); }
|
||||
|
||||
int main(void) {
|
||||
setenv("MEOW_UI_DUMP", "/tmp/pinyin.ppm", 1);
|
||||
meow_ui_opts o = { 480, 720 };
|
||||
assert(meow_ui_init(&o) == 0);
|
||||
|
||||
/* ① 拼音组合 + 点上屏 */
|
||||
open_py();
|
||||
t('n'); t('i'); t('h'); t('a'); t('o');
|
||||
assert(strcmp(meow_ime_composition(), "nihao") == 0);
|
||||
assert(meow_ime_text()[0] == 0); /* 组合不上屏 */
|
||||
assert(g_echo[0] == 0); /* 未上屏不回调 */
|
||||
/* 点候选 0(你好,x=44 起;宿主 stub width=strlen*6) */
|
||||
tap(60, 480);
|
||||
assert(strcmp(meow_ime_text(), "你好") == 0);
|
||||
assert(strcmp(g_echo, "你好") == 0);
|
||||
assert(meow_ime_composition()[0] == 0); /* 组合已清 */
|
||||
close_py();
|
||||
printf("PASS pinyin: nihao -> 你好 (compose+commit+on_change)\n"); fflush(stdout);
|
||||
|
||||
/* ② 候选翻页(shi 候选 >6) */
|
||||
open_py();
|
||||
t('s'); t('h'); t('i');
|
||||
char all[32][64];
|
||||
int n = py_predict("shi", all, 32);
|
||||
assert(n > 6);
|
||||
assert(strcmp(all[0], "是") == 0);
|
||||
/* 点 ▶(下一页)→ 页内首候选应为 all[6](页 0 首候选是 all[0]) */
|
||||
tap(457, 480); /* ▶:页 0 → 页 1 */
|
||||
tap(60, 480); /* 点页 1 候选 0(x=44 起) */
|
||||
assert(strcmp(meow_ime_text(), all[6]) == 0);
|
||||
close_py();
|
||||
printf("PASS pagination: shi page_next then commit page1[0] == all[6]\n"); fflush(stdout);
|
||||
|
||||
/* ③ UTF-8 删字段:上屏"你好"后点退格 → "你" */
|
||||
open_py();
|
||||
t('n'); t('i'); t('h'); t('a'); t('o');
|
||||
tap(60, 480); /* 上屏"你好" */
|
||||
assert(strcmp(meow_ime_text(), "你好") == 0);
|
||||
tap(410, 618); /* ←退格(row3 col7 宽键中心) */
|
||||
assert(strcmp(meow_ime_text(), "你") == 0);
|
||||
assert(strcmp(g_echo, "你") == 0);
|
||||
close_py();
|
||||
printf("PASS utf8 field backspace: 你好 -> 你\n"); fflush(stdout);
|
||||
|
||||
/* ④ 中/英切换 */
|
||||
open_py();
|
||||
tap(456, 570); /* [拼/英] row2 col9 → ASCII */
|
||||
assert(meow_ime_active() == 1);
|
||||
/* 顶条「中」热区(430..474, KB_TOP..KB_TOP+42)→ 切回拼音;组合已被丢弃 */
|
||||
tap(452, 438);
|
||||
assert(meow_ime_active() == 1);
|
||||
t('n'); t('i');
|
||||
assert(strcmp(meow_ime_composition(), "ni") == 0);
|
||||
tap(456, 570); /* 又回 ASCII */
|
||||
assert(strcmp(meow_ime_composition(), "") == 0); /* 组合态已丢弃 */
|
||||
close_py();
|
||||
printf("PASS zh/en switch (pinyin->ascii->pinyin, combo dropped)\n"); fflush(stdout);
|
||||
|
||||
/* ⑤ 空格上屏首候选(ni → 你) */
|
||||
open_py();
|
||||
t('n'); t('i');
|
||||
tap(194, 666); /* 空格 */
|
||||
assert(strcmp(meow_ime_text(), "你") == 0);
|
||||
assert(strcmp(g_echo, "你") == 0);
|
||||
close_py();
|
||||
printf("PASS space commits first candidate: ni -> 你\n"); fflush(stdout);
|
||||
|
||||
printf("ALL PASS\n");
|
||||
meow_ui_shutdown();
|
||||
return 0;
|
||||
}
|
||||
Reference in new issue
Block a user