mirror of
				https://github.com/ArthurSonzogni/FTXUI.git
				synced 2025-10-31 10:38:09 +08:00 
			
		
		
		
	Tweak implementation and documentation.
This commit is contained in:
		| @@ -1,5 +1,9 @@ | ||||
| # POSIX Piped Input in FTXUI | ||||
|  | ||||
| > [!WARNING] | ||||
| > This feature works only on Linux and macOS. It is not supported on | ||||
| > Windows and WebAssembly. | ||||
|  | ||||
| ## What is a POSIX Pipe? | ||||
|  | ||||
| A POSIX pipe is a way for two separate programs to communicate. One program sends its output directly as input to another program. Think of it like a one-way tube for data. | ||||
| @@ -40,7 +44,6 @@ auto screen = ScreenInteractive::Fullscreen(); | ||||
| screen.Loop(component); | ||||
| ``` | ||||
|  | ||||
| **Note:** This feature works only on Linux and macOS. It does nothing on Windows. | ||||
|  | ||||
| ## Turning Off Piped Input | ||||
|  | ||||
|   | ||||
| @@ -43,7 +43,7 @@ class ScreenInteractive : public Screen { | ||||
|   static ScreenInteractive TerminalOutput(); | ||||
|  | ||||
|   // Destructor. | ||||
|   ~ScreenInteractive(); | ||||
|   ~ScreenInteractive() override; | ||||
|  | ||||
|   // Options. Must be called before Loop(). | ||||
|   void TrackMouse(bool enable = true); | ||||
| @@ -101,6 +101,8 @@ class ScreenInteractive : public Screen { | ||||
|   void Draw(Component component); | ||||
|   void ResetCursorPosition(); | ||||
|  | ||||
|   void InstallPipedInputHandling(); | ||||
|  | ||||
|   void Signal(int signal); | ||||
|  | ||||
|   void FetchTerminalEvents(); | ||||
| @@ -118,6 +120,7 @@ class ScreenInteractive : public Screen { | ||||
|                     int dimx, | ||||
|                     int dimy, | ||||
|                     bool use_alternative_screen); | ||||
|  | ||||
|   const Dimension dimension_; | ||||
|   const bool use_alternative_screen_; | ||||
|  | ||||
| @@ -142,12 +145,8 @@ class ScreenInteractive : public Screen { | ||||
|   bool force_handle_ctrl_c_ = true; | ||||
|   bool force_handle_ctrl_z_ = true; | ||||
|  | ||||
| #if !defined(_WIN32) && !defined(__EMSCRIPTEN__) | ||||
|   // Piped input handling state (POSIX only) | ||||
|   bool handle_piped_input_ = true; | ||||
|   bool stdin_was_redirected_ = false; | ||||
|   int original_stdin_fd_ = -1; | ||||
| #endif | ||||
|  | ||||
|   // The style of the cursor to restore on exit. | ||||
|   int cursor_reset_shape_ = 1; | ||||
|   | ||||
| @@ -373,22 +373,16 @@ void ScreenInteractive::TrackMouse(bool enable) { | ||||
| } | ||||
|  | ||||
| /// @brief Enable or disable automatic piped input handling. | ||||
| /// When enabled, FTXUI will detect piped input and redirect stdin to /dev/tty | ||||
| /// When enabled, FTXUI will detect piped input and redirect stdin from /dev/tty | ||||
| /// for keyboard input, allowing applications to read piped data while still | ||||
| /// receiving interactive keyboard events. | ||||
| /// @param enable Whether to enable piped input handling. Default is true. | ||||
| /// @note This must be called before Loop(). | ||||
| /// @note This feature is enabled by default. | ||||
| /// @note This feature is only available on POSIX systems (Linux/macOS). | ||||
| #if !defined(_WIN32) && !defined(__EMSCRIPTEN__) | ||||
| void ScreenInteractive::HandlePipedInput(bool enable) { | ||||
|   handle_piped_input_ = enable; | ||||
| } | ||||
| #else | ||||
| void ScreenInteractive::HandlePipedInput(bool /*enable*/) { | ||||
|   // This feature is not supported on this platform. | ||||
| } | ||||
| #endif | ||||
|  | ||||
| /// @brief Add a task to the main loop. | ||||
| /// It will be executed later, after every other scheduled tasks. | ||||
| @@ -676,47 +670,58 @@ void ScreenInteractive::Install() { | ||||
|   // ensure it is fully applied: | ||||
|   Flush(); | ||||
|  | ||||
| #if !defined(_WIN32) && !defined(__EMSCRIPTEN__) | ||||
|   // Handle piped input redirection if explicitly enabled by the application. | ||||
|   // This allows applications to read data from stdin while still receiving | ||||
|   // keyboard input from the terminal for interactive use. | ||||
|   if (handle_piped_input_ && !stdin_was_redirected_ && !isatty(STDIN_FILENO)) { | ||||
|     // Save the current stdin so we can restore it later | ||||
|     original_stdin_fd_ = dup(STDIN_FILENO); | ||||
|     if (original_stdin_fd_ >= 0) { | ||||
|       // Redirect stdin to the controlling terminal for keyboard input | ||||
|       if (freopen("/dev/tty", "r", stdin) != nullptr) { | ||||
|         stdin_was_redirected_ = true; | ||||
|       } else { | ||||
|         // Failed to open /dev/tty (containers, headless systems, etc.) | ||||
|         // Clean up and continue without redirection | ||||
|         close(original_stdin_fd_); | ||||
|         original_stdin_fd_ = -1; | ||||
|       } | ||||
|     } | ||||
|     // If dup() failed, we silently continue without redirection | ||||
|   } | ||||
| #endif | ||||
|   // Redirect the true terminal to stdin, so that we can read keyboard input | ||||
|   // directly from stdin, even if the input is piped from a file or another | ||||
|   // process. | ||||
|   // | ||||
|   // TODO: Instead of redirecting stdin, we could define the file descriptor to | ||||
|   // read from, and use it in the TerminalInputParser. | ||||
|   InstallPipedInputHandling(); | ||||
|  | ||||
|   quit_ = false; | ||||
|  | ||||
|   PostAnimationTask(); | ||||
| } | ||||
|  | ||||
| void ScreenInteractive::InstallPipedInputHandling() { | ||||
| #if !defined(_WIN32) && !defined(__EMSCRIPTEN__) | ||||
|   // Handle piped input redirection if explicitly enabled by the application. | ||||
|   // This allows applications to read data from stdin while still receiving | ||||
|   // keyboard input from the terminal for interactive use. | ||||
|   if (!handle_piped_input_) { | ||||
|     return; | ||||
|   } | ||||
|  | ||||
|   // If stdin is a terminal, we don't need to redirect it. | ||||
|   if (isatty(STDIN_FILENO)) { | ||||
|     return; | ||||
|   } | ||||
|  | ||||
|   // Save the current stdin so we can restore it later. | ||||
|   int original_fd = dup(STDIN_FILENO); | ||||
|   if (original_fd < 0) { | ||||
|     return; | ||||
|   } | ||||
|  | ||||
|   // Redirect stdin to the controlling terminal for keyboard input. | ||||
|   if (std::freopen("/dev/tty", "r", stdin) == nullptr) { | ||||
|     // Failed to open /dev/tty (containers, headless systems, etc.) | ||||
|     // Clean up and continue without redirection | ||||
|     close(original_fd); | ||||
|     return; | ||||
|   } | ||||
|  | ||||
|   // Restore the original stdin file descriptor on exit. | ||||
|   on_exit_functions.emplace([=] { | ||||
|     dup2(original_fd, STDIN_FILENO); | ||||
|     close(original_fd); | ||||
|   }); | ||||
| #endif | ||||
| } | ||||
|  | ||||
| // private | ||||
| void ScreenInteractive::Uninstall() { | ||||
|   ExitNow(); | ||||
|    | ||||
| #if !defined(_WIN32) && !defined(__EMSCRIPTEN__) | ||||
|   // Restore stdin to its original state if we redirected it | ||||
|   if (stdin_was_redirected_ && original_stdin_fd_ >= 0) { | ||||
|     dup2(original_stdin_fd_, STDIN_FILENO); | ||||
|     close(original_stdin_fd_); | ||||
|     original_stdin_fd_ = -1; | ||||
|     stdin_was_redirected_ = false; | ||||
|   } | ||||
| #endif | ||||
|    | ||||
|   OnExit(); | ||||
| } | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 ArthurSonzogni
					ArthurSonzogni