Here is an updated version, it uses the lib that Lexikos pointed out.
It supports hotkeys, labels, error checking in the command prompt, and colors.
Type "reload" to start a new session.
The only thing that I could not get to work was classes.
To use a hotkey make sure its not on one line and it is followed by a return. Example:
Code:
^a::
msgbox hi
return
Code:
#NoEnv ; Recommended for performance and compatibility with future AutoHotkey releases.
#Persistent
#SingleInstance, Force
; #NoTrayIcon
#ErrorStdOut
SetBatchLines, -1
ListLines, Off
SetWorkingDir %A_ScriptDir% ; Ensures a consistent starting directory.
Onexit, Exit
AhkDll := A_ScriptDir . "\AutoHotkey.dll" ; Path of AutoHotkey.dll
showErrors := 1 ; Change this to 0 to not show any errors in the command prompt.
errorColor := 4 ; Change the numbers for different colors
mainColor := 7
CMD := new CMD
hModule := DllCall("LoadLibrary", "Str", AhkDll)
DllCall(AhkDll "\ahktextdll","Str","","Str","","Str","/ErrorStdOut","Cdecl Uint")
CMD.CreateNew()
CMD.SetTitle("AHK Command-line interface")
CMD.SetWritingColor(2)
CMD.Write("AutoHotkey " . A_AhkVersion . "`n")
CMD.SetWritingColor(mainColor)
Loop
{
CMD.Write(">>> ")
line := CMD.Userinput()
tmpLine := line
while (checkFunction(tmpLine)) ; Check for function< if statements. and labels.
tmpLine := CMD.Userinput(), line .= "`n" . tmpLine
if (line != "Reload" && showErrors)
error := getErrors(line, CMD, mainColor, errorColor)
if (line = "Reload") ; Reload starts a new script.
DllCall(AhkDll "\ahkReload"), CMD.Clear(), CMD.SetWritingColor(2), CMD.Write("AutoHotkey " . A_AhkVersion . "`n"), CMD.SetWritingColor(7)
else if (labels)
DllCall(AhkDll "\addScript","Str", line,"Uchar",0,"Cdecl UInt") ; add function or label to script and not run.
Else if (!error)
DllCall(AhkDll "\ahkExec","Str", line,"Str","","Str","","Cdecl Uint") ; Run line
labels := 0, error := ""
}
ExitApp
return
Exit:
DllCall("FreeLibrary","UInt",hModule)
CMD.release()
Exitapp
return
checkFunction(Script) {
Global labels
static bracketCount, function, labelCount
Loop, Parse, Script, `n
{
currentLine := Trim(A_LoopField)
if (bracketCount) || (function) ; Keep track of brackets
{
if (InStr(currentLine, "{"))
bracketCount++
else if (InStr(currentLine, "}"))
bracketCount--
if (!bracketCount)
function := 0, count := 0
Continue
}
else if (labelCount)
{
if (currentLine = "return")
labelCount--
Continue
}
else if Regexmatch(currentLine, "class .*") ; Filters out any functions located within a class
{
if (InStr(currentLine, "{"))
bracketCount++
else
function := 1
Continue
}
else if (RegExMatch(currentLine, "^[\w\d]*?\(.*\)")) or (Regexmatch(currentLine, "i)^(?:if|loop).*")) ; If the current line is a function or an if statement.
{
if (InStr(currentLine, "{"))
bracketCount++
else
function := 1
Continue
}
else if (Substr(currentLine, 0) = ":") ; If the current line is a hotkey or label.
{
labelCount++
labels := 1
}
}
return (function || bracketCount || labelCount) ? 1 : 0
}
getErrors(text, CMD, mainColor, errorColor) {
Critical
FileAppend, % "#NoTrayIcon`nExitApp`n" . text, % A_Temp . "\tmpFile.ahk"
command = "%A_AhkPath%" /ErrorStdOut "%A_Temp%\tmpFile.ahk" 2> "%A_Temp%\SyntaxError.txt"
RunWait, %ComSpec% /c "%command%",, Hide
Filereadline, Errors, %A_Temp%\SyntaxError.txt, 1
FileDelete % A_Temp . "\SyntaxError.txt"
FileDelete % A_Temp . "\tmpFile.ahk"
CMD.SetWritingColor(errorColor)
RegExMatch(Errors, ".*?\((\d*)?\)\s: \=\=\> (.*)", Info)
if (Info1 && Info2) ; if an error was found add it too error list.
CMD.GetCusorPos(x, y), CMD.WriteToPos("Error: " info2, x, y), CMD.SetCusorPos(x, y + 1)
CMD.SetWritingColor(mainColor)
Critical, Off
return (info2)
}
class CMD
{
CreateNew(){
return DllCall("AllocConsole")
}
TakeExisting(pid=-1){
DllCall("AttachConsole","uint",pid)
return A_LastError
}
Userinput(){
Ptr := (A_PtrSize) ? "uptr" : "uint"
Suffix := (A_IsUnicode) ? "W" : "A"
stdout := DllCall("GetStdHandle", "uint", -11, Ptr)
stdin := DllCall("GetStdHandle", "uint", -10, Ptr)
if ((hConsoleIn=0) || (hConsoleOut=0))
return 0
VarSetCapacity(buffer, 1024)
if ((!DllCall("ReadConsole" . Suffix, Ptr, stdin, Ptr, &buffer, "uint", 1024, Ptr "*", numreaded, Ptr, 0, "uint")) || (numreaded=0))
return 0
Loop, % numreaded
msg .= Chr(NumGet(buffer, (A_Index-1) * ((A_IsUnicode) ? 2 : 1), (A_IsUnicode) ? "ushort" : "uchar"))
StringSplit, msg, msg,`r`n
return msg1
}
SetWritingColor(Color=15){
hConsoleOut := DllCall("GetStdHandle", "uint", -11, Ptr)
hConsoleIn := DllCall("GetStdHandle", "uint", -10, Ptr)
if ((hConsoleIn=0) || (hConsoleOut=0))
return 0
return DllCall("SetConsoleTextAttribute", "uint", hConsoleOut, "uchar", color)
}
Write(Write){
hConsoleOut := DllCall("GetStdHandle", "uint", -11, Ptr)
hConsoleIn := DllCall("GetStdHandle", "uint", -10, Ptr)
if ((hConsoleIn=0) || (hConsoleOut=0))
return 0
Suffix := (A_IsUnicode) ? "W" : "A"
return DllCall("WriteConsole" . Suffix, "uint", hConsoleOut, "str", Write, "uint", strlen(Write), "uint*", Written, "uint", 0)
}
Release(){
return DllCall("FreeConsole")
}
SetTitle(Title="Autohotkey Skript"){
Suffix := (A_IsUnicode) ? "W" : "A"
DllCall("SetConsoleTitle" . Suffix,"str",Title)
}
GetTitle(){
VarSetCapacity(Title,1024)
Suffix := (A_IsUnicode) ? "W" : "A"
DllCall("GetConsoleTitle","str",Title,"uint",1024)
return Title
}
ahkExec(){
return DllCall("GetConsoleWindow")
}
SetFullscreen(Fullscreen=true){
hConsoleOut := DllCall("GetStdHandle", "uint", -11, Ptr)
hConsoleIn := DllCall("GetStdHandle", "uint", -10, Ptr)
if ((hConsoleIn=0) || (hConsoleOut=0))
return 0
VarSetCapacity(CoordStruct,32,0)
Suffix := (A_IsUnicode) ? "W" : "A"
if (Fullscreen)
return DllCall("SetConsoleDisplayMode" . Suffix,"uint",hConsoleOut,"uint",1,"int",&CoordStruct)
else if (!Fullscreen)
return DllCall("SetConsoleDisplayMode" . Suffix,"uint",hConsoleOut,"uint",2,"int",&CoordStruct)
}
Clear(){
hConsoleOut := DllCall("GetStdHandle", "uint", -11, Ptr)
hConsoleIn := DllCall("GetStdHandle", "uint", -10, Ptr)
if ((hConsoleIn=0) || (hConsoleOut=0))
return 0
VarSetCapacity(CoordStruct,4,0)
Numput(3,&CoordStruct,0,"short")
Numput(3,&CoordStruct,2,"short")
VarSetCapacity(CharsWritten,1024)
Suffix := (A_IsUnicode) ? "W" : "A"
prt := (A_PtrSize) ? "Ptr" : "uint"
this.GetBufferSize(h,w)
if (!DllCall("FillConsoleOutputCharacter" . Suffix,"uint",hConsoleOut,"Char",A_Space,"uint",w*h,"uint",CoordStruct,"uint",&CharsWritten))
return 0
if (!DllCall("FillConsoleOutputAttribute","uint",hConsoleOut,"Short",15,"uint",w*h,"uint",CoordStruct,"uint",&CharsWritten))
return 0
return DllCall("SetConsoleCursorPosition","uint",hConsoleOut,"uint",CoordStruct)
}
GetBufferSize(ByRef Width, ByRef Height){
hConsoleOut := DllCall("GetStdHandle", "uint", -11, Ptr)
hConsoleIn := DllCall("GetStdHandle", "uint", -10, Ptr)
if ((hConsoleIn=0) || (hConsoleOut=0))
return 0
VarSetCapacity(CONSOLE_SCREEN_BUFFER_INFO,44,0)
dummy := DllCall("GetConsoleScreenBufferInfo","uint", hConsoleOut,"uint",&CONSOLE_SCREEN_BUFFER_INFO)
Width := NumGet(&CONSOLE_SCREEN_BUFFER_INFO,0,"short")
Height := NumGet(&CONSOLE_SCREEN_BUFFER_INFO,2,"short")
return dummy
}
GetCusorPos(ByRef X,ByRef Y){
hConsoleOut := DllCall("GetStdHandle", "uint", -11, Ptr)
hConsoleIn := DllCall("GetStdHandle", "uint", -10, Ptr)
if ((hConsoleIn=0) || (hConsoleOut=0))
return 0
VarSetCapacity(CONSOLE_SCREEN_BUFFER_INFO,44,0)
dummy := DllCall("GetConsoleScreenBufferInfo","uint", hConsoleOut,"uint",&CONSOLE_SCREEN_BUFFER_INFO)
X := NumGet(&CONSOLE_SCREEN_BUFFER_INFO,4,"short")
Y := NumGet(&CONSOLE_SCREEN_BUFFER_INFO,6,"short")
return dummy
}
GetShownBuffer(ByRef X_upper_lef,ByRef Y_upper_lef,ByRef X_lower_right,ByRef Y_lower_right){
hConsoleOut := DllCall("GetStdHandle", "uint", -11, Ptr)
hConsoleIn := DllCall("GetStdHandle", "uint", -10, Ptr)
if ((hConsoleIn=0) || (hConsoleOut=0))
return 0
VarSetCapacity(CONSOLE_SCREEN_BUFFER_INFO,44,0)
dummy := DllCall("GetConsoleScreenBufferInfo","uint", hConsoleOut,"uint",&CONSOLE_SCREEN_BUFFER_INFO)
X_upper_lef := NumGet(&CONSOLE_SCREEN_BUFFER_INFO,10,"short")
Y_upper_lef := NumGet(&CONSOLE_SCREEN_BUFFER_INFO,12,"short")
X_lower_right := NumGet(&CONSOLE_SCREEN_BUFFER_INFO,14,"short")
Y_lower_right := NumGet(&CONSOLE_SCREEN_BUFFER_INFO,16,"short")
return dummy
}
GetOriginalTitle(){
VarSetCapacity(Title,1024,0)
DllCall("GetConsoleOriginalTitle","uint",&Title,"uint",1024)
return title
}
SetCusorPos(X,Y){
hConsoleOut := DllCall("GetStdHandle", "Int", -11)
hConsoleIn := DllCall("GetStdHandle", "uint", -10, Ptr)
Ptr := A_PtrSize ? "Ptr" : "UInt"
COORD := (Y << 16) + X
Return DllCall("SetConsoleCursorPosition", Ptr, hConsoleOut, "uint", COORD)
}
WriteToPos(Text,X=0,Y=0){
d := this.GetCusorPos(X2,Y2)
if (!d)
return 0
d := this.SetCusorPos(X,Y)
if (!d)
return 0
d := this.Write(Text)
if (!d)
return 0
d := this.SetCusorPos(X2,Y2)
if (!d)
return 0
return 1
}
}