aboutsummaryrefslogtreecommitdiff
path: root/terminal-game-utils.hpp
diff options
context:
space:
mode:
authorroy <[email protected]>2026-06-28 00:24:47 +0300
committerroy <[email protected]>2026-06-28 00:24:47 +0300
commitc690c3417dcb6966dc9ab56d41e37427ec1a4e7a (patch)
tree93062581e1654f83a29121148b4794e0ace48cfc /terminal-game-utils.hpp
Initial commit.
Diffstat (limited to 'terminal-game-utils.hpp')
-rw-r--r--terminal-game-utils.hpp178
1 files changed, 178 insertions, 0 deletions
diff --git a/terminal-game-utils.hpp b/terminal-game-utils.hpp
new file mode 100644
index 0000000..0e41074
--- /dev/null
+++ b/terminal-game-utils.hpp
@@ -0,0 +1,178 @@
+#include <iostream>
+#include <map>
+#include <ostream>
+#include <poll.h>
+#include <string>
+#include <termios.h>
+#include <unistd.h>
+
+namespace TGU {
+
+inline struct termios orig_termios;
+
+inline std::string newline = "\n\r";
+
+enum class GameKey {
+ INVALID,
+ LEFTARROW,
+ DOWNARROW,
+ UPARROW,
+ RIGHTARROW,
+ ESCAPE,
+ A,
+ B,
+ C,
+ D,
+ E,
+ F,
+ G,
+ H,
+ I,
+ J,
+ K,
+ L,
+ M,
+ N,
+ O,
+ P,
+ Q,
+ R,
+ S,
+ T,
+ U,
+ V,
+ W,
+ X,
+ Y,
+ Z,
+ SPACE,
+};
+
+inline std::map<std::string, GameKey> KeyMap = {{"a", GameKey::A},
+ {"b", GameKey::B},
+ {"c", GameKey::C},
+ {"d", GameKey::D},
+ {"e", GameKey::E},
+ {"f", GameKey::F},
+ {"g", GameKey::G},
+ {"h", GameKey::H},
+ {"i", GameKey::I},
+ {"j", GameKey::J},
+ {"k", GameKey::K},
+ {"l", GameKey::L},
+ {"m", GameKey::M},
+ {"n", GameKey::N},
+ {"o", GameKey::O},
+ {"p", GameKey::P},
+ {"q", GameKey::Q},
+ {"r", GameKey::R},
+ {"s", GameKey::S},
+ {"t", GameKey::T},
+ {"u", GameKey::U},
+ {"v", GameKey::V},
+ {"w", GameKey::W},
+ {"x", GameKey::X},
+ {"y", GameKey::Y},
+ {"z", GameKey::Z},
+ {"A", GameKey::A},
+ {"B", GameKey::B},
+ {"C", GameKey::C},
+ {"D", GameKey::D},
+ {"E", GameKey::E},
+ {"F", GameKey::F},
+ {"G", GameKey::G},
+ {"H", GameKey::H},
+ {"I", GameKey::I},
+ {"J", GameKey::J},
+ {"K", GameKey::K},
+ {"L", GameKey::L},
+ {"M", GameKey::M},
+ {"N", GameKey::N},
+ {"O", GameKey::O},
+ {"P", GameKey::P},
+ {"Q", GameKey::Q},
+ {"R", GameKey::R},
+ {"S", GameKey::S},
+ {"T", GameKey::T},
+ {"U", GameKey::U},
+ {"V", GameKey::V},
+ {"W", GameKey::W},
+ {"X", GameKey::X},
+ {"Y", GameKey::Y},
+ {"Z", GameKey::Z},
+ {"\x1b", GameKey::ESCAPE},
+ {"\x1b[D", GameKey::LEFTARROW},
+ {"\x1b[B", GameKey::DOWNARROW},
+ {"\x1b[A", GameKey::UPARROW},
+ {"\x1b[C", GameKey::RIGHTARROW},
+ {" ", GameKey::SPACE}};
+
+inline void DisableRawMode() { tcsetattr(0, TCSAFLUSH, &orig_termios); }
+
+inline void EnableRawMode() {
+
+ tcgetattr(0, &orig_termios);
+
+ atexit(DisableRawMode);
+ struct termios raw = orig_termios;
+ raw.c_iflag &= ~(ICRNL | INPCK | ISTRIP | IXON);
+ raw.c_oflag &= ~(OPOST);
+ raw.c_cflag |= (CS8);
+ raw.c_lflag &= ~(ECHO | ICANON | IEXTEN);
+ raw.c_cc[VMIN] = 1;
+ raw.c_cc[VTIME] = 0;
+
+ tcsetattr(0, TCSAFLUSH, &raw);
+}
+
+inline bool InputAvailable(int timeout_ms) {
+ pollfd pfd{};
+ pfd.fd = STDIN_FILENO;
+ pfd.events = POLLIN;
+
+ return poll(&pfd, 1, timeout_ms) > 0;
+}
+
+inline GameKey GetKeyPress() {
+ std::string keypress_string;
+ char c;
+
+ read(STDIN_FILENO, &c, 1);
+ keypress_string += c;
+
+ if (c == 27)
+ while (InputAvailable(10)) {
+ read(STDIN_FILENO, &c, 1);
+ keypress_string += c;
+ }
+
+ if (KeyMap.count(keypress_string))
+ return KeyMap[keypress_string];
+
+ return KeyMap[keypress_string];
+}
+
+// Terminal color printers:
+
+inline void TextGreen() { std::cout << "\033[32m"; }
+
+inline void TextRed() { std::cout << "\033[31m"; }
+
+inline void TextBlue() { std::cout << "\033[34m"; }
+
+inline void TextReset() { std::cout << "\033[0m"; }
+
+inline void TextRGB(int r, int g, int b) {
+ std::cout << std::format("\033[38;2;{};{};{}m", r, g, b);
+};
+
+// Game buffer printers:
+
+inline void EnterGameBuffer() { std::cout << "\033[?1049h"; }
+
+inline void LeaveGameBuffer() { std::cout << "\033[?1049l"; }
+
+inline void MoveCursor(int row, int col) {
+ std::cout << "\033[" << row << ";" << col << "H" << std::flush;
+}
+}; // namespace TGU