(今日の独り言)(AutoHotkey)(API関数も使える? 電卓をいじってみる 編)
AutoHotKey は APIも使えるので こんな事は出来て当たり前なんですが
「Windowsの仕組み」を知るためにはちょうどいい 遊び いやっ 勉強道具 なのでちょっとだけ 記事を書いてみます
今回は 電卓がすでに起動しているのが前提の話になります
API関数が使えるなら AutoHotkeyから 電卓に対して メッセージ を送ってやる事で リモコンのように操作をする事が出来ます
では サンプルとして 電卓のスタイルを変更してみましょう、 電卓には「普通の電卓」と「関数電卓」の二種類がありますよね?
で 普段 手作業で 切り替えるときは 表示メニューを開いて 切り替えますよね?
要はつまり API関数を使って その真似事をして AutoHotkeyから 電卓をリモコン操作してしまおうということです
これを実行すると 電卓のスタイルが 関数電卓 に 切り替わります
普通の電卓にしたい時は FUNCTION_STYLE の部分を NORMAL_STYLE と 置き換えればOKです
これを簡潔に説明すると
電卓のハンドルを取得し 電卓を特定して、電卓に対して 「メニューから 関数電卓 が 選ばれましたよ!」と
報告していることになります
WM_COMMAND というのは 「なんらかの コマンド(命令) が 送られましたよ」を意味してます
FUNCTION_STYLE の 0x0130 という数値は 電卓 というソフト における メニューの 関数電卓 というアイテムの IDのようなものです
例えば メモ帳 の 上書き保存 の wID は 0x0003 です、 つまり それを呼び出せば 強制的に 上書き保存させる事が出来ます
メニューには こういう wIDが設定されていますので それを特定できれば 「メニューをクリックした」という操作も可能になります
それらを特定するのは VisualC++ などに含まれている SPY++ を使えば 比較的簡単に探す事が出来ます
その他にも、 以下のサンプル自体は 全く持って意味の無いプログラムですが
こんな事も出来ますね
数字 や + = の wID を 送信して 100 + 300 の 計算をやっています
Sleepを入れていないと 爆速過ぎて いきなり答えが出ます 笑)
さらに これも 結果的には 同じ事なんですが 今回は 意味合いが ちょっと違います
ハンドルに対して 「WM_LBUTTONDOWN」 「WM_LBUTTONUP」 と 続けて メッセージ を 送るということは
そのハンドルのウインドウを『クリックした』という事を意味しています
よって 今回は ボタンのハンドルを FindWindowEx関数で ひとつずつ 調べていって
そのハンドルのウインドウに 対して クリックをシミュレーションしてます
上の例だと 単に 「ボタンが押されましたよ」と 報告するだけですが、 この例だと 「実際にボタンをクリックしている」
という違いがあります
「Windowsの仕組み」を知るためにはちょうどいい 遊び いやっ 勉強道具 なのでちょっとだけ 記事を書いてみます
今回は 電卓がすでに起動しているのが前提の話になります
API関数が使えるなら AutoHotkeyから 電卓に対して メッセージ を送ってやる事で リモコンのように操作をする事が出来ます
では サンプルとして 電卓のスタイルを変更してみましょう、 電卓には「普通の電卓」と「関数電卓」の二種類がありますよね?
で 普段 手作業で 切り替えるときは 表示メニューを開いて 切り替えますよね?
要はつまり API関数を使って その真似事をして AutoHotkeyから 電卓をリモコン操作してしまおうということです
[]WM_COMMAND := 0x0111[] []FUNCTION_STYLE := 0x0130[] []NORMAL_STYLE := 0x0131[] []hCalcWindow := DllCall("user32.dll\FindWindowA", "Str", "SciCalc")[] []DllCall("SendMessageA", "Int", hCalcWindow, "Int", WM_COMMAND, "Int", FUNCTION_STYLE)[]これが その 真似事の例です
これを実行すると 電卓のスタイルが 関数電卓 に 切り替わります
普通の電卓にしたい時は FUNCTION_STYLE の部分を NORMAL_STYLE と 置き換えればOKです
これを簡潔に説明すると
電卓のハンドルを取得し 電卓を特定して、電卓に対して 「メニューから 関数電卓 が 選ばれましたよ!」と
報告していることになります
WM_COMMAND というのは 「なんらかの コマンド(命令) が 送られましたよ」を意味してます
FUNCTION_STYLE の 0x0130 という数値は 電卓 というソフト における メニューの 関数電卓 というアイテムの IDのようなものです
例えば メモ帳 の 上書き保存 の wID は 0x0003 です、 つまり それを呼び出せば 強制的に 上書き保存させる事が出来ます
メニューには こういう wIDが設定されていますので それを特定できれば 「メニューをクリックした」という操作も可能になります
それらを特定するのは VisualC++ などに含まれている SPY++ を使えば 比較的簡単に探す事が出来ます
その他にも、 以下のサンプル自体は 全く持って意味の無いプログラムですが
こんな事も出来ますね
[]WM_COMMAND := 0x0111[] []BUTTON0 := 0x007c[] []BUTTON1 := 0x007d[] []BUTTON3 := 0x007f[] []BUTTON_PLUS := 0x005c[] []BUTTON_EQUAL := 0x0070[] []hCalcWindow := DllCall("user32.dll\FindWindowA", "Str", "SciCalc")[] []DllCall("SendMessageA", "Int", hCalcWindow, "Int", WM_COMMAND, "Int", BUTTON1)[] []Sleep, 300[] []DllCall("SendMessageA", "Int", hCalcWindow, "Int", WM_COMMAND, "Int", BUTTON0)[] []Sleep, 300[] []DllCall("SendMessageA", "Int", hCalcWindow, "Int", WM_COMMAND, "Int", BUTTON0)[] []Sleep, 300[] []DllCall("SendMessageA", "Int", hCalcWindow, "Int", WM_COMMAND, "Int", BUTTON_PLUS)[] []Sleep, 300[] []DllCall("SendMessageA", "Int", hCalcWindow, "Int", WM_COMMAND, "Int", BUTTON3)[] []Sleep, 300[] []DllCall("SendMessageA", "Int", hCalcWindow, "Int", WM_COMMAND, "Int", BUTTON0)[] []Sleep, 300[] []DllCall("SendMessageA", "Int", hCalcWindow, "Int", WM_COMMAND, "Int", BUTTON0)[] []Sleep, 300[] []DllCall("SendMessageA", "Int", hCalcWindow, "Int", WM_COMMAND, "Int", BUTTON_EQUAL)[]上のサンプルとやっていることは変わりませんね
数字 や + = の wID を 送信して 100 + 300 の 計算をやっています
Sleepを入れていないと 爆速過ぎて いきなり答えが出ます 笑)
さらに これも 結果的には 同じ事なんですが 今回は 意味合いが ちょっと違います
[]WM_LBUTTONDOWN := 0x0201[] []WM_LBUTTONUP := 0x0202[] []hWindow := DllCall("user32.dll\FindWindowA", "Str", "SciCalc")[] []DllCall("user32.dll\SetWindowTextA", "Int", hWindow, "Str", "でんたくクン")[] []hCWindow0 := DllCall("user32.dll\FindWindowExA", "Int", hWindow, "Int", 0, "Str", "Button", "Str", "0")[] []hCWindow3 := DllCall("user32.dll\FindWindowExA", "Int", hWindow, "Int", 0, "Str", "Button", "Str", "3")[] []hCWindow5 := DllCall("user32.dll\FindWindowExA", "Int", hWindow, "Int", 0, "Str", "Button", "Str", "5")[] []hCWindowPlus := DllCall("user32.dll\FindWindowExA", "Int", hWindow, "Int", 0, "Str", "Button", "Str", "+")[] []hCWindowEqual := DllCall("user32.dll\FindWindowExA", "Int", hWindow, "Int", 0, "Str", "Button", "Str", "=")[] []DllCall("user32.dll\SendMessageA", "Int", hCWindow3, "Int", WM_LBUTTONDOWN, "Int", 0, "Int", 0)[] []DllCall("user32.dll\SendMessageA", "Int", hCWindow3, "Int", WM_LBUTTONUP, "Int", 0, "Int", 0)[] []Sleep, 300[] []DllCall("user32.dll\SendMessageA", "Int", hCWindow0, "Int", WM_LBUTTONDOWN, "Int", 0, "Int", 0)[] []DllCall("user32.dll\SendMessageA", "Int", hCWindow0, "Int", WM_LBUTTONUP, "Int", 0, "Int", 0)[] []Sleep, 300[] []DllCall("user32.dll\SendMessageA", "Int", hCWindow0, "Int", WM_LBUTTONDOWN, "Int", 0, "Int", 0)[] []DllCall("user32.dll\SendMessageA", "Int", hCWindow0, "Int", WM_LBUTTONUP, "Int", 0, "Int", 0)[] []Sleep, 300[] []DllCall("user32.dll\SendMessageA", "Int", hCWindowPlus, "Int", WM_LBUTTONDOWN, "Int", 0, "Int", 0)[] []DllCall("user32.dll\SendMessageA", "Int", hCWindowPlus, "Int", WM_LBUTTONUP, "Int", 0, "Int", 0)[] []Sleep, 300[] []DllCall("user32.dll\SendMessageA", "Int", hCWindow5, "Int", WM_LBUTTONDOWN, "Int", 0, "Int", 0)[] []DllCall("user32.dll\SendMessageA", "Int", hCWindow5, "Int", WM_LBUTTONUP, "Int", 0, "Int", 0)[] []Sleep, 300[] []DllCall("user32.dll\SendMessageA", "Int", hCWindow0, "Int", WM_LBUTTONDOWN, "Int", 0, "Int", 0)[] []DllCall("user32.dll\SendMessageA", "Int", hCWindow0, "Int", WM_LBUTTONUP, "Int", 0, "Int", 0)[] []Sleep, 300[] []DllCall("user32.dll\SendMessageA", "Int", hCWindow0, "Int", WM_LBUTTONDOWN, "Int", 0, "Int", 0)[] []DllCall("user32.dll\SendMessageA", "Int", hCWindow0, "Int", WM_LBUTTONUP, "Int", 0, "Int", 0)[] []Sleep, 300[] []DllCall("user32.dll\SendMessageA", "Int", hCWindowEqual, "Int", WM_LBUTTONDOWN, "Int", 0, "Int", 0)[] []DllCall("user32.dll\SendMessageA", "Int", hCWindowEqual, "Int", WM_LBUTTONUP, "Int", 0, "Int", 0)[]なにやら かなり長くなりましたね 笑)、 今回の計算は 300 + 500 です
ハンドルに対して 「WM_LBUTTONDOWN」 「WM_LBUTTONUP」 と 続けて メッセージ を 送るということは
そのハンドルのウインドウを『クリックした』という事を意味しています
よって 今回は ボタンのハンドルを FindWindowEx関数で ひとつずつ 調べていって
そのハンドルのウインドウに 対して クリックをシミュレーションしてます
上の例だと 単に 「ボタンが押されましたよ」と 報告するだけですが、 この例だと 「実際にボタンをクリックしている」
という違いがあります