长期在 macOS 和 Windows 之间切换,最难改的还是肌肉记忆。

Mac 的 Command 键就在空格旁边,复制、粘贴、撤销、切换窗口,左手拇指顺手就能完成。到了 Windows,同一个位置变成 Alt,Ctrl 则缩到了键盘左下角,来回切换时经常会下意识按错。

我想在 Windows 上实现下面这套键位:

  • 物理左 Alt 充当 Ctrl,用来复制、粘贴和撤销。
  • 物理左 Ctrl 充当 Alt。
  • 物理左 Alt + Tab 继续用于切换窗口,手感接近 Mac 的 Command + Tab。
  • 右 Alt 和右 Ctrl 保持原样,给输入法、AltGr 和故障恢复留一点余地。

交换两个键本身不难,麻烦在于扫描码映射、键盘钩子和修饰键状态会互相影响。试过几种做法后,我留下了下面两部分配置。

配置思路:底层换键,脚本补行为

目前使用的方案很简单:

  1. 通过 Windows 原生的 Scancode Map 交换左 Alt 和左 Ctrl。
  2. 用一条 AutoHotkey 规则恢复物理左 Alt + Tab 的窗口切换。

复制、粘贴等高频操作由系统底层处理,不依赖后台脚本。AutoHotkey 只负责窗口切换这一处特殊行为,配置少,排查起来也轻松一些。

第一层:用 Scancode Map 交换左 Alt 和左 Ctrl

Windows 支持通过下面的注册表位置重映射扫描码:

1
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layout

动手前建议先导出这个注册表项做备份。下面的 .reg 文件会覆盖整个 Scancode Map 值;如果电脑上已经配过 Caps Lock 等其他静态映射,请用 SharpKeys 在现有配置上调整,或者手工合并映射,不要直接覆盖。

确认没有需要保留的旧映射后,新建一个 .reg 文件,写入以下内容并以管理员权限导入:

1
2
3
4
Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layout]
"Scancode Map"=hex:00,00,00,00,00,00,00,00,03,00,00,00,1d,00,38,00,38,00,1d,00,00,00,00,00

这段数据里:

  • 0x1D 代表左 Ctrl。
  • 0x38 代表左 Alt。
  • 第一条映射把左 Alt 改成左 Ctrl。
  • 第二条映射把左 Ctrl 改成左 Alt。
  • 03 表示两条映射,再加一个结束项。

不想手工编辑十六进制数据,也可以用 SharpKeys 写入同样的注册表值。

为什么只交换左侧按键

右 Alt 和右 Ctrl 建议先保留。这样做有几个实际好处:

  • 不容易破坏 AltGr。
  • 对中文输入法和其他国际键盘布局更友好。
  • 某些特殊软件需要原生 Ctrl 时,右 Ctrl 还能备用。
  • 配置出错后,手边至少还有一组没动过的修饰键。

写入后需要重启

Scancode Map 不会立即生效。导入注册表后需要重启 Windows,单纯重启换键工具没有用。

它在系统启动时加载,不需要换键程序常驻,登录界面和管理员窗口里的键位也能保持一致。

这份映射是整机级别的,会作用于所有用户和接入的键盘。如果只想改某一把外接键盘,需要换用能够区分设备的工具。

第二层:把窗口切换放回 Mac 的位置

完成底层交换后,系统看到的按键已经变了:

  • 物理左 Alt 会发送左 Ctrl。
  • 物理左 Ctrl 会发送左 Alt。
  • Windows 原生的 Alt + Tab 因此跑到了物理左 Ctrl + Tab。

为了继续使用物理左 Alt + Tab,可以加一条 AutoHotkey v2 热键:

1
2
3
4
5
6
#Requires AutoHotkey v2.0
#SingleInstance Force

; 注册表交换后,物理左 Alt 在系统中表现为左 Ctrl。
; 使用内置 AltTab 动作处理窗口选择器和松键确认。
<^Tab::AltTab

<^ 表示左 Ctrl。扫描码已经在系统底层交换,所以这条规则捕获到的正是物理左 Alt。

AutoHotkey 内置的 AltTab 动作会处理窗口选择器的状态:

  1. 按住物理左 Alt。
  2. 连续按 Tab,在窗口之间移动。
  3. 松开物理左 Alt,进入当前选中的窗口。

这和 Mac 上 Command + Tab 的操作习惯基本一致。按住修饰键时保留窗口选择界面,快速按下并松开时则会直接回到上一个窗口。

我使用的是 AutoHotkey v2 便携版,运行时和脚本放在一个固定目录:

