mirror of
				https://github.com/ArthurSonzogni/FTXUI.git
				synced 2025-11-01 02:58:12 +08:00 
			
		
		
		
	Parse mouse events.
This commit is contained in:
		| @@ -23,10 +23,35 @@ class DrawKey : public Component { | |||||||
|         code += L" " + std::to_wstring((unsigned int)it); |         code += L" " + std::to_wstring((unsigned int)it); | ||||||
|  |  | ||||||
|       code = L"(" + code + L" ) -> "; |       code = L"(" + code + L" ) -> "; | ||||||
|       if (keys[i].is_character()) |       if (keys[i].is_character()) { | ||||||
|         code += keys[i].character(); |         code += std::wstring(L"character(") + keys[i].character() + L")"; | ||||||
|       else |       } 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)"; |         code += L"(special)"; | ||||||
|  |       } | ||||||
|       children.push_back(text(code)); |       children.push_back(text(code)); | ||||||
|     } |     } | ||||||
|     return window(text(L"keys"), vbox(std::move(children))); |     return window(text(L"keys"), vbox(std::move(children))); | ||||||
|   | |||||||
| @@ -26,8 +26,14 @@ struct Event { | |||||||
|   static Event Character(char); |   static Event Character(char); | ||||||
|   static Event Character(wchar_t); |   static Event Character(wchar_t); | ||||||
|  |  | ||||||
|   static Event Character(const std::string&); |   static Event Character(std::string); | ||||||
|   static Event Special(const 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 --- |   // --- Arrow --- | ||||||
|   static const Event ArrowLeft; |   static const Event ArrowLeft; | ||||||
| @@ -48,17 +54,47 @@ struct Event { | |||||||
|   static Event Custom; |   static Event Custom; | ||||||
|  |  | ||||||
|   //--- Method section --------------------------------------------------------- |   //--- Method section --------------------------------------------------------- | ||||||
|   bool is_character() const { return is_character_; } |   bool is_character() const { return type_ == Type::Character;} | ||||||
|   wchar_t character() const { return 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_; } |   const std::string& input() const { return input_; } | ||||||
|  |  | ||||||
|   bool operator==(const Event& other) const { return input_ == other.input_; } |   bool operator==(const Event& other) const { return input_ == other.input_; } | ||||||
|  |  | ||||||
|   //--- State section ---------------------------------------------------------- |   //--- State section ---------------------------------------------------------- | ||||||
|  private: |  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_; |   std::string input_; | ||||||
|   bool is_character_ = false; |  | ||||||
|   wchar_t character_ = U'?'; |  | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
| @@ -6,11 +6,11 @@ | |||||||
| namespace ftxui { | namespace ftxui { | ||||||
|  |  | ||||||
| // static | // static | ||||||
| Event Event::Character(const std::string& input) { | Event Event::Character(std::string input) { | ||||||
|   Event event; |   Event event; | ||||||
|   event.input_ = input; |  | ||||||
|   event.is_character_ = true; |  | ||||||
|   event.character_ = to_wstring(input)[0]; |   event.character_ = to_wstring(input)[0]; | ||||||
|  |   event.input_ = std::move(input); | ||||||
|  |   event.type_ = Type::Character; | ||||||
|   return event; |   return event; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -23,13 +23,67 @@ Event Event::Character(char c) { | |||||||
| Event Event::Character(wchar_t c) { | Event Event::Character(wchar_t c) { | ||||||
|   Event event; |   Event event; | ||||||
|   event.input_ = {(char)c}; |   event.input_ = {(char)c}; | ||||||
|   event.is_character_ = true; |   event.type_ = Type::Character; | ||||||
|   event.character_ = c; |   event.character_ = c; | ||||||
|   return event; |   return event; | ||||||
| } | } | ||||||
|  |  | ||||||
| // static | // 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 event; | ||||||
|   event.input_ = std::move(input); |   event.input_ = std::move(input); | ||||||
|   return event; |   return event; | ||||||
|   | |||||||
| @@ -155,8 +155,8 @@ static const char DISABLE_LINE_WRAP[] = "\x1B[7l"; | |||||||
| static const char USE_ALTERNATIVE_SCREEN[] = "\x1B[?1049h"; | static const char USE_ALTERNATIVE_SCREEN[] = "\x1B[?1049h"; | ||||||
| static const char USE_NORMAL_SCREEN[] = "\x1B[?1049l"; | static const char USE_NORMAL_SCREEN[] = "\x1B[?1049l"; | ||||||
|  |  | ||||||
| static const char ENABLE_MOUSE[] = "\x1B[?1000;1006;1015h"; | static const char ENABLE_MOUSE[] = "\x1B[?1000;1003;1006;1015h"; | ||||||
| static const char DISABLE_MOUSE[] = "\x1B[?1000;10006;1015l"; | static const char DISABLE_MOUSE[] = "\x1B[?1000;1003;10006;1015l"; | ||||||
|  |  | ||||||
| using SignalHandler = void(int); | using SignalHandler = void(int); | ||||||
| std::stack<std::function<void()>> on_exit_functions; | std::stack<std::function<void()>> on_exit_functions; | ||||||
|   | |||||||
| @@ -30,28 +30,56 @@ bool TerminalInputParser::Eat() { | |||||||
|   return position_ < (int)pending_.size(); |   return position_ < (int)pending_.size(); | ||||||
| } | } | ||||||
|  |  | ||||||
| void TerminalInputParser::Send(TerminalInputParser::Type type) { | void TerminalInputParser::Send(TerminalInputParser::Output output) { | ||||||
|   switch (type) { |   switch (output.type) { | ||||||
|     case UNCOMPLETED: |     case UNCOMPLETED: | ||||||
|       return; |       return; | ||||||
|  |  | ||||||
|     case DROP: |     case DROP: | ||||||
|       pending_.clear(); |       break; | ||||||
|       return; |  | ||||||
|  |  | ||||||
|     case CHARACTER: |     case CHARACTER: | ||||||
|       out_->Send(Event::Character(std::move(pending_))); |       out_->Send(Event::Character(std::move(pending_))); | ||||||
|       pending_.clear(); |       break; | ||||||
|       return; |  | ||||||
|  |  | ||||||
|     case SPECIAL: |     case SPECIAL: | ||||||
|       out_->Send(Event::Special(std::move(pending_))); |       out_->Send(Event::Special(std::move(pending_))); | ||||||
|       pending_.clear(); |       break; | ||||||
|       return; |  | ||||||
|  |     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()) |   if (!Eat()) | ||||||
|     return UNCOMPLETED; |     return UNCOMPLETED; | ||||||
|  |  | ||||||
| @@ -75,7 +103,7 @@ TerminalInputParser::Type TerminalInputParser::Parse() { | |||||||
|   return ParseUTF8(); |   return ParseUTF8(); | ||||||
| } | } | ||||||
|  |  | ||||||
| TerminalInputParser::Type TerminalInputParser::ParseUTF8() { | TerminalInputParser::Output TerminalInputParser::ParseUTF8() { | ||||||
|   unsigned char head = static_cast<unsigned char>(Current()); |   unsigned char head = static_cast<unsigned char>(Current()); | ||||||
|   for (int i = 0; i < 3; ++i, head <<= 1) { |   for (int i = 0; i < 3; ++i, head <<= 1) { | ||||||
|     if ((head & 0b11000000) != 0b11000000) |     if ((head & 0b11000000) != 0b11000000) | ||||||
| @@ -86,7 +114,7 @@ TerminalInputParser::Type TerminalInputParser::ParseUTF8() { | |||||||
|   return CHARACTER; |   return CHARACTER; | ||||||
| } | } | ||||||
|  |  | ||||||
| TerminalInputParser::Type TerminalInputParser::ParseESC() { | TerminalInputParser::Output TerminalInputParser::ParseESC() { | ||||||
|   if (!Eat()) |   if (!Eat()) | ||||||
|     return UNCOMPLETED; |     return UNCOMPLETED; | ||||||
|   switch (Current()) { |   switch (Current()) { | ||||||
| @@ -103,7 +131,7 @@ TerminalInputParser::Type TerminalInputParser::ParseESC() { | |||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
| TerminalInputParser::Type TerminalInputParser::ParseDCS() { | TerminalInputParser::Output TerminalInputParser::ParseDCS() { | ||||||
|   // Parse until the string terminator ST. |   // Parse until the string terminator ST. | ||||||
|   while (1) { |   while (1) { | ||||||
|     if (!Eat()) |     if (!Eat()) | ||||||
| @@ -122,19 +150,35 @@ TerminalInputParser::Type TerminalInputParser::ParseDCS() { | |||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
| TerminalInputParser::Type TerminalInputParser::ParseCSI() { | TerminalInputParser::Output TerminalInputParser::ParseCSI() { | ||||||
|  |   int argument; | ||||||
|  |   std::vector<int> arguments; | ||||||
|   while (true) { |   while (true) { | ||||||
|     if (!Eat()) |     if (!Eat()) | ||||||
|       return UNCOMPLETED; |       return UNCOMPLETED; | ||||||
|  |  | ||||||
|     if (Current() >= '0' && Current() <= '9') |     if (Current() >= '0' && Current() <= '9') { | ||||||
|  |       argument *= 10; | ||||||
|  |       argument += int(Current() - '0'); | ||||||
|       continue; |       continue; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     if (Current() == ';') |     if (Current() == ';') { | ||||||
|  |       arguments.push_back(argument); | ||||||
|  |       argument = 0; | ||||||
|       continue; |       continue; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     if (Current() >= ' ' && Current() <= '~') |     if (Current() >= ' ' && Current() <= '~') { | ||||||
|       return SPECIAL; |       arguments.push_back(argument); | ||||||
|  |       argument = 0; | ||||||
|  |       switch (Current()) { | ||||||
|  |         case 'M': | ||||||
|  |           return ParseMouse(std::move(arguments)); | ||||||
|  |         default: | ||||||
|  |           return SPECIAL; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|     // Invalid ESC in CSI. |     // Invalid ESC in CSI. | ||||||
|     if (Current() == '\x1B') |     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. |   // Parse until the string terminator ST. | ||||||
|   while (true) { |   while (true) { | ||||||
|     if (!Eat()) |     if (!Eat()) | ||||||
| @@ -156,4 +200,28 @@ TerminalInputParser::Type TerminalInputParser::ParseOSC() { | |||||||
|     return SPECIAL; |     return SPECIAL; | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | TerminalInputParser::Output TerminalInputParser::ParseMouse( | ||||||
|  |     std::vector<int> 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 | }  // namespace ftxui | ||||||
|   | |||||||
| @@ -20,18 +20,42 @@ class TerminalInputParser { | |||||||
|   bool Eat(); |   bool Eat(); | ||||||
|  |  | ||||||
|   enum Type { |   enum Type { | ||||||
|     UNCOMPLETED = 0, |     UNCOMPLETED, | ||||||
|     DROP = 1, |     DROP, | ||||||
|     CHARACTER = 2, |     CHARACTER, | ||||||
|     SPECIAL = 3, |     SPECIAL, | ||||||
|  |     MOUSE_UP, | ||||||
|  |     MOUSE_MOVE, | ||||||
|  |     MOUSE_LEFT_DOWN, | ||||||
|  |     MOUSE_LEFT_MOVE, | ||||||
|  |     MOUSE_RIGHT_DOWN, | ||||||
|  |     MOUSE_RIGHT_MOVE, | ||||||
|   }; |   }; | ||||||
|   void Send(Type type); |  | ||||||
|   Type Parse(); |   struct Mouse { | ||||||
|   Type ParseUTF8(); |     int x; | ||||||
|   Type ParseESC(); |     int y; | ||||||
|   Type ParseDCS(); |     Mouse(int x, int y) : x(x), y(y) {} | ||||||
|   Type ParseCSI(); |   }; | ||||||
|   Type ParseOSC(); |  | ||||||
|  |   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<int> arguments); | ||||||
|  |  | ||||||
|   Sender<Event> out_; |   Sender<Event> out_; | ||||||
|   int position_ = -1; |   int position_ = -1; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 ArthurSonzogni
					ArthurSonzogni