进阶专题

命令直通车

让短语与词库条目在选中时执行动作——打开网址、启动程序、模拟按键、切换输入法状态

v0.131.0

命令直通车(Command Bar)把短语 / 用户词库 / 系统词库的条目从"展开成文本"升级为"执行带副作用的动作":打开 URL、启动程序、模拟按键、写入剪贴板、加词到用户库、切换输入法状态等,让输入法兼作快捷命令启动器。

如何触发

命令用一段英文字母编码触发:输入编码 → 候选区出现命令条目 → 选中即执行。

输入选中后
cobd用默认浏览器打开 baidu.com
cojk输出 「」,光标停在中间,可用跳出键越过
coac把剪贴板内容加入用户词库
coen切换中英文模式

系统短语包已内置一批以 co 开头的示例命令,可在 设置 → 词库 → 短语 中浏览、开关或仿写。

触发码只能是英文字母

数字键会被"选中第 N 候选"逻辑吃掉,中文标点在按键阶段就被转换,二者都进不了短语层。因此触发码只能用 ASCII 字母(如 cobd),既不能含数字,也不能用中文标点。想携带查询内容时,用 clip() / last() 等数据源,而不是把词跟在编码后面。

编写位置

命令短语可放在三处,都会自动解析:

位置作用范围入口
命令短语全局,跨方案有效设置 → 词库 → 短语
用户词库仅当前方案设置 → 词库 → 方案 → 用户词库
系统词库仅当前方案设置 → 词库 → 方案 → 系统词库

推荐放命令短语

绝大部分命令放命令短语,拼音 / 五笔 / 混输下都可用。只有方案专属的命令才放用户词库。

四种标记

短语与词库条目共用一个 text 字段,靠内容形式区分类型。命令能力通过以 $ 开头的标记触发。

标记含义前缀输入时完整编码时
$CC(显示名, 动作...)命令显示(可关)显示
$CC1(显示名, 动作...)命令,顶层等同 $CC(但不能嵌进 $SS)显示(可关)显示
$AA(组名, 字符串)字符组显示组名导航无重码时展开为 N 个单字符,有重码时显示组名
$SS(组名, 元素...)数组(字符组的一般形式)显示组名导航无重码时展开为 N 个成员,有重码时显示组名
cobd = $CC("打开百度", open("https://baidu.com"))
cobd = $CC1("打开百度", open("https://baidu.com"))
zzbd = $AA("标点", "、。·ˉˇ¨〃々—~‖…")
zzgo = $SS("常用站点", $CC("百度", open("https://baidu.com")), $CC("GitHub", open("https://github.com")))

`编码 = 内容` 只是本页的示意写法

设置页里编码与内容分两栏填;写进词库文件(.dict.yaml、导入的 TXT)时按该文件的列序、用 Tab 分隔, Rime 词库默认是「内容在前、编码在后」:

$SS("括号", "【】", "()", "〔〕")	uu

内容里的空格、引号原样照写,不用另加转义。命令栏条目不可能是编码,所以哪怕把这一行写成 「编码在前」,输入法也会逐行认出来、自动对调。

`$CC` 与 `$CC1` 在顶层等价

早期 $CC 只在完整编码时出现、$CC1 才参与前缀列举。现在两者都参与:判据是 「没有显式写 {prefix: false}」,而 $CC1 只是把 prefix: true 显式写了出来。 不想让某条命令出现在前缀列表里,给它加 {prefix: false}:

cobd = $CC("打开百度", open("https://baidu.com"), {prefix: false})

唯一的例外在 $SS 的元素位置:那里只能嵌 $CC,写 $CC1 会让整条短语解析失败、 在候选里直接消失且没有任何提示。组前缀由 $SS 统一控制,元素不得自带 prefix。

另外前缀列举本身还受 input.phrase.min_prefix 约束(默认 2), 打得太短不会列。

一步失败就别往下跑:{on_error: "stop"} 0.121 新增

动作链默认是「前一步失败,后一步照跑」。想要「前一步成功才做下一步」,在同一个修饰符袋里写 on_error:

coim = $CC("导入词库", wind.cli("dict import D:\\words.txt"), ui.toast("导入成功"), {on_error: "stop"})

不写时默认 continue,与历史行为一致——默认不能改成 stop:已有词条依赖「前一步失败后一步照跑」(比如剪贴板被占用时仍要把光标移回去)。

不写 stop 的代价是假成功:上面那条链里 wind.cli 失败了,后面那句「导入成功」照样弹。这个修饰符本就是用来防假成功的,所以值写错会直接报错,而不是落回默认——失灵时的表现恰好就是它要防的那件事。

$AA 是 $SS 的字符串简写:$AA 自动按字符拆开,$SS 显式列举每个元素,元素既可是字符串(选中上屏),也可是嵌入的 $CC(...)(选中执行动作)。输入前缀(如 zz)看到组名导航条目,选中后自动补全到完整码进入二级选择。

输入完整码(如 zzbd)时是否展开,看有没有重码:

  • 同码没有别的候选、也只有这一组:直接展开为成员候选。
  • 同码还有别的候选(码表词、别的短语、另一个组):不展开,组只显示成一条组名,免得十几个成员把同码的常规候选挤出首页。选中组名后才展开,且这时只列该组成员;按一次退格先回到折叠态(编码不变),再按才删码。0.130 新增可用 backspace_collapse_group 关掉这一步,让退格直接删码。

$SS 里嵌入的 $CC(...) 成员各自是一条独立的命令候选,选中时只执行它自己的动作,不会连带别的成员。0.130 新增

`$SS` 的元素只能是字符串或 `$CC(...)`

元素位置上的 $CC 不得带 prefix 修饰符——组前缀由 $SS 统一控制。所以 $CC1(...) (它等价于显式写了 prefix: true)和 $CC(..., {prefix: false}) 在这里都会让整条短语 解析失败,现象是打出编码后候选里什么都没有、也没有任何报错。要控制这一组要不要参与前缀 列举,把 {prefix: false} 写在 $SS 自己的末尾。

表达式语法

$CC / $CC1 内部是表达式,只有三种形态:

形态例子
字面量"hello"、42、3.14
标识符last、now、code(等价零参调用)
函数调用open("https://...")、clip.copy("x")、key.tap("Enter")
  • 字符串内插:字符串中用 {expr} 内插子表达式,如 $CC("百度搜 {clip()}", open("https://baidu.com/s?wd={url(clip())}"))
  • $$ 转义:要输出字面 $ 就写 $$,否则 $M 之类会被当模板变量替换。例如 text = "工资: $$M" 显示 工资: $M
  • . 仅作命名空间:. 只用于函数名分隔(clip.copy、key.tap),不能取属性或索引。用 last(1) 而非 last.1,用 len(code) 而非 code.length
  • 具名参数:部分函数接受 名字=值 形式的可选参数(目前是 proc.run 的 cwd / verb / show、proc.shell 的 cwd,以及 ime.pair 的 jump),如 proc.run("dict.exe", cwd="D:\\Dict")。规则三条:必须写在所有位置参数之后、同一个名字不能写两次、名字必须是该函数登记过的(写错会报错,不会被当没写过)。值和普通参数一样可以内插,如 cwd="{clip()}"。

