- Published on
LinuxコマンドラインからAutoHotKeyを実行する関数を実装してみた
- Authors
- Name
- Shou Arisaka nyapp.buzz/shou
- short bio
- Z世代の情報技術者。Next.jsで自作SNSを個人開発中。
LinuxコマンドラインからAutoHotKeyを実行する関数を実装してみたので紹介します。 autohotkeyをWSL Bashから引数でフレキシブルなコーディングを可能にする実装です。
autohotkeyでは俗に言うシェルにおいてのstdout、標準出力がないため、例えばpythonやrubyのように、bashスクリプト上での値をautohotkeyに渡してautohotkeyで処理された値を標準出力として受け取りバイプして…といったことができません。
OutputDebug
OutputDebug
といういかにもなメソッドがあるのですが、こちらはもちろん試しているのですが、できませんでした。 どうやら、専用のエディタ、統合開発環境ソフトウェアでないと出力されないみたいです。意味ないね。OutputDebug - Syntax & Usage | AutoHotkey autohotkey print - Google Search OutputDebug - Google Search[Resolved] Print to Console - AutoHotkey Community
ファイルを使う
で、解決策をとりあえず見つけました。ファイル - ファイルxと呼称 - に一時的に標準出力したいデータをFileAppend
で出力して、bashでファイルxをcat
すれば、実質stdoutが取得できることになります。
以下はbash上からautohotkey経由で、現在のアクティブウィンドウがatom.exeであればtrueを返し、それ以外であればfalseを返すスクリプトです。
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}"
}
stdin(標準入力)をautohotkeyに渡す
では次のステップとして、autohotkeyにbashからstdin標準入力を渡してみます。以下スクリプトがその改良版です。
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 )
: パイプ処理の場合に動かない。 ahkのファイル書き込み処理が終わる前にこちらが動いてしまっているものだと思われる
# cat "${AHKPRINT_STDOUT_FILE}"
: 上記の対策
: 数秒間ファイル書き込みがされるかどうかを検証。ファイル書き込みがされればそれをcatしてループを終了し、数秒間が過ぎた場合は変数およびファイルが空であるとしてループを終了する
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"
}
汎用性を高める
最後に仕上げとして、任意のautohotkeyスクリプトで簡単に実装できるようにします。すこしコードを変えたので使い勝手が上記のそれと変わりますが、気に入らなければ自分でコードいじってみてください
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 )
: パイプ処理の場合に動かない。 ahkのファイル書き込み処理が終わる前にこちらが動いてしまっているものだと思われる
# cat "${AHKPRINT_STDOUT_FILE}"
: 上記の対策
: 数秒間ファイル書き込みがされるかどうかを検証。ファイル書き込みがされればそれをcatしてループを終了し、数秒間が過ぎた場合は変数およびファイルが空であるとしてループを終了する
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
}
軽くまとめると、
- AHKPRINT_STDOUT_FILE定数にはこの関数で使用するstdoutの値を一時的に置いておくファイルのパスを指定します
- AHKPRINT_STDOUT_IDENTIFIER定数にはstdoutとして標準出力するautohotkey上の変数名を指定します。(デフォルト:
var
) - stdin、標準入力がautohotkeyのスクリプトコードそれ自体になります。それに加え、そのコードの内部にはbashの引数、変数を埋め込むことができます。(以下の様なことも可能)
- 今言ったように変数的な意味合いでは、bash上の引数と変数をそれぞれ使うことができます。
- stdout、標準出力したいデータは、autohotkeyスクリプト上で
var
変数( またはAHKPRINT_STDOUT_IDENTIFIERの値、または${AHKPRINT_STDOUT_IDENTIFIER}
)に格納します。
e.g.
[autohotkeyスクリプトを生成するコード] | ahkprint
or ahkprint <<< "echo [autohotkeyスクリプト]"
(引数の代わりに変数を使う場合)
value=typora.exe
ahkprint <<< "$(cat <<'EOT'
WinGet, activeWinproc, ProcessName, A
WinActivate, ahk_exe ${value}
winActivateErrorLevel=%ErrorLevel%
WinWaitActive, ahk_exe ${value}
var = % activeWinproc . " " . winActivateErrorLevel
EOT
)"
さて、上記コードをもとにして、以下のようなフレキシブルなコードで上記と同様のことが実装できます。
ahkprint "typora.exe" <<< "$(cat <<'EOT'
WinGet, activeWinproc, ProcessName, A
WinActivate, ahk_exe ${1}
winActivateErrorLevel=%ErrorLevel%
WinWaitActive, ahk_exe ${1}
var = % activeWinproc . " " . winActivateErrorLevel
EOT
)"
以下に同じ理屈で量産した実用例を置いておきます。
現在のアクティブウィンドウを取得
getActiveWindowName(){
ahkprint ${@} <<< "WinGet, var, ProcessName, A"
}
使用例
[[ ! "$( getActiveWindowName )" == atom.exe ]] && { : アクティブウィンドウがatom.exeじゃないときにしたい処理here ; }
マウス座標を取得
getMousePos(){
: e.g. getMousePos
: e.g. getMousePos Relative
ahkprint ${1:-Screen} ${@:2} <<< "$( cat << 'EOT'
CoordMode, Mouse, ${1}
MouseGetPos, posX, posY
var = % posX . " " . posY
EOT
)"
}
使用例
$ getMousePos Relative
998 510
$ getMousePos
991 923
$
ミュートならミュート解除
unmute(){
: e.g. unmute
ahkprint ${@} <<< "$( cat << 'EOT'
;ミュートならミュート解除
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
)"
}
使用例
$ unmute
Off Off
$ unmute
On Off
$
音量を取得
getVolume(){
: e.g. getVolume
ahkprint ${@} <<< "$( cat << 'EOT'
SoundGet, var
EOT
)"
}
使用例
$ getVolume
6.999999
独自定義の関数とエイリアス
$ 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)
}
まとめ
一応bashやその他プログラミング言語の外部コマンドから任意のブログラマブルなautohotkeyスクリプトを実行して結果を受け取る、というところまで実装してみました。どこか抜けているところやもっといい方法などあればコメントなどで教えてくれたら嬉しいです。
15歳でWordPressサイトを立ち上げ、ウェブ領域に足を踏み入れる。翌年にはRuby on Railsを用いたマイクロサービス開発に着手し、現在はデジタル庁を支えたNext.jsによるHP作成やSaaS開発のプロジェクトに携わりながら、React.js・Node.js・TypeScriptによるモダンなウェブアプリの個人開発を趣味でも行う。
フロントエンドからバックエンドまで一貫したアジャイルなフルスタック開発を得意とし、ウェブマーケティングや広告デザインも必要に応じて担当、広告運用・SEO対策・データ分析まで行う低コストかつ高品質な顧客体験の提供が好評。
国内外から200万人を超える人々に支えられ、9周年を迎えるITブログ「yuipro」の開発者、デザイナーでありライター。現在ベータ段階の自作SNS「nyapp.buzz」を日本一の国産SNSとするべく奮闘中。