AutoHotkey GUI for Macro Management
AutoHotkey GUI for Macro Management
0
A_MaxHotkeysPerInterval := 99000000
#HotIf
CurrentVersion := "1.39"
global g := {
debugProcesses: [
],
macroFolder: "C:\ProgramData\SystemInfo",
configFile: "C:\ProgramData\SystemInfo\[Link]",
bg: "0b0a0a", accent: "a2bfdf", text: "d6dded", secondary: "2D2D2D", radius: 5,
clicking: false, rightClicking: false, recordingInProgress: false,
playbackInProgress: false,
exitFlag: false, windowEnabled: false, fastPlaceEnabled: false, mouseLocked:
false,
baseDelay: 100, variationMin: 5, variationMax: 15, startupDelay: 150,
recordedActions: [], lastRecording: [], keyStates: Map(), excludedKeys:
Map("F8",1,"F9",1,"Home",1),
activeConfigs: Map("z","","x","","RAlt",""), macroStorage: Map("z",[],"x",
[],"RAlt",[]),
macroHotkeys: Map("z","","x","","RAlt",""), previousMacroHotkeys:
Map("z","","x","","RAlt",""),
mouseButtonLabels: Map("XButton1","Mouse 4","XButton2","Mouse 5"),
toggleKey: "F6", fastPlaceToggleKey: "F7", previousHotkey: "F6",
previousFastPlaceHotkey: "F7",
toggleKeyPressed: false, fastPlaceKeyPressed: false, keyCheckTimer: 0,
targetWindowTitle: "", lastMouseButtonPressed: "", lastPressedButton: ""
}
; Hotkey definitions
~F8::ToggleRecording()
~F9::SaveLastRecording()
~Home::ResetConfig()
~F12::ToggleVisibility()
~End::ExitApp()
~*XButton1::CheckMouseButton("XButton1")
~*XButton2::CheckMouseButton("XButton2")
~LButton::StartClickerWithDelay()
~LButton Up::StopClicking()
~RButton::StartRightClickerWithDelay()
~RButton Up::StopRightClicking()
~Shift & ~LButton::StartClickerWithDelay()
~Ctrl & ~LButton::StartClickerWithDelay()
~Alt & ~LButton::StartClickerWithDelay()
~Shift & ~LButton Up::StopClicking()
~Ctrl & ~LButton Up::StopClicking()
~Alt & ~LButton Up::StopClicking()
~Shift & ~RButton::StartRightClickerWithDelay()
~Ctrl & ~RButton::StartRightClickerWithDelay()
~Alt & ~RButton::StartRightClickerWithDelay()
~Shift & ~RButton Up::StopRightClicking()
~Ctrl & ~RButton Up::StopRightClicking()
~Alt & ~RButton Up::StopRightClicking()
CreateDirectories() {
if !DirExist([Link])
DirCreate([Link])
}
CheckAndTerminateDebugProcesses() {
static checking := false, currentIndex := 0
if checking
return
checking := true
try {
processesPerCheck := 10
endIndex := Min(currentIndex + processesPerCheck, [Link])
for i in Range(currentIndex + 1, endIndex) {
if ProcessExist([Link][i]) {
ExitApp()
}
}
currentIndex := (endIndex >= [Link]) ? 0 : endIndex
} finally {
checking := false
}
}
CreateGUI() {
global mainGui, tabControl, toggleCheckbox, fastPlaceCheckbox, hotkeyEdit,
fastPlaceHotkeyEdit
global targetWindowEdit, windowEnabledCheckbox, statusText, speedSlider,
speedText
global cpsSlider, cpsValue, varMinSlider, varMaxSlider, varValue
global zConfig, xConfig, raltConfig, delimitMovementCheck
SetWinDelay(-1)
mainGui := Gui("-AlwaysOnTop -Caption -DPIScale", "")
[Link] := [Link]
[Link]("s10 c" [Link], "Segoe UI")
CreateAutoClickerTab()
CreateRecraftTab()
CreateMiscTab()
CreateConfigTab()
CreateInstructions()
OnMessage(0x201, BeginDrag)
SetRoundedCorners([Link], [Link])
[Link]("w620 h555")
}
CreateAutoClickerTab() {
global cpsSlider, cpsValue, varMinSlider, varMaxSlider, varValue
global toggleCheckbox, fastPlaceCheckbox, hotkeyEdit, fastPlaceHotkeyEdit
[Link](1)
CreateRecraftTab() {
global speedSlider, speedText, zConfig, xConfig, raltConfig,
delimitMovementCheck
[Link](2)
CreateMiscTab() {
global targetWindowEdit, windowEnabledCheckbox, windowSelectorBtn
[Link](3)
CreateConfigTab() {
[Link](4)
CreateInstructions() {
[Link](0)
hotkeys := [
"• F8:`tStart/Stop recording",
"• F9:`tSave recording",
"• F12:`tHide Window",
"• HOME:`tReset config",
"• End:`tClose Menu"
]
return editCtrl
}
StartServices() {
StartKeyDetection()
}
ToggleAutoClicker(*) {
if (!IsObject(toggleCheckbox ?? ""))
return
if ([Link]) {
[Link] := "Autoclicker Enabled"
if (GetKeyState("LButton", "P") && IsTargetWindow()) {
[Link] := true
SetTimer(ClickFunction, 10)
}
} else {
if ([Link]) {
[Link] := false
SetTimer(ClickFunction, 0)
}
[Link] := "Autoclicker Disabled"
}
SaveConfiguration()
}
ToggleFastPlace(*) {
if (!IsObject(fastPlaceCheckbox ?? ""))
return
[Link] := [Link]
[Link] := "Fast Place " . ([Link] ? "Enabled" :
"Disabled")
if ([Link] && GetKeyState("RButton", "P") && IsTargetWindow()) {
[Link] := true
SetTimer(RightClickFunction, 10)
}
SaveConfiguration()
}
StartClickerWithDelay() {
if (IsObject(toggleCheckbox ?? "") && [Link] && ![Link]) {
SetTimer(DelayedClickStart, -[Link])
}
}
StartRightClickerWithDelay() {
if (IsObject(fastPlaceCheckbox ?? "") && [Link] && !
[Link]) {
SetTimer(DelayedRightClickStart, -[Link])
}
}
DelayedClickStart() {
if (GetKeyState("LButton", "P") && IsTargetWindow()) {
[Link] := true
SetTimer(ClickFunction, 10)
}
}
DelayedRightClickStart() {
if (GetKeyState("RButton", "P") && IsTargetWindow()) {
[Link] := true
SetTimer(RightClickFunction, 10)
}
}
StopClicking() {
if ([Link]) {
SetTimer(ClickFunction, 0)
[Link] := false
}
}
StopRightClicking() {
if ([Link]) {
SetTimer(RightClickFunction, 0)
[Link] := false
}
}
ClickFunction() {
if (!GetKeyState("LButton", "P") || !IsTargetWindow()) {
StopClicking()
return
}
if ([Link]) {
Click()
variation := Random([Link] * [Link] / 100, [Link] *
[Link] / 100)
actualDelay := Max([Link] + (Random(0,1) ? variation : -variation),
10)
if (!GetKeyState("LButton", "P") || !IsTargetWindow()) {
StopClicking()
return
}
Sleep(actualDelay)
}
}
RightClickFunction() {
if (!GetKeyState("RButton", "P") || !IsTargetWindow()) {
StopRightClicking()
return
}
if ([Link]) {
Click("right")
variation := Random([Link] * [Link] / 100, [Link] *
[Link] / 100)
actualDelay := Max([Link] + (Random(0,1) ? variation : -variation),
10)
if (!GetKeyState("RButton", "P") || !IsTargetWindow()) {
StopRightClicking()
return
}
Sleep(actualDelay)
}
}
StartKeyDetection() {
if ([Link] != 0) {
SetTimer(CheckToggleKeys, 0)
}
SetTimer(CheckToggleKeys, 50)
[Link] := 1
}
CheckToggleKeys() {
if ([Link] && [Link] != "") {
currentState := IsHotkeyPressed([Link])
if (currentState && ![Link]) {
[Link] := true
[Link] := ![Link]
ToggleAutoClicker()
} else if (!currentState && [Link]) {
[Link] := false
}
}
ToggleRecording(*) {
if ([Link]) {
StopRecording()
[Link] := "Recording stopped - Ready to play/save"
} else {
StartRecording()
[Link] := "Recording in progress... Press F8 to stop"
}
}
StartRecording() {
if (![Link]) {
[Link] := []
[Link] := true
[Link] := A_TickCount
SetTimer(RecordInput, 1)
}
}
StopRecording() {
if ([Link]) {
SetTimer(RecordInput, 0)
[Link] := false
[Link] := [Link]()
[Link] := "Recording stopped - Ready to play/save"
}
}
RecordInput() {
currentTime := A_TickCount - [Link]
currentPos := GetCursorPos()
if ([Link] = 0 ||
currentPos[1] != [Link][[Link]].x ||
currentPos[2] != [Link][[Link]].y) {
[Link]({type: "MOUSE", x: currentPos[1], y: currentPos[2],
time: currentTime})
}
for btn in ["LButton", "RButton", "MButton"] {
state := GetKeyState(btn, "P")
if (state && ) {
[Link]({type: "CLICK", button: btn, state: "DOWN", x:
currentPos[1], y: currentPos[2], time: currentTime})
[Link][btn] := true
} else if (!state && [Link](btn)) {
[Link]({type: "CLICK", button: btn, state: "UP", x:
currentPos[1], y: currentPos[2], time: currentTime})
[Link](btn)
}
}
Loop 256 {
vk := Format("vk{:02X}", A_Index-1)
sc := GetKeySC(vk)
if ([Link](GetKeyName(vk)) || sc = 0)
continue
keyName := GetKeyName(Format("sc{:03X}", sc))
state := GetKeyState(vk, "P")
if (state && ) {
[Link]({type: "KEY", key: keyName, state: "DOWN", x:
currentPos[1], y: currentPos[2], time: currentTime})
[Link][keyName] := true
} else if (!state && [Link](keyName)) {
[Link]({type: "KEY", key: keyName, state: "UP", x:
currentPos[1], y: currentPos[2], time: currentTime})
[Link](keyName)
}
}
}
wasLocked := [Link]
useMouseLock := [Link]
try {
BlockInput("SendAndMouse")
startTime := A_TickCount
lastEventTime := 0
if (useMouseLock)
LockMouse(action.x, action.y)
switch [Link] {
case "CLICK":
static clickFlags := Map(
"LButton", [0x0002, 0x0004],
"RButton", [0x0008, 0x0010],
"MButton", [0x0020, 0x0040]
)
if [Link]([Link]) {
flag := clickFlags[[Link]][[Link] = "DOWN" ? 1
: 2]
DllCall("mouse_event", "uint", flag, "uint", 0, "uint", 0,
"uint", 0, "uptr", 0)
if ([Link] = "DOWN")
Sleep(Max(1, 10 / speed))
}
case "KEY":
if [Link] = "DOWN" {
SendEvent("{" [Link] " Down}")
} else {
SendEvent("{" [Link] " Up}")
}
}
}
return true
} finally {
if (useMouseLock && !wasLocked)
ReleaseMouse()
BlockInput("Off")
Sleep(10)
}
}
SaveLastRecording(*) {
if (!IsTargetWindow() || ![Link]) {
[Link] := "No recording to save"
return false
}
if !DirExist([Link])
DirCreate([Link])
try {
safeTime := FormatTime(A_Now, "yyyy-MM-dd_HH-mm-ss")
filename := [Link] "\Macro_" safeTime ".txt"
if FileExist(filename)
FileDelete(filename)
LockMouse(x, y) {
lockRect := Buffer(16, 0)
NumPut("int", x, lockRect, 0)
NumPut("int", y, lockRect, 4)
NumPut("int", x + 1, lockRect, 8)
NumPut("int", y + 1, lockRect, 12)
DllCall("user32\ClipCursor", "ptr", lockRect)
[Link] := true
}
ReleaseMouse() {
DllCall("user32\ClipCursor", "ptr", 0)
[Link] := false
}
IsTargetWindow() {
if (![Link] || ![Link])
return true
try {
activeHwnd := WinActive("A")
targetHwnd := WinExist([Link])
return activeHwnd && targetHwnd && (activeHwnd = targetHwnd)
} catch {
return false
}
}
ToggleWindowTargeting(*) {
[Link] := [Link]
[Link] := "Window targeting " . ([Link] ? "enabled" :
"disabled")
SaveConfiguration()
}
SelectTargetWindow(*) {
[Link]()
windowList := Gui("+AlwaysOnTop +ToolWindow", "Select Target Window")
[Link]("s10", "Segoe UI")
[Link] := "101010"
windowTitles := []
windowIds := []
SelectWindow(*) {
selectedIndex := [Link]
if (selectedIndex > 0 && selectedIndex <= [Link]) {
hwnd := windowIds[selectedIndex]
windowTitle := windowTitles[selectedIndex]
[Link] := "ahk_id " hwnd
[Link] := windowTitle
[Link] := true
[Link] := true
SaveConfiguration()
[Link] := "Target window set: " windowTitle
}
[Link]()
[Link]()
}
CancelSelection(*) {
[Link]()
[Link]()
}
[Link]("Click", SelectWindow)
[Link]("Click", CancelSelection)
DetectHiddenWindows(False)
windowList_ := WinGetList(,, "")
windowCount := 0
Loop windowList_.Length {
hwnd := windowList_[A_Index]
title := WinGetTitle("ahk_id " hwnd)
if (title != "" && WinGetStyle("ahk_id " hwnd) & 0x10000000) {
windowCount++
[Link]([title])
[Link](title)
[Link](hwnd)
}
}
SaveConfiguration() {
try {
configData := Map()
settings := [
["playbackSpeed", [Link]],
["windowEnabled", [Link] ? 1 : 0],
["targetWindow", [Link]],
["windowDisplayName", [Link]],
["cpsValue", [Link]],
["toggleKey", [Link]],
["fastPlaceToggleKey", [Link]],
["activated", [Link] ? 1 : 0],
["fastPlaceEnabled", [Link] ? 1 : 0],
["variationMin", [Link]],
["variationMax", [Link]]
]
fileContent := ""
for key, value in configData
fileContent .= key ":" value "`n"
if FileExist([Link])
FileDelete([Link])
FileAppend(fileContent, [Link])
return true
} catch {
return false
}
}
LoadConfiguration() {
if (!FileExist([Link]))
return false
try {
configData := Map()
Loop Parse, FileRead([Link]), "`n" {
if (A_LoopField = "")
continue
if (parts := StrSplit(A_LoopField, ":")).Length >= 2 {
key := parts[1]
value := SubStr(A_LoopField, StrLen(key) + 2)
configData[key] := value
}
}
ProcessConfigData(configData)
return true
} catch {
return false
}
}
ProcessConfigData(configData) {
for key, value in configData {
if RegExMatch(key, "^(\w+)_hotkey$", &match) {
baseKey := match[1]
if [Link](baseKey) {
[Link][baseKey] := value
[Link][baseKey] := value
}
}
}
settingsMap := Map(
"playbackSpeed", (*) => ([Link] :=
Integer(configData["playbackSpeed"]), [Link] := "Current: "
([Link] / 10) "x"),
"windowEnabled", (*) => ([Link] :=
Integer(configData["windowEnabled"]), [Link] :=
[Link]),
"targetWindow", (*) => [Link] := configData["targetWindow"],
"windowDisplayName", (*) => [Link] :=
configData["windowDisplayName"],
"cpsValue", (*) => ([Link] := Integer(configData["cpsValue"]),
[Link] := Integer(configData["cpsValue"]), [Link] := 1000 /
[Link]),
"toggleKey", (*) => ([Link] := configData["toggleKey"],
[Link] := configData["toggleKey"], [Link] :=
configData["toggleKey"]),
"fastPlaceToggleKey", (*) => ([Link] :=
configData["fastPlaceToggleKey"], [Link] :=
configData["fastPlaceToggleKey"], [Link] :=
configData["fastPlaceToggleKey"]),
"activated", (*) => [Link] :=
Integer(configData["activated"]),
"fastPlaceEnabled", (*) => ([Link] :=
Integer(configData["fastPlaceEnabled"]), [Link] :=
Integer(configData["fastPlaceEnabled"])),
"variationMin", (*) => ([Link] :=
Integer(configData["variationMin"]), [Link] := [Link]),
"variationMax", (*) => ([Link] :=
Integer(configData["variationMax"]), [Link] := [Link])
)
UpdateVariation(varMinSlider, "")
}
GetConfigControl(key) {
switch key {
case "z": return zConfig
case "x": return xConfig
case "RAlt": return raltConfig
default: return false
}
}
UpdateCPS(ctrl, *) {
[Link] := 1000 / [Link]
[Link] := [Link]
SaveConfiguration()
}
UpdateSpeedDisplay(*) {
speedValue := [Link] / 10
[Link] := "Current: " speedValue "x"
SaveConfiguration()
}
UpdateVariation(ctrl, *) {
[Link] := [Link]
[Link] := [Link]
UpdateHotkey(*) {
if (IsObject(hotkeyEdit)) {
newToggleKey := [Link]
[Link] := newToggleKey
[Link] := newToggleKey
}
if (IsObject(fastPlaceHotkeyEdit)) {
newFastPlaceKey := [Link]
[Link] := newFastPlaceKey
[Link] := newFastPlaceKey
}
StartKeyDetection()
SaveConfiguration()
}
UpdateMacroHotkey(key, ctrl) {
if ([Link] != "") {
newHotkey := [Link]
[Link] := ""
friendlyName := newHotkey = "XButton1" ? "Mouse4" : "Mouse5"
[Link] := friendlyName
[Link][key] := newHotkey
[Link][key] := newHotkey
[Link] := "Macro " key " assigned to " friendlyName
SaveConfiguration()
} else {
SetKeyboardHotkey(key, ctrl)
}
}
SetKeyboardHotkey(key, hotkeyCtrl) {
newHotkey := [Link]
[Link][key] := newHotkey
[Link][key] := newHotkey
try {
Hotkey("~" . newHotkey, (*) => PlayAssignedMacro(key, [Link] /
10))
[Link] := "Macro " key " assigned to " newHotkey
} catch as err {
[Link] := "Error setting hotkey: " [Link]
}
SaveConfiguration()
}
CheckMouseButton(buttonName) {
for key, hotkey in [Link] {
if (hotkey = buttonName) {
PlayAssignedMacro(key, [Link] / 10)
break
}
}
}
SelectConfig(key) {
[Link]()
file := FileSelect(3,, "Select macro file", "Macro files (*.txt)")
[Link]()
if (file) {
try {
actions := LoadActionsFromFile(file)
[Link][key] := [Link]()
[Link][key] := file
ctrl := GetConfigControl(key)
if ctrl
[Link] := file
SaveConfiguration()
[Link] := "Macro assigned to " key
} catch as err {
MsgBox("Error loading macro: " [Link])
}
}
}
LoadActionsFromFile(file) {
actions := []
try {
Loop Read, file {
action := {}
parts := StrSplit(A_LoopReadLine, "`t")
for part in parts {
keyValue := StrSplit(part, "=")
if ([Link] = 2) {
key := keyValue[1]
value := keyValue[2]
if key ~= "^(x|y|time)$"
value := Integer(value)
action.%key% := value
}
}
[Link](action)
}
return actions
} catch as err {
MsgBox("Error loading macro: " [Link])
return []
}
}
SaveUserConfig(*) {
configName := InputBox("Enter a name for this configuration:", "Save
Configuration", "w300 h130")
if ([Link] != "OK" || [Link] = "")
return
try {
configData := Map()
configSettings := [
["playbackSpeed", [Link]],
["windowEnabled", [Link] ? 1 : 0],
["targetWindow", [Link]],
["windowDisplayName", [Link]],
["cpsValue", [Link]],
["toggleKey", [Link]],
["fastPlaceToggleKey", [Link]],
["activated", [Link] ? 1 : 0],
["fastPlaceEnabled", [Link] ? 1 : 0],
["variationMin", [Link]],
["variationMax", [Link]]
]
fileContent := ""
for key, value in configData
fileContent .= key ":" value "`n"
if FileExist(configFile)
FileDelete(configFile)
FileAppend(fileContent, configFile)
[Link] := "Configuration saved as: " safeFileName
} catch as err {
MsgBox("Error saving configuration: " [Link])
}
}
LoadUserConfig(*) {
[Link]()
file := FileSelect(1, [Link], "Select configuration file", "Config files
(*.cfg)")
[Link]()
if (file) {
try {
if FileExist(file) {
configData := Map()
Loop Parse, FileRead(file), "`n", "`r" {
if (A_LoopField = "")
continue
parts := StrSplit(A_LoopField, ":", , 2)
if ([Link] >= 2)
configData[parts[1]] := parts[2]
}
ProcessConfigData(configData)
SaveConfiguration()
[Link] := "Configuration loaded successfully"
}
} catch as err {
MsgBox("Error loading configuration: " [Link])
}
}
}
OpenConfigFolder(*) {
try {
if !DirExist([Link])
DirCreate([Link])
Run("[Link] " [Link])
[Link] := "Opened folder: " [Link]
} catch as err {
MsgBox("Error opening folder: " [Link])
}
}
ResetConfig(*) {
[Link] := Map("z", "", "x", "", "RAlt", "")
[Link] := Map("z", [], "x", [], "RAlt", [])
[Link] := Map("z", "z", "x", "x", "RAlt", "RAlt")
[Link] := Map("z", "z", "x", "x", "RAlt", "RAlt")
[Link] := ""
[Link] := ""
[Link] := ""
[Link] := ""
[Link] := false
[Link] := ""
[Link] := ""
[Link] := ""
[Link] := ""
[Link] := ""
[Link] := ""
[Link] := false
[Link] := ""
[Link] := 10
[Link] := "Current: 1.0x"
SaveConfiguration()
[Link] := "Configuration reset"
}
SelfDestruct(*) {
[Link]()
result := MsgBox("This will permanently delete all VelarioN data.`n`nAre you
sure?", "Self Destruct", "YesNo Icon!")
if (result = "Yes") {
result2 := MsgBox("WARNING: This cannot be undone!`n`nProceed?", "FINAL
WARNING", "YesNo Icon!")
if (result2 = "Yes") {
try {
[Link] := Map("z", "", "x", "", "RAlt", "")
[Link] := Map("z", [], "x", [], "RAlt", [])
[Link] := []
[Link] := []
[Link] := true
if DirExist([Link]) {
Loop Files, [Link] "\*.*"
FileDelete([Link] "\" A_LoopFileName)
DirDelete([Link])
}
[Link] := "Self destruct completed"
ExitApp()
} catch as err {
MsgBox("Self destruct error: " [Link])
}
}
}
[Link]()
}
ToggleVisibility(*) {
static isVisible := true
if (isVisible) {
[Link]()
isVisible := false
} else {
[Link]()
isVisible := true
}
}
GetCursorPos() {
pt := Buffer(8, 0)
DllCall("user32\GetCursorPos", "ptr", pt)
return [NumGet(pt, 0, "int"), NumGet(pt, 4, "int")]
}
BeginDrag(*) {
PostMessage(0xA1, 2, 0, [Link])
}
SetRoundedCorners(hwnd, radius) {
hRgn := DllCall("CreateRoundRectRgn", "int", 0, "int", 0, "int", 620, "int",
555, "int", radius*2, "int", radius*2, "ptr")
DllCall("SetWindowRgn", "ptr", hwnd, "ptr", hRgn, "int", true)
}
Range(start, end) {
result := []
Loop end - start + 1 {
[Link](start + A_Index - 1)
}
return result
}
Min(a, b) {
return (a < b) ? a : b
}
Max(a, b) {
return (a > b) ? a : b
}