前回キーボードの情報を取得しましたが、もし、一回の更新時間が長かった場合、キーが複数回押されたりしても、それを1回と認識したり、または押されていないと認識される可能性もあります。
今回は「バッファ」を使用することにより、ハードウェアの情報をバッファに蓄積し、ソフト側の影響による情報のご認識を防ぐようにします。
下の図はわざと更新時間を長く取り、次の更新のときに蓄積されたデータを一度に取り出したデータです。

下のリンクから今回のプロジェクトをダウンロードできます。
| ファイル名 | 言語 | サイズ |
|---|---|---|
| keyboardbuffer_cs_1_1.zip | C# | 20KB |
| keyboardbuffer_vb_1_1.zip | VB.NET | 25KB |
| keyboardbuffer_cpp_1_1.zip | C++/CLI | 11KB |
今回のメインコードファイルを載せます。重要なコードを赤色で表示させています。部分的な説明に関してはコードの下の方で説明しています。
using System; using System.Collections.Generic; using System.Diagnostics; using System.Drawing; using System.Text; using System.Windows.Forms; using Microsoft.DirectX; using Microsoft.DirectX.DirectInput; namespace MDXSample { /// <summary> /// メインサンプルクラス /// </summary> public class MainSample : IDisposable { /// <summary> /// メインフォーム /// </summary> private MainForm _form = null; /// <summary> /// キーボードデバイス /// </summary> private Device _keyboradDevice = null; /// <summary> /// アプリケーションの初期化 /// </summary> /// <param name="topLevelForm">トップレベルウインドウ</param> /// <returns>全ての初期化がOKなら true, ひとつでも失敗したら false を返すようにする</returns> /// <remarks> /// false を返した場合は、自動的にアプリケーションが終了するようになっている /// </remarks> public bool InitializeApplication(MainForm topLevelForm) { // フォームの参照を保持 this._form = topLevelForm; // キーボードデバイスの初期化 try { // キーボードデバイスの作成 this._keyboradDevice = new Device(SystemGuid.Keyboard); // 協調レベルの設定 this._keyboradDevice.SetCooperativeLevel(topLevelForm, CooperativeLevelFlags.NonExclusive | CooperativeLevelFlags.Background); } catch (DirectXException ex) { MessageBox.Show(ex.ToString(), "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error); return false; } // バッファサイズを指定 this._keyboradDevice.Properties.BufferSize = 16; try { // キャプチャするデバイスを取得 this._keyboradDevice.Acquire(); } catch (DirectXException) { } return true; } /// <summary> /// メインループ処理 /// </summary> public void MainLoop() { // バッファが本当に作用しているかテスト //System.Threading.Thread.Sleep(100); BufferedDataCollection buffer = null; try { // キーボードの状態をキャプチャ buffer = this._keyboradDevice.GetBufferedData(); } catch (DirectXException) { try { // キャプチャするデバイスを取得 this._keyboradDevice.Acquire(); // キーボードの状態をキャプチャ buffer = this._keyboradDevice.GetBufferedData(); } catch (DirectXException) { return; } } if (buffer == null) { // デバイスをキャプチャできない、またはデータがないとき return; } StringBuilder builder = new StringBuilder(); // バッファに蓄積された情報を読み取る foreach (BufferedData i in buffer) { if (i.Data != 0) { builder.Append((Key)i.Offset + " Down" + Environment.NewLine); } else { builder.Append((Key)i.Offset + " Up" + Environment.NewLine); } } // ラベルに表示 this._form.InputLabel.Text = builder.ToString(); } /// <summary> /// リソースの破棄をするために呼ばれる /// </summary> public void Dispose() { // キーボードデバイスの解放 if (this._keyboradDevice != null) { this._keyboradDevice.Dispose(); } } } } |
では、赤文字の部分を説明していきます。
// バッファサイズを指定 this._keyboradDevice.Properties.BufferSize = 16; |
バッファサイズを指定します。バッファサイズはデータをどのくらい格納させるかを決めるためのものです。今回は16個分の記憶領域を使用することにします。
BufferedDataCollection buffer = null; try { // キーボードの状態をキャプチャ buffer = this._keyboradDevice.GetBufferedData(); } catch (DirectXException) { try { // キャプチャするデバイスを取得 this._keyboradDevice.Acquire(); // キーボードの状態をキャプチャ buffer = this._keyboradDevice.GetBufferedData(); } catch (DirectXException) { return; } } |
バッファに格納されたデータを受け取るには「Device.GetBufferedData」メソッドを使用します。BufferedDataCollection には個々のバッファデータが格納されています。
if (buffer == null) { // デバイスをキャプチャできない、またはデータがないとき return; } |
もし取得に失敗したのなら return します。
StringBuilder builder = new StringBuilder(); // バッファに蓄積された情報を読み取る foreach (BufferedData i in buffer) { if (i.Data != 0) { builder.Append((Key)i.Offset + " Down" + Environment.NewLine); } else { builder.Append((Key)i.Offset + " Up" + Environment.NewLine); } } // ラベルに表示 this._form.InputLabel.Text = builder.ToString(); |
BufferedDataCollection から個々のバッファデータを調べます。「BufferedData.Data」には、キーを押した時なら「0x80」、放したときなら「0x00」が格納されているので、それで条件分岐可能です。
また、どのキーの情報が格納されているかは BufferedData.Offset で分類できるので「Key」でキャストして調べられます。