mirror of
https://github.com/ArthurSonzogni/FTXUI.git
synced 2025-07-30 01:11:14 +08:00
Support for CTRL Z
This commit is contained in:
parent
5fc51b557e
commit
2b73998d56
@ -6,6 +6,10 @@ current (development)
|
||||
|
||||
### Component
|
||||
- Feature: Add support for raw input. Allowing more keys to be detected.
|
||||
- Feature: Add `ScreenInteractive::ForceHandleCtrlC(false)` to allow component
|
||||
to fully override the default `Ctrl+C` handler.
|
||||
- Feature: Add `ScreenInteractive::ForceHandleCtrlZ(false)` to allow component
|
||||
to fully override the default `Ctrl+Z` handler.
|
||||
- Feature: Add `Mouse::WeelLeft` and `Mouse::WeelRight` events on supported
|
||||
terminals.
|
||||
- Feature: Add `Event::DebugString()`.
|
||||
|
@ -59,6 +59,15 @@ class ScreenInteractive : public Screen {
|
||||
// temporarily uninstalled.
|
||||
Closure WithRestoredIO(Closure);
|
||||
|
||||
// FTXUI implements handlers for Ctrl-C and Ctrl-Z. By default, these handlers
|
||||
// are executed, even if the component catches the event. This avoid users
|
||||
// handling every event to be trapped in the application. However, in some
|
||||
// cases, the application may want to handle these events itself. In this case,
|
||||
// the application can force FTXUI to not handle these events by calling the
|
||||
// following functions with force=true.
|
||||
void ForceHandleCtrlC(bool force);
|
||||
void ForceHandleCtrlZ(bool force);
|
||||
|
||||
private:
|
||||
void ExitNow();
|
||||
|
||||
@ -114,6 +123,9 @@ class ScreenInteractive : public Screen {
|
||||
|
||||
bool frame_valid_ = false;
|
||||
|
||||
bool force_handle_ctrl_c_ = true;
|
||||
bool force_handle_ctrl_z_ = true;
|
||||
|
||||
// The style of the cursor to restore on exit.
|
||||
int cursor_reset_shape_ = 1;
|
||||
|
||||
|
@ -559,6 +559,19 @@ Closure ScreenInteractive::WithRestoredIO(Closure fn) { // NOLINT
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/// @brief Force FTXUI to handle or not handle Ctrl-C, even if the component
|
||||
/// catches the Event::CtrlC.
|
||||
void ScreenInteractive::ForceHandleCtrlC(bool force) {
|
||||
force_handle_ctrl_c_ = force;
|
||||
}
|
||||
|
||||
/// @brief Force FTXUI to handle or not handle Ctrl-Z, even if the component
|
||||
/// catches the Event::CtrlZ.
|
||||
void ScreenInteractive::ForceHandleCtrlZ(bool force) {
|
||||
force_handle_ctrl_z_ = force;
|
||||
}
|
||||
|
||||
/// @brief Return the currently active screen, or null if none.
|
||||
// static
|
||||
ScreenInteractive* ScreenInteractive::Active() {
|
||||
@ -657,7 +670,7 @@ void ScreenInteractive::Install() {
|
||||
// - C-C => INTR
|
||||
// - C-d => QUIT
|
||||
terminal.c_lflag &= ~IEXTEN; // Disable extended input processing
|
||||
terminal.c_cflag |= (CS8); // 8 bits per byte
|
||||
terminal.c_cflag |= CS8; // 8 bits per byte
|
||||
|
||||
terminal.c_cc[VMIN] = 0; // Minimum number of characters for non-canonical
|
||||
// read.
|
||||
@ -765,13 +778,15 @@ void ScreenInteractive::HandleTask(Component component, Task& task) {
|
||||
|
||||
const bool handled = component->OnEvent(arg);
|
||||
|
||||
if (arg == Event::CtrlC) {
|
||||
Exit();
|
||||
if (arg == Event::CtrlC && (!handled || force_handle_ctrl_c_)) {
|
||||
RecordSignal(SIGABRT);
|
||||
}
|
||||
|
||||
if (arg == Event::CtrlZ) {
|
||||
// How to handle SIGTSTP manually?
|
||||
#if !defined(_WIN32)
|
||||
if (arg == Event::CtrlZ && (!handled || force_handle_ctrl_z_)) {
|
||||
RecordSignal(SIGTSTP);
|
||||
}
|
||||
#endif
|
||||
|
||||
frame_valid_ = false;
|
||||
return;
|
||||
|
@ -64,4 +64,71 @@ TEST(ScreenInteractive, PostTaskToNonActive) {
|
||||
screen.Post([] {});
|
||||
}
|
||||
|
||||
TEST(ScreenInteractive, CtrlC) {
|
||||
auto screen = ScreenInteractive::FitComponent();
|
||||
bool called = false;
|
||||
auto component = Renderer([&] {
|
||||
if (!called) {
|
||||
called = true;
|
||||
screen.PostEvent(Event::CtrlC);
|
||||
}
|
||||
return text("");
|
||||
});
|
||||
screen.Loop(component);
|
||||
}
|
||||
|
||||
TEST(ScreenInteractive, CtrlC_Forced) {
|
||||
auto screen = ScreenInteractive::FitComponent();
|
||||
screen.ForceHandleCtrlC(true);
|
||||
auto component = Renderer([&] {
|
||||
screen.PostEvent(Event::CtrlC);
|
||||
return text("");
|
||||
});
|
||||
|
||||
int ctrl_c_count = 0;
|
||||
component |= CatchEvent([&](Event event) {
|
||||
if (event != Event::CtrlC) {
|
||||
return false;
|
||||
}
|
||||
|
||||
++ctrl_c_count;
|
||||
|
||||
if (ctrl_c_count == 100) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
screen.Loop(component);
|
||||
|
||||
ASSERT_LE(ctrl_c_count, 50);
|
||||
}
|
||||
|
||||
TEST(ScreenInteractive, CtrlC_NotForced) {
|
||||
auto screen = ScreenInteractive::FitComponent();
|
||||
screen.ForceHandleCtrlC(false);
|
||||
auto component = Renderer([&] {
|
||||
screen.PostEvent(Event::CtrlC);
|
||||
return text("");
|
||||
});
|
||||
|
||||
int ctrl_c_count = 0;
|
||||
component |= CatchEvent([&](Event event) {
|
||||
if (event != Event::CtrlC) {
|
||||
return false;
|
||||
}
|
||||
|
||||
++ctrl_c_count;
|
||||
|
||||
if (ctrl_c_count == 100) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
screen.Loop(component);
|
||||
|
||||
ASSERT_GE(ctrl_c_count, 50);
|
||||
}
|
||||
|
||||
} // namespace ftxui
|
||||
|
@ -170,15 +170,8 @@ TerminalInputParser::Output TerminalInputParser::Parse() {
|
||||
return UNCOMPLETED;
|
||||
}
|
||||
|
||||
switch (Current()) {
|
||||
case 24: // CAN NOLINT
|
||||
case 26: // SUB NOLINT
|
||||
return DROP;
|
||||
|
||||
case '\x1B':
|
||||
if (Current() == '\x1B') {
|
||||
return ParseESC();
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (Current() < 32) { // C0 NOLINT
|
||||
|
Loading…
Reference in New Issue
Block a user