Changed concurrent switch to false by default

Some cleanup and updated README.md and CHANGELOG.md
pull/32/head
Jovan Nikolov 5 years ago
parent 3093812269
commit d27a16b01c

@ -40,8 +40,8 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Helpers\Helpers.cs" />
<Compile Include="lib\ManagedWrapper.cs" />
<Compile Include="Helpers\HelperFunctions.cs" />
<Compile Include="Helpers\ManagedWrapper.cs" />
<Compile Include="Manager.cs" />
<Compile Include="Monitor.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />

@ -3,7 +3,7 @@ using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
namespace AutoHotInterception
namespace AutoHotInterception.Helpers
{
public static class ManagedWrapper
{
@ -66,6 +66,7 @@ namespace AutoHotInterception
MouseState.Button4Up | MouseState.Button5Up,
MouseWheel = MouseState.Wheel,
MouseHWheel = MouseState.HWheel
/*
enum InterceptionFilterMouseState
@ -116,6 +117,7 @@ namespace AutoHotInterception
E1 = 0x04,
TermsrvSetLED = 0x08,
TermsrvShadow = 0x10,
TermsrvVKPacket = 0x20
/*
enum InterceptionKeyState
@ -137,6 +139,7 @@ namespace AutoHotInterception
MouseVirturalDesktop = 0x002,
MouseAttributesChanged = 0x004,
MouseMoveNocoalesce = 0x008,
MouseTermsrvSrcShadow = 0x100
/*
enum InterceptionMouseFlag
@ -174,6 +177,7 @@ namespace AutoHotInterception
Button5Up = 0x200,
Wheel = 0x400,
HWheel = 0x800
/*
enum InterceptionMouseState

@ -34,15 +34,9 @@ namespace AutoHotInterception
private readonly ConcurrentDictionary<int, ConcurrentDictionary<ushort, WorkerThread>> _workerThreads =
new ConcurrentDictionary<int, ConcurrentDictionary<ushort, WorkerThread>>();
private bool _filterState;
private Thread _pollThread;
private volatile bool _pollThreadRunning;
public void Dispose()
{
SetThreadState(false);
}
#region Public
#region Initialization
@ -52,6 +46,11 @@ namespace AutoHotInterception
_deviceContext = ManagedWrapper.CreateContext();
}
public void Dispose()
{
SetThreadState(false);
}
public string OkCheck()
{
return "OK";
@ -70,7 +69,7 @@ namespace AutoHotInterception
/// <param name="callback">The callback to fire when the key changes state</param>
/// <param name="concurrent">Whether or not to execute callbacks concurrently</param>
/// <returns></returns>
public void SubscribeKey(int id, ushort code, bool block, dynamic callback, bool concurrent = true)
public void SubscribeKey(int id, ushort code, bool block, dynamic callback, bool concurrent = false)
{
SetFilterState(false);
IsValidDeviceId(false, id);
@ -104,7 +103,7 @@ namespace AutoHotInterception
/// <param name="callback">The callback to fire when the button changes state</param>
/// <param name="concurrent">Whether or not to execute callbacks concurrently</param>
/// <returns></returns>
public void SubscribeMouseButton(int id, ushort btn, bool block, dynamic callback, bool concurrent = true)
public void SubscribeMouseButton(int id, ushort btn, bool block, dynamic callback, bool concurrent = false)
{
IsValidDeviceId(true, id);
@ -135,7 +134,7 @@ namespace AutoHotInterception
/// <param name="callback">The callback to fire when the mouse moves</param>
/// <param name="concurrent">Whether or not to execute callbacks concurrently</param>
/// <returns></returns>
public void SubscribeMouseMoveAbsolute(int id, bool block, dynamic callback, bool concurrent = true)
public void SubscribeMouseMoveAbsolute(int id, bool block, dynamic callback, bool concurrent = false)
{
IsValidDeviceId(true, id);
@ -157,7 +156,7 @@ namespace AutoHotInterception
}
//Shorthand for SubscribeMouseMoveRelative
public void SubscribeMouseMove(int id, bool block, dynamic callback, bool concurrent = true)
public void SubscribeMouseMove(int id, bool block, dynamic callback, bool concurrent = false)
{
SubscribeMouseMoveRelative(id, block, callback, concurrent);
}
@ -170,7 +169,7 @@ namespace AutoHotInterception
/// <param name="callback">The callback to fire when the mouse moves</param>
/// <param name="concurrent">Whether or not to execute callbacks concurrently</param>
/// <returns></returns>
public void SubscribeMouseMoveRelative(int id, bool block, dynamic callback, bool concurrent = true)
public void SubscribeMouseMoveRelative(int id, bool block, dynamic callback, bool concurrent = false)
{
IsValidDeviceId(true, id);
@ -437,8 +436,6 @@ namespace AutoHotInterception
{
ManagedWrapper.SetFilter(_deviceContext, IsMonitoredDevice,
state ? ManagedWrapper.Filter.All : ManagedWrapper.Filter.None);
_filterState = state;
}
// ScanCode notes: https://www.win.tue.nl/~aeb/linux/kbd/scancodes-1.html

@ -9,12 +9,16 @@ namespace AutoHotInterception
public class Monitor : IDisposable
{
private readonly IntPtr _deviceContext;
private readonly ConcurrentDictionary<int, bool> _filteredDevices = new ConcurrentDictionary<int, bool>();
private bool _filterState;
private dynamic _keyboardCallback;
private dynamic _mouseCallback;
private Thread _pollThread;
private bool _pollThreadRunning;
private volatile bool _pollThreadRunning;
#region Public
public Monitor()
{
@ -56,41 +60,43 @@ namespace AutoHotInterception
return HelperFunctions.GetDeviceList(_deviceContext);
}
private void SetFilterState(bool state)
{
ManagedWrapper.SetFilter(_deviceContext, IsMonitoredDevice,
state ? ManagedWrapper.Filter.All : ManagedWrapper.Filter.None);
_filterState = state;
}
#endregion
private int IsMonitoredDevice(int device)
{
return Convert.ToInt32(_filteredDevices.ContainsKey(device));
}
#region Private
private void SetThreadState(bool state)
{
if (state)
{
if (_pollThreadRunning) return;
_pollThreadRunning = true;
_pollThread = new Thread(PollThread);
_pollThread.Start();
}
else
{
_pollThread.Abort();
_pollThreadRunning = true;
_pollThread.Join();
_pollThread = null;
}
}
private int IsMonitoredDevice(int device)
{
return Convert.ToInt32(_filteredDevices.ContainsKey(device));
}
private void SetFilterState(bool state)
{
ManagedWrapper.SetFilter(_deviceContext, IsMonitoredDevice,
state ? ManagedWrapper.Filter.All : ManagedWrapper.Filter.None);
}
private void PollThread()
{
var stroke = new ManagedWrapper.Stroke();
while (true)
while (_pollThreadRunning)
{
for (var i = 1; i < 11; i++)
while (ManagedWrapper.Receive(_deviceContext, i, ref stroke, 1) > 0)
@ -121,5 +127,7 @@ namespace AutoHotInterception
ThreadPool.QueueUserWorkItem(threadProc => _mouseCallback(id, stroke.mouse.state, stroke.mouse.flags,
stroke.mouse.rolling, stroke.mouse.x, stroke.mouse.y, stroke.mouse.information));
}
#endregion
}
}

@ -18,24 +18,24 @@ namespace TestApp
{
im.SubscribeMouseButton(mouseId, 1, true, new Action<int>(value =>
{
//Console.WriteLine("RButton Button Value: " + value);
Console.WriteLine("RButton Button Value: " + value);
}));
im.SubscribeMouseButton(mouseId, 3, true, new Action<int>(value =>
{
//Console.WriteLine("XButton1 Button Value: " + value);
Console.WriteLine("XButton1 Button Value: " + value);
}));
im.SubscribeMouseButton(mouseId, 4, true, new Action<int>(value =>
{
//Console.WriteLine("XButton2 Button Value: " + value);
Console.WriteLine("XButton2 Button Value: " + value);
}));
im.SubscribeMouseButton(mouseId, 5, true, new Action<int>(value =>
{
//Console.WriteLine("WheelVertical Value: " + value);
Console.Write("WheelVertical Value: " + value);
var mycounter = counter;
mycounter++;
Console.WriteLine("Counter: " + mycounter);
Console.WriteLine(" Counter: " + mycounter);
counter = mycounter;
}), false);
}));
}
Console.ReadLine();

@ -5,11 +5,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
## [Unreleased]
### Added
### Changed
- Concurrency switch for executing subscription callback functions. Was implicitly executing on a new thread from the pool, now there is an option to execute each callback on a single thread (one worker per subscription).
### Changed
- By default the new concurrency switch will be set to false meaning that for every subscription there will be only a single worker thread and callbacks will be run sequentially.
### Deprecated
### Removed
### Fixed
- SubscribeMouseMove endpoint fixed to not return bool (Fix "Can not implicitly convert type Void to object" error)
## [0.3.7] - 2018-12-11
- SubscribeMouseMove endpoint fixed to not return bool. (Fix "Can not implicitly convert type Void to object" error)
## [0.3.7] - 2018-12-11

@ -2,18 +2,18 @@
class AutoHotInterception {
_contextManagers := {}
;_contextStates := {}
__New(cls := "Manager"){
__New(cls := "Manager") {
bitness := A_PtrSize == 8 ? "x64" : "x86"
dllName := "interception.dll"
dllFile := A_LineFile "\..\" bitness "\" dllName
if (!FileExist(dllFile)){
if (!FileExist(dllFile)) {
MsgBox % "Unable to find lib\" bitness "\" dllName ", exiting...`nYou should extract both x86 and x64 folders from the library folder in interception.zip into AHI's lib folder."
ExitApp
}
hModule := DllCall("LoadLibrary", "Str", dllFile, "Ptr")
if (hModule == 0){
if (hModule == 0) {
this_bitness := A_PtrSize == 8 ? "64-bit" : "32-bit"
other_bitness := A_PtrSize == 4 ? "64-bit" : "32-bit"
MsgBox % "Bitness of " dllName " does not match bitness of AHK.`nAHK is " this_bitness ", but " dllName " is " other_bitness "."
@ -24,7 +24,7 @@ class AutoHotInterception {
dllName := "AutoHotInterception.dll"
dllFile := A_LineFile "\..\" dllName
hintMessage := "Try right-clicking lib\" dllName ", select Properties, and if there is an 'Unblock' checkbox, tick it`nAlternatively, running Unblocker.ps1 in the lib folder (ideally as admin) can do this for you."
if (!FileExist(dllFile)){
if (!FileExist(dllFile)) {
MsgBox % "Unable to find lib\" dllName ", exiting..."
ExitApp
}
@ -37,79 +37,79 @@ class AutoHotInterception {
MsgBox % dllName " failed to load`n`n" hintMessage
ExitApp
}
if (this.Instance.OkCheck() != "OK"){
if (this.Instance.OkCheck() != "OK") {
MsgBox % dllName " loaded but check failed!`n`n" hintMessage
ExitApp
}
}
GetInstance(){
GetInstance() {
return this.Instance
}
; --------------- Input Synthesis ----------------
SendKeyEvent(id, code, state){
SendKeyEvent(id, code, state) {
this.Instance.SendKeyEvent(id, code, state)
}
SendMouseButtonEvent(id, btn, state){
SendMouseButtonEvent(id, btn, state) {
this.Instance.SendMouseButtonEvent(id, btn, state)
}
SendMouseButtonEventAbsolute(id, btn, state, x, y){
SendMouseButtonEventAbsolute(id, btn, state, x, y) {
this.Instance.SendMouseButtonEventAbsolute(id, btn, state, x, y)
}
SendMouseMove(id, x, y){
SendMouseMove(id, x, y) {
this.Instance.SendMouseMove(id, x, y)
}
SendMouseMoveRelative(id, x, y){
SendMouseMoveRelative(id, x, y) {
this.Instance.SendMouseMoveRelative(id, x, y)
}
SendMouseMoveAbsolute(id, x, y){
SendMouseMoveAbsolute(id, x, y) {
this.Instance.SendMouseMoveAbsolute(id, x, y)
}
*/
; --------------- Querying ------------------------
GetDeviceID(IsMouse, VID, PID, instance := 1){
GetDeviceId(IsMouse, VID, PID, instance := 1) {
static devType := {0: "Keyboard", 1: "Mouse"}
dev := this.Instance.GetDeviceId(IsMouse, VID, PID, instance)
if (dev == 0){
if (dev == 0) {
MsgBox % "Could not get " devType[isMouse] " with VID " VID ", PID " PID ", Instance " instance
ExitApp
}
return dev
}
GetDeviceIdFromHandle(isMouse, handle, instance := 1){
GetDeviceIdFromHandle(isMouse, handle, instance := 1) {
static devType := {0: "Keyboard", 1: "Mouse"}
dev := this.Instance.GetDeviceIdFromHandle(IsMouse, handle, instance)
if (dev == 0){
if (dev == 0) {
MsgBox % "Could not get " devType[isMouse] " with Handle " handle ", Instance " instance
ExitApp
}
return dev
}
GetKeyboardID(VID, PID, instance := 1){
GetKeyboardId(VID, PID, instance := 1) {
return this.GetDeviceId(false, VID, PID, instance)
}
GetMouseID(VID, PID, instance := 1){
GetMouseId(VID, PID, instance := 1) {
return this.GetDeviceId(true, VID, PID, instance)
}
GetKeyboardIdFromHandle(handle, instance := 1){
GetKeyboardIdFromHandle(handle, instance := 1) {
return this.GetDeviceIdFromHandle(false, handle, instance)
}
GetMouseIDFromHandle(handle, instance := 1){
GetMouseIdFromHandle(handle, instance := 1) {
return this.GetDeviceIdFromHandle(true, handle, instance)
}
GetDeviceList(){
GetDeviceList() {
DeviceList := {}
arr := this.Instance.GetDeviceList()
for v in arr {
@ -117,32 +117,32 @@ class AutoHotInterception {
}
return DeviceList
}
; ---------------------- Subscription Mode ----------------------
SubscribeKey(id, code, block, callback, concurrent := true){
SubscribeKey(id, code, block, callback, concurrent := false) {
this.Instance.SubscribeKey(id, code, block, callback, concurrent)
}
SubscribeMouseButton(id, btn, block, callback, concurrent := true){
SubscribeMouseButton(id, btn, block, callback, concurrent := false) {
this.Instance.SubscribeMouseButton(id, btn, block, callback, concurrent)
}
SubscribeMouseMove(id, block, callback, concurrent := true){
SubscribeMouseMove(id, block, callback, concurrent := false) {
this.Instance.SubscribeMouseMove(id, block, callback, concurrent)
}
SubscribeMouseMoveRelative(id, block, callback, concurrent := true){
SubscribeMouseMoveRelative(id, block, callback, concurrent := false) {
this.Instance.SubscribeMouseMoveRelative(id, block, callback, concurrent)
}
SubscribeMouseMoveAbsolute(id, block, callback, concurrent := true){
SubscribeMouseMoveAbsolute(id, block, callback, concurrent := false) {
this.Instance.SubscribeMouseMoveAbsolute(id, block, callback, concurrent)
}
; ------------- Context Mode ----------------
; Creates a context class to make it easy to turn on/off the hotkeys
CreateContextManager(id){
if (this._contextManagers.ContainsKey(id)){
CreateContextManager(id) {
if (this._contextManagers.ContainsKey(id)) {
Msgbox % "ID " id " already has a Context Manager"
ExitApp
}
@ -154,14 +154,13 @@ class AutoHotInterception {
; Helper class for dealing with context mode
class ContextManager {
IsActive := 0
__New(parent, id){
__New(parent, id) {
this.parent := parent
this.id := id
result := this.parent.Instance.SetContextCallback(id, this.OnContextCallback.Bind(this))
}
OnContextCallback(state){
OnContextCallback(state) {
Sleep 0
this.IsActive := state
}

@ -1,16 +1,17 @@
; ==========================================================
; .NET Framework Interop
; http://www.autohotkey.com/forum/topic26191.html
; ==========================================================
; ========================================================================
; .NET Framework Interop
; http://www.autohotkey.com/forum/topic26191.html
; ========================================================================
;
; Author: Lexikos
; Version: 1.2
; Requires: AutoHotkey_L v1.0.96+
; Requires: AutoHotkey_L v1.0.96+
;
; Modified by evilC for compatibility with AHK_H as well as AHK_L
; "null" is a reserved word in AHK_H, so did search & Replace from "null" to "_null"
CLR_LoadLibrary(AssemblyName, AppDomain=0)
{
; "null" is a reserved word in AHK_H, so "null" was replaced with "_null"
; ========================================================================
CLR_LoadLibrary(AssemblyName, AppDomain=0) {
if !AppDomain
AppDomain := CLR_GetDefaultDomain()
e := ComObjError(0)
@ -29,47 +30,43 @@ CLR_LoadLibrary(AssemblyName, AppDomain=0)
return assembly
}
CLR_CreateObject(Assembly, TypeName, Args*)
{
CLR_CreateObject(Assembly, TypeName, Args*) {
if !(argCount := Args.MaxIndex())
return Assembly.CreateInstance_2(TypeName, true)
vargs := ComObjArray(0xC, argCount)
Loop % argCount
vargs[A_Index-1] := Args[A_Index]
static Array_Empty := ComObjArray(0xC,0), _null := ComObject(13,0)
return Assembly.CreateInstance_3(TypeName, true, 0, _null, vargs, _null, Array_Empty)
}
CLR_CompileC#(Code, References="", AppDomain=0, FileName="", CompilerOptions="")
{
CLR_CompileC#(Code, References="", AppDomain=0, FileName="", CompilerOptions="") {
return CLR_CompileAssembly(Code, References, "System", "Microsoft.CSharp.CSharpCodeProvider", AppDomain, FileName, CompilerOptions)
}
CLR_CompileVB(Code, References="", AppDomain=0, FileName="", CompilerOptions="")
{
CLR_CompileVB(Code, References="", AppDomain=0, FileName="", CompilerOptions="") {
return CLR_CompileAssembly(Code, References, "System", "Microsoft.VisualBasic.VBCodeProvider", AppDomain, FileName, CompilerOptions)
}
CLR_StartDomain(ByRef AppDomain, BaseDirectory="")
{
CLR_StartDomain(ByRef AppDomain, BaseDirectory="") {
static _null := ComObject(13,0)
args := ComObjArray(0xC, 5), args[0] := "", args[2] := BaseDirectory, args[4] := ComObject(0xB,false)
AppDomain := CLR_GetDefaultDomain().GetType().InvokeMember_3("CreateDomain", 0x158, _null, _null, args)
return A_LastError >= 0
}
CLR_StopDomain(ByRef AppDomain)
{ ; ICorRuntimeHost::UnloadDomain
CLR_StopDomain(ByRef AppDomain) {
; ICorRuntimeHost::UnloadDomain
DllCall("SetLastError", "uint", hr := DllCall(NumGet(NumGet(0+RtHst:=CLR_Start())+20*A_PtrSize), "ptr", RtHst, "ptr", ComObjValue(AppDomain))), AppDomain := ""
return hr >= 0
}
; NOTE: IT IS NOT NECESSARY TO CALL THIS FUNCTION unless you need to load a specific version.
CLR_Start(Version="") ; returns ICorRuntimeHost*
{
CLR_Start(Version="") {
; returns ICorRuntimeHost*
static RtHst := 0
; The simple method gives no control over versioning, and seems to load .NET v2 even when v4 is present:
; return RtHst ? RtHst : (RtHst:=COM_CreateObject("CLRMetaData.CorRuntimeHost","{CB2F6722-AB3A-11D2-9C40-00C04FA30A3E}"), DllCall(NumGet(NumGet(RtHst+0)+40),"uint",RtHst))
@ -92,22 +89,20 @@ CLR_Start(Version="") ; returns ICorRuntimeHost*
; INTERNAL FUNCTIONS
;
CLR_GetDefaultDomain()
{
CLR_GetDefaultDomain() {
static defaultDomain := 0
if !defaultDomain
{ ; ICorRuntimeHost::GetDefaultDomain
if !defaultDomain {
; ICorRuntimeHost::GetDefaultDomain
if DllCall(NumGet(NumGet(0+RtHst:=CLR_Start())+13*A_PtrSize), "ptr", RtHst, "ptr*", p:=0) >= 0
defaultDomain := ComObject(p), ObjRelease(p)
}
return defaultDomain
}
CLR_CompileAssembly(Code, References, ProviderAssembly, ProviderType, AppDomain=0, FileName="", CompilerOptions="")
{
CLR_CompileAssembly(Code, References, ProviderAssembly, ProviderType, AppDomain=0, FileName="", CompilerOptions="") {
if !AppDomain
AppDomain := CLR_GetDefaultDomain()
if !(asmProvider := CLR_LoadLibrary(ProviderAssembly, AppDomain))
|| !(codeProvider := asmProvider.CreateInstance(ProviderType))
|| !(codeCompiler := codeProvider.CreateCompiler())
@ -115,13 +110,13 @@ CLR_CompileAssembly(Code, References, ProviderAssembly, ProviderType, AppDomain=
if !(asmSystem := (ProviderAssembly="System") ? asmProvider : CLR_LoadLibrary("System", AppDomain))
return 0
; Convert | delimited list of references into an array.
StringSplit, Refs, References, |, %A_Space%%A_Tab%
aRefs := ComObjArray(8, Refs0)
Loop % Refs0
aRefs[A_Index-1] := Refs%A_Index%
; Set parameters for compiler.
prms := CLR_CreateObject(asmSystem, "System.CodeDom.Compiler.CompilerParameters", aRefs)
, prms.OutputAssembly := FileName
@ -129,12 +124,11 @@ CLR_CompileAssembly(Code, References, ProviderAssembly, ProviderType, AppDomain=
, prms.GenerateExecutable := SubStr(FileName,-3)=".exe"
, prms.CompilerOptions := CompilerOptions
, prms.IncludeDebugInformation := true
; Compile!
compilerRes := codeCompiler.CompileAssemblyFromSource(prms, Code)
if error_count := (errors := compilerRes.Errors).Count
{
if error_count := (errors := compilerRes.Errors).Count {
error_text := ""
Loop % error_count
error_text .= ((e := errors.Item[A_Index-1]).IsWarning ? "Warning " : "Error ") . e.ErrorNumber " on line " e.Line ": " e.ErrorText "`n`n"
@ -145,8 +139,7 @@ CLR_CompileAssembly(Code, References, ProviderAssembly, ProviderType, AppDomain=
return compilerRes[FileName="" ? "CompiledAssembly" : "PathToAssembly"]
}
CLR_GUID(ByRef GUID, sGUID)
{
CLR_GUID(ByRef GUID, sGUID) {
VarSetCapacity(GUID, 16, 0)
return DllCall("ole32\CLSIDFromString", "wstr", sGUID, "ptr", &GUID) >= 0 ? &GUID : ""
}
}

@ -6,7 +6,7 @@
# 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).
AutoHotInterception (AHI) allows you to execute AutoHotkey code in response to events from a *specific* keyboard or mouse, whilst (optionally) blocking the native functionality (i.e. 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 Mouse movement (Both Relative and Absolute modes) are supported.
@ -52,13 +52,13 @@ 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. Extract both `x86` and `x64` folders from the `library` folder in `interception.zip` 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.
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. If you do not know the VID/PID of your device, use the included Monitor app to find it.
When using the monitor app, **DO NOT** tick all devices at once, as if it crashes, it will lock up all devices.
Instead, tick one at a time and see if it your device.
When using the monitor app, **DO NOT** tick all devices at once, as if it crashes, it will lock up all devices.
Instead, tick one at a time and see if it your device.
6. Edit one of the example remapping scripts, replacing the VID/PID(s) with that of your device and run it to make sure it works.
6. (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.
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.
------
@ -72,7 +72,7 @@ Include the library
Initialize the library
```
global AHI := InterceptionWrapper()
global AHI := new AutoHotInterception()
```
*Note*
@ -164,7 +164,7 @@ Subscription Mode overrides Context Mode - that is, if a key on a keyboard has b
#### Subscribing to Keyboard keys
Subscribe to a key on a specific keyboard
`SubscribeKey(<deviceId>, <scanCode>, <block>, <callback>)`
`SubscribeKey(<deviceId>, <scanCode>, <block>, <callback>, <concurrent>)`
```
Interception.SubscribeKey(keyboardId, GetKeySC("1"), true, Func("KeyEvent"))
return
@ -177,8 +177,9 @@ KeyEvent(state){
}
```
Parameter `<concurrent>` is optional and is <b>false</b> by default meaning that all the events raised for that key will be handled sequentially (i.e. callback function will be called on a single thread). If set to <b>true</b>, a new thread will be created for each event and the callback function will be called on it.
#### Subscribing to Mouse Buttons
`SubscribeMouseButton(<deviceId>, <button>, <block>, <callback>)`
`SubscribeMouseButton(<deviceId>, <button>, <block>, <callback>, <concurrent>)`
Where `button` is one of:
```
0: Left Mouse
@ -202,7 +203,7 @@ Keep your callbacks **short and efficient** in this mode if you wish to avoid hi
##### Relative Mode
Relative mode is for normal mice and most trackpads.
Coordinates will be delta (change)
`SubscribeMouseMove(<deviceId>, <block>, <callback>)`
`SubscribeMouseMove(<deviceId>, <block>, <callback>, <concurrent>)`
For Mouse Movement, the callback is passed two ints - x and y.
```
Interception.SubscribeMouseMove(mouseId, false, Func("MouseEvent"))
@ -215,6 +216,8 @@ MouseEvent(x, y){
##### Absolute Mode
Absolute mode is used for Graphics Tablets, Light Guns etc.
Coordinates will be in the range 0..65535
`SubscribeMouseMoveAbsolute(<deviceId>, <block>, <callback>, <concurrent>)`
Again, the callback is passed two ints - x and y.
```
Interception.SubscribeMouseMoveAbsolute(mouseId, false, Func("MouseEvent"))
@ -260,4 +263,4 @@ To sent Absolute mouse movement, use:
Note that Absolute mode will probably not work with FPS style mouse-aim games.
## Monitor App
ToDo: Add recording of monitor app
ToDo: Add recording of monitor app
Loading…
Cancel
Save