Mouse And Keyboard Macro Recorder

Post your working scripts, libraries and tools for AHK v1.1 and older
feiyue
Posts: 381
Joined: 08 Aug 2014, 04:08

Mouse And Keyboard Macro Recorder

08 Jul 2017, 08:30

This is a useful script to record mouse, keyboard actions and playback.
Using it, You can quickly write simple automated scripts.
Hope you like it. :dance:

Code: Select all

;-----------------------------------
;  Macro Recorder v2.1  By FeiYue
;
;  Description: This script records the mouse
;  and keyboard actions and then plays back.
;
;  F1  -->  Record(Screen) (CoordMode, Mouse, Screen)
;  F2  -->  Record(Window) (CoordMode, Mouse, Window)
;  F3  -->  Stop   Record/Play
;  F4  -->  Play   LogFile
;  F5  -->  Edit   LogFile
;  F6  -->  Pause  Record/Play
;
;  Note:
;  1. press the Ctrl button individually
;     to record the movement of the mouse.
;  2. Shake the mouse on the Pause button,
;     you can pause recording or playback.
;-----------------------------------

#NoEnv
SetBatchLines, -1
Thread, NoTimers
CoordMode, ToolTip
SetTitleMatchMode, 2
DetectHiddenWindows, On
;--------------------------
LogFile:=A_Temp . "\~Record.txt"
UsedKeys:="F1,F2,F3,F4,F5,F6"
Play_Title:=RegExReplace(LogFile,".*\\") " ahk_class AutoHotkey"
;--------------------------
Gui, +AlwaysOnTop -Caption +ToolWindow +E0x08000000 +Hwndgui_id
Gui, Margin, 0, 0
Gui, Font, s12
s:="[F1]Record(Screen),[F2]Record(Window),"
  . "[F3]Stop,[F4]Play,[F5]Edit,[F6] Pause "
For i,v in StrSplit(s, ",")
{
  j:=i=1 ? "":"x+0", j.=InStr(v,"Pause") ? " vPause":""
  Gui, Add, Button, %j% gRun, %v%
}
Gui, Add, Button, x+0 w0 Hidden vMyText
Gui, Show, NA y0, Macro Recorder
OnMessage(0x200,"WM_MOUSEMOVE")
;--------------------------
SetTimer, OnTop, 2000
OnTop:
Gui, +AlwaysOnTop
return

Run:
if IsLabel(k:=RegExReplace(RegExReplace(A_GuiControl,".*]"),"\W"))
  Goto, %k%
return

WM_MOUSEMOVE() {
  static OK_Time
  ListLines, Off
  if (A_Gui=1) and (A_GuiControl="Pause")
    and (t:=A_TickCount)>OK_Time
  {
    OK_Time:=t+500
    Gosub, Pause
  }
}

ShowTip(s:="", pos:="y35", color:="Red|00FFFF") {
  static bak, idx
  if (bak=color "," pos "," s)
    return
  bak:=color "," pos "," s
  SetTimer, ShowTip_ChangeColor, Off
  Gui, ShowTip: Destroy
  if (s="")
    return
  ; WS_EX_NOACTIVATE:=0x08000000, WS_EX_TRANSPARENT:=0x20
  Gui, ShowTip: +LastFound +AlwaysOnTop +ToolWindow -Caption +E0x08000020
  Gui, ShowTip: Color, FFFFF0
  WinSet, TransColor, FFFFF0 150
  Gui, ShowTip: Margin, 10, 5
  Gui, ShowTip: Font, Q3 s20 bold
  Gui, ShowTip: Add, Text,, %s%
  Gui, ShowTip: Show, NA %pos%, ShowTip
  SetTimer, ShowTip_ChangeColor, 1000
  ShowTip_ChangeColor:
  Gui, ShowTip: +AlwaysOnTop
  r:=StrSplit(SubStr(bak,1,InStr(bak,",")-1),"|")
  Gui, ShowTip: Font, % "Q3 c" r[idx:=Mod(Round(idx),r.length())+1]
  GuiControl, ShowTip: Font, Static1
  return
}


;============ Hotkey =============


F1::
Suspend, Permit
Goto, RecordScreen

F2::
Suspend, Permit
Goto, RecordWindow

RecordScreen:
RecordWindow:
if (Recording or Playing)
  return
Coord:=InStr(A_ThisLabel,"Win") ? "Window":"Screen"
LogArr:=[], oldid:="", Log(), Recording:=1, SetHotkey(1)
ShowTip("Recording")
return


F3::
Stop:
Suspend, Permit
if Recording
{
  if (LogArr.MaxIndex()>0)
  {
    s:="`nLoop, 1`n{`n`nSetTitleMatchMode, 2"
      . "`nCoordMode, Mouse, " Coord "`n"
    For k,v in LogArr
      s.="`n" v "`n"
    s.="`nSleep, 1000`n`n}`n"
    s:=RegExReplace(s,"\R","`n")
    FileDelete, %LogFile%
    FileAppend, %s%, %LogFile%
    s:=""
  }
  SetHotkey(0), Recording:=0, LogArr:=""
}
else if Playing
{
  WinGet, list, List, %Play_Title%
  Loop, % list
    if WinExist("ahk_id " list%A_Index%)!=A_ScriptHwnd
    {
      WinGet, pid, PID
      WinClose,,, 3
      IfWinExist
        Process, Close, %pid%
    }
  SetTimer, CheckPlay, Off
  Playing:=0
}
ShowTip()
Suspend, Off
Pause, Off
GuiControl,, Pause, % "[F6] Pause "
isPaused:=0
return


