Raw Input API による複数キーボードの認識

みんなが作った便利な関数やサンプルを共有するコミュニティです。
[url]http://www.activebasic.com/forum/viewforum.php?f=2]ActiveBasicの「実践コードモジュール」[/url]的な感じでやりましょう。
フォーラム(掲示板)ルール
・投稿するコードはできるだけ一つ、もしくは一つの関数を補助する複数の関数の形式にするか、
それだけをコンパイルして動くソースコード一式の形にしてください。
記事には説明だけを書き、コードは添付ファイルにしてもかまいません。
・使い方などの説明も書いてください。
環境に依存するコードの場合は、対象の環境も書いてください。
・使用条件(ライセンスなど)も書いていただけるとありがたいです。
・C言語、もしくはC++推奨ですが、他の言語でもかまいません。
・コードは正しくcodeタグで囲みましょう。
・一つのスレッドで一つのサンプルが基本です。
関連するサンプルの場合はまとめてもかまいません。
・投稿したサンプルを修正する場合には、スレッドの返信の形で投稿してください。
(新しいスレッドにしないでください。記事の編集でもかまいません)
返信
アバター
a5ua
記事: 199
登録日時: 8年前

Raw Input API による複数キーボードの認識

#1

投稿記事 by a5ua » 7年前

通常、キーボードはいくつ接続しても、1つとして認識されてしまいます。
Raw Input API を使うと、その名の通り、接続されているデバイスから“生”の入力を取得することができます。
当然、マウスやキーボードもそのデバイスに含まれます。
ただし、Raw Input API を使用できるのは、Windows XP 以降のようです。

今回は、Raw Input API を使って、2つ以上のキーボードからの入力を別々に扱う方法を、簡単なサンプルとともに説明します。

言語は、C++を用いるので、RawInputというクラスとして設計したいと思います。
ちなみに、描画部分にはDXライブラリを利用しています。

【ソースコード】
► スポイラーを表示
まず、ヘッダファイル(RawInput.h)ですが、機能としては、コメントに書いてある通りです。
実装の詳細については、この後、説明します。
また、std::bitset<256> というクラスを使っていますが、ビット列(ここでは256ビット)を簡単に操作するためのクラスです。

次に、実装ファイル(RawInput.cpp)の説明です。
コンストラクタでウインドウを作成していますが、これは、入力を受け付けるためのダミーのウインドウです。
子ウインドウとして作成しますが、表示はしません。
また、ウインドウプロシージャの処理をメンバ関数に記述するテクニック[anchor=a1 goto=ref5][5][/anchor]を使用しています。
RawInputの入力は、WM_INPUTメッセージを捕捉して取得します。
WM_INPUTメッセージを発生させるためには、はじめにデバイスを登録しなければなりません。
登録処理は、RawInput::register_device()にまとまっています。
ここでは、接続されているデバイスを列挙し、キーボードのデバイスハンドルを記憶しています。
登録時に、ウインドウ(上で作成したダミーのウインドウです)が最前面になくても、メッセージを受け取れるように以下のフラグを設定します。[anchor=a2 goto=ref4][4][/anchor]

コード:

d.dwFlags = RIDEV_INPUTSINK;
その他、[anchor=a3 goto=ref1][1][/anchor][anchor=a3 goto=ref2][2][/anchor]などが参考になります。
入力状態の更新処理は、RawInput::update(HRAWINPUT hRawInput)という関数に記述しています。
取得したキーボードのデータとして、仮想キーコード(VK_***)やフラグが格納されています。

コード:

m_key_state_table[i][key.VKey] = !(key.Flags & RI_KEY_BREAK);
この文の意味は、i番目のキーボードのVKeyが押されていたら"1"が、押されていなかったら"0"という意味になります。(参考:[anchor=a4 goto=ref3][3][/anchor])

最後に、RawInputクラスを使ったサンプルを紹介します。
GetKeyboardID関数では、要求した分だけのキーボードからの入力があるまで、入力を待ち続け、キーボードIDの配列を返します。
Unitクラスのオブジェクトは、指定された入力状態に従って上下左右に動きます。
[]演算子がオーバーロードされているので、RawInputのオブジェクトinputに対して、input[x]とすることで、x番目のキーボードの入力状態を得ることができます。
さらに、input[x]はbitsetなので、input[x][VK_LEFT]などとすると、x番目のキーボードの左カーソルキーが押されているかどうかを調べることができます。
ちなみに、input[x].any()とすると、x番目のキーボードのどれかのキーが押されているかを知ることができます。(GetKeyboardID関数で利用しています。)

長くなりましたが、暇な人がいたら、動作報告などしてくれたらうれしいです。

【製作環境】
・Windows XP
・Visual Studio 2008 Express Edition

【参考】
[anchor=ref1][/anchor]
[1] 直接入力について (ウィンドウズの操作まわり) - とやとは なにやつ
http://members.jcom.home.ne.jp/toya.hir ... input.html
[anchor=ref2][/anchor]
[2] RawInputで複数のマウスからの入力を取得する - ゲームプログラマ見習いの日記
http://d.hatena.ne.jp/p-tal/20090902/1251852285
[anchor=ref3][/anchor]
[3] Raw Input - Toymaker
http://www.toymaker.info/Games/html/raw_input.html
[anchor=ref4][/anchor]
[4] RAWINPUTDEVICE Structure (Windows) - MSDN Library
http://msdn.microsoft.com/en-us/library ... 85%29.aspx
[anchor=ref5][/anchor]
[5] ウィンドウのクラス化 - Programmer's Studio
http://members3.jcom.home.ne.jp/progstu ... tips2.html

アバター
a5ua
記事: 199
登録日時: 8年前

Re: Raw Input API による複数キーボードの認識

#2

投稿記事 by a5ua » 7年前

上で示したサンプルコードには、
「ウインドウが一度フォーカスを失うと、二度と入力を受け付けなくなる」
というバグがありました。

【解決策】

・DXライブラリで入力処理にDirectInputを使わない設定にします。

コード:

    UseDxLibrary()
    {
        ChangeWindowMode(TRUE);
        SetUseDirectInputFlag(FALSE);	// これ
        SetMainWindowText("Raw Input API のサンプル");
 
        if (DxLib_Init() != 0) {
            throw std::exception("DXライブラリの初期化に失敗");
        }
    
        SetDrawScreen(DX_SCREEN_BACK);
    }
・RawInput.cppの関数を以下のように訂正します。

コード:

// キーボード登録用
RAWINPUTDEVICE RawInputKeyboard(HWND hWnd)
{
    RAWINPUTDEVICE d;
    
    d.usUsagePage = 0x01;
    d.usUsage = 0x06;
    d.dwFlags = 0; // フォーカスを失ったら入力を受け付ける必要はない
    d.hwndTarget = hWnd;
 
    return d;
}

返信

“サンプルを共有するコミュニティ” へ戻る