-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #13 from evilC/AHK-v2
Ahk v2
- Loading branch information
Showing
15 changed files
with
565 additions
and
75 deletions.
There are no files selected for viewing
File renamed without changes.
17 changes: 9 additions & 8 deletions
17
InterceptionTapHoldDemo.ahk → ...nterception Subscription Mode Example.ahk
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
File renamed without changes.
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
#Requires AutoHotkey v2.0 | ||
; Exmaple of Context Specific hotkeys (Only applies to a certain window) | ||
; If the library files are in a subfolder called Lib next to the script, use this | ||
#include Lib\TapHoldManager.ahk | ||
; If you placed all the library files in your My Documents\AutoHotkey\lib folder, use this | ||
;#include <TapHoldManager> | ||
|
||
thm := TapHoldManager(,,,,"ahk_exe notepad.exe") ; with window parameter set here, default window criteria that will be set for all sub-created hotkeys under this manager object is notepad | ||
thm.Add("1", MyFunc1) | ||
thm.Add("2", MyFunc2) | ||
thm.Add("3", MyFunc3,,,,,"ahk_class WordPadClass") ; this hotkey's window criteria will be WordPad (instead of manager object's previously passed-in notepad default) | ||
|
||
MyFunc1(isHold, taps, state){ | ||
ToolTip("1`n" (isHold ? "HOLD" : "TAP") "`nTaps: " taps "`nState: " state) | ||
SetTimer(RemoveTooltip, -1000) | ||
} | ||
|
||
MyFunc2(isHold, taps, state){ | ||
ToolTip("2`n" (isHold ? "HOLD" : "TAP") "`nTaps: " taps "`nState: " state) | ||
SetTimer(RemoveTooltip, -1000) | ||
} | ||
|
||
MyFunc3(isHold, taps, state){ | ||
ToolTip("3`n" (isHold ? "HOLD" : "TAP") "`nTaps: " taps "`nState: " state) | ||
SetTimer(RemoveTooltip, -1000) | ||
} | ||
|
||
RemoveTooltip(){ | ||
ToolTip | ||
} | ||
|
||
^Esc::ExitApp |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
#Requires AutoHotkey v2.0 | ||
#SingleInstance force | ||
|
||
; Demonstrates Interception Subscription Mode with TapHoldManager | ||
|
||
; Use these includes if you placed the contents of the TapHoldManager and AutoHotInterception Lib folders in the AHK lib folder (My Documents\AutoHotkey\Lib) | ||
; #include <AutoHotInterception> | ||
; #include <InterceptionTapHold> | ||
; #include <TapHoldManager> | ||
|
||
; Use these includes if you placed the contents of the TapHoldManager and AutoHotInterception Lib folders in a lib folder next to this script | ||
; ie copy the AutoHotInterception Lib folder into the TapHoldManager Lib folder | ||
#include Lib\AutoHotInterception.ahk | ||
#include Lib\InterceptionTapHold.ahk | ||
#include Lib\TapHoldManager.ahk | ||
|
||
AHI := AutoHotInterception() | ||
; keyboard1Id := AHI.GetDeviceIdFromHandle(false, "HID\VID_03EB&PID_FF02&REV_0008&MI_03") | ||
; keyboard1Id := AHI.GetKeyboardId(0x03EB, 0xFF02) | ||
keyboard1Id := 3 | ||
ITH1 := InterceptionTapHold(AHI, keyboard1Id) | ||
|
||
ITH1.Add("1", Func1) | ||
ITH1.Add("2", Func2) | ||
return | ||
|
||
Func1(isHold, taps, state){ | ||
ToolTip("KB 1 Key 1`n" (isHold ? "HOLD" : "TAP") "`nTaps: " taps "`nState: " state) | ||
} | ||
|
||
Func2(isHold, taps, state){ | ||
ToolTip("KB 1 Key 2`n" (isHold ? "HOLD" : "TAP") "`nTaps: " taps "`nState: " state) | ||
} | ||
|
||
^Esc::{ | ||
ExitApp | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
#Requires AutoHotkey v2.0 | ||
/* | ||
Remaps Keyboard Numpad to Mouse cursor movement | ||
Press and hold a key to move | ||
Double-tap and hold to move quicker | ||
Triple-tap and hold to move even quicker | ||
etc... | ||
*/ | ||
#include Lib\TapHoldManager.ahk | ||
MoveMultiplier := 5 | ||
InitMoveVectors() | ||
|
||
thm := TapHoldManager() | ||
thm.Add("NumpadLeft", HandleInput.Bind("x", "-1")) | ||
thm.Add("NumpadRight", HandleInput.Bind("x", "1")) | ||
|
||
thm.Add("NumpadUp", HandleInput.Bind("y", "-1")) | ||
thm.Add("NumpadDown", HandleInput.Bind("y", "1")) | ||
|
||
HandleInput(axis, dir, isHold, taps, state := -1){ | ||
global MoveVectors, MoveMultiplier | ||
ToolTip("isHold: " isHold ", Axis: " axis ", Dir: " dir ", Taps: " taps ", State: " state) | ||
if (state == 1){ | ||
MoveVectors[axis] := (dir * taps) * MoveMultiplier | ||
SetTimer(DoMove, 10) | ||
} else if (state == 0){ | ||
MoveVectors[axis] := 0 | ||
if (MoveVectors["x"] == 0 && MoveVectors["y"] == 0){ | ||
SetTimer(DoMove, 0) | ||
} | ||
} else { | ||
; Tap | ||
InitMoveVectors() | ||
MoveVectors[axis] := (dir * taps) * MoveMultiplier | ||
MouseMove(MoveVectors["x"], MoveVectors["y"], 0, "R") | ||
} | ||
} | ||
|
||
InitMoveVectors(){ | ||
global MoveVectors | ||
MoveVectors := Map("x", 0, "y", 0) | ||
} | ||
|
||
DoMove(){ | ||
global MoveVectors | ||
MouseMove(MoveVectors["x"], MoveVectors["y"] , 0, "R") | ||
} | ||
|
||
^Esc::ExitApp |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
#Requires AutoHotkey v2.0 | ||
|
||
; Patch for TapAndHoldManager to convert it to use Interception | ||
class InterceptionTapHold extends TapHoldManager { | ||
__New(ahi, id, tapTime?, holdTime?, maxTaps?, block := true){ | ||
this.AHI := ahi | ||
this.isMouse := (id > 10) | ||
this.block := block | ||
this.id := id | ||
super.__New(tapTime?, holdTime?, maxTaps?) | ||
} | ||
|
||
Add(keyName, callback, tapTime?, holdTime?, maxTaps?, block?){ | ||
this.Bindings[keyName] := InterceptionKeyManager(this, keyName, callback, tapTime ?? this.tapTime, holdTime ?? this.holdTime, maxTaps ?? this.maxTaps, block ?? this.block) | ||
} | ||
|
||
GetKeyboardList(){ | ||
return this.AHI.GetDeviceList() | ||
} | ||
} | ||
|
||
class InterceptionKeyManager extends TapHoldManager.KeyManager { | ||
mouseButtonIds := {LButton: 0, RButton: 1, MButton: 2, XButton1: 3, XButton2: 4} | ||
__New(manager, keyName, Callback, tapTime, holdTime, maxTaps, block){ | ||
this.block := block ?? manager.block | ||
super.__New(manager, keyName, Callback, tapTime, holdTime, maxTaps) | ||
} | ||
|
||
DeclareHotkeys(){ | ||
this.SetState(1) | ||
} | ||
|
||
SetState(state){ | ||
if (this.manager.isMouse){ | ||
if (!this.mouseButtonIds.HasKey(this.keyName)){ | ||
MsgBox("Unknown Mouse Button name " this.keyName) | ||
ExitApp | ||
} | ||
keyName := this.mouseButtonIds[this.keyName] | ||
if (state) | ||
result := this.manager.AHI.SubscribeMouseButton(this.manager.id, keyName, this.block, this.KeyEvent.Bind(this)) | ||
else | ||
result := this.manager.AHI.UnsubscribeMouseButton(this.manager.id, keyName) | ||
|
||
} else { | ||
if (state) | ||
result := this.manager.AHI.SubscribeKey(this.manager.id, GetKeySC(this.keyName), this.block, this.KeyEvent.Bind(this)) | ||
else | ||
result := this.manager.AHI.UnsubscribeKey(this.manager.id, GetKeySC(this.keyName)) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,180 @@ | ||
#Requires AutoHotkey v2.0 | ||
|
||
class TapHoldManager { | ||
Bindings := Map() | ||
|
||
__New(tapTime?, holdTime?, maxTaps := "", prefixes := "$", window := ""){ | ||
this.tapTime := tapTime ?? 150 | ||
this.holdTime := holdTime ?? this.tapTime | ||
this.maxTaps := maxTaps | ||
this.prefixes := prefixes | ||
this.window := window | ||
} | ||
|
||
; Add a key | ||
Add(keyName, callback, tapTime?, holdTime?, maxTaps?, prefixes?, window?){ | ||
if this.Bindings.Has(keyName) | ||
this.RemoveHotkey(keyName) | ||
this.Bindings[keyName] := TapHoldManager.KeyManager(this, keyName, callback, tapTime ?? this.tapTime, holdTime ?? this.holdTime, maxTaps?? this.maxTaps, prefixes?, window?) | ||
} | ||
|
||
; Remove a key | ||
RemoveHotkey(keyName){ | ||
this.Bindings.Delete(keyName).SetState(0) | ||
} | ||
|
||
; Pause a key | ||
PauseHotkey(keyName){ | ||
this.Bindings[keyName].SetState(0) | ||
} | ||
|
||
; Unpause a key | ||
ResumeHotkey(keyName){ | ||
this.Bindings[keyName].SetState(1) | ||
} | ||
|
||
class KeyManager { | ||
; AutoHotInterception mod does not use prefixes or window, so these parameters must be optional | ||
__New(manager, keyName, callback, tapTime, holdTime, maxTaps, prefixes?, window?){ | ||
this.state := 0 ; Current state of the key | ||
this.sequence := 0 ; Number of taps so far | ||
|
||
this.holdWatcherState := 0 ; Are we potentially in a hold state? | ||
this.tapWatcherState := 0 ; Has a tap release occurred and another could possibly happen? | ||
|
||
this.holdActive := 0 ; A hold was activated and we are waiting for the release | ||
|
||
this.manager := manager | ||
this.keyName := keyName | ||
this.callback := callback | ||
this.tapTime := tapTime | ||
this.holdTime := holdTime | ||
this.maxTaps := maxTaps | ||
this.prefixes := prefixes ?? manager.prefixes | ||
this.window := window ?? manager.window | ||
|
||
this.HoldWatcherFn := this.HoldWatcher.Bind(this) | ||
this.TapWatcherFn := this.TapWatcher.Bind(this) | ||
this.JoyReleaseFn := this.JoyButtonRelease.Bind(this) | ||
this.DeclareHotkeys() | ||
} | ||
|
||
; Internal use only - declares hotkeys | ||
DeclareHotkeys(){ | ||
if (this.window) | ||
HotIfWinactive this.window ; sets the hotkey window context if window option is passed-in | ||
|
||
Hotkey this.prefixes this.keyName, this.KeyEvent.Bind(this, 1), "On" ; On option is important in case hotkey previously defined and turned off. | ||
if (this.keyName ~= "i)^\d*Joy"){ | ||
Hotkey this.keyName " up", (*) => SetTimer(this.JoyReleaseFn, 10), "On" | ||
} else { | ||
Hotkey this.prefixes this.keyName " up", this.KeyEvent.Bind(this, 0), "On" | ||
} | ||
|
||
if (this.window) | ||
HotIfWinactive ; restores hotkey window context to default | ||
} | ||
|
||
; Turns On/Off hotkeys (should be previously declared) // state is either "1: On" or "0: Off" | ||
SetState(state){ | ||
; "state" under this method context refers to whether the hotkey will be turned on or off, while in other methods context "state" refers to the current activity on the hotkey (whether it's pressed or released (after a tap or hold)) | ||
if (this.window) | ||
HotIfWinactive this.window | ||
|
||
state := (state ? "On" : "Off") | ||
Hotkey this.prefixes this.keyName, state | ||
if (this.keyName ~= "i)^\d*Joy"){ | ||
Hotkey this.keyName " up", state | ||
} else { | ||
Hotkey this.prefixes this.keyName " up", state | ||
} | ||
|
||
if (this.window) | ||
HotIfWinactive | ||
} | ||
|
||
; For correcting a bug in AHK | ||
; A joystick button hotkey such as "1Joy1 up::" will fire on button down, and not on release up | ||
; So when the button is pressed, we start a timer which checks the actual state of the button using GetKeyState... | ||
; ... and when it is actually released, we fire the up event | ||
JoyButtonRelease(){ | ||
if (GetKeyState(this.keyName)) | ||
return | ||
SetTimer this.JoyReleaseFn, 0 | ||
this.KeyEvent(0) | ||
} | ||
|
||
; Called when key events (down / up) occur | ||
KeyEvent(state, *){ | ||
if (state == this.state) | ||
return ; Suppress Repeats | ||
this.state := state | ||
if (state){ | ||
; Key went down | ||
this.sequence++ | ||
this.SetHoldWatcherState(1) | ||
} else { | ||
; Key went up | ||
this.SetHoldWatcherState(0) | ||
if (this.holdActive){ | ||
this.holdActive := 0 | ||
SetTimer this.FireCallback.Bind(this, this.sequence, 0), -1 | ||
this.ResetSequence() | ||
return | ||
} else { | ||
if (this.maxTaps && this.Sequence == this.maxTaps){ | ||
SetTimer this.FireCallback.Bind(this, this.sequence, -1), -1 | ||
this.ResetSequence() | ||
} else { | ||
this.SetTapWatcherState(1) | ||
} | ||
} | ||
} | ||
} | ||
|
||
; Resets everything once a sequence completes | ||
ResetSequence(){ | ||
this.SetHoldWatcherState(0) | ||
this.SetTapWatcherState(0) | ||
this.sequence := 0 | ||
this.holdActive := 0 | ||
} | ||
|
||
; When a key is pressed, if it is not released within tapTime, then it is considered a hold | ||
SetHoldWatcherState(state){ | ||
this.holdWatcherState := state | ||
SetTimer this.HoldWatcherFn, (state ? "-" this.holdTime : 0) | ||
} | ||
|
||
; When a key is released, if it is re-pressed within tapTime, the sequence increments | ||
SetTapWatcherState(state){ | ||
this.tapWatcherState := state | ||
; SetTimer this.TapWatcherFn, (state ? "-" this.tapTime : 0) | ||
SetTimer this.TapWatcherFn, (state ? "-" this.tapTime : 0) | ||
} | ||
|
||
; If this function fires, a key was held for longer than the tap timeout, so engage hold mode | ||
HoldWatcher(){ | ||
if (this.sequence > 0 && this.state == 1){ | ||
; Got to end of tapTime after first press, and still held. | ||
; HOLD PRESS | ||
SetTimer this.FireCallback.Bind(this, this.sequence, 1), -1 | ||
this.holdActive := 1 | ||
} | ||
} | ||
|
||
; If this function fires, a key was released and we got to the end of the tap timeout, but no press was seen | ||
TapWatcher(){ | ||
if (this.sequence > 0 && this.state == 0){ | ||
; TAP | ||
SetTimer this.FireCallback.Bind(this, this.sequence), -1 | ||
this.ResetSequence() | ||
} | ||
} | ||
|
||
; Fires the user-defined callback | ||
FireCallback(seq, state := -1){ | ||
this.Callback.Call(state != -1, seq, state) | ||
} | ||
} | ||
} |
Oops, something went wrong.