diff options
author | HampusM <hampus@hampusmat.com> | 2022-02-28 21:30:30 +0100 |
---|---|---|
committer | HampusM <hampus@hampusmat.com> | 2022-06-13 17:56:54 +0200 |
commit | ede689d23e57c9b701ab19aa9112a0b2368865c9 (patch) | |
tree | e8c7afc7b2e5caf43b1b0c52356c0596021f25cb | |
parent | f0883534b3303cf2b74f3ab51efe16615d2561a9 (diff) |
feat: add input handler & quitting with 'q'
-rw-r--r-- | src/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/bootstrap.cpp | 3 | ||||
-rw-r--r-- | src/engine/user/input.cpp | 64 | ||||
-rw-r--r-- | src/engine/user/input.hpp | 31 | ||||
-rw-r--r-- | src/game/game.cpp | 23 | ||||
-rw-r--r-- | src/game/game.hpp | 7 | ||||
-rw-r--r-- | src/interfaces/input.hpp | 17 | ||||
-rw-r--r-- | src/interfaces/observable.hpp | 16 |
8 files changed, 155 insertions, 7 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 385283d..54793b0 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -18,6 +18,7 @@ file(GLOB SOURCES engine/graphics/bounds.cpp engine/graphics/scene.cpp engine/graphics/string_matrix.cpp + engine/user/input.cpp randomization/generator.cpp randomization/seed_generator.cpp DI/object_type.cpp) diff --git a/src/bootstrap.cpp b/src/bootstrap.cpp index 8a8aa25..6b4a954 100644 --- a/src/bootstrap.cpp +++ b/src/bootstrap.cpp @@ -4,6 +4,7 @@ #include "interfaces/argument_parser.hpp" #include "interfaces/bounds.hpp" #include "interfaces/game.hpp" +#include "interfaces/input.hpp" #include "interfaces/matrix.hpp" #include "interfaces/randomization.hpp" #include "interfaces/scene.hpp" @@ -15,6 +16,7 @@ #include "engine/graphics/scene.hpp" #include "engine/graphics/string_matrix.hpp" #include "engine/graphics/vector2.hpp" +#include "engine/user/input.hpp" #include "game/game.hpp" #include "randomization/generator.hpp" #include "randomization/seed_generator.hpp" @@ -30,6 +32,7 @@ Container bootstrap() container.bind<IArgumentParser>().to<ArgumentParser>(); container.bind<IGame>().to<Game>(); container.bind<IScene>().to<Scene>(); + container.bind<IInputHandler>().to<InputHandler>(); container.bind<IRandomNumberGeneratorFactory>().to_factory( [](const unsigned int &seed) diff --git a/src/engine/user/input.cpp b/src/engine/user/input.cpp new file mode 100644 index 0000000..e68f303 --- /dev/null +++ b/src/engine/user/input.cpp @@ -0,0 +1,64 @@ +#include "input.hpp" + +#include <unistd.h> + +void InputHandler::listen() const +{ + char character = 0; + + while (read(STDIN_FILENO, &character, 1) == 1) + { + notify(character); + } +} + +void InputHandler::attach(const char &event, Callback callback) +{ + if (_key_observers.count(event) == 0) + { + _key_observers[event] = std::vector<Callback>(); + } + + _key_observers[event].push_back(callback); +} + +void InputHandler::notify(const char &event) const +{ + if (_key_observers.count(event) == 0) + { + return; + } + + for (const auto &observer : _key_observers.at(event)) + { + observer(); + } +} + +void InputHandler::enter_raw_mode() +{ + if (_original_termios == nullptr) + { + _original_termios = std::make_shared<termios>(); + } + + tcgetattr(STDIN_FILENO, _original_termios.get()); + + auto raw_termios = termios(*_original_termios); + + raw_termios.c_lflag &= static_cast<unsigned int>(~(ECHO | ICANON | ISIG)); + + tcsetattr(STDIN_FILENO, TCSAFLUSH, &raw_termios); +} + +void InputHandler::leave_raw_mode() +{ + if (_original_termios == nullptr) + { + return; + } + + tcsetattr(STDIN_FILENO, TCSAFLUSH, _original_termios.get()); + + _original_termios = nullptr; +} diff --git a/src/engine/user/input.hpp b/src/engine/user/input.hpp new file mode 100644 index 0000000..f48ab86 --- /dev/null +++ b/src/engine/user/input.hpp @@ -0,0 +1,31 @@ +#pragma once + +#include "DI/auto_wirable.hpp" +#include "interfaces/input.hpp" +#include "interfaces/observable.hpp" + +#include <memory> +#include <termios.h> +#include <unordered_map> +#include <vector> + +class InputHandler : public IInputHandler, public AutoWirable<IInputHandler, InputHandler> +{ +public: + InputHandler() = default; + + void listen() const override; + + void attach(const char &event, Callback callback) override; + + void notify(const char &event) const override; + + void enter_raw_mode() override; + + void leave_raw_mode() override; + +private: + std::unordered_map<char, std::vector<Callback>> _key_observers; + + std::shared_ptr<termios> _original_termios = nullptr; +}; diff --git a/src/game/game.cpp b/src/game/game.cpp index 2c99c6a..2b09470 100644 --- a/src/game/game.cpp +++ b/src/game/game.cpp @@ -1,15 +1,28 @@ #include "game.hpp" -#include <chrono> -#include <thread> - -Game::Game(std::shared_ptr<IScene> scene) : _scene(std::move(scene)) {} +Game::Game(std::shared_ptr<IScene> scene, std::shared_ptr<IInputHandler> input_handler) + : _scene(std::move(scene)), _input_handler(std::move(input_handler)) +{ +} void Game::run() { _scene->enter(); - std::this_thread::sleep_for(std::chrono::seconds(3)); + _input_handler->enter_raw_mode(); + + auto scene = _scene; + auto input_handler = _input_handler; + + _input_handler->attach('q', + [&input_handler, &scene]() + { + input_handler->leave_raw_mode(); + scene->leave(); + exit(EXIT_SUCCESS); + }); + + _input_handler->listen(); _scene->leave(); } diff --git a/src/game/game.hpp b/src/game/game.hpp index e7d91d6..bc37c91 100644 --- a/src/game/game.hpp +++ b/src/game/game.hpp @@ -2,17 +2,20 @@ #include "DI/auto_wirable.hpp" #include "interfaces/game.hpp" +#include "interfaces/input.hpp" #include "interfaces/scene.hpp" #include <memory> -class Game : public IGame, public AutoWirable<IGame, Game, IScene> +class Game : public IGame, public AutoWirable<IGame, Game, IScene, IInputHandler> { public: - explicit Game(std::shared_ptr<IScene> scene); + explicit Game(std::shared_ptr<IScene> scene, + std::shared_ptr<IInputHandler> input_handler); void run() override; private: std::shared_ptr<IScene> _scene; + std::shared_ptr<IInputHandler> _input_handler; }; diff --git a/src/interfaces/input.hpp b/src/interfaces/input.hpp new file mode 100644 index 0000000..956ec4f --- /dev/null +++ b/src/interfaces/input.hpp @@ -0,0 +1,17 @@ +#pragma once + +#include "interfaces/observable.hpp" + +class IInputHandler : public IObservable<char> +{ +public: + void listen() const override = 0; + + void attach(const char &event, Callback callback) override = 0; + + void notify(const char &event) const override = 0; + + virtual void enter_raw_mode() = 0; + + virtual void leave_raw_mode() = 0; +}; diff --git a/src/interfaces/observable.hpp b/src/interfaces/observable.hpp new file mode 100644 index 0000000..ca8ffda --- /dev/null +++ b/src/interfaces/observable.hpp @@ -0,0 +1,16 @@ +#pragma once + +#include <functional> + +using Callback = std::function<void()>; + +template <typename Event> +class IObservable +{ +public: + virtual void listen() const = 0; + + virtual void attach(const Event &event, Callback callback) = 0; + + virtual void notify(const Event &event) const = 0; +}; |