配置文件

Capslox 的按键方案定义在一个文件中:keymap.jsonc

JSONC = JSON with Comments,支持 // 行注释和 /* */ 块注释(不熟悉 JSON?看 MDN 上的简介)。

文件位置

平台 路径
macOS ~/.config/capslox/keymap.jsonc
Windows %USERPROFILE%\.config\capslox\keymap.jsonc

热重载: 保存文件后配置立即生效,无需重启。如果文件有语法错误,Capslox 会弹出错误提示并保留之前的配置。

跨平台覆盖文件

如果你在 macOS 和 Windows 之间需要不同的按键绑定,可以在配置目录下放置平台专属文件:

平台 覆盖文件
macOS keymap.macos.jsonc
Windows keymap.windows.jsonc

Capslox 启动时,若平台专属文件存在则优先使用,否则回退到 keymap.jsonc。常见场景:通过 iCloud Drive、Dropbox、GNU Stow、chezmoi 等工具跨平台同步 dotfiles。

加载优先级: keymap.macos.jsonc / keymap.windows.jsonc > keymap.jsonc


结构概览

顶层结构:

{
  "version": "1.0",
  "custom_modifiers": { "caps": { "alias": "cx", "tap": "esc" } },
  "vars": {
    "apps_emacs_keybindings": ["com.apple.Terminal", "com.googlecode.iterm2"]
  },
  "layers": [
    {
      "id": "base",
      "on_miss": "pass_to_os",
      "bindings": {
        "cx-e": "up",
        "cx-d": "down",
        "cx-s": "left",
        "cx-f": "right",
        "cx-a": {
          "action": "send_keys",
          "keys": "opt-left",
          "when": { "apps": { "$ref": "/vars/apps_emacs_keybindings" }, "action": "ctrl-[ b" }
        }
      }
    }
  ]
}

配置包含:

  • version:配置结构版本(如 "1.0")。
  • custom_modifiers:可选。将物理按键映射为修饰键别名。默认配置使用 "cx"(取自 Capslox 的首尾字母)。详见自定义修饰键
  • vars:可选。定义可复用的值(数组、字符串),在其他位置通过 { "$ref": "/vars/名称" } 引用。适合在多个绑定间共享应用 ID 列表。
  • layers:层数组。每层包含 id、可选的 name、可选的 activationon_missbindings
  • key_sequence_timeout_ms:可选。按键序列等待下一个键的时长(毫秒),默认 1000。按键计时而非整段计时——每按一次键,计时重新开始。不存在「不超时」这个选项。

层是一组绑定的集合。多个层按顺序排列为栈结构,按下按键时从栈顶向下逐层查找:第一个匹配的绑定会被执行。当某一层没有匹配时,由该层的 on_miss 字段决定是继续向下查找、拦截按键还是直接发送给操作系统。

每个层是一个对象,包含以下字段:

  • id(必需):层的唯一标识符。
  • bindings(必需):按键 → 动作的映射对象。
  • on_miss(必需):未命中行为,详见未命中行为
  • activation:激活方式。基础层不需要;手动层用 { "type": "manual" };自动应用层用 { "type": "auto_app", "bundle_ids": [...] }。详见下方对应小节。
  • name:可读标签,会在偏好设置(Preferences → Keymap)等 UI 中显示。
  • enabled:布尔值,默认 true。设为 false 时引擎跳过此层,等同于该层不存在。适合临时禁用某层而不删除其配置。

层有三种类型:

基础层

基础层始终处于活跃状态,不能在运行时推入或弹出。通过 "id": "base" 标识,无需显式设置 activation 字段。

{
  "id": "base",
  "on_miss": "pass_to_os",
  "bindings": {
    "cx-h": "left",
    "cx-j": "down",
    "cx-k": "up",
    "cx-l": "right"
  }
}

手动层

通过绑定中的 layer_pushlayer_togglelayer_swap 动作激活,通过 layer_pop 或对应的释放事件停用。

{
  "id": "vim_normal",
  "activation": { "type": "manual" },
  "on_miss": "block",
  "bindings": {
    "h": "left",
    "j": "down",
    "k": "up",
    "l": "right",
    "i": { "action": "layer_pop", "target": "vim_normal" },
    "esc": "continue"
  }
}

此例中 on_miss 设为 "block" — 未绑定的按键被拦截,类似 Vim 普通模式。"esc": "continue"esc 穿透到下一层(绕过了 block 的拦截效果)。

