# 鼠标与键盘的映射

## 介绍

本部分介绍的方法不适用于 Windows 95/98/Me 环境下的鼠标键盘映射,也不适用于对游戏操作杆进行映射。这两部分的映射方法，可参看下面的链接：

- Windows 9x remapping
- Joystick remapping

限制： 其实可以直接通过修改 Windows 注册表来进行鼠标键盘映射，而且在多数情况下，这要比用 AutoHotKey 来映射鼠标键盘更直接和高效。当然两种方法还是各有其优缺点的，可参看 registry remapping 。

## 映射键盘和鼠标

映射鼠标键盘的语法为： OriginKey::DestinationKey 。例如，包含下面代码的脚本可将 'a' 键映射成 'b' 键(点击 'a' 键将产生点击 'b' 键的效果)。

    a::b

上述代码不会改变 'b' 键，按下 'b' 键时仍然发送 'b' 键被按下的消息。当然，你也可以对 'b' 键进行映射(如下所示)。

    a::b
    b::a

上述的代码中使用的都是小写字母，但也会同时映射相应的大些字母(因此，按下 'a' 则输出 'b' ，按下 'A' 则输出 'B' )。如果 "::" 右边用大写字母，那么就只输出大写字母。例如，如果用下面的代码，不管你输入 'a' 还是 'A' 都只会输出 'B' (但是要保证 Capslock 没有锁住，否则输出会变成 'b' )：

    a::B

映射鼠标：映射鼠标，方法一样。例如：

MButton::Shift | 将鼠标中键映射成 Shift 键。(注意，这里是指按下鼠标中键而不是拨动鼠标滚轮)
XButton1::LButton | 将鼠标的第四个键映射成鼠标左键。
RAlt::RButton | 将右 Alt 键映射成鼠标右键。

其他常用(有用)的映射：

Capslock::Ctrl | 将 Capslock 键映射成 Ctrl 键。但这样会丢失 Capslock 键，可以添加映射 +Capslock::Capslock 。(这样，当你按下 Shift 键再点击 Capslock 就可以开关大写锁定了)
XButton2::^LButton | 将鼠标的第五个键(XButton2)映射成 Control 加鼠标左键。
RAlt::AppsKey | 将右 Alt 键映射成 Apps 键(就是打开右键菜单的键)。
RCtrl::RWin | 将右 Ctrl 键映射成右 Win 键。
Ctrl::Alt | 将左右 Ctrl 键映射成 Alt 键。但是这样会产生一些问题，参看 alt-tab issues 。
^x::^c | 将 Ctrl-X 映射成 Ctrl-C 。同时会附带将 Ctrl-Alt-X 映射成 Ctrl-Alt-C 的效果。
RWin::Return | 禁用右 Win 键(在 "::" 右边返回 return 就可以禁用左边的键)。

你可以试验上面所有的例子。方法是将代码拷贝到一个文本文件中(如 "Remap.ahk" )，然后运行该文件。

可以在 Key List 查看键盘键和鼠标键的完整列表。

## 注意

使用 #IfWinActive/Exist 命令可以让映射仅在指定的窗口内生效。例如：

    #IfWinActive ahk_class Notepad
    a::b  ; 将 'a' 键映射成 'b' 键，但仅在记事本窗口内有效。
    #IfWinActive  ; 这个命令后面的映射和热键将会在所有的窗口内都有效。

任何键盘和鼠标的映射都有如下性质：

- 如果按下修饰键(就是 Ctrl 、Alt 、Shift 这些键)再按原始键(origin key)，会将修饰键的效果带入目标键(destination key)。例如映射 b::a ，按下 Ctrl-B 也会产生 Ctrl-A 的效果。
- 通常 Capslock 对映射键和普通键的影响相同。
- 持续按住原始键(origin key)，目标键(destination key)也处于持续按下的状态。(一些游戏不支持键的映射，在这些游戏中所有的映射都不起作用)
- 被映射的键(原始键)被按下时也会自动重复发送击键消息。(将键盘键映射成鼠标键时除外)

被映射的键(原始键)可以触发含有目标键的普通热键，但不能触发含有目标键的鼠标热键(mouse hotkey)和 钩子热键 (可以使用 ListHotkeys 命令查看那些热键被“勾住”了)。例如，如果映射 a::b 有效，那么按下 Ctrl-Alt-A 会触发 ^!b 热键(只要 ^!b 不是一个钩子热键)。如果 ^!b 是一个钩子热键，而你又希望按下 Ctrl-Alt-A 能够触发它，你可以将 ^!a 定义成和 ^!b 一样的热键，这样按下 Ctrl-Alt-A 和按下 Ctrl-Alt-B 会执行相同的动作，从而达到“触发” ^!b 热键的效果。如下例所示：

    a::b
    ^!a::
    ^!b::
    ToolTip You pressed %A_ThisHotkey%.
    return

