TL;DR —
SendKeysはキーを押しません。キー入力をキューに落とす だけで、それが読み取られた時点でフォーカスを持っているウィンドウが受け取ります。SendKeys への不満のほとんどは、ここから来る二つの帰結で説明できます。Excel に送ったキーが読み取られるのは、マクロが 制御を譲った とき、つまりマクロの終了時かDoEventsの時点だけなので、SendKeysの後ろの行が先に実行されます。そして別のプログラムに送ったキーは、届いた時点で フォーカスを持っているウィンドウ に入るので、意図したウィンドウとは限りません。+ ^ % ~ ( )といった文字はコードなので、文字どおりの50%は50{%}と書かなければなりません。SendKeysは、マクロの最終行で Excel 自身の画面をユーザーのために整えておく用途に限って使ってください。それ以外のすべてには、同じ仕事を直接こなすオブジェクトモデルの呼び出しがあります。
Sub EditNoteCell()
Range("D2").Select
SendKeys "{F2}" ' 最終行:ユーザーは D2 の編集モードから作業を始められる
End Sub
この記事は、Excel があなたの代わりに実行するマクロ を扱うシリーズの第三回です。ショートカットキー から、OnTime による時刻指定 から、そして今回は偽装したキー入力から起動するマクロです。シリーズを貫く考え方は、どれも何かを直接呼び出してはいない。それぞれがキューに要求を入れ、その要求は Excel の手が空いて準備ができたときに処理される ということです。SendKeys の場合、要求とはキー入力であり、キューとは最前面にあるウィンドウのキーボード入力です。
この記事で学べること
- 考え方の軸:キューに入ったキー入力が、フォーカスのあるウィンドウに届く
- 構文、キーコード、そして特殊文字を文字どおりに送る方法
- SendKeys の実行順序が狂って見える理由
- フォーカス、違うウィンドウ、そして無人では実行できない理由
- Num Lock の副作用
- SendKeys が向いている数少ない用途と、代わりに使うべきもの
考え方の軸:キューに入ったキー入力
キーを押すと、Windows はそれをフォーカスを持つウィンドウの入力キューに入れ、そのプログラムは手が空いたときにそれを読み取ります。SendKeys は、キーが実際に打たれたかのように、その同じキューへ書き込みます。
つまり SendKeys が決めるのは 何が 入力されるかであって、いつ 読み取られるかも、誰が 読み取るかも決めません。
- いつ:受け取る側のプログラムは、手が空いたときにキューを読みます。受け取る側が Excel なら、Excel はあなたのマクロの実行で忙しいので、キーを読むのはマクロが制御を譲ったあとです。
- 誰が:キーは、読み取られた瞬間にフォーカスを持っているウィンドウに届きます。その行を書いたときに思い描いていたウィンドウではありません。
この二つの問いを頭に置いておけば、奇妙な挙動も予測できるようになります。
構文とキーコード
書き方は二つあり、引数は同じです。
SendKeys "^c" ' VBA のステートメント
Application.SendKeys "^c" ' Excel のメソッド
SendKeys "~", True ' Wait:=True:キーが処理されるまで待つ
ほとんどのキーはそのまま書きます。SendKeys "abc" と書けば abc と入力されます。修飾キーと名前付きのキーにはコードを使います。
| コード | キー |
|---|---|
^ |
Ctrl。^s で Ctrl+S |
+ |
Shift。+{F10} で Shift+F10 |
% |
Alt。%{DOWN} で Alt+↓ |
~ または {ENTER} |
Enter |
{TAB}、{ESC}、{BS}、{DEL} |
Tab、Esc、BackSpace、Delete |
{UP}、{DOWN}、{LEFT}、{RIGHT} |
方向キー |
{HOME}、{END}、{PGUP}、{PGDN} |
移動用のキー |
{F1} ~ {F16} |
ファンクションキー |
{LEFT 3} |
キーを 3 回繰り返す |
+(abc) |
Shift を押したまま a、b、c を押す |
Windows キーや Print Screen のコードはなく、SendKeys でマウスをクリックすることもできません。
特殊文字は波かっこで囲む
+ ^ % ~ ( ) はコードなので、そのままでは文字として入力できません。次のコードは 50 を入力したあと Alt を押します。
SendKeys "Discount 50%" ' 誤り:% は Alt を意味する
SendKeys "Discount 50{%}" ' 正しい:波かっこで囲むと文字どおりになる
波かっこで囲むべき文字は + ^ % ~ ( ) { } [ ] です。文字列がセルやユーザーから来るなら、手作業ではなく関数でエスケープしましょう。
Function EscapeKeys(ByVal s As String) As String
Dim i As Long, ch As String, result As String
For i = 1 To Len(s)
ch = Mid$(s, i, 1)
If InStr("+^%~(){}[]", ch) > 0 Then
result = result & "{" & ch & "}"
Else
result = result & ch
End If
Next i
EscapeKeys = result
End Function
SendKeys の実行順序が狂って見える理由
いちばんよくある質問がこれです。SendKeys の後ろのコードが、キーより先に実行されてしまう。典型的な例を見てみましょう。
Sub CopyWithKeys()
Range("A1:C10").Select
SendKeys "^c" ' キューに入っただけで、まだ読まれていない
Worksheets("Report").Paste ' 今すぐ実行される:クリップボードはまだ空
End Sub
SendKeys は Ctrl+C を Excel のキューに入れ、すぐに戻りました。Excel は手が空いたときにキューを読みますが、今は手が空いていません。CopyWithKeys を実行中だからです。そのため Paste が先に実行され、コピーはマクロが終わってから起きます。ここで Wait:=True は役に立ちません。コードが実行中の間、Excel は自分宛てのキーを処理できないからです。SendKeys の後ろに DoEvents を置くとキーが通ることもありますが、通らないこともあります。まったく通らないより、むしろたちが悪い状態です。
ここから導かれるルールはこうです。Excel に送るキーは、マクロの最終行に置く。そのあとに起きなければならない処理は、そのキーに依存させてはいけません。そしてこの例での正解は、タイミングを直すことではなく、行が実行されたその瞬間に動くオブジェクトモデルを使うことです。
Range("A1:C10").Copy Destination:=Worksheets("Report").Range("A1")
コピーの方法の全体像は コピーと貼り付けのガイド で扱っています。
キーを受け取るのはフォーカスのあるウィンドウ
別のプログラムにキーを送るときは、二つ目の問いが主役になります。キーが読み取られる時点で、フォーカスを持っているのは誰か、です。
Shell "notepad.exe", vbNormalFocus
Application.Wait Now + TimeSerial(0, 0, 1) ' それまでにメモ帳の準備ができていることを祈る
SendKeys "Monthly total: 1250~"
メモ帳の起動が遅ければ、キーは代わりに Excel に届き、セルに入力されます。その一秒の間に通知やメール、チャットのウィンドウがフォーカスを奪えば、文字はそこに入ります。画面がロックされていたり、リモートセッションが最小化されていたりすれば、キーはどこにも届きません。さらに Windows は、通常のプログラムから管理者として実行中のプログラムへのキー入力をブロックするので、昇格したウィンドウへの SendKeys は黙って何もしません。
だから無人で動かす処理についてのルールは絶対です。SendKeys は、誰も見ていないところでは使えない。 OnTime やタスク スケジューラから起動され、SendKeys を使うマクロは、遅かれ早かれ見当違いの場所に入力します。別のプログラムを操作するなら、CreateObject でそのオブジェクトモデルを使うか、Shell で引数を付けて起動してください。
Num Lock の副作用
昔から知られている副作用があります。多くの Windows PC で、VBA の SendKeys ステートメントは Num Lock をオフにし、Caps Lock に影響することもあります。ユーザーは、あなたのマクロを実行したあとテンキーが効かなくなったことに気づきます。
元に戻そうと {NUMLOCK} を送るコードは、もう一度切り替えるだけなので、ある PC では正しく、別の PC では逆効果になります。Application.SendKeys のほうがステートメントより起きにくいという報告もありますが、どちらも当てにはなりません。本当の解決策は、このページのほかのすべてと同じです。送るキーを減らすことです。最終行で一度だけ SendKeys を使うマクロなら、この問題で気づかれることはまずありません。
判断の分かれ目:最後の手段、それも Excel 自身の画面のために
SendKeys が向いている仕事は一種類だけです。マクロの最終行で、Excel 自身の画面をユーザーのために整えておくこと。 {F2} でセルを編集モードにする、%{DOWN} でフィルターのドロップダウンを開く、といった使い方は妥当です。ユーザーがその場にいて、コードの中に結果に依存する処理が何もないからです。
それ以外のすべてには、行が実行されたその瞬間に、どんなキーボード配列でも、どのウィンドウが前面にあっても動く、直接の呼び出しがあります。
| キーを送ってやりたいこと | 代わりに使うもの |
|---|---|
^c、^v でコピーと貼り付け |
Range.Copy、PasteSpecial |
^s で保存 |
ThisWorkbook.Save |
~ で Excel の確認メッセージに答える |
Application.DisplayAlerts = False |
% から始まるキー操作でリボンのコマンドを実行 |
Application.CommandBars.ExecuteMso "PasteValues" |
| 組み込みダイアログを開く | Application.Dialogs(xlDialogPrint).Show |
| 別のプログラムに入力する | CreateObject 経由でそのオブジェクトモデルを使う |
Alt、H、V、V のようなキー操作の並びは、Office の表示言語にも左右されます。リボンのアクセスキーは英語版・ドイツ語版・スペイン語版の Excel で異なり、日本語版の Excel でも英語版とは違うので、ある言語の Excel で書いた SendKeys の並びは別の言語では間違いになります。右の列の呼び出しには、この問題がありません。キーを一切押さずに Excel 自身の確認メッセージに対処する方法は DisplayAlerts のガイド で紹介しています。
ExcelMaster の活用
SendKeys のコードは、たいてい書かれた PC で、書かれた日には動きます。壊れるのは、キーボード配列が違うとき、PC が遅いとき、Office の言語が違うとき、そして初めて通知がフォーカスを奪ったときです。
ExcelMaster はマクロを読み、各 SendKeys の行が何をしようとしているのかを突き止め、同じ仕事を直接こなすオブジェクトモデルの呼び出しに置き換えます。こうしてマクロは、タイミングにもフォーカスにもキーボード配列にも左右されなくなります。
よくある質問
SendKeys で Enter キーを送るには?
SendKeys "~" または SendKeys "{ENTER}" を使います。チルダはメインの Enter キー、{ENTER} はテンキーの Enter キーで、たいていのプログラムではどちらでも動きます。
マクロで SendKeys が効かないのはなぜですか?
たいていは効いているのですが、思ったより遅れて効いています。Excel に送ったキーはマクロが制御を譲ったあとに読み取られるので、SendKeys の後ろの行が先に実行されます。別のプログラムに送ったキーは、読み取られた時点でフォーカスを持っているウィンドウに届きます。SendKeys を最終行に置くか、オブジェクトモデルの呼び出しに置き換えてください。
SendKeys で Num Lock がオフになるのはなぜですか?
Windows 上の VBA の SendKeys ステートメントで昔から知られている副作用です。{NUMLOCK} を送り返しても切り替わるだけなので当てになりません。SendKeys の使用はできるだけ減らしてください。
SendKeys と Application.SendKeys の違いは何ですか?
SendKeys は VBA のステートメント、Application.SendKeys は Excel のメソッドです。どちらも同じキーコードと同じ Wait 引数を受け取り、どちらもフォーカスを持つウィンドウの入力キューに書き込みます。
SendKeys でパーセント記号やプラス記号を送るには?
波かっこで囲みます:{%}、{+}、{^}、{~}、{(}、{)}。波かっこがないと、これらの文字は Alt、Shift、Ctrl、Enter、グループ化のコードとして読まれます。
検証環境
検証環境: Excel 365 (Windows 11)、VBA 7.1 — 最終確認 2026-10-03。
関連ガイド: VBA Shortcut Key · VBA OnTime · VBA Copy Paste · VBA DisplayAlerts · VBA DoEvents · VBA Shell · VBA CreateObject · VBA Wait
