web-dev-qa-db-ja.com

Win32でキーの押下とキーの保持を決定する最も速い方法は何ですか?

キーが押されているかどうかを判断する最も速い方法と、キーが押されているかどうかを判断する方法は何ですか?ウィンドウメッセージングが遅いようです。その方法の例と、それが他の方法よりも速い理由を教えてください。

明確にするために、これはリアルタイムループ(シミュレーション)であるため、キーが押されたかどうかを判断し、キーが押されているかどうかを確認するための最速の方法を探しています。

11
judeclarke

GetAsyncKeyState() はあなたが探しているものです。入力キューの状態に関係なく、キーボードの物理的な状態を読み取ります。ハイビットが設定されている場合は、呼び出し時にキーが押されていました。

// Fetch tab key state.
SHORT tabKeyState = GetAsyncKeyState( VK_TAB );

// Test high bit - if set, key was down when GetAsyncKeyState was called.
if( ( 1 << 15 ) & tabKeyState )
{
    // TAB key down... 
}

また、記録として、Windowsはリアルタイムオペレーティングシステムではありません。アプリケーションでリアルタイムの精度が必要な場合は、別のプラットフォームを選択することをお勧めします。

24
Bukes

キーボードの状態をポーリングして、どのキーが上下しているかを確認したい場合は、 shift/alt/ctrl 状態、GetKeyboardStateMSDNリファレンス )を呼び出すだけです。

私がゲームスタジオで働いていたとき、これはまさに各フレームのキーボードの状態を取得する方法です。シミュレーションコードに適用できるはずです。

6
selbie

TL; DR:GetAsyncKeyStateを使用して、キーが現在ダウンしているかどうかを確認できますが、キーの押下と解放に対するアプリケーションの応答性を最大限に高めるには、投稿の下部にあるWin32パイプラインコードを使用したい。

GetAsyncKeyState キーが現在ダウンしているかどうかを判断するのに完全に正常に機能しますが、キーが最初に押されたかどうかを判断するという点ではリリースおよびこれが行われた回数、GetAsyncKeyStateは、前のキー状態を保存した後でも、CPUを集中的に使用するアプリケーションでキーストロークを見逃します。

これは私が試したものでした:

static const unsigned int NumberOfKeys = 256U;

bool previousKeyboardState[NumberOfKeys];

//Get the current state of each key as the application starts to ensure that keys held down beforehand are not processed as pressed keys.
for (unsigned int keyNum = 0U; keyNum < NumberOfKeys; ++keyNum)
{
    previousKeyboardState[keyNum] = isKeyDown(keyNum);
}

//Works fine.
bool isKeyDown(int key)
{
    return (GetAsyncKeyState(key) & (1 << 16));
}

//Misses key presses when application is bogged down.
bool isKeyFirstPressed(int key)
{
    bool previousState = previousKeyboardState[key];

    previousKeyboardState[key] = isKeyDown(key);

    return (previousKeyboardState[key] && !previousState);
}

//Misses key releases when application is bogged down.
bool isKeyFirstReleased(int key)
{
    bool previousState = previousKeyboardState[key];

    previousKeyboardState[key] = isKeyDown(key);

    return (!previousKeyboardState[key] && previousState);
}


//Example usage:

if (isKeyDown(VK_W))
{
    //W key.
}

if (isKeyFirstReleased(VK_SNAPSHOT))
{
    //Print screen.
}

GetKeyboardStateは、キーの押下またはリリースの数を追跡しないため、適切ではありません。エリックフィリップスが彼の答えで言ったように、これらはバッファリングされていないソリューションであり、あなたが例えばゲームを書く。すべてのキーストロークを、受信するよりも速く処理する必要があります。

さて、上記の私のコードはきちんと機能し、多くの人に適しているかもしれませんが、私は1回のキーストロークを見逃したくないのです。私は応答しないアプリケーションを使用するのが嫌いです。 Win32アプリケーションの最善の解決策は、パイプラインで WM_KEYDOWN および WM_KEYUP メッセージをキャッチして処理することだと思います。すばらしいのは、WM_KEYDOWNが自動リピートカウントも提供することです。これは、テキストの入力をサポートするアプリケーション(チャット、IDEなど)に役立つ可能性があります。これにより、WM_KEYDOWNのドキュメントに記載されているわずかな問題も追加されます。

自動リピート機能により、WM_KEYUPメッセージが投稿される前に複数のWM_KEYDOWNメッセージが投稿される場合があります。前のキー状態(ビット30)を使用して、WM_KEYDOWNメッセージが最初のダウン遷移を示しているのか、繰り返しダウン遷移を示しているのかを判別できます。

調べることができるWindowsキーボードフックもありますが、それらは使用するのがより困難です。ただし、グローバルなキー押下を受信するのに適しています。

3
Andrew

すべてのWindows間通信がWindowsメッセージング(キーボードイベント、マウスイベント、想像できるほとんどすべてのイベント)を介して行われることを考えると、(独自のキーボードドライバーを作成しない限り)キーボードイベントにアクセスするための低レベルの方法はありません。私は知っています。

DirectXは引き続きWindowsキーボードメッセージングを使用して、DirectXプログラマーがキーボードイベントに簡単にアクセスできるようにします。

更新

DirectXについての私のメモはそれを使用しないことでしたが、Microsoftがプログラマーがリアルタイムのゲームに使用するためのインターフェイスを作成したいとき、彼らはWindowsメッセージキューの上にDirectXを書きました。

メッセージキューから直接読み取ることができるプログラムを作成する方法を検討することをお勧めします。良い例があると思います Code Project Windowsメッセージ処理-パート1

2つのオプションは、メッセージキューから読み取る(バッファリングされる)か、キーボードの状態から直接読み取る(Bukesの状態として)ことです。つまり、独自のループがさまざまな理由でキーボードイベントを技術的に見逃す可能性があります。

2
Erik Philips