自动应用层

当匹配的应用获得焦点时自动激活,失去焦点时自动停用。

{
  "id": "terminal",
  "name": "Terminal Overrides",
  "activation": {
    "type": "auto_app",
    "bundle_ids": ["com.apple.Terminal", "com.googlecode.iterm2"]
  },
  "on_miss": "continue",
  "bindings": {
    "cx-a": "ctrl-a",
    "cx-e": "ctrl-e"
  }
}

应用标识符

平台 格式 示例
macOS Bundle ID com.apple.Terminal
Windows 可执行文件名 WindowsTerminal.exe

通配符匹配规则: 应用标识符里的 * 匹配一个或多个以点分隔的路径段。例如 "com.jetbrains.*" 匹配 com.jetbrains.intellijcom.jetbrains.pycharm,但不匹配 com.jetbrainsxyz。这条规则适用于所有出现 apps 列表的位置,包括 binding 上的 when 子句。


绑定

绑定将按键和动作关联起来。绑定位于层的 bindings 对象中。键是触发键(使用按键语法),值是动作或绑定类型。

"bindings": {
  "cx-h": "left",
  "cx-j": "down",
  "space": {
    "type": "long_press",
    "short": "space",
    "long": { "action": "layer_push", "target": "space_layer" },
    "threshold_ms": 500
  }
}

绑定值的 "type" 字段声明绑定类型(如 "type": "mod_tap""type": "long_press")。当绑定类型是 "action"(直接动作,最常见)时,再用 "action" 字段指明要执行的具体动作(如 "action": "send_keys""action": "layer_push")。

绑定值的写法

绑定值的完整形式是一个对象。当绑定类型为 "action" 时,对象里还有 "action" 字段指明动作类型。

三种等价写法

"type": "action""action": "send_keys" 这两个字段在配置时高频出现。为了方便,Capslox 支持省略——下面三种写法效果完全相同:

"cx-h": { "type": "action", "action": "send_keys", "keys": "left" }  // 完整形式
"cx-h": { "action": "send_keys", "keys": "left" }                    // 省略 type(默认按 action 绑定)
"cx-h": "left"                                                       // 省略整个对象(默认动作就是 send_keys),推荐写法

Mod Tap 与 Long Press

根据按压方式触发不同动作。必须显式写 "type" 字段:

"caps": { "type": "mod_tap", "tap": "esc" }
"space": { "type": "long_press", "short": "space", "long": { "action": "layer_push", "target": "space_layer" } }

详见 Mod TapLong Press

按键序列

触发器可以是依次按下的多个键。段与段之间用空格分隔,或者在键名末尾加 > 并把后续按键嵌套进去:

"cx-m p": { "action": "show_preferences", "label": "Preferences" }
"cx-m>": { "p": { "action": "show_preferences", "label": "Preferences" } }

详见按键序列

指令关键字

三个特殊字符串不是按键语法,而是控制单个按键在层中的未命中行为:

  • "continue":继续查找下一层(忽略该按键在当前层的 on_miss 设置)
  • "block":吞掉按键
  • "pass_to_os":跳过剩余层,直接发送给操作系统
// 在 on_miss: "block" 的层中,让 Escape 穿透到下一层
"esc": "continue"

什么时候写什么

场景 形式
发送按键 "left"(字符串简写)
穿透/拦截/透传 "continue" / "block" / "pass_to_os"(指令关键字)
控制层、剪贴板、窗口等 { "action": "layer_toggle", ... }(动作对象)
需要 when 条件 动作对象 + when
给绑定一个显示名 动作对象 + label
按住修饰键、短按发 Esc { "type": "mod_tap", ... }(按键模式)
长按时推入层 { "type": "long_press", ... }(按键模式)
把一组相关命令收进同一个前缀 "cx-m p""cx-m>"(按键序列)

Mod Tap

按住时充当修饰键,短按时执行动作。

参数:

  • tap:任意动作(字符串简写或对象形式)。
  • timeout_ms:短按判定时长(毫秒),默认 200。

示例:

"caps": { "type": "mod_tap", "tap": "esc", "timeout_ms": 200 }

判定逻辑: 基于中断而非时长。

条件 结果
在超时内释放,期间无其他按键按下 Tap — 触发 tap 动作
按住期间有其他按键按下(任何时间) Hold — 激活为修饰键
超时后释放,期间无其他按键按下 无操作 — 防止误触

Hold 修饰键的身份通过推断确定:如果该键在 custom_modifiers 中有条目,则使用该别名;否则使用物理键名本身作为修饰键。

Long Press

短按执行一个动作,长按(超过阈值)执行另一个动作。纯时长判定——无需与其他按键交互。

参数:

  • short:在阈值前释放时的动作。
  • long:超过阈值时的动作。
  • threshold_ms:时长阈值(毫秒),默认 500。

示例:

"space": {
  "type": "long_press",
  "short": "space",
  "long": { "action": "layer_push", "target": "space_layer" },
  "threshold_ms": 500
}

按键序列

依次按下的多个键,类似 Vim 的 g g。按下第一个键后会弹出一个菜单,列出可选的下一个键,再按其中一个即可执行。

两种写法

序列可以扁平地写,段与段之间用空格分隔;也可以在键名末尾加 > 嵌套着写。两者产生的绑定完全相同:

// 扁平写法——每一段本身都是一个完整的组合键。
"cx-m p": { "action": "show_preferences", "label": "Preferences" }
"cx-m k": { "action": "edit_keymap",      "label": "Edit keymap" }

// 嵌套写法——末尾的 ">" 表示这是个前缀,它的值存放后续按键。
"cx-m>": {
  "p": { "action": "show_preferences", "label": "Preferences" },
  "k": { "action": "edit_keymap",      "label": "Edit keymap" },
  // 块可以继续嵌套:这里是 cx-m,然后 c,然后 1。
  "c>": {
    "1": { "action": "clipboard_paste", "slot": "1", "label": "Paste slot 1" }
  }
}

修饰键不会继承。 嵌套写法里,"cx-m>": { "p": … } 的意思是先按 cx-m,再按单独的 p,而不是 cx-p。块里的每个键都是独立完整的组合键,想要 cx-p 就得照写。

菜单文案

菜单中每一项显示的是该绑定的 label,没有则回退到推导出的名称:

"cx-m p": { "action": "show_preferences" }                              // 菜单显示:show_preferences
"cx-m p": { "action": "show_preferences", "label": "Preferences" }      // 菜单显示:Preferences

计时与中断

等待是按键计时而非整段计时:每按一次键,计时重新开始。上限由顶层的 key_sequence_timeout_ms 设定(默认 1000 毫秒)。

条件 结果
下一个键命中某个后续按键 下潜 —— 菜单显示它之后还能按什么
下一个键什么都没命中 重置 —— 该键被吞掉,既不发给应用,也不会补发
超时前没有按任何键 重置 —— 放弃这段序列
按住最后一个键(系统自动重复) 忽略 —— 自动重复永远不推进序列
当前层发生变化,或 keymap 重新加载 中止 —— 序列丢弃,菜单清空

加载时强制的规则

以下几种写法会在 keymap 加载时被拒绝,而被拒绝的 keymap 不会生效——此前已加载的那份继续保持活动:

  • 同一层内,一个键要么是终点要么是前缀,不能两者兼任。 同时绑定 gg g 属于冲突:按下 g 不可能既表示「立刻执行」又表示「等下一个键」。
  • 指令不能作为序列的终点。 "continue""block""pass_to_os" 描述的是单个按键的未命中行为,放在序列末尾没有意义。它们在单个组合键上依然有效。
  • > 只能是键名的最后一个字符。 "cx>m""cx-m>>" 都是错误。

标签

绑定的可选显示名,用在 Capslox 需要把绑定展示给你、而不是执行它的地方。任何动作绑定都能带一个,写成对象形式即可;字符串简写没有地方放它。

"cx-shift-,": { "action": "show_preferences", "label": "Preferences" }

不写 label 时,Capslox 会从动作本身推导出名称:显示 show_preferences 而不是 Preferences

When 子句

让绑定根据前台应用的不同执行不同动作。在任意直接绑定上添加 when 字段。

// 单条件
"cx-a": {
  "action": "send_keys",
  "keys": "opt-left",
  "when": {
    "apps": ["com.apple.Terminal", "com.googlecode.iterm2"],
    "action": "ctrl-[ b"
  }
}

当前台应用匹配 apps 中的某个 Bundle ID 时,使用 when 中的动作代替默认动作。

