命令直通车
让短语与词库条目在选中时执行动作——打开网址、启动程序、模拟按键、切换输入法状态
命令直通车(Command Bar)把短语 / 用户词库 / 系统词库的条目从"展开成文本"升级为"执行带副作用的动作":打开 URL、启动程序、模拟按键、写入剪贴板、加词到用户库、切换输入法状态等,让输入法兼作快捷命令启动器。
如何触发
命令用一段英文字母编码触发:输入编码 → 候选区出现命令条目 → 选中即执行。
| 输入 | 选中后 |
|---|---|
cobd | 用默认浏览器打开 baidu.com |
cojk | 输出 「」,光标停在中间,可用跳出键越过 |
coac | 把剪贴板内容加入用户词库 |
coen | 切换中英文模式 |
系统短语包已内置一批以 co 开头的示例命令,可在 设置 → 词库 → 短语 中浏览、开关或仿写。
触发码只能是英文字母
数字键会被"选中第 N 候选"逻辑吃掉,中文标点在按键阶段就被转换,二者都进不了短语层。因此触发码只能用 ASCII 字母(如 cobd),既不能含数字,也不能用中文标点。想携带查询内容时,用 clip() / last() 等数据源,而不是把词跟在编码后面。
编写位置
命令短语可放在三处,都会自动解析:
| 位置 | 作用范围 | 入口 |
|---|---|---|
| 快捷短语 | 全局,跨方案有效 | 设置 → 词库 → 短语 |
| 用户词库 | 仅当前方案 | 设置 → 词库 → 方案 → 用户词库 |
| 系统词库 | 仅当前方案 | 设置 → 词库 → 方案 → 系统词库 |
推荐放快捷短语
绝大部分命令放快捷短语,拼音 / 五笔 / 混输下都可用。只有方案专属的命令才放用户词库。
四种标记
短语与词库条目共用一个 text 字段,靠内容形式区分类型。命令能力通过以 $ 开头的标记触发。
| 标记 | 含义 | 前缀输入时 | 完整编码时 |
|---|---|---|---|
$CC(显示名, 动作...) | 命令,仅精确匹配 | 不显示 | 显示 |
$CC1(显示名, 动作...) | 命令,精确 + 前缀都显示 | 显示 | 显示 |
$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")))$AA 是 $SS 的字符串简写:$AA 自动按字符拆开,$SS 显式列举每个元素,元素既可是字符串(选中上屏),也可是嵌入的 $CC(...)(选中执行动作)。输入前缀(如 zz)看到组名导航条目,选中后自动补全到完整码进入二级选择;输入完整码(如 zzbd)直接展开为成员候选。
表达式语法
$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 的怪字符串,而且看不出哪里错了。
别靠「试出来能用」判断
路径写单反斜杠时能否工作,取决于下一个字母恰好是不是转义字母。同一条短语换个目录名就可能失效,且失败时只弹一句「命令执行失败」,不会告诉你是反斜杠的问题。统一写 \\,不要逐条去试。
内部目录变量
不想硬编码安装位置或用户名(换台机器、换个盘符就失效),可以用 ${变量名} 引用输入法自己的目录:
| 变量 | 指向 | 典型位置 |
|---|---|---|
${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()}", 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("数学", "+-<=>±×÷∈∏∑")内置函数参考
所有函数都返回字符串,动作函数返回空串。记号:s 字符串、n 整数、参数后 ? 表示可选。
取值函数(纯函数)
| 函数 | 说明 |
|---|---|
code() / code(n) | 触发编码(第 n 字符起到末尾) |
tail(s, n) | 字符串 s 从第 n 字符起到末尾 |
last() / last(n) | 最近 / 倒数第 n 次上屏文本 |
clip() | 当前剪贴板文本 |
clip(n) | 剪贴板历史第 n 条——尚未实现,参数被忽略,等同 clip() |
app() / title() / sel() | 前台进程名 / 窗口标题 / 选中文本——Windows 上均返回空串(仅 macOS 上报) |
date(fmt) / date(fmt, offset) | 日期,offset 形如 "+1d"、"-2w"、"+3M"、"-1y" |
time() / time(fmt) | 时间,默认 "HH:mm:ss" |
now() | 等价 date("YYYY-MM-DD HH:mm:ss") |
env(name) | 环境变量,如 env("USERNAME") |
config.get(key) | 读取配置项当前值 |
文本处理(纯函数)
| 函数 | 说明 |
|---|---|
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) | 正则替换(RE2 语法) |
split(s, sep, n) | 拆分取第 n 段(1 起,支持负数) |
concat(...) | 拼接 |
reverse(s) | 反转(按 rune) |
url(s) / html(s) / json(s) / base64(s) | URL / HTML / JSON / Base64 编码 |
default(s, fallback) | s 为空时返回 fallback |
计算与内省
| 函数 | 说明 |
|---|---|
calc(expr) | 数学表达式求值,支持 + - * / % ( )、浮点 |
num(s, base) | 进制转换(2/8/10/16),如 num("0xff", 10) → "255" |
help(name) | 返回指定函数的简介 |
以下函数已注册但尚未实现
调用它们不会报错,但拿不到预期结果,请勿写进日常短语:
t2s(s)/s2t(s)/pinyin(s)—— 占位实现,原样返回输入ask(prompt)/pick(...)—— 交互式弹窗,未实现clip(n)的历史查询、proc.shell的 flags 参数
动作函数(有副作用)
部分函数有等价别名(run = proc.run、shell = proc.shell、search = web.search、dict.addword = dict.add、ime.setting = setting.open),推荐写规范名。
| 函数 | 副作用 |
|---|---|
type(s) | 经 TSF 上屏文本,不污染剪贴板 |
open(target) | 打开 URL / 文件 / 程序(http(s) 走浏览器,其他走 ShellExecute) |
proc.run(cmd, ...args, cwd?, verb?, show?) | 异步启动进程,三个具名参数见下 |
proc.shell(cmdline, flags?, cwd?) | 执行 shell 命令,flags 见下、cwd 见下 |
key.tap(combo) / key.seq(...combos) | 单次按键 / 按键序列 |
key.hold(combo) / key.release(combo) | 按下 / 抬起(须成对使用) |
key.type(text) | Unicode 直输,绕过键盘布局(走 SendInput,非 TSF) |
clip.copy(s) / clip.paste() | 写入剪贴板 / 模拟 Ctrl+V |
dict.add(s) / dict.add(s, code) | 加词到用户库(编码自动推导或指定) |
ime.toggle(target) | 切换状态:cn-en / fullshape / layout / candwin / s2t / preedit / toolbar |
ime.schema(id) | 切换并持久化方案,如 "wubi86" / "pinyin" |
ime.theme(name) / ime.theme_cycle(dir?) | 切换主题 / 循环切换(dir ∈ next / prev) |
ime.undo_commit() | 撤销上屏:删除最近一次上屏的内容,见下文 |
ime.pair(left, right, jump?) | 上屏配对符号:光标落两段之间,可用跳出键越过右段,见下文 |
setting.open(page, args?) / setting.web(page, args?) | 打开设置的指定页(page 见下;args 为附加命令行参数;setting.web 已废弃,等价于 setting.open) |
web.search(engine, q) | 打开搜索页,engine ∈ baidu / bing / google / zdic |
config.set(key, value) / config.toggle(key) | 写入配置 / 循环切换枚举或翻转布尔(返回新值) |
wind.cli(...) | 调用命令行子命令,见下文 |
proc.shell 的 flags 暂未区分
term / pwsh 等 flag 参数当前被忽略,一律走默认 shell(Windows 为 cmd /C)。写了不报错,但不会得到可见 console 或 PowerShell。
工作目录: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 | 关于 |
""(空串) | 默认页 |
cost = $CC("打开设置", setting.open(""))
codc = $CC("词库管理", setting.open("dict"))未知 id 会被设置端忽略并落到默认页。setting.web(page) 是等价别名(旧 Web 版设置已废弃)。
附加参数: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("「", "」"))
cozs = $CC("注释", ime.pair("<!--", "-->"))两段都可以是任意文本,不限于单个符号:
输入后: <!--|-->
按 Tab: <!---->|jump:跳出时光标右移的格数。 省略时按右段的字符数推导("-->" → 3),一般不用写。它存在是因为跳出靠合成方向键,而"一次右键越过多少内容"是宿主行为——多数宿主一次跨整个 emoji,少数按编码单元走。若在某个程序里发现跳出后光标位置差了几格,用它手动校准:
cozs = $CC("注释", ime.pair("<!--", "-->", jump=3))分级跳出:同一条词条里写多个 ime.pair 即可,无需额外语法。后写的是内层,跳出时也先出内层:
cokh = $CC("(【】)", ime.pair("(", ")"), ime.pair("【", "】"))
输入后: (【|】)
按 Tab: (【】|) ← 出内层
按 Tab: (【】)| ← 出外层受「标点配对」总开关约束
ime.pair 跟着设置 → 标点配对的开关走(中文模式看中文配对、英文模式看英文配对)。关掉时它退化为纯上屏:整串照常上屏,但光标落在末尾、也不能跳出。
另外,「输入右符号跳出」对它不生效——那条路径只认单个标点按键。ime.pair 压入的配对只能用 Tab / Enter 跳出。
撤销上屏: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 启动子进程后不回收输出与退出码。命令失败时没有任何提示——短语看起来正常执行了,实际可能什么都没做。
调试新命令时,请先在终端里手动跑一遍确认无误,再写进短语。
从短语调用时输入法服务必然在线,所以 schema / dict / phrase / backup 这些需要在线的子命令都能正常连上。
改配置优先用 config.set,不要绕 wind.cli
config.set(key, value) 与 wind.cli("config set ...") 效果相同,但前者在进程内直接生效并能拿到错误,后者是发射后不管。改配置一律用 config.set / config.toggle。
按键 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: 数值码指定精确虚拟键值。
行为细节
- 权重:命令短语与普通短语一样默认权重 1000。命令用的精确英文编码极少与自然候选撞码,默认值通常已足够靠前;拼音方案下更应选一个不与自然词碰撞的编码,而非堆高 weight。
- 自动上屏 / 顶码:纯文本命令(只产出文本)与短语一样可自动上屏、顶码上屏;含副作用的命令不自动上屏,始终等待手动选择,被顶屏时异步执行动作。只有短语的编码(如
date)不参与顶码,也不会被"满码空码清空"误清。 - 不污染历史:
last()只记录真正上屏的文本。有type()的命令进入历史;仅副作用命令(open/proc.run等)不进入,避免显示文字污染下一次last()。 - 副作用会求值两次:
$CC的显示名和动作里的表达式都会被求值。若在两处各写一次config.toggle会切换两次(净效果为零)。想"切一次并显示新状态",让显示名用config.get、动作用config.toggle。
临时拼音下不查快捷短语
进入临时拼音模式后不查询快捷短语层,输 zzbd 得到的是拼音候选而非字符组导航。但词库条目内嵌的 $ 语法在临拼下仍会正常展开与执行。