mirror of
				https://github.com/ArthurSonzogni/FTXUI.git
				synced 2025-11-04 13:38:14 +08:00 
			
		
		
		
	Parse mouse events.
This commit is contained in:
		@@ -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() <= '~')
 | 
			
		||||
      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<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