KeyOpt
InputHook
创建一个对象, 该对象可用于收集或拦截键盘输入.
InputHookObj := InputHook(Options, EndKeys, MatchList)
参数
Options
类型: 字符串
由零个或多个下列选项组成的字符串(可任意顺序, 中间可选空格):
B: 设置 BackspaceIsUndo 为 0(false), 这会导致 Backspace 被忽略.
C: 设置 CaseSensitive 为 1(true), 使 MatchList 区分大小写.
I: 设置 MinSendLevel 为 1 或给定值, 使任何输入级别低于该值的输入被忽略. 例如, I2 将忽略级别为 0(默认值) 或 1 的任何输入, 但将捕获级别为 2 的输入.
L: 长度限制(例如 L5). 输入的最大允许长度. 当文本达到这个长度时, 输入被终止, EndReason 被设置为单词 Max(除非文本匹配 MatchList 中的一个短语, 在这种情况下 EndReason 被设置为单词 Match). 如果未指定, 则长度限制为 1023.
指定 L0 禁用文本的收集和长度限制, 但并不影响按键生成的文本的统计(请参阅 VisibleText). 这可以与 OnChar, OnKeyDown, KeyOpt 或 EndKeys 参数组合使用.
M: 允许在更大范围内使修饰键击生成文本. 通常情况下, 除了 Shift, Ctrl+Alt(即 AltGr) 或 Ctrl+Alt+Shift(即 AltGr+Shift), 按键和其他修饰键组合将被视为非文本. 该选项会尝试翻译其他修饰键组合. 参考这个例子, 它识别 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 映射为 ASCII 控制字符 Chr(1) 到 Chr(26). 系统或活动窗口的键盘布局可定义其他转换. 对于键盘布局未定义修饰符位掩码的修饰符键, 转换可能会忽略. 例如, 如果使用 M 选项, Win+E 通常会转写为 “E”.
M 选项可能会导致某些键盘快捷键, 如 Ctrl+← 在 Input 正在进行时出现异常.
T: 设置 Timeout (例如 T3 或 T2.5).
V: 设置 VisibleText 和 VisibleNonText 为 1(true). 通常, 用户的输入被阻止(对系统隐藏). 使用此选项可将用户的击键发送到活动窗口.
*: 通配符. 设置 FindAnywhere 为 1(true), 允许在用户键入的任何位置找到匹配项.
E: 按字符代码而不是键码处理单字符结束键. 如果活动窗口的键盘布局与脚本的键盘布局不同, 则可以提供更一致的结果. 它还可以防止实际上不会产生给定结束字符的键组合结束 Input(输入); 例如, 如果 @ 是结束键, 则在美式键盘中 Shift+2 将触发它, 但 Ctrl+Shift+2 不会触发(在使用 E 选项时). 如果还使用 C 选项, 则结束字符区分大小写.
EndKeys
类型: 字符串
一个由零个或多个按键组成的列表, 其中任何一个键在按下时终止输入(结束键本身不会写入输入缓冲). 当 Input 以这种方式终止时, EndReason 设置为单词 EndKey, EndKey 属性设置为键的名称.
EndKeys 使用类似于 Send 函数的格式. 例如, 指定 {Enter}.{Esc} 将使 Enter, . 或 Esc 任一一个都能终止 Input. 使用大括号本身作为结束键, 指定 {{} 和/或 {}}.
要使用 Ctrl, Alt 或 Shift 作为结束键, 请指定键的左和/或右的版本, 而不是中性版本. 例如, 指定 {LControl}{RControl} 而不是 {Control}.
尽管不支持诸如 Alt+C(!c) 这样的修饰键, 而非-字母数字字符(如 ?!😡&{}) 默认情况下需要 Shift 或 AltGr 按键按下与否, 取决于字符的正常输入方式. 如果有 E 选项, 则将单个字符键名解释为字符, 在这种情况下, 修饰符键必须处于正确的状态才能生成该字符. 当同时使用 E 选项和 M 选项时, 通过在 EndKeys 中包括相应的 ASCII 控制字符来支持 Ctrl+A 到 Ctrl+Z.
还可以指定明确的虚拟按键代码, 例如 {vkFF} 或 {sc001}. 这在键没有名称且按下时不产生可见字符的罕见情况下非常有用. 它的键码可以通过按键列表页面底部的步骤来确定.
MatchList
类型: 字符串
以逗号分隔的关键词列表, 其中任何一个都将导致终止输入(在这种情况下, EndReason 将被设置为单词 Match). 用户输入的内容必须完全匹配匹配列表中的某个词组(除非有 * 选项). 此外, 分隔符逗号周围的任何空格或制表符都是有意义的, 这意味着它们是匹配字符串的一部分. 例如, 如果 MatchList 为 ABC , XYZ, 则用户必须在 ABC 之后或 XYZ 之前键入空格以形成匹配.
两个连续的逗号产生单个原义逗号. 例如, 后面的匹配列表会在 string1 的末尾产生单个原义逗号: string1,string2. 类似的, 后面的匹配列表仅包含其中有一个原义逗号的单个项目: single,item.
因为 MatchList 中的项目不被视为单独的参数, 所以列表可以完全包含在一个变量中. 事实上, 如果此列表的长度超过 16383, 那么列表的全部或部分必须包含在变量中, 因为这个长度是任何脚本行的最大长度. 例如, MatchList 可能由 List1 “,” List2 “,” List3 组成 – 其中每个变量都包含匹配词组的子列表.
Input 堆栈
任何数量的 InputHook 对象都可以在任何时候创建和进行, 但是它们启动的顺序会影响 Input 的收集方式.
当每个 Input 开始时(通过 Start 方法), 它被推到堆栈的顶部, 只有当 Input 终止时才从堆栈中删除. 键盘事件按最近开始到最早的顺序传递给每个输入. 如果一个输入抑制了一个给定的键盘事件, 那么它就不会再向下传递.
如果击键的发送级别低于 InputHook 的 MinSendLevel, 则忽略 Sent 的击键. 在这种情况下, 击键仍然可以由堆栈中较低的输入来处理.
多个 InputHook 都可以与 MinSendLevel 一起使用, 以分别收集发送的击键和实际击键.
InputHook 对象
InputHook 函数返回一个 InputHook 对象, 该对象具有以下方法和属性.
“InputHookObj” 在下面用作任何 InputHook 对象的占位符, 因为 “InputHook” 是类本身.
方法:
KeyOpt: 设置按键或按键列表的选项.
KeyOptions
类型: 字符串
下列单字符选项中的一个或多个(空格和制表符).
-(减号): 移除 - 后面的任何选项, 直到下一个 +.
+(加号): 取消任何先前的 -, 否则无效.
E: 结束键. 如果启用, 则按下键终止 Input, 将 EndReason 设置为单词 EndKey, 将 EndKey 设置为键的标准名称. 与 EndKeys 参数不同, Shift 或 AltGr 键的状态将被忽略. 例如, @ 和 2 在美式键盘布局中都相当于 {vk32}.
I: 忽略文本. 通常由该键生成的任何文本都将被忽略, 并且该键被视为非文本键(请参阅 VisibleNonText). 如果键通常不产生文本, 则没有效果.
N: 通知. 在每次按下键时调用 OnKeyDown 和 OnKeyUp 回调.
S: 处理按键后抑制(阻止) 按键. 这将覆盖 VisibleText 或 VisibleNonText 直到使用 -S. +S 意味着 -V.
其中 如果设置为 S,那么 onChar/OnKeyDown 函数会执行吗? 同时 字符会进入缓冲区吗?
V: 可见. 防止按键被抑制(阻止). 这将覆盖 VisibleText 或 VisibleNonText 直到使用 -V. +V 意味着 -S.
其中 如果设置为 S,那么 onChar/OnKeyDown 函数会执行吗? 同时 字符会进入缓冲区吗? 并详细解释每一个配置参
好的,我们来详细分析 InputHook
对象,并重点解答您关于 KeyOpt
中 S
选项的问题。
首先,直接回答您的核心问题:
KeyOpt
中 S 选项的核心问题解答
问题:如果为某个按键设置了
S
选项 (KeyOpt(Keys, "S")
),那么onChar
/OnKeyDown
函数会执行吗?同时,字符会进入缓冲区吗?
答案是:会执行,也会进入。
让我们来分解这个过程,这能帮助您更好地理解 InputHook
的工作流:
-
捕获 (Capture): 用户按下一个键。
InputHook
作为键盘钩子,在操作系统将该按键消息发送给活动窗口之前,首先捕获到这个事件。 -
处理 (Process):
InputHook
内部开始处理这个按键事件。- 回调 (Callbacks): 如果您为这个按键设置了
N
(通知) 选项,那么OnKeyDown
回调函数会被立即调用。 - 文本生成:
InputHook
会判断这个按键是否会生成一个字符(例如,按下 ‘a’ 键,而不是 ‘Shift’ 键)。- 如果它生成字符,并且您没有为这个按键设置
I
(忽略) 选项,那么这个字符会被添加到Input
缓冲区。 - 在字符被添加到缓冲区之后,
OnChar
回调函数会被立即调用。
- 如果它生成字符,并且您没有为这个按键设置
- 匹配检查:
InputHook
会检查更新后的Input
缓冲区内容是否与MatchList
中的某一项匹配,或者是否触发了其他结束条件。
- 回调 (Callbacks): 如果您为这个按键设置了
-
抑制/传递 (Suppress/Pass-through): 在
InputHook
完成了上述所有内部处理之后,它才会根据S
(抑制) 或V
(可见) 选项来决定如何处理这个按键事件的“命运”。- 如果设置了
S
选项:InputHook
会“吞掉”这个按键事件,阻止它被传递给活动窗口。因此,您在记事本或其他程序中看不到这个字符被输入。 - 如果未设置
S
(或设置了V
):InputHook
会将这个按键事件放行,让它继续传递给操作系统和活动窗口。
- 如果设置了
总结一下:
S
(抑制) 选项只影响按键事件最终是否被系统(活动窗口)看到。- 它不影响
InputHook
对象内部的处理流程。 OnKeyDown
/OnChar
的触发和字符是否进入Input
缓冲区,取决于N
(通知) 和I
(忽略) 选项,与S
无关。
InputHook 配置参数详细解释
下面我们来详细解释 InputHook
的每一个参数和选项,并辅以示例。
InputHook(Options, EndKeys, MatchList)
构造函数
这个函数用来创建一个 InputHook
的“配置实例”。它本身不开始监听,只是定义了监听的规则。
1. Options
(字符串)
这是一个由单字符代码组成的字符串,用来快速设置常用的全局选项。
-
B
:BackspaceIsUndo = false
- 解释: 默认情况下,按 Backspace 会删除
Input
缓冲区里的最后一个字符。设置B
选项后,Backspace 键会被当作一个普通按键(或被忽略),不会有删除功能。 - 场景: 当您需要捕获 Backspace 键本身,而不是用它来编辑时。
- 解释: 默认情况下,按 Backspace 会删除
-
C
:CaseSensitive = true
- 解释: 使
MatchList
中的匹配项区分大小写。默认不区分。 - 示例:
ih := InputHook("C",, "Secret")
,用户必须输入Secret
而不是secret
或SECRET
才能匹配。
- 解释: 使
-
I
:MinSendLevel
- 解释: 忽略由
Send
命令等方式模拟的、低于指定级别的键盘输入。这对于区分真实用户输入和脚本模拟输入非常有用。 - 示例:
ih := InputHook("I")
或ih := InputHook("I1")
会忽略默认级别Send "text"
的输入。ih := InputHook("I2")
会忽略SendLevel 1
及以下的输入。
- 解释: 忽略由
-
L
: 长度限制 (e.g.,L5
)- 解释: 设置
Input
缓冲区的最大字符数。一旦达到此长度,输入会立即终止,EndReason
为Max
。 - 示例:
ih := InputHook("L4")
创建一个最多只能输入4个字符的钩子,常用于密码或验证码输入。
- 解释: 设置
-
M
:Modified keys
(修饰键)- 解释: 允许
InputHook
翻译更多带有修饰键(如 Ctrl, Win)的组合键。默认情况下,只有 Shift 和 AltGr (Ctrl+Alt) 组合的按键才被视为文本。 - 示例: 要捕获 Ctrl+C,需要用
M
选项。
CtrlC := Chr(3) ih := InputHook("M L1") ih.Start() ih.Wait() if (ih.Input == CtrlC)MsgBox "你按下了 Ctrl+C"
- 解释: 允许
-
T
: 超时 (e.g.,T3
for 3 seconds)- 解释: 如果用户在指定秒数内没有任何按键输入,则自动终止输入,
EndReason
为Timeout
。计时器在每次按键后会重置。 - 示例:
ih := InputHook("T5")
,如果用户停止输入5秒,InputHook
将自动结束。
- 解释: 如果用户在指定秒数内没有任何按键输入,则自动终止输入,
-
V
:Visible
- 解释: 让用户的输入对系统可见。即用户输入的内容会同时出现在
InputHook
的缓冲区和活动窗口中(如记事本)。这等同于同时设置VisibleText
和VisibleNonText
为true
。 - 场景: 当您希望在监控用户输入的同时,不影响他们的正常打字操作。
- 解释: 让用户的输入对系统可见。即用户输入的内容会同时出现在
-
*
:FindAnywhere = true
(通配符)- 解释:
MatchList
中的匹配项可以在输入文本的任何位置被找到,而不仅仅是完全匹配。 - 示例:
; 没有 * 选项 ih := InputHook(,"exit") ih.Start() ; 用户必须精确输入 "exit" 才能匹配; 有 * 选项 ih := InputHook("*",, "exit") ih.Start() ; 用户输入 "please exit now" 时,因为包含了 "exit",输入会立即终止
- 解释:
-
E
: 按字符代码处理结束键- 解释: 使
EndKeys
参数中的单字符结束键按其字符本身来判断,而不是按物理按键。这在不同键盘布局下能提供更稳定的结果。 - 示例: 结束键是
@
。在美式键盘上,这是Shift+2
。- 无
E
选项:InputHook(,{vk32})
或InputHook(,"2")
可能会被触发。Shift+2
会触发,但如果某些程序将Ctrl+2
映射为@
,InputHook
不会响应。 - 有
E
选项:InputHook("E", "@")
。只有当用户按下能产生@
字符的组合键(通常是Shift+2
)时,输入才会终止。按下2
本身则不会终止。
- 无
- 解释: 使
2. EndKeys
(字符串)
一个以 Send
格式定义的按键列表。按下其中任何一个键都会立即终止输入。
EndReason
:EndKey
EndKey
属性: 记录是哪个键触发了终止。- 示例:
"{Enter}.{Esc}"
: Enter 键、.
键、或者 Esc 键都可以结束输入。"{LControl}{RShift}"
: 左 Ctrl 键或右 Shift 键。注意,必须指定左右,不能用中性的{Control}
。
3. MatchList
(字符串)
一个以逗号分隔的短语列表。当用户输入的内容与其中一个短语完全匹配时,输入终止。
EndReason
:Match
Match
属性: 记录匹配到的是哪个短语。- 分隔符: 逗号是分隔符。
"word1,word2,word3"
。 - 空格: 逗号周围的空格是匹配内容的一部分。
"word1 , word2"
匹配的是"word1 "
和" word2"
。 - 转义逗号: 连续两个逗号
,,
代表一个字面上的逗号。"one,,two"
匹配的是字符串"one,two"
。
KeyOpt(Keys, KeyOptions)
方法详解
此方法用于对特定的按键进行精细化的行为控制,其设置会覆盖 Options
中的全局设置。
-
Keys
: 您想控制的按键列表,格式与Send
和EndKeys
相同。{All}
: 应用于所有按键。{Enter}
: Enter 键。abc
: a, b, c 三个字母键。
-
KeyOptions
: 一串单字符选项。-
+
/-
: 用于启用或禁用后续的选项。例如+S-V
表示启用S
并禁用V
。 -
E
(End): 将此键设为结束键。这类似于将其添加到EndKeys
列表,但它忽略 Shift/AltGr 等修饰键的状态。例如,ih.KeyOpt("2", "E")
会使2
和Shift+2
(@
) 都成为结束键。 -
I
(Ignore): 忽略此键产生的文本。- 效果: 该键的字符不会进入
Input
缓冲区,OnChar
不会被调用。但OnKeyDown
(如果设置了N
) 仍然会被调用。 - 示例:
ih.KeyOpt("a", "I")
,用户输入 “banana”,ih.Input
会变成 “bnn”。
- 效果: 该键的字符不会进入
-
N
(Notify): 发出通知。- 效果: 每当按下或释放此键时,会分别调用
OnKeyDown
和OnKeyUp
回调函数。 - 示例:
ih.OnKeyDown := (ih, vk, sc) => ToolTip("Pressed key with VK: " vk)
,然后ih.KeyOpt("b", "N")
,按下b
时就会显示 ToolTip。
- 效果: 每当按下或释放此键时,会分别调用
-
S
(Suppress): 处理后抑制。- 效果:
InputHook
内部处理完该按键后(包括调用回调、添加字符到缓冲区),阻止该按键消息被发送到活动窗口。 - 关系:
+S
暗示-V
。它们是互斥的。
- 效果:
-
V
(Visible): 可见。- 效果: 强制该按键不被抑制,即使全局设置是隐藏输入。
- 关系:
+V
暗示-S
。它们是互斥的。
-
希望这份详细的解释能帮助您完全掌握 InputHook
的强大功能!