使用 $ref 共享应用列表

"cx-a": {
  "action": "send_keys",
  "keys": "opt-left",
  "when": {
    "apps": { "$ref": "/vars/apps_emacs_keybindings" },
    "action": "ctrl-[ b"
  }
}

这引用了顶层 vars 对象中定义的 apps_emacs_keybindings 数组。

多条件

按顺序检查,首次匹配生效:

"cx-cmd-a": {
  "action": "send_keys",
  "keys": "opt-left*5",
  "when": [
    {
    "apps": { "$ref": "/vars/apps_emacs_keybindings" },
      "action": "(ctrl-[ b)*5"
    },
    {
      "apps": ["com.jetbrains.*"],
      "action": "alt-left*5"
    }
  ]
}

apps 中的通配符使用自动应用层中定义的点号边界匹配规则。

如果没有 when 条件匹配,则使用绑定的默认动作。

特殊 when 动作

使用 "noop" 作为 when 动作,在特定应用中屏蔽按键而不让其穿透:

"cx-i": {
  "action": "send_keys",
  "keys": "shift-up",
  "when": {
    "apps": { "$ref": "/vars/apps_emacs_keybindings" },
    "action": "noop"
  }
}

与 AutoApp 层的关系: when 用于"同一触发键,不同应用不同输出"。AutoApp 层用于"特定应用中完全不同的绑定集"。两者可以共存。

未命中行为

每层的 on_miss 字段控制当某个按键在该层没有匹配绑定时的行为。

行为 适用场景
"continue" 检查栈中的下一层(默认) 叠加层(如某 App 专属覆盖层),只处理部分按键,其余按键交给下一层
"block" 拦截按键 — 不做任何事 手动激活的临时层(如游戏地图、IDE 命令模式),避免误触
"pass_to_os" 跳过剩余层,将原始按键发送给操作系统 基础层,让未绑定的按键正常发给系统
{
  "id": "vim_normal",
  "activation": { "type": "manual" },
  "on_miss": "block",
  "bindings": { ... }
}

单个绑定可以通过指令关键字忽略该按键所在层的 on_miss 设置:

// 即使 on_miss 为 "block",Escape 也会穿透到下一层
"esc": "continue"

// 强制某个按键直接传递给操作系统,跳过所有剩余层
"f5": "pass_to_os"

完整指令关键字列表见上方绑定值的三种形式章节。


动作

每个绑定都会触发一个动作。动作使用 "action" 字段作为类型标识。动作出现在绑定的值一侧,以及按键模式的字段中(tapshortlong)。

可用动作

Capslox 通用

动作 说明
show_preferences 打开 Capslox 偏好设置
edit_keymap 打开内置的 keymap 编辑器

层切换

动作 说明
layer_push 推入层(触发键释放时停用)
layer_pop 弹出层(或栈顶层)
layer_toggle 切换层的开关状态
layer_swap 用目标层替换栈顶非 base 层

组合与控制

动作 说明
shell_action 执行 shell 命令
action_sequence 按顺序执行多个动作
noop 屏蔽按键(不做任何事)

输入与状态

动作 说明
send_keys 发送按键
toggle_caps_lock 切换 Caps Lock 开关

窗口

动作 说明
bind_window 将当前窗口绑定到槽位
activate_window 激活或最小化绑定到槽位的窗口

剪贴板

动作 说明
clipboard_copy 复制到命名剪贴板槽位
clipboard_cut 剪切到命名剪贴板槽位
clipboard_paste 从命名剪贴板槽位粘贴
clipboard_paste_plain 从剪贴板槽位粘贴纯文本

show_preferences

打开 Capslox 偏好设置窗口。

示例:

"cx-shift-,": { "action": "show_preferences" }

edit_keymap

打开内置的 keymap 编辑器。

示例:

"cx-shift-/": { "action": "edit_keymap" }

layer_push

将一层推入栈。该层在触发键释放时自动停用。

参数:

  • target(string):要推入的层 id

示例:

"cx-v": { "action": "layer_push", "target": "vim_normal" }

layer_pop

从栈中弹出一层。

参数:

  • target(string,可选):要移除的层 id。省略则弹出栈顶;指定时从栈中任意位置移除该 id 的层。

示例:

"i":   { "action": "layer_pop", "target": "vim_normal" }
"esc": { "action": "layer_pop" }

