#include #include #include #include #include #include static tty_t ttys[MAX_TTYS]; static uint8_t num_ttys = 0; static tty_t* active_tty = NULL; static inline size_t next_index(size_t index) { return (index + 1) % TTY_BUFFER_SIZE; } static inline bool tty_empty(tty_t* tty) { return tty->head == tty->tail; } static inline bool tty_full(tty_t* tty) { return ((tty->head + 1) % TTY_BUFFER_SIZE) == tty->tail; } static inline bool is_canonical(tty_t* tty) { return (tty->flags & TTY_CANONICAL) != 0; } tty_t* tty_get_active(void) { return active_tty; } void tty_backspace(tty_t* tty) { if (tty->head == tty->tail) { return; /* buffer empty */ } //tty->head = (tty->head + TTY_BUFFER_SIZE - 1) % TTY_BUFFER_SIZE; tty->head = (tty->head + TTY_BUFFER_SIZE - 1) / TTY_BUFFER_SIZE; } ssize_t tty_read_active(char* buf, size_t count) { return tty_read(active_tty, buf, count); } /*ssize_t tty_read(tty_t* tty, char* buf, size_t count) { size_t bytes_read = 0; while (bytes_read < count) { IRQ_DISABLE(); spin_lock(&tty->lock); if (!tty_empty(tty)) { char c = tty->input_buffer[tty->tail]; tty->tail = (tty->tail + 1) % TTY_BUFFER_SIZE; tty->tail = next_index(tty->tail); spin_unlock(&tty->lock); IRQ_ENABLE(); /* change? *//* buf[bytes_read++] = c; if (is_canonical(tty) && c == '\n') { break; } } else { spin_unlock(&tty->lock); IRQ_ENABLE(); } } return bytes_read; }*/ ssize_t tty_read(tty_t* tty, char* buf, size_t count) { if (!tty || !buf) return -1; size_t bytes = 0; while (1) { IRQ_DISABLE(); spin_lock(&tty->lock); if (!tty->line_ready) { spin_unlock(&tty->lock); IRQ_ENABLE(); continue; /* spin until newline */ } while (bytes < count && tty->tail != tty->head) { char c = tty->input_buffer[tty->tail]; tty->tail = (tty->tail + 1) % TTY_BUFFER_SIZE; buf[bytes++] = c; if (c == '\n') { tty->line_ready = false; break; } } spin_unlock(&tty->lock); IRQ_ENABLE(); break; } return bytes; } int input_buffer_put(tty_t* tty, char c) { IRQ_DISABLE(); spin_lock(&tty->lock); size_t next = next_index(tty->head); if (next == tty->tail) { spin_unlock(&tty->lock); IRQ_ENABLE(); return -1; } tty->input_buffer[tty->head] = c; tty->head = next; spin_unlock(&tty->lock); IRQ_ENABLE(); return 0; } int init_tty(void) { if (num_ttys >= MAX_TTYS) { return -1; } tty_t* t = &ttys[0]; memset(t, 0, sizeof(tty_t)); t->flags = TTY_NORMAL; active_tty = t; num_ttys = 1; return 0; } tty_t* get_active_tty(void) { return active_tty; } tty_t* make_tty(uint32_t flags) { if (num_ttys >= MAX_TTYS) { return NULL; } tty_t* t = &ttys[num_ttys]; memset(t, 0, sizeof(tty_t)); t->flags = flags; num_ttys++; return t; } void tty_receive_char(char c, uint32_t kbd_mod) { if (!active_tty || c == 0) { return; } c = tty_translate_char(c, kbd_mod); /* Handle backspace */ if (c == '\b') { tty_backspace(active_tty); if (active_tty->head == active_tty->tail) { extern void terminal_putcharat(char c, uint16_t row, uint16_t column); terminal_putcharat('Z', 20, 20); } if (active_tty->flags & TTY_ECHO) { /* erase character visually */ putc('\b'); } return; } input_buffer_put(active_tty, c); if (active_tty->flags & TTY_ECHO) { if ((active_tty->flags & TTY_PASSWORD) == 0) { putc(c); } else { putc('*'); } } } void tty_input_char(tty_t* tty, char c) { if (!tty || c == 0) return; IRQ_DISABLE(); spin_lock(&tty->lock); /* backspace */ if (c == '\b') { if (tty->head != tty->tail) { tty->head = (tty->head + TTY_BUFFER_SIZE - 1) % TTY_BUFFER_SIZE; if (tty->flags & TTY_ECHO) { putc('\b');/* putc(' '); putc('\b');*/ } } spin_unlock(&tty->lock); IRQ_ENABLE(); return; } size_t next = (tty->head + 1) % TTY_BUFFER_SIZE; if (next != tty->tail) { tty->input_buffer[tty->head] = c; tty->head = next; if (c == '\n') { tty->line_ready = true; } } spin_unlock(&tty->lock); IRQ_ENABLE(); if (tty->flags & TTY_ECHO) { putc(c); } } char tty_translate_char(char c, uint32_t modifiers) { bool caps = (modifiers & MODIFIER_CAPS) != 0; bool shift = (modifiers & MODIFIER_SHIFT) != 0; bool ctrl = (modifiers & (MODIFIER_LCTRL | MODIFIER_RCTRL)) != 0; /* handle alphabetic characters */ if (c >= 'a' && c <= 'z') { if (caps ^ shift) /* XOR logic */ { return c - 32; /* to uppercase */ } return c; } if (c >= 'A' && c <= 'Z') { if (caps ^ shift) { return c; } return c + 32; /* to lowercase */ } /* handle ctrl (should later include control mapping/sending messages to processes via these) */ if (ctrl) { if (c >= 'a' && c <= 'z') { return c - 'a' + 1; /* Ctrl+A → 1 */ } if (c >= 'A' && c <= 'Z') { return c - 'A' + 1; } } /* shifted symbols (US layout) */ if (shift) { switch (c) { case '1': return '!'; case '2': return '@'; case '3': return '#'; case '4': return '$'; case '5': return '%'; case '6': return '^'; case '7': return '&'; case '8': return '*'; case '9': return '('; case '0': return ')'; case '-': return '_'; case '=': return '+'; case '[': return '{'; case ']': return '}'; case ';': return ':'; case '\'': return '"'; case ',': return '<'; case '.': return '>'; case '/': return '?'; case '\\': return '|'; case '`': return '~'; } } return c; }