Excel や Access の VBA で SendKeys を使うと、なぜか NumLock(テンキーのロック)がオフになってしまう。数字を打とうとしたら矢印キーとして動いて困る――。VBA を書いている人の間では昔から知られている症状です。
症状
- マクロの中で
SendKeysを実行すると、NumLock のランプが消える - テンキーで数字が入力できなくなる
- 毎回ではなく、実行するたびにオンとオフが入れ替わることもある
原因
SendKeys は、キーボードを押したことにして Windows にキー入力を送る仕組みです。このとき NumLock の状態がうまく扱われず、オン・オフが切り替わってしまうことがあります。Microsoft の環境やバージョンによって起きたり起きなかったりするので、「SendKeys を使う限り起こりうる」と考えておくのが安全です。
対処1:SendKeys を使わずに済む方法に置き換える(おすすめ)
いちばん確実なのは、SendKeys を使わないことです。SendKeys でやりたいことの多くは、VBA の命令で直接書けます。たとえば Access で「検索」ダイアログを出したいだけなら、次のように書けます。
Me.ACCOUNT.SetFocus
DoCmd.RunCommand acCmdFind
Excel なら、セルの移動は Range("A1").Select、コピーは Range("A1").Copy のように、操作そのものを命令で書けます。「キー操作をまねる」のではなく「やりたいことを直接書く」と考えると、置き換え先が見つかりやすいです。
対処2:SendKeys のあとで NumLock を戻す
どうしても SendKeys が必要な場合は、実行後に NumLock がオフになっていたら戻す、という処理を足す方法があります。
#If VBA7 Then
Private Declare PtrSafe Function GetKeyState Lib "user32" (ByVal nVirtKey As Long) As Integer
#Else
Private Declare Function GetKeyState Lib "user32" (ByVal nVirtKey As Long) As Integer
#End If
Private Const VK_NUMLOCK As Long = &H90
Sub SendKeysKeepNumLock(ByVal keys As String)
Dim wasOn As Boolean
wasOn = (GetKeyState(VK_NUMLOCK) And 1) <> 0
SendKeys keys, True
If wasOn And (GetKeyState(VK_NUMLOCK) And 1) = 0 Then
SendKeys "{NUMLOCK}", True
End If
End Sub
使うときは SendKeysKeepNumLock "^f" のように、SendKeys の代わりに呼び出します。SendKeys でもう一度 NumLock を押し直しているので、環境によってはうまく戻らないこともあります。あくまで応急処置と考えてください。
まとめ
SendKeys で NumLock がオフになるのは、SendKeys の仕組み上起こりうる症状です。まずは SendKeys を使わない書き方に置き換えられないか考えて、どうしても必要なときだけ NumLock を戻す処理を足しましょう。


コメント