F4::
Play:
Suspend, Permit
if (Recording or Playing)
  Gosub, Stop
ahk:=A_IsCompiled ? A_ScriptDir "\AutoHotkey.exe" : A_AhkPath
IfNotExist, %ahk%
{
  MsgBox, 4096, Error, Can't Find %ahk% !
  Exit
}
Run, %ahk% /r "%LogFile%"
SetTimer, CheckPlay, 500
Gosub, CheckPlay
return

CheckPlay:
Check_OK:=0
WinGet, list, List, %Play_Title%
Loop, % list
  if (list%A_Index%!=A_ScriptHwnd)
    Check_OK:=1
if Check_OK
  Playing:=1, ShowTip("Playing")
else if Playing
{
  SetTimer, CheckPlay, Off
  Playing:=0, ShowTip()
}
return


F5::
Edit:
Suspend, Permit
Gosub, Stop
Run, notepad.exe "%LogFile%"
return


F6::
Pause:
Suspend, Permit
if Recording
{
  Suspend
  Pause, % A_IsSuspended ? "On":"Off", 1
  isPaused:=A_IsSuspended, Log()
}
else if Playing
{
  isPaused:=!isPaused
  WinGet, list, List, %Play_Title%
  Loop, %list%
    if WinExist("ahk_id " list%A_Index%)!=A_ScriptHwnd
      PostMessage, 0x111, 65306
}
else return
if isPaused
  GuiControl,, Pause, [F6]<Pause>
else
  GuiControl,, Pause, % "[F6] Pause "
return


;============ Functions =============


SetHotkey(f:=0) {
  ; These keys are already used as hotkeys
  global UsedKeys
  f:=f ? "On":"Off"
  Loop, 254
  {
    k:=GetKeyName(vk:=Format("vk{:X}", A_Index))
    if k not in ,Control,Alt,Shift,%UsedKeys%
      Hotkey, ~*%vk%, LogKey, %f% UseErrorLevel
  }
  For i,k in StrSplit("NumpadEnter|Home|End|PgUp"
    . "|PgDn|Left|Right|Up|Down|Delete|Insert", "|")
  {
    sc:=Format("sc{:03X}", GetKeySC(k))
    if k not in ,Control,Alt,Shift,%UsedKeys%
      Hotkey, ~*%sc%, LogKey, %f% UseErrorLevel
  }
  SetTimer, LogWindow, %f%
  if (f="On")
    Gosub, LogWindow
}

LogKey:
LogKey()
return

LogWindow:
LogWindow()
return

LogKey() {
  Critical
  k:=GetKeyName(vksc:=SubStr(A_ThisHotkey,3))
  k:=StrReplace(k,"Control","Ctrl"), r:=SubStr(k,2)
  if r in Alt,Ctrl,Shift,Win
    LogKey_Control(k)
  else if k in LButton,RButton,MButton
    LogKey_Mouse(k)
  else
  {
    if (k="NumpadLeft" or k="NumpadRight") and !GetKeyState(k,"P")
      return
    k:=StrLen(k)>1 ? "{" k "}" : k~="\w" ? k : "{" vksc "}"
    Log(k,1)
  }
}

LogKey_Control(key) {
  global LogArr, Coord
  k:=InStr(key,"Win") ? key : SubStr(key,2)
  if (k="Ctrl")
  {
    CoordMode, Mouse, %Coord%
    MouseGetPos, X, Y
  }
  Log("{" k " Down}",1)
  Critical, Off
  KeyWait, %key%
  Critical
  Log("{" k " Up}",1)
  if (k="Ctrl")
  {
    i:=LogArr.MaxIndex(), r:=LogArr[i]
    if InStr(r,"{Blind}{Ctrl Down}{Ctrl Up}")
      LogArr[i]:="MouseMove, " X ", " Y
  }
}

LogKey_Mouse(key) {
  global gui_id, LogArr, Coord
  k:=SubStr(key,1,1)
  CoordMode, Mouse, %Coord%
  MouseGetPos, X, Y, id
  if (id=gui_id)
    return
  Log("MouseClick, " k ", " X ", " Y ",,, D")
  CoordMode, Mouse, Screen
  MouseGetPos, X1, Y1
  t1:=A_TickCount
  Critical, Off
  KeyWait, %key%
  Critical
  t2:=A_TickCount
  if (t2-t1<=200)
    X2:=X1, Y2:=Y1
  else
    MouseGetPos, X2, Y2
  i:=LogArr.MaxIndex(), r:=LogArr[i]
  if InStr(r, ",,, D") and Abs(X2-X1)+Abs(Y2-Y1)<5
    LogArr[i]:=SubStr(r,1,-5), Log()
  else
    Log("MouseClick, " k ", " (X+X2-X1) ", " (Y+Y2-Y1) ",,, U")
}