layer_toggle

切换一层:未激活则激活,已激活则停用。

参数:

  • target(string):要切换的层 id

示例:

"cx-t": { "action": "layer_toggle", "target": "symbols" }

layer_swap

原子地移除栈顶非 base 层,并将 target 层推入其位置。如果当前只有 base 层活跃,swap 会将 target 作为新的栈顶推入。

参数:

  • target(string):要推入为新栈顶的层 id

示例:

"cx-s": { "action": "layer_swap", "target": "numbers" }

shell_action

执行 shell 命令。发后即忘——命令在后台运行,不捕获输出。

参数:

  • command(string):要执行的 shell 命令。

示例:

// ───── macOS(POSIX shell, /bin/sh)─────

// 启动应用、URL、文件夹
"cx-cmd-t":   { "action": "shell_action", "command": "open -a Terminal" }
"cx-shift-c": { "action": "shell_action", "command": "open -a 'Google Chrome'" }
"cx-shift-g": { "action": "shell_action", "command": "open https://github.com" }
"cx-shift-h": { "action": "shell_action", "command": "open ~" }
"cx-shift-p": { "action": "shell_action", "command": "code ~/path/to/your/repo" }

// 读 / 写剪贴板
"cx-shift-s": { "action": "shell_action", "command": "open \"https://www.google.com/search?q=$(pbpaste)\"" }
"cx-shift-i": { "action": "shell_action", "command": "open \"$(pbpaste)\"" }
"cx-shift-d": { "action": "shell_action", "command": "date | pbcopy" }

// 截图、休眠、通知
"cx-shift-4": { "action": "shell_action", "command": "screencapture -i ~/Desktop/screen-$(date +%Y%m%d-%H%M%S).png" }
"cx-shift-l": { "action": "shell_action", "command": "pmset displaysleepnow" }
"cx-shift-b": { "action": "shell_action", "command": "osascript -e 'display notification \"Build done\" with title \"Capslox\"'" }

// 切换 macOS 暗黑模式
"cx-shift-m": {
  "action": "shell_action",
  "command": "osascript -e 'tell app \"System Events\" to tell appearance preferences to set dark mode to not dark mode'"
}

// ───── Windows(cmd.exe)— JSON 字符串里反斜杠要写成 \\ ─────

// 打开 URL、文件夹、文件(`start` 用默认应用打开目标)
"cx-shift-g": { "action": "shell_action", "command": "start \"\" https://github.com" }
"cx-shift-h": { "action": "shell_action", "command": "explorer \"%USERPROFILE%\"" }
"cx-shift-i": { "action": "shell_action", "command": "start \"\" \"%USERPROFILE%\\Documents\\notes.md\"" }
"cx-shift-p": { "action": "shell_action", "command": "code \"%USERPROFILE%\\projects\\myrepo\"" }

// 把字面字符串写入剪贴板(`clip` 是 Windows 内置命令)
"cx-shift-c": { "action": "shell_action", "command": "echo Hello from Capslox| clip" }

// 锁屏
"cx-shift-l": { "action": "shell_action", "command": "rundll32.exe user32.dll,LockWorkStation" }

工作方式

系统 Shell 命令
macOS /bin/sh(登录 shell) /bin/sh -l -c "{command}"
Windows cmd.exe cmd /C {command}
  • 在用户主目录下运行(macOS 为 $HOME,Windows 为 %USERPROFILE%)。
  • 在 macOS 上,/bin/sh 是 POSIX shell(大多数系统上为 bash 的 sh 兼容模式)。它使用默认 shell(如 fish、zsh)——始终调用 /bin/sh
  • 在 Windows 上,cmd.exe 不是 bash —— 不支持 bash 的 $(...) 命令替换、POSIX glob 通配,也不能用单引号字符串。如果需要把动态值(比如剪贴板内容)传入管道,请显式调用 PowerShell:powershell -NoProfile -Command "<pipeline>"
  • PATH 与环境变量:
    • macOS:/bin/sh -l 会读取 .profile / .bash_profile。如果你日常用 fish 或 zsh 并在其中设置 PATH,npmcargocode 等命令可能不会被 shell_action 找到,除非它们也在 /bin/sh 的 PATH 中。
    • Windows:cmd.exe 不读取任何 shell rc 文件。PATH 来自系统与用户环境变量(设置 → "编辑系统环境变量")。添加新工具到 PATH 后需要重启 Capslox 才能生效。
  • 不捕获输出。如果命令失败,退出码会被内部记录(ShellAction exited with code N)。
  • 一次性:命令被 spawn 后即被遗忘。无法从 Capslox 中终止或等待它。

