pubnix/lib/neovision/include/neovision/term.h

155 lines
3.7 KiB
C++

#pragma once
#include <signal.h>
#include <termios.h>
#include <chrono>
#include <streambuf>
#include <unordered_map>
namespace neovision {
class Application;
class Vector2D;
/**
* @brief Terminal event callback.
*
* This function signature is used for registering terminal event callbacks.
* The application is passed as a convenience, as anything that needs to be
* accessible within the function can be wired into the application class.
*/
typedef std::function<void()> TerminalEventCallback;
/**
* Class for terminal i/o operations.
*
* Any terminal setting changes made during the lifetime of the class will be
* restored to their previous state when the instance is destroyed.
*
* While you can use this class on it's own, it is sort-of assumed that the
* Terminal is instantiated by the Application class.
* Specifically, the callback functions rely on the 'TheApp' pointer being
* set in order to dispatch their events.
*
* @todo this is going to require platform-specific split implementations.
*/
class Terminal {
bool m_initialized{false};
termios m_savedTerminalSettings{};
TerminalEventCallback m_onResize;
TerminalEventCallback m_onTerminate;
struct sigaction m_resizeSignal{};
std::chrono::milliseconds m_ioTimeOut{100};
int m_fd{0};
static void sigIntHandler(int);
static void sigWinchHandler(int);
public:
/**
* Constructor.
*/
Terminal();
/**
* @brief Destructor.
*/
~Terminal();
/**
* @brief Cleanup
*
* Call this on exit. The destructor will attempt to, but it's not
* guaranteed to actually run correctly that way since we can't predict the
* order in which things are destroyed.
*/
void Cleanup();
/**
* @brief Initialize.
*
* Initializes the terminal for use. You should call this after
* constructing.
*/
void Initialize();
/**
* @brief Processes terminal events.
*
* Checks for ioctl signals, triggers callbacks as-needed.
*/
void ProcessEvents();
/**
* @brief Reads n bytes from terminal input.
*
* @param[in] n How many bytes to read.
* @return Returns the data read from terminal input.
*/
std::wstring Read(size_t n);
/**
* @brief Restores terminal settings back to their original state.
*/
void Restore();
/**
* @brief Sets the on-resize callback function.
*
* This function gets executed when the terminal gets resized.
*
* @param callback Function to be executed when the terminal gets resized.
*/
void SetOnResize(TerminalEventCallback callback);
/**
* @brief Set the on-terminate callback function.
*
* This function gets executed when the terminal gets killed, for instance
* with ctrl+c or a kill command.
*
* If you've got cleanup to run for graceful termination, you should hook
* into this to execute it.
*/
void SetOnTerminate(TerminalEventCallback callback);
/**
* @brief Get the terminal size.
*
* @return Returns the terminal size as a Position with X representing the
* number of columns, and Y the number of rows.
*/
Vector2D Size();
/**
* @brief Get IO timeout.
*
* @return Returns the current I/O timeout.
*/
std::chrono::milliseconds Timeout() const;
/**
* @brief Set IO timeout.
*
* @param[in] t New IO timeout in seconds.
*/
void Timeout(const std::chrono::milliseconds& t);
/**
* @brief Disables buffered i/o in the terminal.
*/
void Unbuffer();
/**
* @brief Writes data into the terminal.
* @param data Data to write.
*/
void Write(const std::wstring& data);
};
} // namespace neovision