进阶专题

方案配置

方案文件(.schema.toml)的完整结构、词库文件(.dict.yaml)格式、排序配置、差异化覆盖与从零创建方案

v0.122.0

本页面向要自制或改造输入方案的用户,讲清楚三件事:方案文件里能写什么、词库文件的格式规范、以及排序相关的几个字段各自作用在哪一层。

日常使用不需要读本页——启用、排序、扩展词库开关、导入导出都在方案设置里点几下就行。

行为开关不写在方案文件里

上屏策略、调频、造词、模糊音、临时拼音等行为都是全局配置,集中在 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 / mixed

icon_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 里的 10 正常进编码,而空编码时按数字键仍是选词或输出数字。

码元会从原有功能手里抢走按键

编码输入期间,码元字符优先于选词键、翻页键、以词定字键和数字选词。把 ; 配成码元后,编码输入时按 ; 就是打码而非选第二个候选。

写进 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 会视 ' 是否已被占作选择键,在 ' 与反引号之间自动选一个;不确定实际是哪个键时,把它显式设成 quotebacktick

已知限制

  • 简码歧义无解 —— 同一串击键既可能是一个二简词、也可能是两个一简字,两者完全同形,打分无从区分。这类只能靠手动分隔符指定,是本路线的固有限制而非缺陷。
  • 顶码自动让位 —— 开启后 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,全局唯一
labelUI 显示名,留空回退 id
description设置工具开关下方的小字说明
path词库文件路径,相对 schemas\ 目录;用户数据目录下的同名文件优先于程序 data\
typerime_codetable / rime_pinyin / english(空 = 回退 rime_codetable
default是否为主词库;每个带词库的方案有且仅一个
default_enabled扩展词库的方案默认启用状态;省略视为未启用
enabled用户覆盖启用状态,由设置工具写入;未设时继承 default_enabled
base_order该库的层级基序档位,见排序配置
default_weight整库权重硬覆盖,见排序配置

启用判定优先级:enabled > default_enabled > 主词库始终启用

混输方案不写 dictionaries

混输是引用型方案,自己不拥有词库:方案文件里没有 [[dictionaries]] 段,词库全部来自 [engine.mixed]primary_schemasecondary_schema 指向的那两个方案。自制混输方案时不必(也不应)为它配主词库。详见混输方案配置

词库文件(.dict.yaml)

词库文件沿用 Rime 的 .dict.yaml 外形,但解析器是本输入法自己的,与 librime 并不等价。理解下面这几条能避免绝大多数「词库加载了却不生效」的问题。

YAML 头只有两个键被读取

除 columns / import_tables 外,头部所有键一律被忽略——包括 name

解析器逐行扫描头部,只认 columns:(全部词库类型)与 import_tables:(仅 type = "rime_pinyin" 的词库)。其余键既不报错也不告警,直接跳过。

这意味着 name: 写什么都不影响任何行为——词库的显示名来自方案文件的 [[dictionaries]].label,不是 YAML 头里的 name。同理 versionuse_preset_vocabularyvocabulary 等 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-z0-9 及少数符号),恰有一列像码才计一票。

  • 平票或零票 → 回退 text code weight
  • 无论投票结果如何,权重恒取第 3 列
  • 每次走启发式都会记 WARN,日志里带票数与建议写法

始终显式写 columns

纯 ASCII 词条(符号库里的 @、命令直通车的 $CC(...))会让投票判错,把词条当成编码列。列序是文件级属性、判定一次全文固定,一旦判反整个词库的编码与词条就是对调的。显式声明 columns 可以完全绕开这套启发式。

其他正文规则

  • # no comment 指令 —— 整行恰好等于它时,其后所有 # 开头的行按数据而非注释解析
  • 只剥行尾空白,保留行首 —— 因为全角空格 U+3000 属于 Unicode 空白,用常规 trim 会把「全角空格」这个词条本身削掉
  • 空 text 或空 code 的行被跳过
  • 权重解析失败记为 0 —— Rime 的 50% 相对权重语法未实现,会落到这里

排序配置四件套

base_sortbase_orderdefault_weightsort 名字相近但分属三个不同的文件层,作用点完全不同。这是方案定制里最容易混淆的一组:

名字写在哪作用
base_sort方案文件 [engine.codetable]选定全局排序维度
base_order方案文件 [[dictionaries]]词库层间档位
default_weight方案文件 [[dictionaries]]整库权重硬覆盖
sort词库 .dict.yaml 头部死键,只触发告警

base_sort —— 选定排序维度

只对码表引擎生效,写在拼音方案里无效。

取值比较链
weight(默认,留空同)权重降序 → base_order 升序 → 库内出现序 → …
naturalbase_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枚举followfollow / 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_mappings0.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.layoutcandidate.text_orientation两根独立的轴

谁说了算回答的问题
layout(横 / 竖)用户——全局设置、临时模式、方案都能改候选成一行还是一列
text_orientation方案这套文字本身怎么写

蒙古文这类纵向书写的文字用 rotated:整项顺时针转 90°,而候选摆位仍走横排那一套—— 所以横排的注释模板、窗口宽度下限这些配置照常生效,不必为它再配一遍。 upright 则是「字不转、逐字往下走」,像中文对联。

因为是两根轴,切换候选排列不会丢掉方案的声明:在蒙古文方案里把候选切成竖排、 再切回横排,旋转还在。

竖排时不生效

layoutverticaltext_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 一个字段 —— pathlabelbase_orderdefault_weight 等永远以方案文件为准,覆盖层改不了

第二条是刻意的:它保证用户层的词库开关不会把整份词库定义冻结成快照,否则方案升级后新增或改路径的词库都会失效。

从零创建自定义方案

  1. 准备方案文件 —— 建议先在方案页导出一个内置方案作模板,在其基础上修改;方案 ID 必须与文件名前缀一致
  2. 放置文件 —— 方案文件存入 %APPDATA%\WindInput\schemas\;引用的词库文件(.dict.yaml)放在用户数据目录 schemas\ 下,或复用 data\ 下的内置词库路径
  3. 登记方案 —— 在 config.tomlschema.available 中加入方案 ID
  4. 生效 —— 重启输入法或切换方案;扩展词库开关等热重载项除外

相关阅读

对这篇文档有疑问,或发现内容有误?

欢迎到文档仓库提 issue,写明问题时附上本页链接即可。

去提 issue →

本页目录