forked from Bananymous/banan-os
Kernel: Add basic ANSI support :)
This commit is contained in:
parent
862b32d735
commit
03e7812cae
|
@ -1,6 +1,7 @@
|
||||||
#include <kernel/IO.h>
|
#include <kernel/IO.h>
|
||||||
#include <kernel/multiboot.h>
|
#include <kernel/multiboot.h>
|
||||||
#include <kernel/panic.h>
|
#include <kernel/panic.h>
|
||||||
|
#include <kernel/Serial.h>
|
||||||
#include <kernel/tty.h>
|
#include <kernel/tty.h>
|
||||||
|
|
||||||
#include "vga.h"
|
#include "vga.h"
|
||||||
|
@ -8,6 +9,16 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#define BEL 0x07
|
||||||
|
#define BS 0x08
|
||||||
|
#define HT 0x09
|
||||||
|
#define LF 0x0A
|
||||||
|
#define FF 0x0C
|
||||||
|
#define CR 0x0D
|
||||||
|
#define ESC 0x1B
|
||||||
|
|
||||||
|
#define CSI '['
|
||||||
|
|
||||||
namespace TTY
|
namespace TTY
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -20,6 +31,15 @@ namespace TTY
|
||||||
static uint8_t terminal_color;
|
static uint8_t terminal_color;
|
||||||
static uint16_t* terminal_buffer;
|
static uint16_t* terminal_buffer;
|
||||||
|
|
||||||
|
static char s_ansi_escape_mode = '\0';
|
||||||
|
static int s_ansi_escape_index = 0;
|
||||||
|
static int s_ansi_escape_nums[2] = { -1, -1 };
|
||||||
|
|
||||||
|
|
||||||
|
inline constexpr int max(int a, int b) { return a > b ? a : b; }
|
||||||
|
inline constexpr int min(int a, int b) { return a < b ? a : b; }
|
||||||
|
inline constexpr int clamp(int x, int a, int b) { return x < a ? a : x > b ? b : x; }
|
||||||
|
|
||||||
void putentryat(unsigned char c, uint8_t color, size_t x, size_t y)
|
void putentryat(unsigned char c, uint8_t color, size_t x, size_t y)
|
||||||
{
|
{
|
||||||
const size_t index = y * VGA_WIDTH + x;
|
const size_t index = y * VGA_WIDTH + x;
|
||||||
|
@ -58,6 +78,13 @@ namespace TTY
|
||||||
if (s_multiboot_info->flags & (1 << 12))
|
if (s_multiboot_info->flags & (1 << 12))
|
||||||
if (s_multiboot_info->framebuffer.type != 2)
|
if (s_multiboot_info->framebuffer.type != 2)
|
||||||
Kernel::panic("Invalid framebuffer_type in multiboot info");
|
Kernel::panic("Invalid framebuffer_type in multiboot info");
|
||||||
|
|
||||||
|
for (int i = 0; i < 16; i++)
|
||||||
|
{
|
||||||
|
terminal_color = vga_entry_color((vga_color)i, VGA_COLOR_BLACK);
|
||||||
|
putchar('#');
|
||||||
|
}
|
||||||
|
putchar('\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
void setcolor(uint8_t color)
|
void setcolor(uint8_t color)
|
||||||
|
@ -96,42 +123,243 @@ namespace TTY
|
||||||
update_cursor();
|
update_cursor();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void reset_ansi_escape()
|
||||||
|
{
|
||||||
|
s_ansi_escape_mode = '\0';
|
||||||
|
s_ansi_escape_index = 0;
|
||||||
|
s_ansi_escape_nums[0] = -1;
|
||||||
|
s_ansi_escape_nums[1] = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_ansi_SGR()
|
||||||
|
{
|
||||||
|
switch (s_ansi_escape_nums[0])
|
||||||
|
{
|
||||||
|
case -1: case 0:
|
||||||
|
terminal_color = vga_entry_color(VGA_COLOR_WHITE, VGA_COLOR_BLACK);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 30:
|
||||||
|
terminal_color = vga_set_foreground(VGA_COLOR_BLACK, terminal_color);
|
||||||
|
break;
|
||||||
|
case 31:
|
||||||
|
terminal_color = vga_set_foreground(VGA_COLOR_RED, terminal_color);
|
||||||
|
break;
|
||||||
|
case 32:
|
||||||
|
terminal_color = vga_set_foreground(VGA_COLOR_GREEN, terminal_color);
|
||||||
|
break;
|
||||||
|
case 33:
|
||||||
|
terminal_color = vga_set_foreground(VGA_COLOR_LIGHT_BROWN, terminal_color);
|
||||||
|
break;
|
||||||
|
case 34:
|
||||||
|
terminal_color = vga_set_foreground(VGA_COLOR_BLUE, terminal_color);
|
||||||
|
break;
|
||||||
|
case 35:
|
||||||
|
terminal_color = vga_set_foreground(VGA_COLOR_MAGENTA, terminal_color);
|
||||||
|
break;
|
||||||
|
case 36:
|
||||||
|
terminal_color = vga_set_foreground(VGA_COLOR_CYAN, terminal_color);
|
||||||
|
break;
|
||||||
|
case 37:
|
||||||
|
terminal_color = vga_set_foreground(VGA_COLOR_DARK_GREY, terminal_color);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 40:
|
||||||
|
terminal_color = vga_set_background(VGA_COLOR_BLACK, terminal_color);
|
||||||
|
break;
|
||||||
|
case 41:
|
||||||
|
terminal_color = vga_set_background(VGA_COLOR_RED, terminal_color);
|
||||||
|
break;
|
||||||
|
case 42:
|
||||||
|
terminal_color = vga_set_background(VGA_COLOR_GREEN, terminal_color);
|
||||||
|
break;
|
||||||
|
case 43:
|
||||||
|
terminal_color = vga_set_background(VGA_COLOR_LIGHT_BROWN, terminal_color);
|
||||||
|
break;
|
||||||
|
case 44:
|
||||||
|
terminal_color = vga_set_background(VGA_COLOR_BLUE, terminal_color);
|
||||||
|
break;
|
||||||
|
case 45:
|
||||||
|
terminal_color = vga_set_background(VGA_COLOR_MAGENTA, terminal_color);
|
||||||
|
break;
|
||||||
|
case 46:
|
||||||
|
terminal_color = vga_set_background(VGA_COLOR_CYAN, terminal_color);
|
||||||
|
break;
|
||||||
|
case 47:
|
||||||
|
terminal_color = vga_set_background(VGA_COLOR_DARK_GREY, terminal_color);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_ansi_escape(char c)
|
||||||
|
{
|
||||||
|
switch (s_ansi_escape_mode)
|
||||||
|
{
|
||||||
|
case '\1':
|
||||||
|
{
|
||||||
|
if (c == CSI)
|
||||||
|
{
|
||||||
|
s_ansi_escape_mode = CSI;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return reset_ansi_escape();
|
||||||
|
}
|
||||||
|
|
||||||
|
case CSI:
|
||||||
|
{
|
||||||
|
switch (c)
|
||||||
|
{
|
||||||
|
case '0': case '1': case '2': case '3': case '4':
|
||||||
|
case '5': case '6': case '7': case '8': case '9':
|
||||||
|
{
|
||||||
|
int& val = s_ansi_escape_nums[s_ansi_escape_index];
|
||||||
|
val = (val == -1) ? (c - '0') : (val * 10 + c - '0');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case ';':
|
||||||
|
s_ansi_escape_index++;
|
||||||
|
return;
|
||||||
|
case 'A': // Cursor Up
|
||||||
|
if (s_ansi_escape_nums[0] == -1)
|
||||||
|
s_ansi_escape_nums[0] = 1;
|
||||||
|
terminal_row = max(terminal_row - s_ansi_escape_nums[0], 0);
|
||||||
|
return reset_ansi_escape();
|
||||||
|
case 'B': // Curson Down
|
||||||
|
if (s_ansi_escape_nums[0] == -1)
|
||||||
|
s_ansi_escape_nums[0] = 1;
|
||||||
|
terminal_row = min(terminal_row + s_ansi_escape_nums[0], VGA_HEIGHT - 1);
|
||||||
|
return reset_ansi_escape();
|
||||||
|
case 'C': // Cursor Forward
|
||||||
|
if (s_ansi_escape_nums[0] == -1)
|
||||||
|
s_ansi_escape_nums[0] = 1;
|
||||||
|
terminal_col = min(terminal_col + s_ansi_escape_nums[0], VGA_WIDTH - 1);
|
||||||
|
return reset_ansi_escape();
|
||||||
|
case 'D': // Cursor Back
|
||||||
|
if (s_ansi_escape_nums[0] == -1)
|
||||||
|
s_ansi_escape_nums[0] = 1;
|
||||||
|
terminal_col = max(terminal_col - s_ansi_escape_nums[0], 0);
|
||||||
|
return reset_ansi_escape();
|
||||||
|
case 'E': // Cursor Next Line
|
||||||
|
if (s_ansi_escape_nums[0] == -1)
|
||||||
|
s_ansi_escape_nums[0] = 1;
|
||||||
|
terminal_row = min(terminal_row + s_ansi_escape_nums[0], VGA_HEIGHT - 1);
|
||||||
|
terminal_col = 0;
|
||||||
|
return reset_ansi_escape();
|
||||||
|
case 'F': // Cursor Previous Line
|
||||||
|
if (s_ansi_escape_nums[0] == -1)
|
||||||
|
s_ansi_escape_nums[0] = 1;
|
||||||
|
terminal_row = max(terminal_row - s_ansi_escape_nums[0], 0);
|
||||||
|
terminal_col = 0;
|
||||||
|
return reset_ansi_escape();
|
||||||
|
case 'G': // Cursor Horizontal Absolute
|
||||||
|
if (s_ansi_escape_nums[0] == -1)
|
||||||
|
s_ansi_escape_nums[0] = 1;
|
||||||
|
terminal_col = clamp(s_ansi_escape_nums[0] - 1, 0, VGA_WIDTH - 1);
|
||||||
|
return reset_ansi_escape();
|
||||||
|
case 'H': // Cursor Position
|
||||||
|
if (s_ansi_escape_nums[0] == -1)
|
||||||
|
s_ansi_escape_nums[0] = 1;
|
||||||
|
if (s_ansi_escape_nums[1] == -1)
|
||||||
|
s_ansi_escape_nums[1] = 1;
|
||||||
|
terminal_row = clamp(s_ansi_escape_nums[0] - 1, 0, VGA_HEIGHT - 1);
|
||||||
|
terminal_col = clamp(s_ansi_escape_nums[1] - 1, 0, VGA_WIDTH - 1);
|
||||||
|
return reset_ansi_escape();
|
||||||
|
case 'J': // Erase in Display
|
||||||
|
dprintln("Unsupported ANSI CSI character J");
|
||||||
|
return reset_ansi_escape();
|
||||||
|
case 'K': // Erase in Line
|
||||||
|
switch (s_ansi_escape_nums[0])
|
||||||
|
{
|
||||||
|
case -1: case 0:
|
||||||
|
for (size_t i = terminal_col; i < VGA_WIDTH; i++)
|
||||||
|
putentryat(' ', terminal_color, i, terminal_row);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
for (size_t i = 0; i <= terminal_col; i++)
|
||||||
|
putentryat(' ', terminal_color, i, terminal_row);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
for (size_t i = 0; i < VGA_WIDTH; i++)
|
||||||
|
putentryat(' ', terminal_color, i, terminal_row);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return reset_ansi_escape();
|
||||||
|
case 'S': // Scroll Up
|
||||||
|
dprintln("Unsupported ANSI CSI character S");
|
||||||
|
return reset_ansi_escape();
|
||||||
|
case 'T': // Scroll Down
|
||||||
|
dprintln("Unsupported ANSI CSI character T");
|
||||||
|
return reset_ansi_escape();
|
||||||
|
case 'f': // Horizontal Vertical Position
|
||||||
|
dprintln("Unsupported ANSI CSI character f");
|
||||||
|
return reset_ansi_escape();
|
||||||
|
case 'm':
|
||||||
|
handle_ansi_SGR();
|
||||||
|
return reset_ansi_escape();
|
||||||
|
default:
|
||||||
|
dprintln("Unsupported ANSI CSI character {}", c);
|
||||||
|
return reset_ansi_escape();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
dprintln("Unsupported ANSI mode");
|
||||||
|
return reset_ansi_escape();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void putchar(char c)
|
void putchar(char c)
|
||||||
{
|
{
|
||||||
if (c == '\t')
|
if (s_ansi_escape_mode)
|
||||||
c = ' ';
|
return handle_ansi_escape(c);
|
||||||
|
|
||||||
if (c == '\n')
|
// https://en.wikipedia.org/wiki/ANSI_escape_code
|
||||||
|
switch (c)
|
||||||
{
|
{
|
||||||
terminal_col = 0;
|
case BEL: // TODO
|
||||||
terminal_row++;
|
break;
|
||||||
}
|
case BS:
|
||||||
else if (c == '\b')
|
if (terminal_col > 0)
|
||||||
{
|
terminal_col--;
|
||||||
if (terminal_col > 0)
|
break;
|
||||||
terminal_col--;
|
case HT:
|
||||||
putentryat(' ', terminal_color, terminal_col, terminal_row);
|
terminal_col++;
|
||||||
}
|
while (terminal_col % 8)
|
||||||
else
|
terminal_col++;
|
||||||
{
|
break;
|
||||||
putentryat(c, terminal_color, terminal_col, terminal_row);
|
case LF:
|
||||||
terminal_col++;
|
terminal_col = 0;
|
||||||
|
terminal_row++;
|
||||||
|
break;
|
||||||
|
case FF:
|
||||||
|
terminal_row++;
|
||||||
|
break;
|
||||||
|
case CR:
|
||||||
|
terminal_col = 0;
|
||||||
|
break;
|
||||||
|
case ESC:
|
||||||
|
s_ansi_escape_mode = '\1';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
putentryat(c, terminal_color, terminal_col, terminal_row);
|
||||||
|
terminal_col++;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (terminal_col == VGA_WIDTH)
|
if (terminal_col >= VGA_WIDTH)
|
||||||
{
|
{
|
||||||
terminal_col = 0;
|
terminal_col = 0;
|
||||||
terminal_row++;
|
terminal_row++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (terminal_row == VGA_HEIGHT)
|
while (terminal_row >= VGA_HEIGHT)
|
||||||
{
|
{
|
||||||
for (size_t line = 1; line < VGA_HEIGHT; line++)
|
for (size_t line = 1; line < VGA_HEIGHT; line++)
|
||||||
scroll_line(line);
|
scroll_line(line);
|
||||||
clear_line(VGA_HEIGHT - 1);
|
clear_line(VGA_HEIGHT - 1);
|
||||||
|
|
||||||
terminal_col = 0;
|
terminal_col = 0;
|
||||||
terminal_row = VGA_HEIGHT - 1;
|
terminal_row--;
|
||||||
}
|
}
|
||||||
|
|
||||||
update_cursor();
|
update_cursor();
|
||||||
|
|
|
@ -22,9 +22,19 @@ enum vga_color
|
||||||
VGA_COLOR_WHITE = 15,
|
VGA_COLOR_WHITE = 15,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static inline uint8_t vga_set_foreground(enum vga_color fg, uint8_t color)
|
||||||
|
{
|
||||||
|
return (color & 0xf0) | fg;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint8_t vga_set_background(enum vga_color bg, uint8_t color)
|
||||||
|
{
|
||||||
|
return (bg << 4) | (color & 0x0f);
|
||||||
|
}
|
||||||
|
|
||||||
static inline uint8_t vga_entry_color(enum vga_color fg, enum vga_color bg)
|
static inline uint8_t vga_entry_color(enum vga_color fg, enum vga_color bg)
|
||||||
{
|
{
|
||||||
return fg | bg << 4;
|
return (bg << 4) | fg;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint16_t vga_entry(unsigned char uc, uint8_t color)
|
static inline uint16_t vga_entry(unsigned char uc, uint8_t color)
|
||||||
|
|
|
@ -228,6 +228,10 @@ namespace Keyboard
|
||||||
s_key_callback = callback;
|
s_key_callback = callback;
|
||||||
IDT::register_irq_handler(KEYBOARD_IRQ, irq_handler);
|
IDT::register_irq_handler(KEYBOARD_IRQ, irq_handler);
|
||||||
PIC::unmask(KEYBOARD_IRQ);
|
PIC::unmask(KEYBOARD_IRQ);
|
||||||
|
|
||||||
|
kb_command(0xED, 0b111);
|
||||||
|
IO::io_wait();
|
||||||
|
while (kb_try_read(tmp));
|
||||||
}
|
}
|
||||||
|
|
||||||
char key_to_ascii(Key key, uint8_t modifiers)
|
char key_to_ascii(Key key, uint8_t modifiers)
|
||||||
|
|
|
@ -28,10 +28,16 @@ void on_key_press(Keyboard::Key key, uint8_t modifiers, bool pressed)
|
||||||
kprint("time since boot: {} ms\n", PIT::ms_since_boot());
|
kprint("time since boot: {} ms\n", PIT::ms_since_boot());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
else if (key == Keyboard::Key::Backspace)
|
||||||
char ascii = Keyboard::key_to_ascii(key, modifiers);
|
{
|
||||||
if (ascii)
|
kprint("\b \b");
|
||||||
kprint("{}", ascii);
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
char ascii = Keyboard::key_to_ascii(key, modifiers);
|
||||||
|
if (ascii)
|
||||||
|
kprint("{}", ascii);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,9 +51,6 @@ void kernel_main(multiboot_info_t* mbi, uint32_t magic)
|
||||||
if (magic != 0x2BADB002)
|
if (magic != 0x2BADB002)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (mbi->framebuffer.type != 2)
|
|
||||||
return;
|
|
||||||
|
|
||||||
TTY::initialize();
|
TTY::initialize();
|
||||||
Serial::initialize();
|
Serial::initialize();
|
||||||
|
|
||||||
|
@ -60,17 +63,11 @@ void kernel_main(multiboot_info_t* mbi, uint32_t magic)
|
||||||
PIT::initialize();
|
PIT::initialize();
|
||||||
Keyboard::initialize(on_key_press);
|
Keyboard::initialize(on_key_press);
|
||||||
|
|
||||||
|
|
||||||
kprintln("Hello from the kernel!");
|
kprintln("Hello from the kernel!");
|
||||||
|
|
||||||
dprintln("Hello emulator from kernel!");
|
kprint("HHHHHHHHHHHHHHHHHHHHHHHHHHHHH\e[20D.\e[3K");
|
||||||
|
|
||||||
int** lol = new int*[10];
|
ENABLE_INTERRUPTS();
|
||||||
for (int i = 0; i < 10; i++)
|
|
||||||
lol[i] = new int;
|
|
||||||
|
|
||||||
kprint("{.2}\n", -12.123f);
|
|
||||||
kprint("0x{.H}", 0xcafebabe);
|
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue