From cbd13499ae32f588486afb59cb7ae2fa143deaa1 Mon Sep 17 00:00:00 2001 From: ArthurSonzogni Date: Sun, 18 Apr 2021 18:32:38 +0200 Subject: [PATCH] Parse mouse events. --- examples/util/print_key_press.cpp | 31 +++++- include/ftxui/component/event.hpp | 46 +++++++- src/ftxui/component/event.cpp | 64 ++++++++++- src/ftxui/component/screen_interactive.cpp | 4 +- src/ftxui/component/terminal_input_parser.cpp | 104 +++++++++++++++--- src/ftxui/component/terminal_input_parser.hpp | 46 ++++++-- 6 files changed, 251 insertions(+), 44 deletions(-) diff --git a/examples/util/print_key_press.cpp b/examples/util/print_key_press.cpp index 60c36da..35ef936 100644 --- a/examples/util/print_key_press.cpp +++ b/examples/util/print_key_press.cpp @@ -23,10 +23,35 @@ class DrawKey : public Component { code += L" " + std::to_wstring((unsigned int)it); code = L"(" + code + L" ) -> "; - if (keys[i].is_character()) - code += keys[i].character(); - else + if (keys[i].is_character()) { + code += std::wstring(L"character(") + keys[i].character() + L")"; + } else if (keys[i].is_mouse_move()) { + code += L"mouse_move(" + // + std::to_wstring(keys[i].mouse_x()) + L"," + + std::to_wstring(keys[i].mouse_y()) + L")"; + } else if (keys[i].is_mouse_up()) { + code += L"mouse_up(" + // + std::to_wstring(keys[i].mouse_x()) + L"," + + std::to_wstring(keys[i].mouse_y()) + L")"; + } else if (keys[i].is_mouse_left_down()) { + code += L"mouse_left_down(" + // + std::to_wstring(keys[i].mouse_x()) + L"," + + std::to_wstring(keys[i].mouse_y()) + L")"; + } else if (keys[i].is_mouse_left_move()) { + code += L"mouse_left_move(" + // + std::to_wstring(keys[i].mouse_x()) + L"," + + std::to_wstring(keys[i].mouse_y()) + L")"; + } else if (keys[i].is_mouse_right_down()) { + code += L"mouse_right_down(" + // + std::to_wstring(keys[i].mouse_x()) + L"," + + std::to_wstring(keys[i].mouse_y()) + L")"; + } else if (keys[i].is_mouse_right_move()) { + code += L"mouse_right_move(" + // + std::to_wstring(keys[i].mouse_x()) + L"," + + std::to_wstring(keys[i].mouse_y()) + L")"; + } else { code += L"(special)"; + } children.push_back(text(code)); } return window(text(L"keys"), vbox(std::move(children))); diff --git a/include/ftxui/component/event.hpp b/include/ftxui/component/event.hpp index 14e826a..40ab123 100644 --- a/include/ftxui/component/event.hpp +++ b/include/ftxui/component/event.hpp @@ -26,8 +26,14 @@ struct Event { static Event Character(char); static Event Character(wchar_t); - static Event Character(const std::string&); - static Event Special(const std::string&); + static Event Character(std::string); + static Event Special(std::string); + static Event MouseMove(std::string, int x, int y); + static Event MouseUp(std::string, int x, int y); + static Event MouseLeftMove(std::string, int x, int y); + static Event MouseLeftDown(std::string, int x, int y); + static Event MouseRightMove(std::string, int x, int y); + static Event MouseRightDown(std::string, int x, int y); // --- Arrow --- static const Event ArrowLeft; @@ -48,17 +54,47 @@ struct Event { static Event Custom; //--- Method section --------------------------------------------------------- - bool is_character() const { return is_character_; } + bool is_character() const { return type_ == Type::Character;} wchar_t character() const { return character_; } + + bool is_mouse_left_down() const { return type_ == Type::MouseLeftDown; } + bool is_mouse_left_move() const { return type_ == Type::MouseLeftMove; } + bool is_mouse_right_down() const { return type_ == Type::MouseRightDown; } + bool is_mouse_right_move() const { return type_ == Type::MouseRightMove; } + bool is_mouse_up() const { return type_ == Type::MouseUp; } + bool is_mouse_move() const { return type_ == Type::MouseMove; } + int mouse_x() const { return mouse_.x; } + int mouse_y() const { return mouse_.y; } + const std::string& input() const { return input_; } bool operator==(const Event& other) const { return input_ == other.input_; } //--- State section ---------------------------------------------------------- private: + enum class Type { + Unknown, + Character, + MouseMove, + MouseUp, + MouseLeftDown, + MouseLeftMove, + MouseRightDown, + MouseRightMove, + }; + + struct Mouse { + int x; + int y; + }; + + Type type_ = Type::Unknown; + + union { + wchar_t character_ = U'?'; + Mouse mouse_; + }; std::string input_; - bool is_character_ = false; - wchar_t character_ = U'?'; }; diff --git a/src/ftxui/component/event.cpp b/src/ftxui/component/event.cpp index 29fc9c1..5dc9e77 100644 --- a/src/ftxui/component/event.cpp +++ b/src/ftxui/component/event.cpp @@ -6,11 +6,11 @@ namespace ftxui { // static -Event Event::Character(const std::string& input) { +Event Event::Character(std::string input) { Event event; - event.input_ = input; - event.is_character_ = true; event.character_ = to_wstring(input)[0]; + event.input_ = std::move(input); + event.type_ = Type::Character; return event; } @@ -23,13 +23,67 @@ Event Event::Character(char c) { Event Event::Character(wchar_t c) { Event event; event.input_ = {(char)c}; - event.is_character_ = true; + event.type_ = Type::Character; event.character_ = c; return event; } // static -Event Event::Special(const std::string& input) { +Event Event::MouseMove(std::string input, int x, int y) { + Event event; + event.input_ = std::move(input); + event.type_ = Type::MouseMove; + event.mouse_ = {x, y}; + return event; +} + +// static +Event Event::MouseUp(std::string input, int x, int y) { + Event event; + event.input_ = std::move(input); + event.type_ = Type::MouseUp; + event.mouse_ = {x, y}; + return event; +} + +// static +Event Event::MouseLeftDown(std::string input, int x, int y) { + Event event; + event.input_ = std::move(input); + event.type_ = Type::MouseLeftDown; + event.mouse_ = {x, y}; + return event; +} + +// static +Event Event::MouseLeftMove(std::string input, int x, int y) { + Event event; + event.input_ = std::move(input); + event.type_ = Type::MouseLeftMove; + event.mouse_ = {x, y}; + return event; +} + +// static +Event Event::MouseRightDown(std::string input, int x, int y) { + Event event; + event.input_ = std::move(input); + event.type_ = Type::MouseRightDown; + event.mouse_ = {x, y}; + return event; +} + +// static +Event Event::MouseRightMove(std::string input, int x, int y) { + Event event; + event.input_ = std::move(input); + event.type_ = Type::MouseRightMove; + event.mouse_ = {x, y}; + return event; +} + +// static +Event Event::Special(std::string input) { Event event; event.input_ = std::move(input); return event; diff --git a/src/ftxui/component/screen_interactive.cpp b/src/ftxui/component/screen_interactive.cpp index 4c3eb29..36c4c54 100644 --- a/src/ftxui/component/screen_interactive.cpp +++ b/src/ftxui/component/screen_interactive.cpp @@ -155,8 +155,8 @@ static const char DISABLE_LINE_WRAP[] = "\x1B[7l"; static const char USE_ALTERNATIVE_SCREEN[] = "\x1B[?1049h"; static const char USE_NORMAL_SCREEN[] = "\x1B[?1049l"; -static const char ENABLE_MOUSE[] = "\x1B[?1000;1006;1015h"; -static const char DISABLE_MOUSE[] = "\x1B[?1000;10006;1015l"; +static const char ENABLE_MOUSE[] = "\x1B[?1000;1003;1006;1015h"; +static const char DISABLE_MOUSE[] = "\x1B[?1000;1003;10006;1015l"; using SignalHandler = void(int); std::stack> on_exit_functions; diff --git a/src/ftxui/component/terminal_input_parser.cpp b/src/ftxui/component/terminal_input_parser.cpp index 78e0fdd..de73bd5 100644 --- a/src/ftxui/component/terminal_input_parser.cpp +++ b/src/ftxui/component/terminal_input_parser.cpp @@ -30,28 +30,56 @@ bool TerminalInputParser::Eat() { return position_ < (int)pending_.size(); } -void TerminalInputParser::Send(TerminalInputParser::Type type) { - switch (type) { +void TerminalInputParser::Send(TerminalInputParser::Output output) { + switch (output.type) { case UNCOMPLETED: return; case DROP: - pending_.clear(); - return; + break; case CHARACTER: out_->Send(Event::Character(std::move(pending_))); - pending_.clear(); - return; + break; case SPECIAL: out_->Send(Event::Special(std::move(pending_))); - pending_.clear(); - return; + break; + + case MOUSE_MOVE: + out_->Send( + Event::MouseMove(std::move(pending_), output.mouse.x, output.mouse.y)); + break; + + case MOUSE_UP: + out_->Send( + Event::MouseUp(std::move(pending_), output.mouse.x, output.mouse.y)); + break; + + case MOUSE_LEFT_DOWN: + out_->Send(Event::MouseLeftDown(std::move(pending_), output.mouse.x, + output.mouse.y)); + break; + + case MOUSE_LEFT_MOVE: + out_->Send(Event::MouseLeftMove(std::move(pending_), output.mouse.x, + output.mouse.y)); + break; + + case MOUSE_RIGHT_DOWN: + out_->Send(Event::MouseRightDown(std::move(pending_), output.mouse.x, + output.mouse.y)); + break; + + case MOUSE_RIGHT_MOVE: + out_->Send(Event::MouseRightMove(std::move(pending_), output.mouse.x, + output.mouse.y)); + break; } + pending_.clear(); } -TerminalInputParser::Type TerminalInputParser::Parse() { +TerminalInputParser::Output TerminalInputParser::Parse() { if (!Eat()) return UNCOMPLETED; @@ -75,7 +103,7 @@ TerminalInputParser::Type TerminalInputParser::Parse() { return ParseUTF8(); } -TerminalInputParser::Type TerminalInputParser::ParseUTF8() { +TerminalInputParser::Output TerminalInputParser::ParseUTF8() { unsigned char head = static_cast(Current()); for (int i = 0; i < 3; ++i, head <<= 1) { if ((head & 0b11000000) != 0b11000000) @@ -86,7 +114,7 @@ TerminalInputParser::Type TerminalInputParser::ParseUTF8() { return CHARACTER; } -TerminalInputParser::Type TerminalInputParser::ParseESC() { +TerminalInputParser::Output TerminalInputParser::ParseESC() { if (!Eat()) return UNCOMPLETED; switch (Current()) { @@ -103,7 +131,7 @@ TerminalInputParser::Type TerminalInputParser::ParseESC() { } } -TerminalInputParser::Type TerminalInputParser::ParseDCS() { +TerminalInputParser::Output TerminalInputParser::ParseDCS() { // Parse until the string terminator ST. while (1) { if (!Eat()) @@ -122,19 +150,35 @@ TerminalInputParser::Type TerminalInputParser::ParseDCS() { } } -TerminalInputParser::Type TerminalInputParser::ParseCSI() { +TerminalInputParser::Output TerminalInputParser::ParseCSI() { + int argument; + std::vector arguments; while (true) { if (!Eat()) return UNCOMPLETED; - if (Current() >= '0' && Current() <= '9') + if (Current() >= '0' && Current() <= '9') { + argument *= 10; + argument += int(Current() - '0'); continue; + } - if (Current() == ';') + if (Current() == ';') { + arguments.push_back(argument); + argument = 0; continue; + } - if (Current() >= ' ' && Current() <= '~') - return SPECIAL; + if (Current() >= ' ' && Current() <= '~') { + arguments.push_back(argument); + argument = 0; + switch (Current()) { + case 'M': + return ParseMouse(std::move(arguments)); + default: + return SPECIAL; + } + } // Invalid ESC in CSI. if (Current() == '\x1B') @@ -142,7 +186,7 @@ TerminalInputParser::Type TerminalInputParser::ParseCSI() { } } -TerminalInputParser::Type TerminalInputParser::ParseOSC() { +TerminalInputParser::Output TerminalInputParser::ParseOSC() { // Parse until the string terminator ST. while (true) { if (!Eat()) @@ -156,4 +200,28 @@ TerminalInputParser::Type TerminalInputParser::ParseOSC() { return SPECIAL; } } + +TerminalInputParser::Output TerminalInputParser::ParseMouse( + std::vector arguments) { + if (arguments.size() != 3) + return SPECIAL; + switch(arguments[0]) { + case 32: + return Output(MOUSE_LEFT_DOWN, arguments[1], arguments[2]); + case 64: + return Output(MOUSE_LEFT_MOVE, arguments[1], arguments[2]); + + case 34: + return Output(MOUSE_RIGHT_DOWN, arguments[1], arguments[2]); + case 66: + return Output(MOUSE_RIGHT_MOVE, arguments[1], arguments[2]); + + case 35: + return Output(MOUSE_UP, arguments[1], arguments[2]); + case 67: + return Output(MOUSE_MOVE, arguments[1], arguments[2]); + } + return SPECIAL; +} + } // namespace ftxui diff --git a/src/ftxui/component/terminal_input_parser.hpp b/src/ftxui/component/terminal_input_parser.hpp index ac0df24..72fc095 100644 --- a/src/ftxui/component/terminal_input_parser.hpp +++ b/src/ftxui/component/terminal_input_parser.hpp @@ -20,18 +20,42 @@ class TerminalInputParser { bool Eat(); enum Type { - UNCOMPLETED = 0, - DROP = 1, - CHARACTER = 2, - SPECIAL = 3, + UNCOMPLETED, + DROP, + CHARACTER, + SPECIAL, + MOUSE_UP, + MOUSE_MOVE, + MOUSE_LEFT_DOWN, + MOUSE_LEFT_MOVE, + MOUSE_RIGHT_DOWN, + MOUSE_RIGHT_MOVE, }; - void Send(Type type); - Type Parse(); - Type ParseUTF8(); - Type ParseESC(); - Type ParseDCS(); - Type ParseCSI(); - Type ParseOSC(); + + struct Mouse { + int x; + int y; + Mouse(int x, int y) : x(x), y(y) {} + }; + + struct Output { + Type type; + union { + Mouse mouse; + }; + + Output(Type type) : type(type) {} + Output(Type type, int x, int y) : type(type), mouse(x, y) {} + }; + + void Send(Output type); + Output Parse(); + Output ParseUTF8(); + Output ParseESC(); + Output ParseDCS(); + Output ParseCSI(); + Output ParseOSC(); + Output ParseMouse(std::vector arguments); Sender out_; int position_ = -1;