プログラミング

Node.jsでAutoHotkeyをスクリプティングする

Node.jsでAutohotkeyプログラムが書けると、他のライブラリ、例えばウェブサーバーのExpress.jsや、WebSocketなどnode.jsの便利なライブラリと統合して、
フレキシビリティの高いプログラミングを行うことができます。

以下は下記の関数を定義してから実行できるコードの例です。
このコードではシンプルに、マウスクリックをして→”hoge hoge”とキーボードタイピングする、という動作を行います。

await ahk({program: `MouseClick, left`});
await ahk({program: `send, hoge hoge`});

今回は特にこれといったnode.jsのためのautohotkeyラッパーライブラリを使う、といったことはせず、シンプルに手軽に使える関数を定義してみます。

以下は軽く書いてみたコードです。


const fs = require('fs');
const exec = require('child_process').exec;

// ..

async function ahk(...arg)
{
  fs.writeFileSync(`./tmp.ahk`, `
    #include C:/pg/autohotkey/ahkrc.ahk

    ${arg[0].program}

    file := FileOpen("C:/pg/autohotkey/.is_finished", "w", "UTF-8") ; wait for ahk finish
    file.Write("0")
    file.Close()
  `);
  await exec("nkf --overwrite --oc=UTF-8-BOM ./tmp.ahk", (error, stdout, stderr) => { if ( error ){ console.log(error) } if ( stdout ){ console.log(stdout) } if ( stderr ){ console.log(stderr) } });
  await exec("AutoHotkeyU64.exe ./tmp.ahk &", (error, stdout, stderr) => { if ( error ){ console.log(error) } if ( stdout ){ console.log(stdout) } if ( stderr ){ console.log(stderr) } });

  await (new Promise((resolve) => {
    fs.watch('/mnt/c/pg/autohotkey/.is_finished', (e, f) => { resolve() })
  })); // wait for ahk finish
}

“C:/pg/autohotkey”パスを適当なフォルダパスに変更して使用します。
“ahkrc.ahk”は常に読み込むautohotkeyスクリプト、例えば関数など、のファイルです。不必要な場合はコメントインしてください。

“nkf”コマンドでのファイルの文字コード変更は、autohotkeyスクリプトに日本語文字列が含まれているような場合に推奨しています。
なお、nkfコマンドはWindows 10のWSL Bash上でnode.jsを動かしていることを想定して使われています。Powershellなどからnode.jsを動かしているような場合は、”nkf”をchochocolateyなどでwindowsにインストールするか、以下のようなコマンドでWSLを呼び出すことでおそらく可能です。

bash -c "nkf --overwrite --oc=UTF-8-BOM ./tmp.ahk"

“AutoHotkeyU64.exe”ファイルのフォルダにはパスを通しておく必要があります。フォルダへのパスは以下のはずです。

C:\Program Files\AutoHotkey\AutoHotkeyU64.exe

パスを通したくない場合は、以下でおそらく代替できます。

powershell.exe 'C:\Program` Files\AutoHotkey\AutoHotkeyU64.exe ./tmp.ahk'

この関数の基本的な構造は、単純に、fs.writeFileSyncでahkファイルを作成、execでそのファイルをコマンド実行、というシンプルな2ステップですが、
このスクリプトでは、autohotkeyの動作の終了をawaitで待機することができます。
仕組みとして、以下のahkスクリプトをスクリプトの最後に実行し、一時ファイルを作成します。

file := FileOpen("C:/pg/autohotkey/.is_finished", "w", "UTF-8") ; wait for ahk finish
file.Write("0")
file.Close()

一方、node.js側では、一時ファイルの作成アクションがされること、すなわちahkスクリプトが最後まで実行されたこと、を確認し、その後のスクリプトへ続きます。

await (new Promise((resolve) => {
    fs.watch('/mnt/c/pg/autohotkey/.is_finished', (e, f) => { resolve() })
}));

これにより、以下のようなコードでは、クリックが実行されずに”hoge hoge”がタイピングされてしまうのに対し、

ahk({program: `MouseClick, left`}); // this does not wait the ahk program finish, thus, the text will be sent before the left click
ahk({program: `send, hoge hoge`});

awaitで終了を待機してそれぞれのautohotkeyプログラムを順次安定的に実行していくことができます。

await ahk({program: `MouseClick, left`}); // this does work perfectly
await ahk({program: `send, hoge hoge`});

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です