AutoHotInterception使用说明翻译,以及解释,愿愿原创。

上一篇通过联想m300多功能光电鼠标侧键的重新定义,引进了AutoHotInterception。但说实话,这是相当粗糙的叙述。以下,我将,一边翻译原文,一边解释,让读者们,更好的使用这个工具。

首先,讲AutoHotInterception离不开[Interception Driver](http://www.oblita.com/interception) 拦截驱动软件。(原文我就不贴了,只翻译并解释,有兴趣的看看以上的网页)

Interception
What’s Interception?

何为Interception?

它是拦截系统与windows设备通信的编程接口软件工具。

我能用它来干什么。

Currently, with Interception you are able to intercept and transform input data from keyboard and mouse. Support is still Windows only (from Windows XP to Windows 10).

目前,用它能够拦截并转换从键盘和鼠标发送来的输入请求。它仅支持微软windows,比如:win xp到win10。

这个功能我可以用windows钩子来做,有什么问题吗?

没有问题,钩子可以做很多事情,但windows钩子有几点做不到。
1,当你有多个键盘和鼠标时,windows是不能分辨从那个键盘,或者从哪个鼠标发过来的请求。用windows Raw Input可以辨别,但无法进行拦截或者对它进行转换。

2,你无法在用户模式拦截CTRL-ALT-DELETE快捷键,以及在登陆界面做些小动作。
3,你无法用钩子来拦截一些旧版本的DirectInput编写的游戏。

好,别着急,想知道如何实现以上的功能,请往下看.
本软件包,提供了与内核模式组件通信的接口,简单但功能强大。本软件的核心位于正常驱动之上(愿愿:它可以叫筛选器驱动程序)。
曾经有人说,你这个东西对有些内核组件是无效的,这一点我不认同,事实上,它是可以做到的。

2015 Francisco Lopes with help from Jekyll Bootstrap and The Hooligan Theme

其次,我们开始进入主题。

# AutoHotInterception

AutoHotInterception(AHI) allows you to execute AutoHotkey code in response to events from a *specific* keyboard or mouse, whilst (optionally) blocking the native functionality (ie stopping Windows from seeing that keyboard or mouse event).  
In other words, you can use a key on a second (or third, or fourth..) keyboard to trigger AHK code, and that key will not be seen by applications. You can use the *same key* on multiple keyboards for individual actions.  
Keyboard Keys, Mouse Buttons and (Relative) Mouse movement are supported. Support for Absolute Mouse movement is planned.  
用AutoHotInterception(AHI)可以让你在AutoHotkey代码中,识别不同的键盘和鼠标。(愿愿:比如联想m300,就是一个鼠标和键盘的结合体,设备管理器中,它对应着一个键盘,虽然它只有一个侧键),同时它能阻塞键盘和鼠标事件,让windows无法看到阻塞的按键。也就是说,它可以用来触发AutoHotkey热键,而又不让程序或者windows知道是某个热键干的。
你可以用不同键盘的同一键,做不同的事情。键盘按键和鼠标键都是支持的,但注意鼠标移动事件,它是部分支持的(Relative)。Absolute Mouse movement就是为鼠标移动事件而专门设计的。
AHI使用了Francisco Lopez 开发的Interception driver。重要的事情说三遍,是Francisco Lopez,Francisco Lopez,Francisco Lopez。

AHI uses the Interception driver by Francisco Lopez  

# WARNING
**TAKE CARE** when using this code. Because Interception is a driver, and sits below windows proper, blocking with Interception goes so deep that it can even block CTRL+ALT+DEL etc. As such, it is entirely possible to lock up all input, or at least make life a little difficult.  
In general, worst-case scenario would require use of the reset button.  
For example, using Subscription Mode with `block` enabled will **totally** block that key from working on that keyboard.
So if you block `Ctrl` on your only keyboard, you just blocked CTRL+ALT+DEL.  
This is less of an issue whilst AHI does not support mouse blocking (As you could probably kill the script with just the mouse), but if/when that happens, the potential is there.  
Be wary of making scripts using this code run on startup. Know how to enter "Safe Mode" in windows and disable startup of the scripts. Know mouse alternatives to emergency keyboard actions (Right click on clock for Task Manager!)    
As they say - ***With great power comes great responsibility***.  
If this all scares you and you don't really understand it, then TL/DR is you should probably stick to "Context Mode", it's safer.  
警告!!!
因为Interception软件是一个驱动,虽然它并不是函数级驱动,但它好歹位于windows系统之下,它能够拦截CTRL+ALT+DEL这样的系统关键键,所以功能上它可以使得你的windows操作系统完全接受不到任何设备的输入信号,
请谨慎!!!最坏的情况下,你要重装系统才可以恢复电脑正常。(愿愿:当然,AutoHotInterception(AHI)包装了Interception的功能,也避免了你直接用Interception的危险。)
例如,如果在“Subscription Mode”(愿愿:订阅模式)下,以block参数为true,来订阅某个按键,那么你可以屏蔽那个键,让windows看不见它。
如果你用AHI屏蔽了你的电脑的唯一的键盘的Ctrl键,那么CTRL+ALT+DEL也会被屏蔽。
AHI不支持鼠标屏蔽,因为这样做,可能让你无法关闭AutoHotkey脚本。但利用该拦截驱动,你可以屏蔽鼠标,所以需要谨慎。谨慎的设置脚本开机启动,牢记安全模式进入方法,牢记鼠标右键可以在紧急情况下可以打开任务管理器,并关闭程序。
老话说,权利越大责任就越大。
如果你不太了解,那么在Context Mode(环境模式)下,使用TL/DR,这会更安全。
如何安装请看csdn博客“如何重新定义联想m300多功能鼠标的侧键?愿愿原创。 ”文章。

# Setup
1. Download and install the [Interception Driver](http://www.oblita.com/interception)  
2. Download an AHI release from the [releases page](https://github.com/evilC/AutoHotInterception/releases) and extract it to a folder.  
DO NOT use the "Clone or Download" link on the main page.  
This is the folder where (at least initially) you will be running scripts from.  
It contains a number of sample `.ahk` scripts and a `lib` folder, which contains all the libraries and files needed for AHI.  
3. Copy the `interception.dll` from the folder where you ran the interecption install into the `lib` folder that was created in step (2)  
4. Right-click `Unblocker.ps1` in the lib folder and select `Run as Admin`.  
This is because downloaded DLLs are often blocked and will not work.  
This can be done manually by right clicking the DLLs, selecting Properties, and checking a "Block" box if it exists.  
5. Edit the example script, enter the VID and PID of your keyboard  
6. Run one of the sample scripts  
7. (Optional) The contents of the `lib` folder can actually be placed in one of the AutoHotkey lib folders (eg `My Documents\AutoHotkey\lib` - make it if it does not exist), and the `#include` lines of the sample scripts changed to `#include <AutoHotInterception>`, to enable your AHI scripts to be in any folder, without each needing it's own copy of the library files.  

# Device IDs / VIDs PIDs etc  
Interception identifies unique devices by an ID. This is a number from 1..21.  
Devices 1-10 are always keyboards  
Devices 11-21 are always mice  
This ID scheme is totally unique to Interception, and IDs may change as you plug / unplug devices etc.  
On PC, devices are often identified by VendorID (VID) and ProductID (PID). These are identifiers baked into the hardware at time of manufacture, and are identical for all devices of the same make / model.  
Most AHI functions (eg to Subscribe to a key etc) use an Interception ID, so some handy functions are provided to allow you to find the (current) Interception ID of your device, given a VID / PID.  
If you are unsure of what the VID / PID of your device is (or even if Interception can see it), you can use the included Monitor script to find it.  
设备ID,厂商ID,产品ID等等吧
Interception通过“ID”来区分不同的设备
1至10代表键盘,11-21代表鼠标。当设备重插时,“ID”可能会改变。
对于个人电脑,设备经常用厂商ID(VID)和产品ID(PID)来标识,这些信息在出厂时就被烧进了硬件。
多数的AHI函数,比如订阅一个按键,使用的是Interception ID作为参数。当然,你可以很方便的使用AHI提供的函数得到它,需要提供的参数只有VID / PID。
如果不知道设备的VID与PID,你可以用AutoHotInterception(AHI),自带的Monitor脚本来查看。(愿愿:本人是用设备管理器,查看设备实例信息得到的,霍霍~)

# Usage
## Initializing the Library
Include the library
```
#Persistent ; (Interception hotkeys do not stop AHK from exiting, so use this)
Inerception热键并不排斥让AHK代码一直运行,所以加了这句,让脚本一直运行,具体说明请参考autohotkey帮助文档。
#include Lib\AutoHotInterception.ahk
```

Initialize the library
```
<<<<<<< HEAD
global AHI := InterceptionWrapper()
```
In this case, `AHI` is actually an AHK class - it wraps the AHI DLL and provides some extra functionality.  
The majority of the documented commands can be called directly on the DLL itself by calling them on `AHI.Instance` instead of `AHI`.  
在AutoHotInterception的AHK包中,我们用"AHI.Instance"来直接调用AHI DLL中绝大多数的函数。而下面主要讲的方法,是用`AHI`语句以及autohotkey简单的语法来实现,而不是用麻烦的DLL库函数,毕竟AHI事实上是AHK的一个类,它包装了AHI DLL,并提供了一些额外功能。
=======
AHI := new AutoHotInterception()
global Interception := AHI.GetInstance()
```

`AHI` is an AHK class that makes it easy to interact with the AutoHotInterception DLL. For example, it wraps `GetDeviceList()` to make it return a normal AHK array. Most of the time you will not need it.  
For advanced users, if you wish to directly communicate with the AHI DLL (eg for best possible performance), you can call `AHI.Instance` instead of `AHI` for most functions (eg when sending of synthesized input using `SendMouseMove`).  
AHI包装了`GetDeviceList()`函数,使它能够返回AHK的一个数组,通常情况下,你直接使用AHI类提供的方法来得到该数组。
如果你希望有更好的性能,需要直接调用AHI DLL库函数,你可以用"AHI.Instance"作为语句前缀,而不是`AHI`作为语句前缀。比如:用SendMouseMove来发送模拟按键输入。

>>>>>>> 612da55d842ed730fc4884b04d28356e3527e3b6

## Finding Device IDs  
### Finding a specific device  
In most cases, you will want to hard-wire a script to a specific VID/PID - in this instance, use one of the following methods.    
For all these methods, if you have multiple identical VID/PID devices, you can specify an `instance` (Starts from 1).  
如果你有多个相同VID/PID的设备,在脚本中,你可以使用“instance”参数,来标识具体是哪一个设备,该参数从1开始指定,请参照以下方法。

#### GetDeviceId
`AHI.GetDeviceId(<isMouse>, <VID>, <PID> [,<instance = 1>] )`  
Where `isMouse` is `true` if you wish to find a mouse, or `false` if you wish to find a keyboard.  
eg `AHI.GetDeviceId(false, 0x04F2, 0x0112)`  to find a keyboard with VID 0x04F2 and PID 0x0112  

如果你要得到鼠标ID,则`isMouse`设置为true,如果要得到键盘ID,则,设置为false。
比如:`AHI.GetDeviceId(false, 0x04F2, 0x0112)`,是要得到VID为0x04F2,PID为0x0112的键盘ID

#### GetKeyboardId
`AHI.GetKeyboardId(<VID>, <PID> [,<instance = 1>] )`  

#### GetMouseId
`AHI.GetMouseId(<VID>, <PID> [,<instance = 1>] )`  

### Getting a list of devices
If you wish to get a list of all available devices, you can call `AHI.GetDeviceList()`, which will return an array of `DeviceInfo` objects,
each of which has the following properties:  
要得到所有可用设备列表,可以用AHI.GetDeviceList(),返回的是`DeviceInfo`对象数组,该对象有下列属性:
```
Id
isMouse
Vid
Pid
```

## Modes
There are two modes of operation for AHI, and both can be used simultaneously.  
AHI使用,有两种模式,它们可以同时使用
### Context mode(环境模式)

Context mode is so named as it takes advantage of AutoHotkey's [Context Sensitive Hotkeys](https://autohotkey.com/docs/Hotkeys.htm#Context).  
As such, only Keyboard Keys and Mouse Buttons are supported in this mode. Mouse Movement is not supported.  
Context mode环境模式这样命名,主要是源于AutoHotkey中的Context Sensitive Hotkeys(环境条件触发热键)(参考:https://autohotkey.com/docs/Hotkeys.htm#Context).
In context mode, you create a "Context Manager" object which turns on/off a set of AHK hotkeys for you.  
You wrap your hotkeys in an #if block which is controlled by the manager.  
在环境模式中,你可以用"Context Manager"(环境管理器) 对象来打开关闭AHK热键。
Create a Context Manager for the keyboard or mouse, pass it the Interception ID of the device.  
Then Create your hotkeys, wrapped in an `#if` block that checks the `.IsActive` property of your Context Manager  
要创建一个环境管理器,可以把键盘或者鼠标的ID传给它,在使用时,将你的热键包裹在#if块中,并检查`.IsActive`属性。如下操作:
(Complete, working script)  
```
#include Lib\AutoHotInterception.ahk

keyboard1Id := AHI.GetKeyboardId(0x04F2, 0x0112)
cm1 := AHI.CreateContextManager(keyboard1Id)

#if cm1.IsActive    ; Start the #if block
::aaa::JACKPOT
1::
    ToolTip % "KEY DOWN EVENT @ " A_TickCount
    return
    
1 up::
    ToolTip % "KEY UP EVENT @ " A_TickCount
    return
#if            ; Close the #if block
```

### Subscription mode
In Subscription mode, you bypass AHK's hotkey system completely, and Interception notifies you of key events via callbacks.  
All forms of input are supported in Subscription Mode.  
Subscription Mode overrides Context Mode - that is, if a key on a keyboard has been subscribed to with Subscription Mode, then Context Mode will not fire for that key on that keyboard.  
订阅模式
在订阅模式中,订阅的AHK热键将完全绕过AHK热键系统,Interception驱动会通过回调函数来通知按键事件,编辑回调函数,你可以做你想做的任何事情。
所有的输入都是被支持的,包括鼠标和键盘。
订阅模式会覆盖环境模式,也就是说,如果一个键盘键被订阅,那么该键盘键的环境模式的热键,将不会被触发,相同的按键只会触发订阅模式中的回调函数。

#### Subscribing to Keyboard keys
Subscribe to a key on a specific keyboard
订阅方法如下:
先是,订阅指定键盘的按键的方法:

`SubscribeKey(<deviceId>, <scanCode>, <block>, <callback>)`
```
Interception.SubscribeKey(keyboardId, GetKeySC("1"), true, Func("KeyEvent"))
return
```

Callback function is passed state `0` (released) or `1` (pressed)
回调函数,state参数为0,表示被放开,1表示被按下。
```
KeyEvent(state){
    ToolTip % "State: " state
}
```


#### Subscribing to Mouse Buttons
其次,订阅鼠标键的方法
`SubscribeMouseButton(<deviceId>, <button>, <block>, <callback>)`  
Where `button` is one of:  
```
0: Left Mouse
1: Right Mouse
2: Middle Mouse
3: Side Button 1
4: Side Button 2
```  
Otherwise, usage is identical to `SubscribeKey`  
`button`参数,是以上含义,除此之外,用法与`SubscribeKey` 相同。

#### Subscribing to Mouse Movement  
**Warning!** When Subscribing to mouse movement, you will get **LOTS** of callbacks.  
Note the CPU usage of the demo Monitor app.  
AutoHotkey is *not good* for handling heavy processing in each callback (eg updating a GUI, like the monitor app does).  
Keep your callbacks **short and efficient** in this mode if you wish to avoid high CPU usage.  
最后,如何订阅鼠标移动
警告!!!当订阅鼠标移动时,将会产生大量的回调函数事件,这会给电脑造成很大负担,会拖慢电脑运行,所以订阅鼠标移动,并不是个
“好主意”。所以即使要这么做,也要尽量使得你的回调函数代码简单短小。由于时间关系,加之该订阅不常用,就不介绍了,
相信,只要是程序员,英文是必要的。

##### Relative Mode  
Relative mode is for normal mice and most trackpads.  
Coordinates will be delta (change)
`SubscribeMouseMove(<deviceId>, <block>, <callback>)`  
For Mouse Movement, the callback is passed two ints - x and y.  
```
Interception.SubscribeMouseMove(mouseId, false, Func("MouseEvent"))

MouseEvent(x, y){
    [...]
}
```

##### Absolute Mode
Absolute mode is used for Graphics Tablets, Light Guns etc.  
Coordinates will be in the range 0..65535  
```
Interception.SubscribeMouseMoveAbsolute(mouseId, false, Func("MouseEvent"))

MouseEvent(x, y){
    [...]
}
```
## Synthesizing Output
Note that these commands will work in both Context and Subscription modes  
Also note that you can send as any device, regardless of whether you have subscribed to it in some way or not.
模拟输出
以下命令,环境与订阅模式通用,请注意不论你是否已经订阅某个设备的某个按键,你都可以以该设备的名义,发送模拟输出。

### Sending Keyboard Keys
You can send keys as a specific keyboard using the `SendKeyEvent` method.  
你可以模拟发送某个键盘的按键,用`SendKeyEvent`方法。
`Interception.SendKeyEvent(<keyboardId>, <scanCode>, <state>)`  
scanCode = the Scan Code of the key  
state = 1 for press, 0 for release  
keyboardId = The Interception ID of the keyboard

```
Interception.SendKeyEvent(keyboardId, GetKeySC("a"), 1)
```


If you subscribe to a key using Subscription mode with the `block` parameter set to true, then send a different key using `SendKeyEvent`,
you are transforming that key in a way which is totally invisible to windows (And all apps running on it), and it will respond as appropriate.
 For example, AHK `$` prefixed hotkeys **will not** be able to tell that this is synthetic input, and will respond to it.

(愿愿:解释重点,请注意参考!!)
如果用Subscription模式,以block参数为true的条件,设置了一个键的回调函数,那么在该键的回调函数中,如果用SendKeyEvent发送了一个不同的按键(愿愿:也就是说,你在回调函数中没有发送自身按键),那么这个订阅按键将对于windows是不可见的(包括其上的所有程序),但同时,它根据回调函数的定义正常响应。比如,以`$`为前缀的热键,我们知道是系统钩子热键,它不会被模拟按键所触发,但如果是用SendKeyEvent发送该热键,它不会分辨出这是一个模拟
按键,它会像执行物理按键一样,触发系统钩子热键。举个例子,假设用$f定义了一个热键$f::send {f}{g},因为该热键是
由windows系统键盘钩子实现的。首先,如果用windows的send命令,它将输出f,不会触发windows系统钩子,因为send命令不能触发键盘钩子实现的热键。
其次,如果直接物理上按下f按键,它将输出输出fg。再次,如果用SendKeyEvent,发送f键,将也输出fg。$定义的windows系统钩子热键不能分辨这是一个模拟输入,会像物理按下一样正常响应。最后,这也说明了,AHI SendKeyEvent更接近物理层,并且位于windows系统钩子管理之外,windows只能把它发送的按键解释为一次真实的物理操作。但不论哪种情况,Subscription mode(分发模式)下,每个按键的回调函数,都不会被send,或者SendKeyEvent的触发,它只会被比Interception Driver驱动更为底层的驱动,或者干脆是物理层,所触发。

比如:以下例子
AHI.SubscribeKey(id2, GetKeySC("x"), false, Func("x_KeyEvent"))
AHI.SubscribeKey(id2, GetKeySC("s"), true, Func("s_KeyEvent"))
s_KeyEvent(state)
{
;   AHI.SendKeyEvent(id2, GetKeySC("m"), 1) ;true,时,s被吃掉了,windows接收不到。但能触发$定义的m热键,或酌情响应。
}
x_KeyEvent(state)
{
;   AHI.SendKeyEvent(id2, GetKeySC("m"), 1) ;相反,false时,该按键windows可以收到。
}

所以block参数用来,阻止订阅的按键本身是否对windows可见,或者说是否阻塞订阅的按键本身的输入请求传递给windows。
Normally, the windows API function RegisterHotkey() is used to implement a keyboard hotkey whenever possible. However,
the responsiveness of hotkeys might be better under some conditions if the keyboard hook is used instead.
愿愿的额外话:一般,在autohotkey编程环境中,键盘热键是用windows的RegisterHotkey()API函数实现的,可是在一些情况下,如果用键盘钩子实现,热键的响应能力会好些。
用$前缀和用#UseHook指令的作用是一样的,都是为了定义一个键盘钩子实现的热键。相反,不使用它们修饰的热键,都是用RegisterHotkey()
来实现的。

### Sending Mouse Buttons

`Interception.SendMouseButtonEvent(<mouseId>, <button>, <state>)`  
Where `button` is the button index, as used in `SubscribeMouseButton`  

### Sending Mouse Movement
#### Relative
`Interception.SendMouseMove(<mouseId>, <x>, <y>)`  

#### Absolute
`Interception.SendMouseMoveAbsolute(<mouseId>, <x>, <y>)`  

## Monitor App
ToDo: Add recording of monitor app

猜你喜欢

转载自blog.csdn.net/tom_xuzg/article/details/82823450
今日推荐