diff --git a/README.md b/README.md index cf1da20..5bd6210 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ - [x] Драйвер таймера - [x] Драйвер клавиатуры - [x] Нормальный драйвер VGA (скролл итд) -- [ ] Нормальный драйвер клавиатуры (Caps Lock, Shift, Numpad итд) +- [x] Нормальный драйвер клавиатуры (Caps Lock, Shift, Numpad итд) - [ ] Драйвер PC Speaker - [ ] Screen buffers (как tty в Linux) - [ ] ANSI Escape в screen buffers diff --git a/drivers/keyboard.c b/drivers/keyboard.c index 6c0ea57..815046b 100644 --- a/drivers/keyboard.c +++ b/drivers/keyboard.c @@ -1,41 +1,135 @@ #include "keyboard.h" #include "serial.h" #include "vga.h" -#include "../kernel/io.h" // Отсюда заберём inb -#include "../kernel/logger.h" +#include "../kernel/io.h" -// Карта скан-кодов (US Layout, первый сет). 0 — это непечатаемые символы -static const char kbdus[128] = { +// Состояние модификаторов клавиатуры +static int is_e0 = 0; +static int shift_pressed = 0; +static int caps_lock_active = 0; + +// Скан-коды управления (Set 1) +#define SCAN_LSHIFT 0x2A +#define SCAN_RSHIFT 0x36 +#define SCAN_CAPS_LOCK 0x3A + +// Скан-коды стрелок (после 0xE0) +#define SCAN_UP 0x48 +#define SCAN_DOWN 0x50 +#define SCAN_LEFT 0x4B +#define SCAN_RIGHT 0x4D + +// Таблица 1: Обычные символы (без Shift) +static const char kbdus_lower[128] = { 0, 27, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\b', '\t', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n', 0, 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '`', 0, '\\', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', 0, '*', 0, ' ', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '-', 0, 0, 0, '+', 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // Остальное нули + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +// Таблица 2: Символы при зажатом Shift +static const char kbdus_upper[128] = { + 0, 27, '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', '\b', + '\t', 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', '\n', + 0, 'A', 's', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '"', '~', 0, + '|', 'Z', 'X', 'C', 'V', 'B', 'N', 'M', '<', '>', '?', 0, '*', 0, + ' ', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, '_', 0, 0, 0, '+', 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; void keyboard_init(void) { - // Чисто для логов, unmask мы уже сделали в kmain - log_info(LOG_NORMAL, "Keyboard driver ready.\n"); + shift_pressed = 0; + caps_lock_active = 0; + is_e0 = 0; + kprint_serial("[INFO] Full keyboard driver with Modifiers initialized.\n"); } void keyboard_handler(void) { - // Читаем байт из порта контроллера клавиатуры (8042) uint8_t scancode = inb(0x60); - // Если старший бит (0x80) установлен, это отпускание клавиши (Key Release). Игнорируем пока. + // 1. Ловим префикс расширенных кодов + if (scancode == 0xE0) { + is_e0 = 1; + return; + } + + // 2. Обработка ОТПУСКАНИЯ клавиш (Key Release / Break code) + // В Set 1 код отпускания — это код нажатия + 0x80 (установлен старший бит) if (scancode & 0x80) { - // Здесь можно отслеживать отпускание Shift/Ctrl - } else { - // Клавиша нажата (Key Press). Проверяем, входит ли в нашу карту - if (scancode < 128 && kbdus[scancode] != 0) { - char c = kbdus[scancode]; - - // Выводим символ на экран через VGA драйвер + uint8_t released_code = scancode & 0x7F; // Получаем чистый код нажатия + + if (is_e0) { + is_e0 = 0; // Для расширенных кодов просто сбрасываем флаг + return; + } + + // Если отпустили левый или правый Shift — выключаем режим шифта + if (released_code == SCAN_LSHIFT || released_code == SCAN_RSHIFT) { + shift_pressed = 0; + kprint_serial("[KEY] Shift Released\n"); + } + return; + } + + // 3. Обработка НАЖАТИЯ клавиш (Key Press / Make code) + if (is_e0) { + // Обработка расширенных клавиш (стрелочки) + switch (scancode) { + case SCAN_UP: kprint_serial("[KEY] UP\n"); break; + case SCAN_DOWN: kprint_serial("[KEY] DOWN\n"); break; + case SCAN_LEFT: kprint_serial("[KEY] LEFT\n"); break; + case SCAN_RIGHT: kprint_serial("[KEY] RIGHT\n"); break; + default: break; + } + is_e0 = 0; // Сбрасываем префикс после обработки + return; + } + + // Обработка обычных управляющих клавиш + if (scancode == SCAN_LSHIFT || scancode == SCAN_RSHIFT) { + shift_pressed = 1; + kprint_serial("[KEY] Shift Pressed\n"); + return; + } + + if (scancode == SCAN_CAPS_LOCK) { + caps_lock_active = !caps_lock_active; // Инвертируем состояние + kprint_serial("[KEY] Caps Lock Toggled\n"); + return; + } + + // Печать символов из таблиц + if (scancode < 128) { + char c = 0; + + // Определяем, какую таблицу использовать и нужно ли менять регистр букв + // Логика для букв: Shift XOR CapsLock (если нажат Shift и включен Caps, буквы будут маленькими) + int use_upper = shift_pressed; + + // Проверяем, является ли символ буквой, чтобы к нему применялся Caps Lock + char base_char = kbdus_lower[scancode]; + int is_alpha = (base_char >= 'a' && base_char <= 'z'); + + if (is_alpha && caps_lock_active) { + use_upper = !use_upper; // Caps Lock инвертирует поведение Shift для букв + } + + // Выбираем символ из нужной матрицы + if (use_upper) { + c = kbdus_upper[scancode]; + } else { + c = kbdus_lower[scancode]; + } + + // Если символ есть в раскладке — выводим + if (c != 0) { vga_putchar(c); - // И дублируем в сериал для надежной отладки + // Дублируем в сериал отладку char str[2] = {c, 0}; kprint_serial(str); }