バッファを使用したキーボードの情報取得

Page creation date :

The page you are currently viewing does not support the selected display language.

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

下の図はわざと更新時間を長く取り、次の更新のときに蓄積されたデータを一度に取り出したデータです。

バッファを使用したキーボードの情報取得

今回のメインコードファイルを載せます。部分的な説明に関してはコードの下の方で説明しています。

MainSample.cs

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」でキャストして調べられます。