KeyMapping:win上使用mac键位

最近购入了台17年12寸的 macbook,想着体验一下mac生态,但是熟悉之后感觉确实不错。尤其是 Command 键的位置和用法,但是切换回 Windows 的时候就不太顺畅了。于是就想写一个脚本,实现键位映射。但是用mac RDP win的时候发现这些映射又容易出问题,于是想办法搞成动态映射来解决这个问题。

本文介绍如何使用 AutoHotkey (v2.0) 编写脚本,实现动态键位映射:既能在本地完美复刻 Mac 体验,又能智能识别远程桌面来源,自动适配 RDP 客户端的键位逻辑。

💡 核心痛点:本地与远程的“精神分裂”

在 Windows 上复刻 Mac 键位,最直接的思路是将键盘左下角的 Alt 映射为 Ctrl(因为 Mac 的 Command 键就在这个位置)。

然而,当你从一台 Mac 通过 Microsoft Remote Desktop 远程连接到这台 Windows 时,问题就出现了: 1. 本地使用时:我们需要 Alt -> Ctrl。 2. Mac 远程连接时:Mac 的 RDP 客户端通常会将 Command 键映射为 Windows 的 Win 键。此时,我们在 Mac 上按 Cmd + C,Windows 接收到的是 Win + C

如果我们简单粗暴地全局重映射,就会导致远程连接时快捷键失效。我们需要一个“智能”的脚本,它能知道当前是谁在操作电脑

🔍 解决方案:WTSAPI 动态识别

Windows 提供了 WTSAPI (Windows Terminal Services API),允许我们查询当前会话的信息。通过 WTSQuerySessionInformation 函数,我们可以获取连接到当前会话的客户端名称(Client Name)。

  • 本地登录:客户端名称通常为空。
  • 远程登录:客户端名称会显示发起连接的设备名)。

利用这一点,我们可以编写一个 IsRemoteMac() 函数来动态判断当前的上下文。

🛠️ 脚本实现

以下是完整的 AutoHotkey v2 脚本。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
#Requires AutoHotkey v2.0
#SingleInstance Force

; ============================================================================
; MacKeys.ahk - Windows 下模拟 Mac 键位布局
; ============================================================================
;
; 功能说明:
; - 将 Alt 键模拟为 Mac 的 Cmd 键
; - 支持远程 Mac 模式(通过 RDP 连接时)和本地 Windows 模式自动切换
;
; 使用方式:
; - 双击运行此脚本,托盘区会出现 AHK 图标
; - 右键图标可退出或重新加载脚本
;
; ============================================================================

; ============================================================================
; 函数定义
; ============================================================================

IsRemoteMac() {
clientName := Trim(GetRdpClientName())
if (clientName = "")
return false

if InStr(clientName, "zihao-macbook") {
return true
}

return false
}

GetRdpClientName() {
try {
pBuffer := 0
bytes := 0
if !DllCall("wtsapi32\WTSQuerySessionInformationW"
, "Ptr", 0 ; WTS_CURRENT_SERVER_HANDLE
, "Int", -1 ; WTS_CURRENT_SESSION
, "Int", 10 ; WTSClientName
, "Ptr*", &pBuffer
, "UInt*", &bytes)
return ""

name := StrGet(pBuffer, "UTF-16")
DllCall("wtsapi32\WTSFreeMemory", "Ptr", pBuffer)
return name
} catch {
return ""
}
}

; ============================================================================
; 远程 Mac 模式 (通过 RDP 连接到 Mac 时)
; ============================================================================

#HotIf IsRemoteMac()

; Alt + Tab -> Win + Tab (任务切换)
$!Tab::
{
SendInput "{LAlt up}"
Sleep 10
SendEvent "#{Tab}"
return
}

