Mouse support. Fix & verify Webassembly support.

There was some undefined behavior to be fixed in the terminal input
parser.

The behavior of flush seems to have change. The fix was to invert '\0'
and std::flush.
This commit is contained in:
ArthurSonzogni 2021-04-25 16:58:16 +02:00
parent 0b9b6c692a
commit a27c878a3f
No known key found for this signature in database
GPG Key ID: 41D98248C074CD6C
6 changed files with 55 additions and 19 deletions

View File

@ -10,7 +10,7 @@
<div class="page">
<h1>FTXUI WebAssembly Example </h1>
<p>
<a href="https://github.com/ArthurSonzogni/FTXUI">FTXUI</a> is a single
<a href="https://github.com/ArthurSonzogni/FTXUI">FTXUI</a> is a simple
C++ library for terminal user interface.
</p>
<p>
@ -69,10 +69,8 @@
];
const url_search_params = new URLSearchParams(window.location.search);
const example_index = url_search_params.get("id") || 16;
const example = example_list[example_index];
var select = document.getElementById("selectExample");
const example = url_search_params.get("file") || "./dom/color_gallery.js"
const select = document.getElementById("selectExample");
for(var i = 0; i < example_list.length; i++) {
var opt = example_list[i];
@ -81,9 +79,10 @@
el.value = opt;
select.appendChild(el);
}
select.selectedIndex = example_index;
select.selectedIndex = example_list.findIndex(path => path == example) || 0;
select.addEventListener("change", () => {
location.href = (location.href).split('?')[0] + "?id=" + select.selectedIndex;
location.href = (location.href).split('?')[0] + "?file=" +
example_list[select.selectedIndex];
});
let stdin_buffer = [];
@ -94,6 +93,7 @@
stdout_buffer = [];
let stdout = code => {
if (code == 0) {
console.log(code);
term.write(new Uint8Array(stdout_buffer));
stdout_buffer = [];
} else {

View File

@ -27,6 +27,11 @@ class Input : public Component {
// Component implementation.
Element Render() override;
bool OnEvent(Event) override;
private:
bool OnMouseEvent(Event);
Box input_box_;
Box cursor_box_;
};
} // namespace ftxui

View File

@ -15,14 +15,15 @@ Element Input::Render() {
// Placeholder.
if (content.size() == 0) {
if (is_focused)
return text(placeholder) | focus | dim | inverted | main_decorator;
return text(placeholder) | focus | dim | inverted | main_decorator |
reflect(input_box_);
else
return text(placeholder) | dim | main_decorator;
return text(placeholder) | dim | main_decorator | reflect(input_box_);
}
// Not focused.
if (!is_focused)
return text(content) | main_decorator;
return text(content) | main_decorator | reflect(input_box_);
std::wstring part_before_cursor = content.substr(0, cursor_position);
std::wstring part_at_cursor = cursor_position < (int)content.size()
@ -37,13 +38,18 @@ Element Input::Render() {
return
hbox(
text(part_before_cursor),
text(part_at_cursor) | underlined | focused,
text(part_at_cursor) | underlined | focused | reflect(cursor_box_),
text(part_after_cursor)
) | flex | inverted | frame | main_decorator;
// clang-format off
) | flex | inverted | frame | main_decorator | reflect(input_box_);
// clang-format on
}
bool Input::OnEvent(Event event) {
cursor_position = std::max(0, std::min<int>(content.size(), cursor_position));
if (event.is_mouse())
return OnMouseEvent(event);
std::wstring c;
// Backspace.
@ -95,6 +101,26 @@ bool Input::OnEvent(Event event) {
return false;
}
bool Input::OnMouseEvent(Event event) {
if (!input_box_.Contain(event.mouse().x, event.mouse().y))
return false;
TakeFocus();
if (event.mouse().button == Mouse::Left &&
event.mouse().motion == Mouse::Pressed) {
int new_cursor_position =
cursor_position + event.mouse().x - cursor_box_.x_min;
new_cursor_position =
std::max(0, std::min<int>(content.size(), new_cursor_position));
if (cursor_position != new_cursor_position) {
cursor_position = new_cursor_position;
on_change();
}
}
return true;
}
} // namespace ftxui
// Copyright 2020 Arthur Sonzogni. All rights reserved.

View File

@ -40,7 +40,7 @@ namespace {
void Flush() {
// Emscripten doesn't implement flush. We interpret zero as flush.
std::cout << std::flush << (char)0;
std::cout << '\0' << std::flush;
}
constexpr int timeout_milliseconds = 20;
@ -353,6 +353,8 @@ void ScreenInteractive::Loop(Component* component) {
DECMode::kMouseSgrExtMode,
});
flush();
auto event_listener =
std::thread(&EventListener, &quit_, event_receiver_->MakeSender());

View File

@ -41,19 +41,23 @@ void TerminalInputParser::Send(TerminalInputParser::Output output) {
case CHARACTER:
out_->Send(Event::Character(std::move(pending_)));
pending_.clear();
return;
case SPECIAL:
out_->Send(Event::Special(std::move(pending_)));
pending_.clear();
return;
case MOUSE:
out_->Send(Event::Mouse(std::move(pending_), output.mouse));
pending_.clear();
return;
case CURSOR_REPORTING:
out_->Send(Event::CursorReporting(std::move(pending_), output.cursor.x,
output.cursor.y));
pending_.clear();
return;
}
// NOT_REACHED().
@ -133,7 +137,7 @@ TerminalInputParser::Output TerminalInputParser::ParseDCS() {
TerminalInputParser::Output TerminalInputParser::ParseCSI() {
bool altered = false;
int argument;
int argument = 0;
std::vector<int> arguments;
while (true) {
if (!Eat())
@ -205,9 +209,8 @@ TerminalInputParser::Output TerminalInputParser::ParseMouse(
output.mouse.button = Mouse::Button((arguments[0] & 3) + //
((arguments[0] & 64) >> 4));
output.mouse.motion = Mouse::Motion(pressed);
output.mouse.shift = arguments[0] & 4;
output.mouse.meta = arguments[0] & 8;
output.mouse.control = arguments[0] & 16;
output.mouse.shift = bool(arguments[0] & 4);
output.mouse.meta = bool(arguments[0] & 8);
output.mouse.x = arguments[1];
output.mouse.y = arguments[2];
return output;

View File

@ -184,7 +184,7 @@ std::string Screen::ToString() {
}
void Screen::Print() {
std::cout << ToString() << std::flush << (char)0;
std::cout << ToString() << '\0' << std::flush;
}
/// @brief Access a character a given position.