ExcelでVBAでマクロを組む場合、SendKeysを使うとキー入力がシミュレートできるので、重宝する。しかし、意外と知られていない問題点がある。
(SendKeysについてはこのOffice TANAKA氏のページが参考になる。)
●コピー・ペーストについて
まず以下のマクロをVBエディターで標準モジュールに入力する。
SendKeys "^c{RIGHT}^v" ,True
End Sub
エクセルで、文字が入力されているセルを選択してから、このマクロを実行すると、
① Ctrl + C
② [→]キー
③ Ctrl + V
の順にキー入力がシミュレートされ、右側のセルに貼り付けが行われる。
しかし、マクロを「 SendKeys "^v" ,True 」とだけ記入し、①と②を手動で行い、マクロで実行しようとすると貼り付けが動かない。
つまり、マクロ側でコピーしたクリップボードの内容でないと貼り付けができない。
●waitオプションとSleep関数について
Sendkeysは相手を確認しないまま、ただキー入力を送り出すだけの仕組みだ。そのため、ダイアログボックスを呼び出して複雑な処理をさせるような場合、受け取るシステム側がSendkeysのキー入力に追いつけなくなり、誤作動を起こすことがある。そのような場合、waitオプションをTrueに指定すると、キーストロークが渡るまで処理を中断させることできする。
waitオプションを省略した場合は、デフォルトでFalseになる。
Sendkeys "(文字列)",True
ただし、キーが受信されたかを確認しているだけで、その結果の「システム側の処理が終わったかどうか」は確認していないので、誤作動の余地は残る。
その場合、API関数のSleepで、システム側の処理に時間を与えることで、改善する場合もある。
'標準モジュールの冒頭で宣言
Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
Sub Sample()
Sendkeys "(文字列)" ,True
Sleep(10) 'マクロの処理を指定時間だけ停止。1000で1秒
End Sub
●デバッグ中の誤作動
開発中にVBエディターでブレークポイントを設定しながらデバッグしていると、Sendkeysが誤作動を起こすことがある。
これは、ブレークポイントで停止すると、システムのフォーカスはエクセルのシートからVBエディターに移っているので、Sendkeysのキー入力がVBエディターの編集画面に送られることによる。このため、Sendkeysは、単体で十分テストしてから組み込む必要がある。
これ以外でも意図せずにシステムのフォーカスが移動することは多い。Sendkeysは相手を確認しないまま、ただキー入力を送り出すだけの仕組みなので、誤作動を完全に排除することはできない。このため、やむを得ない場合に限り利用し、できる限り短時間に終了するようにすべきだ。
●ダイアログの表示について
SendKeys "%fu" ,True
このマクロは、メニューの「ファイル(F)」→「ページ設定(U)」を開くショートカットキー(Alt + f → u )のキー入力をシミュレートする。実行すると、一気にページ設定ダイアログが開く。
最後のTrueは、処理が終わるまで、他のマクロを実行しないための指示。
しかし、SendKeysが行えるのはダイアログを表示するまでで、たとえば
SendKeys "%fuz" ,True
などとしても、「用紙サイズ(Z)」を操作することはできない。
これは、他のダイアログでも同じ模様。
●機能キーによるフォーカス移動
そこで、{RIGHT}、{TAB}、{HOME}などの機能キーを使う。(一覧はOffice TANAKA氏のページで)
下記では、ページ設定ダイアログで下余白を1.5mmに設定している。
SendKeys "%fu", True ' ページ設定ダイアログ開く
SendKeys "{RIGHT}", True ' 右カーソルで「余白」のタブへ
SendKeys "{TAB}{TAB}", True ' 下余白へ移動
SendKeys "{DOWN}{DOWN}{HOME}", True ' 余白を1.5mmにしHOMEキーで決定
SendKeys "{ENTER}", True ' 決定
これは、以下のようにつなげて書いても問題ない。
SendKeys "%fu{RIGHT}{TAB}{TAB}{DOWN}{DOWN}{HOME}{ENTER}", True
●{ESC}の取扱い
なお、ダイアログによっては{ENTER}だけでは、ダイアログが閉じない。その場合は
SendKeys "{ESC}", True ' ESCキーでダイアログを閉じる
しかし、{ESC}処理は長いマクロコードの中で使うと、問題を引き起こすことがある。
タイミングによっては、マクロを停止させるESCキー入力と誤判断され、処理が中断されることがあるのだ。
このため、該当サブルーチン等の中では、前もって、ESCキーのキャンセル処理を受け付けないようにしておく。
Application.EnableCancelKey = xlDisabled
Sendkeys ".......",True
SendKeys "{ESC}", True ' ESCキーでダイアログを閉じる