1
2
%LOCALAPPDATA%\MacWindowSwitch\AutoHotkey64.exe
%LOCALAPPDATA%\MacWindowSwitch\mac-window-switch.ahk

然后在下面的位置添加登录自启动项:

1
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run

在注册表编辑器中新建一个「可扩充字符串值」(REG_EXPAND_SZ),名称设为 MacWindowSwitch,值数据为:

1
"%LOCALAPPDATA%\MacWindowSwitch\AutoHotkey64.exe" "%LOCALAPPDATA%\MacWindowSwitch\mac-window-switch.ahk"

这里要留意值类型。%LOCALAPPDATA% 属于环境变量,普通字符串值(REG_SZ)不保证会展开;如果使用 REG_SZ,请直接填写展开后的绝对路径。

AutoHotkey 脚本修改后不用重启 Windows,重新加载脚本或重启进程即可。

两层配置在管理员窗口里的表现并不完全相同:底层的按键交换仍然有效,普通权限的 AutoHotkey 脚本却可能收不到高权限窗口里的热键。若问题只在管理员窗口中出现,先检查两边的权限级别。

几个容易踩到的坑

别让运行时钩子承担整套修饰键交换

我最初也试过只用键盘钩子交换 Alt 和 Ctrl。平时大多正常,碰到其他热键工具、管理员窗口、远程桌面或输入法后,排查就会复杂很多。脚本中断或重载时,还可能留下没有正确释放的修饰键。

像这种固定、全局的键对键映射,交给扫描码会稳定很多。

不要同时启用多套映射

写入 Scancode Map 后,应当停用其他工具中的 Alt/Ctrl 交换规则。

两套配置叠在一起会产生双重映射。有时看起来像交换没有生效,有时键位会再次颠倒,很难从表面现象判断是哪一层出了问题。

迁移之前最好先备份旧配置,然后只保留一处修饰键交换。

少手工拼接 Alt 的按下和松开

我曾在 AutoHotkey 中手工发送下面这组事件:

1
Left Alt down -> Tab -> Left Alt up

这类写法需要脚本自己维护 Alt 的状态。只要脚本中断、热键冲突,或前台窗口的权限高于脚本,实际结果就可能偏离预期。

窗口切换直接使用 AutoHotkey 内置的 AltTab 动作更省事,也能少处理一层按下和松开状态。

AltTab 特殊热键会在启动时检查格式

AutoHotkey 的 AltTabShiftAltTab 属于特殊动作,对热键格式有额外要求。我曾把 Ctrl 和 Shift 一起写进特殊热键,脚本启动时收到下面的错误:

1
This AltTab hotkey must have exactly one modifier/prefix.

改完脚本后要实际启动一次,单纯的语法检查发现不了热键注册阶段的问题。

窗口选择器一直显示,不一定是故障

窗口切换常见的操作方式有两种:

  • 每按一次组合键就立即切换。
  • 按住修饰键,连续按 Tab 选择窗口,松开后确认。

Mac 的 Command + Tab 使用后一种方式。只要松开物理左 Alt 后能进入选中的窗口,按住期间显示窗口列表就是正常现象。

故障排查清单

如果输入字母时突然开始触发快捷键,可以按下面的顺序检查:

  1. 分别按下并松开左右 Ctrl、Alt、Shift 和 Win。
  2. 打开屏幕键盘,看看是否有修饰键一直处于高亮状态。
  3. 确认没有其他换键软件同时管理 Ctrl 和 Alt。
  4. 检查 Scancode Map 是否存在,内容是否正确。
  5. 确认 AutoHotkey 脚本仍在运行,并检查有没有错误窗口。
  6. 如果刚刚修改过 Scancode Map,确认 Windows 已经重启。
  7. 到「设置 → 辅助功能 → 键盘」中检查粘滞键和筛选键是否被误开启。

恢复原始键位

如果这台电脑的 Scancode Map 只包含本文添加的两条映射,可以导入下面的 .reg 文件:

1
2
3
4
Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layout]
"Scancode Map"=-

这段配置会删除整个 Scancode Map 值。还有其他静态映射需要保留时,请恢复之前导出的备份,或只删除 Alt/Ctrl 对应的两条映射。

确认可以删除后,导入恢复文件,先删除 MacWindowSwitch 登录自启动项并退出 AutoHotkey 脚本,然后再重启 Windows。重启完成后,键位就会恢复原状。

写在最后

现在这套配置只剩一个注册表值和一条 AutoHotkey 热键:固定换键由 Scancode Map 处理,脚本只补上 Alt + Tab。以后再调整 Caps Lock、Win 等按键,我也会沿用这个顺序,能用扫描码解决就先用扫描码,确实涉及组合逻辑时再加脚本。

参考资料