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"(" + 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))); | ||||
|   | ||||
| @@ -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: | ||||
|   std::string input_; | ||||
|   bool is_character_ = false; | ||||
|   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_; | ||||
| }; | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -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; | ||||
|   | ||||
| @@ -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<std::function<void()>> on_exit_functions; | ||||
|   | ||||
| @@ -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<unsigned char>(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<int> 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() <= '~') | ||||
|     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<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 | ||||
|   | ||||
| @@ -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<int> arguments); | ||||
|  | ||||
|   Sender<Event> out_; | ||||
|   int position_ = -1; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 ArthurSonzogni
					ArthurSonzogni