配置文件

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

层是一组绑定的集合。多个层按顺序排列为栈结构,按下按键时从栈顶向下逐层查找:第一个匹配的绑定会被执行。当某一层没有匹配时,由该层的 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

指令关键字

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

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

什么时候写什么

场景 形式
发送按键 "left"(字符串简写)
穿透/拦截/透传 "continue" / "block" / "pass_to_os"(指令关键字)
控制层、剪贴板、窗口等 { "action": "layer_toggle", ... }(动作对象)
需要 when 条件 动作对象 + when
按住修饰键、短按发 Esc { "type": "mod_tap", ... }(按键模式)
长按时推入层 { "type": "long_press", ... }(按键模式)

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
}

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"