; Win 键映射
$#/::Send "^/" ; 斜杠 (Win + / -> Ctrl + /)
$#b::Send "^b" ; 加粗 (Win + B -> Ctrl + B)
$#s::Send "^s" ; 保存 (Win + S -> Ctrl + S)
$#-::Send "^-" ; 缩小 (Win + - -> Ctrl + -)
$#=::Send "^=" ; 放大 (Win + = -> Ctrl + =)
$#p::Send "^p" ; 打印 (Win + P -> Ctrl + P)
$#[::Send "^[" ; 反缩进 (Win + [ -> Ctrl + [)
$#t::Send "^t" ; 新建标签页 (Win + T -> Ctrl + T)
$#+k::Send "^+k" ; 插入代码块 (Win + Shift + K -> Ctrl + Shift + K)

#HotIf

; ============================================================================
; 本地 Windows 模式 (将 Alt 模拟 Mac 的 Cmd 键)
; ============================================================================

#HotIf !IsRemoteMac()

; ---- 基础编辑操作 ----
$!c::Send "^c" ; 复制 (Alt + C -> Ctrl + C) 实现 Cmd + C
$!v::Send "^v" ; 粘贴 (Alt + V -> Ctrl + V) 实现 Cmd + V
$!x::Send "^x" ; 剪切 (Alt + X -> Ctrl + X) 实现 Cmd + X
$!z::Send "^z" ; 撤销 (Alt + Z -> Ctrl + Z) 实现 Cmd + Z
$!+z::Send "^y" ; 重做 (Alt + Shift + Z -> Ctrl + Y) 实现 Cmd + Shift + Z
$!a::Send "^a" ; 全选 (Alt + A -> Ctrl + A) 实现 Cmd + A

; ---- 文件操作 ----
$!s::Send "^s" ; 保存 (Alt + S -> Ctrl + S) 实现 Cmd + S
$!n::Send "^n" ; 新建 (Alt + N -> Ctrl + N) 实现 Cmd + N
$!w::Send "^w" ; 关闭 (Alt + W -> Ctrl + W) 实现 Cmd + W
$!p::Send "^p" ; 搜索 (Alt + P -> Ctrl + P) 实现 Cmd + P
$!,::Send "^," ; 菜单 (Alt + , -> Ctrl + ,) 实现 Cmd + ,

