Terminal: Add cursor rendering

Cursor is now shown at the current position. It can be hidden (or shown)
with the ansi `\033[?25h` or `\033[?25l`
This commit is contained in:
Bananymous 2024-08-12 00:50:06 +03:00
parent 60b4d90608
commit 18e7cf2069
2 changed files with 54 additions and 1 deletions

View File

@ -91,6 +91,9 @@ void Terminal::run()
m_font = MUST(LibFont::Font::load("/usr/share/fonts/lat0-16.psfu"_sv)); m_font = MUST(LibFont::Font::load("/usr/share/fonts/lat0-16.psfu"_sv));
MUST(m_cursor_buffer.resize(m_font.width() * m_font.height(), m_bg_color));
show_cursor();
m_window->set_key_event_callback([&](LibGUI::EventPacket::KeyEvent event) { on_key_event(event); }); m_window->set_key_event_callback([&](LibGUI::EventPacket::KeyEvent event) { on_key_event(event); });
const int max_fd = BAN::Math::max(m_shell_info.pts_master, m_window->server_fd()); const int max_fd = BAN::Math::max(m_shell_info.pts_master, m_window->server_fd());
@ -111,9 +114,36 @@ void Terminal::run()
} }
} }
void Terminal::hide_cursor()
{
const uint32_t cursor_base_x = m_cursor.x * m_font.width();
const uint32_t cursor_base_y = m_cursor.y * m_font.height();
for (uint32_t y = 0; y < m_font.height(); y++)
for (uint32_t x = 0; x < m_font.width(); x++)
m_window->set_pixel(cursor_base_x + x, cursor_base_y + y, m_cursor_buffer[y * m_font.width() + x]);
m_window->invalidate(cursor_base_x, cursor_base_y, m_font.width(), m_font.height());
}
void Terminal::show_cursor()
{
const uint32_t cursor_base_x = m_cursor.x * m_font.width();
const uint32_t cursor_base_y = m_cursor.y * m_font.height();
for (uint32_t y = 0; y < m_font.height(); y++)
for (uint32_t x = 0; x < m_font.width(); x++)
m_cursor_buffer[y * m_font.width() + x] = m_window->get_pixel(cursor_base_x + x, cursor_base_y + y);
if (m_cursor_shown)
{
for (uint32_t y = m_font.height() * 13 / 16; y < m_font.height() - 1; y++)
for (uint32_t x = 0; x < m_font.width(); x++)
m_window->set_pixel(cursor_base_x + x, cursor_base_y + y, 0xFFFFFFFF);
m_window->invalidate(cursor_base_x, cursor_base_y, m_font.width(), m_font.height());
}
}
bool Terminal::read_shell() bool Terminal::read_shell()
{ {
hide_cursor();
char buffer[128]; char buffer[128];
ssize_t nread = read(m_shell_info.pts_master, buffer, sizeof(buffer) - 1); ssize_t nread = read(m_shell_info.pts_master, buffer, sizeof(buffer) - 1);
if (nread < 0) if (nread < 0)
@ -122,6 +152,9 @@ bool Terminal::read_shell()
return false; return false;
for (ssize_t i = 0; i < nread; i++) for (ssize_t i = 0; i < nread; i++)
putchar(buffer[i]); putchar(buffer[i]);
show_cursor();
return true; return true;
} }
@ -182,7 +215,10 @@ void Terminal::handle_csi(char ch)
} }
if (ch == '?') if (ch == '?')
{
m_csi_info.question = true;
return; return;
}
if (isdigit(ch)) if (isdigit(ch))
{ {
@ -282,6 +318,15 @@ void Terminal::handle_csi(char ch)
case 'u': case 'u':
m_cursor = m_saved_cursor; m_cursor = m_saved_cursor;
break; break;
case 'h':
case 'l':
if (!m_csi_info.question || m_csi_info.fields[0] != 25)
{
dprintln("invalid ANSI CSI ?{}{}", m_csi_info.fields[0], (char)ch);
break;
}
m_cursor_shown = (ch == 'h');
break;
default: default:
dprintln("TODO: CSI {}", ch); dprintln("TODO: CSI {}", ch);
break; break;
@ -303,6 +348,7 @@ void Terminal::putchar(uint8_t ch)
m_csi_info.index = 0; m_csi_info.index = 0;
m_csi_info.fields[0] = -1; m_csi_info.fields[0] = -1;
m_csi_info.fields[1] = -1; m_csi_info.fields[1] = -1;
m_csi_info.question = false;
return; return;
} }

View File

@ -18,6 +18,9 @@ private:
void putchar(uint8_t ch); void putchar(uint8_t ch);
bool read_shell(); bool read_shell();
void hide_cursor();
void show_cursor();
void on_key_event(LibGUI::EventPacket::KeyEvent); void on_key_event(LibGUI::EventPacket::KeyEvent);
void start_shell(); void start_shell();
@ -46,16 +49,20 @@ private:
{ {
int32_t fields[2]; int32_t fields[2];
size_t index; size_t index;
bool question;
}; };
private: private:
BAN::UniqPtr<LibGUI::Window> m_window; BAN::UniqPtr<LibGUI::Window> m_window;
LibFont::Font m_font; LibFont::Font m_font;
Cursor m_cursor { 0, 0 };
ShellInfo m_shell_info; ShellInfo m_shell_info;
State m_state { State::Normal }; State m_state { State::Normal };
CSIInfo m_csi_info; CSIInfo m_csi_info;
bool m_cursor_shown { true };
Cursor m_cursor { 0, 0 };
BAN::Vector<uint32_t> m_cursor_buffer;
uint8_t m_utf8_index { 0 }; uint8_t m_utf8_index { 0 };
uint8_t m_utf8_bytes[4] { }; uint8_t m_utf8_bytes[4] { };