diff --git a/kernel/src/arch/x86_64/CPU.cpp b/kernel/src/arch/x86_64/CPU.cpp index c1c85ef2..f7bc7634 100644 --- a/kernel/src/arch/x86_64/CPU.cpp +++ b/kernel/src/arch/x86_64/CPU.cpp @@ -161,7 +161,11 @@ void io_thread() static void timer_interrupt(Registers* regs, void*) { Timer::tick(); - if (should_invoke_scheduler()) Scheduler::invoke(regs); + if (should_invoke_scheduler()) + { + Scheduler::invoke(regs); + TextConsole::tick_cursor(); + } } static void keyboard_interrupt(Registers*, void*) diff --git a/kernel/src/fs/devices/ConsoleDevice.cpp b/kernel/src/fs/devices/ConsoleDevice.cpp index c592e0a8..16846414 100644 --- a/kernel/src/fs/devices/ConsoleDevice.cpp +++ b/kernel/src/fs/devices/ConsoleDevice.cpp @@ -246,6 +246,9 @@ Result ConsoleDevice::ioctl(int request, void* arg) } case TTYSETGFX: { s_is_in_graphical_mode = (bool)arg; + if (!s_is_in_graphical_mode) TextConsole::enable_cursor(); + else + TextConsole::disable_cursor(); return 0; } default: return err(EINVAL); diff --git a/kernel/src/video/TextConsole.cpp b/kernel/src/video/TextConsole.cpp index 19bca1ce..efc41612 100644 --- a/kernel/src/video/TextConsole.cpp +++ b/kernel/src/video/TextConsole.cpp @@ -47,6 +47,11 @@ static bool bold = false; static u32 g_x_position = 0; static u32 g_y_position = 0; +static constexpr int CURSOR_TIMEOUT = 500; +static int current_cursor_timeout = CURSOR_TIMEOUT; +static bool cursor_activated = true; +static bool cursor_enabled = true; + static Utf8StateDecoder utf8_decoder; static Option escape_sequence_parser; @@ -82,7 +87,7 @@ static void scroll() static bool should_scroll() { - return (g_y_position + FONT_HEIGHT) >= Framebuffer::height(); + return g_y_position >= Framebuffer::height(); } static void next_line() @@ -106,6 +111,11 @@ static void erase_current_char() Framebuffer::rect(g_x_position, g_y_position, FONT_WIDTH, FONT_HEIGHT, BLACK); } +static void draw_cursor() +{ + Framebuffer::rect(g_x_position, g_y_position, FONT_WIDTH, FONT_HEIGHT, WHITE); +} + static bool at_end_of_screen() { return (g_x_position + FONT_WIDTH) > Framebuffer::width(); @@ -323,6 +333,11 @@ namespace TextConsole if (handle_escape_sequence(c)) return; } + // Erase the current cursor. + if (cursor_enabled) erase_current_char(); + + bool should_draw_cursor = cursor_enabled; + switch (c) { case L'\n': { @@ -345,7 +360,10 @@ namespace TextConsole case L'\x1b': case L'\x9b': case L'\x90': - case L'\x9d': escape_sequence_parser = EscapeSequenceParser { (u8)c }; break; + case L'\x9d': + escape_sequence_parser = EscapeSequenceParser { (u8)c }; + should_draw_cursor = false; + break; default: { if (_iscntrl(c)) return; putwchar_at(c, g_x_position, g_y_position); @@ -358,6 +376,42 @@ namespace TextConsole break; } } + + if (should_draw_cursor) + { + current_cursor_timeout = CURSOR_TIMEOUT; + cursor_activated = true; + draw_cursor(); + } + } + + void tick_cursor() + { + if (!cursor_enabled) return; + + current_cursor_timeout--; + if (current_cursor_timeout == 0) + { + current_cursor_timeout = CURSOR_TIMEOUT; + cursor_activated = !cursor_activated; + + if (cursor_activated) draw_cursor(); + else + erase_current_char(); + } + } + + void disable_cursor() + { + cursor_enabled = false; + } + + void enable_cursor() + { + cursor_enabled = true; + cursor_activated = true; + current_cursor_timeout = CURSOR_TIMEOUT; + draw_cursor(); } Result putchar(char c) diff --git a/kernel/src/video/TextConsole.h b/kernel/src/video/TextConsole.h index 6e6f5287..4197dbb3 100644 --- a/kernel/src/video/TextConsole.h +++ b/kernel/src/video/TextConsole.h @@ -19,6 +19,9 @@ namespace TextConsole Result println(const char* str); void wprintln(const wchar_t* str); Result printf(const char* format, ...) _format(1, 2); + void tick_cursor(); + void disable_cursor(); + void enable_cursor(); u16 rows(); u16 cols();