LogWindow() {
  global oldid, LogArr
  static oldtitle
  id:=WinExist("A")
  WinGetTitle, title
  WinGetClass, class
  if (title="" and class="")
    return
  if (id=oldid and title=oldtitle)
    return
  oldid:=id, oldtitle:=title
  title:=SubStr(title,1,50)
  if (!A_IsUnicode)
  {
    GuiControl,, MyText, %title%
    GuiControlGet, s,, MyText
    if (s!=title)
      title:=SubStr(title,1,-1)
  }
  title.=class ? " ahk_class " class : ""
  title:=RegExReplace(Trim(title), "[``%;]", "``$0")
  s:="tt = " title "`nWinWait, %tt%"
    . "`nIfWinNotActive, %tt%,, WinActivate, %tt%"
  i:=LogArr.MaxIndex(), r:=LogArr[i]
  if InStr(r,"tt = ")=1
    LogArr[i]:=s, Log()
  else
    Log(s)
}

Log(str:="", Keyboard:=0) {
  global LogArr
  static LastTime
  t:=A_TickCount, Delay:=(LastTime ? t-LastTime:0), LastTime:=t
  IfEqual, str,, return
  i:=LogArr.MaxIndex(), r:=LogArr[i]
  if (Keyboard and InStr(r,"Send,") and Delay<1000)
  {
    LogArr[i]:=r . str
    return
  }
  if (Delay>200)
    LogArr.Push("Sleep, " (Delay//2))
  LogArr.Push(Keyboard ? "Send, {Blind}" str : str)
}

;============ The End ============

;
Last edited by feiyue on 13 Mar 2020, 21:21, edited 187 times in total.
snowflake2

Re: Macro Record ( Mouse and Keyboard )

10 Jul 2017, 15:02

hi

the save F2 button isn't working for me :(
feiyue
Posts: 381
Joined: 08 Aug 2014, 04:08

Re: Macro Record ( Mouse and Keyboard )

11 Jul 2017, 00:42

First, press F1 to record the mouse and keyboard, then press F2 to stop recording,
then press F3 test playback (this step can be optionally executed),
and finally press F4 to see the code and copy it into your own script.

Press F2 to stop there is still a hint, the left upper corner of the video yellow tips will disappear, you look carefully.
User avatar
gregster
Posts: 9224
Joined: 30 Sep 2013, 06:48

Re: Macro Record ( Mouse and Keyboard )

11 Jul 2017, 06:10

The A_AhkPath for the log file might be an issue. It's generally probably not a good idea to save the log file of a specific script there instead of the script directory because the script might not be allowed to write to that directory (at least, if you installed AHK to the programs directory and don't run the script as admin)... and F2 will fail.
feiyue
Posts: 381
Joined: 08 Aug 2014, 04:08

Re: Macro Record ( Mouse and Keyboard )

11 Jul 2017, 06:35

gregster wrote: (at least, if you installed AHK to the programs directory and don't run the script as admin)... and F2 will fail.
Oh, I don't know about this. Thank you for your reminder. :thumbup:
I have updated to put the Log file in the temporary folder.
Last edited by feiyue on 14 Jul 2017, 18:00, edited 1 time in total.
User avatar
SpeedMaster
Posts: 494
Joined: 12 Nov 2016, 16:09

Re: Macro Record ( Mouse and Keyboard )

12 Jul 2017, 06:26

Same as above (v2.1) with some additional features:

Macro Recorder v2.1+ :
  • Added button for options (F9)
  • Added Possibility to choose what will be recorded. (keyboard, mouse or window)
  • Added variable Playspeed:= in the macro to adjust the speed. (for ex. 2.5x 3x 10x faster or 0.5x 0.2x 0.9x slower)
  • Added variable EditorPath:= to choose the default editor
  • Added button to hide/show panel buttons (F10)
  • Added button to import macro
  • Added button to export macro
  • Added button to exit the script
  • Basic text indentation to incrase redability of the macro
  • Renamed Log file ~Record.txt to ~Record.ahk

Code: Select all

;-----------------------------------
;  Macro Recorder v2.1+  By FeiYue  (modified by Speedmaster)
;
;  Description: This script records the mouse
;  and keyboard actions and then plays back.
;
;  F1  -->  Record(Screen) (CoordMode, Mouse, Screen)
;  F2  -->  Record(Window) (CoordMode, Mouse, Window)
;  F3  -->  Stop   Record/Play
;  F4  -->  Play   LogFile
;  F5  -->  Edit   LogFile
;  F6  -->  Pause  Record/Play
;  F9  -->  More Options
;  F10  --> Hide/Show Panel Buttons
;
;  Note:
;  1. press the Ctrl button individually
;     to record the movement of the mouse.
;  2. Shake the mouse on the Pause button,
;     you can pause recording or playback.
;-----------------------------------

#SingleInstance force
#NoEnv
SetBatchLines, -1
Thread, NoTimers
CoordMode, ToolTip
SetTitleMatchMode, 2
DetectHiddenWindows, On

;--------------------------
logkeys:=""
playspeed:=2                           ; Set default playing speed here
EditorPath:="Notepad.exe"              ; set default editor path here
;~ EditorPath:=StrReplace(a_ahkpath, "autohotkey.exe") . "SciTE\SciTE.exe"     ; actvate if you have installed SciTE
LogFile:=A_Temp . "\~Record.ahk"
UsedKeys:="F1,F2,F3,F4,F5,F6,F9"
Play_Title:=RegExReplace(LogFile,".*\\") " ahk_class AutoHotkey"
global tlogmouse,tlogkey, playspeed
;--------------------------
Gui 1: +AlwaysOnTop -Caption +ToolWindow +E0x08000000 +Hwndgui_id
Gui 1: Margin, 0, 0
Gui 1: Font, s11
s:="[F1]Rec (Scr),[F2]Rec (Win),"
  . "[F3]Stop,[F4]Play,[F5]Edit,[F6]Pause,[F9]Options "
For i,v in StrSplit(s, ",")
{
  j:=i=1 ? "":"x+0", j.=InStr(v,"Pause") ? " vPause":""
  Gui, Add, Button, %j% gRun, %v%
}
Gui 1: Add, Button, x+0 w0 Hidden vMyText
Gui 1: Show, NA y0, Macro Recorder

gui 2: add, groupbox, r3,Record
Gui 2: Add, Checkbox, y25 xp+10 Checked1 ghcheck vTLogkey, Log keys
Gui 2: Add, Checkbox, Checked1 ghcheck vTLogmouse, Log mouse
Gui 2: Add, Checkbox, Checked1 ghcheck vTLogWindow, Log window


Gui 2:add, button, vTbuttons ghidebuttons y+20 w130, Hide Panel Buttons F10
Gui 2:add, button, gopen wp, Import Macro
Gui 2:add, button, gFileSaveAs wp, Export Macro
Gui 2:add, button, gexit wp, Exit Macro Recorder
gui 2: submit

if !InStr(FileExist("Macros"), "D")
   FileCreateDir, Macros

OnMessage(0x200,"WM_MOUSEMOVE")
;--------------------------
SetTimer, OnTop, 2000
OnTop:
Gui, +AlwaysOnTop
return

hcheck:
gui 2: submit, nohide
return

F10::
hidebuttons:
hidebuttons:=!hidebuttons
if hidebuttons {
	guicontrol,, tbuttons, Show Panel Buttons F10
	Gui 1:Hide
}
else {
	guicontrol,, tbuttons, Hide Panel Buttons F10
	Gui 1:show
}
return


Run:
aguictrl:=A_GuiControl
instr(aguictrl, "scr")&&aguictrl:="[F1]Record(Screen)"
instr(aguictrl, "win")&&aguictrl:="[F2]Record(Window)"
if IsLabel(k:=RegExReplace(RegExReplace(aguictrl,".*]"),"\W")) {
  Goto, %k%
}
return




WM_MOUSEMOVE() {
  static OK_Time
  ListLines, Off
  if (A_Gui=1) and (A_GuiControl="Pause")
    and (t:=A_TickCount)>OK_Time
  {
    OK_Time:=t+500
    Gosub, Pause
  }
}

ShowTip(s:="", pos:="y35", color:="Red|00FFFF") {
  static bak, idx
  if (bak=color "," pos "," s)
    return
  bak:=color "," pos "," s
  SetTimer, ShowTip_ChangeColor, Off
  Gui, ShowTip: Destroy
  if (s="")
    return
  ; WS_EX_NOACTIVATE:=0x08000000, WS_EX_TRANSPARENT:=0x20
  Gui, ShowTip: +LastFound +AlwaysOnTop +ToolWindow -Caption +E0x08000020
  Gui, ShowTip: Color, FFFFF0
  WinSet, TransColor, FFFFF0 150
  Gui, ShowTip: Margin, 10, 5
  Gui, ShowTip: Font, Q3 s20 bold
  Gui, ShowTip: Add, Text,, %s%
  Gui, ShowTip: Show, NA %pos%, ShowTip
  SetTimer, ShowTip_ChangeColor, 1000
  ShowTip_ChangeColor:
  Gui, ShowTip: +AlwaysOnTop
  r:=StrSplit(SubStr(bak,1,InStr(bak,",")-1),"|")
  Gui, ShowTip: Font, % "Q3 c" r[idx:=Mod(Round(idx),r.length())+1]
  GuiControl, ShowTip: Font, Static1
  return
}


;============ Hotkey =============


F1::
Suspend, Permit
Goto, RecordScreen

F2::
Suspend, Permit
Goto, RecordWindow

RecordScreen:
RecordWindow:
if (Recording or Playing)
  return
Coord:=InStr(A_ThisLabel,"Win") ? "Window":"Screen"
LogArr:=[], oldid:="", Log(), Recording:=1, SetHotkey(1)
ShowTip("Recording")
return

;~ F7::
F3::
Stop:
Suspend, Permit
if Recording
{
  if (LogArr.MaxIndex()>0)
  {
    s:="`nPlayspeed:=" playspeed " `n`nLoop, 1`n{`n`nSetTitleMatchMode, 2"
      . "`nCoordMode, Mouse, " Coord "`n"
    For k,v in LogArr
      s.="`n" v "`n"
    ;~ s.="`nSleep, 1000`n`n}`n"
    s.="`n  Sleep, 1000  //PlaySpeed `n`n}`n"
    s:=RegExReplace(s,"\R","`n")
    FileDelete, %LogFile%
    FileAppend, %s%, %LogFile%
    s:=""
  }
  SetHotkey(0), Recording:=0, LogArr:=""
}
else if Playing
{
  WinGet, list, List, %Play_Title%
  Loop, % list
    if WinExist("ahk_id " list%A_Index%)!=A_ScriptHwnd
    {
      WinGet, pid, PID
      WinClose,,, 3
      IfWinExist
        Process, Close, %pid%
    }
  SetTimer, CheckPlay, Off
  Playing:=0
}
ShowTip()
Suspend, Off
Pause, Off
GuiControl,, Pause, % "[F6] Pause "
isPaused:=0
return


F4::
Play:
Suspend, Permit
if (Recording or Playing)
  Gosub, Stop
ahk:=A_IsCompiled ? A_ScriptDir "\AutoHotkey.exe" : A_AhkPath
IfNotExist, %ahk%
{
  MsgBox, 4096, Error, Can't Find %ahk% !
  Exit
}
Run, %ahk% /r "%LogFile%"
SetTimer, CheckPlay, 500
Gosub, CheckPlay
return

CheckPlay:
Check_OK:=0
WinGet, list, List, %Play_Title%
Loop, % list
  if (list%A_Index%!=A_ScriptHwnd)
    Check_OK:=1
if Check_OK
  Playing:=1, ShowTip("Playing")
else if Playing
{
  SetTimer, CheckPlay, Off
  Playing:=0, ShowTip()
}
return


;~ F8::
F5::
Edit:
Suspend, Permit
Gosub, Stop
Run, %EditorPath% "%LogFile%"
return


F6::
Pause:
Suspend, Permit
if Recording
{
  Suspend
  Pause, % A_IsSuspended ? "On":"Off", 1
  isPaused:=A_IsSuspended, Log()
}
else if Playing
{
  isPaused:=!isPaused
  WinGet, list, List, %Play_Title%
  Loop, %list%
    if WinExist("ahk_id " list%A_Index%)!=A_ScriptHwnd
      PostMessage, 0x111, 65306
}
else 
return

if isPaused
  GuiControl,, Pause, [F6]<Pause>
else
  GuiControl,, Pause, % "[F6] Pause "
return


Open:
OutputVar:=""
FileSelectFile, OutputVar,, macros, Import File, AHK Macro File (*.ahk; *.txt)
if (OutputVar)
FileCopy, % OutputVar, % LogFile , 1
return

;-------------------------
FileSaveAs:
Gui +OwnDialogs  ; Force the user to dismiss the FileSelectFile dialog before returning to the main window.
FileSelectFile, SelectedFileName, S16, Macros, Save File, AHK File (*.ahk)
if SelectedFileName =  ; No file selected.
    return
CurrentFileName = %SelectedFileName%

IfExist %CurrentFileName%
{
    FileDelete %CurrentFileName%
    if ErrorLevel
    {
        MsgBox The attempt to overwrite "%CurrentFileName%" failed.
        return
    }
}

SplitPath, CurrentFileName,,, OutExtension

if (OutExtension)
  FileCopy, % LogFile, % CurrentFileName , 1
else
  FileCopy, % LogFile, % CurrentFileName ".ahk" , 1
return

F9::
Options:
Gui 2: +AlwaysOntop
Gui 2: Show, y100, Macro Recorder
gui 2: submit, nohide
return

;~ F12::
exit:
SplashTextOn,100,70,Macro recorder, `nGoodbye
sleep, 1000
exitapp
return


;============ Functions =============


SetHotkey(f:=0) {
  ; These keys are already used as hotkeys
  global UsedKeys
  f:=f ? "On":"Off"
  Loop, 254
  {
    k:=GetKeyName(vk:=Format("vk{:X}", A_Index))
    if k not in ,Control,Alt,Shift,%UsedKeys%
      Hotkey, ~*%vk%, LogKey, %f% UseErrorLevel
  }
  For i,k in StrSplit("NumpadEnter|Home|End|PgUp"
    . "|PgDn|Left|Right|Up|Down|Delete|Insert", "|")
  {
    sc:=Format("sc{:03X}", GetKeySC(k))
    if k not in ,Control,Alt,Shift,%UsedKeys%
      Hotkey, ~*%sc%, LogKey, %f% UseErrorLevel
  }
  SetTimer, LogWindow, %f%
  if (f="On")
    Gosub, LogWindow
}

LogKey:
LogKey()
return

LogWindow:
(tLogWindow)&&LogWindow()
return

LogKey() {
  Critical
  k:=GetKeyName(vksc:=SubStr(A_ThisHotkey,3))
  k:=StrReplace(k,"Control","Ctrl"), r:=SubStr(k,2)
  if r in Alt,Ctrl,Shift,Win
    (tlogkey)&&LogKey_Control(k)
  else if k in LButton,RButton,MButton
    (TlogMouse)&&LogKey_Mouse(k)
  else
  {
    if (!tlogkey)
      return
    if (k="NumpadLeft" or k="NumpadRight") and !GetKeyState(k,"P")
      return
    k:=StrLen(k)>1 ? "{" k "}" : k~="\w" ? k : "{" vksc "}"
    Log(k,1)
  }
}

LogKey_Control(key) {
  global LogArr, Coord
  k:=InStr(key,"Win") ? key : SubStr(key,2)
  if (k="Ctrl")
  {
    CoordMode, Mouse, %Coord%
    MouseGetPos, X, Y
  }
  Log("{" k " Down}",1)
  Critical, Off
  KeyWait, %key%
  Critical
  Log("{" k " Up}",1)
  if (k="Ctrl")
  {
    i:=LogArr.MaxIndex(), r:=LogArr[i]
    if InStr(r,"{Blind}{Ctrl Down}{Ctrl Up}")
      LogArr[i]:="MouseMove, " X ", " Y
  }
}

LogKey_Mouse(key) {
  global gui_id, LogArr, Coord
  k:=SubStr(key,1,1)
  CoordMode, Mouse, %Coord%
  MouseGetPos, X, Y, id
  if (id=gui_id)
    return
  Log("MouseClick, " k ", " X ", " Y ",,, D")
  CoordMode, Mouse, Screen
  MouseGetPos, X1, Y1
  t1:=A_TickCount
  Critical, Off
  KeyWait, %key%
  Critical
  t2:=A_TickCount
  if (t2-t1<=200)
    X2:=X1, Y2:=Y1
  else
    MouseGetPos, X2, Y2
  i:=LogArr.MaxIndex(), r:=LogArr[i]
  if InStr(r, ",,, D") and Abs(X2-X1)+Abs(Y2-Y1)<5
    LogArr[i]:=SubStr(r,1,-5), Log()
  else
    Log("MouseClick, " k ", " (X+X2-X1) ", " (Y+Y2-Y1) ",,, U")
}

LogWindow() {
  global oldid, LogArr
  static oldtitle
  id:=WinExist("A")
  WinGetTitle, title
  WinGetClass, class
  if (title="" and class="")
    return
  if (id=oldid and title=oldtitle)
    return
  oldid:=id, oldtitle:=title
  title:=SubStr(title,1,50)
  if (!A_IsUnicode)
  {
    GuiControl,, MyText, %title%
    GuiControlGet, s,, MyText
    if (s!=title)
      title:=SubStr(title,1,-1)
  }
  title.=class ? " ahk_class " class : ""
  title:=RegExReplace(Trim(title), "[``%;]", "``$0")
  ;~ s:="tt = " title "`nWinWait, %tt%"
    ;~ . "`nIfWinNotActive, %tt%,, WinActivate, %tt%"  
  s:="      tt = " title "`n      WinWait, %tt%"
    . "`n      IfWinNotActive, %tt%,, WinActivate, %tt%"    
  i:=LogArr.MaxIndex(), r:=LogArr[i]
  if InStr(r,"tt = ")=1
    LogArr[i]:=s, Log()
  else
    Log(s)
}

Log(str:="", Keyboard:=0) {
  global LogArr
  static LastTime
  t:=A_TickCount, Delay:=(LastTime ? t-LastTime:0), LastTime:=t
  IfEqual, str,, return
  i:=LogArr.MaxIndex(), r:=LogArr[i]
  if (Keyboard and InStr(r,"Send,") and Delay<1000)
  {
    LogArr[i]:=r . str
    return
  }
  if (Delay>200)
    ;~ LogArr.Push("Sleep, " (Delay//2))
    LogArr.Push("  Sleep, `% " (Delay) " //playspeed")
  LogArr.Push(Keyboard ? "Send, {Blind}" str : str)
}

;============ The End ============

Cheers,
Last edited by SpeedMaster on 19 Mar 2023, 12:34, edited 9 times in total.
feiyue
Posts: 381
Joined: 08 Aug 2014, 04:08

Re: Macro Record ( Mouse and Keyboard ) v1.5

12 Jul 2017, 19:46

@SpeedMaster, Thank you very much for the improvements you've made. :thumbup: :clap:
Referring to your suggestion, I updated my code to the v1.5 version, creating a simple GUI interface.
Because users can operate through the GUI button, the default did not set a lot of hot keys,
users can use their own settings, recording, stop, playback hotkey.
Last edited by feiyue on 14 Jul 2017, 18:01, edited 1 time in total.
sancarn
Posts: 224
Joined: 01 Mar 2016, 14:52

Re: Macro Record of Mouse and Keyboard v1.5

13 Jul 2017, 08:59

I haven't got time for improving the code at the moment, however you might want to add some functionality to record clicks using controlclick, if possible. This is much more stable as you may know than the normal click events as windows don't need to be in the correct position.
User avatar
Relayer
Posts: 160
Joined: 30 Sep 2013, 13:09
Location: Delaware, USA

Re: Macro Record of Mouse and Keyboard v1.5

13 Jul 2017, 15:54

Hi,

I needed to comment out the line 282

Code: Select all

. (class ? " ahk_class " . class : "")
Appending the ahk_class name to the window title did not work for me. In my scripts I usually use one or the other but not both.

Relayer
feiyue
Posts: 381
Joined: 08 Aug 2014, 04:08

Re: Macro Record of Mouse and Keyboard v1.5

14 Jul 2017, 05:14

Relayer wrote: I needed to comment out the line 282

Code: Select all

. (class ? " ahk_class " . class : "")
Appending the ahk_class name to the window title did not work for me. In my scripts I usually use one or the other but not both.
@Relayer, Thank you for your feedback. :P
Some windows (such as Notepad) just appear the title is the first,
and a little while later becomes the second title, but the window ID has not changed,
so the result of the capture window is the first one that caused the error.
Now I've updated the script to fix the problem.
Last edited by feiyue on 14 Jul 2017, 18:07, edited 2 times in total.
feiyue
Posts: 381
Joined: 08 Aug 2014, 04:08

Re: Macro Record of Mouse and Keyboard v1.5

14 Jul 2017, 17:52

sancarn wrote: however you might want to add some functionality to record clicks using controlclick, if possible.
@sancarn, Your suggestion is very good ! :thumbup:
In the beginning, I wrote this script to help beginners generate code automatically,
So I didn't think about letting it record mouse action as ControlClick code.
Now I upgrade the code to v2.0 and add the function to record the mouse action as a ControlClick code. :beer:
sancarn
Posts: 224
Joined: 01 Mar 2016, 14:52

Re: Macro Record of Mouse and Keyboard v1.5

14 Jul 2017, 19:00

feiyue wrote:
sancarn wrote: however you might want to add some functionality to record clicks using controlclick, if possible.
@sancarn, Your suggestion is very good ! :thumbup:
In the beginning, I wrote this script to help beginners generate code automatically,
So I didn't think about letting it record mouse action as ControlClick code.
Now I upgrade the code to v2.0 and add the function to record the mouse action as a ControlClick code. :beer:
Very cool +1
User avatar
SpeedMaster
Posts: 494
Joined: 12 Nov 2016, 16:09

Re: Macro Record of Mouse and Keyboard v2.0

15 Jul 2017, 03:20

Great :thumbup:
Last edited by SpeedMaster on 09 Nov 2021, 05:55, edited 2 times in total.
sancarn
Posts: 224
Joined: 01 Mar 2016, 14:52

Re: Macro Record of Mouse and Keyboard v2.0

15 Jul 2017, 04:47

It depends what you really want this to be, but if you want it to be a general purpose macro recorder it may actually be a good idea to also use acc.ahk... This would be even better than control click. Again, it's not really good for beginners though...

Code: Select all

MouseGetPos,x,y
oCtrl:=Acc_ObjectFromPoint(,x,y)
pathToControl:=Acc_GetPath(oCtrl)

x=
(
accCtrl:=Acc_Get("Object","%pathToControl%","%winTitle%")
accCtrl.doDefaultAction()
)
Log(x)


Acc_GetPath(Acc, byref hwnd:="") {
       ;By Jeeswg / Sean
	hwnd := Acc_WindowFromObject(Acc)
	WinObj := Acc_ObjectFromWindow(hwnd)
	WinObjPos := Acc_Location(WinObj).pos
	while (Acc_WindowFromObject(Parent:=Acc_Parent(Acc)) = hwnd) {
		t2 := GetEnumIndex(Acc) "." t2
		if (Acc_Location(Parent).pos = WinObjPos)
			return {AccObj:Parent, Path:SubStr(t2,1,-1)}
		Acc := Parent
	}
	while (Acc_WindowFromObject(Parent:=Acc_Parent(WinObj)) = hwnd)
		t1.="P.", WinObj:=Parent
	return {AccObj:Acc, Path:t1 SubStr(t2,1,-1)}
}
CAH9t
Posts: 29
Joined: 15 Jul 2017, 11:12
Location: Land

Re: Macro Record of Mouse and Keyboard v2.0

15 Jul 2017, 11:57

Good whatever you're having right now! As that is my first post. :)

Actually I'm Keeping your design on radar for quite some time and still waiting that someone says, hey I got this, but nobody does. That itch made me register.

So to the brass tacks.

As it is now it doesn't act on other key layout. For example "Send, {Blind}[someAnotherLayout]{Ctrl Down}{Space}{Ctrl Up}[someAnotherLayout]" Should've been blabla and that actually is on screen . Version 1.0 had no such problem as I remember (can't actually prove as I arrogantly rewrote it) . The problem is the default language if that's Eng than script records only english letters without changing to another layout.

Another one, what I'd like to know. Can your recorder operate in scs or vks and make a comment about what has been written? Would happen quite useful for multilingual guys like yours sincerely. Example: "Send, {Sc030}{Sc026}{Sc01E} ; bla"

Note: I know and understand that ahk is pretty fishy when it comes down to language changes during keystrokes recording and if that's one hell of a work, than forget it :) .
Last edited by CAH9t on 11 Aug 2017, 20:35, edited 1 time in total.
feiyue
Posts: 381
Joined: 08 Aug 2014, 04:08

Re: Macro Record of Mouse and Keyboard v2.0

16 Jul 2017, 01:17

Hello, CAH9t.
I think even in non English speaking countries, the standard keyboard output characters are also English characters,
The non English country characters are then generated by the input method installed in the computer.
As the basic function of keyboard recording, just record the original English characters of the keyboard,
If you want to send non English characters directly in the script (those generated by the input method),
you can manually modify the record file, And using the Unicode version of AHK,
send the Unicode characters directly using the Send command,
Or use the clipboard to paste characters through Send ^v.

As for the key record as a SC or VK form, I don't know what the advantages are,
but I think you can replace the following first line with the following second line:
k:=k="``" ? "``" k : StrLen(k)>1 or k=";" ? "{" k "}" : k
k:=Format("{{}vk{1:X}sc{2:X}{}}", GetKeyVK(k), GetKeySC(k))
vasili111
Posts: 747
Joined: 21 Jan 2014, 02:04
Location: Georgia

Re: Macro Record of Mouse and Keyboard v2.0

16 Jul 2017, 12:11

I think this thread should be moved to Editors sections.
DRAKON-AutoHotkey: Visual programming for AutoHotkey.
sancarn
Posts: 224
Joined: 01 Mar 2016, 14:52

Re: Macro Record of Mouse and Keyboard v2.0

16 Jul 2017, 16:31

vasili111 wrote:I think this thread should be moved to Editors sections.
How is it an editor?
vasili111
Posts: 747
Joined: 21 Jan 2014, 02:04
Location: Georgia

Re: Macro Record of Mouse and Keyboard v2.0

17 Jul 2017, 00:29

sancarn wrote:
vasili111 wrote:I think this thread should be moved to Editors sections.
How is it an editor?
The title is currently misleading ( https://autohotkey.com/boards/viewtopic.php?f=2&t=33714 ) but it actually includes all AutoHotkey tools.
DRAKON-AutoHotkey: Visual programming for AutoHotkey.
CAH9t
Posts: 29
Joined: 15 Jul 2017, 11:12
Location: Land

Re: Macro Record of Mouse and Keyboard v2.0

17 Jul 2017, 00:37

Thnx, feiyue. Great job. Works like magic indeed.

Is it possible to Exclude from the equation all non-language dependable keys ( mods LRwin shift ctrl alt (now they're fine that is not scancoded as enter) ,capsScrNumlck,prntscreen,tab,esc,enter, space backspace insDel EndHome pgUpDn , rightLeftUpDown ,appkey, f1-f12, numpadKeys) ? All-keyboard sc-keys are redundant and they've been working nicely as they were in your recorder from the beginning. More so As for the numpad keys they aren't working properly via sc at all, acting like numlock is off (you're getting Num insDelEndHomePgUpDn instead of figures).

Another point.
It would be like X-mas during summer if there were an option to assemble user's-own commentary section (just a place where to place needed variables). Off the bat I can think of

1) For window title - opportunity to write down only ahc_class and note the title in commentary section. There is « tt:="*new 1 - Notepad++ ahk_class Notepad++" » My thought «tt:="ahk_class Notepad++ ; *new 1 - Notepad++ » . Field of application: video-audio-players such as foobar change wintitle with each track, Notepad++ changes the name of the window depending on saved\not saved, and I'm silent about documents may have different names and so on. ps. Of course one can change it manually each time.

2) For click - just a place where user can insert his own stuff . ( I would manually add some full screen coordinates and colour (I'm going American) color under the cursor )

3) For keys . I've already asked transcript of sc stuff «Send, {Blind}{sc26}{sc18}{sc2F}{sc12} ; sc = love » or at least «Send, {Blind}{Ctrl Down}{sc21}
{Ctrl Up} ; {Ctrl Down}f{Ctrl Up} » i.e sorta reminder of the sc in play, if it's easier might be the same string that was generated by default or something like that ( on the second thought it could be a problem but you should know better ) .

You've mentioned about usefulness of scs. They're language-insensitive for instance. I wasn't as a matter of fact gunning for writing down essays with macrorecorder - said it just to name a problem. What I really have in mind are the hotkeys. Lovable ctrl+f ctrl+c ctrl+v (and many others) wouldn't work in some apps if they are send from another language so sc'ing them insures 100% reliability.

Return to “Scripts and Functions (v1)”

Who is online

Users browsing this forum: No registered users and 107 guests