Edited at

AutoHotkeyで指定ウィンドウごとに独自マクロを設定・実行する

特定のアプリにて同じ入力を繰り返し行った際、その入力を自動化したくなる場面がありますが、その自動入力をAutoHotkey(以降AHK)スクリプト内の独自マクロとして記述し、実行出来るようにしました。

指定したウィンドウを対象に、Send・Sleep・Copy・Paste・文字列の挿入を実行する事が出来ます。

11/5: コピー・ペーストコマンドを追加しました。

マクロの編集画面

macro_edit.png

入力欄がマクロの記述先、Backgroundチェックボックスはマクロ実行後にアクティブウィンドウをもとに戻すか、Shift+Insert Pasteチェックボックスは文字列ペーストをShift+Insertで行うか(デフォルトはCtrl+v)の設定です。

本記事のスクリプトは最後に記載しています。


使い方


  1. 任意のウィンドウをアクティブ状態にし、独自マクロの編集画面を起動します。

  2. 独自マクロを記述後、OKボタンを押します。

  3. この状態で、別のウィンドウをアクティブにしていても1.のウィンドウに対して独自マクロの操作が実行されるようになります。


使用例・デモ

これだけだとピンとこないので幾つか使用例を載せておきます。


その1(コマンドプロンプト)

コマンドプロンプトにてC言語のコンパイル・実行する場合は

>gcc main.c -o a.exe && a

と入力・実行出来ますが、これをマクロ内に文字列として記述し、任意のコマンドプロンプトを対象にして実行させる事が出来ます。

マクロ内容(再掲)

macro_edit.png

デモ(コンパイル・実行)

gcc_demo.gif


その2(メモ帳)

メモ帳にて、メニューの「日付と時刻」を組み合わせてみます。

マクロ内容

macro_notepad_edit.png

「日付と時刻」のキーボード選択はAlt+e、dキーで出来ます。

デモ(日付と時刻の入力)

notepad_demo.gif

また、日付と時刻取得ツールとして利用する事も出来ます。

マクロ内容

macro_time.png

デモ(日付と時刻取得ツールとして)

demo_time.gif

ペーストだけをして、コピー内容のストックとして利用してみます。

マクロ内容

macro_paste.png

デモ(コピー内容ストック)

demo_paste.gif


その3(電卓)

計算結果を受け取ってみます。

マクロ内容

macro_calc.png

デモ(計算結果の取得)

demo_calc.gif


スクリプト

掲載ソースでは無変換 & ファンクションキーに設定しています、Ctrlキーの有無で編集、実行を切り替え出来るようにしています。

また、独自マクロはスクリプトと同じフォルダに「minimacro」フォルダを掘り、その中に保存されるようになっています。

これらが気に入らなければカスタマイズして下さい。


AutoHotkey.ahk

; ミニマクロ

