方案配置
方案文件(.schema.toml)的完整结构、词库文件(.dict.yaml)格式、排序配置、差异化覆盖与从零创建方案
本页面向要自制或改造输入方案的用户,讲清楚三件事:方案文件里能写什么、词库文件的格式规范、以及排序相关的几个字段各自作用在哪一层。
日常使用不需要读本页——启用、排序、扩展词库开关、导入导出都在方案设置里点几下就行。
行为开关不写在方案文件里
上屏策略、调频、造词、模糊音、临时拼音等行为都是全局配置,集中在 config.toml 的 [schema.codetable] / [schema.pinyin] / [schema.mix] / [schema.english]。方案文件只写引擎的固定参数。见核心概念。
方案文件的位置与命名
方案文件为 TOML 格式,位于 %APPDATA%\WindInput\schemas\,命名为 <方案ID>.schema.toml。方案 ID 必须与文件名前缀一致。
内置方案对应文件(在安装目录的 data\schemas\ 下):
| 文件 | 方案 |
|---|---|
pinyin.schema.toml | 全拼 |
shuangpin.schema.toml | 双拼 |
wubi86.schema.toml | 五笔 86 |
wubi86_pinyin.schema.toml | 五笔拼音混输 |
在用户目录放一个同名文件即整份替换内置那份,见同结构覆盖机制。
最小结构
[schema]
id = "my_schema" # 方案 ID,须与文件名前缀一致
name = "我的方案"
icon_label = "我" # 模式指示 / 状态气泡的图标短称(可选)
version = "1.0"
author = "作者"
description = "方案说明"
[engine]
type = "codetable" # 引擎类型:pinyin / codetable / mixedicon_label 画在 16px 的任务栏图标里,宽度上限是一个汉字:一个汉字(我)或两个
拉丁字符(En)能完整显示,写两个汉字只会取首字。想让任务栏显示哪个字,就把它写在最前面。
引擎类型
三种引擎各有一段固定参数:
# 拼音引擎(全拼 / 双拼)
[engine.pinyin]
scheme = "full" # full(全拼)/ shuangpin(双拼)
[engine.pinyin.shuangpin]
layout = "xiaohe" # xiaohe / ziranma / mspy / sogou / abc / ziguang
# 码表引擎(五笔等)
[engine.codetable]
max_code_length = 4 # 最大码长(0 = 回退 4)
base_sort = "weight" # 基础排序维度,见下文「排序配置」
input_chars = "" # 码元字符集(空 = a-z),见下
leading_chars = "" # 可作第一码的字符(空 = 同 input_chars)
sentence_input = false # 整句输入(实验性),见下
split_input = false # 逆切分(切分模式),见下
# 混合引擎(码表优先、拼音兜底)
[engine.mixed]
primary_schema = "wubi86" # 主方案(码表)
secondary_schema = "pinyin" # 辅助方案(拼音)码元字符集 0.114 新增
默认只有 26 个字母算「输入码」,按别的键就走标点、选词或直接上屏。方案的编码里若含别的字符,用 input_chars 声明:
[engine.codetable]
input_chars = "a-y" # 五笔码元集:z 不进编码
input_chars = "a-y/" # 再加一个 /,供 /test 这类词条
input_chars = "a-z0-9" # 字母加数字,词库里有 Win10 这类词条时需要写法是范围 + 字面的组合,大小写不敏感;- 写在首位或末位时作字面字符(a-z-)。不在集内的字符按下时会终结当前编码:先上屏当前候选,再输出该字符本身。
数字通常要配 leading_chars。数字键在空编码时是选词键,直接让它作码元会把这个用法整个占掉:
[engine.codetable]
input_chars = "a-z0-9"
leading_chars = "a-z" # 数字能作码元,但不能起头这样 win10 里的 1、0 正常进编码,而空编码时按数字键仍是选词或输出数字。
码元会从原有功能手里抢走按键
编码输入期间,码元字符优先于选词键、翻页键、以词定字键和数字选词。把 ; 配成码元后,编码输入时按 ; 就是打码而非选第二个候选。
写进 leading_chars 的字符连空编码时也归码表,以它作引导键的功能(快捷输入、临时拼音/英文、特殊模式)便进不去了。想两者共存,把它排除出 leading_chars——它就只在编码输入途中作码元。有冲突时启动日志会逐条告警并给出改法。
字符集写错(如 z-a 逆序、含空格)不会让方案失灵,会回落默认 a-z 并记录告警。
整句输入(实验性) 0.119 新增
实验性功能,仅供研究,不建议日常使用
默认关闭,且只能在方案文件里手动开启,设置界面不提供入口。简码歧义下的切分仍会出错(见下文「已知限制」),配置项与行为在后续版本可能变更或移除。
开启后,码表方案可以像拼音那样连续输入:超过码长的一长串编码会被自动切分成若干编码单元并组成句子,不必逐词上屏。
手动开启
推荐走差异化覆盖,只写这一项,方案文件的后续更新仍能透传。在 %APPDATA%\WindInput\schema_overrides\ 下新建或编辑 <方案ID>.toml:
# 例:五笔 86 → schema_overrides\wubi86.toml
[engine.codetable]
sentence_input = true也可以直接写进方案文件自己的 [engine.codetable] 段。改完重启输入法生效。
为什么没有全局开关
一张码表能不能整句,取决于它的编码结构——是否定长、简码体系有多深。这是方案属性而非用户偏好,所以它只在方案文件里声明,没有全局基线可回落。
怎么用
- 只在超过
max_code_length时触发,码长以内的输入行为分毫不变。 - 组合区会显示切分结果(如
aawt'aawt),据此能看出引擎把编码断在了哪里。 - 切分不对时用手动分隔符划定边界,如
q'j强制断成两个单元。分隔符键沿用拼音分隔符的设置:出厂auto会视'是否已被占作选择键,在'与反引号之间自动选一个;不确定实际是哪个键时,把它显式设成quote或backtick。
已知限制
- 简码歧义无解 —— 同一串击键既可能是一个二简词、也可能是两个一简字,两者完全同形,打分无从区分。这类只能靠手动分隔符指定,是本路线的固有限制而非缺陷。
- 顶码自动让位 —— 开启后
top_code_commit不再生效。两者抢的是同一个区间(超码长),而顶码是自动上屏,一触发用户就看不到整句候选了。 - 混输方案下不生效 —— 混输超过码长时走拼音兜底,不经码表主引擎。即便在混输方案里写了
sentence_input = true也不会触发,启动日志会为此告警。 - 组句质量依赖拼音词库 —— 词频借自拼音词库(
data\schemas\pinyin\)。词库缺失不会让功能失效,但组句准确度会明显下降。 - 开启的方案会额外常驻一份简码索引与词频表,首次使用前在后台构建,不占打字。
逆切分(切分模式) 0.122 新增
效果高度依赖码表结构,开之前请先看「适合哪些码表」
默认关闭,且只能在方案文件里手动开启,设置界面不提供入口。它在音形类码表上是实打实的提速,在纯字形码表(如五笔)上多半只是噪声——原因见下文。
编码一条候选都出不来时(空码),切出一个二简当前段、剩下的归后段,各查一次词典,再把结果拼成候选:
hfkn → hf(很) + kn(可能) → 很可能 ← 打满四码
sma → sm(什么) + a(啊) → 什么啊 ← 只打了三码,且再打下去也没有编码了原本要六键才能打出的两个二简字词,现在四键就成——这是论坛用户 flypy 提出的思路。
手动开启
推荐走差异化覆盖,只写这一项,方案文件的后续更新仍能透传。在 %APPDATA%\WindInput\schema_overrides\ 下新建或编辑 <方案ID>.toml:
# 例:某音形方案 → schema_overrides\<方案ID>.toml
[engine.codetable]
split_input = true也可以直接写进方案文件自己的 [engine.codetable] 段。改完重启输入法生效。
怎么用
- 只在一条候选都没有时触发。有候选的编码分毫不受影响,这是它不会打扰日常输入的根据。
- 编码没打满也能切,但要求再往下打也没有任何编码了(词库里没有以它开头的更长编码)——这时你已经打不下去了,这串就是到此为止。还能继续打的时候不切,免得替你提前下结论。
- 切出来的某一段若只查到符号(二简位没字可编时,词库有时会把符号编在那里),那一段按空码处理:整条组合不出现,编码该怎么清屏就怎么清屏。
- 组合区会显示切分位置(如
hf'kn),据此能看出引擎把编码断在了哪里。 - 前段取首选、后段逐条列出:后段没有重码时只有一条候选,配合满码自动上屏可以四码直接上屏;后段有重码时列成候选,继续打下一个字母则顶出首选。
- 想让前段也列举(一次看到更多组合),加
split_front_candidates = 2。 - 上屏过的组合只记词频,不会存进用户词库 —— 下次打同一串编码仍然走切分,结果一样。 (好处是选错一次也不会被永久固化成一条词条。)
适合哪些码表
同一套机制在不同码表上的价值相差极大,差别不在「触发得多不多」,而在二简位上放的是词还是字:
| 五笔 86 | 某音形方案 | |
|---|---|---|
| 四码空码(能触发的比例) | 81.4% | 87.2% |
| 其中两段都查得到 | 96.6% | 93.7% |
| 后段无重码(可四码上屏) | 93.4% | 86.1% |
| 前段是词而非单字 | 0% | 54.5% |
前三行几乎一样,光看它们会以为两者一样合适。真正的差别是最后一行:
- 音形类把二简位的富余留给了词(声韵组合占不满 26×26 的空间),切出来是「安保+排」「本来+这次」这样以词起头的组合;
- 五笔类的二简位是一二级简码、全是单字,切出来必然是「节+就」「菜+药」这类两个不相干的字。
⇒ 音形方案值得一试;纯字形码表开了之后,八成的四码空码都会冒出一条读不通的候选。
已知限制
- 单字输入模式下别开 —— 单字输入只出单字,而逆切分的产物必是多字,会被整条滤掉:屏幕上一条候选都没有,编码却还留在那里不会自动清空。两个功能语义相冲,同开没有意义。
- 五笔类码表上会让顶码顶出拼凑结果 —— 开启后,打错编码再继续打字时,
top_code_commit顶上屏的就是那条拼凑出来的候选(以前是什么都不发生)。音形方案下这正是想要的效果,字形码表下则是副作用。 - 与整句同开时,「继续打字母顶首选」失效 —— 整句输入会让
top_code_commit整体让位。两个功能本身互不冲突(一个管码长内、一个管超码长),只是顶码这条交互会被整句收走,启动日志会告警。 - 混输方案下不生效 —— 混输(码表 + 拼音)里切分候选会排到拼音正解前面占住首位,因此这一版在混输方案上整体关闭;写了
split_input = true也会被忽略,启动日志会告警。要用它请在纯码表方案上开。 - 切出来的组合是否读得通,取决于码表把哪些字词放在了二简位上,引擎不做语义判断(符号除外,见上)。
- 需要
max_code_length大于 2(前段恒取一个二简、后段至少 1 码)。不满足时开了也不生效,启动日志会说明原因。
词库配置
码表、拼音、英文方案用 dictionaries 数组列出自己的所有词库,分两类:主词库仅 1 个(default = true,始终启用),扩展词库任意多个(可被用户独立开关)。
[[dictionaries]]
id = "wubi86_main"
label = "极点五笔主词库"
path = "wubi86/wubi86_jidian.dict.yaml"
type = "rime_codetable"
default = true
[[dictionaries]]
id = "wubi86_emoji"
label = "Emoji 表情"
path = "wubi86/wubi86_jidian_emoji.dict.yaml"
type = "rime_codetable"
default_enabled = true # 方案默认启用
[[dictionaries]]
id = "wubi86_district"
label = "行政区域"
path = "wubi86/wubi86_jidian_district.dict.yaml"
type = "rime_codetable"
base_order = 1 # 排在主库(0)之后
default_weight = 500 # 该库无权重列,整库定档 500| 字段 | 说明 |
|---|---|
id | 词库 ID,全局唯一 |
label | UI 显示名,留空回退 id |
description | 设置工具开关下方的小字说明 |
path | 词库文件路径,相对 schemas\ 目录;用户数据目录下的同名文件优先于程序 data\ |
type | rime_codetable / rime_pinyin / english(空 = 回退 rime_codetable) |
default | 是否为主词库;每个带词库的方案有且仅一个 |
default_enabled | 扩展词库的方案默认启用状态;省略视为未启用 |
enabled | 用户覆盖启用状态,由设置工具写入;未设时继承 default_enabled |
base_order | 该库的层级基序档位,见排序配置 |
default_weight | 整库权重硬覆盖,见排序配置 |
启用判定优先级:enabled > default_enabled > 主词库始终启用。
混输方案不写 dictionaries
混输是引用型方案,自己不拥有词库:方案文件里没有 [[dictionaries]] 段,词库全部来自 [engine.mixed] 里 primary_schema 与 secondary_schema 指向的那两个方案。自制混输方案时不必(也不应)为它配主词库。详见混输方案配置。
词库文件(.dict.yaml)
词库文件沿用 Rime 的 .dict.yaml 外形,但解析器是本输入法自己的,与 librime 并不等价。理解下面这几条能避免绝大多数「词库加载了却不生效」的问题。
YAML 头只有两个键被读取
除 columns / import_tables 外,头部所有键一律被忽略——包括 name
解析器逐行扫描头部,只认 columns:(全部词库类型)与 import_tables:(仅 type = "rime_pinyin" 的词库)。其余键既不报错也不告警,直接跳过。
这意味着 name: 写什么都不影响任何行为——词库的显示名来自方案文件的 [[dictionaries]].label,不是 YAML 头里的 name。同理 version、use_preset_vocabulary、vocabulary 等 Rime 键在这里全是装饰。
sort: 是个特例:它会被读取,但只用来打一条日志告警,不影响排序。要控制排序请用下文的排序配置四件套。
---
name: my_dict # 被忽略(显示名取方案文件的 label)
version: "1.0" # 被忽略
sort: by_weight # 读取,但只触发一条 WARN 日志,不生效
columns: # ← 真正生效的键
- text
- code
- weight
...
你好 nihao 1000分隔行:... 必需,--- 可选
正文的起点是首个恰好等于 ... 的行。--- 只是头部里的一行普通内容,写不写都行。
缺少 `...` 会让整个词库静默变成零条目
找不到 ... 时解析器按零条目处理,只在日志里留一条 WARN。词库看起来「加载成功」但一个候选都没有——这是最常见的自制词库失效原因。
行尾只有 \r 的文件也会落进这一条:整份文件被当成一行,自然不存在「恰好等于 ... 的行」,症状一模一样(实测 0 条、只留一条 WARN)。这一条只针对 .dict.yaml:它按原样解析,必须是 LF 或 CRLF。词库导入、辅助码表与常用字表都会在入口统一行尾,不受影响。从旧 Mac 工具或某些转换脚本拿到的 .dict.yaml 值得先确认一下行尾。
columns 支持的列名
columns 只认三个名字,两种 YAML 写法(块序列 - text 与流式 [text, code, weight])都支持:
| 列名 | 必需性 | 缺失后果 |
|---|---|---|
text | 必需 | 整个词库被跳过并记 ERROR |
code | 必需 | 整个词库被跳过并记 ERROR |
weight | 可选 | 全库权重按 0 处理 |
其他列名(如 Rime 的 stem)语法合法但不取用,只作占位——占位会顺延其后各列的下标,所以必须写全,不能省略中间列。
不写 columns 会走启发式猜测
省略 columns: 时,解析器会采样正文(最多 200 行 / 攒够 32 票)投票判断列序:逐列检查是否「像编码」(全部字符属于 a-z、0-9 及少数符号),恰有一列像码才计一票。
- 平票或零票 → 回退
textcodeweight - 无论投票结果如何,权重恒取第 3 列
- 每次走启发式都会记 WARN,日志里带票数与建议写法
始终显式写 columns
纯 ASCII 词条(符号库里的 @、命令直通车的 $CC(...))会让投票判错,把词条当成编码列。列序是文件级属性、判定一次全文固定,一旦判反整个词库的编码与词条就是对调的。显式声明 columns 可以完全绕开这套启发式。
其他正文规则
# no comment指令 —— 整行恰好等于它时,其后所有#开头的行按数据而非注释解析- 只剥行尾空白,保留行首 —— 因为全角空格 U+3000 属于 Unicode 空白,用常规 trim 会把「全角空格」这个词条本身削掉
- 空 text 或空 code 的行被跳过
- 权重解析失败记为 0 —— Rime 的
50%相对权重语法未实现,会落到这里
排序配置四件套
base_sort、base_order、default_weight、sort 名字相近但分属三个不同的文件层,作用点完全不同。这是方案定制里最容易混淆的一组:
| 名字 | 写在哪 | 作用 |
|---|---|---|
base_sort | 方案文件 [engine.codetable] | 选定全局排序维度 |
base_order | 方案文件 [[dictionaries]] | 词库层间档位 |
default_weight | 方案文件 [[dictionaries]] | 整库权重硬覆盖 |
sort | 词库 .dict.yaml 头部 | 死键,只触发告警 |
base_sort —— 选定排序维度
只对码表引擎生效,写在拼音方案里无效。
| 取值 | 比较链 |
|---|---|
weight(默认,留空同) | 权重降序 → base_order 升序 → 库内出现序 → … |
natural | base_order 升序 → 库内出现序 → …(权重完全不参与) |
natural 即「字根序 / 文件原序」,适合按编码规则天然有序的码表。
不接受 Rime 的 by_weight / original 拼法
这两个 librime 写法被明确列为非法值而非别名。填入任何未知取值都会回退到 weight 并记一条告警——刻意不做兼容,是为了避免两套排序词汇被误当等价。
base_order —— 词库之间的硬分档
小整数档位,排序时作为独立层级参与,位置在权重之后、库内出现序之前。
它存在的理由是:库内出现序是每个词库各自从 0 起的局部序号。没有 base_order 时跨库直接比较,会让小词库靠前的词条反超主词库深处的词条。给扩展库配 base_order = 1 就能让它整体排在主库(0)之后。
系统词库建议取 >= 0
用户词、临时词等非系统层有默认的负档位(逻辑层 -4、用户层 -3 等)。系统词库若配负值会与这些层交错,产生难以预料的顺序。
default_weight —— 整库权重硬覆盖
设置后无条件替换该词库每一条词条的权重,词库自身的权重信息完全丢弃。
用途是没有权重列的扩展库:不设时全库 weight = 0,在权重模式下会整体沉底。给行政区域库配 default_weight = 500 就能让它落在设计者选定的档位。
有真实权重的库绝不要配
Emoji 库靠 200/199/198… 递减权重表达展示顺序,抹平就毁了它的排列;扩展词库带真实词频,抹平会丢掉词频信息。
另外注意两个相互作用:整库同权会让库内自动退化为文件原序;而 base_sort = "natural" 时权重根本不参与比较,此时配 default_weight 完全没有意义。
优先级串联
base_sort 选定比较器
├─ weight → 权重降序 → base_order 升序 → 库内出现序 → …
└─ natural → base_order 升序 → 库内出现序 → …(权重不参与)
其中权重的值 = default_weight(若配置)或词库原始权重
└─ 覆盖发生在更早的取数层,不是排序层词组编码器
码表方案通常需要编码器为自动造出来的词组生成编码。规则写在方案文件的 [encoder] 段:
[encoder]
max_word_length = 10
[[encoder.rules]]
length_equal = 2 # 二字词
formula = "AaAbBaBb" # 第一字前两码 + 第二字前两码
[[encoder.rules]]
length_equal = 3 # 三字词
formula = "AaBaCaCb"
[[encoder.rules]]
length_in_range = [4, 10] # 四字及以上
formula = "AaBaCaZa"公式语法:A / B / C / Z = 第 1、2、3、末个字;a / b = 该字的第 1、2 个编码(如 Aa = 第 1 字第 1 码)。
拆字配置
形码方案可挂拆字库,在候选悬停提示与候选注释里显示构字信息。整段配置写在 [engine.chaizi] 下,路径相对 schemas\:
[engine.chaizi]
db_path = "wubi86/wubi86_chaizi.txt" # 拆字库(字\t字根\t编码)
font_path = "wubi86/HeiTiZiGen.ttf" # 字根字体 TTF(用自带字根字体时必填)
font_family = "黑体字根" # 该 TTF 内部自报的家族名(同上,两项成对填写)| 键 | 必填 | 说明 |
|---|---|---|
db_path | 是 | 拆字库文件,制表符分隔的三列:字\t字根\t编码 |
font_path | 用自带字根字体时必填 | 字根字体 TTF,路径相对 schemas\。由输入法直接加载,不必安装到系统 |
font_family | 同上,与 font_path 成对填写 | 该 TTF 内部自报的家族名。填错或留空,字根就显示为方框 |
只有字根全部用普通汉字表示的拆字库才可以两项都不填——那种字根正文字体本来就画得出来。只要拆字库里出现了私用区(PUA)码位的专用字根,这两项就都是必填的:字形只存在于那个 TTF 里,系统字体无从取字。
两项的分工:
font_path—— 字体文件本身,路径相对schemas\,须随方案一起装进 schemas 目录。输入法把它读进一个私有字体集来渲染字根,因此不需要安装到系统;它同时决定方案包里带不带这个字体:导出时把该 TTF 一并打进方案包,导入时随方案落地。这一项为空,整条字根字体通路就不启动,此时font_family填了也没有任何作用font_family—— 在上面那个字体文件内部指定用哪个家族。填的是字体自报的家族名(TTF name 表里的名字,双击字体文件在预览窗口中可见),不是文件名、不是路径,也不必是它在系统字体列表里的显示名。留空不等于「自动」:留空时按内置默认名黑体字根去找,字体不叫这个名字就一样匹配不上
家族名对不上,字根静默变方框
字体文件在、路径也对,但 font_family 与该 TTF 自报的家族名不一致时,不会报错——私用区字根取不到字形,直接显示成方框或空白。这是这一段最常见的配错形态,且现象与「字体文件根本没找到」一模一样。
所以填之前先确认字体自报的名字:双击 TTF 打开预览窗口,标题处显示的就是家族名。留意全角 / 半角、空格与大小写差异。
macOS 侧不看 font_family
macOS 直接用字体文件的字节建描述符作级联回退,用不到家族名,font_path 指对就能显示。因此同一份方案在 macOS 上正常、Windows 上是方框,基本可以断定是 font_family 写错了。
overlay 段 0.115 新增
[overlay] 声明「本方案可以被引导键临时叠加进入」——按引导键进去打一段,选完候选自动退回原方案。快符、生僻字表这类小码表就靠它,用法见引导键特殊模式。
段存在即声明,没有总开关:方案有这一段就是特殊方案,没有就只能作常驻方案切换使用。
[overlay]
show_all_on_enter = false # 进入模式即展示候选
candidate_layout = "follow" # 本模式期间的候选窗布局
comment_template_vertical = "" # 本模式期间的候选注释模板(竖排)
comment_template_horizontal = "" # 同上(横排)| 键 | 类型 | 默认 | 说明 |
|---|---|---|---|
show_all_on_enter | 布尔 | false | 刚进入、尚未敲码时就铺开本方案码表的首页候选。面向小符号表;大码表要遍历整表取首页,有开销 |
candidate_layout | 枚举 | follow | follow / vertical / horizontal。进入本模式期间覆盖全局,退出自动恢复 |
comment_template_vertical / _horizontal | 字符串 | 不写=跟随全局 | 本模式期间的候选注释模板。三态:不写=跟随全局,写模板=改用它,写空串=不显示 |
这一段装的不是「这张码表是什么」(那是 [engine.codetable]),而是「这张码表被叠加使用时怎么表现」——三个字段的语义都依赖「进入 / 退出」这条生命周期。
引导键不写在这里
[overlay] 里没有 trigger_keys / hotkey。引导键与直达热键统一住在 config.toml 的 [keys.key_actions](写作 special:<方案id>)与方案文件的 [key_actions] 两张表里。在这里再开一个入口就成了第三个真相源。
[overlay] 与 [schema].hidden 是正交的两件事:hidden 管「列不列进方案切换列表」,[overlay] 管「能不能被引导键叠加进入」。特殊模式通常两个都写,但并非必须——只写 [overlay] 的方案照样能被引导键进入,只是它同时也留在方案列表里。
本段也可以写进 schema_overrides\<方案ID>.toml,设置工具的「特殊模式」一节改的就是那里。
方案级行为 0.119 新增
三段可选配置,声明「切到本方案时,标点、候选呈现(排列、文字排列、字体与注释)、短语加载各是什么状态」。三段都不写才是常态——不写即「跟随全局」,与本功能出现之前的行为完全一致。
设置工具位置:方案 → 选中一个方案 → 方案自定义 → 本方案行为(enabled 之外的两个短语字段仅配置文件)。
注释模板那两项在界面上是**「自定义」勾选框 + 输入框**:不勾 = 跟随全局,勾上填模板 = 本方案改用它,勾上留空 = 本方案不显示注释。这三态与配置文件里的「不写 / 写模板 / 写空串」一一对应。
[punct]
mode = "follow" # follow(默认,跟随全局)/ chinese / english
# 本方案专用的标点映射表(不写这一段 = 跟随全局)。列序与全局那份一致:
# [中文半角, 英文全角, 中文全角, 英文半角];引号用 "1 / "2('1 / '2)区分左右形。
# [punct.custom_mappings]
# "." = ["。", ".", "。", "."]
# "," = [",", ",", ",", ","]
[candidate]
layout = "follow" # follow(默认,跟随全局)/ vertical / horizontal
text_orientation = "normal" # 横排时文字怎么排:normal / rotated / upright
# font_family = "Noto Sans Mongolian" # 只改候选文字的字体(不写 = 跟随全局)
# 本方案的候选注释模板(不写这两个键 = 跟随全局;写空串 "" = 本方案不显示注释)
# comment_template_vertical = "${code_hint}"
# comment_template_horizontal = ""
[phrases]
enabled = true # 本方案是否加载短语
categories = [] # 只加载这些分类(空 = 不限制)
exclude_categories = [] # 排除这些分类(空 = 不限制)| 段 · 键 | 类型 | 可选值 | 默认 | 说明 |
|---|---|---|---|---|
punct.mode | 枚举 | follow / chinese / english | "follow" | 切到本方案时的标点态。follow = 不干预 |
punct.custom_mappings | 表 0.119 新增 | — | 不写 | 本方案专用的自定义标点映射。不写 = 跟随全局,写了则整份替换全局那张表,写空表 {} = 本方案一条自定义标点都不要。详见整份替换,不是逐行合并 |
candidate.layout | 枚举 | follow / vertical / horizontal | "follow" | 本方案期间的候选窗排列方向。语义同模式级候选布局,但生效范围是「整个方案期间」而非「进入 / 退出一个临时模式」 |
candidate.text_orientation | 枚举 0.120 新增 | normal / rotated / upright | "normal" | 横排时文字怎么排:normal 照常水平、rotated 整项顺时针转 90°、upright 逐字直立下行(对联式)。竖排时不生效,详见横排时文字排列 |
candidate.font_family | 字符串 0.120 新增 | — | 不写 | 本方案候选文字的字体;不写 = 用全局字体。只作用于候选词本身,序号、编码栏、注释不跟着换 |
candidate.comment_template_vertical | 字符串 0.119 新增 | — | 不写 | 本方案竖排候选的注释模板。不写 = 跟随全局,写空串 "" = 本方案不显示注释 |
candidate.comment_template_horizontal | 字符串 0.119 新增 | — | 不写 | 本方案横排候选的注释模板。两个方向各自独立,只配一个、另一个跟随全局是常见用法 |
phrases.enabled | 布尔 | — | true | 本方案是否加载短语。关掉后不出短语候选,短语也不再占用码位 |
phrases.categories | 字符串数组 | — | [] | 只加载列出的分类。空数组 = 不施加这项限制(全部加载) |
phrases.exclude_categories | 字符串数组 | — | [] | 在上一项的结果里再排除这些分类。空数组 = 不排除 |
内置英文方案三段全写了:英文标点、竖排、不加载短语——它正是这三项能力的来由。
「跟随全局」不是「保持现状」
follow 的含义是回到不受任何方案影响的那个值,不是「沿用上一个方案留下的值」。
举例:五笔(follow)下你用的是中文标点 → 切到英文方案(mode = "english")变英文标点 → 切回五笔会变回中文标点。若你在五笔下本就把标点设成了英文,那么这一趟往返之后仍是英文——还原的是你自己的偏好,不是硬编码的中文。
候选排列同理。
方案期间手动改,仍然算数
方案声明的是默认值,不是锁。在英文方案期间按 toggle_punct(中/英标点切换)改成中文标点,它在本次停留期间一直有效,不会被方案意图顶回去;切走再切回来,重新按方案声明落地。
横排时文字排列 0.120 新增
candidate.layout 与 candidate.text_orientation 是两根独立的轴:
| 轴 | 谁说了算 | 回答的问题 |
|---|---|---|
layout(横 / 竖) | 用户——全局设置、临时模式、方案都能改 | 候选摆成一行还是一列 |
text_orientation | 方案 | 这套文字本身怎么写 |
蒙古文这类纵向书写的文字用 rotated:整项顺时针转 90°,而候选摆位仍走横排那一套——
所以横排的注释模板、窗口宽度下限这些配置照常生效,不必为它再配一遍。
upright 则是「字不转、逐字往下走」,像中文对联。
因为是两根轴,切换候选排列不会丢掉方案的声明:在蒙古文方案里把候选切成竖排、 再切回横排,旋转还在。
竖排时不生效
layout 为 vertical 时 text_orientation 不起作用——已经竖着排的候选再转 90°,就又成了横排。
自定义标点:整份替换,不是逐行合并 0.119 新增
punct.custom_mappings 一旦写了,全局 input.punct.custom_mappings 就整份不参与——包括全局的 custom_enabled 总开关也一并被换掉。
这有两条容易踩的推论:
- **全局总开关关着,声明了本段的方案照样出自定义符号。**那个开关管的是全局那张表。
- 本段里没写的行,走的是内置默认转换(
.→。这些),不是全局表里的值。想保留全局的某几行,得把它们抄到本段里。
三态与注释模板同构,由「这个键在不在」区分:
| 写法 | 含义 |
|---|---|
不写 [punct.custom_mappings] | 跟随全局(含全局的总开关) |
| 写了并列出若干行 | 本方案只认这几行,其余走内置默认 |
写了但一行都没有(custom_mappings = {}) | 本方案一条自定义标点都不要 |
`schema_overrides` 里这一段也是整份替换
其它段写进 schema_overrides\<方案ID>.toml 时是逐键合并(方案文件写了 A、你写了 B,结果两者都在)。custom_mappings 是例外:你那份整个盖掉方案作者那份。
这是为了让「删掉方案作者写的某一行」成为可能——逐键合并里没有「删除」的写法,删掉的行会从方案文件里再冒出来。设置工具改这一节时也是整表回写的。
哪些源字符可配、四列分别对应什么状态,与全局那份完全一致,见自定义标点映射。
短语分类
categories / exclude_categories 面向短语分类功能。分类界面尚未开放时,所有存量短语的分类都是空串——因此:
- 写
categories = ["工作"]会把未分类短语一并滤掉(它们不在白名单里) - 要同时保留未分类的,显式列出空串:
categories = ["", "工作"]
两个字段都是「空数组 = 不施加这项限制」,不是「一条都不要」——「一条都不要」由 enabled = false 表达。
三段都能写进 schema_overrides
[punct] / [candidate] / [phrases] 既可写在方案文件里(作方案作者给的默认),也可写在 schema_overrides\<方案ID>.toml(作你自己的覆盖)。设置工具改的是后者。
差异化覆盖(schema_overrides)
全局引擎配置是所有同类方案的基线;当某个方案需要与全局值不同的行为时,用 schema_overrides\<方案ID>.toml 只覆盖个别项,未覆盖项跟随全局值。设置工具的扩展词库开关、双拼布局、方案级码表配置都写入这个文件。它不会被安装包升级覆盖。
与「整份替换方案文件」的区别
schema_overrides\ 是逐项深合并,只表达差异;而在用户数据目录 schemas\ 下放一个与内置方案同名的 .schema.toml 是整份替换——内置那份完全不参与。两条路都不会被升级覆盖,但前者能让方案文件的后续更新继续透传。
覆盖采用深合并,但有两条例外:
- 数组整体替换 —— 如
encoder.rules写了就是整份替换,不会逐条合并 [[dictionaries]]按 id 稀疏合并,且只接受enabled一个字段 ——path、label、base_order、default_weight等永远以方案文件为准,覆盖层改不了
第二条是刻意的:它保证用户层的词库开关不会把整份词库定义冻结成快照,否则方案升级后新增或改路径的词库都会失效。
从零创建自定义方案
- 准备方案文件 —— 建议先在方案页导出一个内置方案作模板,在其基础上修改;方案 ID 必须与文件名前缀一致
- 放置文件 —— 方案文件存入
%APPDATA%\WindInput\schemas\;引用的词库文件(.dict.yaml)放在用户数据目录schemas\下,或复用data\下的内置词库路径 - 登记方案 —— 在
config.toml的schema.available中加入方案 ID - 生效 —— 重启输入法或切换方案;扩展词库开关等热重载项除外
相关阅读
对这篇文档有疑问,或发现内容有误?
欢迎到文档仓库提 issue,写明问题时附上本页链接即可。