VBA の SendKeys で NumLock がオフになるときの対処法

表計算とコードエディタの画面、テンキーと歯車のイラスト Excel・VBA

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 は、実行中に別のウィンドウが前に出てくると、そちらにキー入力が送られてしまうという弱点もあります。業務で使うマクロでは、できるだけ対処1の方法をおすすめします。

まとめ

SendKeys で NumLock がオフになるのは、SendKeys の仕組み上起こりうる症状です。まずは SendKeys を使わない書き方に置き換えられないか考えて、どうしても必要なときだけ NumLock を戻す処理を足しましょう。

コメント

タイトルとURLをコピーしました