不适用于 交互式命令、长时间运行的监视工具,或依赖特定 shell 环境的命令。


action_sequence

按顺序执行多个动作。当单一动作类型无法满足需求时使用。

参数:

  • actions(array):非空动作列表。每个元素可以是字符串简写(解析为 send_keys)或完整动作对象。

示例:

// 把当前日期写入剪贴板,然后粘贴。
"cx-shift-d": {
  "action": "action_sequence",
  "actions": [
    { "action": "shell_action", "command": "date | pbcopy" },
    "cmd-v"
  ]
}

noop

抑制按键,不执行任何操作。

示例:

"cx-q": "noop"

在叠加层中用于屏蔽特定按键,防止其传递到下层。也常用于 when 子句中,在特定应用中屏蔽某个绑定(默认动作在那些应用里没有意义)。


send_keys

发送一个或多个按键事件。最常用的动作类型。

参数:

  • keys(string):按键语法字符串,一个或多个组合键,可选地带重复和分组。详见下方按键语法。

示例:

// 字符串简写(推荐——因为 send_keys 是默认动作,可省略整个对象)
"cx-h":     "left"
"cx-cmd-a": "alt-left*5"

// 需要 when 子句时必须用对象形式
"cx-a": {
  "action": "send_keys",
  "keys": "opt-left",
  "when": { "apps": { "$ref": "/vars/apps_emacs_keybindings" }, "action": "ctrl-[ b" }
}

