第5回 WshShellオブジェクトの詳細(1):Windows管理者のためのWindows Script Host入門(4/4 ページ)
WshShellオブジェクトを利用し、スクリプトから外部プログラムを起動して、キー・ストロークを送信して制御する。
キー・ストロークの送信:SendKeysメソッド
COMオブジェクトとして利用できる外部Windowsプログラムは、WSHスクリプトから直接操作できるが、そうでないWindowsプログラムをスクリプトで操作するには、プログラムを起動しておき、スクリプトからキー・ストロークを送信して、擬似的にプログラムがキーボードから操作されたように制御する。これに使えるのがWshShellオブジェクトのSendKeysメソッドとAppActivateメソッドである。
SendKeysメソッドは起動されているプログラムにキー・ストロークを送信するメソッドである。SendKeysメソッドを利用してキー操作をエミュレートすれば、ほとんどのWindowsプログラムを操作できる。ただし問題は、制御の可否が時間的なタイミングに大きく影響を受けることだ。
これは例えば、プログラムからダイアログ・ボックスをポップアップ表示して、[OK]ボタンを押すという操作を考えればすぐ分かる。基本的には、プログラムの本体にメニュー操作用のキー・ストロークを送信してダイアログを表示させ、次に[Enter]キーを送信して[OK]ボタンを押せばよい(多くのダイアログでは、標準で[OK]ボタンに入力フォーカスが設定されている)。しかしダイアログが表示されるよりも早く[Enter]を送信してしまうと、これは正しく処理されない。このため多くの場合スクリプトのプログラマは、キーの送信を行うタイミングを実行環境(コンピュータの性能など)に合わせて試行錯誤しながら設定しなければならない。また時間的なタイミングばかりでなく、スクリプトの実行中にユーザーがほかのプログラムをアクティブにしてしまったりすると誤動作することがある。実行時オプションや標準入出力を利用するこれまでの方法に比べると不安定な要素が大きい。従って安易にSendKeysメソッドに頼るのではなく、プログラムを制御する別の方法がないかを検討することが望ましい。
SendKeysメソッドのパラメータはプログラムに送信するキー・ストロークに対応する文字列である。SendKeysメソッドを実行すると、パラメータに指定した文字列がその時点でアクティブなウィンドウに送信される。例えば次は、メモ帳を起動し、起動処理が完了するまで1秒間待ち、“hello”と書き込むスクリプトである。なお、SendKeysメソッドでは、日本語などの2バイト文字を送信することはできない。
1: Set objShell = WScript.CreateObject("WScript.Shell")
2: objShell.Run "notepad.exe"
3: WScript.Sleep 1000
4: objShell.SendKeys "hello"
ShiftやCtrlキーなどの特殊キーには特別な文字列が割り当てられており、これを指定することで対応する特殊キーをプログラムに送信できる。具体的には、Shiftは「+」、Ctrlは「^」、Altは「%」、Enterは「~」といった具合だ(「^」などの記号自体を送信したければ、{ }でくくって{^}のようにする)。これら以外の特殊キーは{ }(中カッコ)を使って指定する。例えばEscは{ESC}、Tabは{TAB}、Back Spaceは{BACKSPACE}または{BS}、{BKSP}という具合である。詳細は前出のSendKeysメソッドのリファレンスにまとめられている。特殊キーの記述方法一覧を以下に示す。
キー | SenKeysメソッドのパラメータ |
---|---|
+ | {+} |
^ | {^} |
% | {%} |
Shift | + |
Ctrl | ^ |
Alt | % |
Enter | {ENTER} または ~ |
↓ | {DOWN} |
← | {LEFT} |
→ | {RIGHT} |
↑ | {UP} |
Back Space | {BACKSPACE}、{BS}、または {BKSP} |
Break | {BREAK} |
Caps Lock | {CAPSLOCK} |
Delete | {DELETE} または {DEL} |
End | {END} |
Esc | {ESC} |
Help | {HELP} |
Home | {HOME} |
Insert | {INSERT} または {INS} |
Num Lock | {NUMLOCK} |
Page Down | {PGDN} |
Page Up | {PGUP} |
Print Screen | {PRTSC} |
Scroll Lock | {SCROLLLOCK} |
Tab | {TAB} |
F1 | {F1} |
F2 (F3〜F12も同様) | {F2} |
特殊キーの記述方法 |
ShiftやCtrl、Altなどは、ほかのキーと組み合わせて使われるものだ。例えば[Ctrl]+[C]なら、「^c」のように記述する。またShift、Ctrl、Altを押しながら2文字以上を入力する場合は、カッコ「( )」で囲んで表す。例えば「%FO」なら、Altキーを押したままFキーを押し、Altキーを離してOキーを押すことを表すが、「%(FO)」ならAltキーを押したままF、Oの2つのキーを連続して押すことを表す(多くのWindowsプログラムのメニューであれば、どちらの方法でも「ファイル(F)」−「開く(O)」メニューを実行できる)。
1つのキーを繰り返し押す場合には、「{X 10}」のように記述すれば、Xキーを10回送信することができる。特殊文字の場合も、例えば「{DOWN 5}」と記述すれば5回下カーソルキー(↓)を送信することができる。
ここで例として、test.txtをメモ帳で開き、最初に「WSH」が登場する行をクリップボードにコピーし、メモ帳を終了するコードを作ってみよう。具体的にはメモ帳を起動し、検索ダイアログを表示し、“WSH”という文字列の検索を実行し、文字列が見つかった行の先頭から選択してクリップボードにコピーしてメモ帳を終了する。
1: Set objShell = WScript.CreateObject("WScript.Shell")
2: objShell.Run "notepad.exe test.txt"
3: WScript.Sleep 1000
4: objShell.SendKeys "^f" ' Ctrl+Fで検索ダイアログの表示
5: WScript.Sleep 100
6: objShell.SendKeys "WSH~" ' WSHと入力してEnterキーを押す
7: objShell.SendKeys "{ESC}" ' ダイアログを閉じる
8: WScript.Sleep 100
9: objShell.SendKeys "{HOME}" ' 行頭に戻る
10: objShell.SendKeys "+{END}" ' Shift+End で行末まで選択
11: objShell.SendKeys "^c" ' Ctrl+Cでコピー
12: objShell.SendKeys "%{F4}" ' Alt+F4で終了
スクリプトでは、最初にRunメソッドによりtext.txtを開き、その後の操作を順にSendKeysで送信している。最初の起動では1秒(3行目)、検索ダイアログの表示とダイアログを閉じる部分ではそれぞれ0.1秒ずつ待ち時間を設けている(5行目と8行目)。後半の処理の途中でも待ち時間を設定すれば、実際に行われている動作が目で追えるので面白いかもしれない。
プログラムのアクティベーション:AppActivateメソッド
上の例では、アクティブなプログラムに対してキーを送信し続けるため、ユーザーの操作などで、途中で別のウィンドウがアクティブになってしまうと、そのウィンドウに対してキーを送信してしまい、正常に動作することができない。また、起動までの時間を1秒と決めているので、それ以上起動に時間がかかった場合も問題が生じる。このような問題を少しでも解消するために、SendKeysを使う場合にはその直前にAppActivateメソッドを用い、キーを送信したいウィンドウをアクティブにしておくことが望ましい。
AppActivateメソッドは、ウィンドウ・タイトルの文字列、もしくはプロセスIDを指定することで、そのアプリケーション・ウィンドウをアクティブにするメソッドである。タイトルは完全に一致する文字列でなくても、最初から途中まで、もしくは途中から最後までの文字列を指定するだけでもよい。実行時には、完全に一致するもの→先頭が一致するもの→末尾が一致するものの順に検索される。いくつものウィンドウがヒットした場合には、そのうちのどれがアクティブになるかは決まっていない。
一方のプロセスIDは、Execを使って起動したプログラムでは、WshScriptExecオブジェクトのProcessIDプロパティから取得できる。
AppActivateメソッドは、実行に成功すればTrueを、失敗すればFalseを返す。この戻り値を利用して、成功するまで待つことができる。先ほどの例を書き直せば次のようになる。
1: Set objShell = WScript.CreateObject("WScript.Shell")
2: Set objExec = objShell.Exec("notepad.exe test.txt")
3: ' 起動を待つ
4: Do Until objShell.AppActivate(objExec.ProcessID)
5: WScript.Sleep 1000
6: Loop
7: objShell.SendKeys "^f" ' Ctrl+Fで検索ダイアログの表示
8: ' ダイアログの表示を待つ
9: Do Until objShell.AppActivate("検索")
10: WScript.Sleep 100
11: Loop
12: objShell.SendKeys "WSH~" ' WSHと入力してEnterキーを押す
13: objShell.SendKeys "{ESC}" ' ダイアログを閉じる
14: WScript.Sleep 100
15: objShell.AppActivate(objExec.ProcessID)
16: objShell.SendKeys "{HOME}" ' 行頭に戻る
17: objShell.SendKeys "+{END}" ' Shift+End で行末まで選択
18: objShell.SendKeys "^c" ' Ctrl+Cでコピー
19: objShell.SendKeys "%{F4}" ' Alt+F4で終了
AppActivateメソッドを利用して、4行目でメモ帳の起動完了を待ち、9行目で検索ダイアログの表示完了を待ち、15行目でメモ帳本体のウィンドウを再度明示的にアクティブにしている。このようにAppActivateを挿入することで、意図しないウィンドウへキーを送ることを防ぎ、スクリプトの安全性を高めることができる。
次回も引き続き、WshShellオブジェクトのメソッドとプロパティについて解説する。
Copyright© Digital Advantage Corp. All Rights Reserved.