/* * kbd_raw_sync.c — восстановление held-состояния после Rx-overrun SIO. * * Аппаратный приёмный FIFO SIO — 3 байта. Если прерывания запрещены * достаточно долго (DI-окна графики/кадрового IRQ), а в этот момент * приходит пачка скан-кодов (напр. быстрый тап стрелки = E0 74 + E0 F0 74, * 5 байт) — FIFO переполняется, байт(ы) теряются аппаратно. Потерянный * break → клавиша «залипает» в _kbdraw_down. * * Трамплин ловит overrun (RR1 бит5) и взводит _kbdraw_overrun. Приложение * зовёт kbd_raw_sync() раз в кадр: при взведённом флаге сбрасывается * held-состояние ВСЕХ клавиш, КРОМЕ модификаторов (Shift/Ctrl/Alt — * таблица ниже). Обычные реально зажатые клавиши «перечитаются» их * make-повтором (typematic) за ~0.1 с. Модификаторы НЕ сбрасываем * принципиально: PS/2 автоповторяет только ПОСЛЕДНЮЮ нажатую клавишу, * удерживаемый Shift при повторе стрелки не шлёт НИЧЕГО — сброшенный * модификатор невозможно перечитать, он «отваливался» до перенажатия * (баг PoP: Shift+→ = осторожный шаг превращался в бег, 2026-07-22). * Цена: если overrun потерял именно break модификатора, тот залипнет до * следующего нажатия — редкий случай против регулярного отвала. */ #include #include "_kbdraw.h" /* Скан-коды модификаторов (PS/2 Set 2): L/R Shift, LCtrl, LAlt, * RCtrl (E0 14 → +256), RAlt (E0 11 → +256). */ static const uint16_t _kbd_mod_codes[6] = { 0x12, 0x59, 0x14, 0x11, 0x0114, 0x0111 }; void kbd_raw_sync(void) { uint8_t save[6]; uint8_t i; if (!_kbdraw_overrun) return; _kbdraw_overrun = 0; for (i = 0; i < 6; i++) save[i] = _kbdraw_down[_kbd_mod_codes[i]]; memset(_kbdraw_down, 0, sizeof(_kbdraw_down)); for (i = 0; i < 6; i++) _kbdraw_down[_kbd_mod_codes[i]] = save[i]; }