创建一个对象, 该对象可用于收集或拦截键盘输入.
InputHook := InputHook(Options, EndKeys, MatchList)
由零个或多个下列字母组成的字符串(可任意顺序, 中间可选空格):
B: 设置 BackspaceIsUndo 为 false, 这会导致 Backspace 被忽略.
C: 设置 CaseSensitive 为 true, 使 MatchList 区分大小写.
I: 设置 MinSendLevel 为 1 或给定值, 使任何输入级别低于该值的输入被忽略. 例如, I2
将忽略级别为 0(默认值) 或 1 的任何输入, 但将捕获级别为 2 的输入.
L: 长度限制(例如 L5
). 输入的最大允许长度. 当文本达到这个长度时, 输入被终止, EndReason 被设置为单词 Max(除非文本匹配 MatchList 中的一个短语, 在这种情况下 EndReason 被设置为单词 Match). 如果未指定, 则长度限制为 1023.
指定 L0
禁用文本的收集和长度限制, 但并不影响按键生成的文本的统计(请参阅 VisibleText). 这可以与 OnChar, OnKeyDown, KeyOpt 或 EndKeys 组合使用.
M: 将修饰键击对应于真正的 ASCII 字符, 识别并转录修饰键击(如 Ctrl+A 到 Ctrl+Z). 参考这个例子, 它识别 Ctrl+C:
CtrlC := Chr(3) ; 将 Ctrl-C 对应的字符存储在 CtrlC 变量中. ih := InputHook("L1 M") ih.Start() ih.Wait() if (ih.Input = CtrlC) MsgBox "You pressed Control-C."
注意: 字符 Ctrl+A 到 Ctrl+Z 对应于 Chr(1) 到 Chr(26). 此外, M 选项可能会导致某些键盘快捷键(如 Ctrl+←) 在输入正在进行时出现异常.
T: 设置 Timeout (例如 T3
或 T2.5
).
V: 设置 VisibleText 和 VisibleNonText 为 true. 通常, 用户的输入被阻止(对系统隐藏). 使用此选项可将用户的击键发送到活动窗口.
*: 通配符. 设置 FindAnywhere 为 true, 允许在用户键入的任何位置找到匹配项.
E: 按字符代码而不是键码处理单字符结束键. 如果活动窗口的键盘布局与脚本的键盘布局不同, 则可以提供更一致的结果. 它还可以防止实际上不会产生给定结束字符的键组合结束 Input(输入); 例如, 如果 @
是结束键, 则在美式键盘中 Shift+2 将触发它, 但 Ctrl+Shift+2 不会触发(在使用 E 选项时). 如果还使用 C 选项, 则结束字符区分大小写.
一个由零个或多个按键组成的列表, 其中任何一个键在按下时终止输入(结束键本身不会写入输入缓冲). 当 Input 以这种方式终止时, EndReason 设置为单词 EndKey, EndKey 属性设置为键的名称.
EndKeys 列表使用类似于 Send 函数的格式. 例如, 指定 {Enter}.{Esc}
将使 Enter, . 或 Esc 任一一个都能终止 Input. 使用大括号本身作为结束键, 指定 {{}
和/或 {}}
.
要使用 Ctrl, Alt 或 Shift 作为结束键, 请指定键的左和/或右的版本, 而不是中性版本. 例如, 指定 {LControl}{RControl}
而不是 {Control}
.
尽管不支持诸如 Alt+C(!c) 这样的修饰键, 而非-字母数字字符(如 ?!:@&{}
) 默认情况下需要 Shift 按键按下与否, 取决于字符的正常输入方式. 如果有 E 选项, 则将单个字符键名解释为字符, 在这种情况下, 修饰符键必须处于正确的状态才能生成该字符. 当同时使用 E 和 M 选项时, 通过在 EndKeys 中包括相应的 ASCII 控制字符来支持 Ctrl+A 到 Ctrl+Z.
还可以指定明确的虚拟按键代码, 例如 {vkFF}
或 {sc001}
. 这在键没有名称且按下时不产生可见字符的罕见情况下非常有用. 它的虚拟键码可以通过按键列表页面底部的步骤来确定.
以逗号分隔的关键词列表, 其中任何一个都将导致终止输入(在这种情况下, EndReason 将被设置为单词 Match). 用户输入的内容必须完全匹配匹配列表中的某个词组(除非有 * 选项). 此外, 分隔符逗号周围的任何空格或制表符都是有意义的, 这意味着它们是匹配字符串的一部分. 例如, 如果 MatchList 为 ABC , XYZ
, 则用户必须在 ABC 之后或 XYZ 之前键入空格以形成匹配.
两个连续的逗号产生单个原义逗号. 例如, 后面的匹配列表会在 string1 的末尾产生单个原义逗号: string1,,,string2
. 类似的, 后面的匹配列表仅包含其中有一个原义逗号的单个项目: single,,item
.
因为 MatchList 中的项目不被视为单独的参数, 所以列表可以完全包含在一个变量中. 事实上, 如果此列表的长度超过 16383, 那么列表的全部或部分必须包含在变量中, 因为这个长度是任何脚本行的最大长度. 例如, MatchList 可能由 List1 "," List2 "," List3
组成 -- 其中每个变量都包含匹配词组的子列表.
任何数量的 InputHook 对象都可以在任何时候创建和进行, 但是它们启动的顺序会影响 Input 的收集方式.
当每个 Input 开始时(通过 Start 方法), 它被推到堆栈的顶部, 只有当 Input 终止时才从堆栈中删除. 键盘事件按最近开始到最早的顺序传递给每个输入. 如果一个输入抑制了一个给定的键盘事件, 那么它就不会再向下传递.
如果击键的发送级别低于 InputHook 的 MinSendLevel, 则忽略 Sent 的击键. 在这种情况下, 击键仍然可以由堆栈中较低的输入来处理.
多个 InputHook 都可以与 MinSendLevel 一起使用, 以分别收集发送的击键和实际击键.
InputHook 函数返回一个 InputHook 对象, 该对象具有以下方法和属性.
方法:
常规属性:
选项属性:
设置按键或按键列表的选项.
InputHook.KeyOpt(Keys, KeyOptions)
按键列表. 大括号用于括起按键名称, 虚拟键码或扫描码, 类似于 Send 函数. 例如, {Enter}.{{}
将应用于 Enter, . 和 {. 按名称, 按 {vkNN}
或按 {scNNN}
指定按键可能会产生三种不同的结果; 有关详情, 请参阅下文.
单独指定字符串 {All}
(不区分大小写) 以便将 KeyOptions 应用于所有 VK 和所有 SC. 然后可以再次调用 KeyOpt 从特定按键中删除选项.
下列单字符选项中的一个或多个(空格和制表符).
-(减号): 移除 -
后面的任何选项, 直到下一个 +
.
+(加号): 取消任何先前的 -
, 否则无效.
E: 结束键. 如果启用, 则按下键终止 Input, 将 EndReason 设置为单词 EndKey, 将 EndKey 属性设置为键的标准名称. 与 EndKeys 参数不同, Shift 键的状态将被忽略. 例如, @
和 2
在美式键盘布局中都相当于 {vk32}
.
I: 忽略文本. 通常由该键生成的任何文本都将被忽略, 并且该键被视为非文本键(请参阅 VisibleNonText). 如果键通常不产生文本, 则没有效果.
N: 通知. 在每次按下键时调用 OnKeyDown 和 OnKeyUp 回调.
S: 处理它后抑制(阻止) 按键. 这将覆盖 VisibleText 或 VisibleNonText 直到使用 -S
. +S
意味着 -V
.
V: 可见. 防止键按被抑制(阻止). 这将覆盖 VisibleText 或 VisibleNonText 直到使用 -V
. +V
意味着 -S
.
选项可以通过虚拟键码和扫描码来设置, 并且是累加的.
当按名称指定一个键时, 选项通过 VK 或 SC 来设置. 如果两个物理键共享相同的 VK, 但 SC 不同(如 Up 和 NumpadUp), 则由 SC 处理. 相反, 如果使用 VK 码, 则它将应用于产生该 VK 的任何物理键(这可能会随着时间的推移而变化, 这取决于活动键盘布局).
通过 VK 码删除选项不会影响 SC 设置的任何选项, 反之亦然. 但是, 当按键名删除一个选项并且该名称由 VK 处理时, 对应的 SC 也会删除该选项(根据脚本的键盘布局). 这允许在对所有按键应用一个选项后按名称排除按键.
如果通过 VK 设置 +V
, 而通过 SC 设置 +S
(反之亦然), 则 +V
优先.
启动收集输入.
InputHook.Start()
如果 Input 已经在进行中, 则没有效果.
新启动的 Input 放在 InputHook 堆栈的顶部, 这允许它覆盖任何先前启动的 Input.
此方法安装键盘钩子(如果还没有安装).
等待, 直到 Input 终止(InProgress 为 false).
InputHook.Wait(MaxTime)
等待的最大秒数. 如果 Input 在 MaxTime 秒后仍在进行中, 则该方法返回且不终止 Input.
返回 EndReason.
返回结束键的名称, 按下结束键以终止 Input.
KeyName := InputHook.EndKey
注意, EndKey 返回按键的 "标准" 名称, 而不管它在 EndKeys 中是如何编写的. 例如, {Esc}
和 {vk1B}
都产生 Escape
. GetKeyName 可用于检索标准名称.
如果使用 E 选项, EndKey 返回输入的实际字符(如果合适). 否则, 键名将根据脚本的活动键盘布局来确定.
如果 EndReason 不是 "EndKey", EndKey 返回一个空字符串.
返回在 Input 终止时逻辑上按下的修饰符的字符串.
Mods := InputHook.EndMods
如果所有修饰符在逻辑上都是按下的, 则完整的字符串为:
<^>^<!>!<+>+<#>#
这些修饰符与热键的具有相同的含义. 每个修饰符总是用 <(左) 或 >(右) 限定. 对应的键名是: LCtrl, RCtrl, LAlt, RAlt, LShift, RShift, LWin, RWin.
InStr 可以用来检查给定的修饰符(如 >!
或 ^
) 是否存在的. 下面的行可以用来将 Mods 转换成中性修饰符的字符串, 如 ^!+#
:
Mods := RegExReplace(Mods, "[<>](.)(?:>\1)?", "$1")
由于这是瞬间发生的, 此属性可能比 GetKeyState 更可靠, 即使在 Input 终止后立即调用 GetKeyState, 或者在 OnEnd 回调中.
返回 EndReason 字符串, 该字符串表明了 Input 是如何终止的.
Reason := InputHook.EndReason
如果 Input 正在进行, 则返回空字符串.
如果输入正在进行, 返回 true, 否则返回 false.
Boolean := InputHook.InProgress
返回自上次 Input 启动以来收集的任何文本.
String := InputHook.Input
此属性可在输入进行中或输入结束后使用.
返回导致 Input 终止的 MatchList 项目.
String := InputHook.Match
返回匹配项及其原始大小写, 如果省略了 C 选项, 则返回的大小写可能与用户键入的大小写不同. 如果 EndReason 不是 "Match", 则返回空字符串.
检索或设置在 Input 终止时调用的函数对象.
MyFunc := InputHook.OnEnd
InputHook.OnEnd := MyFunc
该函数传递一个参数: 对 InputHook 对象的引用.
该函数作为一个新线程被调用, 因此使用 SendMode 和 DetectHiddenWindows 等设置的默认值重新开始.
检索或设置将字符添加到输入缓冲后调用的函数对象.
MyFunc := InputHook.OnChar
InputHook.OnChar := MyFunc
函数被传递以下参数: InputHook, Char
. Char 是包含一个或多个字符的字符串.
多个字符的存在表明在先前最后的键击中使用了一个死键, 但是这两个键不能转换为单个字符. 例如, 在一些键盘布局中 `e 产生 è
, 而 `z 产生 `z
.
当按下结束键时, 该函数不会被调用.
检索或设置当按下启用通知的按键时调用的函数对象.
MyFunc := InputHook.OnKeyDown
InputHook.OnKeyDown := MyFunc
键-按下通知必须首先由 KeyOpt 或 NotifyNonText 启用.
函数被传递如下参数: InputHook, VK, SC
. VK 和 SC 都是整数. 要检索按键名称(如果有), 请使用 GetKeyName(Format("vk{:x}sc{:x}", VK, SC))
.
该函数作为一个新线程被调用, 因此使用设置(如 SendMode 和 DetectHiddenWindows) 的默认值重新开始.
当按下结束键时, 该函数不会被调用.
检索或设置释放启用通知的按键时调用的函数对象.
MyFunc := InputHook.OnKeyUp
InputHook.OnKeyUp := MyFunc
按键-释放通知必须首先由 KeyOpt 或 NotifyNonText 启用. 键被认为是文本还是非文本取决于什么时候键被按下. 如果 InputHook 在没有检测到 key-down 的情况下检测到 key-up, 则认为它是非文本.
函数被传递如下参数: InputHook, VK, SC
. VK 和 SC 都是整数. 要检索按键名称(如果有), 请使用 GetKeyName(Format("vk{:x}sc{:x}", VK, SC))
.
该函数作为一个新线程, 调用, 因此使用设置(如 SendMode 和 DetectHiddenWindows) 的默认值重新开始.
控制 Backspace 是否从 Input 缓冲的末尾删除最近按下的字符.
Boolean := InputHook.BackspaceIsUndo
InputHook.BackspaceIsUndo := Boolean
类型: 整数(布尔值). 默认值: true. 选项 B 设置该值为 false.
当 Backspace 用作 undo 时, 它被视为文本输入键. 具体来说, 是否抑制该键取决于 VisibleText 而不是 VisibleNonText.
Backspace 与修饰符键(如 Ctrl) 结合使用, 则始终忽略 Backspace(检查的是修饰符的逻辑状态, 而不是物理状态).
注意: 如果输入文本是可见的(如在编辑器中) 并且使用箭头键或其他方法在其中导航, Backspace 仍然会删除最后一个字符, 而不是插入符号(插入点) 后面的字符.
控制 MatchList 是否区分大小写.
Boolean := InputHook.CaseSensitive
InputHook.CaseSensitive := Boolean
类型: 整数(布尔值). 默认值: false. 选项 C 会设置该值为 true.
控制每个匹配项是否可以是输入文本的子字符串.
Boolean := InputHook.FindAnywhere
InputHook.FindAnywhere := Boolean
类型: 整数(布尔值). 默认值: false. 选项 * 设置该值为 true.
如果为真(true), 则可以在用户键入的任何位置找到匹配(匹配可以是输入文本的子字符串). 如果为假(false), 则用户键入的所有内容必须与 MatchList 中的一个短语匹配. 在这两种情况下, 都必须完整输入 MatchList 中的一个短语.
检索或设置要收集输入的最小发送级别.
Level := InputHook.MinSendLevel
InputHook.MinSendLevel := Level
Type: Integer. 默认值: 0. 选项 I 设置该值为 1(或给定值).
Level 应该是 0 到 101 之间的整数. 发送级别 低于 此值的事件将被忽略. 例如, 值 101 会忽略 SendEvent 生成的所有输入, 而值 1 只会忽略默认发送级别(0) 的输入.
无论这个设置如何, SendInput 和 SendPlay 方法总是被忽略. 除了 AutoHotkey 以外的任何其他源生成的输入都不会因为这个设置而被忽略.
控制当按下非文本键时是否调用 OnKeyDown 和 OnKeyUp 回调.
Boolean := InputHook.NotifyNonText
InputHook.NotifyNonText := Boolean
类型: 整数(布尔值). 默认值: false.
将此设置为 true 可启用所有不产生文本的按键的通知, 如按下 Left 或 Alt+F. 设置此属性不会影响按键的 options, 因为文本的生成取决于按下按键时活动窗口的键盘布局.
NotifyNonText 通过考虑先前匹配的 VK 码的 key-down 是被归类为文本还是非文本来应用 key-up 事件. 例如, 如果 NotifyNonText 为 true, 那么按下 Ctrl+A 将同时产生对 Ctrl 和 A 的 OnKeyDown 和 OnKeyUp 调用, 而按下 A 本身不会调用 OnKeyDown 或 OnKeyUp, 除非使用 KeyOpt 来启用该键的通知.
有关计为生成文本的键详细信息, 请参阅 VisibleText.
检索或设置超时值(以秒为单位).
Seconds := InputHook.Timeout
InputHook.Timeout := Seconds
类型: Float. 默认值: 0.0(无). 选项 T 也能设置超时值.
超时周期通常在调用 Start 时启动, 但如果在 Input 进行中为该属性赋值, 则会重新启动. 如果在超时时间过去后 Input 仍在进行中, 则终止输入并将 EndReason 设置为单词 Timeout.
控制不产生文本的键或键组合是否可见(不阻止).
Boolean := InputHook.VisibleNonText
InputHook.VisibleNonText := Boolean
类型: 整数(布尔值). 默认值: true. 选项 V 设置该值为 true.
如果为真, 不产生文本的键和键组合可能触发热键或被传递到活动窗口. 如果为假, 则会阻止它们.
有关计为生成文本的键详细信息, 请参阅 VisibleText.
控制产生文本的键或键组合是否可见(不阻止).
Boolean := InputHook.VisibleText
InputHook.VisibleText := Boolean
类型: 整数(布尔值). 默认值: false. 选项 V 设置该值为 true.
如果为真(true), 产生文本的键和键组合可以触发热键或被传递到活动窗口. 如果为假(false), 则会阻止它们.
导致文本被附加到输入缓冲的任何击键都被视为生成文本, 即使在其他应用程序中通常不会这样做. 例如, 如果使用 M 选项, Ctrl+A 生成文本, 而 Esc 生成控制字符 Chr(27)
.
尽管死键通常不会立即产生效果, 但它们被视为产生文本. 按下死键也可能导致后面的键生成文本(如果只有死键的字符).
Backspace 仅在作为撤销时才被计为生成文本.
标准的修饰符键和 CapsLock, NumLock 和 ScrollLock 总是可见的(不被阻止).
EndReason 属性返回以下字符串之一:
字符串 | 描述 |
---|---|
Stopped | Stop 方法已被调用或 Start 尚未被调用. |
Max | 输入达到允许的最大长度, 且它不匹配 MatchList 中的任何项. |
Timeout | Input 超时. |
Match | Input(输入) 匹配 MatchList 中的一项. Match 属性包含匹配的项. |
EndKey |
EndKeys 中的一个被按下终止了输入. EndKey 属性包含终止键的名称或字符, 不带大括号. |
如果 Input(输入) 正在进行中, EndReason 为空. |
必须先调用 Start 方法, 然后才能收集输入.
InputHook 设计为允许脚本的不同部分都能监视输入, 并且冲突最小. 它可以连续操作, 例如观察任意的单词或其他模式. 它还可以临时运行, 例如收集用户输入或临时覆盖特定(或非-特定) 按键而不干扰热键.
当 Input 正在进行时, 键盘热键仍然有效, 但是如果任何必需的修饰符键被抑制, 或者如果热键使用 reg 方法并且其后缀键被抑制, 则不能激活热键. 例如, 热键 ^+a::
可能 会被 InputHook 覆盖, 而热键 $^+a::
会优先, 除非 InputHook 抑制 Ctrl 或 Shift.
按键抑制(阻止) 与否取决于以下因素(按顺序):
Input 正在进行时需要键盘钩子, 但当 Input 终止时, 如果不再需要键盘钩子, 则会自动卸载.
Input 正在进行时, 脚本为自动持续运行, 所以即使没有正在运行的线程, 它也会继续监视输入. 当输入结束时, 脚本可能会自动退出(如果没有正在运行的线程, 并且该脚本由于其他原因而不会持续运行).
AutoHotkey 不支持输入法编辑器(IME). 键盘钩子拦截键盘事件, 并通过使用 ToUnicodeEx 或 ToAsciiEx 将它们转换为文本(VK_PACKET 事件除外, 它封装了单个字符).
如果您使用多种语言或键盘布局, 则 Input 会使用活动窗口的键盘布局而不是脚本的(不论 Input 是否可见).
尽管不够灵活, 但热字串更容易使用.
在 AutoHotkey v1.1 中, InputHook 是 Input 命令的替代品, 提供了更大的灵活性. 在 2.0 版本中删除了 Input 命令, 但下面的代码基本相同:
; Input OutputVar, % Options, % EndKeys, % MatchList ; v1 ih := InputHook(Options, EndKeys, MatchList) ih.Start() ErrorLevel := ih.Wait() if (ErrorLevel = "EndKey") ErrorLevel .= ":" ih.EndKey OutputVar := ih.Input
Input 命令终止任何先前由它启动的 Input, 而 InputHook 允许同时多个 Input.
Options 解释相同, 但默认设置不同:
Input 命令在进行时会阻塞线程, 而 InputHook 允许线程继续, 甚至退出(这允许中断的任何线程继续运行). 脚本可以注册一个 OnEnd 函数, 当输入终止时调用该函数, 而不是等待.
Input 命令只在输入终止后返回用户的输入, 而 InputHook 的 Input 属性允许在任何时候检索它. 脚本可以注册一个 OnChar 函数, 以便在字符增加时调用, 而不是不断地检查 Input 属性.
InputHook 通过 KeyOpt 方法对单个按键提供了更多控制. 这包括添加或删除结束键, 抑制或不抑制特定键, 或忽略特定键生成的文本.
与 Input 命令不同, InputHook 可用于检测不产生文本的键, 而 不 终止输入. 这是通过注册 OnKeyDown 函数和使用 KeyOpt 或 NotifyNonText 来指定相关键来完成的.
如果 MatchList 中的项目导致 Input 终止, 可以参考 Match 属性来确定到底是哪个匹配(当 * 选项存在时这更有用).
尽管脚本可以在 Input 函数返回后查询 GetKeyState, 但有时它无法准确反映输入终止时按下了哪些键. InputHook 的 EndMods 属性反映了 Input 终止时修饰键的逻辑状态.
在向后兼容性方面有一些不同之处:
如果 EndKeys 中使用的键的名称对应于两个物理键共享 VK(如 NumpadUp 和 Up), 则 Input 命令通过 VK 处理主键通过 SC 处理次要键, 而 InputHook 都通过 SC 来处理. {vkNN}
表示可以通过 VK 来处理按键.
当结束键由 VK 处理时, 两个物理键都可以终止输入. 例如, {NumpadUp}
将导致通过按下 Up 终止 Input 命令, 但是 ErrorLevel 将包含 EndKey:NumpadUp
, 因为只考虑 VK.
当结束键由 SC 处理时, Input 命令将始终为任何给定 VK 的已知辅助 SC 生成名称, 并始终为任何其他键生成 scNNN
. 与之相比, InputHook 产生按键名(如果有).
KeyWait, 热字串, InputBox, InstallKeybdHook, 线程
MsgBox KeyWaitAny() ; 再来一遍, 但不阻止按键. MsgBox KeyWaitAny("V") KeyWaitAny(Options:="") { ih := InputHook(Options) if !InStr(Options, "V") ih.VisibleNonText := false ih.KeyOpt("{All}", "E") ; 结束 ih.Start() ih.Wait() return ih.EndKey ; 返回按键名称 }
等待任何与 Ctrl/Alt/Shift/Win 组合的按键.
MsgBox KeyWaitCombo() KeyWaitCombo(Options:="") { ih := InputHook(Options) if !InStr(Options, "V") ih.VisibleNonText := false ih.KeyOpt("{All}", "E") ; 结束 ; Exclude the modifiers ih.KeyOpt("{LCtrl}{RCtrl}{LAlt}{RAlt}{LShift}{RShift}{LWin}{RWin}", "-E") ih.Start() ih.Wait() return ih.EndMods . ih.EndKey ; 返回字符串, 例如 <^<+Esc }
简单的自动完成: 一周中的任何一天. 除了字母双关外, 这是一个功能齐全的例子. 只需运行脚本并开始输入, 按 Tab 完成或按 Esc 退出.
global WordList := "Monday`nTuesday`nWednesday`nThursday`nFriday`nSaturday`nSunday" global Suffix := "", SacHook SacHook := InputHook("V", "{Esc}") SacHook.OnChar := SacChar SacHook.OnKeyDown := SacKeyDown SacHook.KeyOpt("{Backspace}", "N") SacHook.Start() SacChar(ih, char) ; 当一个字符被添加到 SacHook.Input 时调用. { Suffix := "" if RegExMatch(ih.Input, "`nm)\w+$", prefix) && RegExMatch(WordList, "`nmi)^" prefix[0] "\K.*", Suffix) Suffix := Suffix[0] if CaretGetPos(cx, cy) ToolTip Suffix, cx + 15, cy else ToolTip Suffix ; 只在显示工具提示时拦截 Tab 键. ih.KeyOpt("{Tab}", Suffix = "" ? "-NS" : "+NS") } SacKeyDown(ih, vk, sc) { if (vk = 8) ; 退格键 SacChar(ih, "") else if (vk = 9) ; Tab 键 Send "{Text}" Suffix }