mirror of
https://github.com/ArthurSonzogni/FTXUI.git
synced 2025-09-18 17:18:08 +08:00
Add UTF8 support and a better xterm parsing.
This fixes: https://github.com/ArthurSonzogni/FTXUI/issues/2
This commit is contained in:
@@ -1,39 +1,160 @@
|
||||
#include "ftxui/component/event.hpp"
|
||||
#include "ftxui/screen/string.hpp"
|
||||
|
||||
namespace ftxui {
|
||||
|
||||
constexpr int ESC = int(27);
|
||||
// static
|
||||
Event Event::Character(const std::string& input) {
|
||||
Event event;
|
||||
event.input_ = input;
|
||||
event.is_character_ = true;
|
||||
event.character_ = to_wstring(input)[0];
|
||||
return event;
|
||||
}
|
||||
|
||||
// --- Character ---
|
||||
Event Event::Character(int c) {
|
||||
return Event{c};
|
||||
// static
|
||||
Event Event::Character(char c) {
|
||||
return Character(wchar_t(c));
|
||||
}
|
||||
|
||||
// static
|
||||
Event Event::Character(wchar_t c) {
|
||||
Event event;
|
||||
event.input_ = {(char)c};
|
||||
event.is_character_ = true;
|
||||
event.character_ = c;
|
||||
return event;
|
||||
}
|
||||
|
||||
// static
|
||||
Event Event::Special(const std::string& input) {
|
||||
Event event;
|
||||
event.input_ = std::move(input);
|
||||
return event;
|
||||
}
|
||||
|
||||
Event ParseUTF8(std::function<char()>& getchar, std::string& input) {
|
||||
if ((input[0] & 0b11000000) == 0b11000000)
|
||||
input += getchar();
|
||||
if ((input[0] & 0b11100000) == 0b11100000)
|
||||
input += getchar();
|
||||
if ((input[0] & 0b11110000) == 0b11110000)
|
||||
input += getchar();
|
||||
return Event::Character(input);
|
||||
}
|
||||
|
||||
void ParsePs(std::function<char()> getchar, std::string input) {
|
||||
while (1) {
|
||||
char key = getchar();
|
||||
input += key;
|
||||
if ('0' <= key && key <= '9')
|
||||
continue;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Event ParseCSI(std::function<char()> getchar, std::string& input) {
|
||||
while (1) {
|
||||
char c = getchar();
|
||||
input += c;
|
||||
|
||||
if (c >= ' ' && c <= '/')
|
||||
return Event::Special(input);
|
||||
|
||||
// Invalid ESC in CSI.
|
||||
if (c == '\e')
|
||||
return Event::Special(input);
|
||||
|
||||
if (c >= '@' && c <= 'v')
|
||||
return Event::Special(input);
|
||||
}
|
||||
}
|
||||
|
||||
Event ParseDCS(std::function<char()> getchar, std::string& input) {
|
||||
// Parse until the string terminator ST.
|
||||
while (1) {
|
||||
input += getchar();
|
||||
if (input.back() != '\e')
|
||||
continue;
|
||||
input += getchar();
|
||||
if (input.back() != '\\')
|
||||
continue;
|
||||
return Event::Special(input);
|
||||
}
|
||||
}
|
||||
|
||||
Event ParseOSC(std::function<char()> getchar, std::string& input) {
|
||||
// Parse until the string terminator ST.
|
||||
while (1) {
|
||||
input += getchar();
|
||||
if (input.back() != '\e')
|
||||
continue;
|
||||
input += getchar();
|
||||
if (input.back() != '\\')
|
||||
continue;
|
||||
return Event::Special(input);
|
||||
}
|
||||
}
|
||||
|
||||
Event ParseESC(std::function<char()> getchar, std::string& input) {
|
||||
input += getchar();
|
||||
switch (input.back()) {
|
||||
case 'P':
|
||||
return ParseDCS(getchar, input);
|
||||
case '[':
|
||||
return ParseCSI(getchar, input);
|
||||
case ']':
|
||||
return ParseOSC(getchar, input);
|
||||
default:
|
||||
input += getchar();
|
||||
return Event::Special(input);
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
Event Event::GetEvent(std::function<char()> getchar) {
|
||||
std::string input;
|
||||
input += getchar();
|
||||
|
||||
switch (input[0]) {
|
||||
case 24: // CAN
|
||||
case 26: // SUB
|
||||
return Event(); // Ignored.
|
||||
|
||||
case 'P':
|
||||
return ParseDCS(getchar, input);
|
||||
|
||||
case '\e':
|
||||
return ParseESC(getchar, input);
|
||||
}
|
||||
|
||||
if (input[0] < 32) // C0
|
||||
return Event::Special(input);
|
||||
|
||||
return ParseUTF8(getchar, input);
|
||||
}
|
||||
|
||||
// --- Arrow ---
|
||||
Event Event::ArrowLeft{ESC, '[', 'D'};
|
||||
Event Event::ArrowRight{ESC, '[', 'C'};
|
||||
Event Event::ArrowUp{ESC, '[', 'A'};
|
||||
Event Event::ArrowDown{ESC, '[', 'B'};
|
||||
Event Event::ArrowLeft = Event::Special("\e[D");
|
||||
Event Event::ArrowRight = Event::Special("\e[C");
|
||||
Event Event::ArrowUp = Event::Special("\e[A");
|
||||
Event Event::ArrowDown = Event::Special("\e[B");
|
||||
Event Event::Backspace = Event::Special({127});
|
||||
Event Event::Delete = Event::Special("\e[3~");
|
||||
Event Event::Escape = Event::Special("\e");
|
||||
Event Event::Return = Event::Special({10});
|
||||
Event Event::F1 = Event::Special("\e[OP");
|
||||
Event Event::F2 = Event::Special("\e[OQ");
|
||||
Event Event::F3 = Event::Special("\e[OR");
|
||||
Event Event::F4 = Event::Special("\e[OS");
|
||||
Event Event::F5 = Event::Special("\e[15~");
|
||||
Event Event::F6 = Event::Special("\e[17~");
|
||||
Event Event::F7 = Event::Special("\e[18~");
|
||||
Event Event::F8 = Event::Special("\e[19~");
|
||||
Event Event::F9 = Event::Special("\e[20~");
|
||||
Event Event::F10 = Event::Special("\e[21~");
|
||||
Event Event::F11 = Event::Special("\e[21~"); // Doesn't exist
|
||||
Event Event::F12 = Event::Special("\e[24~");
|
||||
Event Event::Custom = Event::Special({0});
|
||||
|
||||
// --- Other ---
|
||||
Event Event::Backspace{127};
|
||||
Event Event::Delete{ESC, '[', '3', '~'};
|
||||
Event Event::Escape{ESC};
|
||||
Event Event::Return{10};
|
||||
|
||||
Event Event::F1{ESC, '[', 'O', 'P'};
|
||||
Event Event::F2{ESC, '[', 'O', 'Q'};
|
||||
Event Event::F3{ESC, '[', 'O', 'R'};
|
||||
Event Event::F4{ESC, '[', 'O', 'S'};
|
||||
Event Event::F5{ESC, '[', '1', '5', '~'};
|
||||
Event Event::F6{ESC, '[', '1', '7', '~'};
|
||||
Event Event::F7{ESC, '[', '1', '8', '~'};
|
||||
Event Event::F8{ESC, '[', '1', '9', '~'};
|
||||
Event Event::F9{ESC, '[', '2', '0', '~'};
|
||||
Event Event::F10{ESC, '[', '2', '1', '~'};
|
||||
Event Event::F11{ESC, '[', '2', '1', '~'}; // Same as F10 ?
|
||||
Event Event::F12{ESC, '[', '2', '4', '~'};
|
||||
|
||||
Event Event::Custom{0, 0, 0, 0, 0};
|
||||
|
||||
} // namespace ftxui
|
||||
} // namespace ftxui
|
||||
|
@@ -73,10 +73,8 @@ bool Input::OnEvent(Event event) {
|
||||
}
|
||||
|
||||
// Content
|
||||
constexpr char ESC = char(27);
|
||||
if (event.values[0] != ESC) {
|
||||
wchar_t v = (char)event.values[0];
|
||||
content.insert(cursor_position, 1, v);
|
||||
if (event.is_character()) {
|
||||
content.insert(cursor_position, 1, event.character());
|
||||
cursor_position++;
|
||||
return true;
|
||||
}
|
||||
|
@@ -4,47 +4,13 @@
|
||||
#include <termios.h>
|
||||
#include <unistd.h>
|
||||
#include <iostream>
|
||||
#include "ftxui/component/component.hpp"
|
||||
#include "ftxui/screen/terminal.hpp"
|
||||
#include <thread>
|
||||
#include "ftxui/component/component.hpp"
|
||||
#include "ftxui/screen/string.hpp"
|
||||
#include "ftxui/screen/terminal.hpp"
|
||||
|
||||
namespace ftxui {
|
||||
|
||||
namespace {
|
||||
constexpr int ESC = 27;
|
||||
constexpr int WAT = 195;
|
||||
constexpr int WAT2 = 194;
|
||||
constexpr int WATWAIT = 91;
|
||||
|
||||
Event GetEvent() {
|
||||
int v1 = getchar();
|
||||
if (v1 == ESC) {
|
||||
int v2 = getchar();
|
||||
int v3 = getchar();
|
||||
|
||||
// if (v2 == WATWAIT) {
|
||||
// int v4 = getchar();
|
||||
// int v5 = getchar();
|
||||
// return Event{v1, v2, v3, v4, v5};
|
||||
//}
|
||||
return Event{v1, v2, v3};
|
||||
}
|
||||
|
||||
if (v1 == WAT) {
|
||||
int v2 = getchar();
|
||||
return Event{v1, v2};
|
||||
}
|
||||
|
||||
if (v1 == WAT2) {
|
||||
int v2 = getchar();
|
||||
return Event{v1, v2};
|
||||
}
|
||||
|
||||
return Event{v1};
|
||||
};
|
||||
|
||||
}; // namespace
|
||||
|
||||
ScreenInteractive::ScreenInteractive(int dimx,
|
||||
int dimy,
|
||||
Dimension dimension)
|
||||
@@ -109,8 +75,10 @@ void ScreenInteractive::Loop(Component* component) {
|
||||
tcsetattr(STDIN_FILENO, TCSANOW, &terminal_configuration_new);
|
||||
|
||||
std::thread read_char([this]() {
|
||||
while (!quit_)
|
||||
PostEvent(GetEvent());
|
||||
while (!quit_) {
|
||||
auto event = Event::GetEvent([] { return (char)getchar(); });
|
||||
PostEvent(std::move(event));
|
||||
}
|
||||
});
|
||||
|
||||
std::string reset_position;
|
||||
|
Reference in New Issue
Block a user