GetAsyncKeyState vs WM_KEY どっち使うの?
はじめに
Windowsでゲーム制作をする際のキ―ボード入力はどうするのか?というお話です。WindowsAPIにはキー入力を検知する手段が複数用意されていますが、どれを使えばよいのかいまいち理解しずらいと思ったので、個人的な意見ですがまとめてみました。
キー入力を検知する手段
私の知る限り、WindowsAPIには以下の4種類の方法があります。
GetKeyboardState
BYTE(unsigned char)[256]
型の配列にキーボードの情報を一括で格納する関数
対応する要素(キー)の値の最上位ビットが1であればキーが押されている、それ以外なら押されていないという判定になります。BYTE
型なので、0x80
でビットマスクをする
BYTE keyState[256] = {};
GetKeyboardState(keyState));
if( keyState[VK_ESCAPE] & 0x80 )
{
// escキーが押されている
}
GetKeyState
GetKeyboardState
がキーボード全体だったのに対して、こちらはキー1つのみを調べたい場合に使います。同様に最上位ビットが1ならキーが押されている、そうでなければ押されていないという判定になりますが、戻り値がSHORT
型なのでビットマスクが0x8000
になる
if (GetKeyState(VK_ESCAPE) & 0x8000)
{
// escキーが押されている
}
GetAsyncKeyState
基本的にはGetKeyState
と同じです。異なるのは戻り値のビットに違いがあり、最上位ビットの押下判定に加えて最下位ビットが1であれば、最後にこの関数の呼び出した時からこの関数呼び出しの間にキーが押下されたという判定になる。
if (GetAsyncKeyState(VK_ESCAPE) & 0x8000)
{
// escキーが押されている
}
if (GetAsyncKeyState(VK_ESCAPE) & 0x0001)
{
// escキーが以前に押されたことがある
}
WM_KEYDOWN / WM_KEYUP
キーが押された瞬間 / キーが離された瞬間に起きるイベント。wParam
には入力されたキーコードが、lParam
にはキーの状態が格納される。lParam
の30ビット目のフラグがたっていれば繰り返し入力がされています。
int64 CALLBACK WndProc(HWND hWnd, uint32 uMsg, uint64 wParam, int64 lParam)
{
switch (uMsg)
{
case WM_KEYDOWN:
{
// キーが押された
switch (wParam)
{
case VK_ESCAPE: ...; // escキー
case VK_RETURN: ...; // enterキー
}
}
case WM_UP:
{
// キーが離された
}
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
// 文字コード
const int32 keyCode = wParam;
// 30ビット目が1ならリピート入力
bool bIsRepeat = ( lParam & 0x40000000 ) != 0;
評価
GetKeyState / GetKeyboardState
関数なのでポーリング(一定間隔でチェックすること)が必要でGetKeyState
やGetAsyncKeyState
はキー単体の入力を調べるのには向いている。複数のキーを使うのであれば、1度に全てのキーを取得するとこができるGetKeyboardState
も便利。ただし、入力クラスなどの全てのキー(256
個)の状態の取得が求められる場合はGetKeyboardState
を使うべきです。60fps
でポーリングする場合GetKeyboardState
は60
回、GetAsyncKeyState
は15,360
回の呼び出しが必要にまります。
WM_KEYDOWN / WM_KEYUP
ウィンドウメッセージで入力を取得する場合はGetKeyState
/ GetKeyboardState
とは異なり、ウィンドウメッセージのコールバックを処理するだけで良い。入力クラスなど、全てのキーの状態の取得が求められる場合でもポーリングが必要ないのでパフォーマンスに優れている。
まとめ
ポーリングしなくても良いというパフォーマンスの点からウィンドウメッセージでキー入力を取得することをオススメします。キー配列を2つ(現在と前回の入力を)用意すれば、毎フレームキー配列をクリアしながらメッセージが発行されたタイミングでキーの状態を上書きするだけで、簡易的なキーボードクラスが実装できます。
-
WM_INPUT
様々なデバイスのデータにアクセスできるなど扱いの範囲が大きいので今回は範囲外とした。
高解像度マウスなどの対応に使われる。 ↩︎ -
DirectInput
Microsoftが非推奨としているので除外 ↩︎
Discussion