27 {std::string({8}), std::string({127})},
50 {
"\x1B[1~",
"\x1B[H"},
51 {
"\x1B[4~",
"\x1B[F"},
60 {
"\x1B[[A",
"\x1BOP"},
61 {
"\x1B[[B",
"\x1BOQ"},
62 {
"\x1B[[C",
"\x1BOR"},
63 {
"\x1B[[D",
"\x1BOS"},
64 {
"\x1B[[E",
"\x1B[15~"},
67 {
"\x1B[11~",
"\x1BOP"},
68 {
"\x1B[12~",
"\x1BOQ"},
69 {
"\x1B[13~",
"\x1BOR"},
70 {
"\x1B[14~",
"\x1BOS"},
73 {
"\x1BOt",
"\x1B[15~"},
74 {
"\x1BOu",
"\x1B[17~"},
75 {
"\x1BOv",
"\x1B[18~"},
76 {
"\x1BOl",
"\x1B[19~"},
77 {
"\x1BOw",
"\x1B[20~"},
78 {
"\x1BOx",
"\x1B[21~"},
85 {
"\x1B[Q",
"\x1B[15~"},
86 {
"\x1B[R",
"\x1B[17~"},
87 {
"\x1B[S",
"\x1B[18~"},
88 {
"\x1B[T",
"\x1B[19~"},
89 {
"\x1B[U",
"\x1B[20~"},
90 {
"\x1B[V",
"\x1B[21~"},
91 {
"\x1B[W",
"\x1B[23~"},
92 {
"\x1B[X",
"\x1B[24~"},
96 : out_(std::move(out)) {}
100 const int timeout_threshold = 50;
101 if (timeout_ < timeout_threshold) {
105 if (!pending_.empty()) {
117unsigned char TerminalInputParser::Current() {
118 return pending_[position_];
121bool TerminalInputParser::Eat() {
123 return position_ < static_cast<int>(pending_.size());
126void TerminalInputParser::Send(TerminalInputParser::Output output) {
127 switch (output.type) {
139 std::string next = pending_.substr(position_);
140 pending_.resize(position_);
142 pending_ = std::move(next);
149 out_(Event::Character(std::move(pending_)));
156 pending_ = it->second;
158 out_(Event::Special(std::move(pending_)));
164 out_(Event::Mouse(std::move(pending_), output.mouse));
168 case CURSOR_POSITION:
169 out_(Event::CursorPosition(std::move(pending_),
176 out_(Event::CursorShape(std::move(pending_), output.cursor_shape));
180 case TERMINAL_NAME_VERSION:
181 out_(Event::TerminalNameVersion(std::move(pending_),
182 std::move(output.terminal_name),
183 output.terminal_version));
187 case TERMINAL_EMULATOR:
188 out_(Event::TerminalEmulator(std::move(pending_),
189 std::move(output.terminal_name),
190 std::move(output.terminal_version_string)));
194 case TERMINAL_CAPABILITIES:
195 out_(Event::TerminalCapabilities(
196 std::move(pending_), std::move(output.terminal_capabilities)));
203TerminalInputParser::Output TerminalInputParser::Parse() {
208 if (Current() ==
'\x1B') {
212 if (Current() < 32) {
216 if (Current() == 127) {
238TerminalInputParser::Output TerminalInputParser::ParseUTF8() {
239 auto head = Current();
240 unsigned char selector = 0b1000'0000;
246 unsigned int first_zero = 8;
247 for (
unsigned int i = 0; i < 8; ++i) {
249 if (!(head & selector)) {
257 auto value = uint32_t(head & ~mask);
260 const unsigned int max_utf8_bytes = 5;
261 if (first_zero == 1 || first_zero >= max_utf8_bytes) {
266 for (
unsigned int i = 2; i <= first_zero; ++i) {
273 if ((head & 0b1100'0000) != 0b1000'0000) {
277 value += head & 0b0011'1111;
282 if (
value <= 0b000'0000'0111'1111) {
284 }
else if (
value <= 0b000'0111'1111'1111) {
286 }
else if (
value <= 0b1111'1111'1111'1111) {
288 }
else if (
value <= 0b1'0000'1111'1111'1111'1111) {
294 if (extra_byte != position_) {
301TerminalInputParser::Output TerminalInputParser::ParseESC() {
330 if (Current() ==
'\x1B') {
342TerminalInputParser::Output TerminalInputParser::ParseDCS() {
349 if (Current() !=
'\x1B') {
357 if (Current() !=
'\\') {
362 if (pending_.size() >= 5 && pending_[2] ==
'>' && pending_[3] ==
'|') {
365 const std::string content = pending_.substr(4, pending_.size() - 6);
366 Output output(TERMINAL_EMULATOR);
367 const size_t space = content.find(
' ');
368 const size_t open_paren = content.find(
'(');
369 if (space != std::string::npos) {
370 output.terminal_name = content.substr(0, space);
371 output.terminal_version_string = content.substr(space + 1);
372 }
else if (open_paren != std::string::npos) {
373 output.terminal_name = content.substr(0, open_paren);
374 output.terminal_version_string = content.substr(open_paren + 1);
375 if (!output.terminal_version_string.empty() &&
376 output.terminal_version_string.back() ==
')') {
377 output.terminal_version_string.pop_back();
380 output.terminal_name = content;
381 output.terminal_version_string =
"unknown";
386 if (pending_.size() == 10 &&
387 pending_[2] ==
'1' &&
388 pending_[3] ==
'$' &&
389 pending_[4] ==
'r' &&
391 Output output(CURSOR_SHAPE);
392 output.cursor_shape = pending_[5] -
'0';
400TerminalInputParser::Output TerminalInputParser::ParseCSI() {
401 bool altered_less =
false;
402 bool altered_greater =
false;
403 bool altered_question =
false;
405 std::vector<int> arguments;
411 if (Current() ==
'<') {
416 if (Current() ==
'>') {
417 altered_greater =
true;
421 if (Current() ==
'?') {
422 altered_question =
true;
426 if (Current() >=
'0' && Current() <=
'9') {
428 argument += Current() -
'0';
432 if (Current() ==
';') {
433 arguments.push_back(argument);
440 if (Current() >=
'@' && Current() <=
'~' &&
445 arguments.push_back(argument);
450 return ParseMouse(altered_less,
true, std::move(arguments));
452 return ParseMouse(altered_less,
false, std::move(arguments));
454 return ParseCursorPosition(std::move(arguments));
456 return ParseDeviceAttributes(altered_greater, altered_question,
457 std::move(arguments));
464 if (Current() ==
'\x1B') {
470TerminalInputParser::Output TerminalInputParser::ParseOSC() {
476 if (Current() !=
'\x1B') {
482 if (Current() !=
'\\') {
489TerminalInputParser::Output TerminalInputParser::ParseMouse(
492 std::vector<int> arguments) {
493 if (arguments.size() != 3) {
499 Output output(MOUSE);
500 output.mouse.motion = Mouse::Motion(pressed);
512 const int button = arguments[0] & (1 + 2);
513 const bool is_shift = arguments[0] & 4;
514 const bool is_meta = arguments[0] & 8;
515 const bool is_control = arguments[0] & 16;
516 const bool is_move = arguments[0] & 32;
517 const bool is_wheel = arguments[0] & 64;
520 output.mouse.motion = is_move ? Mouse::Moved : Mouse::Motion(pressed);
521 output.mouse.button = is_wheel ? Mouse::Button(Mouse::WheelUp + button)
522 : Mouse::Button(button);
523 output.mouse.shift = is_shift;
524 output.mouse.meta = is_meta;
525 output.mouse.control = is_control;
526 output.mouse.x = arguments[1];
527 output.mouse.y = arguments[2];
534TerminalInputParser::Output TerminalInputParser::ParseCursorPosition(
535 std::vector<int> arguments) {
536 if (arguments.size() != 2) {
539 Output output(CURSOR_POSITION);
540 output.cursor.y = arguments[0];
541 output.cursor.x = arguments[1];
546TerminalInputParser::Output TerminalInputParser::ParseDeviceAttributes(
547 bool altered_greater,
548 bool altered_question,
549 std::vector<int> arguments) {
550 if (altered_greater) {
553 if (arguments.size() >= 3) {
557 Output output(TERMINAL_NAME_VERSION);
558 output.terminal_version = arguments[1];
559 switch (arguments[0]) {
561 output.terminal_name =
"xterm";
564 output.terminal_name =
"vt220";
567 output.terminal_name =
"vt240";
570 output.terminal_name =
"vt330";
573 output.terminal_name =
"vt340";
576 output.terminal_name =
"vt320";
579 output.terminal_name =
"vt420";
582 output.terminal_name =
"vt510";
585 output.terminal_name =
"vt520";
588 output.terminal_name =
"vt525";
591 output.terminal_name =
"tmux";
594 output.terminal_name =
"urxvt";
597 output.terminal_name =
"unknown";
604 }
else if (altered_question) {
607 Output output(TERMINAL_CAPABILITIES);
608 output.terminal_capabilities = std::move(arguments);
const std::map< std::string, std::string > g_uniformize