公司动态
在 Arch Linux 上模拟 macOS 键盘习惯:keyd + Sway + WezTerm 配置实录
一、目标在 ThinkPad E490Arch Linux Sway 1.12上实现 macOS 风格的键盘操作键帽期望行为win 键帽当 Sway 的$mod窗口管理 复制粘贴CtrlShiftC/Vctrl 键帽当 Ctrl终端中断^C、CtrlZ 撤销alt 键帽当 AltmacOS 的 opt 键关键约束win 键帽同时承担两个角色——给Sway当 Super/Mod4$mod触发窗口管理快捷键给WezTerm当 CtrlShift触发复制粘贴等编辑操作二、技术栈组件版本作用keyd2.4.3内核级键位重映射不依赖桌面环境Sway1.12Wayland 平铺窗口管理器WezTerm2026-07-16 (git)GPU 加速终端跨平台配置三、踩坑实录坑 1keyd 的物理键命名与键帽印字不一致现象在 ThinkPad 内置键盘上物理位置的 win 键帽keyd 内部叫leftalt物理位置的 alt 键帽keyd 内部叫leftmeta。诊断方法用sudo keyd monitor实时查看按键输出keyd virtual keyboard leftalt down ← 你按的是 win 键帽 keyd virtual keyboard leftmeta down ← 你按的是 alt 键帽 keyd virtual keyboard leftcontrol down ← 你按的是 ctrl 键帽结论keyd 配置必须按keyd 内部名写不能按键帽印字写。ThinkPad 上win 键帽 leftaltkeyd 内部alt 键帽 leftmetakeyd 内部ctrl 键帽 leftcontrolkeyd 内部坑 2keyd layer 的:M后缀与编辑键冲突第一次尝试用[winmod:M]让 win 键帽模拟 Super然后在里面定义c C-c。结果keyd monitor 显示 winc 输出leftmeta leftcontrol cSuperCtrlc而不是纯 Ctrlc。:M后缀让 layer 模拟 SuperC-c又叠加了 Ctrl结果是 SuperCtrlc。正确做法不用:M后缀模拟 Super改为在[winmod]layer 里显式发 Superkeyenter M-enter等对编辑键 c/v/x/a/z/s 发macro(C-S-c)等CtrlShiftkey这样 winc 就是干净的CtrlShiftcwinEnter 是SuperEnter给 Sway 当$mod。坑 3WezTerm 复制粘贴的默认绑定是 CtrlShiftC/V现象配置好 keyd 后winc 在 WezTerm 里吐出^C中断信号winv 显示^V字面字符都不是复制粘贴。原因WezTerm 的复制/粘贴默认绑定是CtrlShiftC/CtrlShiftV不是CtrlC/CtrlV。CtrlC在终端里是 SIGINT 中断信号。解决在 keyd 的[winmod]layer 里把 c/v/x/a/z/s 映射成macro(C-S-c)/macro(C-S-v)等CtrlShiftkey匹配 WezTerm 的复制粘贴绑定。坑 4旧版 wezterm (2024-02) 与 Sway 1.12 wl_shm 协议不兼容现象运行wezterm报错[wayland-client error] Attempted to dispatch unknown opcode 0 for wl_shm, aborting.WezTerm 启动后立即崩溃。原因Arch 官方仓库的wezterm是 2024-02 版本 (20240203.110809.5046fc22-2)与 Sway 1.12 的wl_shm协议版本不兼容。解决改用 AUR 的wezterm-git包编译安装最新 git 版本2026-07-16wl_shm 错误消失。坑 5SSH heredoc 吞掉$变量现象通过 SSH 写 Sway 配置后Sway 报Invalid set command: expected at least 2 arguments, got 1。原因ssh host cat file EOF外层双引号让本地 shell 先展开了$mod、$term、$menu变量空字符串传到远端时set $mod Mod1变成了set Mod1。解决外层用单引号ssh host cat file \EOF\ ...防止本地展开。坑 6bindsym 覆盖上游绑定产生红色横幅现象Sway 顶部持续显示红色横幅overwriting binding Mod4Return from exec foot。原因上游/etc/sway/config定义bindsym $modReturn exec foot用户配置include之后又写bindsym $modReturn exec weztermSway 检测到覆盖并警告。解决加--no-warn标志抑制横幅bindsym --no-warn $modReturn exec $term四、最终配置/etc/keyd/default.confkeyd 键位映射[ids] * [main] win keycap (keyd internal leftalt) - winmod layer leftalt layer(winmod) rightalt layer(altgr) alt keycap (keyd internal leftmeta) - keep Alt leftmeta layer(alt) ctrl keycap - keep Ctrl leftcontrol layer(control) rightcontrol layer(control) winmod layer: does NOT simulate Super. Each key explicitly emits Superkey (M- prefix) so Sway $mod matches. Edit keys c/v/x/a/z/s emit CtrlShiftkey for WezTerm copy/paste/select. [winmod] enter M-enter d M-d 1 M-1 2 M-2 3 M-3 4 M-4 5 M-5 6 M-6 7 M-7 8 M-8 9 M-9 0 M-0 q M-q w M-w e M-e r M-r t M-t y M-y u M-u i M-i o M-o p M-p g M-g h M-h j M-j k M-k l M-l semicolon M-semicolon apostrophe M-apostrophe z M-z b M-b n M-n m M-m comma M-comma period M-period slash M-slash f M-f space M-space tab M-tab backspace M-backspace escape M-escape left M-left right M-right up M-up down M-down Edit keys - WezTerm copy/paste/select (CtrlShiftkey) c macro(C-S-c) v macro(C-S-v) x macro(C-S-x) s macro(C-S-s) a macro(C-S-a) z macro(C-S-z) Shift combos preserved [winmodshift] a macro(S-C-a)配置逻辑说明[main]区块把物理 win 键帽keyd 内部leftalt指向自定义的winmodlayer。alt 键帽和 ctrl 键帽保持原样。[winmod]layer这个 layer不模拟任何修饰符没有:M后缀而是对每个键显式发 Superkeyenter M-enter→ 发 SuperEnterSway 的$modReturn开 WezTermd M-d→ 发 SuperdSway 的$modd开 wmenu 启动器c macro(C-S-c)→ 发 CtrlShiftcWezTerm 的复制绑定v macro(C-S-v)→ 发 CtrlShiftvWezTerm 的粘贴绑定其他字母键 → 发 Superkey给 Sway 当$mod[winmodshift]layer处理 winShiftkey 的组合如 winShifta 全选。~/.config/sway/configSway 用户配置include /etc/sway/config set $mod Mod4 set $term wezterm set $menu wmenu-run bindsym --no-warn $modReturn exec $term bindsym --no-warn $modd exec $menu output * bg #424242 solid_color配置逻辑说明include /etc/sway/config引入上游默认配置键绑定、bar、gaps 等。set $mod Mod4Sway 的$mod设为 Mod4Super配合 keyd 的 winmod layer让物理 win 键帽触发窗口管理快捷键。set $term wezterm终端用 WezTerm跨平台macOS 上共享同一份配置。bindsym --no-warn $modReturn exec $term重新绑定 SuperEnter 开 WezTerm覆盖上游的 foot。--no-warn抑制覆盖绑定的红色横幅。output * bg #424242 solid_color壁纸设为纯色暗灰#424242极简风格无图片。五、功能对照表键帽组合keyd 输出Sway 行为软件层结果win EnterSuperEnter$modReturn开 WezTermwin dSuperd$modd开 wmenu 启动器win cCtrlShiftc(无 Sway 绑定)WezTerm 复制win vCtrlShiftv(无 Sway 绑定)WezTerm 粘贴win xCtrlShiftx(无 Sway 绑定)WezTerm 剪切win aCtrlShifta(无 Sway 绑定)WezTerm 全选win zCtrlShiftz(无 Sway 绑定)WezTerm 撤销win sCtrlShifts(无 Sway 绑定)WezTerm 保存win 1/2/3...Super1/2/3...$mod1/2/3...切换工作区ctrl cCtrlc(无 Sway 绑定)终端中断 ^Cctrl zCtrlz(无 Sway 绑定)终端挂起alt 任意Altkey(无 Sway 绑定)AltmacOS opt六、安装步骤1. 安装 keydyay -S keyd sudo systemctl enable --now keyd2. 安装 wezterm-git解决 wl_shm 兼容性# 旧版 wezterm (2024-02) 与 Sway 1.12 的 wl_shm 协议不兼容 # 必须用 AUR 的 wezterm-git # 如果已装旧版 wezterm先卸载 sudo pacman -R wezterm 用 yay 编译安装 wezterm-git约 20-40 分钟 yay -S wezterm-git3. 应用 keyd 配置sudo cp /etc/keyd/default.conf /etc/keyd/default.conf.bak sudo tee /etc/keyd/default.conf /dev/null EOF [ids] * [main] leftalt layer(winmod) rightalt layer(altgr) leftmeta layer(alt) leftcontrol layer(control) rightcontrol layer(control) [winmod] enter M-enter d M-d ... (所有键显式发 Superkey) c macro(C-S-c) v macro(C-S-v) x macro(C-S-x) s macro(C-S-s) a macro(C-S-a) z macro(C-S-z) [winmodshift] a macro(S-C-a) EOF sudo keyd reload4. 应用 Sway 配置mkdir -p ~/.config/sway cat ~/.config/sway/config EOF include /etc/sway/config set $mod Mod4 set $term wezterm set $menu wmenu-run bindsym --no-warn $modReturn exec $term bindsym --no-warn $modd exec $menu output * bg #424242 solid_color EOF swaymsg reload5. 验证# 查看 keyd 实时按键输出 sudo keyd monitor 查看 Sway 配置错误/警告 swaymsg -t get_config | python3 -c import sys,json; djson.load(sys.stdin); print(Errors:, d.get(errors,none)); print(Warnings:, d.get(warnings,none)) 查看 WezTerm 版本 wezterm --version 应输出: wezterm 20260716-102532-2ef4bef4 (或更新)七、调试命令速查命令作用sudo keyd monitor实时查看 keyd 输出的键码sudo keyd listen查看 keyd layer 状态变化sudo keyd reload重新加载 keyd 配置swaymsg -t get_config查看 Sway 当前配置含 errors/warningsswaymsg -t get_inputs查看所有输入设备swaymsg -t get_bindings查看 Sway 当前活跃绑定swaymsg reload重新加载 Sway 配置wevWayland 事件查看器查看按键 events八、设计哲学这套配置的核心思路是分层职责清晰keyd 层内核级负责把物理键帽重映射到正确的修饰符并用 winmod layer 实现win 键帽双角色——给 Sway 当 Super给 WezTerm 当 CtrlShift。Sway 层窗口管理只关心 Superkey 的组合把它们绑定到窗口管理命令开终端、切工作区、杀窗口等。WezTerm 层终端应用只关心 CtrlShiftkey 的组合把它们绑定到编辑操作复制、粘贴、剪切、全选、撤销、保存。ctrl 键帽纯 Ctrl给终端用中断 ^C、挂起 ^Z。alt 键帽纯 Alt给应用当 opt 键用。为什么不直接用 Sway 的bindsym把 Superc 重映射成 CtrlShiftc因为 Sway 的bindsym只能执行 Sway 命令exec、kill、reload等不能转发按键给焦点窗口。要在 Sway 层做按键转发需要wtype这样的外部工具且会有焦点切换的 race condition。keyd 在内核层做重映射更干净、更可靠。九、已知限制winc 只在 WezTerm 里是复制在其他应用如 Firefox里winc 会发 CtrlShiftc可能不是复制。如果需要应用级差异要给 Firefox 单独绑 CtrlShiftc 复制。keyd 配置是系统级的/etc/keyd/default.conf对所有用户生效。多用户环境下可能需要按用户区分。winmod layer 的键列表是手动的每次加新键都要手动写M-key。可以用include机制把通用绑定抽到共享文件。WezTerm 版本要紧跟上游仓库版 wezterm (2024-02) 与 Sway 1.12 不兼容必须用 wezterm-git。每次 Sway 大版本升级后要确认 wezterm-git 是否需要重新编译。十、参考链接keyd 官方仓库GitHub - rvaiya/keyd: A key remapping daemon for linux. · GitHubSway 官方文档GitHub - swaywm/sway: i3-compatible Wayland compositor · GitHubWezTerm 官方文档Wezterm - Wez FurlongWezTerm 复制粘贴绑定文档https://wezfurlong.org/wezterm/config/keys.htmlArch Wiki keydhttps://wiki.archlinux.org/title/Keyd十一、完整配置文件下载本文涉及的所有配置文件都已开源在scripts/bash/configure-keyd-macbook-layout.sh— keyd 配置脚本scripts/bash/configure-sway-mod-key.sh— Sway 配置脚本docs/sway-config-pitfalls.md— 完整踩坑记录仓库地址gitgitcode.com:k4m7v2pz/archlinux-setup.gitdev 分支十二、总结这套 keyd Sway WezTerm 的组合拳实现了在 Arch Linux 上模拟 macOS 键盘习惯的目标win 键帽同时当 Sway 的$mod窗口管理和 WezTerm 的 CtrlShift复制粘贴ctrl 键帽纯 Ctrl给终端中断用alt 键帽纯 Alt当 macOS 的 opt 键关键难点是win 键帽的双角色——给 Sway 当 Super给 WezTerm 当 CtrlShift。解决方案是在 keyd 的 winmod layer 里对窗口管理键Enter、d、数字键等发Superkey对编辑键c、v、x、a、z、s发CtrlShiftkeyWezTerm 复制粘贴绑定整个配置无图形依赖、无外部工具、无 race condition在内核层完成所有重映射干净可靠。环境信息硬件ThinkPad E490i5-8265U, 32GB RAM, Intel UHD 620系统Arch Linux, kernel 7.1.3-arch1-3桌面Sway 1.12 WezTerm (wezterm-git, 2026-07-16)键位映射keyd 2.4.3终端WezTerm 20260716-102532-2ef4bef4AUR helperyay 13.0.1