如果在自动运行区(auto-execute section，就是从脚本的第一行到出现第一个 Return, Exit, hotkey/hotstring label 之前的区域)使用了 SendMode ，所有的映射将会受其影响。另外，由于映射使用的是 Send {Blind} 模式，而 SendPlay mode 不完全支持 {Blind} 模式，一些映射(尤其是包含 Control, Shift, Alt, Win 键的映射)在 SendPlay mode 下会出现一些不正常的现象。所以当脚本中有映射时，应避免在自动运行区使用 SendPlay 模式；然后在脚本其他需要的地方使用 SendPlay 命令来代替 Send 命令。或者，另一种解决这个问题的方法是，将你的脚本用相应的热键代替(下面有详细的介绍)，这些热键使用 SendEvent 代替 Send 命令。

当脚本加载时，其中的每一个映射会被翻译成一对 热键(hotkeys) 。例如，映射 a::b 会被翻译成如下两个热键：

    *a::
    SetKeyDelay -1  ; 如果目标键是鼠标键，则使用 SetMouseDelay 命令。
    Send {Blind}{b DownTemp}  ; DownTemp 和 Down 相似，只是如果使用 DownTemp ，脚本运行到下一个 Send 命令时会不会认为 'b' 键仍处于按下的状态。
    return

    *a up::
    SetKeyDelay -1  ; 代码中两处 SetKeyDelay 命令都没有指定按键时长(press-duration ， SetKeyDelay 命令的第二个参数)，其原因请看下面的解释。
    Send {Blind}{b Up}
    return

在下面的情况下，将映射翻译成热键时会作一些调整：

1. 如果原始键(source key)是 LCtrl 键，目标键(destination key)是 Alt 键， Send {Blind}{LAlt DownTemp} 会被替换成 Send {Blind}{LCtrl Up}{LAlt DownTemp} 。当原始键是 RCtrl 时也会作类似的调整。
2. 如果是把键盘键映射成鼠标键(如 RCtrl::RButton )，则会用 SetMouseDelay 命令代替 SetKeyDelay 命令。同时，上面的第一个热键也会被替换成下面的热键，这样就可以防止由于键盘键按下后会重复发送键击消息而产生鼠标重复点击的消息：

       *RCtrl::
       SetMouseDelay -1
       if not GetKeyState("RButton")  ; 换言之，鼠标右键尚未按下。
           Send {Blind}{RButton DownTemp}
       return

注意 SetKeyDelay 命令的第二个参数 按键时长(press duration) 在上述的热键中被略去了。这是因为按键时长不适用于键按下和键弹起这样的事件(如 {b down} 和 {b up} )。但是按键时长却适用于涉及到 Shift/Ctrl/Alt/Win 键的事件，例如在 a::B 和 a::^b 中。因此，脚本中在 自动运行区(auto-execute section) 发生作用的按键时长参数会对所有这样的映射产生影响。

虽然不能将一对键直接映射成单个键(例如， a & c::b 这样的映射是无效的)，但只需修改上述的代码中两个热键(分别是键按下和键弹起时的热键)就可以实现：将 *a:: 替换成 a & c:: ，并将 *a up:: 替换成 a & c up:: 即可。

由于映射最终会被翻译成热键， Suspend 命令也会对映射产生影响。同样，也可以用 Hotkey 命令来禁用或修改一个映射。例如，下面两行代码可以禁用映射 a::b 。

    Hotkey, *a, off
    Hotkey, *a up, off

与 Alt-tab 有关的问题：如果你将一个键盘键或鼠标键映射成 Alt 键，这个键很有可能实现不了 alt-tab 的功能。在多数情况下，添加 *Tab::Send {Blind}{Tab} 这个热键解决这个问题——但是注意这很有可能会影响原始 Alt 键实现 alt-tab 的功能。因此，只有当你仅用映射键或 alt-tab hotkeys 来实现 alt-tab 的功能时才用这个方法。

