(今日の独り言)(AutoHotkey)(API関数も使える? 電卓をいじってみる 編)

 AutoHotKeyAPIも使えるので こんな事は出来て当たり前なんですが
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_STYLE0x0130 という数値は 電卓 というソフト における メニューの 関数電卓 というアイテムの IDのようなものです
例えば メモ帳 の 上書き保存wID0x0003 です、 つまり それを呼び出せば 強制的に 上書き保存させる事が出来ます
メニューには こういう 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関数で ひとつずつ 調べていって
そのハンドルのウインドウに 対して クリックをシミュレーションしてます
上の例だと 単に 「ボタンが押されましたよ」と 報告するだけですが、 この例だと 「実際にボタンをクリックしている」
という違いがあります