fanlusky
|
9f5572c525
|
fix(build): 所有 MSVC 目标显式按 UTF-8 编译源文件
#548 修了 ngram,同类问题还有几处:源文件或头文件是无 BOM 的 UTF-8,
目标却没有 /utf-8,在代码页 936 的系统上注释会吞掉换行。
- ui:Controls.h 让 msimeui 与各 demo 单独构建失败,/utf-8 设为 PUBLIC
- server/tests/portable:input_key_policy.h 让 MSVC 构建失败
- engine test_windows_ipc_contract、tests/pipe-probe、windows/tests:C4819
- windows DLL:此前只靠 fmt 的 INTERFACE 选项带来 /utf-8,改为显式设置,
否则 L"“" 等宽字符标点会在去掉 fmt 后静默变成乱码
|
2026-09-30 15:37:13 +08:00 |
|
Lu Fan(SonnyCalcr)
|
68742373e3
|
Merge pull request #548 from ouchihao/codex/fix-436-ngram-utf8
fix(engine): compile ngram sources as UTF-8 on MSVC
|
2026-09-30 15:36:12 +08:00 |
|
fanlusky
|
375e1bcd48
|
feat(engine): 新增候选框翻页箭头消息 candidatePage
候选页点击翻页箭头时发出 candidatePage,数据限定为 previous / next。
同步重新生成 TypeScript / C++ 绑定与 ui-html/webview2/shared 副本,并补充契约用例。
|
2026-09-30 12:42:14 +08:00 |
|
Ouchihao
|
9b867175d7
|
fix(engine): compile ngram sources as UTF-8 on MSVC
|
2026-09-30 03:02:12 +08:00 |
|
fanlusky
|
42fbb9541c
|
feat(engine): 快捷短语混入全拼 / 双拼候选并参与调频
Shift+K 快捷短语模式保留,仍按编码前缀查询(query_quick_phrases)。另外全拼 / 双拼下
编码精确匹配(query_quick_phrases_by_code)的快捷短语作为一组插在固定位置候选之后,由
LocalModeOptions::quick_phrase_candidates 单独开关;五笔不混。
用户日志新增 quick_phrase_slots 表记录快捷短语组前的普通候选数:选中短语让组前移,
越过组选普通候选让组后移,后移上限为页长减一。quick_phrase_frequency 关掉时组固定在
首位。与普通候选同文本时保留快捷短语那份。
|
2026-09-29 14:31:51 +08:00 |
|
fanlusky
|
c9b86e0026
|
feat(engine): 支持用户自定义双拼方案
用户在数据目录 shuangpin\custom\ 下放 TOML 文件,在设置页以 custom/<文件名>
选用。零声母规则从 o、a、first_letter、full_pinyin 四种里选,声母和韵母
映射由文件指定,可用 [zero_initials] 覆盖个别零声母音节。
- 引擎:新增 CustomShuangpinLayout 与 BuildCustomShuangpinProfile,校验缺键、
声母撞键,并对全部音节做往返解码,冲突时给出可读的错误信息;新增运行时
方案注册表,按需加载。
- Server:扫描并解析自定义方案,配置快照带上方案列表与目录;文件缺失或无效
时回退到小鹤。
- 设置页:仿照自定义辅助码,新增打开目录和刷新按钮;无效方案列出但禁用,
悬停时显示错误。
- 安装器:覆盖安装与迁移数据目录时保留 shuangpin 目录。
- 文档:docs/custom-shuangpin.example.toml 提供带详细注释的示例。
|
2026-09-29 11:33:23 +08:00 |
|
fanlusky
|
f56551c34b
|
feat(engine): 内置搜狗、紫光、智能ABC、国标和拼音加加双拼方案
新增五套双拼方案表,零声母规则:
- 搜狗、紫光、智能ABC:o + 韵母所在键
- 国标:a + 韵母所在键
- 拼音加加:韵母第一个字母 + 韵母所在键
搜狗和紫光与微软一样把 ing 放在分号上。分号作韵母键原先按方案名写死为
microsoft,现改为 ShuangpinProfileUsesSemicolonFinal 按方案表判断,
引擎、Server 按键处理和下发给 TSF 的开关一并生效。
智能ABC 键位图把 ve 也标在 V 上,但这样 lv/nv 会同时解成 lü 与 lüe,
这里按标准智能ABC 把 ve 放在 M(与 ue 同键)。
Server 配置校验改为按方案解析结果判断;设置页下拉框、配置模板注释和
README 同步更新;新增各方案键位、零声母、分号及全方案逐音节往返测试。
|
2026-09-29 03:52:19 +08:00 |
|
fanlusky
|
738435b002
|
fix(engine): 全拼长句不再为更短的前缀补 Google 整句
前缀查不到词时 query_single_path 会补一条 Google 整句,长句候选后面于是缀上一串越来越短的〔Unigram〕子串。整句联想只对完整输入出一句,前缀只取词库里的词,查不到就交给更短的前缀。
|
2026-09-29 02:22:57 +08:00 |
|
fanlusky
|
d0feee74cc
|
fix(engine): 修正五笔混输的候选方案标记、通配排序与固定位置去重
- 首字母展开与固定位置补入的拼音候选不经过 query(),此前保留默认 Quanpin,
双拼会话里调频/删除会落到全拼引擎;现在按查询方案打标。
- 混输与 z 通配同时开启时,含 z 的编码拼音候选排在通配结果之前,避免通配
整页码行把 zi/zu 这类拼写的正解挤到后几页。
- 固定位置分区合并时,拼音分区 include_missing 补回的词若五笔分区已列出则去掉,
保持同词只留五笔一份。
|
2026-09-29 00:12:46 +08:00 |
|
Jia Sui
|
e9c824266f
|
test(engine): 恢复被拒第五键不改候选的断言
|
2026-09-28 18:31:18 +08:00 |
|
Jia Sui
|
a9920cb40f
|
perf(engine): 五笔设置未变化时不再重建候选
|
2026-09-28 18:29:50 +08:00 |
|
Jia Sui
|
a50232f06c
|
fix(engine): set_wubi_mixed_pinyin 不再复位 z 通配开关
|
2026-09-28 18:28:42 +08:00 |
|
Jia Sui
|
456fdb819c
|
feat(engine,server,ui-html,installer): 五笔拼音混输改为同时混排并拆出独立开关
Signed-off-by: Jia Sui <jsfaint@gmail.com>
|
2026-09-28 17:55:36 +08:00 |
|
fanlusky
|
69ee4fb49b
|
test(engine): 新增逐键耗时基准 bench_input_session
在真实词库上逐字母输入几串典型拼音(单词、短语、整句),每串前清空候选缓存,
按整句联想的几档设置统计每个键在引擎里的耗时(中位数 / p90 / 最大)。只构建、
不注册 ctest,也不选词、不写用户日志;用 METASEQUOIA_IME_DATA_DIR 指向数据目录
的副本运行。
本机一次结果(ms/键,冷缓存,5 轮):
设置 中位数 p90 最大
全关 0.10 0.19 1.04
词格 0.39 2.12 3.97
词格+Google 0.34 1.93 4.43
全开(含两档神经) 0.44 2.72 5.61
引擎查询本身不是打字卡顿的来源,性能工作应放在绘制、IPC 与 UI 线程等待上。
|
2026-09-27 17:02:04 +08:00 |
|
fanlusky
|
2c3546f823
|
perf(engine): 简拼、快捷短语、表情、颜文字查询复用词库连接
这四种模式每个键都新开一次 SQLite 连接,第一次 prepare 还要解析整个 schema
——msime.db 有两百多张分表。新增 local_modes/local_database,四个查询统一经它
打开只读连接:路径正是当前数据目录下的 msime.db 或 others.db 时共享一条连接,
其余路径(测试、工具)照旧每次独立打开、用完即关。
只共享这两个随安装包发布的库:msime.db 本来就被引擎整个会话持有,others.db 只在
Server 停止时由安装程序替换;保持其它文件常开会让删除它们的工具或测试在 Windows
上失败。close_default_user_database() 同时释放这些连接,调用方原本就用它在删除
或替换数据目录前放开文件。
引擎测试(本地单独构建,CI 不跑)23/23 通过;不加释放钩子时 input_session、
mixed_expressive_input_session、jianpin_input_session 会因目录删不掉而失败。
|
2026-09-27 16:10:01 +08:00 |
|
fanlusky
|
8f2c81dd0f
|
perf(server,engine): 选词学习的写库挪出按键线程
权重调整(AdjustCandidateRanking)和输入过的英文词(LearnEnteredEnglishWord)
原本和按键排在同一个 worker 队列里:每次选非首位候选都要在下一个键之前付一次
用户日志的提交和 fsync,触发阈值时还有 msime.db 的一次提交。磁盘忙或杀软扫描
时,这就是肉眼可见的卡顿。
- server/src/utils/serial_task_runner:单线程、按提交顺序执行、低优先级,Stop()
先执行完队列再退出,选词不会在退出时丢失。附单元测试。
- 两类写入改为投递给这个执行器。它们只调用 user_dictionary,不碰输入会话;唯一
的会话副作用——权重变化后清引擎候选缓存——经 EnqueueResetInputSessionCacheTask
回到 worker。删除对应的 TaskType 和 Task 字段。main 在 worker join 之后调用
ShutdownDictionaryWriter()。
- user_dictionary:默认日志连接改为每线程一条。FULLMUTEX 只保证单次调用安全,
保证不了事务:连接只有一个事务状态,写线程的 BEGIN IMMEDIATE..COMMIT 会把
worker 的读卷进来,worker 侧 UserDatabase 析构时还会把它回滚。
close_default_user_database() 递增代号,各线程下次访问时关闭旧连接。
- WorkerThread 取任务改为 move,不再每次复制整个 Task。
行为变化:选词后如果写入还没完成就立刻再打同一串,会短暂看到旧顺序;写完后
worker 清缓存,下一次查询即是新顺序。此前的“下一个键之前一定写完”换成了不阻塞
按键。
|
2026-09-27 16:09:51 +08:00 |
|
fanlusky
|
1e372c9c48
|
fix(engine): 读词库的连接等写锁而不是直接失败
msime.db 的三条读连接(全拼词典、双拼词典、quanpin_query 的 SqliteDb)都没设
busy timeout。设置页或学习写入提交的那几毫秒里,落在这段时间的查询直接拿到
SQLITE_BUSY,这一页候选就是空的。统一设 250 ms(与 english.db 读连接一致):
写锁只占一次提交,这点等待足够;大批量导入时最多卡一下,而不是出空页。
这也是把学习写入挪出按键线程的前提:之后读写会真正并发。
|
2026-09-27 16:09:28 +08:00 |
|
fanlusky
|
fc6f6469f7
|
perf(engine): 上屏不再清空候选缓存,按键不再重复重建混合候选
- set_rescoring_context:每次选词都会换上文并清空 cache_、series_cache_ 和
segmentation_cache_,下一个词的前几键因此都是冷查询。上文只经神经重排
进入候选,没有生效的神经模型时与缓存无关,此时不清;之后打开神经重排
会经 set_sentence_association 清缓存。全拼、双拼同改。
- set_quanpin_autocorrect_types:Server 每键重新应用配置,值没变也会调用
update_mixed_candidates 复制整份候选列表。值不变时直接返回;构造时已把
初值同步给引擎。
|
2026-09-27 15:03:17 +08:00 |
|
fanlusky
|
57dd0fc2f3
|
fix(engine,server): 整句来源标签只挂在整句联想候选上
候选窗按 CandidateSource 挂〔Trigram〕/〔Unigram〕,但 Generated/Fallback 同时被
原样上屏兜底、英文模式原文、日期、Unicode、假名、译文义项等合成候选借用,导致
输入 E 等特殊模式前缀时原样候选被误标为〔Unigram〕。
WordItem 新增 sentence_association 标记,只由 Google 解码器整句(全拼、双拼)与
kenlm 词格整句置位;Server 挂标签时同时要求来源与标记。source 本身不变,落库与
学习策略不受影响。
|
2026-09-27 08:25:51 +08:00 |
|
Lu Fan(SonnyCalcr)
|
4375d80414
|
feat: 支持导入自定义辅助码,内置“加加”更名为“拼音加加” (#477)
* feat(engine): 支持 helpcodes/custom 下的自定义辅助码
custom 目录里的每个 .txt 都是一套方案,方案名为 custom/<文件名>。
文件开头的 "# name:" / "# name_en:" 注释给出中英文显示名,缺省用文件名;
兼容 BOM、CRLF 和全角冒号。方案名不能跳出 custom 目录。
* feat(engine): WebView 契约新增 openHelpcodeDirectory
设置页请求打开自定义辅助码目录,仅允许 settings 页发送。同步 ui-html/webview2/shared。
* feat(server): 设置页列出自定义辅助码并可打开其目录
配置快照带上 helpcode.custom_schemas 与 helpcode.custom_directory,每次都会重新扫描;
方案文件被删除或改名后回退到 lantian。两个设置宿主都会处理 openHelpcodeDirectory。
* feat(ui-html): 辅助码设置显示拼音加加与自定义方案
内置方案“加加”改名为“拼音加加”。自定义方案追加在内置方案之后;新增说明区,
提供“打开目录”和“刷新方案”两个按钮,刷新完成后弹出提示。
* feat(installer): 升级与迁移数据目录时保留自定义辅助码
升级清理时只清掉 helpcodes 里的内置表,保留 custom 子目录;更换数据目录时一并迁移;
安装时建出 helpcodes\custom。
|
2026-09-26 20:21:55 +08:00 |
|
fanlusky
|
b3b3b3303c
|
feat(windows): 焦点切换到另一个输入框时提示当前中英文状态
新增开关 general.caret_state_indicator_on_focus(默认关闭,需同时开启光标
状态提示)。
- DLL 把以下情况视为“换了输入框”:焦点窗口变化(Win32 编辑框、对话框、
其他应用各有自己的窗口);焦点经过一段没有可编辑文档的间隙后落到可
编辑文档上(Chromium、WPF 等单窗口宿主在字段之间就是先失焦再聚焦);
焦点会话真正结束后重新开始。Chromium 打字时在两个可编辑文档之间直接
替换文档管理器,不会触发。从 Win+. 面板返回不计入;线程焦点在真正的
应用切换后返回计入。一次切换的多次回调由定时器合并为一次提示;组字
过程中、以及没有光标的控件都保持静默。每次判断在 TSF 诊断日志里记录
判定标志,不含任何文本
- 协议复用 IMESwitch:wch 改为 FanyImeCaretStateTrigger(UserToggle /
CapsLockEdge / FocusEntered),CapsLockEdge 保持首发时的 VK_CAPITAL
取值,Server 对未知值按 UserToggle 处理
- Server 在开关打开时显示当前的有效模式(Caps Lock 开启时为“英”);
配置项同步写入两份模板和两个设置窗口宿主的读写映射
- 设置页在光标状态提示卡片中增加“切换输入框时提示”开关
|
2026-09-26 17:09:34 +08:00 |
|
fanlusky
|
597d087580
|
fix(server): 光标状态提示仅由用户快捷键触发并收紧协议边界
- DLL 只在 Shift/Ctrl 切换、Shift+Space、Ctrl+.、Caps Lock 与
Ctrl+Shift+F 处显式请求提示;Server 下发的模式同步、宿主转换模式
同步和激活初始化不再弹出提示,移除 compartment 回调里的推断逻辑
- 恢复文档切换时候选窗的 OnKillThreadFocus,改用 COM 身份比较
- 能力位改名为 CaretStateIndicator,DLL 仅在 Server 确认后发送切换
事件;Server 端这些事件只驱动提示,不再改写工具栏或状态快照
- 标点提示的中英模式由 DLL 随 PuncSwitch 携带
- UILess 宿主不显示提示,会话转为 UILess 时隐藏已显示的提示
- Ctrl+Shift+F 的锚点就地读取,不再覆盖 Global::Point,且只采信
协商了该能力的客户端
- 撤回对所有包默认 point 的修改;提示窗口创建失败不再阻断 Server
启动;提示内容改为结构化 CaretStateBadge
- Caps Lock 在同一按键重复进入 TestKeyDown 时只处理一次
|
2026-09-26 13:58:22 +08:00 |
|
fanlusky
|
dc7cfa0354
|
Merge branch 'develop' into feat/issue-229-ime-status-indicator
|
2026-09-26 13:58:03 +08:00 |
|
fanlusky
|
e7f7addd4f
|
feat(engine): 神经网络整句联想与词格 n-best 重排
- 新增 engine/neural:移植 chinese-ime-lm 的字符级 Transformer 推理,在词格解出的最多 12 条
n-best 里重排挑选整句,desktop / keyboard 两档模型各出一条首选,后台 worker 异步打分
- 词格支持 n-best 输出与重排(quanpin/lattice_rerank),全拼、双拼共用
- 新增 SentenceAssociationOptions,经 QueryRequest 传给各 provider;四个来源默认全关
- 资源契约登记两个 safetensors 与 NOTICE;模型二进制不进仓库,由
scripts/fetch-neural-model.ps1 按 neural-model/lock.json 下载并校验 SHA256
- 新增 neural_sentence 测试
|
2026-09-24 14:03:39 +08:00 |
|
Jia Sui
|
5b0be4e71d
|
Merge branch 'develop' into feat/caret-driven-resegmentation
|
2026-09-24 08:45:54 +08:00 |
|
Jia Sui
|
54c41d34b2
|
fix(engine): reset_cache 连带失效 caret 前缀候选缓存
|
2026-09-23 21:32:59 +08:00 |
|
fanlusky
|
7b7b19f449
|
fix(wubi): 前缀提示不挡混合拼音、候选去重,修复顶字/自动上屏后快打丢字母
- 只有精确码行才算五笔表已回答,前缀提示不再阻止混合拼音回退;拼音无结果时保留提示
- 五笔前缀查询按词去重,保留精确码行
- HideCandidate 抑制改为推送成功记账、Hide 消费(带 1s 时限),不再被下一个按键撤销;
四码唯一自动上屏路径同样记账
|
2026-09-23 15:41:04 +08:00 |
|
AaGMix
|
a855a9c7f4
|
feat(windows): 发送光标状态切换事件
|
2026-09-22 21:20:07 +08:00 |
|
Jia Sui
|
1cfba58eba
|
feat(engine): 光标驱动的拼音前缀解码与候选重算
caret 从纯显示状态升级为查询管线输入:set_caret 量化到最后一个完整
音节单元边界(只消费 segment_raw_boundaries,#187 契约),前缀候选
独立解码、preedit 保持全串拼音风格;纯移动光标同样重算候选。
IInputScheme::set_raw_input 提升为接口方法以支持不动现场组合的
独立前缀查询。runtime_isolation 两处按 R3/R4 新语义改写(caret 在
音节中间 floor 到空前缀、候选为空是预期状态);新增 caret 前缀
会话单测(engine/tests + server CI 目标,隔离词库夹具,覆盖
全拼 floor、双拼贪心配对、五笔无单元模型、boundary=0 空候选)。
|
2026-09-22 14:56:22 +08:00 |
|
Jia Sui
|
c6632e8d85
|
feat(engine): 五笔前缀逐键提示与调频接线
- 码表查询从精确匹配改为前缀匹配:精确等长行优先(保住一级/二级简码),
前缀行按权重降序跟随,LIMIT 50 截断(引擎层不读 server 配置的分层边界)
- WubiCandidateProvider 注入 RuntimePaths:接通 update_weight / delete_by_key
到 user_dictionary journal;新增 bump_wubi_weight(同码组 MAX+1、主库更新
与 journal upsert 同事务,行缺失不造行)
- create_word / cache_dynamic_candidate 补「为何 no-op」注释(后续任务范畴)
- 两个 toml 的 wubi_schema 注释与实现对齐:当前仅支持 wubi86
- server 测试:前缀语义、LIMIT 截断、上界构造、调频+journal 回放、删词墓碑
|
2026-09-22 09:23:25 +08:00 |
|
Jia Sui
|
536d0a95ef
|
feat(windows): 五笔四码后继续输入不丢字(顶字)
四码(不论是否唯一)之后继续敲字母时,先上屏该码的首选候选,再把这个字母
保留为下一次组合的开头。根因是两侧对「组合里有几个字母」认知不一致:TSF 的
本地按键缓冲跟着敲键涨(raw 预编辑样式下 preedit 就是它),服务端的五笔 raw
被引擎裁在四码;空格提交时组合文本被整段替换成候选并清掉本地缓冲,多敲的
字母随之丢失。
- 新增 worker 消息 CommitCandidateAndContinue(27),payload "<consumed>\t<text>":
TSF 按服务端给出的消费数裁**自己**的组合缓冲,而不是套用服务端按旧视图算好
的剩余串——快打时用户已多敲的字母因此不会被覆盖
- TSF 处理序列全部复用既有原语:_InsertTextToComposition + _HandleCompleteCommitFirst
真提交,_StartComposition + AddVirtualKey + _HandleCompositionInputWorker(NO_REQUEST_ID)
重建余下字母的组合;无组合时退化为直写
- 服务端顶字不看自动上屏开关:开关只决定唯一码要不要多敲一键才上屏,
不决定丢不丢输入;自动上屏那条路也改用同一消息,顺带收掉快打竞态
- 引擎新增 wubi_four_code_is_complete(完整四码、码表作答、不要求唯一;
空码不算——没有候选可提交时不触发顶字)
已知限制:光标在组合中间时的改码行为维持现状;空码继续敲字母仍会被忽略。
|
2026-09-22 09:23:25 +08:00 |
|
Jia Sui
|
5d1a9a6cc2
|
feat(server): 五笔四码唯一自动上屏
五笔敲满四码且码表只答一个候选时不再需要空格:第四个字母落下即上屏,下一个
字母直接开新组合。行为无条件生效,不设配置开关:业界默认开启(微软五笔、
搜狗五笔、极点、Rime 主流五笔方案),唯一候选没有第二选择,确认空格是纯冗余;
而一条开关要牵动配置五处同步,换不来可形成预期的行为差异,不值。
- engine 只报告事实(wubi_unique_four_code:完整四码、码表作答、候选恰好一个),
是否上屏由 Server 决定;判定收在 input_key_policy.h 的纯函数里,随 portable
目标进 ASan/UBSan;组词(creating_word)激活时组合保持打开,唯一四码不会把
正在拼的词截断上屏
- 提交复用 ProcessSelectionKey,与空格上屏同一套记账;但只能走 worker 管道推送
CommitCandidate:字母键在默认 raw 预编辑样式下不读请求-回复管道,回一帧 Normal
既不会上屏,还会在 TSF 侧留下永不释放的回复帧,而 Server 已按 Normal 清掉组合
- 上屏前按当前组合同步重建候选页:候选页异步发布,提交路径读的 ui.items /
page_words 否则可能还停在第三码那一拍
- 非唯一四码不做顶字上屏:一个按键只能回一条管道消息,真顶字需要扩 IPC 协议
|
2026-09-22 09:23:24 +08:00 |
|
fanlusky
|
837af70b7e
|
fix(engine): 全拼云查询带上手动分词而非去边界的裸串
手动把 qi'e'huan 分成三段,云端却返回二段的「切换」。因为全拼云查询的 query_text
取自 normalized_input(已去掉撇号的裸串),云端拿不到音节边界只能自行贪心断句。改用
保留手动撇号的 normalized_segmentation 构造 query_text,与双拼分支一致;也让
to_google_spelling 能逐音节把 nve/lve 换成云端认的 nue/lue 写法。
|
2026-09-22 01:13:11 +08:00 |
|
fanlusky
|
99a8a355c0
|
fix(engine): 云/AI 联想候选上屏后按手动分词落库
选中云或 AI 联想候选上屏后,再次输入同样的拼音却不出现该词。根因有二:
- create_word_from_canonical_pinyin 已按 canonical 键里的撇号校验过分段,却又调用
do_validate 二次校验;do_validate 会先去掉撇号、再用贪心 correction 重新断句,把
qi'e'huan 切成 qie'huan(音节数 3→2),与字数不符而静默拒绝入库。移除这次多余且
有害的二次校验,分段以调用方给定的 canonical 键为准(do_validate 本身保持不变,
造词/调频/删除三条旧路径不受影响)。
- 上屏时 AI/云候选自身不带 canonical_pinyin,落库用的是去掉音节边界的
committed_pinyin,同样会被重新贪心断句。改用会话里带撇号的 normalized_segmentation
作 canonical 键,经 create_word_from_canonical_pinyin 落库。
|
2026-09-22 01:13:11 +08:00 |
|
Jia Sui
|
566ff8b832
|
feat(engine): 新增加加辅助码(拼音加加),第六套辅助码方案
按笔顺拆前两个部件、各取读音首字母(妈 = 女 n + 马 m = nm),部件用加加俗称读音(亻=d、
扌=t、纟=j、忄=s、攵=f、夂=z、刂=l、彳=s);138 个独体/部首字取「本字声母 + 起笔」。码表
7968 条,覆盖《通用规范汉字表》7846 字,比小鹤少 422 个扩展区生僻字——缺码会让含这些字的
词组拿不到辅助码,是已知取舍。
编码对齐拼音加加 5.x 安装包内的 fzm.bin(双拼键位已换算为声母):6487 字取到两码,6349 字
逐字一致,138 字保留本表规则,覆盖外的 800 字按同一规则重建。来源与非官方性质写在 NOTICE.md
与随包的 THIRD_PARTY_NOTICES.txt。
- engine/contracts/assets 注册 helpcode_jiajia,assets.h 重新生成(5 → 6)
- 设置页两个下拉显示名「加加」,两份配置模板注释同步
- 两侧测试补支持列表;README / README.en.md / server/AGENTS.md 改「六套」
默认值不变(双拼 lantian、全拼 ziranma)。
|
2026-09-20 22:00:34 +08:00 |
|
fanlusky
|
94df9a7917
|
fix(stats): 修复统计功能审查发现的 8 个问题
- Server 退出时唤醒统计管道监听线程,避免从未有客户端连接时 join 永久阻塞
- DLL 发送批次时对 ERROR_FILE_NOT_FOUND 重试,覆盖服务端重建管道的窗口
- 新增 StatisticsEnabledChanged(26) 推送开关,DLL 侧在采集入口直接短路:
关闭时不读 range、不分类、不开管道
- stats_meta 的 schema_version 写入正确的键名(此前键与值都是 "1")
- dropped_count 仅在实际发送的批次中消费,空批次不再吞掉丢弃计数
- _CaptureCompositionStats 改为遍历 composition range 的克隆,避免移动宿主的活动区间
- FanyImeStatsEvent 显式声明 reserved 尾部,不再把未初始化的填充字节写入管道
- 透传统计去重标记在抑制一次后即消费,避免同一 tick 内的连击被漏计
|
2026-09-20 20:34:50 +08:00 |
|
Jia Sui
|
ffcd1aee28
|
feat: 输入统计(DLL 采集、Server 聚合存储与设置页展示)
- windows: 三上屏出口 + OnTestKeyDown 直通字符采集,修复半角数字恒零
- engine: 统计 Web 消息契约(statsRequest/statsResponse)
- server: 统计管道接收、聚合、SQLite 存储、保留策略与每日自动清理
- ui-html: 设置页「统计」模块(卡片、热图、明细、开关、清理)
- docs: PRIVACY / README 改为内置可选统计
|
2026-09-20 19:08:16 +08:00 |
|
fanlusky
|
1ea01d5e0a
|
fix(quanpin): 备选切分保护位只拉首页外的候选,不覆盖调频名次
保护位原来对任何排在 index 1 之后的备选切分都生效,于是调频刚把 吉安 排到
自然第 5 位,它就因为成了 ji'an 组里权重最高的词、过了 1/100 门槛而被重新
钉回第 2 位。用户选一次就跳到第二,之后再怎么调也只能停在第二——固定槽位把
调频写进权重的结果整个覆盖掉了。
改成只对自然排序已经掉出首页(默认 page_size 6)的备选切分生效。西安 在出货
词库里的自然位置是 16,仍旧提升到第 2 位;调频过的 吉安 留在它自己挣来的位置
上,之后按 promote 一步步往上走。
夹具同步补候选:engine 与 server 的 xian 夹具原来只有三条主候选,备选切分自然
就在首页内,测不到提升这条路径。
|
2026-09-19 22:42:29 +08:00 |
|
fanlusky
|
e32eeadec9
|
fix(engine): 调频比较集跨键合并,按权重而非显示顺序取基准
打 jian 时列表里混着另一种切分 ji'an 的词。吉安 在出货词库里权重是 1,压在同组的
积案(9420)/几案(5999) 底下,而 adjust_candidate_ranking 按音节数圈比较集,于是
吉安 只跟 ji'an 这一组比,可学权重封顶一万出头,永远追不上 见 的 3460998——用户
选多少次,这个候选都纹丝不动。
音节数这个尺度是 #400 加的,为的是挡住另一个 bug:显示列表里备选切分词会被保护位
顶到最前面,中点数学却假定列表按权重降序,于是拿 西鄂(w=6) 当基准把 写 写成 506。
根子在「显示顺序 != 权重顺序」,按音节数滤掉跨表行只是绕开了症状,代价是把每个候选
关进自己的组里。
改成在比较集上直接按权重降序排一次,不变式在源头恢复:任何行都不可能坐在高于自身
权重的位置上充当基准,西鄂 那条路被堵死;同时比较集不再按音节数切开,吉安 的基准
取到整个列表最重的 见,置顶一次即越过,promote 模式连选五次一路走到首位。写入仍只
落在 entry_key 的行上,#36 的护栏不变。
test_user_dictionary_journal 新增两条回归(跨键置顶、连续 promote 收敛到首位),
#400 的两条断言原样保留并仍然通过。
|
2026-09-19 22:14:57 +08:00 |
|
fanlusky
|
01c5bca325
|
fix(engine): 选中的整句候选落成用户词组
词格(CandidateSource::Generated)和 Google 解码器(CandidateSource::Fallback)
猜出来的整句在词库里没有对应的行,而调频走的是
update_weight_by_pinyin_and_word——它只改 SQLite 里已经存在的行,找不到行就什么
也不做。于是用户选中这种整句多少次,下次输入同样的拼音,它仍然是猜出来的,仍然
排在词库里那条同音短语后面,看起来就是"永远提不上来"。
选中即落库才是对的处理:存成用户词组之后,下次它以 UserDatabase 候选出现,按
quanpin::generated_sentence_insert_position 的约定排在两条整句之前,之后再选还能
走正常调频。
落库不受 frequency_adjustment_ 约束(那是候选词频策略,不是造词),也不跳过
index == 0——首位整句同样没有落库,下次仍要靠猜。长度上限对标
quanpin::WordLatticeOptions::max_phrase_syllables,再长的整句只是这一次输入的
产物,落库除了撑大用户词库没有别的作用。
|
2026-09-19 13:48:17 +08:00 |
|
fanlusky
|
b4728fdb3b
|
test(engine): 九键删词只要求词库那一行消失
test_nine_key_session 的删词断言从词格整句合并(#430)之后就是红的:删掉
tbl_2_n 里的「你好」之后,重开 session 仍能看到「你好」,但它的 source 是
Generated——整句合成用还活着的单字「你」和「好」拼出来的,同一批候选里还有
「米好」。tbl_2_n 已经空了,删词本身没问题。
删词的契约是词库里那一行没了,不是这几个字从此打不出来(真要那样,删过一次
词就再也输入不了这个词)。断言相应收窄成 Database/UserDatabase 来源的候选。
|
2026-09-19 12:29:09 +08:00 |
|
fanlusky
|
ccbaa3a631
|
fix(engine): 送进 Google 解码器前把 ü 换成 nue/lue/ju 写法
小鹤双拼 ntdddswu 出的是「女蛾黛动物」而不是「虐待动物」:nt 转成全拼后
是 nve(shuangpin_pinyin_set 把 nue 抹掉了,词库与词格那一侧统一用 v 形),
而本地 googlepinyinime-rev 的拼写表和 inputtools 云输入都不认 nve/lve/jv,
只有 nue/lue/ju/jue,也不做 v→ü 的转写。带分隔符的串照样送过去了,解码器
却把 nve 重新切成 nv + e,于是有了「女蛾」。
加一个 quanpin::to_google_spelling,按音节整体改写 nve→nue、lve→lue、
jv→ju 这一类拼写,只在两个 Google 解码器的边界上用:云输入的 query_text、
双拼与全拼的整句回退。词库查询和词格用的仍然是 canonical_syllable 那一侧的
v 形写法,没有动。nv'er、lv'se 这些 Google 也认的写法原样通过。
|
2026-09-19 12:29:01 +08:00 |
|
fanlusky
|
e2a5f5f988
|
fix(engine): 词格整句只用精确读音,并补上多音字读音先验
长句联想此前会把读音对不上的词拿去造句,也分不清多音字的常见读音与生僻读音。
词格的跨度查询改用批量精确键查询。原先走的 query_segments_keyed_flat 带降级:
精确键查不到就退到前缀区间扫描(key >= "gun'qi" AND key < …),gun'qi 因此捞出
gun'qiu 的「滚球」,简拼那两级同理。联想出来的每个词,读音都必须精确对上用户
敲的那段拼音。顺带省掉了白扫的前缀区间,也不再需要 QuerySource——区分全拼与
双拼的只有简拼那几级。
新增读音先验:每一行按「自己的权重 / 该拼音跨度的权重和」算读音占比,占比低于
免罚线的部分按 log10 扣分。语言模型只看汉字,分不出「卷」读 gun、「而」读 neng
这种词库里权重为 0 的多音字读音,于是 gun'qi 出「卷七」、neng'fa'sheng 出
「而发生」。不能整体按 log10 P(词|拼音) 扣,那等于把字频算两遍(语言模型已经
算过一次),「跑得很快」会被「跑的很快」压掉——得/地 各占 de 的 7%~9%,本来就是
常见读音;真正的生僻读音占比是 1e-5 量级,离免罚线还差好几个数量级。
ü 的两种拼法归一化到词库存的那一种。intact_pinyin_list() 两种都认,词库只存
一种(j/q/x/y 后写 u,l/n 后写 v),切出来的 jv、lue 这类音节因此一行都查不到。
改精确键查询之后这会让整张词格断在那里——wo'men'lue'de 解不出任何路径,长句
联想整个消失。lue 和 lve 本来就是同一个读音的两种拼写,归一化之后仍是精确匹配。
新增两条回归用例:生僻读音不得赢下词格;421 个合法音节每个都必须在词库里至少
查得到一行,切分器与词库哪边漂了都先在这里炸。
|
2026-09-19 10:08:39 +08:00 |
|
fanlusky
|
03a5b4fe26
|
feat(engine): 整句候选把词格排到 Google 解码器之前
词格换成 kenlm 三元模型打分之后,它出的整句整体比 Google 解码器那条准,
所以由它占首位。
merge_lattice_candidates 的插入点本来就在 Fallback 之前,word_lattice.h
里也是这么写的不变量;真正把次序翻过来的是词典层在合并之后的一个后置
步骤——它把 Fallback 重新提回表头。全拼和双拼各有一份,这次都删掉。
这一步此前没有任何测试盯着:test_pinyin 里的用例断的是
merge_lattice_candidates 自身,词典层怎么再排它看不见。补一个查询层的
回归用例,断相对位置而不是具体句子——词格出什么取决于 msime.db 和
sc.lm,钉死了会随词库更新而碎;两条来源凑不齐时按既有风格优雅跳过。
顺带修掉 ScopedLocalAppDataOverride 上一条已经过期的注释:dict_pinyin.dat
现在随安装包发布了,不发布的只有 role=user 的 user_dict.dat。
|
2026-09-19 10:08:39 +08:00 |
|
fanlusky
|
80b1fc42a1
|
feat(engine): 词格整句改用 kenlm 三元模型打分
词格原先的整句打分是一份没校准过的启发式 unigram,质量很差。这里内嵌 libime
在用的 kenlm 查询子集,改由它的三元模型 sc.lm 来打路径分。
- engine/ngram 只编 kenlm 的 query / trie-build 路径。不定义 WITH_THREADS,
parallel_read.cc 因此退化成串行实现,整个子集零 Boost 依赖。
KENLM_MAX_ORDER=3 必须与建模阶数一致,改它等于读不懂已发布的模型文件。
- ngram::LanguageModel 是唯一 include kenlm 头文件的地方,对外只给出一个纯
std 的头,_HAS_AUTO_PTR_ETC 和 kenlm 的 include 目录都保持 PRIVATE。
- shared_language_model 按资源路径共享一份 mmap。kenlm 的查询是只读的且把
上下文放在调用方的 State 里,所以并发会话不需要额外加锁。
- 模型缺失时 valid() 为假,词格退回原来的启发式打分:整句候选只是变差,不会
停止工作。测试覆盖了缺模型降级与按路径共享。
- 出货的 ARPA 不带 <s>/</s>,所以解码从 null_state() 起算而非 begin_state()。
kenlm 是上游副本,不重排版、不进 clang-format,其 LGPL-2.1+ 与 BSD 例外清单
已补进 THIRD_PARTY_NOTICES.txt。googlepinyinime 那条 Fallback 整句路径不变。
|
2026-09-19 10:08:39 +08:00 |
|
Lu Fan(SonnyCalcr)
|
e1d53dd8f0
|
Merge pull request #426 from ouchihao/codex/fix-299-double-helpcode-cache
fix(engine): isolate ordered double-helpcode query caches
|
2026-09-18 21:34:50 +08:00 |
|
Ouchihao
|
0925937bfe
|
fix(engine): isolate ordered double-helpcode query caches
|
2026-09-18 20:43:17 +08:00 |
|
Ouchihao
|
5e641fb5a0
|
fix(engine): accept yo as a complete shuangpin syllable
|
2026-09-18 20:35:14 +08:00 |
|
Lu Fan(SonnyCalcr)
|
4dea1cd12f
|
Merge pull request #420 from metasequoiaime/feat/ctrl-arrows-segment-caret
feat(input): 组词内按分词的光标与删除(#35 / #187 / #347)
|
2026-09-18 12:35:52 +08:00 |
|
Jia Sui
|
2576986881
|
feat(windows): Ctrl+左右键按分词移动光标
组词中 Ctrl+Left/Right 按一个字的拼音(音节段)移动光标,
与 Ctrl+Backspace 的删除粒度共用同一套引擎分段边界。
- 闸门归纳为 SegmentEditFunction(code, modifiers):Ctrl-only + 组词存在,
VK_BACK/LEFT/RIGHT 分别映射到 segment 函数;三处判据与延迟投影共用
- 新增 FUNCTION_MOVE_LEFT_SEGMENT / FUNCTION_MOVE_RIGHT_SEGMENT,
编辑会话只按 CompositionRestored 的 caret 移动本地光标,不重建 buffer
- Server 用 segment_raw_boundaries() 取前/后边界,能力位与非 UiLess 时回包;
非拼音/本地模式/UiLess/旧端仍按单字符 ±1 回退
Refs #187
|
2026-09-17 23:36:34 +08:00 |
|