イネマルのプログラミング備忘録

趣味プログラマのメモ

DXライブラリ向け 簡易キー入力クラス

はじめに

DXライブラリで、キー入力の開始や終了を取る際、自前で機能を用意する必要があります。
必要になるたびに作るのが面倒そうなので、キー入力クラステンプレート的なものを置いときます。
対象は、キーボードとマウスです。

昔、DxLibをラップした自作ライブラリで学習がてら作ったものから、
切り出しだけなので、気になる部分があれば、適当に調整してください。

実装

押した瞬間、押している間、離した瞬間 が取れる実装です。

ビルド環境:Microsoft Visual C++ 2015

(長いので折り畳み)

#include <DxLib.h>
#include <array>

namespace dxlut
{
    // 入力クラス
    struct Input final
    {
        // 入力情報更新
        static bool Update() {
            Mouse::Update();
            return Keyboard::Update();
        }
        
        // 何らかのキーの入力開始
        static bool AnyKeyPress() {
            return DxLib::CheckHitKeyAll() != 0;
        }
        
        // 何らかのキーの入力中
        static bool AnyKeyDown() {
            return Keyboard::AnyDown() || Mouse::AnyDown();
        }

        // 何らかのキーの入力終了
        static bool AnyKeyUp() {
            return Keyboard::AnyUp() || Mouse::AnyUp();
        }

        // キーボード
        struct Keyboard final
        {
            typedef std::array<char, 256> KeyStateBuffer;

            // 入力情報更新
            static bool Update() {
                keyBuffer_.swap(prevKeyBuffer_);
                return GetHitKeyStateAll(&keyBuffer_.front()) == 0;
            }

            // 入力開始
            static bool IsPress(const int keyCode) {
                return keyBuffer_[keyCode] ? true : false;
            }

            // 入力中
            static bool IsDown(const int keyCode) {
                return keyBuffer_[keyCode] && !prevKeyBuffer_[keyCode];
            }

            // 入力終了
            static bool IsUp(const int keyCode) {
                return !keyBuffer_[keyCode] && prevKeyBuffer_[keyCode];
            }

            // 何らかのキーの入力開始(キーボード)
            static bool AnyPress() {
                for (unsigned idx = 0; idx < keyBuffer_.size(); ++idx) {
                    if (keyBuffer_[idx] != 0) {
                        return true;
                    }
                }
                return false;
            }

            // 何らかのキーの入力中(キーボード)
            static bool AnyDown() {
                for (unsigned idx = 0; idx < keyBuffer_.size(); ++idx) {
                    if (keyBuffer_[idx] && !prevKeyBuffer_[idx]) {
                        return true;
                    }
                }
                return false;
            }

            // 何らかのキーの入力終了(キーボード)
            static bool AnyUp() {
                for (unsigned idx = 0; idx < keyBuffer_.size(); ++idx) {
                    if (!keyBuffer_[idx] && prevKeyBuffer_[idx]) {
                        return true;
                    }
                }
                return false;
            }

        private:
            static KeyStateBuffer  keyBuffer_;
            static KeyStateBuffer  prevKeyBuffer_;
        };

        // マウス
        struct Mouse final
        {
            // 入力情報更新
            static void Update() {
                backKeyBuffer_ = keyBuffer_;
                keyBuffer_ = GetMouseInput();
            }

            // 入力開始
            static bool IsPress(const int keyCode) {
                return (keyBuffer_ & keyCode) != 0;
            }

            // 入力中
            static bool IsDown(const int keyCode) {
                return ((keyBuffer_ & keyCode) != 0) && !((backKeyBuffer_ & keyCode) != 0);
            }

            // 入力終了
            static bool IsUp(const int keyCode) {
                return !((keyBuffer_ & keyCode) != 0) && ((backKeyBuffer_ & keyCode) != 0);
            }

            // 何らかのボタン入力開始(マウス)
            static bool AnyPress() {
                return keyBuffer_ != 0;
            }

            // 何らかのボタン入力中(マウス)
            static bool AnyDown() {
                return (keyBuffer_ != 0) && !(backKeyBuffer_ != 0);
            }

            // 何らかのボタン入力終了(マウス)
            static bool AnyUp() {
                return !(keyBuffer_ != 0) && (backKeyBuffer_ != 0);
            }

        private:
            static int  keyBuffer_;
            static int  backKeyBuffer_;
        };
    };
    Input::Keyboard::KeyStateBuffer Input::Keyboard::keyBuffer_ = {};
    Input::Keyboard::KeyStateBuffer Input::Keyboard::prevKeyBuffer_ = {};
    int Input::Mouse::keyBuffer_ = 0;
    int Input::Mouse::backKeyBuffer_ = 0;

    // DXライブラリ簡易ラップクラス
    struct DxLibApp final
    {
        DxLibApp()
        {
            SetGraphMode(1024, 600, 32);
            ChangeWindowMode(TRUE);
            if (DxLib_Init() == -1) {
                throw;
            }
            SetDrawScreen(DX_SCREEN_BACK);
        }

        ~DxLibApp() {
            DxLib_End();
        }

        static bool Update() {
            return (ScreenFlip() == 0 && ProcessMessage() == 0 && ClearDrawScreen() == 0 && Input::Update());
        }
    } _app;
}

// エントリーポイント
int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
    using namespace dxlut;

    // メインループ
    while (DxLibApp::Update())
    {
        // Esc 終了
        if (Input::Keyboard::IsDown(KEY_INPUT_ESCAPE)) {
            break;
        }

        // とりあえず、「キーボードのZ」と「マウス左クリック」の入力検査サンプル
        // 他のキーは、キーコードだけ変えればよし

        // Zキーの状態
        if (Input::Keyboard::IsDown(KEY_INPUT_Z)) {
            DxLib::printfDx(_T("[Z] 入力開始\n"));
        }
        if (Input::Keyboard::IsPress(KEY_INPUT_Z)) {
            DxLib::printfDx(_T("[Z] 入力中\n"));
        }
        if (Input::Keyboard::IsUp(KEY_INPUT_Z)) {
            DxLib::printfDx(_T("[Z] 入力終了\n"));
        }

        // 左クリックの状態
        if (Input::Mouse::IsDown(MOUSE_INPUT_LEFT)) {
            DxLib::printfDx(_T("[Mouse L] 入力開始\n"));
        }
        if (Input::Mouse::IsPress(MOUSE_INPUT_LEFT)) {
            DxLib::printfDx(_T("[Mouse L] 入力中\n"));
        }
        if (Input::Mouse::IsUp(MOUSE_INPUT_LEFT)) {
            DxLib::printfDx(_T("[Mouse L] 入力終了\n"));
        }
    }

    return 0;
}

あとがき

たまたま、DXライブラリ製の小物プログラムを改修する機会がありました。
入力周りの制御をネットで調べると意外と簡易的なものが見つからなかったので、昔のコードを掘り返し備忘録行き。

DXライブラリは、よく使いそうな便利関数も自分で用意しないといけない部分が多い印象です。
この点において、イマドキだとUnityだったり、C++ならSiv3D(OpenSiv3D)が便利関数豊富で初心者が取っつきやすい環境かなと感じています。