<> I’ve implemented a function to execute AutoHotKey from the Linux command line, so I’ll introduce it. This is an implementation that enables flexible coding with arguments from WSL Bash to autohotkey.

OutputDebug
There’s a method called OutputDebug that seems obvious, and of course I tried it, but it didn’t work.
Apparently, it doesn’t output unless it’s a dedicated editor or integrated development environment software. Pretty useless.
OutputDebug - Syntax & Usage | AutoHotkey
autohotkey print - Google Search
[Resolved] Print to Console - AutoHotkey Community
Using Files
So, I found a solution for now.
If you output the data you want to temporarily stdout to a file - let’s call it file x - using FileAppend, and cat file x in bash, you can essentially get stdout.
Below is a script that returns true if the current active window is atom.exe via autohotkey from bash, and false otherwise.

export AHKPRINT_STDOUT_FILE="/mnt/c/data/ahkprint.txt"
export AHKPRINT_STDOUT_IDENTIFIER="var"
ahkprint(){
: <<<'
e.g. ahkprint
'
# tmpdird
: check AHKPRINT_STDOUT_FILE file and path/dir exist then handling error
[[ ! -f "${AHKPRINT_STDOUT_FILE}" ]] && {
touch "${AHKPRINT_STDOUT_FILE}" || {
printf "${red}E: Couldn't make the file." ; return 1 ;
}
}
: make null the file
> "${AHKPRINT_STDOUT_FILE}"
cat << EOT > /mnt/c/_tmp/tmp.ahk
WinGet, ${AHKPRINT_STDOUT_IDENTIFIER}, ProcessName, A
FileAppend , %${AHKPRINT_STDOUT_IDENTIFIER}% , $( wslpathr "${AHKPRINT_STDOUT_FILE}" )
EOT
psl ahk $( wslpathr /mnt/c/_tmp/tmp.ahk )
cat "${AHKPRINT_STDOUT_FILE}"
}
Passing stdin (standard input) to autohotkey
As the next step, let’s pass stdin standard input from bash to autohotkey.
The following script is an improved version.

ahkprint(){
: <<<'
e.g. ahkprint
'
# tmpdird
: If a argment defined use it else if stdin defined use it else make error
[[ -z "${1}" ]] && stdin="$(</dev/stdin)"
[[ ! -z "${1}" ]] && {
value="${1}"
} || {
[[ ! -z "${stdin}" ]] && {
value="${stdin}"
} || {
printf "${red}No data to store to the value. at least you'd specify argment(s) or stdin." ; return 1 ;
}
}
: check AHKPRINT_STDOUT_FILE file and path/dir exist then handling error
[[ ! -f "${AHKPRINT_STDOUT_FILE}" ]] && {
touch "${AHKPRINT_STDOUT_FILE}" || {
printf "${red}E: Couldn't make the file." ; return 1 ;
}
}
: make null the file
> "${AHKPRINT_STDOUT_FILE}"
cat << EOT > /mnt/c/_tmp/tmp.ahk
WinGet, activeWinproc, ProcessName, A
WinActivate, ahk_exe ${value}
winActivateErrorLevel=%ErrorLevel%
WinWaitActive, ahk_exe ${value}
${AHKPRINT_STDOUT_IDENTIFIER} = % activeWinproc . " " . winActivateErrorLevel
FileAppend , %${AHKPRINT_STDOUT_IDENTIFIER}% , $( wslpathr "${AHKPRINT_STDOUT_FILE}" )
EOT
psl ahk $( wslpathr /mnt/c/_tmp/tmp.ahk )
: Won't work in pipe processing. Presumably this is running before ahk's file write processing finishes
# cat "${AHKPRINT_STDOUT_FILE}"
: Countermeasure for the above
: Verify whether file writing occurs for a few seconds. If file writing occurs, cat it and end the loop; if a few seconds pass, end the loop considering the variable and file are empty
tmpdate=$(date +"%s")
while [[ "$( echo $(( $( date +"%s" ) - ${tmpdate} )) )" -lt 3 ]] ;
do
[[ ! -z "$( cat "${AHKPRINT_STDOUT_FILE}" )" ]] && {
cat "${AHKPRINT_STDOUT_FILE}" ; break ;
}
sleep 0.1
done
# echo "hogehoge"
}
Increasing Versatility
Finally, as finishing touches, let’s make it easy to implement with arbitrary autohotkey scripts.
I’ve changed the code a bit so the usability differs from the above, but if you don’t like it, try tweaking the code yourself
ahkprint(){
: <<<'
e.g. ahkprint
'
# tmpdird
stdin="$(</dev/stdin)"
: check AHKPRINT_STDOUT_FILE file and path/dir exist then handling error
[[ ! -f "${AHKPRINT_STDOUT_FILE}" ]] && {
touch "${AHKPRINT_STDOUT_FILE}" || {
printf "${red}E: Couldn't make the file." ; return 1 ;
}
}
: make null the file
> "${AHKPRINT_STDOUT_FILE}"
cat << EOT > /mnt/c/_tmp/tmp.ahk
$( eval "cat << EOT
$( echo "${stdin}" )
EOT" )
FileAppend , %${AHKPRINT_STDOUT_IDENTIFIER}% , $( wslpathr "${AHKPRINT_STDOUT_FILE}" )
EOT
psl ahk $( wslpathr /mnt/c/_tmp/tmp.ahk )
: Won't work in pipe processing. Presumably this is running before ahk's file write processing finishes
# cat "${AHKPRINT_STDOUT_FILE}"
: Countermeasure for the above
: Verify whether file writing occurs for a few seconds. If file writing occurs, cat it and end the loop; if a few seconds pass, end the loop considering the variable and file are empty
tmpdate=$(date +"%s")
while [[ "$( echo $(( $( date +"%s" ) - ${tmpdate} )) )" -lt 3 ]] ;
do
[[ ! -z "$( cat "${AHKPRINT_STDOUT_FILE}" )" ]] && {
cat "${AHKPRINT_STDOUT_FILE}" ; break ;
}
sleep 0.1
done
}
To summarize briefly,
- The AHKPRINT_STDOUT_FILE constant specifies the path of the file that temporarily stores the stdout value used by this function
- The AHKPRINT_STDOUT_IDENTIFIER constant specifies the variable name in autohotkey to output as stdout. (Default:
var) - stdin, standard input becomes the autohotkey script code itself. In addition, bash arguments and variables can be embedded inside that code. (The following is also possible)
- As just mentioned, in terms of variables, you can use bash arguments and variables respectively.
- Data you want to stdout, standard output, is stored in the
varvariable (or the value of AHKPRINT_STDOUT_IDENTIFIER, or${AHKPRINT_STDOUT_IDENTIFIER}) in the autohotkey script.
[code generating autohotkey script] | ahkprint
or
ahkprint <<< “echo [autohotkey script]”
(When using variables instead of arguments)
value=typora.exe
ahkprint <<< "$(cat <<'EOT'
WinGet, activeWinproc, ProcessName, A
WinActivate, ahk_exe ${value}
winActivateErrorLevel=%ErrorLevel%
WinWaitActive, ahk_exe ${value}
var = % activeWinproc . " " . winActivateErrorLevel
EOT
)"
Now, based on the above code, you can implement the same thing with flexible code like the following.
ahkprint "typora.exe" <<< "$(cat <<'EOT'
WinGet, activeWinproc, ProcessName, A
WinActivate, ahk_exe ${1}
winActivateErrorLevel=%ErrorLevel%
WinWaitActive, ahk_exe ${1}
var = % activeWinproc . " " . winActivateErrorLevel
EOT
)"
Below are practical examples mass-produced with the same logic.
Get Current Active Window
getActiveWindowName(){
ahkprint ${@} <<< "WinGet, var, ProcessName, A"
}
Usage example
[[ ! "$( getActiveWindowName )" == atom.exe ]] && { : Process you want to do when active window is not atom.exe here ; }
Get Mouse Coordinates
getMousePos(){
: e.g. getMousePos
: e.g. getMousePos Relative
ahkprint ${1:-Screen} ${@:2} <<< "$( cat << 'EOT'
CoordMode, Mouse, ${1}
MouseGetPos, posX, posY
var = % posX . " " . posY
EOT
)"
}
Usage example
$ getMousePos Relative
998 510
$ getMousePos
991 923
$
Unmute if Muted
unmute(){
: e.g. unmute
ahkprint ${@} <<< "$( cat << 'EOT'
;Unmute if muted
SoundGet, MuteState, Master, Mute
if ErrorLevel
{
MsgBox, %ErrorLevel%
Return
}
prevMuteState = %MuteState%
if MuteState=On
{
MuteState=1
}
if MuteState=1
{
Send, {Volume_Mute}
}
SoundGet, currentMuteState, Master, Mute
var = % prevMuteState . " " . currentMuteState
EOT
)"
}
Usage example
$ unmute
Off Off
$ unmute
On Off
$
Get Volume
getVolume(){
: e.g. getVolume
ahkprint ${@} <<< "$( cat << 'EOT'
SoundGet, var
EOT
)"
}
Usage example
$ getVolume
6.999999
Custom Defined Functions and Aliases
$ psl which ahk
C:\Program Files\AutoHotkey\AutoHotkeyU64.exe
$ psl which ahk^C
$ type psl wslpathr
psl is aliased to `/mnt/c/WINDOWS/System32/WindowsPowerShell/v1.0/powershell.exe'
wslpathr is a function
wslpathr ()
{
wslpath -w $(realpath $1)
}
Summary
I’ve implemented up to the point of executing arbitrary programmable autohotkey scripts from bash and other programming languages’ external commands and receiving results.
I’d be happy if you could let me know in comments if there are any gaps or better methods.