155 lines
3.7 KiB
C++
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
|