除了 Key List 页面所列出来的鼠标键和键盘键外，原始键(source key)也可以是一个虚拟键(virtual key 或 VKnn)或扫描码(scan code 或 SCnnn)，在 special keys 页面中有对虚拟键和扫描码的介绍。同样，目标按键也可以使用虚拟键或扫描码，不过它还可以同时使用虚拟键和扫描码(在虚拟按键后面再指定一个扫描码)。例如，在大多数键盘布局下 sc01e::vk42sc030 与 a::b 等效。

如果想禁用一个键，而不是映射这个键，将其定义成直接 returns 的热键。例如，热键 F1::return 可以禁用 F1 键。

以下的键不支持映射：

- 鼠标滚轮。(虽然写着不支持,不过确实支持啊)
- Pause 键和 Break 键不能作为目标键(destination keys)。(这是因为它们在代码中会被当做命令执行)。
- 花括号 {} 不能作为目标键。但是可以用 虚拟键/扫描码的方法(VK/SC method) 来实现。如 x::+sc01A 和 y::+sc01B
- 百分号 % 不能作为目标键。同样可以用 虚拟键/扫描码的方法(VK/SC method) 来实现。
- 回车符 "Return" 不能作为目标键。用 "Enter" 代替。

## 用键盘来移动鼠标光标

通过映射(或者热键)，键盘可以用来移动鼠标的光标，如 键盘-鼠标脚本(Keyboard-To-Mouse script) 所示。由于这个脚本能提供鼠标平滑移动、加速和其他的功能，如果你需要用键盘来实现鼠标的功能，推荐你使用这个脚本。下面是一个简化的键盘-鼠标脚本实例：

    *#up::MouseMove, 0, -10, 0, R  ; Win+UpArrow hotkey => 光标上移
    *#Down::MouseMove, 0, 10, 0, R  ; Win+DownArrow => 光标下移
    *#Left::MouseMove, -10, 0, 0, R  ; Win+LeftArrow => 光标左移
    *#Right::MouseMove, 10, 0, 0, R  ; Win+RightArrow => 光标右移

    *<#RCtrl::  ; LeftWin + RightControl => 鼠标左击。
    SendEvent {Blind}{LButton down}
    KeyWait RCtrl  ; 防止键盘自动重复导致鼠标重复点击。
    SendEvent {Blind}{LButton up}
    return

    *<#AppsKey::  ; LeftWin + AppsKey => 鼠标右击。
    SendEvent {Blind}{RButton down}
    KeyWait AppsKey  ; 防止键盘自动重复导致鼠标重复点击。
    SendEvent {Blind}{RButton up}
    return

## 使用注册表的“扫描码映射(Scancode Map)”功能来实现映射

优点：

- 注册表映射在大多数情况下比 AutoHotkey 的映射 更加直接和有效。如，注册表映射能在更多的游戏中起作用，而且不会存在 alt-tab 问题 ；另外也能够触发 AutoHotkey 中的钩子热键(hook hotkey)。(而 AutoHotkey 中的映射需要使用 间接的方法(workaround) 才能“触发”勾住的热键)。
- 如果你是手动地修改注册表项(下面会详细描述)，那么不需要使用任何外部软件就可以实现映射。即使你使用 KeyTweak 来修改注册表项，修改完后也不需要 KeyTweak 运行就可以让映射生效(而 AutoHotkey 则需要一直运行才能使映射生效)。

缺点：

- 缺少灵活性：每一次修改映射，需要重启计算机后才能让修改生效。
- 不能让映射仅对特定的用户、程序有效。
- 不能发送包含 Shift, Control, Alt, AltGr 键的组合键击消息。也不能将一个小写字母映射成大写字母。
- 在 Windows 95/98/Me 下不被支持。而 AutoHotkey 能实现 部分Win9x映射(limited Win9x remapping) 。
- 仅支持对键盘的映射。而 AutoHotkey 还支持 鼠标映射 和 部分操作杆映射(limited joystick remapping) 。

如何修改注册表：至少有两种方法：

1. 通过软件，如 KeyTweak (免费软件)来映射键盘。它会自动修改注册表。
2. 手动创建 .reg 文件(纯文本文件)并将它载入注册表。详见 www.autohotkey.com/forum/post-56216.html#56216

## Windows 95/98/Me下的映射方法

方法是直接使用热键。推荐在编写热键时使用 Send 和 KeyWait 这两个命令。例如，下面的热键可以将 'A' 键映射成左方向键：

    a::
    Send {Left down}  ; 按下左方向键。
    KeyWait a  ; 等待用户释放 'a' 键。
    Send {Left up}  ; 释放左方向键。
    return

## 相关主题

List of keys and mouse buttons
GetKeyState
Remapping a joystick