`k=v` 与 `{k: v}` 不是一回事

k=v 是函数的参数,管这一次调用;$CC(..., {prefix: false}) 那种花括号是短语的修饰符,管这条候选怎么显示。两者位置和作用对象都不同,写错地方会直接报错而不是悄悄生效。

路径里的反斜杠要写两个

字符串里的 \ 是转义引导符,写 Windows 路径时必须写成 \\:

# ✅ 正确
cotmp = $CC("[打开临时目录]", open("D:\\notes\\temp"))

# ❌ 错误:`\n` 被当成换行、`\t` 被当成 Tab
cotmp = $CC("[打开临时目录]", open("D:\notes\temp"))

被吃掉的是这几个:\n \t \r 分别变成换行、Tab、回车,\\ \" \' \{ \} \( \) \$ 变成对应的单个字符。其余组合(如 \我、\x)原样保留反斜杠——这正是坑人的地方:D:\我的文档 恰好能用,于是很容易以为单反斜杠没问题,直到某天路径里出现 \notes、\tools、\report,才发现路径被截断成了带换行/Tab 的怪字符串,而且看不出哪里错了。

别靠「试出来能用」判断

路径写单反斜杠时能否工作,取决于下一个字母恰好是不是转义字母。同一条短语换个目录名就可能失效,且失败时只弹一句「命令执行失败」,不会告诉你是反斜杠的问题。统一写 \\,不要逐条去试。

网络共享路径开头是四个

UNC 路径(\\服务器\共享名)本身就以两个反斜杠开头,每个都要按上面的规则写成两个,所以开头一共是四个:

想访问的路径命令里写
\\nas\share\dict.exe\\\\nas\\share\\dict.exe
\\192.168.1.5\tools\\\\192.168.1.5\\tools
conas = $CC("[打开共享]", open("\\\\nas\\share"))

规则本身没变,仍然是「一个 \ 写成 \\」——只是 UNC 的开头恰好有两个。写成两个(\\nas)解析出来是单个反斜杠开头的 \nas,那不是 UNC 路径,打不开;而这同样属于上面说的「不报错,只是打不开」。

换个地方写,还是两个

输入法内部只有一份真实文本:库里存的就是输入时用的,存储层对转义一无所知。转义只发生在文本进出系统的边界上,一共三类:

边界方向做的事
词库 / 短语文件(方案的 .dict.yaml、导入的 TSV/TXT、备份的 .wdict.yaml)读入、导出\\→\、\n→换行、\t→Tab,其余组合原样保留
设置 → 词库 的编辑框显示、保存与上一行互逆:库里的换行显示成 \n、制表显示成 \t,保存时再还原回去
候选窗只显示换行画成 ↵、制表画成 ⇥;上屏的仍是真换行

命令栏语法条目的反斜杠不参与这三层——$CC / $CC1 / $SS / $AA 以及含 {} 的模板,它们的 \ 由表达式解析独占,边界再转一次就成了双重展开。所以上面那条「写两个」在哪儿写都一样:设置页的输入框、方案的词库文件、配置分发包里内嵌的码表,写法完全相同,照搬不用换算。

而纯文本词条没有表达式那一层,边界规则直接落到它身上:

想得到的内容词库文件 / 设置页里写
C:\Users\noteC:\\Users\\note
两行文本第一行\n第二行
带一个制表符列一\t列二

0.114 – 0.117 的命令短语要写四个

  • 这几个版本里,命令短语经设置页或词库文件写入时会被多转义一层:路径分隔符得写四个反斜杠(open("D:\\\\notes"))才能真正得到一个。写进方案自己的 TOML 不过这一层,仍是两个——同一条命令在不同载体规则不同,正是该修的地方。
  • 各处统一为两个 0.118 新增:命令栏语法条目在边界上原样穿过。已经按四个写好的短语不用动——库里存的本来就是两个,升级后照常工作,只是设置页里显示的数量从四个变回两个(导出的文件同理)。

内部目录变量

不想硬编码安装位置或用户名(换台机器、换个盘符就失效),可以用 ${变量名} 引用输入法自己的目录:

变量指向典型位置
${APP_DIR}程序安装目录(wind_input.exe 所在目录)C:\Program Files\WindInput
${USER_DATA}漫游用户数据目录%APPDATA%\WindInput
${LOCAL_DATA}本机用户数据目录(不随漫游同步)%LOCALAPPDATA%\WindInput
# 打开安装目录
coad = $CC("[打开安装目录]", open("${APP_DIR}"))

# 上屏安装目录路径
cotd = $CC("[输出安装目录]", type("${APP_DIR}"))

# 拼接子目录 —— 反斜杠同样要写两个
colg = $CC("[打开日志]", open("${LOCAL_DATA}\\logs"))

变量在解析阶段就被替换成绝对路径,可用在任何字符串位置(动作参数、显示名、拼接片段)。这三个变量与 CLI 的路径参数完全一致,写法可以互相照搬。

不认识的 ${...} 会原样保留

只有上表三个是内部目录变量。写错名字(如 ${APPDIR})不会报错,而是原样留下字面的 ${APPDIR} ——因为 ${YC} 这类短语模板变量也用同样的写法,命令栏不能把它们当错误吞掉。所以路径打不开时,先核对变量名拼写。

