#include <cursor.h> #include <terminal.h> #include <util.h> uint16_t *framebuffer = (uint16_t *)FRAMEBUFFER_LOCATION; uint8_t currentFormat = 0x0A; void setTextStyle(uint8_t style) { currentFormat = style; } void setCharAtOffset(uint16_t offset, char c, uint8_t format) { *((uint16_t *)FRAMEBUFFER_LOCATION + offset) = format << 8 | c; } uint16_t getOffset(uint8_t x, uint8_t y) { return VIDEO_WIDTH * y + x; } void clearScreen() { setCursorOffset(0); for (int y = 0; y < VIDEO_HEIGHT; y++) { for (int x = 0; x < VIDEO_WIDTH; x++) { setCharAtOffset(getOffset(x, y), ' ', currentFormat); } } } void shiftUp() { for (int y = 1; y < VIDEO_HEIGHT; y++) { for (int x = 0; x < VIDEO_WIDTH; x++) { uint16_t old = *(uint16_t *)(FRAMEBUFFER_LOCATION + getOffset(x, y) * 2); setCharAtOffset(getOffset(x, y - 1), old, old >> 8); } } for (int x = 0; x < VIDEO_WIDTH; x++) { setCharAtOffset(getOffset(x, VIDEO_HEIGHT - 1), ' ', currentFormat); } } void shiftDown() { for (int y = VIDEO_HEIGHT - 1; y >= 0; y--) { for (int x = 0; x < VIDEO_WIDTH; x++) { uint16_t old = *(uint16_t *)(FRAMEBUFFER_LOCATION + getOffset(x, y) * 2); setCharAtOffset(getOffset(x, y + 1), old, old >> 8); } } for (int x = 0; x < VIDEO_WIDTH; x++) { setCharAtOffset(x, ' ', currentFormat); } } uint16_t cursorOffset = 0; void newLine() { uint8_t x = cursorOffset % VIDEO_WIDTH; uint8_t y = cursorOffset / VIDEO_WIDTH; x = 0; y++; if (y >= VIDEO_HEIGHT) { shiftUp(); y--; } cursorOffset = getOffset(x, y); setCursorOffset(cursorOffset); } typedef enum { STANDARD, ANSI_ESCAPE } States; typedef enum { BRACKET_OPEN, BUFFER } AnsiEscapeStates; States currentState = STANDARD; AnsiEscapeStates currentAnsiEscapeState = BRACKET_OPEN; uint32_t ansiEscapeBuffer1 = 0; uint32_t ansiEscapeBuffer2 = 0; uint32_t *currentBuffer = &ansiEscapeBuffer1; void writeChar(char c) { if (c == 0) return; switch (currentState) { case STANDARD: if (c == '\x1B') { currentState = ANSI_ESCAPE; currentAnsiEscapeState = BRACKET_OPEN; } break; case ANSI_ESCAPE: switch (currentAnsiEscapeState) { case BRACKET_OPEN: currentAnsiEscapeState = BUFFER; return; case BUFFER: switch (c) { case '1': *currentBuffer += 1; case '2': *currentBuffer += 2; case '3': *currentBuffer += 3; case '4': *currentBuffer += 4; case '5': *currentBuffer += 5; case '6': *currentBuffer += 6; case '7': *currentBuffer += 7; case '8': *currentBuffer += 8; case '9': *currentBuffer += 9; case '0': *currentBuffer *= 10; // shift right in decimal break; case 'H': cursorOffset = 0; setCursorOffset(0); currentState = STANDARD; return; case 'J': clearScreen(); currentState = STANDARD; return; case 'A': if (cursorOffset <= 0) { shiftDown(); } else { cursorOffset -= VIDEO_WIDTH; setCursorOffset(cursorOffset); } currentState = STANDARD; return; case 'B': if (cursorOffset / VIDEO_WIDTH + 1 >= VIDEO_HEIGHT) { shiftUp(); } else { cursorOffset += VIDEO_WIDTH; setCursorOffset(cursorOffset); } currentState = STANDARD; return; case 'C': if ((cursorOffset + 1) / VIDEO_WIDTH >= VIDEO_HEIGHT) { newLine(); } else { cursorOffset++; setCursorOffset(cursorOffset); } currentState = STANDARD; return; case 'D': if (cursorOffset == 0) { cursorOffset = VIDEO_WIDTH - 1; newLine(); } else { cursorOffset--; } setCursorOffset(cursorOffset); currentState = STANDARD; return; } } } if (currentState != STANDARD) { return; } switch (c) { case '\n': newLine(); return; case '\b': setCharAtOffset(--cursorOffset, ' ', currentFormat); setCursorOffset(cursorOffset); return; } setCharAtOffset(cursorOffset++, c, currentFormat); setCursorOffset(cursorOffset); }