030af74631
Симптом: Shift работал в одиночку и НЕ работал вместе со стрелками — прыжок с зацепом не выходил (BUG-GRAB-1), а осторожный шаг срывался в бег. Декодеры делали из «fake shift» два вывода, и второй был неверен: обёртка E0 F0 12 / E0 12 есть -> Shift зажат -> взвести бит — верно; расширенный make БЕЗ обёртки -> Shift отпущен -> снять бит — НЕТ. Замер потока байт (MAME, breakpoint на выходе из in a,($18)): клавиатура pc_kbd ms_naturl обёртку не шлёт вовсе — при зажатом Shift поток на ↑ ровно `E0 75 E0 75 …`, ни одного F0/12. А typematic-повторы идут непрерывно, пока стрелка зажата, значит каждый повтор снимал реально зажатый Shift. Короткий тап это маскировал: после отпускания стрелки Shift снова становился последней клавишей, и его собственный автоповтор `12` взводил бит обратно за ~30 мс. Фикс: обратный вывод убран, расширенная клавиша о Shift не судит. Состояние Shift ведут его собственные make/break 12 / F0 12 — они приходят всегда. Прямой вывод оставлен (дёшев и верен там, где обёртка есть). Ушла ставшая ненужной _kbdraw_fakesh; трамплин короче на 36 Б (0x150→0x12C), что важно — его клавиатурный блок упирается в диапазон jr. Плата: потерянный при overrun break Shift снять нечем, модификатор может залипнуть до перенажатия (BUG-KBD-3). Размен решён как и раньше в kbd_raw_sync: лучше залипание, чем отвал — сорванный посреди игры Shift в PoP стоит жизни. Проверено в MAME чтением _kbdraw_down: Shift+↑+→ зажаты 5 с (автоповтор идёт) -> LSh остаётся 04; отпускание Shift -> 00. Зацеп в игре подтверждён пользователем. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
73 lines
4.5 KiB
C
73 lines
4.5 KiB
C
/*
|
||
* kbd_raw_sync.c — восстановление held-состояния после Rx-overrun SIO.
|
||
*
|
||
* Аппаратный приёмный FIFO SIO — 3 байта. Если прерывания запрещены
|
||
* достаточно долго (DI-окна графики/кадрового IRQ), а в этот момент
|
||
* приходит пачка скан-кодов — FIFO переполняется, байт(ы) теряются
|
||
* аппаратно. Потерянный break → клавиша «залипает» в _kbdraw_down.
|
||
*
|
||
* Трамплин (и kbd_raw_poll) ловят overrun (RR1 бит5): делают Error Reset,
|
||
* чистят FSM префиксов _kbdraw_pending и взводят _kbdraw_overrun.
|
||
* Приложение зовёт kbd_raw_sync() раз в кадр — по флагу сбрасывается
|
||
* held-состояние карты. Реально зажатые клавиши перечитаются make-повтором
|
||
* (typematic) за ~0.1 с.
|
||
*
|
||
* МОДИФИКАТОРЫ ИЗ СБРОСА ИСКЛЮЧЕНЫ (2026-08-03, третья редакция). История
|
||
* вопроса — две неудачные крайности:
|
||
*
|
||
* 1) исключать модификаторы, не имея иного способа их проверить:
|
||
* потерянный break Shift снять нечем, Shift залипает навсегда
|
||
* (BUG-KBD-3);
|
||
* 2) сбрасывать ВСЁ, как DSS (KBD_Receiver_Overrun в KEYINTER.ASM чистит
|
||
* и KEYCTRL, и KEY_FLG): залипания нет, но удерживаемый Shift сносится
|
||
* каждым overrun'ом, а при зажатом Shift КАЖДЫЙ тап стрелки — это 10
|
||
* байт в 3-байтовый FIFO, то есть overrun почти гарантирован. Игрок
|
||
* жмёт Shift+→ ожидая осторожный шаг, а Кид уходит в бег — в PoP это
|
||
* прямо стоит жизни (яма/пики). Хуже залипания (BUG-KBD-4).
|
||
*
|
||
* Выбран вариант (1) — модификаторы НЕ сбрасываем. Была и третья редакция,
|
||
* обещавшая снять сам размен: «fake shift» (E0 F0 12 / E0 12) читался в обе
|
||
* стороны, и расширенный make без обёртки снимал Shift, то есть залипание
|
||
* лечилось первым же тапом стрелки. Обратный вывод оказался неверным
|
||
* (замер 2026-08-05, BUG-GRAB-1: обёртку шлют не все клавиатуры и никогда —
|
||
* на typematic-повторах), и он ломал Shift вместе со стрелками; убран, см.
|
||
* _kbdraw.h. Значит размен вернулся, и здесь он решается в пользу
|
||
* «лучше залипание, чем отвал»: залипший модификатор снимается его же
|
||
* перенажатием, а сорванный посреди игры Shift в PoP стоит жизни.
|
||
*
|
||
* Overrun теперь редок сам по себе: FIFO вычерпывается опросом из главного
|
||
* цикла (kbd_raw_poll, KBD-1), а не только по пойманному прерыванию.
|
||
*/
|
||
#include <string.h>
|
||
#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;
|
||
|
||
/* Карта упакована по битам (см. _kbdraw.h): сохраняем/возвращаем
|
||
* именно БИТ модификатора, а не байт. */
|
||
for (i = 0; i < 6; i++) {
|
||
uint16_t c = _kbd_mod_codes[i];
|
||
save[i] = (uint8_t)((_kbdraw_down[c >> 3] >> (c & 7)) & 1);
|
||
}
|
||
memset(_kbdraw_down, 0, sizeof(_kbdraw_down));
|
||
for (i = 0; i < 6; i++) {
|
||
uint16_t c = _kbd_mod_codes[i];
|
||
if (save[i]) _kbdraw_down[c >> 3] |= (uint8_t)(1 << (c & 7));
|
||
}
|
||
/* FSM префиксов трамплин уже сбросил; дублируем на случай overrun'а,
|
||
* пойманного вне его (kbd_raw_poll между кадрами). */
|
||
_kbdraw_pending = 0;
|
||
}
|