若你确实想输出字面的 $ 且后面紧跟 {,写 \${...}。

常用示例

# 打开网址
cobd = $CC("打开百度", open("https://baidu.com"))
cogh = $CC("打开 GitHub", open("https://github.com"))

# 搜索剪贴板 / 上次上屏内容
cobs = $CC("百度搜 · {clip()}", web.search("baidu", clip()))
cozd = $CC("汉典 · {last()}", open("https://www.zdic.net/hans/{url(last())}"))

# 配对符号(光标落两段之间,可用跳出键越过右段)
cojk = $CC("「」", ime.pair("「", "」"))

# 删除当前行
codl = $CC("[删行]", key.seq("Home", "Shift+End", "Backspace"))

# 启动程序
cono = $CC("打开记事本", proc.run("notepad.exe"))

# 加词到用户库(编码自动生成)
coac = $CC("加词 · {clip()}", dict.add(clip()))

# 计算剪贴板表达式
coca = $CC("={calc(clip())}", type(calc(clip())))

# 切换输入法状态
coen = $CC("切中英", ime.toggle("cn-en"))
cots = $CC("切主题", ime.theme_cycle())

# 字符组
zzbd = $AA("标点", "、。·ˉˇ¨〃々—~‖…")
zzsx = $AA("数学", "+-<=>±×÷∈∏∑")

内置函数参考

函数只有一种返回值:字符串——数字、布尔在这里也是字符串(len("abc") 得到 3,可以直接拼进文本),动作函数返回空串。记号:s 字符串、n 整数、参数后 ? 表示可选。

每张表先给速查,表后的小节讲具体怎么写。

四条通用规则

  • 索引从 1 起,按字符数。 code(2) / sub(s, 2) / split(s, ",", 2) / dict.rev(s, 2) 里的 2 都指第 2 个字符(第 2 段);汉字、emoji 各算一个。sub 与 split 还接受负数,-1 是最后一个。
  • 取不到就给空串,不报错。 索引越界(sub("abc", 9))、历史不够长(last(9))、剪贴板为空,结果都是空串。这是刻意的:$SS 里固定写 N 条各查一个字,取不满是常态,报错会让整条短语连带消失。
  • 写错才报错,而报错等于候选消失。 函数名不存在(含拼写、大小写写错)、参数个数不对、该给数字的位置给了别的,都算错误。错误在显示名里 → 打出编码后候选里什么都没有、也没有提示;错误在动作里 → 选中时提示命令执行失败。所以"编码打出来却看不到候选",第一嫌疑就是函数名或参数写错。
  • 显示名里只能用纯函数。 $CC 的第一个参数只接受取值 / 文本 / 计算类函数;写 open、config.set、key.tap 这类动作函数会被判为不纯、整条失效——候选被列出来的时候不该有副作用发生。

显示与执行各求值一次

显示名在候选生成时求值,动作在选中那一刻才求值。所以 type(last()) 取到的是选中时的历史;而 uuid() 在显示名和动作里各写一次会得到两个不同的 ID——要让看到的和打出来的一致,就只在 type() 里写,显示名写死。

取值函数(纯函数)

函数说明
code() / code(n)触发时组合区里的编码(第 n 字符起到末尾)
tail(s, n)字符串 s 从第 n 字符起到末尾
last() / last(n)最近 / 倒数第 n 次上屏文本
clip()当前剪贴板文本
app() / title() / sel()前台进程名 / 窗口标题 / 选中文本——Windows 上均返回空串(仅 macOS 上报;其中 title() 还需 macOS 的辅助功能授权,未授权返回空串)
date(fmt) / date(fmt, offset)日期,见下
time() / time(fmt)时间,默认 "HH:mm:ss",见下
now()等价 date("YYYY-MM-DD HH:mm:ss")
env(name)环境变量,见下
uuid() / uuid(flags)随机 UUID(v4),见下
config.get(key)读取配置项当前值,key 是配置文件里的路径,如 ui.theme.name
dict.rev(s) / dict.rev(s, n) 0.117 新增反查:s 中第 n 个字(1 起,默认 1)的编码与读音,见下文

日期与时间:date / time / now

fmt 里下面这些字母是占位符,其余字符(- / : 年 等)原样输出。三个函数用的是同一套占位符,time 只是默认值不同、now 是写死的格式。

占位符含义2026-06-14 09:05:07 时
YYYY四位年2026
YY两位年26
MM月,补零06
M月,不补零6
DD日,补零14
D日,不补零14
HH时,24 小时制补零09
h时,12 小时制不补零9
mm分,补零05
m分,不补零5
ss秒,补零07
s秒,不补零7
YC 0.131 新增中文年份二〇二六
MC 0.131 新增中文月份六
DC 0.131 新增中文日期十四
WC 0.131 新增星期(中文)日
LMD 0.131 新增农历月日四月廿九
LM 0.131 新增农历月四月
LD 0.131 新增农历日廿九
LY 0.131 新增干支年丙午
LZ 0.131 新增生肖马
LYN 0.131 新增农历年数字(与公历年可能差 1)2026
LF 0.131 新增传统节日,平常日子为空端午当天 端午节
ts / tsms 0.131 新增秒级 / 毫秒时间戳(随当前时间变化)

没有上午/下午、月份英文名的占位符。24 小时制补零只有 HH(没有 H),12 小时制只有 h(没有 hh)。

推荐用 date,而不是 $变量。

YC 以下的占位符与命令短语里的 $变量同名、同值——$LMD 能做的,date("LMD") 都能做。写短语时更推荐 date(),因为它多出三样 $变量 没有的本事:

  • 能平移:date("LMD", "-1d") 是昨天的农历,$LMD 只能是今天的。
  • 能混写:公历、农历、星期写在同一个格式串里,不必拆成一堆 $ 拼接。
  • 能嵌进别的表达式:交给 concat()、type() 等函数继续加工。

农历只覆盖 1900–2100 年,超出范围(含平移后超出)会报错、候选不出现,而不是只剩一半文字。LF 平常日子是空串,date("LY年LMDLF") 平时给出「丙午年四月廿九」,端午当天给出「丙午年五月初五端午节」。

常用配方:

想要写法结果
今天date("YYYY-MM-DD")2026-06-14
中文日期date("YYYY年M月D日")2026年6月14日
明天 / 昨天date("YYYY-MM-DD", "+1d") / date("YYYY-MM-DD", "-1d")2026-06-15 / 2026-06-13
后天 / 前天date("YYYY-MM-DD", "+2d") / date("YYYY-MM-DD", "-2d")2026-06-16 / 2026-06-12
下周同一天date("YYYY-MM-DD", "+1w")2026-06-21
中文星期date("星期WC")星期日
农历date("LY年LMDLF")丙午年四月廿九
明天的农历date("LMDLF", "+1d")五月初一
上个月date("YYYY-MM", "-1M")2026-05
文件名时间戳date("YYYYMMDD-HHmmss")20260614-090507
只要时间time() / time("HH:mm")09:05:07 / 09:05
日期加时间now()2026-06-14 09:05:07
codt = $CC("{date("YYYY-MM-DD")}", type(date("YYYY-MM-DD")))
cotm = $CC("{date("YYYY-MM-DD", "+1d")}", type(date("YYYY-MM-DD", "+1d")))

大小写就是两个不同的占位符

MM 是月、mm 是分;DD 是日、HH 是时。date("YYYY-mm-DD") 不会报错,它会把分钟填进月份的位置,得到 2026-05-14 这种看着像日期、其实每分钟都在变的东西。

格式串里别混英文单词

单个 M D h m s 也是占位符,所以格式串里写英文会被就地替换:date("Monday") 得到的是 6onday(M → 月份 6)。要固定的英文文字请用 concat() 拼在 date() 外面,或者只在格式串里放中文与标点。

上表里 YC 起的那些多字母占位符同理:格式串里出现这些连续字母也会被替换。

`%` 是保留字符,不要写进格式串

格式串里的 % 会被直接交给底层的时间格式化器:%Y 这类恰好合法的会按 strftime 解释,而落单的 %(或 % 后跟着不认识的字母)会让求值报错、这条候选不出现。想输出百分号,用 concat(date("YYYY"), "%") 拼在外面。

0.130 及更早版本遇到这种写法会让输入法直接退出,不只是报错。

offset:把日期平移一段。 形如 "+1d",三部分缺一不可:

部分规则
符号+ 或 -,必须写。"1d" 会报错
数字整数。"+1.5d" 报错
单位d 天 / w 周 / M 月 / y 年,大小写敏感

单位只有这四个:M 是月、小写 m 不是分钟而是非法单位,也没有小时/分钟级的偏移——要平移时间只能靠 date(fmt, offset),而它最小的单位是天。

月和年按自然月平移,落到不存在的日期时夹到当月最后一天:3 月 31 日 -1M 得到 2 月 28 日(闰年 29 日)。

示例:给自己加「昨天」「明天」的短语

输入法没有内置「昨天」「明天」这类相对日期的短语(需要的人不多,内置了反而占码位)。需要的话,自己在用户短语里加几条——内容直接写 {date(...)},不需要 $CC,也不需要 type():

编码内容上屏(以 2026-06-14 为准)
zuotian{date("YYYY年M月D日", "-1d")}2026年6月13日
mingtian{date("YYYY年M月D日", "+1d")}2026年6月15日
houtian{date("YYYY年M月D日", "+2d")}2026年6月16日
qiantian{date("YYYY年M月D日", "-2d")}2026年6月12日

编码用全拼的话,打出来的候选会和正常的词条「昨天」并列出现,位置由权重决定;觉得碍事就换成不会撞词的缩写,如 zt mt。

同一个编码可以加多条,每条一种写法,就得到「一个编码出多种格式」:

编码内容上屏
mingtian{date("YYYY-MM-DD", "+1d")}2026-06-15
mingtian{date("星期WC", "+1d")}星期一
mingtian{date("农历LMDLF", "+1d")}农历五月初一

想要的不是整天而是别的间隔,换单位就行:"+1w" 下周、"-1M" 上个月、"+1y" 明年同一天。

编码、历史与剪贴板:code / tail / last / clip

写法取到什么
code()触发这条候选时组合区里已输入的编码
code(n)同上,但从第 n 个字符切到末尾;n ≤ 1 等于全部,超出长度得空串
tail(s, n)与 code(n) 同规则,但作用于任意字符串
last() / last(1)最近一次上屏的文本
last(2) / last(3)上上次 / 上上上次;n < 1 或超出历史长度得空串
clip()当前系统剪贴板里的纯文本;剪的是图片或剪贴板为空时得空串

历史只记真正上屏的文本,纯副作用命令(open / proc.run 等)不进历史,所以 last() 不会被命令自己污染(见行为细节)。

last() 与前台信息在命令触发的那一刻冻结成快照,之后动作里再读也是同一份。

环境变量与随机 ID:env / uuid

env(name) 读输入法进程的环境变量,读不到返回空串(不报错):

couser = $CC("{env("USERNAME")}", type(env("USERNAME")))
cohome = $CC("[打开用户主目录]", open(env("USERPROFILE")))

新加的环境变量要重启输入法才可见

进程的环境变量在启动时就固定了。刚在系统属性里新建的变量,输入法要退出重开才读得到。输入法自己的目录别用 env() 猜,直接用 ${APP_DIR} 一类的内部目录变量。

uuid() 生成随机 UUID(v4),flags 控制形态,字母不区分大小写:

写法结果形如
uuid()9f1c2b7e-3a4d-4f65-8c21-0d5e7a9b1234
uuid("n")9f1c2b7e3a4d4f658c210d5e7a9b1234(去横杠)
uuid("u")9F1C2B7E-3A4D-...(转大写)
uuid("nu")两者组合

只认 n 和 u,写别的字母(uuid("x"))会报错、候选消失——这是刻意的,静默忽略会让人以为"格式没生效"。短语层的 $uuid 模板变量走的是同一套实现。

文本处理(纯函数)

函数说明
len(s)字符数(按 rune)
upper(s) / lower(s)转大写 / 小写
trim(s) / trim(s, chars)去首尾空白 / 去首尾的指定字符
sub(s, start) / sub(s, start, end)切片,索引 1 起,双闭区间,支持负数
replace(s, old, new)字面替换(全部出现处)
regex(s, pat, rep)正则替换,见下
split(s, sep, n)按 sep 拆分取第 n 段(1 起,支持负数)
concat(...)拼接任意个片段
reverse(s)反转(按 rune)
url(s) / html(s) / json(s) / base64(s)URL / HTML / JSON / Base64 编码,见下
default(s, fallback)s 为空时返回 fallback

照着抄的例子(左边是写法,右边是结果):

写法结果
len("清风输入法")5
upper("Wind") / lower("Wind")WIND / wind
trim(" 两边有空格 ")两边有空格
trim("**重点**", "*")重点
sub("abcdef", 3)cdef
sub("abcdef", 2, 4)bcd
sub("abcdef", -2)ef
sub("abcdef", 1, -2)abcde
replace("2026/06/14", "/", "-")2026-06-14
split("张三,李四,王五", ",", 2)李四
split("a-b-c", "-", -1)c
concat("【", clip(), "】")剪贴板内容加书名号
reverse("abc")cba
default(clip(), "(先复制点东西)")剪贴板为空时给出提示语

trim(s, chars) 的第二个参数是字符集合不是子串:trim("xxabcxx", "x") 与 trim("xxabcxx", "xy") 结果相同,都是 abc。

正则替换:regex(s, pat, rep)

pat 用 Rust regex 语法(与 RE2 同族):\d \w \s、[[:alpha:]]、+ * ? {n,m}、|、分组都支持,不支持反向引用和环视((?<=...)、\1)。

  • 模式里的反斜杠按字符串规则写两个:\\d 才是一个 \d(见路径里的反斜杠要写两个)
  • 量词的大括号要转义成 \{ \}:{ 在字符串里是插值语法,"\\d{3}" 会被求值成 \d3——正则悄悄变成了另一个意思,还不报错
  • 替换串里用 ${1} ${2} 引用捕获组。${...} 不会被当插值(那是内部目录变量的写法,名字不认识就原样保留),可以照写;$1 也认,但后面紧跟字母数字时会被吞进组名,统一写 ${1} 更稳
  • 匹配处全部替换,没有"只换第一处"的开关
  • 正则本身写错(括号不配对等)→ 求值报错 → 候选消失

匹配换行要用 `\r?\n`,不能用 `\n`

clip() 从 Windows 剪贴板取到的文本,换行通常是 \r\n 两个字符(记事本、Word、浏览器复制都是这样);而 last()、code 以及你自己写在字符串里的换行,往往只有 \n 一个。同一条正则要两种来源都能用,只有 \r?\n 一种写法:

模式\r\n 来源(剪贴板居多)\n 来源
"\n"❌ 只吃掉 \n,剩下的 \r 原样上屏✅
"\r\n"✅❌ 一处都匹配不上,原文照抄
"\r?\n"✅✅

第一行剩下的那个 \r,在多数编辑器里既不显示也不换行,看上去就是「替换好像没生效」或者「行首多了个看不见的东西」。撞上之后最顺手的自救是把 \n 改成 \r\n——那恰好掉进第二行那个更隐蔽的坑:换个来源就一个都匹配不上,而且同样不报错。

这一条不受上面「反斜杠写两个」的约束:"\r?\n" 与 "\\r?\\n" 结果完全相同(前者由字符串转义直接生成真的回车 / 换行字符,后者原样交给正则引擎去解释),写哪个都行。

# 把连续数字换成 #
como = $CC("[数字打码]", type(regex(clip(), "\\d+", "#")))

# 日期换成中文写法(捕获组用 ${1})
cocn = $CC("[日期转中文]", type(regex(clip(), "(\\d+)-(\\d+)-(\\d+)", "${1}年${2}月${3}日")))

# 手机号中间四位打码:注意量词的大括号写成 \{3\}
comask = $CC("[手机号打码]", type(regex(clip(), "(\\d\{3\})\\d\{4\}(\\d\{4\})", "${1}****${2}")))

# 多行粘贴合成一行:\r?\n 才能同时吃掉 \r\n 和 \n
cojoin = $CC("[多行并一行]", type(regex(clip(), "\\r?\\n", "、")))

四个编码函数:url / html / json / base64

写法结果用在哪
url("清风 输入")%E6%B8%85%E9%A3%8E+%E8%BE%93%E5%85%A5拼进查询串。空格变 +(query 编码),拼进路径段要留意
html("<b>&")&lt;b&gt;&amp;往 HTML 里贴文本
json("a\"b")"a\"b"带外层引号,出来的是一个完整的 JSON 字符串字面量
base64("hi")aGk=标准 Base64(带 = 补位)

url() 正是搜索类命令的关键一环——open("https://www.zdic.net/hans/{url(last())}") 里少了它,含空格或标点的词就会把 URL 拼坏。

计算与内省

函数说明
calc(expr)数学表达式求值,见下
num(s, base)进制转换(2/8/10/16),见下
help(name)返回指定函数的一行简介,查不到返回空串

算术:calc(expr)

支持 + - * / %(取余)、圆括号、一元正负号、小数与空格。

不支持:乘方 ^、科学计数法 1e3、千分位逗号、全角符号((1+2))、sin 之类的函数、变量。碰到不认识的字符就报错,整条候选消失。

写法结果
calc("1+2*3")7
calc("(1+2)*3")9
calc("6/2")3(整数结果不带 .0)
calc("1/3")0.3333333333333333
calc("10%3")1
calc("")空串(不报错)
calc("1/0")报错,候选消失

最后两行是配剪贴板算式用的:calc(clip()) 在没复制东西时静默给空串,所以出厂那条 coca = $CC("={calc(clip())}", type(calc(clip()))) 只会显示一个 =,而不是整条消失。

进制:num(s, base)

s 的进制由前缀自动识别,base 是输出进制:

写法结果
num("0xff", 10)255
num("255", 16)ff(小写,不带 0x)
num("10", 2)1010
num("0b1011", 10)11
num("0o17", 10)15
num("-255", 10)-255

输入前缀:0x/0X 十六进制、0o/0O 八进制、0b/0B 二进制、无前缀按十进制,可带正负号,首尾空格自动去掉。base 只能是 2 / 8 / 10 / 16,其它值报错;只处理整数,num("3.5", 10) 报错。

负数只在转十进制时正常

转成 2 / 8 / 16 进制时,负数按 64 位补码输出而不是带负号:num("-255", 16) 得到的是 ffffffffffffff01,num("-10", 2) 是一长串 1。要给负数换进制,请自己把符号拆出来处理。

查手册:help(name)

help("date") 返回 date 的一行内置简介。配上剪贴板就是一条随手可查的手册:

cohelp = $CC("{default(help(clip()), "复制一个函数名再查")}", type(help(clip())))

动作函数(有副作用)

函数副作用
type(s)经 TSF 上屏文本,不污染剪贴板
open(target)打开 URL / 文件 / 程序(http(s) 走浏览器,其他走 ShellExecute)
proc.run(cmd, ...args, cwd?, verb?, show?)异步启动进程,三个具名参数见下
proc.shell(cmdline, cwd?)执行 shell 命令,cwd 见下
key.tap(combo) / key.seq(...combos)单次按键 / 按键序列
key.hold(combo) / key.release(combo)按下 / 抬起(须成对使用)
key.type(text)Unicode 直输,绕过键盘布局(走 SendInput,非 TSF)。文本里的换行与制表符会发成回车 / Tab 按键 0.118 新增
clip.copy(s) / clip.paste()写入剪贴板 / 模拟 Ctrl+V
dict.add(s) / dict.add(s, code)加词到用户库(不给 code 就按当前方案的取码规则推导)
ime.toggle(target)切换状态:cn-en / fullshape / layout / candwin / s2t / t2s / preedit / toolbar
ime.toggle("comment") 0.129 新增切换候选注释的持久状态(默认 ⇄ 详细),写回配置;系统短语 cozs「切注释」就是它
ime.set("comment", "default") / ime.set("comment", "detail") 0.129 新增直达指定状态;已是该状态则不改动。注意这里的状态值是 default / detail,不是 on / off
ime.toggle("emoji") / ime.toggle("emoji:模块id") / ime.toggle("dict:库id") 0.126 新增数据开关:emoji 候选总开关 / 某个 emoji 附加模块 / 某个注释词库,见下文
ime.set(target, 状态) 0.126 新增把开关设为指定状态(on / off),已是该状态则不改动。target 可以是 cn-en(on = 中文)/ fullshape / s2t / t2s / toolbar,也可以是下文的数据开关;layout / candwin / preedit 是循环切换,只能用 ime.toggle
ime.schema(id)切换并持久化方案,如 "wubi86" / "pinyin"
ime.theme(name) / ime.theme_cycle(dir?)切换主题 / 循环切换(dir ∈ next / prev)
ime.undo_commit()撤销上屏:删除最近一次上屏的内容,见下文
ime.reload() 0.129 新增重载配置:重新读取用户配置并应用,等同设置端保存后的热重载;手改 config.toml 后用。读取失败(语法错误等)时沿用当前配置并提示
ime.pair(left, right, jump?)上屏配对符号:光标落两段之间,可用跳出键越过右段,见下文
setting.open(page, args?)打开设置的指定页(page 见下;args 为附加命令行参数)
web.search(engine, q)打开搜索页,engine ∈ baidu / bing / google / zdic,见下
config.set(key, value) / config.toggle(key)写入配置 / 循环切换枚举或翻转布尔(返回新值)
wind.cli(...)调用命令行子命令,见下文
ui.toast(text, kind?, color?, pos?, ms?) 0.121 新增弹一条桌面提示,见下文

数据开关 0.126 新增

ime.toggle 也能开关几项「查表」类功能,适合做成短语或绑到按键上,不必进设置页。要明确打开或关闭时用 ime.set(target, 状态):状态写 on / off(也认 true / false、1 / 0、开 / 关),已经是这个状态就不改动;toggle 只能翻转,事先不知道当前状态时没法保证结果。

target开关的是
emojiemoji 候选总开关
emoji:模块id一个 emoji 附加模块,如 emoji:frost_greek(希腊字母);用户目录 emoji\ 里放的表,id 就是文件名
dict:库id一个注释词库,id 即设置页列表里 ${dict:…} 显示的那个
coxl = $CC("希腊字母开关", ime.toggle("emoji:frost_greek"))
cozy = $CC("中英释义开关", ime.toggle("dict:chinese_english"))
# 一次切到「查英文」状态:开释义、关 emoji
coyw = $CC("英文释义模式", ime.set("dict:chinese_english", "on"), ime.set("emoji", "off"))
# 确保回到中文、半角
cozw = $CC("中文半角", ime.set("cn-en", "on"), ime.set("fullshape", "off"))

状态真的变了才写进配置并立即生效,屏幕中央提示「…已开启 / 已关闭」;ime.set 遇到状态本就一致时不写配置,只提示「…已是开启状态」,让你知道命令确实执行了。id 写错或状态写成认不出的值时报错,不会静默无反应。输入状态(cn-en、fullshape 等)用 ime.set 时同理:已是目标状态只提示「已是中文模式」「简入繁出已是开启状态」之类,否则照常切换。

type(s) 是唯一被特殊对待的名字:它只能作为 $CC 的动作直接写出来,不能嵌进别的函数里、也不能出现在显示名中,且只接受 1 个参数、不接受具名参数。help("type") 也查不到它。别和 key.type 搞混——后者是模拟键盘直输,走的是另一条路径。

web.search(engine, q) 的 engine 不区分大小写、首尾空格会被去掉;q 为空时不会打开浏览器,而是报错——避免开出一个空搜索页却让人以为命令没执行。zdic 走的是汉典的词条页而非搜索参数。

工作目录:cwd=

被启动的程序总有一个确定的工作目录,规则如下:

写法工作目录
proc.run("D:\\Dict\\dict.exe")D:\Dict(程序自己所在的目录)
proc.run("notepad.exe")用户主目录(%USERPROFILE%)
proc.run("x.exe", cwd="D:\\Data")D:\Data
proc.shell("dict -q 词")用户主目录
proc.shell("dict -q 词", cwd="D:\\Dict")D:\Dict

不写 cwd 时,proc.run 默认取被启动程序所在的目录——等同于你在资源管理器里双击它。靠相对路径找数据文件的程序(各类词典、绿色版工具)正是按这个前提写的,所以多数情况下不需要写 cwd。

proc.shell 是把整条命令行交给 shell,认不出目标程序,所以默认只能落到主目录。命令里带相对路径就必须显式写 cwd。

cwd 支持内部目录变量,也支持内插:

# 用输入法自己的目录
cotool = $CC("[跑工具]", proc.run("${APP_DIR}\\tools\\t.exe", cwd="${APP_DIR}\\tools"))

# 查词:词库在程序目录下,靠相对路径加载
codc = $CC("查 {last(1)}", proc.run("D:\\Dict\\dict.exe", "{last(1)}", cwd="D:\\Dict"))

`cwd` 写了个不存在的目录会被忽略

此时程序仍会启动,但工作目录退回默认值,只在日志里留一条警告。之所以不直接失败,是因为你的目的是启动程序而不是校验路径——但这也意味着 cwd 路径写错时表面上一切正常,只是程序又找不到它的数据了。排查这类问题先检查路径拼写和反斜杠。

管理员运行与窗口状态:verb= show=

只对 proc.run 有效,且只在 Windows 生效(macOS 会忽略并在日志留一条说明)。

verb效果
省略该文件类型的默认动作
open打开
runas以管理员身份运行(会弹 UAC 提示)
edit / print编辑 / 打印
explore / properties在资源管理器中浏览 / 打开属性对话框
show效果
省略 / normal正常窗口
min最小化启动,且不抢焦点
max最大化启动
hidden不显示窗口
# 以管理员身份跑一个维护脚本
coadm = $CC("[管理员运行]", proc.run("D:\\tools\\fix.exe", verb="runas"))

# 后台静默启动,不打断当前打字
cobg = $CC("[后台同步]", proc.run("D:\\tools\\sync.exe", show="hidden", cwd="D:\\tools"))

取值必须是上表里的小写词,写错(含大小写不符,如 verb="RUNAS")会直接报错并列出合法取值——这个校验在所有平台一致,所以在 macOS 上写错也会当场发现,不会等到换台 Windows 机器才炸。

`hidden` 不会让程序变成后台服务

它只是不显示窗口。程序本身如果会弹对话框或自己创建窗口,照样会出现;反过来,一个需要你操作的程序设了 hidden 就变成了看不见摸不着的进程,只能去任务管理器结束。

打开设置页:setting.open(page)

page 是目标页的规范 id,直接跳到对应标签页:

page页面
schema方案
input输入
keys按键
ui外观
dict词库
advanced高级
about关于
import不是独立标签页:切到高级页并弹出导入对话框,同时读一次剪贴板(用于配置分发包)
""(空串)默认页
cost = $CC("打开设置", setting.open(""))
codc = $CC("词库管理", setting.open("dict"))

未知 id 会被设置端忽略并落到默认页。

附加参数:setting.open(page, args) 0.113 新增

第二个参数是原样直通给设置工具的命令行参数串,写法与设置工具的命令行参数完全一致。最常用的是直接落到某个方案的某类词库数据:

codw = $CC("五笔用户词库", setting.open("dict", "--schema=wubi86 --type=user-dict"))
cods = $CC("五笔候选调整", setting.open("dict", "--schema=wubi86 --type=shadow"))
copy = $CC("拼音词频", setting.open("dict", "--schema=pinyin --type=freq"))

输入法只负责转交,不解析这串参数——设置工具支持什么就能写什么,新版本加的参数无需等输入法跟进。参数不认识或方案不存在时,设置工具会退到最接近的位置并给出提示,不会打不开。

含空格的值要自己加引号

参数串会被重新切分成多个参数,--text=你 好 会断在空格处。含空格的值请写成 --text="你 好"。

配对符号:ime.pair(left, right, jump?)

上屏 left + right、光标落在两段之间,并把这一层压入配对状态——之后按跳出键(在设置里配的 Tab / Enter)就能越过右段,和自动配对打出来的括号完全一样。

cojk = $CC("「」", ime.pair("「", "」"))
cozg = $CC("注释符", ime.pair("<!--", "-->"))

两段都可以是任意文本,不限于单个符号:

输入后:  <!--|-->
按 Tab:  <!---->|

jump:跳出时光标右移的格数。 省略时按右段的字符数推导("-->" → 3),一般不用写。它存在是因为跳出靠合成方向键,而"一次右键越过多少内容"是宿主行为——多数宿主一次跨整个 emoji,少数按编码单元走。若在某个程序里发现跳出后光标位置差了几格,用它手动校准:

cozg = $CC("注释符", ime.pair("<!--", "-->", jump=3))

分级跳出:同一条词条里写多个 ime.pair 即可,无需额外语法。后写的是内层,跳出时也先出内层:

cokh = $CC("(【】)", ime.pair("(", ")"), ime.pair("【", "】"))

输入后:  (【|】)
按 Tab:  (【】|)     ← 出内层
按 Tab:  (【】)|     ← 出外层

受「标点配对」总开关约束

ime.pair 跟着设置 → 标点配对的开关走(中文模式看中文配对、英文模式看英文配对)。关掉时它退化为纯上屏:整串照常上屏,但光标落在末尾、也不能跳出。

另外,「输入右符号跳出」对它不生效——那条路径只认单个标点按键。ime.pair 压入的配对只能用 Tab / Enter 跳出。

反查剪贴板里的字 0.117 新增

平时的反查要先把字打出来,才能在悬停提示里看它的编码和读音。碰到不认识的字(从网页、 PDF、聊天记录里看到的),这条路走不通——你根本不知道怎么打它。

dict.rev 反过来走:先复制,再查。

出厂已带 cofc,直接可用:

cofc = $CC(default(dict.rev(clip()), "剪贴板反查(需先复制文字)"), type(dict.rev(clip())))

复制一个「我」,切回输入法打 cofc,候选就是:

我: q/trn/trnt wǒ

编码给的是全部码位(简码在前),因为反查回答的是「这个字怎么打」——q 这样的简码才是 最有用的答案。编码来自码表的反查索引,不是按取码规则算出来的,所以给出的码一定打得出来。

选中即上屏这行文字。

编码为空是正常的

dict.rev 查的是当前主码表。纯拼音方案下没有形码可查,编码段自然是空的,只出读音。

查第几个字

默认查第 1 个字。dict.rev(s, n) 查第 n 个(1 起);n 超出字数返回空串,不报错。

想一次看多个字,用 $SS 列若干条、各查一个:

cofd = $SS("反查", "{dict.rev(clip(),1)}", "{dict.rev(clip(),2)}", "{dict.rev(clip(),3)}")

写几条就是最多查几个字。剪贴板不足位数时,多出来的那几条自动不出现,不会留空白候选。

换版式:format=

版式用候选注释的同一套 ${...} 模板语法, 变量名也一样,学一次即可:

写法结果
dict.rev(clip())我: q/trn/trnt wǒ(默认 ${char}: ${code_all} ${pinyin})
dict.rev(clip(), 1, format="${pinyin}")wǒ
dict.rev(clip(), 1, format="${code_all:/}")q/trn/trnt
dict.rev(clip(), 1, format="${char} ${chaizi}[${chaizi_code}]")形如 你 亻尔[wqiy](字根用私用区字形,需装字根字体才显示)

可用变量:${char}(被查的字)、${code_all}(全部码位)、${code}(只要最长的全码)、 ${pinyin}、${chaizi}、${chaizi_code}、${dict}(注释词库释义)。

模板里要写 `${}` 不能写 `{}`

{...} 在命令栏字符串里是求值插值,format="{code}" 会去调用 code() 函数(触发编码), 静默得到完全不相干的结果。变量一律写 ${code} 这种形式。

为什么用 $CC 而不是直接写模板

直接写 {dict.rev(clip())} 也能用,但候选的显示文本就是上屏文本,两者绑死。于是剪贴板 为空时只有两个都不好的结果:整条候选消失(分不清是没复制还是功能坏了),或者把提示语本身 打进文档。

$CC 把两者拆开:display 只管显示(查不到时用 default 回落到提示语),上屏走 type(dict.rev(clip()))(查不到时求值为空,选中什么也不打)。

撤销上屏:ime.undo_commit()

按上屏历史删除最近一次上屏的内容——记录上屏了几个字符,就往前删几个。连续触发可逐条回退。

coun = $CC("撤销上屏", ime.undo_commit())

配合快捷键使用更顺手:把这条短语绑一个好按的编码,或用 config.set 给它挂全局热键。

行为细节:

  • 正在打字时不动作 —— 输入缓冲非空(组合区有内容)时直接忽略,不会误删
  • 无上屏历史时删除 1 个字符
  • 每撤销一次就从历史中弹出一条,推送失败会回滚该条记录

撤销不校验光标前的内容

它只按历史记录的字符数往前删,不检查光标前实际是什么。上屏后如果你在输入法之外移动过光标、或改过文本,撤销会删错位置的内容。

另外计数按 UTF-16 单位,在使用退格兜底的宿主里遇到 emoji 可能多删。

调用命令行:wind.cli(...)

把命令行工具的任意子命令挂到短语上,用主程序自身执行。两种传参形式:

# 单参形式:按空白拆分
cocr = $CC("重建词库缓存", wind.cli("schema rebuild"))
codf = $CC("停用辅码库", wind.cli("schema dict disable wubi86 fl"))

# 多参形式:逐个原样传递,用于含空格的路径
cobk = $CC("备份", wind.cli("backup", "create", "D:\\我的 备份\\wind.zip"))

# 配合内部目录变量,免去硬编码路径
cobu = $CC("备份到用户目录", wind.cli("backup", "create", "${USER_DATA}\\backups\\wind.zip"))

含空格的参数(尤其是文件路径)必须用多参形式,否则会被空白拆散成多个参数。路径里的反斜杠仍按短语字符串规则写成 \\(见路径里的反斜杠要写两个)——这一层与 CLI 无关,是短语先解析、再把结果交给 CLI。

照搬终端命令的两道坎

从终端里跑通一条命令、再原样贴进 wind.cli(...),是最常见的写法,也最容易连撞两道坎。拿一条命令举例——把某个字符串类配置键(下面用 some.template_key 代称)设成 {${chaizi}}{ [${chaizi_code}]}{ ${pinyin}}(这是字符串本身的样子,下面写进短语时还要再转义一层):

# ❌ 错误:整条命令行塞进一个参数,大括号也没转义
[[phrases]]
code = 'comm'
text = '$CC1("设模板串", wind.cli("config set some.template_key {${chaizi}}{ [${chaizi_code}]}{ ${pinyin}}"))'

# ✅ 正确:按空格拆成 4 个参数,大括号写成 \{ \}
[[phrases]]
code = 'comm'
text = '$CC1("设模板串", wind.cli("config", "set", "some.template_key", "\{${chaizi}\}\{ [${chaizi_code}]\}\{ ${pinyin}\}"))'
weight = 1000
position = 1

第一道:参数得你自己拆开。 单参形式只是把整串按空白切一刀(每遇到空白就分出一个参数),它只适合参数本身不含空格的命令。上面那条模板串自己带空格,切完就散成了六七个参数,CLI 收到的东西跟你写的完全不是一回事。只要有任何一个参数可能含空格,就把命令行的每一段写成独立的字符串参数——包括 config、set 这些子命令名。

第二道:\{ 和 \} 要转义。 字符串里的 {...} 是内插语法,{${chaizi}} 会被当成「求值这个表达式」而不是字面的大括号。要输出大括号本身,必须按转义表写成 \{ \}(见路径里的反斜杠要写两个)。

${chaizi} 这类 ${名字} 不用转义:只有内部目录变量那三个名字会被替换,其余原样穿过,正好交给 CLI。

两道坎的失败现象不一样,可以据此判断撞的是哪道

症状撞的是
打出编码后候选里根本没有这条短语,也没有任何报错第二道。大括号没转义 → 整条短语解析失败被静默丢弃
候选正常出现、选中后也没提示,但配置没变第一道。参数没拆开 → CLI 收到错的参数,而 wind.cli 不回收错误

两种都不会弹错误框,所以别按「有没有报错」判断对错,要按上表对症状。

写在 TOML 里请用单引号

上面的 text = '...' 用的是 TOML 的单引号字面串,里面的 \ 原样保留,写法与设置页输入框、词库文件里完全一致。若改用双引号 text = "...",TOML 自己会先吃掉一层转义,而 \{ 在 TOML 里是非法转义,整个文件都会读不进去。

执行完给出反馈 0.121 新增

wind.cli 会等命令跑完,按退出码把结果弹成 toast:成功文案取 CLI 自己打印的最后一行(「✓ 用户词库: 新增 12 · 更新 3」),失败取 stderr 的首行。三个具名参数管这件事,都不影响命令本身:

参数默认说明
toaston执行结果提示。on = 成败都弹;off = 都不弹(此时也不等待);error = 只在失败时弹
ok省略成功时的自定文案。省略则用命令自身输出的最后一行,不自造第二套说法
wait10000等待命令结束的毫秒上限。0 = 不等待,此时无结果可报。超时会给一条「命令仍在执行,未能确认结果」的中性提示,迟到的真结果不再补弹
# 导入用户词库,失败时才提示
coim = $CC("导入词库", wind.cli("dict import D:\\words.txt", toast="error"))

# 服务侧本来就会弹提示的子命令,把这一层关掉,免得撞车
cort = $CC("重启服务", wind.cli("restart", toast="off"))

# 自定成功文案,并把等待放宽到 30 秒
corb = $CC("重建缓存", wind.cli("schema rebuild", ok="缓存已重建", wait="30000"))

哪些子命令该设 toast 为 off

服务侧本身就会弹提示的那些(restart / config set)。撞不撞车只有写词条的人当场知道,输入法不去维护一张子命令名单。

从短语调用时输入法服务必然在线,所以 schema / dict / phrase / backup 这些需要在线的子命令都能正常连上。

候选注释也能单项配置

注释的开关、两态、切换键用 ui.comment.enabled / state / switch_key / switch_mode;分配的某一格与某个用户模板用 ui.comment.assign.<范围>.<名>.<格> 与 ui.comment.template.<id>,写空串即删除。键的完整写法与示例见候选注释(ui.comment)。临时切换默认 / 详细态用 ime.toggle("comment") 或 ime.set("comment", "detail")。

改配置优先用 config.set,不要绕 wind.cli

config.set(key, value) 与 wind.cli("config set ...") 效果相同,但前者在进程内直接生效、错误就地返回,后者要另起一个进程再把结果读回来。改配置一律用 config.set / config.toggle;wind.cli 留给没有对应短语函数的子命令。

弹一条提示:ui.toast(...) 0.121 新增

# 最简形式
$CC("提示", ui.toast("已完成"))

# 指定类型与位置
$CC("提示", ui.toast("导入完成", kind="success", pos="top_right", ms="4000"))

# 自定强调色
$CC("提示", ui.toast("注意", color="#FF8800"))

除文案外全部具名、与顺序无关:

参数默认取值
kindinfoinfo / success / error,决定强调条颜色
color省略自定强调色 #RRGGBB 或 #RRGGBBAA
posbottom_centercenter / top / top_center / bottom_center / top_left / top_right / bottom_left / bottom_right
ms2500显示毫秒数

底色与文字色仍归主题,不开放到词条——只有强调色可以在这里改。

kind 与 color 只能给一个

两者都是「强调色」的写法,同时出现只能是写错了。此时会直接报错而不是猜一个——静默取一个会让另一个看起来「没生效」。

同理,pos 把 top_right 写成 right、ms 写成 "5秒",都会当场报错,不会静默降级。

外部脚本与计划任务也能弹:命令行 wind_input ui toast "文案",见命令行工具。

按键 combo 格式

key.* 的 combo 为 [修饰键+]...主键,大小写不敏感,+ 分隔。修饰键:Ctrl、Shift、Alt、Win(各有别名如 Control / Menu / Super)。主键支持常见控制键(Enter、Tab、Escape、Home、End、Up 等)、功能键 F1–F24、字母数字键,以及标点键(Comma、Period、Slash 等)。

key.tap("Ctrl+C")                       # 复制
key.tap("Alt+F4")                       # 关闭窗口
key.seq("Home", "Shift+End", "Delete")  # 删除整行
key.type("Hello, 世界")                  # Unicode 直输

未列出的特殊键用 vk: 前缀指定 Windows 虚拟键值,0x 前缀为十六进制、无前缀为十进制,有效范围 0x01–0xFF:

key.tap("vk:0x5D")    # 右键菜单键(VK_APPS)
key.tap("vk:0x60")    # 数字小键盘 0
key.tap("Shift+vk:0x5D")

标点键 VK 码基于美式布局

标点符号键的 VK 码按美式 US 键盘布局定义,非 US 布局下物理键位可能不同,此时改用 vk: 数值码指定精确虚拟键值。

macOS 上 key.* 需要「辅助功能」授权

key.tap / key.seq / key.hold / key.release 靠向前台应用注入键盘事件实现,macOS 把这类能力归在辅助功能权限下。未授权时系统会静默吞掉事件——命令看起来执行了,按键却没发出去。到 系统设置 → 隐私与安全性 → 辅助功能 打开「清风输入法」即可,见 macOS 版 · 授权辅助功能。

key.type(文本直输)与 clip.paste 走的是输入法自己的文本插入接口,不需要这项授权。

行为细节

  • 权重:命令短语与普通短语一样默认权重 1000。命令用的精确英文编码极少与自然候选撞码,默认值通常已足够靠前;拼音方案下更应选一个不与自然词碰撞的编码,而非堆高 weight。
  • 自动上屏 / 顶码:纯文本命令(只产出文本)与短语一样可自动上屏、顶码上屏;含副作用的命令不自动上屏,始终等待手动选择,被顶屏时异步执行动作。只有短语的编码(如 date)不参与顶码,也不会被"满码空码清空"误清。
  • 不污染历史:last() 只记录真正上屏的文本。有 type() 的命令进入历史;仅副作用命令(open / proc.run 等)不进入,避免显示文字污染下一次 last()。
  • 显示与执行是两次独立求值:显示名在候选生成时算一遍,动作在选中时再算一遍。所以 uuid()、now() 写在两处会得到两个值。想"切一次并显示新状态",让显示名用 config.get、动作用 config.toggle——把 config.toggle 写进显示名不会切换两次,而是整条候选直接失效(显示名不允许有副作用)。

临时拼音下不查命令短语

进入临时拼音模式后不查询命令短语层,输 zzbd 得到的是拼音候选而非字符组导航。但词库条目内嵌的 $ 语法在临拼下仍会正常展开与执行。

绑到一个键上 0.123 新增

这套表达式不止能写进短语——也可以直接绑到一个键上,按一下就执行,不必先输入编码再选中。写法与语义见按键配置 · 命令直通(配置项 keys.key_actions / keys.session_actions 的 command:<表达式>),图形界面入口见按键设置 · 调用直通命令。

相关阅读

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

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

去提 issue →

本页目录