Created
April 13, 2025 14:32
-
-
Save PaleNeutron/d15e3a83050473b4b33f066d12be734a to your computer and use it in GitHub Desktop.
AutoHotkey Recorder with exact timestamp
This file contains hidden or 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
| ; EDITED from https://github.com/raeleus/AHK-Macro-Recorder | |
| #Requires AutoHotkey v2.0+ | |
| ;#NoTrayIcon | |
| #SingleInstance Off | |
| Thread("NoTimers") | |
| CoordMode("ToolTip") | |
| SetTitleMatchMode(2) | |
| DetectHiddenWindows(true) | |
| ;-------------------------- | |
| if (A_Args.Length < 1) { | |
| A_Args.Push("~Record1.ahk") | |
| } | |
| if (A_Args.Length < 2) { | |
| A_Args.Push("F1") | |
| } | |
| LogFile := ".\" A_Args[1] | |
| UpdateSettings | |
| Recording := false | |
| Playing := false | |
| ActionKey := A_Args[2] | |
| Hotkey(ActionKey, KeyAction) | |
| return | |
| ShowTip(s := "", pos := "y35", color := "Red|00FFFF") { | |
| static bak := "", idx := 0, ShowTip := Gui(), RecordingControl | |
| if (bak = color "," pos "," s) | |
| return | |
| bak := color "," pos "," s | |
| SetTimer(ShowTip_ChangeColor, 0) | |
| ShowTip.Destroy() | |
| if (s = "") | |
| return | |
| ShowTip := Gui("+LastFound +AlwaysOnTop +ToolWindow -Caption +E0x08000020", "ShowTip") | |
| WinSetTransColor("FFFFF0 150") | |
| ShowTip.BackColor := "cFFFFF0" | |
| ShowTip.MarginX := 10 | |
| ShowTip.MarginY := 5 | |
| ShowTip.SetFont("q3 s20 bold cRed") | |
| RecordingControl := ShowTip.Add("Text", , s) | |
| ShowTip.Show("NA " . pos) | |
| SetTimer(ShowTip_ChangeColor, 1000) | |
| ShowTip_ChangeColor() { | |
| r := StrSplit(SubStr(bak, 1, InStr(bak, ",") - 1), "|") | |
| RecordingControl.SetFont("q3 c" r[idx := Mod(Round(idx), r.Length) + 1]) | |
| return | |
| } | |
| } | |
| ;============ Hotkey ============= | |
| KeyAction(HotkeyName) { | |
| if (Recording) { | |
| Stop | |
| return | |
| } | |
| KeyDown := A_TickCount | |
| loop { | |
| Duration := A_TickCount - KeyDown | |
| if (Duration < 400) { | |
| ShowTip | |
| if (!GetKeyState(ActionKey)) { | |
| ShowTip | |
| PlayKeyAction | |
| break | |
| } | |
| } else if (Duration < 1400) { | |
| ShowTip("RECORD") | |
| if (!GetKeyState(ActionKey)) { | |
| ShowTip | |
| RecordKeyAction | |
| break | |
| } | |
| } else { | |
| ShowTip("SHOW SOURCE") | |
| if (!GetKeyState(ActionKey)) { | |
| ShowTip | |
| EditKeyAction | |
| break | |
| } | |
| } | |
| } | |
| } | |
| RecordKeyAction() { | |
| if (Recording) { | |
| Stop() | |
| return | |
| } | |
| #SuspendExempt | |
| RecordScreen() | |
| } | |
| RecordScreen() { | |
| global LogArr := [] | |
| global oldid := "" | |
| global Recording := false | |
| global RelativeX, RelativeY | |
| if (Recording || Playing) | |
| return | |
| UpdateSettings() | |
| LogArr := [] | |
| oldid := "" | |
| Log() | |
| Recording := true | |
| SetHotkey(1) | |
| CoordMode("Mouse", "Screen") | |
| MouseGetPos(&RelativeX, &RelativeY) | |
| ShowTip("Recording") | |
| return | |
| } | |
| UpdateSettings() { | |
| global MouseMode, RecordSleep | |
| if (FileExist(LogFile)) { | |
| LogFileObject := FileOpen(LogFile, "r") | |
| Loop 3 { | |
| LogFileObject.ReadLine() | |
| } | |
| MouseMode := RegExReplace(LogFileObject.ReadLine(), ".*=") | |
| LogFileObject.ReadLine() | |
| RecordSleep := RegExReplace(LogFileObject.ReadLine(), ".*=") | |
| LogFileObject.Close() | |
| } else { | |
| MouseMode := "screen" | |
| RecordSleep := "true" | |
| } | |
| if (MouseMode != "screen" && MouseMode != "window" && MouseMode != "relative") | |
| MouseMode := "screen" | |
| if (RecordSleep != "true" && RecordSleep != "false") | |
| RecordSleep := "false" | |
| } | |
| Stop() { | |
| global LogArr, Recording, isPaused | |
| #SuspendExempt | |
| if (Recording) { | |
| if (LogArr.Length > 0) { | |
| UpdateSettings() | |
| s := ";Press " ActionKey " to play. Hold to record. Long hold to edit`n;#####SETTINGS#####`n;What is the preferred method of recording mouse coordinates (screen,window,relative)`n;MouseMode=" MouseMode "`n;Record sleep between input actions (true,false)`n;RecordSleep=" RecordSleep "`nLoop(1)`n{`n`nStartingValue := 0`ni := RegRead(`"HKEY_CURRENT_USER\SOFTWARE\`" A_ScriptName, `"i`", StartingValue)`nRegWrite(i + 1, `"REG_DWORD`", `"HKEY_CURRENT_USER\SOFTWARE\`" A_ScriptName, `"i`")`n`nSetKeyDelay(30)`nSendMode(`"Event`")`nSetTitleMatchMode(2)" | |
| if (MouseMode == "window") { | |
| s .= "`n;CoordMode(`"Mouse`", `"Screen`")`nCoordMode(`"Mouse`", `"Window`")`n" | |
| } else { | |
| s .= "`nCoordMode(`"Mouse`", `"Screen`")`n;CoordMode(`"Mouse`", `"Window`")`n" | |
| } | |
| For k, v in LogArr | |
| s .= "`n" v "`n" | |
| s .= "`n`n}`nExitApp()`n`n" ActionKey "::ExitApp()`n" | |
| s := RegExReplace(s, "\R", "`n") | |
| if (FileExist(LogFile)) | |
| FileDelete(LogFile) | |
| FileAppend(s, LogFile, "UTF-16") | |
| s := "" | |
| } | |
| Recording := 0 | |
| LogArr := "" | |
| SetHotkey(0) | |
| } | |
| ShowTip() | |
| Suspend(false) | |
| Pause(false) | |
| isPaused := false | |
| return | |
| } | |
| PlayKeyAction() { | |
| #SuspendExempt | |
| if (Recording || Playing) | |
| Stop() | |
| ahk := A_AhkPath | |
| if (!FileExist(ahk)) | |
| { | |
| MsgBox("Can't Find " ahk " !", "Error", 4096) | |
| Exit() | |
| } | |
| if (A_IsCompiled) { | |
| Run(ahk " /script /restart `"" LogFile "`"") | |
| } else { | |
| Run(ahk " /restart `"" LogFile "`"") | |
| } | |
| return | |
| } | |
| EditKeyAction() { | |
| #SuspendExempt | |
| Stop() | |
| SplitPath(LogFile, &LogFileName) | |
| try { | |
| RegDelete("HKEY_CURRENT_USER\SOFTWARE\" LogFileName, "i") | |
| } catch OSError as err { | |
| } | |
| Run("`"" EnvGet("LocalAppData") "\Programs\Microsoft VS Code\Code.exe`" `"" LogFile "`"") | |
| return | |
| } | |
| ;============ Functions ============= | |
| SetHotkey(f := false) { | |
| f := f ? "On" : "Off" | |
| Loop 254 | |
| { | |
| k := GetKeyName(vk := Format("vk{:X}", A_Index)) | |
| if (!(k ~= "^(?i:|Control|Alt|Shift)$")) | |
| Hotkey("~*" vk, LogKey, f) | |
| } | |
| For i, k in StrSplit("NumpadEnter|Home|End|PgUp" . "|PgDn|Left|Right|Up|Down|Delete|Insert", "|") | |
| { | |
| sc := Format("sc{:03X}", GetKeySC(k)) | |
| if (!(k ~= "^(?i:|Control|Alt|Shift)$")) | |
| Hotkey("~*" sc, LogKey, f) | |
| } | |
| if (f = "On") { | |
| SetTimer(LogWindow) | |
| LogWindow() | |
| } else | |
| SetTimer(LogWindow, 0) | |
| } | |
| LogKey(HotkeyName) { | |
| Critical() | |
| k := GetKeyName(vksc := SubStr(A_ThisHotkey, 3)) | |
| k := StrReplace(k, "Control", "Ctrl"), r := SubStr(k, 2) | |
| if (r ~= "^(?i:Alt|Ctrl|Shift|Win)$") | |
| LogKey_Control(k) | |
| else if (k ~= "^(?i:LButton|RButton|MButton)$") | |
| LogKey_Mouse(k) | |
| else { | |
| if (k = "NumpadLeft" || k = "NumpadRight") && !GetKeyState(k, "P") | |
| return | |
| k := StrLen(k) > 1 ? "{" k "}" : k ~= "\w" ? k : "{" vksc "}" | |
| Log(k, 1) | |
| } | |
| } | |
| LogKey_Control(key) { | |
| global LogArr | |
| k := InStr(key, "Win") ? key : SubStr(key, 2) | |
| Log("{" k " Down}", 1) | |
| Critical("Off") | |
| ErrorLevel := !KeyWait(key) | |
| Critical() | |
| Log("{" k " Up}", 1) | |
| } | |
| LogKey_Mouse(key) { | |
| global LogArr, RelativeX, RelativeY | |
| k := SubStr(key, 1, 1) | |
| ;screen | |
| CoordMode("Mouse", "Screen") | |
| MouseGetPos(&X, &Y, &id) | |
| Log((MouseMode == "window" || MouseMode == "relative" ? ";" : "") "MouseClick(`"" k "`", " X ", " Y ",,, `"D`") `;screen") | |
| ;window | |
| CoordMode("Mouse", "Window") | |
| MouseGetPos(&WindowX, &WindowY, &id) | |
| Log((MouseMode != "window" ? ";" : "") "MouseClick(`"" k "`", " WindowX ", " WindowY ",,, `"D`") `;window") | |
| ;relative | |
| CoordMode("Mouse", "Screen") | |
| MouseGetPos(&tempRelativeX, &tempRelativeY, &id) | |
| Log((MouseMode != "relative" ? ";" : "") "MouseClick(`"" k "`", " (tempRelativeX - RelativeX) ", " (tempRelativeY - RelativeY) ",,, `"D`", `"R`") `;relative") | |
| RelativeX := tempRelativeX | |
| RelativeY := tempRelativeY | |
| ;get dif | |
| CoordMode("Mouse", "Screen") | |
| MouseGetPos(&X1, &Y1) | |
| t1 := A_TickCount | |
| Critical("Off") | |
| ErrorLevel := !KeyWait(key) | |
| Critical() | |
| t2 := A_TickCount | |
| if (t2 - t1 <= 200) | |
| X2 := X1, Y2 := Y1 | |
| else | |
| MouseGetPos(&X2, &Y2) | |
| ;log screen | |
| i := LogArr.Length - 2, r := LogArr[i] | |
| if (InStr(r, ",,, `"D`")") && Abs(X2 - X1) + Abs(Y2 - Y1) < 5) | |
| LogArr[i] := SubStr(r, 1, -16) ") `;screen", Log() | |
| else | |
| Log((MouseMode == "window" || MouseMode == "relative" ? ";" : "") "MouseClick(`"" k "`", " (X + X2 - X1) ", " (Y + Y2 - Y1) ",,, `"U`") `;screen") | |
| ;log window | |
| i := LogArr.Length - 1, r := LogArr[i] | |
| if (InStr(r, ",,, `"D`")") && Abs(X2 - X1) + Abs(Y2 - Y1) < 5) | |
| LogArr[i] := SubStr(r, 1, -16) ") `;window", Log() | |
| else | |
| Log((MouseMode != "window" ? ";" : "") "MouseClick(`"" k "`", " (WindowX + X2 - X1) ", " (WindowY + Y2 - Y1) ",,, `"U`") `;window") | |
| ;log relative | |
| i := LogArr.Length, r := LogArr[i] | |
| if (InStr(r, ",,, `"D`", `"R`")") && Abs(X2 - X1) + Abs(Y2 - Y1) < 5) | |
| LogArr[i] := SubStr(r, 1, -23) ",,,, `"R`") `;relative", Log() | |
| else | |
| Log((MouseMode != "relative" ? ";" : "") "MouseClick(`"" k "`", " (X2 - X1) ", " (Y2 - Y1) ",,, `"U`", `"R`") `;relative") | |
| } | |
| LogWindow() { | |
| global oldid, LogArr, MouseMode | |
| static oldtitle | |
| id := WinExist("A") | |
| title := WinGetTitle() | |
| class := WinGetClass() | |
| if (title = "" && class = "") | |
| return | |
| if (id = oldid && title = oldtitle) | |
| return | |
| oldid := id, oldtitle := title | |
| title := SubStr(title, 1, 50) | |
| title .= class ? " ahk_class " class : "" | |
| title := RegExReplace(Trim(title), "[``%;]", "``$0") | |
| CommentString := "" | |
| if (MouseMode != "window") | |
| CommentString := ";" | |
| s := CommentString "tt := `"" title "`"`n" CommentString "WinWait(tt)" . "`n" CommentString "if (!WinActive(tt))`n" CommentString " WinActivate(tt)" | |
| i := LogArr.Length | |
| r := i = 0 ? "" : LogArr[i] | |
| if (InStr(r, "tt = ") = 1) | |
| LogArr[i] := s, Log() | |
| else | |
| Log(s) | |
| } | |
| Log(str := "", Keyboard := false) { | |
| global LogArr, RecordSleep | |
| static LastTime := 0 | |
| t := A_TickCount | |
| Delay := (LastTime ? t - LastTime : 0) | |
| LastTime := t | |
| if (str = "") | |
| return | |
| i := LogArr.Length | |
| r := i = 0 ? "" : LogArr[i] | |
| ; if (Keyboard && InStr(r, "Send") && Delay < 1000) { | |
| ; LogArr[i] := SubStr(r, 1, -1) . str "`"" | |
| ; return | |
| ; } | |
| LogArr.Push((RecordSleep == "false" ? ";" : "") "Sleep(" (Delay) ")") | |
| LogArr.Push(Keyboard ? "Send `"{Blind}" str "`"" : str) | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment