情シス担当の備忘録

VBA・労働法とか。

【ExcelVBA】手作りRPAで使う「keybd_event」についての追記(MapVirtualKey関数がわかったようでわからない)

以前、「【ExcelVBA】keybd_eventをつかってCitrix経由で起動しているアプリにキー入力を送る。(手作りRPA)」という記事を書きました。

cha-hanman.hatenablog.com

この記事の中で「keybd_event」という関数を使ってRPAを手作りしたわけですが、この記事を書いた当時はこの関数のことをよくわかっていませんでした。
いや、今もよくわかっていませんが、当時よりわかってきた気がするので追記します。

「keybd_event」には引数が4つあります。
①「bVk」には仮想キーコードを設定します。
②「bScan」にはスキャンコードを設定します。
(設定しなくても大丈夫という意見もありますが、私の環境では設定しないと動きませんでした)
③「dwFlags」は、メイクコードを送る際には0を設定しますが、ブレイクコードを設定する際には「&H2」を設定します。
④「dwExtraInfo」は使いません。
(まだ勉強不足です。使うときはあるのでしょうか。)

当時の記事の中では「keybd_event」のために「仮想キーコード」と「スキャンコード」の両方を調べなければならないと書きました。
しかし、これがぶっちゃけかなり面倒です。特に「スキャンコード」は環境によって違うようなので、自分の環境に合ったスキャンコードを調べる必要がありました。
しかし、「MapVirtualKey」関数を使うことで「スキャンコード」を調べる手間を減らせるのではないかと思います。

「MapVirtualKey」については以下のページが参考になりました。いくつか機能がありますが、RPAを作るうえでは仮想キーコードをスキャンコードに変換してくれる機能が役に立ちます。
www.tokovalue.jp

「MapVirtualKey」には引数が二つあります。
「wCode」と「wMapType」です。
「wCode」には仮想キーコードを設定します。
「wMapType」には使用したい機能ごとに値を設定します。
仮想キーコードをスキャンコードに変換したい場合は「0」を設定します。

これらの情報をもとに、「keybd_event」を「MapVirtualKey」を活用しながら使うと以下のようになります。

Private Declare PtrSafe Sub keybd_event Lib "user32" _
(ByVal bVk As Byte, ByVal bScan As Byte, ByVal dwFlags As Long, ByVal dwExtraInfo As Long)
Private Declare PtrSafe Function MapVirtualKey Lib "user32" _
Alias "MapVirtualKeyA" (ByVal wCode As Long, ByVal wMapType As Long) As Long

Dim wsh As Object

Set wsh = CreateObject("Wscript.shell")
    wsh.AppActivate "新規 Microsoft Excel ワークシート.xlsm"

Range("A1").Select
keybd_event 65, MapVirtualKey(65, 0), 0, 0
'keybd_event 65, MapVirtualKey(vbKeyA, 0), 0, 0 でも可
Set wsh = Nothing

End Sub


このようにすることで、A1セルにアルファベット小文字のaを入力できます。

では、例えば以下のようにしたら「ctrl+A」と「ctrl+V」を再現してコピペができるかと思ったのですが、動きませんでした・・・。

Private Declare PtrSafe Sub keybd_event Lib "user32" _
(ByVal bVk As Byte, ByVal bScan As Byte, ByVal dwFlags As Long, ByVal dwExtraInfo As Long)
Private Declare PtrSafe Function MapVirtualKey Lib "user32" _
Alias "MapVirtualKeyA" (ByVal wCode As Long, ByVal wMapType As Long) As Long
Dim wsh As Object

Set wsh = CreateObject("Wscript.shell")
    wsh.AppActivate "新規 Microsoft Excel ワークシート.xlsm"
    
Call コピー
Call ペースト

Set wsh = Nothing

End Sub

Private Sub コピー()

Range("A1").Select
keybd_event &H11, MapVirtualKey(&H11, 0), 0, 0
keybd_event 67, MapVirtualKey(67, 0), 0, 0
keybd_event 67, MapVirtualKey(67, 0), &H2, 0
keybd_event &H11, MapVirtualKey(&H11, 0), &H2, 0

End Sub


Private Sub ペースト()

Range("A2").Select
Application.Wait [Now() + TimeValue("00:00:00.5")]
 
Call keybd_event(&H11, MapVirtualKey(&H11, 0), 0, 0)
Call keybd_event(86, MapVirtualKey(86, 0), 0, 0)
Call keybd_event(86, MapVirtualKey(86, 0), &H2, 0)
Call keybd_event(&H11, MapVirtualKey(&H11, 0), &H2, 0)

End Sub


原因は勉強中です。
sub「コピー」を呼び出した後の「keybd_event 67, MapVirtualKey(67, 0), &H2, 0」で何故か処理が終了してしまうんですよね。

ここがクリアできれば、手作りRPAを作るのがもっと楽になります(スキャンコードを調べる手間がなくなるので)。
そしたら、手作りRPAのメンテナンスとかが楽になって、ウチの会社の他の課の人とかにも使って貰いやすくなるなぁ・・・。

なんて、そもそもVBAを使える人も勉強する人も全然いない弊社では広めていくのは難しいんですがね・・・。