ホーム‎ > ‎私の開発環境‎ > ‎

イベントでプログラムを制御しよう!

http://home.att.ne.jp/zeta/gen/excel/c04p07.htm


■ マウスやキーボードのイベントを取得する

業務用アプリケーションのプログラムとゲームプログラムの一番大きな違いはなんでしょう?

一般的に業務用アプリケーションの場合、一つの処理が始まるとその処理が終わるまでユーザーに制御が返りません。
たとえば入力値をチェックする処理ならば、ユーザーの入力が終わった時点で処理が始まり、入力値が正しければ次のコントロールへカーソルを移し、正しくないときはアラートを出してユーザーに修正を促します。

ゲームコントロールの場合、ゲームが開始されてから終了するまでの間、プログラムはずっと実行されています。
ユーザーに制御が返りませんので、プログラムはユーザーのアクションを何らかの方法で取得しなければなりません。
図で描くとこのような感じになります。


ではいったいどうすればユーザーは実行中のプログラムを外部から制御できるのでしょう?
API関数の中に、まさにうってつけの関数がありますので今回はその使い方をご紹介します。
さっそくコードを見てまいりましょう。

' モジュール宣言部に記述ここから −−−−−−−−−−−−−−−−−−−−−−−−−−
Public Declare Function GetAsyncKeyState Lib "User32.dll" ( _
                ByVal vKey As Long _
                ) As Long
Public Const VK_LBUTTON = &H1 '[LeftClick]
Public Const VK_RBUTTON = &H2 '[RightClick]
Public Const VK_SPACE = &H20 '[Space]
Public Const VK_LEFT = &H25 '[←]
Public Const VK_UP = &H26 '[↑]
Public Const VK_RIGHT = &H27 '[→]
Public Const VK_DOWN = &H28 '[↓]
Public Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
' モジュール宣言部に記述ここまで −−−−−−−−−−−−−−−−−−−−−−−−−−

Public Sub test()
  Do
    If GetAsyncKeyState(VK_LEFT) <> 0 Then
      Debug.Print "←"
    ElseIf GetAsyncKeyState(VK_UP) <> 0 Then
      Debug.Print "↑"
    ElseIf GetAsyncKeyState(VK_RIGHT) Then
      Debug.Print "→"
    ElseIf GetAsyncKeyState(VK_DOWN) Then
      Debug.Print "↓"
    Else
      Debug.Print "*"
    End If
    Call Sleep(500)
  Loop Until GetAsyncKeyState(VK_LBUTTON)
End Sub

このプログラムは一度実行されると、マウスの左クリックイベントを取得するまでループを続けます。
イベントを取得しているのは、API関数のGetAsyncKeyStateです。
この関数の便利な所は、キーボードのイベントを取得するだけでなく、マウスのクリック状態も取得できるところです。
プログラムが実行されると、イミディエイトウィンドウに"*"が出力され続けます。
これは、どのキーも押されていない状態のとき、IF文の最後のelseが実行されているからです。
Sleep関数でインターバルを入れているのはユーザーからの制御を受け付けるのに適当なウェイトがあったほうが都合がいいからです。この値を増やしたり減らしたりして、どのように制御の受け付けが変化するかを確かめてください。

キーボードの矢印キーを上下左右にいろいろと押してみてください。
GetAsyncKeyState(VK_LEFT) <> 0 の部分でキーが押されているかどうかを判定しています。正確にはGetAsyncKeyStateの戻り値には最上位ビットと最下位ビットをセットして戻 しますので、現在キーが押されているかどうかまで知ることができます。
このサンプルでは押されたかどうかだけの判定なので、矢印キーのどれかが押され0以外の値が戻ったらイミディエイトに押された矢印キーをあらわす文字列を出力しています。

※ If GetAsyncKeyState(VK_RIGHT) Then と記述した場合、False=0以外のどの値でもTrueと判定されます。つまり、If GetAsyncKeyState(VK_RIGHT) <> 0 Then と記述したことと同じになります。