按键语法

  • 单个组合键:leftsuper-shift-4
  • 多组合键(空格分隔,顺序执行):super-shift-left backspace
  • 重复(组合键后加 *N):alt-left*5
  • 分组重复((组合键)*N):(ctrl-[ b)*5

规则:

  • 不带括号的 *N 只重复紧前面的单个组合键。
  • (组合键)*N 将组合键分组并重复整组。
  • 不支持嵌套:((...)...)*N 无效。
  • 最大重复次数:100。

常用组合键

节选自默认方案,可直接复制。

macOS:

// 光标移动
"cx-e":     "up"             // 上
"cx-d":     "down"           // 下
"cx-s":     "left"           // 左
"cx-f":     "right"          // 右
"cx-a":     "opt-left"       // 按词向左
"cx-g":     "opt-right"      // 按词向右
"cx-p":     "cmd-left"       // 跳到行首
"cx-;":     "cmd-right"      // 跳到行尾
"cx-cmd-p": "cmd-up"         // 跳到文档开头
"cx-cmd-;": "cmd-down"       // 跳到文档结尾

// 文本选择
"cx-i":     "shift-up"       // 选中上一行
"cx-k":     "shift-down"     // 选中下一行
"cx-j":     "shift-left"     // 选中左一字符
"cx-l":     "shift-right"    // 选中右一字符
"cx-h":     "shift-opt-left" // 选中左一词
"cx-.":     "shift-opt-right"// 选中右一词
"cx-u":     "shift-cmd-left" // 选中至行首
"cx-o":     "shift-cmd-right"// 选中至行尾

// 删除
"cx-w":     "backspace"      // 向前删除一个字符
"cx-r":     "delete"         // 向后删除一个字符
"cx-cmd-w": "opt-backspace"  // 向前删除一个词
"cx-cmd-r": "opt-delete"     // 向后删除一个词

Windows:

// 光标移动
"cx-e":     "up"
"cx-d":     "down"
"cx-s":     "left"
"cx-f":     "right"
"cx-a":     "ctrl-left"      // 按词向左
"cx-g":     "ctrl-right"     // 按词向右
"cx-p":     "home"           // 跳到行首
"cx-;":     "end"            // 跳到行尾
"cx-alt-p": "ctrl-home"      // 跳到文档开头
"cx-alt-;": "ctrl-end"       // 跳到文档结尾

// 文本选择
"cx-i":     "shift-up"
"cx-k":     "shift-down"
"cx-j":     "shift-left"
"cx-l":     "shift-right"
"cx-h":     "shift-ctrl-left"  // 选中左一词
"cx-.":     "shift-ctrl-right" // 选中右一词
"cx-u":     "shift-home"       // 选中至行首
"cx-o":     "shift-end"        // 选中至行尾

// 删除
"cx-w":     "backspace"
"cx-r":     "delete"
"cx-alt-w": "ctrl-backspace"   // 向前删除一个词
"cx-alt-r": "ctrl-delete"      // 向后删除一个词

toggle_caps_lock

切换操作系统的 Caps Lock 状态。

示例:

"cx-shift-c": { "action": "toggle_caps_lock" }

将窗口绑定到命名槽位,便于瞬时切换或最小化。

bind_window

将当前窗口绑定到命名槽位。

参数:

  • slot(string):窗口槽位名称。

示例:

"cx-cmd-1": { "action": "bind_window", "slot": "1" }

activate_window

激活绑定到命名槽位的窗口。如果该窗口已是最前窗口,则最小化它(toggle 行为)。

参数:

  • slot(string):窗口槽位名称。

示例:

"cx-1": { "action": "activate_window", "slot": "1" }

Capslox 提供独立于系统剪贴板的命名剪贴板槽位。槽位名是任意字符串。

clipboard_copy

将当前选区复制到命名剪贴板槽位。

参数:

  • slot(string):剪贴板槽位名称。

示例:

"cx-c": { "action": "clipboard_copy", "slot": "1" }

clipboard_cut

将当前选区剪切到命名剪贴板槽位。

参数:

  • slot(string):剪贴板槽位名称。

示例:

"cx-x": { "action": "clipboard_cut", "slot": "1" }

clipboard_paste

从命名剪贴板槽位粘贴,保留格式。

参数:

  • slot(string):剪贴板槽位名称。

示例:

"cx-v": { "action": "clipboard_paste", "slot": "1" }

clipboard_paste_plain

从命名剪贴板槽位粘贴纯文本,去除格式。

参数:

  • slot(string):剪贴板槽位名称。

示例:

"cx-shift-v": { "action": "clipboard_paste_plain", "slot": "1" }

按键词汇表

完整按键词汇表。所有名称均为小写。用于绑定键、按键序列字符串和 custom_modifiers

字母: a b c d e f g h i j k l m n o p q r s t u v w x y z

数字: 0 1 2 3 4 5 6 7 8 9

方向键: up down left right

导航键: home end pageup pagedown

功能键: f1 f2 f3 f4 f5 f6 f7 f8 f9 f10 f11 f12

控制键

键名 说明
space 空格键
enter 回车键
tab Tab 键
esc Escape 键
backspace 向后删除(macOS 的 Delete 键)
delete 向前删除(macOS 的 Fn+Delete)
caps Caps Lock 键

安全符号键

直接使用字面字符。

键名 字符
[ 左方括号
] 右方括号
/ 斜杠
= 等号
, 逗号
. 句点
; 分号
' 撇号

命名符号键

这三个字符在按键语法中有特殊含义,对应物理键用单词形式。

键名 物理按键 原因
minus - 组合键分隔符
backslash \ JSON 转义符
backtick ` 视觉容易混淆

小键盘

键名 说明
kp_0kp_9 小键盘数字
kp_enter 小键盘回车
kp_plus 小键盘 +
kp_minus 小键盘 -
kp_multiply 小键盘 *
kp_divide 小键盘 /
kp_decimal 小键盘 .
kp_equal 小键盘 =
kp_clear 小键盘 Clear

按键语法:- 组合修饰键和按键:

"ctrl-shift-a"    // Ctrl + Shift + A
"cmd-left"        // Command + 左箭头
"shift-/"         // Shift + /
"cmd-minus"       // Command + -

修饰键顺序: 修饰键可以任意顺序书写——ctrl-shift-ashift-ctrl-a 等价。建议的书写顺序为:自定义修饰键 → capsctrlaltshiftcmd(参考 Apple HIG)。

修饰键

修饰键在按键语法中作为前缀使用:修饰键-按键。各平台习惯不同的命名,两种写法都接受,建议使用对应平台的名称,配置在该平台读起来更自然:

修饰键 macOS Windows
Control ctrl ctrl
Shift shift shift
Option / Alt opt alt
Command / Win cmd win

任意修饰键加 _left / _right 后缀即指定侧别,例如 opt_leftcmd_rightctrl_left。不加后缀表示任意一侧。

"ctrl_right-a"   // 仅右 Ctrl + A
"ctrl-a"         // 任意一侧 Ctrl + A

跨平台别名 super 同时匹配 macOS 的 cmd 和 Windows 的 win,便于在跨平台 keymap 中使用统一的修饰键名。

Windows 用户注意: Windows 系统保留 Win 键组合(如 Win+R、Win+D)作为系统级快捷键。根据 Microsoft 官方文档,涉及 Win 键的键盘快捷键保留给操作系统使用。所以建议 Windows 上的快捷键尽量避免使用 win,改用 alt 等不冲突的修饰键组合。

自定义修饰键

任何物理按键都可以通过 custom_modifiers 成为修饰键。

字段:

  • alias:在绑定中使用的修饰键名(如 cx-h)。
  • tap:短按释放时触发的动作。接受任意动作:字符串简写(解析为 send_keys,例如 "esc")或完整动作对象(引擎原生动作如 toggle_caps_lock 必须用对象形式)。默认值是按键本身。
  • timeout_ms:短按判定时长(毫秒),默认 200。

三种写法

为减少书写量,custom_modifiers 支持逐层省略——下面三种写法引擎都接受:

// 完整形式
"custom_modifiers": {
  "caps": { "alias": "cx", "tap": { "action": "toggle_caps_lock" }, "timeout_ms": 300 }
}

// 省略默认值(等价于 { "alias": "cx", "tap": "caps", "timeout_ms": 200 },短按 Caps Lock 发送 Caps Lock)
"custom_modifiers": {
  "caps": { "alias": "cx" }
}

// 字符串简写(只需别名时的最简形式,短按保持原按键行为)—— 推荐
"custom_modifiers": {
  "caps": "cx"
}

自动 mod_tap 回退

custom_modifiers 中声明的按键自动获得 mod_tap 行为——按住时充当修饰键,短按时执行 tap 动作。换句话说,配置 custom_modifiers 之后不需要再单独写一条 mod_tap 绑定,省去重复:

{
  "custom_modifiers": { "caps": { "alias": "cx", "tap": "esc" } },
  "layers": [{
    "id": "base",
    "on_miss": "pass_to_os",
    "bindings": {
      // 不需要 "caps": { "type": "mod_tap", ... }!
      // 按住 Caps = cx 修饰键,短按 Caps = Escape(来自 custom_modifiers)
      "cx-h": "left",
      "cx-j": "down"
    }
  }]
}

如果某层为该键设置了显式绑定,显式绑定优先于回退行为。

多对一别名

多个物理按键可以共享同一个别名。最实用的场景:默认方案用 caps 作为 cx 修饰键,但 HHKB 等紧凑键盘没有 Caps Lock 键。把 tab 也设为 cx,就能瞬间继承所有现有绑定,不必为新键盘重做配置:

"custom_modifiers": {
  "caps": "cx",
  "tab": "cx"
}

现在 capstab 都激活 cx 修饰键。无论按住哪个,cx-h 都会触发。

别名可以使用任何符合按键命名规范的名称(小写字母、数字、下划线)。cx 是默认惯例,取自 Capslox 的缩写。


常见错误

绑定不符合预期时的快速排查清单:

  • 物理按键名 vs Shift 后字符:写 shift-/ 而不是 ?,写 shift-[ 而不是 {,写 shift-1 而不是 !。按键以 US QWERTY 物理位置命名(参见按键词汇表)。
  • 三个键必须用单词形式minus(不是 -)、backslash(不是 \)、backtick(不是 `)——它们分别与组合键分隔符、JSON 转义、TS 模板字面量冲突。
  • 连接方式:修饰键与按键之间用 -,例如 cx-h 是 cx + h 的组合键。
  • 引擎原生动作必须用对象形式toggle_caps_locklayer_pushshell_action、剪贴板与窗口类动作都不支持字符串简写,必须写 { "action": "..." }。字符串简写仅限 send_keys(任意按键语法)、"noop",以及三个指令关键字 "continue" / "block" / "pass_to_os"
  • 一个键不能既是快捷键又是序列前缀:同一层里同时绑定 gg g 会被拒绝,而被拒绝的 keymap 完全不会生效——于是所有绑定都停在旧版本上。详见按键序列
  • 嵌套序列不继承修饰键"cx-m>": { "p": … }cx-m 然后单独的 p