BUG-KBD-5: зажатый Shift снимался автоповтором стрелки

Симптом: 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>
This commit is contained in:
Александр Петров
2026-08-05 12:33:15 +03:00
parent 3fe083331f
commit 030af74631
6 changed files with 55 additions and 92 deletions
+16 -17
View File
@@ -23,25 +23,24 @@ extern uint8_t _kbdraw_pending; /* FSM декодера make/break, см. в
extern uint8_t _kbdraw_overrun; /* 1 = ISR поймал Rx-overrun SIO (потерян
* байт → возможно потерян break); снимает
* kbd_raw_sync (чистит _kbdraw_down) */
/* «Fake shift» (замер на железе/MAME 2026-08-03). Пока реально зажат
* Shift, клавиатура PS/2 обёртывает КАЖДЫЙ расширенный код парой служебных
* посылок: перед make идёт E0 F0 12 (снять fake shift), после break — E0 12
* (вернуть). Это не клавиши, а прямое и непрерывное свидетельство того,
* зажат ли Shift на самом деле, — и единственный способ узнать это, не
* полагаясь на целость потока (PS/2 состояние опросить нельзя, а typematic
* повторяет только ПОСЛЕДНЮЮ нажатую клавишу, то есть стрелку, не Shift).
/* «Fake shift». Часть PS/2-клавиатур, пока реально зажат Shift, обёртывает
* расширенный код парой служебных посылок: перед make идёт E0 F0 12 (снять
* fake shift), после break — E0 12 (вернуть). Это не клавиши, а прямое
* свидетельство того, что Shift зажат, поэтому декодеры (трамплин и
* kbd_raw_poll) взводят по обёртке plain-бит Shift.
*
* Декодеры (трамплин и kbd_raw_poll) используют его в обе стороны:
* - увидели fake shift -> реальный Shift ЗАЖАТ -> взвести plain-бит;
* - расширенный make БЕЗ предшествующей обёртки -> Shift ОТПУЩЕН ->
* снять plain-биты обоих Shift.
* Отсюда: залипший Shift снимается первым же нажатием стрелки, а
* kbd_raw_sync больше не обязан сбрасывать модификаторы «на всякий случай»
* (из-за чего Shift отваливался посреди игры — BUG-KBD-4).
* ОБРАТНЫЙ ВЫВОД ЗАПРЕЩЁН (замер 2026-08-05, BUG-GRAB-1). Раньше отсюда
* делался и второй вывод: «расширенный make БЕЗ обёртки => Shift отпущен,
* снять plain-биты». Он неверен: обёртку шлют не все клавиатуры (в MAME
* Sprinter — pc_kbd ms_naturl — при зажатом Shift поток на стрелку вверх
* ровно `E0 75 E0 75 …`, ни одного F0/12), и она заведомо не сопровождает
* typematic-повторы. Результат: КАЖДЫЙ повтор зажатой стрелки снимал
* реально зажатый Shift, и Shift был неработоспособен вместе со стрелками.
*
* Хранит промежуточное состояние: 1 = разобрана break-форма (E0 F0 12),
* ждём расширенный код, который она обёртывает. */
extern uint8_t _kbdraw_fakesh;
* Состояние Shift ведётся его собственными make/break (12 / F0 12) — они
* приходят всегда; обёртка лишь подтверждает. Ценой этого потерянный при
* overrun'е break Shift снять нечем — лечится перенажатием Shift
* (см. kbd_raw_sync и BUG-KBD-3/4). */
/* Позиции бит модификаторов в карте (используют и декодеры на асме, и
* kbd_raw_sync): L Shift 0x12 -> байт 2 бит 2, R Shift 0x59 -> байт 11 бит 1. */