WshScriptのSendKeysメソッドを使う

ち~んw珍現象は続く

WshScriptのSendKeysメソッド

前回の

akashi-keirin.hatenablog.com

コチラの記事にid:imihito さんからコメントをいただいた。

そこでご紹介いただいたのは、コチラの方法。このうち、「WshShellのSendKeysをラップする」というやつを使わせていただくことにした。

要するに、バグがあることが分かっている方法を使うのを避けて、同じような機能を持つバグのないメソッドを使おうということ。極めて健全な対処法だと思う。

面白いなと思ったのが、

毎回CreateObjectすると負荷が大きくなるので、Static宣言+存在判定をしています。

という考え方。なるほど。Static変数をそういうふうに使うのか! VBAのStatic変数って、プロシージャ内でしか使えなくて、イマイチ使いどころが分からなかったんだよな。クラス変数みたいに使えたらいいのに。

ただ、ちょっと気になる記述が。

代わりにオブジェクトを破棄する方法が無くなるので、wshShellオブジェクトがメモリに残り続けます。

むむむ。イマイチVBAガベージコレクションの動作がよく分からないし、素人の悲しさ、メモリ関係もよく分かっとらんので、あまり気にしたこともないのだが、こうはっきり書いてあると、「メモリに残り続けるってのもマズいのかなあ」とかビビってしまう。

まあ、オブジェクトの破棄については、素人の浅知恵を後ほど披露するとして、ちょっとやってみた。

WshScriptのSendKeysメソッド呼び出し用プロシージャ

コチラのコードをちょっとだけ改造する。

リスト1 標準モジュール
Public Sub callWshScriptSendKeys(ByVal wsKeys As String, _
                                 Optional ByVal wsWait As Boolean, _
                                 Optional ByVal isFinal As Boolean)    '……(1)'
  Static objWshShell As Object
  If isFinal Then Set objWshShell = Nothing: Exit Sub    '……(2)'
  If objWshShell Is Nothing Then Set objWshShell = CreateObject("Wscript.Shell")
  Call objWshShell.SendKeys(wsKeys, wsWait)
End Sub

元のコードに付け加えたのは(1)の引数リストと(2)のコードだけ。

(1)の

Public Sub callWshScriptSendKeys(ByVal wsKeys As String, _
                                 Optional ByVal wsWait As Boolean, _
                                 Optional ByVal isFinal As Boolean)

では、省略可能な第3引数isFinalを設定している。

(2)の

If isFinal Then Set objWshShell = Nothing: Exit Sub

では、第3引数のisFinalがTrueだったら、objWshShellをNothingにしてそのままプロシージャを抜けるようにした。

全体の処理の最後に、第3引数isFinalをTrueにしてこのプロシージャを呼び出すことで、オブジェクトを破棄できると考えた。これが、素人の浅知恵の部分w

まあ、そのために第1引数wsKeysにアテ馬のように文字列を与えないと呼び出せない(もちろん、""でいいんだけれど)ので、ブサイクといえばブサイクですけどw

SendKeysメソッド呼び出し回りの改造

VBAのApplication.SendKeysメソッドの使用をやめ、全面的にWshScriptのSendKeysメソッドに置き換える。

具体的には、

akashi-keirin.hatenablog.com

このときのリスト1を、リスト1で作成したプロシージャを呼び出す形に書き換える。

スト2 標準モジュール
Public Sub cutText()
  Call callWshScriptSendKeys("^X")
  DoEvents
End Sub
Public Sub copyText()
  Call callWshScriptSendKeys("^C")
  DoEvents
End Sub
Public Sub pasteText()
  Call callWshScriptSendKeys("^V")
  DoEvents
End Sub
Public Sub selectAll()
  Call callWshScriptSendKeys("^A")
  DoEvents
End Sub

これで準備万端のはず。

実行結果

f:id:akashi_keirin:20180104165843j:plain

伝わりにくいと思いますが、NumLockがオンになっているので、数字の入力ができることを表現した画像ですw

この状態で、

f:id:akashi_keirin:20180104165850j:plain

右クリックして、「貼り付け」をクリック。

f:id:akashi_keirin:20180104165901j:plain

おおっ! 無事に貼り付けできたぞ!

f:id:akashi_keirin:20180104165914j:plain

今度は、「全て選択」だっ!

f:id:akashi_keirin:20180104165927j:plain

ガッ……!?

ど、どういうことやねん???

今度は「切り取り」をクリック!

f:id:akashi_keirin:20180104165942j:plain

ガッ……!?

な、何が起こっているんだーーーーッ!?

んで、気色悪いのが、

OSDにNumLockオン、オフの表示が出るのが不規則

だということ。右クリックメニューを使ったときに、出たり出なかったりする。んで、「NUM LOCK OFF」ばっかり連続で出るかと思ったら、急に「NUM LOCK ON」に変わったり、わけが分からない。

で、途方に暮れかけているときに気づいたのが、

OSDのオン、オフ表示に関係なく、NumLockの状態は変化していない

という、さらにわけの分からない事実

f:id:akashi_keirin:20180104165956j:plain

OSDに「NUM LOCK OFF」と表示された後でも、こんなふうに普通にテンキーで数字が入力できる。

私のノートPCに限った現象だと思う(デスクトップはキーボードのLEDの点灯でNumLockの状態を知らせる仕組み)けれど、気色悪いなあ。

おわりに

id:imihito さん、ありがとうございました。

@akashi_keirin on Twitter