KBD: состояние Shift по «fake shift» — ни залипания, ни отвала
Клавиатура PS/2 обёртывает КАЖДЫЙ расширенный код парой E0 F0 12 / E0 12,
пока реально зажат Shift (замер на железе/MAME: правый шифт обёртывается
своим кодом 0x59). Это прямое и непрерывное свидетельство состояния
Shift — единственное доступное, потому что опросить PS/2 нельзя, а
typematic повторяет последнюю нажатую клавишу, то есть стрелку.
Оба декодера (_irq_tramp.c, kbd_raw_poll.c) читают обёртку в обе стороны:
обёртка есть -> Shift взвести; расширенный make без обёртки -> Shift
снять. Бит взводит общий писатель — достаточно обнулить префиксы, и код
уходит в plain-половину карты как make.
Это снимает размен, между крайностями которого мы метались:
- исключать модификаторы из сброса по overrun -> Shift залипал навсегда
(BUG-KBD-3);
- сбрасывать всю карту, как DSS -> Shift сносился каждым overrun'ом, а
при зажатом Shift тап стрелки это 10 байт в 3-байтовый FIFO, то есть
overrun почти гарантирован (BUG-KBD-4).
Теперь kbd_raw_sync снова не трогает модификаторы, и это безопасно:
залипание снимается первым же нажатием стрелки.
Раскладка трамплина: клавиатурный блок перевалил за 127 байт, а jp внутри
запрещён (копия в W2). Префиксные обработчики переехали вплотную к своим
cp, посередине тела стоят ретрансляторы tr_kbd_hub/tr_hub_notkbd/
tr_hub_dss. В kbd_raw_poll такого ограничения нет — там три jp.
Проверено в MAME: Shift переживает пять тапов подряд; штатное отпускание
снимает; искусственно залипший бит снимается первым тапом.
make size-check — роста нет.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+49
-4
@@ -61,13 +61,54 @@ uint8_t kbd_raw_poll(void) __naked
|
||||
kp_drain:
|
||||
in a, (#_IRQ_SIO_DATA) ; чтение деструктивно = дренаж байта
|
||||
cp #0xF0
|
||||
jr Z, kp_setbrk
|
||||
jp Z, kp_setbrk ; jp, а не jr: тело цикла длиннее 127 Б (fake shift)
|
||||
cp #0xE0
|
||||
jr Z, kp_setext
|
||||
jp Z, kp_setext ; (в отличие от трамплина, здесь jp разрешён)
|
||||
|
||||
;; --- «fake shift» — тот же разбор, что в трамплине (см. _kbdraw.h):
|
||||
;; расширенные 12/59 не клавиши, а обёртка вокруг расширенного кода,
|
||||
;; которую клавиатура шлёт, пока реально зажат Shift. ---
|
||||
ld e, a ; E = код
|
||||
ld a, (__kbdraw_pending)
|
||||
bit 1, a ; EXT?
|
||||
ld a, e ; A = код обратно (ld флаги не трогает)
|
||||
jr Z, kp_code ; обычный код — прежний путь
|
||||
cp #0x12
|
||||
jr Z, kp_fake
|
||||
cp #0x59
|
||||
jr Z, kp_fake
|
||||
;; расширенная КЛАВИША: make без обёртки => Shift не зажат
|
||||
ld a, (__kbdraw_pending)
|
||||
bit 0, a ; break — состояние Shift не судим
|
||||
jr NZ, kp_fkclr
|
||||
ld a, (__kbdraw_fakesh)
|
||||
or a, a
|
||||
jr NZ, kp_fkclr ; обёртка была => Shift зажат
|
||||
ld hl, #(__kbdraw_down + _KBDRAW_LSH_BYTE)
|
||||
res _KBDRAW_LSH_BIT, (hl)
|
||||
ld hl, #(__kbdraw_down + _KBDRAW_RSH_BYTE)
|
||||
res _KBDRAW_RSH_BIT, (hl)
|
||||
kp_fkclr:
|
||||
xor a, a
|
||||
ld (__kbdraw_fakesh), a
|
||||
ld a, e
|
||||
jr kp_code
|
||||
|
||||
kp_fake:
|
||||
;; Бит взводит ОБЩИЙ писатель ниже: обнуляем префиксы — и он кладёт
|
||||
;; код в PLAIN-половину карты (без +32) и именно взведёт бит.
|
||||
ld a, (__kbdraw_pending)
|
||||
and #1 ; 1 = break-форма (идёт ПЕРЕД обёрнутым make)
|
||||
ld (__kbdraw_fakesh), a
|
||||
xor a, a
|
||||
ld (__kbdraw_pending), a
|
||||
ld a, e
|
||||
;; fall through в kp_code
|
||||
|
||||
;; --- обычный байт кода: БИТ code&7 в _kbdraw_down[code>>3].
|
||||
;; Маска сдвигом, а не таблицей — ровно как в трамплине, чтобы
|
||||
;; расхождения декодеров были невозможны by construction. ---
|
||||
kp_code:
|
||||
ld e, a ; E = код
|
||||
and #7
|
||||
ld b, a
|
||||
@@ -120,7 +161,7 @@ uint8_t kbd_raw_poll(void) __naked
|
||||
kp_next:
|
||||
in a, (#_IRQ_SIO_A)
|
||||
rrca ; ещё байт в FIFO?
|
||||
jr C, kp_drain
|
||||
jp C, kp_drain
|
||||
|
||||
;; --- FIFO пуст: тот же разбор Rx-overrun, что и в трамплине.
|
||||
;; RR1 бит5 = Rx Overrun; без Error Reset (WR0 = 0x30) бит залипнет
|
||||
@@ -132,7 +173,11 @@ uint8_t kbd_raw_poll(void) __naked
|
||||
jr Z, kp_noovr
|
||||
ld a, #0x30
|
||||
out (#_IRQ_SIO_A), a ; WR0 Error Reset
|
||||
ld a, #1
|
||||
;; Сброс FSM префиксов — как KBD_Receiver_Overrun у DSS (чистит
|
||||
;; KEY_FLG): повисший 0xF0/0xE0 инвертировал бы следующий код.
|
||||
xor a, a
|
||||
ld (__kbdraw_pending), a
|
||||
inc a
|
||||
ld (__kbdraw_overrun), a ; снимет kbd_raw_sync()
|
||||
kp_noovr:
|
||||
pop bc
|
||||
|
||||
Reference in New Issue
Block a user