キーボードイベントの利用

前々回の続きで今回はキーボードイベントを試してみましょう。

グラフィックスウィンドーでキーボードが押された時と離された時にイベントを発生させることができる。キーボードを押した歳のイベントは GraphicsWindow.KeyDown 、キーボードが離された際のイベントはGraphicsWindow.KeyUp でイベントハンドラを割り当てます。

この二つのイベントはどのように使い分けるのでしょうか?

実はGraphicsWindow.KeyDown イベントはキーボードのキーを押したときだけではなく、例えばそのキーを押しっぱなしにしていると定期的にイベントが発生します。ちょっと何の事を言っているか分かりにくいですよね。サンプルプログラムを見てください。

wWidth  = 800
wHeight = 800
cursize = 40
x = wWidth /2  - cursize /2
y = wHeight /2 - cursize /2
GraphicsWindow.Width  = wWidth
GraphicsWindow.Height = wHeight
cur = Shapes.AddEllipse(cursize,cursize)
Shapes.Move(cur, x, y)

GraphicsWindow.Show()
GraphicsWindow.KeyDown = OnKeyDown

Sub OnKeyDown
  If GraphicsWindow.LastKey = "H" Then
    x = x - 10
  ElseIf GraphicsWindow.LastKey = "L" Then
    x = x + 10
  ElseIf GraphicsWindow.LastKey = "J" Then
    y = y + 10
  ElseIf GraphicsWindow.LastKey = "K" Then
    y = y - 10
  EndIf
  Shapes.Animate(cur, x, y, 5)
EndSub

グラフィックスウィンドーが開くと真中に青い円が現れます。キーボードの"h", "j", "l", "k" を押すと青い円が上下左右に移動します。

プログラムを見てみましょう。GraphicsWindow.KeyDown イベントにサブルーチンOnKeyDownを割り当てているのは前々回の説明の流れなので分かると思います。サブルーチンOnKeyDown の中でGraphicsWindow.LastKeyというプロパティをチェックしています。このプロパティはもっとも最近に押されたキーを保持しています。つまり、例えばキーボードから「a」のキーを押すとこのプロパティには"A"という文字が入ります。小文字の「a」を押しても、大文字の「A」を押しても"A"という文字が入ることに気を付けてください。ついでに言うと、「Ctrl-A」を押した場合にも"A"が入ります。

ところで、Windowsの場合キーボードのあるキーを押しっぱなしにした場合、最初の文字が入力されてからほんの少し(0.5秒くらい?)だけまってからその文字が連続されて入力されますよね。「メモ帳」で試してみてください。この仕組みをキーリピートと呼んだりします。

キーを押しっぱなしにした場合、GraphicsWindow.KeyDown で発生するキーボードイベントもこの仕組みのもとで連続した複数のイベントを発生させます。

さて、キーボードイベントにはGraphicsWindow.KeyUp というキーを話した時に発生するイベントもあります。先ほどのサンプルプログラムの12行目の GraphicsWindow.KeyDown を GraphicsWindow.KeyUp に変更してみましょう。プログラムを実行するとどうなるでしょうか。先ほどと同様にキーボードの hjkl キーで青い円が移動しますが、先ほどと違い、キーを押しっぱなしにしても円は一度しか動きません。円を動かすためにはキーをポンポンと押したり離したりする度に円が移動します。GraphicsWindow.KeyUp イベントは実際にキーを話した際にだけ発生することに注意してください。

このあたりの動きがGraphicsWindow.KeyDown と GraphicsWindow.KeyUp イベントの違いです。

ところで補足です。通常の文字以外のキーが押された場合はどうなるのでしょうか。

キー LastKey キー LastKey キー LastKey キー LastKey
F1〜F12 "F1",..,"F12" Tab "Tab" 左側Shift "LeftShift" 左側Ctrl "LeftCtrl"
左側Windowsキー "LWin" Alt "System" スペース "Space" 無変換 "ImeNonConvert"
1〜0 "D1",..,"D0" - "OemMinus" ^ "OemQuotes" \ "Oem5"
[ "OemOpenBlackets" ] "Oem6" + "OemPlus" "Oem1"
, "OemComma" . "OemPeriod" / "OemQuestion" \(_) "OemBackslash"
"Left" "Right" "Up" "Down"
PgDown "Next" PgUp "PageUp" Home "Home" アプリケーションキー "Apps"
右側Ctrl "RightCtrl" 右側Shift "RightShift" Enter "Return" Scroll Lock "Scroll"
Backspace "Back" Del "Delete" Ins "Insert" Pause "Pause"

ところで、今回のプログラムを実行して青い丸を動かし続けると画面の外に出てしまいます。青い丸が外に出ないようにするには画面の(座標の)境界を調べて、境界に青い丸が来た場合にはそれ以上移動しないようにすればよいでしょう。

wWidth  = 800
wHeight = 800
cursize = 40
x = wWidth /2  - cursize /2
y = wHeight /2 - cursize /2
GraphicsWindow.Width  = wWidth
GraphicsWindow.Height = wHeight
cur = Shapes.AddEllipse(cursize,cursize)
Shapes.Move(cur, x, y)

GraphicsWindow.Show()
GraphicsWindow.KeyDown = OnKeyDown

Sub OnKeyDown
  If GraphicsWindow.LastKey = "H" Then
    x = x - 10
    If x < 0 Then
      x = 0
    EndIf
  ElseIf GraphicsWindow.LastKey = "L" Then
    x = x + 10
    If x > wWidth - cursize then
      x = wWidth - cursize
    EndIf
  ElseIf GraphicsWindow.LastKey = "J" Then
    y = y + 10
    If y > wHeight - cursize then
      y = wHeight - cursize
    EndIf
  ElseIf GraphicsWindow.LastKey = "K" Then
    y = y - 10
    If y < 0 then
      y = 0
    EndIf
  EndIf
  Shapes.Animate(cur, x, y, 5)
EndSub