; ---- 文本编辑 ----
$!b::Send "^b" ; 加粗 (Alt + B -> Ctrl + B) 实现 Cmd + B
$!f::Send "^f" ; 查找 (Alt + F -> Ctrl + F) 实现 Cmd + F
$!h::Send "^h" ; 替换 (Alt + H -> Ctrl + H) 实现 Cmd + H
$!/::Send "^/" ; 注释 (Alt + / -> Ctrl + /) 实现 Cmd + /
$![::Send "^[" ; 反缩进 (Alt + [ -> Ctrl + [) 实现 Cmd + [
$!+k::Send "^+k" ; 插入代码块 (Alt + Shift + K -> Ctrl + Shift + K) 实现 Cmd + Shift + K

; ---- 浏览器/标签页 ----
$!t::Send "^t" ; 新建标签页 (Alt + T -> Ctrl + T) 实现 Cmd + T
$!r::Send "^r" ; 刷新 (Alt + R -> Ctrl + R) 实现 Cmd + R

; ---- 缩放控制 ----
$!=::Send "^{=}" ; 放大 (Alt + = -> Ctrl + =) 实现 Cmd + =
$!-::Send "^{-}" ; 缩小 (Alt + - -> Ctrl + -) 实现 Cmd + -
$!0::Send "^0" ; 恢复大小 (Alt + 0 -> Ctrl + 0) 实现 Cmd + 0

#HotIf

; ============================================================================
; 应用专属快捷键
; ============================================================================

; ---- Typora 专属 ----
#HotIf !IsRemoteMac() && WinActive("ahk_exe Typora.exe")
{
$!1::Send "^1" ; 一级标题 (Alt + 1 -> Ctrl + 1) 实现 Cmd + 1
$!2::Send "^2" ; 二级标题 (Alt + 2 -> Ctrl + 2) 实现 Cmd + 2
$!3::Send "^3" ; 三级标题 (Alt + 3 -> Ctrl + 3) 实现 Cmd + 3
$!4::Send "^4" ; 四级标题 (Alt + 4 -> Ctrl + 4) 实现 Cmd + 4
$!5::Send "^5" ; 五级标题 (Alt + 5 -> Ctrl + 5) 实现 Cmd + 5
}
#HotIf

; ---- 浏览器专属 (Chrome, Edge, Firefox) ----
#HotIf !IsRemoteMac() && (WinActive("ahk_exe chrome.exe") || WinActive("ahk_exe msedge.exe") || WinActive("ahk_exe firefox.exe"))
{
$!Left::Send "!{Left}" ; 后退 (Alt + Left -> Alt + Left) 实现 Cmd + [
$!Right::Send "!{Right}" ; 前进 (Alt + Right -> Alt + Right) 实现 Cmd + ]
}
#HotIf

; ---- VS Code 专属 ----
#HotIf !IsRemoteMac() && WinActive("ahk_exe Code.exe")
{
$!+p::Send "^+p" ; 命令面板 (Alt + Shift + P -> Ctrl + Shift + P) 实现 Cmd + Shift + P
$!g::Send "^g" ; 跳转行号 (Alt + G -> Ctrl + G) 实现 Cmd + G
}
#HotIf

; ============================================================================
; 本地 Windows 模式 - 通用快捷键 (在应用专属之后处理)
; ============================================================================

#HotIf !IsRemoteMac()

; ---- 光标移动 ----
$!Left::Send "{Home}" ; 光标移至行首 (Alt + Left -> Home) 实现 Cmd + Left
$!Right::Send "{End}" ; 光标移至行尾 (Alt + Right -> End) 实现 Cmd + Right
$!Up::Send "^{Home}" ; 光标移至文档头 (Alt + Up -> Ctrl + Home) 实现 Cmd + Up
$!Down::Send "^{End}" ; 光标移至文档尾 (Alt + Down -> Ctrl + End) 实现 Cmd + Down

; ---- 文本选择 ----
$!+Left::Send "+{Home}" ; 选中至行首 (Alt + Shift + Left -> Shift + Home) 实现 Cmd + Shift + Left
$!+Right::Send "+{End}" ; 选中至行尾 (Alt + Shift + Right -> Shift + End) 实现 Cmd + Shift + Right
$!+Up::Send "^+{Home}" ; 选中至文档头 (Alt + Shift + Up -> Ctrl + Shift + Home) 实现 Cmd + Shift + Up
$!+Down::Send "^+{End}" ; 选中至文档尾 (Alt + Shift + Down -> Ctrl + Shift + End) 实现 Cmd + Shift + Down

; ---- 系统快捷键 ----
$!e::Send "#e" ; 打开资源管理器 (Alt + E -> Win + E) 实现 Cmd + E

; ---- 聚焦搜索 (Alt + Space -> Win + S) 实现 Cmd + Space ----
; 使用 ~ 前缀允许原生 Alt+Space 行为,延迟触发 Win+S
~!Space::
{
KeyWait "Alt"
Sleep 50
Send "#s"
return
}

; ---- Win 键特殊映射 ----
$#z::Send "!z" ; 自动换行 (Win + Z -> Alt + Z) 实现 Cmd + Z
$#1::Send "^!1" ; 截图并复制 (Win + 1 -> Ctrl + Alt + 1) 实现 Cmd + 1
$#2::Send "^!2" ; 贴图 (Win + 2 -> Ctrl + Alt + 2) 实现 Cmd + 2
$#3::Send "^!3" ; 截图 (Win + 3 -> Ctrl + Alt + 3) 实现 Cmd + 3

; ---- 单击 LAlt 发送 Win 键 ----
~LAlt::Send "{Blind}{vkE8}"
~LAlt Up::
{
if (A_PriorKey = "LAlt")
{
Send "{LWin}"
}
}

#HotIf

🚀 如何使用

  1. 安装 AutoHotkey v2
  2. 创建一个新文件 MacKeys.ahk,将上述代码粘贴进去。
  3. 双击运行即可。
  4. (可选)将其放入 Windows 的启动文件夹,实现开机自启。

仓库地址放到这里,希望这对你有帮助!