バッファを使用したマウスの情報取得

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 _mouseDevice = 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._mouseDevice = new Device(SystemGuid.Mouse);

                // 協調レベルの設定
                this._mouseDevice.SetCooperativeLevel(topLevelForm,
                    CooperativeLevelFlags.Background | CooperativeLevelFlags.NonExclusive);
            }
            catch (DirectXException ex)
            {
                MessageBox.Show(ex.ToString(), "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return false;
            }

            // バッファサイズを指定
            this._mouseDevice.Properties.BufferSize = 16;

            try
            {
                // キャプチャするデバイスを取得
                this._mouseDevice.Acquire();
            }
            catch (DirectXException)
            {
            }

            return true;
        }

        /// <summary>
        /// メインループ処理
        /// </summary>
        public void MainLoop()
        {
            // バッファが本当に作用しているかテスト
            //System.Threading.Thread.Sleep(100);

            BufferedDataCollection buffer = null;
            try
            {
                // マウスの状態をキャプチャ
                buffer = this._mouseDevice.GetBufferedData();
            }
            catch (DirectXException)
            {
                try
                {
                    // キャプチャするデバイスを取得
                    this._mouseDevice.Acquire();

                    // マウスの状態をキャプチャ
                    buffer = this._mouseDevice.GetBufferedData();
                }
                catch (DirectXException)
                {
                    return;
                }
            }

            if (buffer == null)
            {
                // デバイスをキャプチャできない、またはデータがないとき
                return;
            }

            StringBuilder builder = new StringBuilder();

            // バッファに蓄積された情報を読み取る
            foreach (BufferedData i in buffer)
            {
                switch ((MouseOffset)i.Offset)
                {
                    case MouseOffset.Button0:
                    case MouseOffset.Button1:
                    case MouseOffset.Button2:
                    case MouseOffset.Button3:
                    case MouseOffset.Button4:
                    case MouseOffset.Button5:
                    case MouseOffset.Button6:
                    case MouseOffset.Button7:
                        if (i.Data != 0)
                        {
                            builder.Append("Button" + (i.Offset - (int)MouseOffset.Button0) +
                                " Down" + Environment.NewLine);
                        }
                        else
                        {
                            builder.Append("Button" + (i.Offset - (int)MouseOffset.Button0) +
                                " Up" + Environment.NewLine);
                        }
                        break;
                    case MouseOffset.X:
                        builder.Append("X:" + i.Data + Environment.NewLine);
                        break;
                    case MouseOffset.Y:
                        builder.Append("Y:" + i.Data + Environment.NewLine);
                        break;
                    case MouseOffset.Z:
                        builder.Append("Z:" + i.Data + Environment.NewLine);
                        break;
                }
            }

            // ラベルに表示
            this._form.InputLabel.Text = builder.ToString();
        }

        /// <summary>
        /// リソースの破棄をするために呼ばれる
        /// </summary>
        public void Dispose()
        {
            // マウスデバイスの解放
            if (this._mouseDevice != null)
            {
                this._mouseDevice.Dispose();
            }
        }
    }
}

// バッファサイズを指定
this._mouseDevice.Properties.BufferSize = 16;

バッファサイズを指定します。バッファサイズはデータをどのくらい格納させるかを決めるためのものです。今回は16個分の記憶領域を使用することにします。


BufferedDataCollection buffer = null;
try
{
    // マウスの状態をキャプチャ
    buffer = this._mouseDevice.GetBufferedData();
}
catch (DirectXException)
{
    try
    {
        // キャプチャするデバイスを取得
        this._mouseDevice.Acquire();

        // マウスの状態をキャプチャ
        buffer = this._mouseDevice.GetBufferedData();
    }
    catch (DirectXException)
    {
        return;
    }
}

バッファに格納されたデータを受け取るには「Device.GetBufferedData」メソッドを使用します。BufferedDataCollection には個々のバッファデータが格納されています。


if (buffer == null)
{
    // デバイスをキャプチャできない、またはデータがないとき
    return;
}

もし取得に失敗したのなら return します。


StringBuilder builder = new StringBuilder();

// バッファに蓄積された情報を読み取る
foreach (BufferedData i in buffer)
{
    switch ((MouseOffset)i.Offset)
    {
        case MouseOffset.Button0:
        case MouseOffset.Button1:
        case MouseOffset.Button2:
        case MouseOffset.Button3:
        case MouseOffset.Button4:
        case MouseOffset.Button5:
        case MouseOffset.Button6:
        case MouseOffset.Button7:
            if (i.Data != 0)
            {
                builder.Append("Button" + (i.Offset - (int)MouseOffset.Button0) +
                    " Down" + Environment.NewLine);
            }
            else
            {
                builder.Append("Button" + (i.Offset - (int)MouseOffset.Button0) +
                    " Up" + Environment.NewLine);
            }
            break;
        case MouseOffset.X:
            builder.Append("X:" + i.Data + Environment.NewLine);
            break;
        case MouseOffset.Y:
            builder.Append("Y:" + i.Data + Environment.NewLine);
            break;
        case MouseOffset.Z:
            builder.Append("Z:" + i.Data + Environment.NewLine);
            break;
    }
}

// ラベルに表示
this._form.InputLabel.Text = builder.ToString();

BufferedDataCollection から個々のバッファデータを調べます。BufferedData.Offset でマウスのどの情報かを分類できるので「MouseOffset」でキャストして調べます。

状態は BufferedData.Data 調べることが出来ます。どのような値が格納されているかは、前回の MouseState と同じです。マウスのボタンに関しては押したときと放したときもバッファに格納されるので、今回はそれもチェックしています。


// バッファが本当に作用しているかテスト
//System.Threading.Thread.Sleep(100);

サンプルは、更新頻度が早いのでバッファの恩恵があまり感じられません。なので、コメントアウトしている上の行を追加してわざと更新間隔を長くするとバッファがきちんと使われていることを認識できると思います。