t-hom’s diary

主にVBAネタを扱っているブログ…とも言えなくなってきたこの頃。

VBA 画面の任意の箇所をクリックさせるマクロ

ネットで色々と探したけれど、なかなかシンプルなコードが無かったので、可能な限りシンプルに、張り付けてそのまま動く形で公開しておく。
以下のマクロを実行すると、左から100ピクセル、上から35ピクセルの位置にカーソルが移動して、そこがクリックされる。

Declare Function SetCursorPos Lib "user32" (ByVal x As Long, ByVal y As Long) As Long
Declare Sub mouse_event Lib "user32" ( _
    ByVal dwFlags As Long, _
    Optional ByVal dx As Long = 0, _
    Optional ByVal dy As Long = 0, _
    Optional ByVal dwDate As Long = 0, _
    Optional ByVal dwExtraInfo As Long = 0)

Sub マウスで画面の任意の位置をクリック()
    SetCursorPos 100, 35  '左から100ピクセル、上から35ピクセルの位置にカーソルを移動
    mouse_event 2  '左ボタン押下のコード
    mouse_event 4  '左ボタン解放のコード
End Sub

他のサイトのサンプルでは、次のように定数を宣言して16進数を代入し、他の引数も省略せずに次のように書かれている。

    Const MOUSEEVENTF_LEFTDOWN = &H2
    Const MOUSEEVENTF_LEFTUP = &H4
    '~中略~
    mouse_event MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0
    mouse_event MOUSEEVENTF_LEFTUP, 0, 0, 0, 0

ただ、クリックするたびに0, 0, 0, 0を渡すのはコードが煩雑に見えるので、宣言側で工夫して省略できるようにした。
また、とりあえず「シンプルに見えて動くコード」にしたかったので左ボタンだけなら直接Longのリテラルで良いかと思い、定数にはしなかった。
「&H」から始まる数字は16進数であるが、2と4は10進数でも16進数でも同じなので省略した。
※&H10は十進数の16である。

ちなみに右クリックのコードは押下が8(または&H8)、解放が16(または&H10)である。

VBAで他アプリを操作する際に、オブジェクトの直接操作ができればそれに越したことはないが、そもそも外部から操作される前提で作成されていないアプリもあるので、そのようなケースではキーボード操作やマウス操作をVBAでエミュレートするしかない。

実際には解像度やタスクバーの配置などのPC環境によってウインドウが表示される位置は異なるため、マウス操作を行うマクロを広く配布するつもりならそのあたりの解消も必要かと思う。(マクロを使う場合の設定を統一してもらうか、また別のAPIで設定を取得してマクロ側で調整をかけるか等。)

出来ればこういう不安定な手段に頼りたくはないが、最終手段としてこうしたテクニックを覚えておくと作れるものの幅が広がって良いと思う。

今回のマクロではWin32APIを使用して(つまりWindows OSの力を借りて)マウス移動とクリックを実現している。
Windows APIを使うとVBA単体では実現できない色々な操作ができるようになる。
詳しく学びたい方はこちらの書籍がオススメ。

大村あつし の Excel VBA  Win64/32 APIプログラミング

大村あつし の Excel VBA Win64/32 APIプログラミング

2018/1/3 追記

Twitterで、難しすぎるーという声があったので追記。
このブログでは中・上級者のためにあえて詳細を解説しているけれど、基本的に他人が作ったFunctionは単に使い方さえ分かればOK。

ということで、改めて使い方に絞って説明。
今回は右クリック、左クリックそれぞれマクロ化した。

まず以下は「おまじない」なので、深く考えずに単に標準モジュールに張り付ける。

Private Type Position
    x As Long
    y As Long
End Type
Declare Function SetCursorPos Lib "User32" (ByVal x As Long, ByVal y As Long) As Long
Declare Sub mouse_event Lib "User32" ( _
    ByVal dwFlags As Long, _
    Optional ByVal dx As Long = 0, _
    Optional ByVal dy As Long = 0, _
    Optional ByVal dwDate As Long = 0, _
    Optional ByVal dwExtraInfo As Long = 0)
Declare Function GetCursorPos Lib "User32" _
    (lpPoint As Position) As Long
Sub LeftClick()
    mouse_event 2
    mouse_event 4
End Sub
Sub RightClick()
    mouse_event 8
    mouse_event 16
End Sub

次にクリックしたい場所の座標を調べる必要がある。
以下を標準モジュールに貼り付けて、コード入力のテキストカーソルを合わせておく。

Sub 座標を調べる()
    Dim pos As Position
    Call GetCursorPos(pos)
    Debug.Print pos.x, pos.y
    MsgBox pos.x & ", " & pos.y
End Sub

下図のようにテキスト入力のカーソルさえあれば、マウスカーソルがどこにあってもF5で実行できる。
f:id:t-hom:20180103180015p:plain

そして任意の場所にマウスを持っていき、F5で実行する。
するとメッセージボックスに数字が2つ出力されるので、控えておく。これが現在のマウスカーソルの座標である。

この座標を調べるマクロは、調べるためだけのマクロなので調べ終わったら削除してもOK。

そして以下のマクロのSetCursorPosに控えておいた座標を入力して実行。

Sub マウスで画面の任意の位置をクリック()
    SetCursorPos 1469, 408  '調べておいた座標を入力
    LeftClick
End Sub

これでその座標が左クリックされる。

右クリックしたいときは、LeftClickの代わりにRightClickと書くだけ。

以上。

当ブログは、amazon.co.jpを宣伝しリンクすることによってサイトが紹介料を獲得できる手段を提供することを目的に設定されたアフィリエイト宣伝プログラムである、 Amazonアソシエイト・プログラムの参加者です。