// // ncurses-poll.hpp // // A header for performing asynchronous I/O with ncurses using Boost.Asio. // // @author CismonX // #ifndef NCURSES_POLL_HPP_ #define NCURSES_POLL_HPP_ #include #include #include template class ncurses_poll { using stream_descriptor_t = boost::asio::posix::stream_descriptor; /// Provides asynchronous I/O functionalities for this ncurses instance. stream_descriptor_t sd_; /// I/O context used by the stream descriptor. boost::asio::io_context *context_; /// File pointer of this tty. FILE *file_ = nullptr; /// Screen pointer of this ncurses instance. SCREEN *screen_ = nullptr; /// User-defined session for this ncurses instance. Session session_; public: /// Provides support for stackless coroutines. boost::asio::coroutine coro; /** * Constructor. * * @param io_context The I/O context used for dispatching handlers. */ explicit ncurses_poll(boost::asio::io_context& io_context) : sd_(io_context), context_(&io_context), session_(this) {} /** * Deleted default constructor. */ ncurses_poll() = delete; /** * Initialize ncurses instance. * * @param path File path. e.g. "/dev/pts/0". Empty for current tty. */ int init(const std::string& path = ttyname(STDIN_FILENO)) { file_ = fopen(path.c_str(), "r+"); if (file_ == nullptr) { return errno; } screen_ = newterm(nullptr, file_, file_); boost::system::error_code ec; sd_.assign(fileno(file_), ec); return ec.value(); } /** * Invoke the given callback once the terminal is readable. * * @param read_cb The callback to be invoked. */ template void on_readable(F&& read_cb) { sd_.async_wait(stream_descriptor_t::wait_read, boost::bind( [this, read_cb](const boost::system::error_code& ec) { set_term(screen_); read_cb(ec, this); }, boost::asio::placeholders::error)); } /** * Invoke the given callback once the terminal is writable. * * @param write_cb The callback to be invoked. */ template void on_writable(F&& write_cb) { sd_.async_wait(stream_descriptor_t::wait_write, boost::bind( [this, write_cb](const boost::system::error_code& ec) { set_term(screen_); write_cb(ec, this); }, boost::asio::placeholders::error)); } /** * Get current session. */ Session *session() { return &session_; } /** * Get screen pointer of this ncurses instance. */ SCREEN *screen() const { return screen_; } /** * Get current I/O context. */ boost::asio::io_context *get_io_context() { return context_; } /** * Destructor. */ ~ncurses_poll() { if (screen_) { set_term(screen_); endwin(); delscreen(screen_); } if (file_) { fclose(file_); } } }; #endif