Compare commits
7 Commits
95a80bfe81
...
9f4cb5c4dd
Author | SHA1 | Date |
---|---|---|
|
9f4cb5c4dd | |
|
73f9de6635 | |
|
12b9c82086 | |
|
a8edb8870e | |
|
dabc3c6cc4 | |
|
cc7c1ad30d | |
|
4d840a8d9a |
|
@ -18,78 +18,78 @@ namespace BAN
|
|||
using const_iterator = ConstIteratorSimple<T, Array>;
|
||||
|
||||
public:
|
||||
Array() = default;
|
||||
Array(const T&);
|
||||
constexpr Array() = default;
|
||||
constexpr Array(const T&);
|
||||
|
||||
iterator begin() { return iterator(m_data); }
|
||||
iterator end() { return iterator(m_data + size()); }
|
||||
const_iterator begin() const { return const_iterator(m_data); }
|
||||
const_iterator end() const { return const_iterator(m_data + size()); }
|
||||
|
||||
const T& operator[](size_type) const;
|
||||
T& operator[](size_type);
|
||||
constexpr const T& operator[](size_type) const;
|
||||
constexpr T& operator[](size_type);
|
||||
|
||||
const T& back() const;
|
||||
T& back();
|
||||
const T& front() const;
|
||||
T& front();
|
||||
constexpr const T& back() const;
|
||||
constexpr T& back();
|
||||
constexpr const T& front() const;
|
||||
constexpr T& front();
|
||||
|
||||
Span<T> span() { return Span(m_data, size()); }
|
||||
const Span<T> span() const { return Span(m_data, size()); }
|
||||
|
||||
constexpr size_type size() const;
|
||||
|
||||
const T* data() const { return m_data; }
|
||||
T* data() { return m_data; }
|
||||
constexpr const T* data() const { return m_data; }
|
||||
constexpr T* data() { return m_data; }
|
||||
|
||||
private:
|
||||
T m_data[S] {};
|
||||
};
|
||||
|
||||
template<typename T, size_t S>
|
||||
Array<T, S>::Array(const T& value)
|
||||
constexpr Array<T, S>::Array(const T& value)
|
||||
{
|
||||
for (size_type i = 0; i < S; i++)
|
||||
m_data[i] = value;
|
||||
}
|
||||
|
||||
template<typename T, size_t S>
|
||||
const T& Array<T, S>::operator[](size_type index) const
|
||||
constexpr const T& Array<T, S>::operator[](size_type index) const
|
||||
{
|
||||
ASSERT(index < S);
|
||||
return m_data[index];
|
||||
}
|
||||
|
||||
template<typename T, size_t S>
|
||||
T& Array<T, S>::operator[](size_type index)
|
||||
constexpr T& Array<T, S>::operator[](size_type index)
|
||||
{
|
||||
ASSERT(index < S);
|
||||
return m_data[index];
|
||||
}
|
||||
|
||||
template<typename T, size_t S>
|
||||
const T& Array<T, S>::back() const
|
||||
constexpr const T& Array<T, S>::back() const
|
||||
{
|
||||
ASSERT(S != 0);
|
||||
return m_data[S - 1];
|
||||
}
|
||||
|
||||
template<typename T, size_t S>
|
||||
T& Array<T, S>::back()
|
||||
constexpr T& Array<T, S>::back()
|
||||
{
|
||||
ASSERT(S != 0);
|
||||
return m_data[S - 1];
|
||||
}
|
||||
|
||||
template<typename T, size_t S>
|
||||
const T& Array<T, S>::front() const
|
||||
constexpr const T& Array<T, S>::front() const
|
||||
{
|
||||
ASSERT(S != 0);
|
||||
return m_data[0];
|
||||
}
|
||||
|
||||
template<typename T, size_t S>
|
||||
T& Array<T, S>::front()
|
||||
constexpr T& Array<T, S>::front()
|
||||
{
|
||||
ASSERT(S != 0);
|
||||
return m_data[0];
|
||||
|
|
|
@ -27,9 +27,10 @@ namespace Kernel
|
|||
const LibFont::Font& font() const override { return m_font; };
|
||||
|
||||
private:
|
||||
FramebufferTerminalDriver(BAN::RefPtr<FramebufferDevice> framebuffer_device)
|
||||
: m_framebuffer_device(framebuffer_device)
|
||||
{ }
|
||||
FramebufferTerminalDriver(BAN::RefPtr<FramebufferDevice> framebuffer_device, const Palette& palette)
|
||||
: TerminalDriver(palette)
|
||||
, m_framebuffer_device(framebuffer_device)
|
||||
{}
|
||||
|
||||
void read_cursor();
|
||||
void show_cursor(bool use_data);
|
||||
|
@ -42,7 +43,7 @@ namespace Kernel
|
|||
uint32_t m_cursor_y { 0 };
|
||||
bool m_cursor_shown { true };
|
||||
BAN::Vector<uint32_t> m_cursor_data;
|
||||
static constexpr Color m_cursor_color = TerminalColor::BRIGHT_WHITE;
|
||||
static constexpr Color m_cursor_color = TerminalColor::WHITE;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ namespace Kernel
|
|||
|
||||
BAN::ErrorOr<BAN::String> ptsname();
|
||||
|
||||
void putchar(uint8_t ch);
|
||||
bool putchar(uint8_t ch);
|
||||
|
||||
protected:
|
||||
BAN::ErrorOr<size_t> read_impl(off_t, BAN::ByteSpan) override;
|
||||
|
@ -61,7 +61,7 @@ namespace Kernel
|
|||
void clear() override;
|
||||
|
||||
protected:
|
||||
void putchar_impl(uint8_t ch) override;
|
||||
bool putchar_impl(uint8_t ch) override;
|
||||
|
||||
BAN::ErrorOr<long> ioctl_impl(int, void*) override;
|
||||
|
||||
|
|
|
@ -53,7 +53,7 @@ namespace Kernel
|
|||
|
||||
protected:
|
||||
virtual BAN::StringView name() const override { return m_name; }
|
||||
virtual void putchar_impl(uint8_t) override;
|
||||
virtual bool putchar_impl(uint8_t) override;
|
||||
|
||||
private:
|
||||
SerialTTY(Serial);
|
||||
|
|
|
@ -58,14 +58,14 @@ namespace Kernel
|
|||
protected:
|
||||
TTY(mode_t mode, uid_t uid, gid_t gid);
|
||||
|
||||
virtual void putchar_impl(uint8_t ch) = 0;
|
||||
virtual bool putchar_impl(uint8_t ch) = 0;
|
||||
virtual void update_cursor() {}
|
||||
|
||||
virtual BAN::ErrorOr<size_t> read_impl(off_t, BAN::ByteSpan) override;
|
||||
virtual BAN::ErrorOr<size_t> write_impl(off_t, BAN::ConstByteSpan) override;
|
||||
|
||||
private:
|
||||
void putchar(uint8_t ch);
|
||||
bool putchar(uint8_t ch);
|
||||
void do_backspace();
|
||||
|
||||
protected:
|
||||
|
|
|
@ -12,20 +12,28 @@ namespace Kernel
|
|||
public:
|
||||
struct Color
|
||||
{
|
||||
constexpr Color()
|
||||
: rgb(0)
|
||||
{ }
|
||||
constexpr Color(uint32_t rgb)
|
||||
: rgb(rgb)
|
||||
{ }
|
||||
constexpr Color(uint8_t r, uint8_t g, uint8_t b)
|
||||
: rgb(((uint32_t)r << 16) | ((uint32_t)g << 8) | b)
|
||||
{ }
|
||||
uint8_t red() const { return (rgb >> 0x10) & 0xFF; }
|
||||
uint8_t green() const { return (rgb >> 0x08) & 0xFF; }
|
||||
uint8_t blue() const { return (rgb >> 0x00) & 0xFF; }
|
||||
constexpr uint8_t red() const { return (rgb >> 0x10) & 0xFF; }
|
||||
constexpr uint8_t green() const { return (rgb >> 0x08) & 0xFF; }
|
||||
constexpr uint8_t blue() const { return (rgb >> 0x00) & 0xFF; }
|
||||
uint32_t rgb;
|
||||
};
|
||||
|
||||
using Palette = BAN::Array<Color, 16>;
|
||||
|
||||
public:
|
||||
static BAN::ErrorOr<void> initialize_from_boot_info();
|
||||
TerminalDriver(const Palette& palette)
|
||||
: m_palette(palette)
|
||||
{}
|
||||
virtual ~TerminalDriver() {}
|
||||
virtual uint32_t width() const = 0;
|
||||
virtual uint32_t height() const = 0;
|
||||
|
@ -40,29 +48,19 @@ namespace Kernel
|
|||
virtual bool has_font() const { return false; }
|
||||
virtual BAN::ErrorOr<void> set_font(LibFont::Font&&) { return BAN::Error::from_errno(EINVAL); }
|
||||
virtual const LibFont::Font& font() const { ASSERT_NOT_REACHED(); }
|
||||
|
||||
const Palette& palette() const { return m_palette; }
|
||||
|
||||
protected:
|
||||
Palette m_palette;
|
||||
};
|
||||
|
||||
extern BAN::RefPtr<TerminalDriver> g_terminal_driver;
|
||||
|
||||
namespace TerminalColor
|
||||
{
|
||||
static constexpr TerminalDriver::Color BLACK = 0x000000;
|
||||
static constexpr TerminalDriver::Color RED = 0xFF0000;
|
||||
static constexpr TerminalDriver::Color GREEN = 0x00FF00;
|
||||
static constexpr TerminalDriver::Color YELLOW = 0xFFFF00;
|
||||
static constexpr TerminalDriver::Color BLUE = 0x0000FF;
|
||||
static constexpr TerminalDriver::Color MAGENTA = 0xFF00FF;
|
||||
static constexpr TerminalDriver::Color CYAN = 0x00FFFF;
|
||||
static constexpr TerminalDriver::Color WHITE = 0xBFBFBF;
|
||||
|
||||
static constexpr TerminalDriver::Color BRIGHT_BLACK = 0x3F3F3F;
|
||||
static constexpr TerminalDriver::Color BRIGHT_RED = 0xFF7F7F;
|
||||
static constexpr TerminalDriver::Color BRIGHT_GREEN = 0x7FFF7F;
|
||||
static constexpr TerminalDriver::Color BRIGHT_YELLOW = 0xFFFF7F;
|
||||
static constexpr TerminalDriver::Color BRIGHT_BLUE = 0x7F7FFF;
|
||||
static constexpr TerminalDriver::Color BRIGHT_MAGENTA = 0xFF7FFF;
|
||||
static constexpr TerminalDriver::Color BRIGHT_CYAN = 0x7FFFFF;
|
||||
static constexpr TerminalDriver::Color BRIGHT_WHITE = 0xFFFFFF;
|
||||
constexpr TerminalDriver::Color BLACK = 0x000000;
|
||||
constexpr TerminalDriver::Color WHITE = 0xFFFFFF;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -21,8 +21,9 @@ namespace Kernel
|
|||
void set_cursor_position(uint32_t, uint32_t) override;
|
||||
|
||||
private:
|
||||
TextModeTerminalDriver(paddr_t paddr, uint32_t width, uint32_t height, uint32_t pitch)
|
||||
: m_paddr(paddr)
|
||||
TextModeTerminalDriver(paddr_t paddr, uint32_t width, uint32_t height, uint32_t pitch, const Palette& palette)
|
||||
: TerminalDriver(palette)
|
||||
, m_paddr(paddr)
|
||||
, m_width(width)
|
||||
, m_height(height)
|
||||
, m_pitch(pitch)
|
||||
|
@ -36,7 +37,7 @@ namespace Kernel
|
|||
const uint32_t m_height;
|
||||
const uint32_t m_pitch;
|
||||
vaddr_t m_vaddr { 0 };
|
||||
static constexpr Color s_cursor_color = TerminalColor::BRIGHT_WHITE;
|
||||
static constexpr Color s_cursor_color = TerminalColor::WHITE;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -11,6 +11,9 @@ namespace Kernel
|
|||
|
||||
class VirtualTTY : public TTY
|
||||
{
|
||||
public:
|
||||
using Palette = TerminalDriver::Palette;
|
||||
|
||||
public:
|
||||
static BAN::ErrorOr<BAN::RefPtr<VirtualTTY>> create(BAN::RefPtr<TerminalDriver>);
|
||||
|
||||
|
@ -23,7 +26,7 @@ namespace Kernel
|
|||
|
||||
protected:
|
||||
virtual BAN::StringView name() const override { return m_name; }
|
||||
virtual void putchar_impl(uint8_t ch) override;
|
||||
virtual bool putchar_impl(uint8_t ch) override;
|
||||
void update_cursor() override;
|
||||
|
||||
private:
|
||||
|
@ -35,6 +38,7 @@ namespace Kernel
|
|||
void putcodepoint(uint32_t codepoint);
|
||||
void putchar_at(uint32_t codepoint, uint32_t x, uint32_t y);
|
||||
void render_from_buffer(uint32_t x, uint32_t y);
|
||||
void scroll_if_needed();
|
||||
|
||||
private:
|
||||
enum class State
|
||||
|
@ -47,11 +51,15 @@ namespace Kernel
|
|||
|
||||
struct AnsiState
|
||||
{
|
||||
int32_t nums[2] { -1, -1 };
|
||||
int32_t index { 0 };
|
||||
static constexpr size_t max_nums = 5;
|
||||
int32_t nums[max_nums] { -1, -1, -1, -1, -1 };
|
||||
size_t index { 0 };
|
||||
bool question { false };
|
||||
};
|
||||
|
||||
BAN::Optional<TerminalDriver::Color> get_8bit_color();
|
||||
BAN::Optional<TerminalDriver::Color> get_24bit_color();
|
||||
|
||||
struct UTF8State
|
||||
{
|
||||
uint32_t codepoint { 0 };
|
||||
|
@ -60,14 +68,16 @@ namespace Kernel
|
|||
|
||||
struct Cell
|
||||
{
|
||||
TerminalDriver::Color foreground { TerminalColor::BRIGHT_WHITE };
|
||||
TerminalDriver::Color background { TerminalColor::BLACK };
|
||||
TerminalDriver::Color foreground;
|
||||
TerminalDriver::Color background;
|
||||
uint32_t codepoint { ' ' };
|
||||
};
|
||||
|
||||
private:
|
||||
BAN::String m_name;
|
||||
|
||||
BAN::RefPtr<TerminalDriver> m_terminal_driver;
|
||||
|
||||
State m_state { State::Normal };
|
||||
AnsiState m_ansi_state { };
|
||||
UTF8State m_utf8_state { };
|
||||
|
@ -84,11 +94,11 @@ namespace Kernel
|
|||
uint32_t m_column { 0 };
|
||||
Cell* m_buffer { nullptr };
|
||||
|
||||
TerminalDriver::Color m_foreground { TerminalColor::BRIGHT_WHITE };
|
||||
TerminalDriver::Color m_background { TerminalColor::BLACK };
|
||||
bool m_colors_inverted { false };
|
||||
const Palette& m_palette;
|
||||
|
||||
BAN::RefPtr<TerminalDriver> m_terminal_driver;
|
||||
TerminalDriver::Color m_foreground;
|
||||
TerminalDriver::Color m_background;
|
||||
bool m_colors_inverted { false };
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -104,7 +104,7 @@ namespace Debug
|
|||
{
|
||||
if (!isprint(ch))
|
||||
ch = '?';
|
||||
g_terminal_driver->putchar_at(ch, col, row, TerminalColor::BRIGHT_WHITE, TerminalColor::BLACK);
|
||||
g_terminal_driver->putchar_at(ch, col, row, TerminalColor::WHITE, TerminalColor::BLACK);
|
||||
|
||||
col++;
|
||||
if (col >= g_terminal_driver->width())
|
||||
|
@ -121,9 +121,9 @@ namespace Debug
|
|||
{
|
||||
for (uint32_t i = col; i < g_terminal_driver->width(); i++)
|
||||
{
|
||||
g_terminal_driver->putchar_at(' ', i, row, TerminalColor::BRIGHT_WHITE, TerminalColor::BLACK);
|
||||
g_terminal_driver->putchar_at(' ', i, row, TerminalColor::WHITE, TerminalColor::BLACK);
|
||||
if (row + 1 < g_terminal_driver->height())
|
||||
g_terminal_driver->putchar_at(' ', i, row + 1, TerminalColor::BRIGHT_WHITE, TerminalColor::BLACK);
|
||||
g_terminal_driver->putchar_at(' ', i, row + 1, TerminalColor::WHITE, TerminalColor::BLACK);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -360,7 +360,7 @@ namespace Kernel
|
|||
[&x, y](char ch)
|
||||
{
|
||||
if (x < g_terminal_driver->width() && y < g_terminal_driver->height())
|
||||
g_terminal_driver->putchar_at(ch, x++, y, TerminalColor::BRIGHT_WHITE, TerminalColor::BLACK);
|
||||
g_terminal_driver->putchar_at(ch, x++, y, TerminalColor::WHITE, TerminalColor::BLACK);
|
||||
};
|
||||
|
||||
BAN::Formatter::print(proc_putc, "CPU { 2}: { 3}.{3}%", current_id(), load_x1000 / 1000, load_x1000 % 1000);
|
||||
|
|
|
@ -3,15 +3,38 @@
|
|||
namespace Kernel
|
||||
{
|
||||
|
||||
|
||||
static consteval TerminalDriver::Palette default_palette()
|
||||
{
|
||||
TerminalDriver::Palette palette;
|
||||
palette[ 0] = 0x000000;
|
||||
palette[ 1] = 0xFF0000;
|
||||
palette[ 2] = 0x00FF00;
|
||||
palette[ 3] = 0xFFFF00;
|
||||
palette[ 4] = 0x0000FF;
|
||||
palette[ 5] = 0xFF00FF;
|
||||
palette[ 6] = 0x00FFFF;
|
||||
palette[ 7] = 0xBFBFBF;
|
||||
palette[ 8] = 0x3F3F3F;
|
||||
palette[ 9] = 0xFF7F7F;
|
||||
palette[10] = 0x7FFF7F;
|
||||
palette[11] = 0xFFFF7F;
|
||||
palette[12] = 0x7F7FFF;
|
||||
palette[13] = 0xFF7FFF;
|
||||
palette[14] = 0x7FFFFF;
|
||||
palette[15] = 0xFFFFFF;
|
||||
return palette;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<BAN::RefPtr<FramebufferTerminalDriver>> FramebufferTerminalDriver::create(BAN::RefPtr<FramebufferDevice> framebuffer_device)
|
||||
{
|
||||
auto* driver_ptr = new FramebufferTerminalDriver(framebuffer_device);
|
||||
auto* driver_ptr = new FramebufferTerminalDriver(framebuffer_device, default_palette());
|
||||
if (driver_ptr == nullptr)
|
||||
return BAN::Error::from_errno(ENOMEM);
|
||||
auto driver = BAN::RefPtr<FramebufferTerminalDriver>::adopt(driver_ptr);
|
||||
TRY(driver->set_font(BAN::move(TRY(LibFont::Font::prefs()))));
|
||||
driver->set_cursor_position(0, 0);
|
||||
driver->clear(TerminalColor::BLACK);
|
||||
driver->clear(driver->m_palette[0]);
|
||||
return driver;
|
||||
}
|
||||
|
||||
|
@ -60,6 +83,9 @@ namespace Kernel
|
|||
for (uint32_t x = 0; x < m_framebuffer_device->width(); x++)
|
||||
m_framebuffer_device->set_pixel(x, y, color.rgb);
|
||||
m_framebuffer_device->sync_pixels_full();
|
||||
|
||||
if (m_cursor_shown)
|
||||
show_cursor(false);
|
||||
}
|
||||
|
||||
void FramebufferTerminalDriver::read_cursor()
|
||||
|
@ -78,6 +104,11 @@ namespace Kernel
|
|||
|
||||
void FramebufferTerminalDriver::show_cursor(bool use_data)
|
||||
{
|
||||
// NOTE: cursor is allowed to be on width as scrolling only
|
||||
// happens after character gets printed to next line
|
||||
if (m_cursor_x == width())
|
||||
return;
|
||||
|
||||
if (!use_data)
|
||||
read_cursor();
|
||||
|
||||
|
|
|
@ -85,16 +85,19 @@ namespace Kernel
|
|||
return BAN::Error::from_errno(ENODEV);
|
||||
}
|
||||
|
||||
void PseudoTerminalMaster::putchar(uint8_t ch)
|
||||
bool PseudoTerminalMaster::putchar(uint8_t ch)
|
||||
{
|
||||
SpinLockGuard _(m_buffer_lock);
|
||||
|
||||
reinterpret_cast<uint8_t*>(m_buffer->vaddr())[(m_buffer_tail + m_buffer_size) % m_buffer->size()] = ch;
|
||||
if (m_buffer_size >= m_buffer->size())
|
||||
return false;
|
||||
|
||||
if (m_buffer_size < m_buffer->size())
|
||||
m_buffer_size++;
|
||||
else
|
||||
m_buffer_tail = (m_buffer_tail + 1) % m_buffer->size();
|
||||
reinterpret_cast<uint8_t*>(m_buffer->vaddr())[(m_buffer_tail + m_buffer_size) % m_buffer->size()] = ch;
|
||||
m_buffer_size++;
|
||||
|
||||
m_buffer_blocker.unblock();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<size_t> PseudoTerminalMaster::read_impl(off_t, BAN::ByteSpan buffer)
|
||||
|
@ -166,10 +169,11 @@ namespace Kernel
|
|||
(void)write_impl(0, BAN::ConstByteSpan::from(message));
|
||||
}
|
||||
|
||||
void PseudoTerminalSlave::putchar_impl(uint8_t ch)
|
||||
bool PseudoTerminalSlave::putchar_impl(uint8_t ch)
|
||||
{
|
||||
if (auto master = m_master.lock())
|
||||
master->putchar(ch);
|
||||
return master->putchar(ch);
|
||||
return false;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<long> PseudoTerminalSlave::ioctl_impl(int request, void* argument)
|
||||
|
|
|
@ -258,9 +258,10 @@ namespace Kernel
|
|||
return m_serial.height();
|
||||
}
|
||||
|
||||
void SerialTTY::putchar_impl(uint8_t ch)
|
||||
bool SerialTTY::putchar_impl(uint8_t ch)
|
||||
{
|
||||
m_serial.putchar(ch);
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -327,11 +327,12 @@ namespace Kernel
|
|||
}
|
||||
}
|
||||
|
||||
void TTY::putchar(uint8_t ch)
|
||||
bool TTY::putchar(uint8_t ch)
|
||||
{
|
||||
SpinLockGuard _(m_write_lock);
|
||||
if (m_tty_ctrl.draw_graphics)
|
||||
putchar_impl(ch);
|
||||
return putchar_impl(ch);
|
||||
return true;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<size_t> TTY::read_impl(off_t, BAN::ByteSpan buffer)
|
||||
|
@ -365,10 +366,12 @@ namespace Kernel
|
|||
BAN::ErrorOr<size_t> TTY::write_impl(off_t, BAN::ConstByteSpan buffer)
|
||||
{
|
||||
SpinLockGuard _(m_write_lock);
|
||||
for (size_t i = 0; i < buffer.size(); i++)
|
||||
putchar(buffer[i]);
|
||||
size_t written = 0;
|
||||
for (; written < buffer.size(); written++)
|
||||
if (!putchar(buffer[written]))
|
||||
break;
|
||||
update_cursor();
|
||||
return buffer.size();
|
||||
return written;
|
||||
}
|
||||
|
||||
void TTY::putchar_current(uint8_t ch)
|
||||
|
|
|
@ -7,36 +7,39 @@
|
|||
namespace Kernel
|
||||
{
|
||||
|
||||
static constexpr TerminalDriver::Color s_palette[] {
|
||||
TerminalColor::BLACK,
|
||||
TerminalColor::BLUE,
|
||||
TerminalColor::GREEN,
|
||||
TerminalColor::CYAN,
|
||||
TerminalColor::RED,
|
||||
TerminalColor::MAGENTA,
|
||||
TerminalColor::YELLOW,
|
||||
TerminalColor::WHITE,
|
||||
TerminalColor::BRIGHT_BLACK,
|
||||
TerminalColor::BRIGHT_BLUE,
|
||||
TerminalColor::BRIGHT_GREEN,
|
||||
TerminalColor::BRIGHT_CYAN,
|
||||
TerminalColor::BRIGHT_RED,
|
||||
TerminalColor::BRIGHT_MAGENTA,
|
||||
TerminalColor::BRIGHT_YELLOW,
|
||||
TerminalColor::BRIGHT_WHITE,
|
||||
};
|
||||
static consteval TerminalDriver::Palette default_palette()
|
||||
{
|
||||
TerminalDriver::Palette palette;
|
||||
palette[ 0] = 0x000000;
|
||||
palette[ 1] = 0x0000AA;
|
||||
palette[ 2] = 0x00AA00;
|
||||
palette[ 3] = 0x00AAAA;
|
||||
palette[ 4] = 0xAA0000;
|
||||
palette[ 5] = 0xAA00AA;
|
||||
palette[ 6] = 0xAA5500;
|
||||
palette[ 7] = 0xAAAAAA;
|
||||
palette[ 8] = 0x555555;
|
||||
palette[ 9] = 0x5555FF;
|
||||
palette[10] = 0x55FF55;
|
||||
palette[11] = 0x55FFFF;
|
||||
palette[12] = 0xFF5555;
|
||||
palette[13] = 0xFF55FF;
|
||||
palette[14] = 0xFFFF55;
|
||||
palette[15] = 0xFFFFFF;
|
||||
return palette;
|
||||
}
|
||||
|
||||
static constexpr uint8_t color_to_text_mode_color(TerminalDriver::Color color)
|
||||
{
|
||||
uint32_t min_diff = BAN::numeric_limits<uint32_t>::max();
|
||||
uint8_t closest = 0;
|
||||
|
||||
static_assert(sizeof(s_palette) / sizeof(*s_palette) == 16);
|
||||
static_assert(default_palette().size() == 16);
|
||||
for (size_t i = 0; i < 16; i++)
|
||||
{
|
||||
const auto rdiff = color.red() - s_palette[i].red();
|
||||
const auto gdiff = color.green() - s_palette[i].green();
|
||||
const auto bdiff = color.blue() - s_palette[i].blue();
|
||||
const auto rdiff = color.red() - default_palette()[i].red();
|
||||
const auto gdiff = color.green() - default_palette()[i].green();
|
||||
const auto bdiff = color.blue() - default_palette()[i].blue();
|
||||
const uint32_t diff = rdiff*rdiff + gdiff*gdiff + bdiff*bdiff;
|
||||
if (diff >= min_diff)
|
||||
continue;
|
||||
|
@ -56,7 +59,8 @@ namespace Kernel
|
|||
g_boot_info.framebuffer.address,
|
||||
g_boot_info.framebuffer.width,
|
||||
g_boot_info.framebuffer.height,
|
||||
g_boot_info.framebuffer.pitch
|
||||
g_boot_info.framebuffer.pitch,
|
||||
default_palette()
|
||||
);
|
||||
if (driver_ptr == nullptr)
|
||||
return BAN::Error::from_errno(ENOMEM);
|
||||
|
@ -83,7 +87,7 @@ namespace Kernel
|
|||
m_vaddr = vaddr + (m_paddr % PAGE_SIZE);
|
||||
|
||||
set_cursor_position(0, 0);
|
||||
clear(TerminalColor::BLACK);
|
||||
clear(m_palette[0]);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
@ -114,7 +118,7 @@ namespace Kernel
|
|||
{
|
||||
for (uint32_t y = 0; y < m_height; y++)
|
||||
for (uint32_t x = 0; x < m_width; x++)
|
||||
putchar_at(' ', x, y, TerminalColor::BRIGHT_WHITE, color);
|
||||
putchar_at(' ', x, y, color, color);
|
||||
}
|
||||
|
||||
void TextModeTerminalDriver::set_cursor_shown(bool shown)
|
||||
|
@ -136,6 +140,10 @@ namespace Kernel
|
|||
|
||||
void TextModeTerminalDriver::set_cursor_position(uint32_t x, uint32_t y)
|
||||
{
|
||||
// NOTE: cursor is allowed to be on width as scrolling only
|
||||
// happens after character gets printed to next line
|
||||
if (x == m_width)
|
||||
return;
|
||||
const uint16_t pos = y * m_width + x;
|
||||
IO::outb(0x3D4, 0x0F);
|
||||
IO::outb(0x3D5, pos & 0xFF);
|
||||
|
|
|
@ -39,6 +39,9 @@ namespace Kernel
|
|||
: TTY(0600, 0, 0)
|
||||
, m_name(MUST(BAN::String::formatted("tty{}", s_next_tty_number++)))
|
||||
, m_terminal_driver(driver)
|
||||
, m_palette(driver->palette())
|
||||
, m_foreground(m_palette[15])
|
||||
, m_background(m_palette[0])
|
||||
{
|
||||
m_width = m_terminal_driver->width();
|
||||
m_height = m_terminal_driver->height();
|
||||
|
@ -95,10 +98,11 @@ namespace Kernel
|
|||
void VirtualTTY::reset_ansi()
|
||||
{
|
||||
ASSERT(m_write_lock.current_processor_has_lock());
|
||||
m_ansi_state.index = 0;
|
||||
m_ansi_state.nums[0] = -1;
|
||||
m_ansi_state.nums[1] = -1;
|
||||
m_ansi_state.question = false;
|
||||
m_ansi_state = {
|
||||
.nums = { -1, -1, -1, -1, -1 },
|
||||
.index = 0,
|
||||
.question = false,
|
||||
};
|
||||
m_state = State::Normal;
|
||||
}
|
||||
|
||||
|
@ -108,64 +112,76 @@ namespace Kernel
|
|||
switch (ch)
|
||||
{
|
||||
case 0:
|
||||
m_foreground = TerminalColor::BRIGHT_WHITE;
|
||||
m_background = TerminalColor::BLACK;
|
||||
m_foreground = m_palette[15];
|
||||
m_background = m_palette[0];
|
||||
m_colors_inverted = false;
|
||||
break;
|
||||
|
||||
case 7: m_colors_inverted = true; break;
|
||||
case 27: m_colors_inverted = false; break;
|
||||
|
||||
case 30: m_foreground = TerminalColor::BLACK; break;
|
||||
case 31: m_foreground = TerminalColor::RED; break;
|
||||
case 32: m_foreground = TerminalColor::GREEN; break;
|
||||
case 33: m_foreground = TerminalColor::YELLOW; break;
|
||||
case 34: m_foreground = TerminalColor::BLUE; break;
|
||||
case 35: m_foreground = TerminalColor::MAGENTA; break;
|
||||
case 36: m_foreground = TerminalColor::CYAN; break;
|
||||
case 37: m_foreground = TerminalColor::WHITE; break;
|
||||
case 30: case 31: case 32: case 33: case 34: case 35: case 36: case 37:
|
||||
m_foreground = m_palette[ch - 30];
|
||||
break;
|
||||
|
||||
case 40: m_background = TerminalColor::BLACK; break;
|
||||
case 41: m_background = TerminalColor::RED; break;
|
||||
case 42: m_background = TerminalColor::GREEN; break;
|
||||
case 43: m_background = TerminalColor::YELLOW; break;
|
||||
case 44: m_background = TerminalColor::BLUE; break;
|
||||
case 45: m_background = TerminalColor::MAGENTA; break;
|
||||
case 46: m_background = TerminalColor::CYAN; break;
|
||||
case 47: m_background = TerminalColor::WHITE; break;
|
||||
case 40: case 41: case 42: case 43: case 44: case 45: case 46: case 47:
|
||||
m_background = m_palette[ch - 40];
|
||||
break;
|
||||
|
||||
case 90: m_foreground = TerminalColor::BRIGHT_BLACK; break;
|
||||
case 91: m_foreground = TerminalColor::BRIGHT_RED; break;
|
||||
case 92: m_foreground = TerminalColor::BRIGHT_GREEN; break;
|
||||
case 93: m_foreground = TerminalColor::BRIGHT_YELLOW; break;
|
||||
case 94: m_foreground = TerminalColor::BRIGHT_BLUE; break;
|
||||
case 95: m_foreground = TerminalColor::BRIGHT_MAGENTA; break;
|
||||
case 96: m_foreground = TerminalColor::BRIGHT_CYAN; break;
|
||||
case 97: m_foreground = TerminalColor::BRIGHT_WHITE; break;
|
||||
case 90: case 91: case 92: case 93: case 94: case 95: case 96: case 97:
|
||||
m_foreground = m_palette[ch - 90 + 8];
|
||||
break;
|
||||
|
||||
case 100: m_background = TerminalColor::BRIGHT_BLACK; break;
|
||||
case 101: m_background = TerminalColor::BRIGHT_RED; break;
|
||||
case 102: m_background = TerminalColor::BRIGHT_GREEN; break;
|
||||
case 103: m_background = TerminalColor::BRIGHT_YELLOW; break;
|
||||
case 104: m_background = TerminalColor::BRIGHT_BLUE; break;
|
||||
case 105: m_background = TerminalColor::BRIGHT_MAGENTA; break;
|
||||
case 106: m_background = TerminalColor::BRIGHT_CYAN; break;
|
||||
case 107: m_background = TerminalColor::BRIGHT_WHITE; break;
|
||||
case 100: case 101: case 102: case 103: case 104: case 105: case 106: case 107:
|
||||
m_background = m_palette[ch - 100 + 8];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
BAN::Optional<TerminalDriver::Color> VirtualTTY::get_8bit_color()
|
||||
{
|
||||
ASSERT(m_ansi_state.nums[1] == 5);
|
||||
if (m_ansi_state.nums[2] < 1)
|
||||
return {};
|
||||
|
||||
const uint8_t code = BAN::Math::min(m_ansi_state.nums[2], 256) - 1;
|
||||
if (code < 16)
|
||||
return m_palette[code];
|
||||
|
||||
if (code < 232)
|
||||
{
|
||||
const uint8_t r = (code - 16) / 36 % 6 * 40 + 55;
|
||||
const uint8_t g = (code - 16) / 6 % 6 * 40 + 55;
|
||||
const uint8_t b = (code - 16) / 1 % 6 * 40 + 55;
|
||||
return TerminalDriver::Color(r, g, b);
|
||||
}
|
||||
|
||||
const uint8_t gray = (code - 232) * 10 + 8;
|
||||
return TerminalDriver::Color(gray, gray, gray);
|
||||
}
|
||||
|
||||
BAN::Optional<TerminalDriver::Color> VirtualTTY::get_24bit_color()
|
||||
{
|
||||
ASSERT(m_ansi_state.nums[1] == 2);
|
||||
if (m_ansi_state.nums[2] < 1) return {};
|
||||
if (m_ansi_state.nums[3] < 1) return {};
|
||||
if (m_ansi_state.nums[4] < 1) return {};
|
||||
const uint8_t r = BAN::Math::min(m_ansi_state.nums[2], 256) - 1;
|
||||
const uint8_t g = BAN::Math::min(m_ansi_state.nums[3], 256) - 1;
|
||||
const uint8_t b = BAN::Math::min(m_ansi_state.nums[4], 256) - 1;
|
||||
return TerminalDriver::Color(r, g, b);
|
||||
}
|
||||
|
||||
void VirtualTTY::handle_ansi_csi(uint8_t ch)
|
||||
{
|
||||
constexpr size_t max_ansi_args = sizeof(m_ansi_state.nums) / sizeof(*m_ansi_state.nums);
|
||||
|
||||
ASSERT(m_write_lock.current_processor_has_lock());
|
||||
switch (ch)
|
||||
{
|
||||
case '0': case '1': case '2': case '3': case '4':
|
||||
case '5': case '6': case '7': case '8': case '9':
|
||||
{
|
||||
if ((size_t)m_ansi_state.index >= max_ansi_args)
|
||||
dwarnln("Only {} arguments supported with ANSI codes", max_ansi_args);
|
||||
if (m_ansi_state.index >= m_ansi_state.max_nums)
|
||||
dwarnln("Only {} arguments supported with ANSI codes", m_ansi_state.max_nums);
|
||||
else
|
||||
{
|
||||
int32_t& val = m_ansi_state.nums[m_ansi_state.index];
|
||||
|
@ -174,7 +190,7 @@ namespace Kernel
|
|||
return;
|
||||
}
|
||||
case ';':
|
||||
m_ansi_state.index = BAN::Math::min<size_t>(m_ansi_state.index + 1, max_ansi_args);
|
||||
m_ansi_state.index = BAN::Math::min<size_t>(m_ansi_state.index + 1, m_ansi_state.max_nums);
|
||||
return;
|
||||
case 'A': // Cursor Up
|
||||
if (m_ansi_state.nums[0] == -1)
|
||||
|
@ -306,7 +322,22 @@ namespace Kernel
|
|||
dprintln_if(DEBUG_VTTY, "Unsupported ANSI CSI character f");
|
||||
return;
|
||||
case 'm':
|
||||
for (int i = 0; i <= m_ansi_state.index && i < static_cast<int>(max_ansi_args); i++)
|
||||
if (m_ansi_state.nums[0] == 38 || m_ansi_state.nums[0] == 48)
|
||||
{
|
||||
if (m_ansi_state.nums[1] != 5 && m_ansi_state.nums[1] != 2)
|
||||
{
|
||||
reset_ansi();
|
||||
dprintln_if(DEBUG_VTTY, "Unsupported ANSI SGR {}", m_ansi_state.nums[1]);
|
||||
return;
|
||||
}
|
||||
const auto color = (m_ansi_state.nums[1] == 5)
|
||||
? get_8bit_color()
|
||||
: get_24bit_color();
|
||||
if (color.has_value())
|
||||
(m_ansi_state.nums[0] == 38 ? m_foreground : m_background) = *color;
|
||||
return reset_ansi();
|
||||
}
|
||||
for (size_t i = 0; i <= m_ansi_state.index && i < m_ansi_state.max_nums; i++)
|
||||
handle_ansi_csi_color(BAN::Math::max(m_ansi_state.nums[i], 0));
|
||||
return reset_ansi();
|
||||
case 's':
|
||||
|
@ -401,6 +432,29 @@ namespace Kernel
|
|||
m_terminal_driver->putchar_at(codepoint, x, y, cell.foreground, cell.background);
|
||||
}
|
||||
|
||||
void VirtualTTY::scroll_if_needed()
|
||||
{
|
||||
while (m_row >= m_height)
|
||||
{
|
||||
memmove(m_buffer, m_buffer + m_width, m_width * (m_height - 1) * sizeof(Cell));
|
||||
|
||||
// Clear last line in buffer
|
||||
for (uint32_t x = 0; x < m_width; x++)
|
||||
m_buffer[(m_height - 1) * m_width + x] = { .foreground = m_foreground, .background = m_background, .codepoint = ' ' };
|
||||
|
||||
if (!m_terminal_driver->scroll(m_background))
|
||||
{
|
||||
// No fast scrolling, render the whole buffer to the screen
|
||||
for (uint32_t y = 0; y < m_height; y++)
|
||||
for (uint32_t x = 0; x < m_width; x++)
|
||||
render_from_buffer(x, y);
|
||||
}
|
||||
|
||||
m_column = 0;
|
||||
m_row--;
|
||||
}
|
||||
}
|
||||
|
||||
void VirtualTTY::putcodepoint(uint32_t codepoint)
|
||||
{
|
||||
ASSERT(m_write_lock.current_processor_has_lock());
|
||||
|
@ -432,40 +486,22 @@ namespace Kernel
|
|||
m_state = State::WaitingAnsiEscape;
|
||||
break;
|
||||
default:
|
||||
if (m_column >= m_width)
|
||||
{
|
||||
m_column = 0;
|
||||
m_row++;
|
||||
}
|
||||
scroll_if_needed();
|
||||
putchar_at(codepoint, m_column, m_row);
|
||||
m_last_graphic_char = codepoint;
|
||||
m_column++;
|
||||
break;
|
||||
}
|
||||
|
||||
if (m_column >= m_width)
|
||||
{
|
||||
m_column = 0;
|
||||
m_row++;
|
||||
}
|
||||
|
||||
while (m_row >= m_height)
|
||||
{
|
||||
memmove(m_buffer, m_buffer + m_width, m_width * (m_height - 1) * sizeof(Cell));
|
||||
|
||||
// Clear last line in buffer
|
||||
for (uint32_t x = 0; x < m_width; x++)
|
||||
m_buffer[(m_height - 1) * m_width + x] = { .foreground = m_foreground, .background = m_background, .codepoint = ' ' };
|
||||
|
||||
if (!m_terminal_driver->scroll(m_background))
|
||||
{
|
||||
// No fast scrolling, render the whole buffer to the screen
|
||||
for (uint32_t y = 0; y < m_height; y++)
|
||||
for (uint32_t x = 0; x < m_width; x++)
|
||||
render_from_buffer(x, y);
|
||||
}
|
||||
|
||||
m_column = 0;
|
||||
m_row--;
|
||||
}
|
||||
scroll_if_needed();
|
||||
}
|
||||
|
||||
void VirtualTTY::putchar_impl(uint8_t ch)
|
||||
bool VirtualTTY::putchar_impl(uint8_t ch)
|
||||
{
|
||||
ASSERT(m_write_lock.current_processor_has_lock());
|
||||
|
||||
|
@ -495,10 +531,10 @@ namespace Kernel
|
|||
{
|
||||
reset_ansi();
|
||||
dprintln_if(DEBUG_VTTY, "invalid utf8");
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
m_state = State::WaitingUTF8;
|
||||
return;
|
||||
return true;
|
||||
case State::WaitingAnsiEscape:
|
||||
if (ch == CSI)
|
||||
m_state = State::WaitingAnsiCSI;
|
||||
|
@ -507,21 +543,21 @@ namespace Kernel
|
|||
reset_ansi();
|
||||
dprintln_if(DEBUG_VTTY, "unsupported byte after ansi escape {2H}", (uint8_t)ch);
|
||||
}
|
||||
return;
|
||||
return true;
|
||||
case State::WaitingAnsiCSI:
|
||||
handle_ansi_csi(ch);
|
||||
return;
|
||||
return true;
|
||||
case State::WaitingUTF8:
|
||||
if ((ch & 0xC0) != 0x80)
|
||||
{
|
||||
m_state = State::Normal;
|
||||
dprintln_if(DEBUG_VTTY, "invalid utf8");
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
m_utf8_state.codepoint = (m_utf8_state.codepoint << 6) | (ch & 0x3F);
|
||||
m_utf8_state.bytes_missing--;
|
||||
if (m_utf8_state.bytes_missing)
|
||||
return;
|
||||
return true;
|
||||
m_state = State::Normal;
|
||||
codepoint = m_utf8_state.codepoint;
|
||||
break;
|
||||
|
@ -530,6 +566,7 @@ namespace Kernel
|
|||
}
|
||||
|
||||
putcodepoint(codepoint);
|
||||
return true;
|
||||
}
|
||||
|
||||
void VirtualTTY::update_cursor()
|
||||
|
|
|
@ -185,6 +185,8 @@ void Terminal::run()
|
|||
|
||||
void Terminal::hide_cursor()
|
||||
{
|
||||
if (m_cursor.x == cols())
|
||||
return;
|
||||
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++)
|
||||
|
@ -195,6 +197,8 @@ void Terminal::hide_cursor()
|
|||
|
||||
void Terminal::show_cursor()
|
||||
{
|
||||
if (m_cursor.x == cols())
|
||||
return;
|
||||
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++)
|
||||
|
@ -321,6 +325,42 @@ void Terminal::handle_sgr(int32_t value)
|
|||
}
|
||||
}
|
||||
|
||||
BAN::Optional<uint32_t> Terminal::get_8bit_color()
|
||||
{
|
||||
ASSERT(m_csi_info.fields[1] == 5);
|
||||
if (m_csi_info.fields[2] < 1)
|
||||
return {};
|
||||
|
||||
const uint8_t code = BAN::Math::min(m_csi_info.fields[2], 256) - 1;
|
||||
if (code < 8)
|
||||
return s_colors_dark[code];
|
||||
if (code < 16)
|
||||
return s_colors_bright[code - 8];
|
||||
|
||||
if (code < 232)
|
||||
{
|
||||
const uint8_t r = (code - 16) / 36 % 6 * 40 + 55;
|
||||
const uint8_t g = (code - 16) / 6 % 6 * 40 + 55;
|
||||
const uint8_t b = (code - 16) / 1 % 6 * 40 + 55;
|
||||
return b | (g << 8) | (r << 16) | (0xCC << 24);
|
||||
}
|
||||
|
||||
const uint8_t gray = (code - 232) * 10 + 8;
|
||||
return gray | (gray << 8) | (gray << 16) | (0xCC << 24);
|
||||
}
|
||||
|
||||
BAN::Optional<uint32_t> Terminal::get_24bit_color()
|
||||
{
|
||||
ASSERT(m_csi_info.fields[1] == 2);
|
||||
if (m_csi_info.fields[2] < 1) return {};
|
||||
if (m_csi_info.fields[3] < 1) return {};
|
||||
if (m_csi_info.fields[4] < 1) return {};
|
||||
const uint8_t r = BAN::Math::min(m_csi_info.fields[2], 256) - 1;
|
||||
const uint8_t g = BAN::Math::min(m_csi_info.fields[3], 256) - 1;
|
||||
const uint8_t b = BAN::Math::min(m_csi_info.fields[4], 256) - 1;
|
||||
return b | (g << 8) | (r << 16) | (0xCC << 24);
|
||||
}
|
||||
|
||||
Rectangle Terminal::handle_csi(char ch)
|
||||
{
|
||||
if (ch == ';')
|
||||
|
@ -504,6 +544,20 @@ Rectangle Terminal::handle_csi(char ch)
|
|||
m_cursor.y = BAN::Math::clamp<int32_t>(m_csi_info.fields[0], 1, rows()) - 1;
|
||||
break;
|
||||
case 'm':
|
||||
if (m_csi_info.fields[0] == 38 || m_csi_info.fields[0] == 48)
|
||||
{
|
||||
if (m_csi_info.fields[1] != 5 && m_csi_info.fields[1] != 2)
|
||||
{
|
||||
dprintln("unsupported ANSI SGR {}", m_csi_info.fields[1]);
|
||||
break;
|
||||
}
|
||||
const auto color = (m_csi_info.fields[1] == 5)
|
||||
? get_8bit_color()
|
||||
: get_24bit_color();
|
||||
if (color.has_value())
|
||||
(m_csi_info.fields[0] == 38 ? m_fg_color : m_bg_color) = *color;
|
||||
break;
|
||||
}
|
||||
for (size_t i = 0; i <= m_csi_info.index && i < m_csi_info.max_fields; i++)
|
||||
handle_sgr(m_csi_info.fields[i]);
|
||||
break;
|
||||
|
@ -563,6 +617,20 @@ Rectangle Terminal::putcodepoint(uint32_t codepoint)
|
|||
break;
|
||||
default:
|
||||
{
|
||||
if (m_cursor.x >= cols())
|
||||
{
|
||||
m_cursor.x = 0;
|
||||
m_cursor.y++;
|
||||
}
|
||||
|
||||
if (m_cursor.y >= rows())
|
||||
{
|
||||
const uint32_t scroll = m_cursor.y - rows() + 1;
|
||||
m_cursor.y -= scroll;
|
||||
m_window->shift_vertical(-scroll * (int32_t)m_font.height(), m_bg_color);
|
||||
should_invalidate = { 0, 0, m_window->width(), m_window->height() };
|
||||
}
|
||||
|
||||
const uint32_t cell_w = m_font.width();
|
||||
const uint32_t cell_h = m_font.height();
|
||||
const uint32_t cell_x = m_cursor.x * cell_w;
|
||||
|
@ -580,12 +648,6 @@ Rectangle Terminal::putcodepoint(uint32_t codepoint)
|
|||
}
|
||||
}
|
||||
|
||||
if (m_cursor.x >= cols())
|
||||
{
|
||||
m_cursor.x = 0;
|
||||
m_cursor.y++;
|
||||
}
|
||||
|
||||
if (m_cursor.y >= rows())
|
||||
{
|
||||
const uint32_t scroll = m_cursor.y - rows() + 1;
|
||||
|
@ -608,10 +670,11 @@ Rectangle Terminal::putchar(uint8_t ch)
|
|||
return {};
|
||||
}
|
||||
m_state = State::CSI;
|
||||
m_csi_info.index = 0;
|
||||
m_csi_info.fields[0] = -1;
|
||||
m_csi_info.fields[1] = -1;
|
||||
m_csi_info.question = false;
|
||||
m_csi_info = {
|
||||
.fields = { -1, -1, -1, -1, -1 },
|
||||
.index = 0,
|
||||
.question = false,
|
||||
};
|
||||
return {};
|
||||
}
|
||||
|
||||
|
|
|
@ -41,6 +41,9 @@ private:
|
|||
Rectangle putchar(uint8_t ch);
|
||||
bool read_shell();
|
||||
|
||||
BAN::Optional<uint32_t> get_8bit_color();
|
||||
BAN::Optional<uint32_t> get_24bit_color();
|
||||
|
||||
void hide_cursor();
|
||||
void show_cursor();
|
||||
|
||||
|
@ -70,7 +73,7 @@ private:
|
|||
|
||||
struct CSIInfo
|
||||
{
|
||||
static constexpr size_t max_fields = 2;
|
||||
static constexpr size_t max_fields = 5;
|
||||
int32_t fields[max_fields];
|
||||
size_t index;
|
||||
bool question;
|
||||
|
|
Loading…
Reference in New Issue