sc07B & F1:: mmEditOrRun(macids, 1)
sc07B & F2:: mmEditOrRun(macids, 2)
sc07B & F3:: mmEditOrRun(macids, 3)
{
; 編集/実行
mmEditOrRun(ByRef ids, idx)
{
; initialize
global g_mm_checkBackgrounds
global g_mm_checkShiftInsertPastes

g_mm_checkBackgrounds := (g_mm_checkBackgrounds) ? g_mm_checkBackgrounds : {}
g_mm_checkShiftInsertPastes := (g_mm_checkShiftInsertPastes) ? g_mm_checkShiftInsertPastes : {}
ids := (ids) ? ids : {}

if GetKeyState("ctrl", "P") {
mmEdit(ids, idx)
} else {
mmRun(ids, idx)
}
}

g_mm_checkBackgrounds := {}
g_mm_checkShiftInsertPastes := {}
g_mm_guiIndex := -1
g_mm_editMacro := ""

; 編集
mmEdit(ByRef ids, idx)
{
global g_mm_checkBackgrounds
global g_mm_checkShiftInsertPastes
global g_mm_guiIndex
global g_mm_editMacro

g_mm_guiIndex := idx
g_mm_editMacro := mmRead(idx)

; 対象ウィンドウを記憶
WinGet, id, ID, A
ids[g_mm_guiIndex] := id

background := g_mm_checkBackgrounds.HasKey(idx) ? g_mm_checkBackgrounds[idx] : 1
checkedBG := (background) ? "Checked" : ""

paste := g_mm_checkShiftInsertPastes.HasKey(idx) ? g_mm_checkShiftInsertPastes[idx] : 0
checkedPaste := (paste) ? "Checked" : ""

; 編集画面
Gui, Add, Edit, W300 H70 vg_mm_editMacro, %g_mm_editMacro%
Gui, Add, Checkbox, vcheckBackground %checkedBG%, Background(&B)
Gui, Add, Checkbox, vcheckShiftInsertPaste %checkedPaste%, Shift+Insert Paste(&P)
Gui, Add, Button, W80 X70, &OK
Gui, Add, Button, W80 X+0, &Cancel
Gui, Show, , MiniMacro (%g_mm_guiIndex%)
}
ButtonOK:
Gui, Submit
; ミニマクロ、設定の保存
mmWrite(g_mm_guiIndex, g_mm_editMacro)
g_mm_checkBackgrounds[g_mm_guiIndex] := checkBackground
g_mm_checkShiftInsertPastes[g_mm_guiIndex] := checkShiftInsertPaste
ButtonCancel:
GuiClose:
GuiEscape:
Gui, Destroy
return

; 実行
mmRun(ByRef ids, idx)
{
global g_mm_checkBackgrounds
global g_mm_checkShiftInsertPastes

if (!ids.HasKey(idx)) {
MsgBox, 0x10, ,Target Window is none
return
}

id := ids[idx]
background := g_mm_checkBackgrounds.HasKey(idx) ? g_mm_checkBackgrounds[idx] : 1
shiftInsertPaste := g_mm_checkShiftInsertPastes.HasKey(idx) ? g_mm_checkShiftInsertPastes[idx] : 0

clip_bak := ClipboardAll
WinGet, win_bak, ID, A

; 対象ウィンドウをアクティブにし
WinActivate, ahk_id %id%
; ミニマクロ実行
for _, line in StrSplit(mmRead(idx), "`n")
{
line := Trim(line)

if (InStr(line, "Sleep,") == 1) {
msec := Trim(SubStr(line, 7))
Sleep, %msec%
} else if (InStr(line, "Send,") == 1) {
keys := Trim(SubStr(line, 6))
Send, %keys%
} else if (InStr(line, "Copy,") == 1) {
Clipboard = ; Empty the clipcboard
Send, ^c
copyWaitWithThrow()
clip_bak := ClipboardAll
} else if (InStr(line, "Paste,") == 1) {
if (shiftInsertPaste) {
Send, +{Blind}{Insert}
} else {
Send, ^v
}
pasteWaitWithThrow()
} else {
Clipboard := line
; 貼り付けEnter
if (shiftInsertPaste) {
Send, +{Blind}{Insert}
} else {
Send, ^v
}
Send, {Blind}{Enter}
pasteWaitWithThrow()
Clipboard := clip_bak
}
}

; 復元
if (background) {
WinActivate, ahk_id %win_bak%
}
}

; クリップボードのペースト完了を待つ
pasteWaitWithThrow()
{
local timeout = 2000
local h
local tic := a_tickcount
Sleep, 10
while ((h := DllCall("GetOpenClipboardWindow", "Ptr")) && a_tickcount - tic < timeout) {
Sleep, 10
}
Sleep, 10

if (!!h) {
throw "The attempt to paste text from the clipboard failed."
}
}
; クリップボードのコピー完了を待つ
copyWaitWithThrow()
{
ClipWait, 2
if (ErrorLevel <> 0) {
throw "The attempt to copy text onto the clipboard failed."
}
}

; ミニマクロ読み込み
mmRead(idx)
{
dir := A_ScriptDir . "\minimacro"
filename := dir . "\minimacro" . idx . ".txt"

macro := ""
if (FileExist(filename)) {
FileRead, macro, *t %filename%
}
return macro
}
; ミニマクロ書き出し
mmWrite(idx, macro)
{
dir := A_ScriptDir . "\minimacro"
if (!FileExist(dir)) {
FileCreateDir, %dir%
}
filename := dir . "\minimacro" . idx . ".txt"

file := FileOpen(filename, "w `n")
file.Write(macro)
file.Close()
}
}



余談(コピー・ペーストについて)

コピーの完了待ちは、AHK組み込みのClipWait関数で待つようにしましょう、その際は一度クリップボードを空にしないと上手く待ってくれません。

ペーストの完了待ちは、Win32APIのGetOpenClipboardWindows関数でクリップボードを操作しているアプリの存在をチェックし、無くなるまで待機をすれば上手く動作します。


参考