15#include <initializer_list>
39#define DEFINE_CONSOLEV2_PROPERTIES
40#define WIN32_LEAN_AND_MEAN
46#error Must be compiled in UNICODE mode
49#include <sys/select.h>
55#if defined(__clang__) && defined(__APPLE__)
56#define quick_exit(a) exit(a)
65 screen->RequestAnimationFrame();
76 std::cout <<
'\0' << std::flush;
86 auto parser = TerminalInputParser(
out->Clone());
108 for (
const auto& r :
records) {
109 switch (r.EventType) {
134#elif defined(__EMSCRIPTEN__)
135#include <emscripten.h>
139 auto parser = TerminalInputParser(std::move(
out));
175 auto parser = TerminalInputParser(std::move(
out));
184 std::array<char, buffer_size>
buffer;
186 for (
size_t i = 0; i < l; ++i) {
260const std::string
CSI =
"\x1b[";
263const std::string
DCS =
"\x1bP";
265const std::string
ST =
"\x1b\\";
272enum class DECMode : std::uint16_t {
278 kMouseVt200Highlight = 1001,
280 kMouseBtnEventMouse = 1002,
281 kMouseAnyEvent = 1003,
284 kMouseSgrExtMode = 1006,
285 kMouseUrxvtMode = 1015,
286 kMouseSgrPixelsMode = 1016,
287 kAlternateScreen = 1049,
291enum class DSRMode : std::uint8_t {
309std::string Set(
const std::vector<DECMode>&
parameters) {
320 return CSI + std::to_string(
int(
ps)) +
"n";
323class CapturedMouseImpl :
public CapturedMouseInterface {
325 explicit CapturedMouseImpl(std::function<
void(
void)>
callback)
328 CapturedMouseImpl(
const CapturedMouseImpl&) =
delete;
329 CapturedMouseImpl(CapturedMouseImpl&&) =
delete;
330 CapturedMouseImpl& operator=(
const CapturedMouseImpl&) =
delete;
331 CapturedMouseImpl& operator=(CapturedMouseImpl&&) =
delete;
334 std::function<
void(
void)> callback_;
339 const auto time_delta = std::chrono::milliseconds(15);
341 out->Send(AnimationTask());
348ScreenInteractive::ScreenInteractive(
int dimx,
352 : Screen(dimx, dimy),
386 Dimension::Fullscreen,
399 Dimension::Fullscreen,
409 Dimension::TerminalOutput,
419 Dimension::FitComponent,
454 task_sender_->Send(std::move(
task));
467 if (animation_requested_) {
470 animation_requested_ =
true;
471 auto now = animation::Clock::now();
474 previous_animation_time_ =
now;
483 if (mouse_captured) {
486 mouse_captured =
true;
487 return std::make_unique<CapturedMouseImpl>(
488 [
this] { mouse_captured =
false; });
501bool ScreenInteractive::HasQuitted() {
506void ScreenInteractive::PreMain() {
511 suspended_screen_->ResetCursorPosition();
513 suspended_screen_->
dimx_ = 0;
514 suspended_screen_->
dimy_ = 0;
517 suspended_screen_->Uninstall();
524 previous_animation_time_ = animation::Clock::now();
528void ScreenInteractive::PostMain() {
530 ResetCursorPosition();
535 if (suspended_screen_) {
549 if (!use_alternative_screen_) {
551 std::cout << std::flush;
570 force_handle_ctrl_c_ =
force;
576 force_handle_ctrl_z_ =
force;
586void ScreenInteractive::Install() {
587 frame_valid_ =
false;
606 std::cout <<
"\033[?25h";
607 std::cout <<
"\033[" + std::to_string(cursor_reset_shape_) +
" q";
697 if (use_alternative_screen_) {
699 DECMode::kAlternateScreen,
709 enable({DECMode::kMouseVt200});
710 enable({DECMode::kMouseAnyEvent});
711 enable({DECMode::kMouseUrxvtMode});
712 enable({DECMode::kMouseSgrExtMode});
720 task_sender_ = task_receiver_->MakeSender();
722 std::thread(&
EventListener, &quit_, task_receiver_->MakeSender());
723 animation_listener_ =
728void ScreenInteractive::Uninstall() {
730 event_listener_.join();
731 animation_listener_.join();
740 if (task_receiver_->Receive(&
task)) {
749 while (task_receiver_->ReceiveNonBlocking(&
task)) {
761 using T = std::decay_t<
decltype(
arg)>;
765 if constexpr (std::is_same_v<T, Event>) {
766 if (
arg.is_cursor_position()) {
767 cursor_x_ =
arg.cursor_x();
768 cursor_y_ =
arg.cursor_y();
772 if (
arg.is_cursor_shape()) {
773 cursor_reset_shape_=
arg.cursor_shape();
777 if (
arg.is_mouse()) {
778 arg.mouse().x -= cursor_x_;
779 arg.mouse().y -= cursor_y_;
796 frame_valid_ =
false;
801 if constexpr (std::is_same_v<T, Closure>) {
807 if constexpr (std::is_same_v<T, AnimationTask>) {
808 if (!animation_requested_) {
812 animation_requested_ =
false;
815 previous_animation_time_ =
now;
819 frame_valid_ =
false;
838 switch (dimension_) {
839 case Dimension::Fixed:
843 case Dimension::TerminalOutput:
847 case Dimension::Fullscreen:
851 case Dimension::FitComponent:
858 ResetCursorPosition();
863 if ((
dimx <
dimx_) && !use_alternative_screen_) {
864 std::cout <<
"\033[J";
865 std::cout <<
"\033[H";
872 pixels_ = std::vector<std::vector<Pixel>>(
dimy, std::vector<Pixel>(
dimx));
880#if defined(FTXUI_MICROSOFT_TERMINAL_FALLBACK)
889 if (!use_alternative_screen_ && (i % 150 == 0)) {
895 if (!use_alternative_screen_ &&
896 (previous_frame_resized_ || i % 40 == 0)) {
900 previous_frame_resized_ =
resized;
909 set_cursor_position.clear();
910 reset_cursor_position.clear();
913 set_cursor_position +=
"\x1B[" + std::to_string(
dy) +
"A";
914 reset_cursor_position +=
"\x1B[" + std::to_string(
dy) +
"B";
918 set_cursor_position +=
"\x1B[" + std::to_string(
dx) +
"D";
919 reset_cursor_position +=
"\x1B[" + std::to_string(
dx) +
"C";
923 set_cursor_position +=
"\033[?25l";
925 set_cursor_position +=
"\033[?25h";
926 set_cursor_position +=
931 std::cout <<
ToString() << set_cursor_position;
938void ScreenInteractive::ResetCursorPosition() {
939 std::cout << reset_cursor_position;
940 reset_cursor_position =
"";
946 return [
this] {
Exit(); };
952 Post([
this] { ExitNow(); });
956void ScreenInteractive::ExitNow() {
958 task_sender_.reset();
962void ScreenInteractive::Signal(
int signal) {
972 ResetCursorPosition();
978 std::ignore = std::raise(
SIGTSTP);
std::vector< std::vector< Pixel > > pixels_
bool HasQuitted()
Whether the loop has quitted.
static void Signal(ScreenInteractive &s, int signal)
static ScreenInteractive TerminalOutput()
void Exit()
Exit the main loop.
static ScreenInteractive FixedSize(int dimx, int dimy)
void PostEvent(Event event)
Add an event to the main loop. It will be executed later, after every other scheduled events.
void Post(Task task)
Add a task to the main loop. It will be executed later, after every other scheduled tasks.
static ScreenInteractive FitComponent()
static ScreenInteractive Fullscreen()
static ScreenInteractive FullscreenPrimaryScreen()
static ScreenInteractive * Active()
Return the currently active screen, or null if none.
CapturedMouse CaptureMouse()
Try to get the unique lock about behing able to capture the mouse.
static ScreenInteractive FullscreenAlternateScreen()
void TrackMouse(bool enable=true)
Set whether mouse is tracked and events reported. called outside of the main loop....
void RequestAnimationFrame()
Add a task to draw the screen one more time, until all the animations are done.
Closure ExitLoopClosure()
Return a function to exit the main loop.
void ForceHandleCtrlC(bool force)
Force FTXUI to handle or not handle Ctrl-C, even if the component catches the Event::CtrlC.
void ForceHandleCtrlZ(bool force)
Force FTXUI to handle or not handle Ctrl-Z, even if the component catches the Event::CtrlZ.
Closure WithRestoredIO(Closure)
Decorate a function. It executes the same way, but with the currently active screen terminal hooks te...
std::string ToString() const
std::string ResetPosition(bool clear=false) const
Return a string to be printed in order to reset the cursor position to the beginning of the screen.
void Clear()
Clear all the pixel from the screen.
void SetFallbackSize(const Dimensions &fallbackSize)
Override terminal size in case auto-detection fails.
Dimensions Size()
Get the terminal size.
std::chrono::duration< float > Duration
std::chrono::time_point< Clock > TimePoint
void RequestAnimationFrame()
std::unique_ptr< CapturedMouseInterface > CapturedMouse
std::shared_ptr< T > Make(Args &&... args)
std::shared_ptr< ComponentBase > Component
std::string to_string(const std::wstring &s)
Convert a UTF8 std::string into a std::wstring.
Element select(Element)
Set the child to be the one selected among its siblings.
std::variant< Event, Closure, AnimationTask > Task
void Render(Screen &screen, const Element &element)
Display an element on a ftxui::Screen.
std::function< void()> Closure
Represent an event. It can be key press event, a terminal resize, or more ...
static Event Special(std::string)
An custom event whose meaning is defined by the user of the library.