動きを一通り確認したらマウスを左クリックしてください。プログラムが終了します。
(このプログラムはVBEから実行します)

GetAsyncKeyStateの戻り値ですが、少し詳しく書くと16ビットの整数値が返されます、
・呼び出した時に押されている:16ビットの最上位ビットが1(&H8000) 
・前回呼び出し後に押されている:16ビットの最下位ビットが1(&H1) 
・押されていない:0
のいずれかが返ります。

これをうまく使うと、どのくらいキーが押されていたかでプログラムを細かく制御することが可能です。
もうひとつサンプルを記述してみましょう。

Public Sub test2()
Dim MyKeyState As Long
  Do
    MyKeyState = GetAsyncKeyState(VK_SPACE)
    If MyKeyState And &H8000 Then
      Debug.Print "現在押されている"
    ElseIf MyKeyState And &H1 Then
      Debug.Print "前回押されている"
    Else
      Debug.Print "押されていない"
    End If
    Call Sleep(500)
  Loop Until GetAsyncKeyState(VK_LBUTTON)
End Sub

このサンプルではスペースキーが押されている状態にあるのか、押されていたけど離したのか、細かく取得することができます。
先ほど同様、VBEから実行してください。

実行すると"押されてない"がイミディエイトに出力され続けます。
スペースを押した時点で MyKeyStateに戻り値が返りますので最上位ビットの1を調べるには&H8000との論理積を判定します。
イミディエイトには"現在押されている"が出力され続けます。
スペースキーを離した時点でMyKeyStateに最下位ビットの1が返されますので&H1との論理積を判定してやります。
イミディエイトには"前回押されている"が一度出力されます。
次のループではMyKeyStateは0を返しますので再びスペースキーが押されるまで"押されていない"を出力し続けます。

※ ビット演算についてはこちらを参照してください。 演算子について詳しく知ろう!

よくあるシューティングゲームの"タメ"などはこの方法で簡単に実現できます。

また業務用アプリへの応用ですが、長時間に及ぶバッチ処理などの場合、終了するまでユーザーからの制御を全く受け付けなくなってしまうという問題をこれで回避できます。

キーイベントからプログラムを実行する

さて、これとは逆にあるキーが押された時にプログラムを実行するにはどうすればよいのでしょう?
Excelには大変便利な、Application.OnKey メソッドが用意されています。

使い方はいろいろありますが、WorkbookのOpenイベントに記述すると便利です。

' ワークブックモジュールに記述ここから −−−−−−−−−−−−−−−−−−−−−−−
Private Sub Workbook_Open()
  Application.OnKey "{F1}", "UserFunction1"
  Application.OnKey "{F2}", "UserFunction2"
  Application.OnKey "{F3}", "UserFunction3"
  Application.OnKey "{F4}", "UserFunction4"
  Application.OnKey "{F5}", "UserFunction5"
End Sub
' ワークブックモジュールに記述ここまで −−−−−−−−−−−−−−−−−−−−−−−

この場合、ブックの起動時にファンクションキーのF1〜F5にUserFunction1〜5という名前のユーザー関数(プロシージャ)が割り当てられます。割り当てられるキーは様々で、
 {UP} 
→   {RIGHT} 
 {DOWN} 
 {LEFT} 
BackSpace  {BACKSPACE} 
CapsLock  {CAPSLOCK} 
Clear  {CLEAR} 
Ctrl + Break  {BREAK} 
Delete  {DELETE} 
End   {END} 
Enter  {ENTER} 
Esc  {ESCAPE}
F1 〜 F15  {F1} から {F15} 
Help  {HELP} 
Home  {HOME} 
Ins  {INSERT} 
NumLock  {NUMLOCK} 
PageDown  {PGDN} 
PageUp  {PGUP} 
Return  {RETURN} 
ScrollLock  {SCROLLLOCK} 
Tab  {TAB} 
この他にも文字キーやAlt、Ctrl、Shiftと組み合わせて使用することもできます。
詳しくはExcelのヘルプ、OnKeyメソッドを参照してください。

Comments