aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHampusM <hampus@hampusmat.com>2022-06-29 20:17:23 +0200
committerHampusM <hampus@hampusmat.com>2022-06-29 20:17:23 +0200
commitd02d46d27982a8e351736067ab9787f87052b989 (patch)
tree540ddb694585ea4b6662101e358a94c81c509ed3
parentd2a76bd8cfd883070259bf572a9f723a37c0d96e (diff)
refactor: add termios abstraction
-rw-r--r--src/CMakeLists.txt3
-rw-r--r--src/engine/graphics/scene.cpp35
-rw-r--r--src/engine/graphics/scene.hpp4
-rw-r--r--src/engine/io/terminal.cpp54
-rw-r--r--src/engine/io/terminal.hpp130
5 files changed, 201 insertions, 25 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index a29cc35..2a98dd7 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -15,7 +15,8 @@ file(GLOB SOURCES
engine/graphics/string_matrix.cpp
engine/graphics/component_renderer.cpp
engine/user/input.cpp
- engine/user/cursor.cpp)
+ engine/user/cursor.cpp
+ engine/io/terminal.cpp)
add_executable(${PROJECT_NAME} ${SOURCES})
diff --git a/src/engine/graphics/scene.cpp b/src/engine/graphics/scene.cpp
index 7c23c7d..8ec8ddf 100644
--- a/src/engine/graphics/scene.cpp
+++ b/src/engine/graphics/scene.cpp
@@ -1,13 +1,13 @@
#include "scene.hpp"
+#include <cstdint>
#include <fmt/core.h>
+#include <iostream>
#include <sys/ioctl.h>
-#include <termios.h>
#include <unistd.h>
-#include <cstdint>
-#include <iostream>
#include "engine/escape.hpp"
+#include "engine/io/terminal.hpp"
class IComponent;
@@ -19,7 +19,7 @@ Scene::Scene(const IMatrixFactory<MatrixElement> &matrix_factory) noexcept
void Scene::enter() noexcept
{
- if (_is_shown || _original_termios != nullptr)
+ if (_is_shown)
{
return;
}
@@ -28,30 +28,22 @@ void Scene::enter() noexcept
fmt::print(ENABLE_ALT_BUFFER, fmt::arg("esc", ESC));
std::cout.flush();
- // Create a backup of the current terminal state
- _original_termios = std::make_shared<termios>();
- tcgetattr(STDIN_FILENO, _original_termios.get());
+ _original_terminal_state = get_terminal_state(STDIN_FILENO);
- auto new_termios = termios(*_original_termios);
+ auto new_terminal_state = TerminalState(_original_terminal_state);
- // Set the local mode flags of the new termios structure
- //
- // The following flags are disabled:
- // ECHO - Echoing input characters
- // ICANON - Canonical mode (line by line input)
- // ISIG - Generate the corresponding signals for the characters
- // INTR, QUIT, SUSP and DSUSP
- new_termios.c_lflag &= static_cast<std::uint32_t>(~(ECHO | ICANON | ISIG));
+ new_terminal_state.set_local_mode_flag(TerminalLocalModeFlag::echo, false);
+ new_terminal_state.set_local_mode_flag(TerminalLocalModeFlag::icanon, false);
+ new_terminal_state.set_local_mode_flag(TerminalLocalModeFlag::isig, false);
- // Set a new terminal state
- tcsetattr(STDIN_FILENO, TCSAFLUSH, &new_termios);
+ set_terminal_state(STDIN_FILENO, new_terminal_state);
_is_shown = true;
}
void Scene::leave() noexcept
{
- if (!_is_shown || _original_termios == nullptr)
+ if (!_is_shown)
{
return;
}
@@ -60,10 +52,9 @@ void Scene::leave() noexcept
fmt::print(DISABLE_ALT_BUFFER, fmt::arg("esc", ESC));
std::cout.flush();
- // Restore the original terminal state
- tcsetattr(STDIN_FILENO, TCSAFLUSH, _original_termios.get());
+ set_terminal_state(STDIN_FILENO, _original_terminal_state);
- _original_termios = nullptr;
+ _original_terminal_state = {};
_is_shown = false;
}
diff --git a/src/engine/graphics/scene.hpp b/src/engine/graphics/scene.hpp
index 5b52027..da3d990 100644
--- a/src/engine/graphics/scene.hpp
+++ b/src/engine/graphics/scene.hpp
@@ -3,13 +3,13 @@
#include <fmt/core.h>
#include <memory>
#include <string_view>
-#include <termios.h>
#include <utility>
#include <vector>
#include <yacppdic/auto_wirable.hpp>
#include "engine/data/bounds.hpp"
#include "engine/data/vector2.hpp"
+#include "engine/io/terminal.hpp"
#include "interfaces/component.hpp"
#include "interfaces/matrix.hpp"
#include "interfaces/scene.hpp"
@@ -47,7 +47,7 @@ private:
std::shared_ptr<IMatrix<MatrixElement>> _matrix;
bool _is_shown;
- std::shared_ptr<termios> _original_termios = nullptr;
+ TerminalState _original_terminal_state{};
std::vector<std::pair<std::shared_ptr<IComponent>, Vector2>> _components;
};
diff --git a/src/engine/io/terminal.cpp b/src/engine/io/terminal.cpp
new file mode 100644
index 0000000..e6d7d3a
--- /dev/null
+++ b/src/engine/io/terminal.cpp
@@ -0,0 +1,54 @@
+#include "terminal.hpp"
+
+TerminalState::TerminalState(termios term_attrs) noexcept : _term_attrs(term_attrs) {}
+
+void TerminalState::set_input_mode_flag(TerminalInputModeFlag flag, bool is_on) noexcept
+{
+ auto flag_num = static_cast<tcflag_t>(flag);
+
+ _term_attrs.c_iflag &= is_on ? flag_num : ~flag_num;
+}
+
+void TerminalState::set_output_mode_flag(TerminalOutputModeFlag flag, bool is_on) noexcept
+{
+ auto flag_num = static_cast<tcflag_t>(flag);
+
+ _term_attrs.c_oflag &= is_on ? flag_num : ~flag_num;
+}
+
+void TerminalState::set_control_mode_flag(
+ TerminalControlModeFlag flag,
+ bool is_on) noexcept
+{
+ auto flag_num = static_cast<tcflag_t>(flag);
+
+ _term_attrs.c_cflag &= is_on ? flag_num : ~flag_num;
+}
+
+void TerminalState::set_local_mode_flag(TerminalLocalModeFlag flag, bool is_on) noexcept
+{
+ auto flag_num = static_cast<tcflag_t>(flag);
+
+ _term_attrs.c_lflag &= is_on ? flag_num : ~flag_num;
+}
+
+auto TerminalState::get_attributes() noexcept -> termios
+{
+ return _term_attrs;
+}
+
+auto get_terminal_state(int term_fd) noexcept -> TerminalState
+{
+ termios term_attrs{};
+
+ tcgetattr(term_fd, &term_attrs);
+
+ return TerminalState(term_attrs);
+}
+
+void set_terminal_state(int term_fd, TerminalState state) noexcept
+{
+ auto state_attrs = state.get_attributes();
+
+ tcsetattr(term_fd, TCSAFLUSH, &state_attrs);
+}
diff --git a/src/engine/io/terminal.hpp b/src/engine/io/terminal.hpp
new file mode 100644
index 0000000..27455bb
--- /dev/null
+++ b/src/engine/io/terminal.hpp
@@ -0,0 +1,130 @@
+#pragma once
+
+#include <termios.h>
+
+enum class TerminalControlModeFlag
+{
+ csize = 0000060,
+ cs5 = 0000000,
+ cs6 = 0000020,
+ cs7 = 0000040,
+ cs8 = 0000060,
+ cstopb = 0000100,
+ cread = 0000200,
+ parenb = 0000400,
+ parodd = 0001000,
+ hupcl = 0002000,
+ clocal = 0004000,
+};
+
+enum class TerminalInputModeFlag
+{
+ ignbrk = 0000001, // Ignore break condition
+ brkint = 0000002, // Signal interrupt on break
+ ignpar = 0000004, // Ignore characters with parity errors
+ parmrk = 0000010, // Mark parity and framing errors
+ inpck = 0000020, // Enable input parity check
+ istrip = 0000040, // Strip = 8,th bit off characters
+ inlcr = 0000100, // Map NL to CR on input
+ igncr = 0000200, // Ignore CR
+ icrnl = 0000400, // Map CR to NL on input
+ iuclc = 0001000, // Map uppercase characters to lowercase on input (not in POSIX)
+ ixon = 0002000, // Enable start/stop output control
+ ixany = 0004000, // Enable any character to restart output
+ ixoff = 0010000, // Enable start/stop input control
+ imaxbel = 0020000, // Ring bell when input queue is full (not in POSIX)
+ iutf8 = 0040000, // Input is UTF8 (not in POSIX)
+};
+
+enum class TerminalOutputModeFlag
+{
+ opost = 0000001, // Post-process output
+ olcuc = 0000002, // Map lowercase characters to uppercase on output (not in POSIX)
+ onlcr = 0000004, // Map NL to CR-NL on output
+ ocrnl = 0000010, // Map CR to NL on output
+ onocr = 0000020, // No CR output at column = 0
+ onlret = 0000040, // NL performs CR function
+ ofill = 0000100, // Use fill characters for delay
+ ofdel = 0000200, // Fill is DEL
+ nldly = 0000400, // Select newline delays:
+ nl0 = 0000000, // Newline type = 0
+ nl1 = 0000400, // Newline type = 1
+ crdly = 0003000, // Select carriage-return delays:
+ cr0 = 0000000, // Carriage-return delay type = 0
+ cr1 = 0001000, // Carriage-return delay type = 1
+ cr2 = 0002000, // Carriage-return delay type = 2
+ cr3 = 0003000, // Carriage-return delay type = 3
+ tabdly = 0014000, // Select horizontal-tab delays:
+ tab0 = 0000000, // Horizontal-tab delay type = 0
+ tab1 = 0004000, // Horizontal-tab delay type = 1
+ tab2 = 0010000, // Horizontal-tab delay type = 2
+ tab3 = 0014000, // Expand tabs to spaces
+ bsdly = 0020000, // Select backspace delays:
+ bs0 = 0000000, // Backspace-delay type = 0
+ bs1 = 0020000, // Backspace-delay type = 1
+ ffdly = 0100000, // Select form-feed delays:
+ ff0 = 0000000, // Form-feed delay type = 0
+ ff1 = 0100000, // Form-feed delay type = 1
+ vtdly = 0040000, // Select vertical-tab delays:
+ vt0 = 0000000, // Vertical-tab delay type = 0
+ vt1 = 0040000, // Vertical-tab delay type = 1
+ xtabs = 0014000,
+};
+
+enum class TerminalLocalModeFlag
+{
+ isig = 0000001, // When any of the characters INTR, QUIT, SUSP, or DSUSP are received,
+ // generate the corresponding signal
+ icanon = 0000002, // Canonical input
+ xcase = 0000004,
+ echo = 0000010, // Echo input characters
+ echoe = 0000020, // Echo erase character as error-correcting backspace
+ echok = 0000040, // Echo KILL
+ echonl = 0000100, // Echo NL
+ noflsh = 0000200, // Disable flush after interrupt or quit
+ tostop = 0000400, // Send SIGTTOU for background output
+ echoctl = 0001000, /* If ECHO is also set, terminal special characters
+ other than TAB, NL, START, and STOP are echoed as
+ ^X, where X is the character with ASCII code = 0,x40
+ greater than the special character
+ (not in POSIX) */
+ echoprt = 0002000, /* If ICANON and ECHO are also set, characters are
+ printed as they are being erased
+ (not in POSIX) */
+ echoke = 0004000, /* If ICANON is also set, KILL is echoed by erasing
+ each character on the line, as specified by ECHOE
+ and ECHOPRT (not in POSIX) */
+ flusho = 0010000, /* Output is being flushed This flag is toggled by
+ typing the DISCARD character (not in POSIX) */
+ pendin = 0040000, /* All characters in the input queue are reprinted
+ when the next character is read
+ (not in POSIX) */
+ iexten = 0100000, // Enable implementation-defined input processing
+ extproc = 0200000,
+};
+
+class TerminalState
+{
+public:
+ TerminalState() = default;
+
+ explicit TerminalState(termios term_attrs) noexcept;
+
+ void set_input_mode_flag(TerminalInputModeFlag flag, bool is_on) noexcept;
+
+ void set_output_mode_flag(TerminalOutputModeFlag flag, bool is_on) noexcept;
+
+ void set_control_mode_flag(TerminalControlModeFlag flag, bool is_on) noexcept;
+
+ void set_local_mode_flag(TerminalLocalModeFlag flag, bool is_on) noexcept;
+
+ auto get_attributes() noexcept -> termios;
+
+private:
+ termios _term_attrs;
+};
+
+auto get_terminal_state(int term_fd) noexcept -> TerminalState;
+
+void set_terminal_state(int term_fd, TerminalState state) noexcept;
+