Volkov: добавить Sprinter Commander
Реализовать двухпанельный Commander от платформенного PoC до этапов P6-P20: EMM-каталог, сортировку и выбор, операции с файлами и деревьями, транзакционное копирование, метаданные, политику конфликтов и предварительную проверку свободного места. Добавить проектную документацию, HDD/MAME-сценарии и проверенные артефакты. Расширить libc операцией bank_write_page, исправлением режима O_RDONLY и связанными регрессионными проверками.
This commit is contained in:
@@ -0,0 +1,324 @@
|
||||
# Sprinter Commander: клавиши и команды
|
||||
|
||||
Статус: PoC и первые команды 0.2 подтверждены в MAME
|
||||
|
||||
Связанные документы:
|
||||
[требования](commander-requirements.md),
|
||||
[архитектура](commander-architecture.md),
|
||||
[план разработки](commander-roadmap.md)
|
||||
|
||||
## 1. Назначение
|
||||
|
||||
Документ отделяет физические клавиши Sprinter от логических команд
|
||||
Commander. Только модуль `sc_input.c` знает scan-коды, а только
|
||||
`sc_command.c` знает таблицу их назначения.
|
||||
|
||||
Панели и операции получают значения `ScCommand`, а не результаты `getkey()`.
|
||||
Это позволяет позднее добавить мышь, переназначение клавиш и альтернативную
|
||||
клавиатуру без изменений файловых функций.
|
||||
|
||||
## 2. Формат события
|
||||
|
||||
```c
|
||||
enum {
|
||||
SC_MOD_SHIFT = 0x01,
|
||||
SC_MOD_CTRL = 0x02,
|
||||
SC_MOD_ALT = 0x04
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
uint8_t ascii;
|
||||
uint8_t scan;
|
||||
uint8_t modifiers;
|
||||
} ScKeyEvent;
|
||||
```
|
||||
|
||||
Правила нормализации:
|
||||
|
||||
- обычный символ записывается в `ascii`;
|
||||
- расширенная клавиша записывается в `scan`, `ascii == 0`;
|
||||
- при активном Ctrl/Alt/Shift DSS может установить бит 7 scan-кода;
|
||||
диагностическая трассировка показывает raw-значение, а `sc_input`
|
||||
передаёт командам базовый `scan & 0x7F`;
|
||||
- левый и правый Shift объединяются в `SC_MOD_SHIFT`;
|
||||
- левый и правый Ctrl объединяются в `SC_MOD_CTRL`;
|
||||
- левый и правый Alt объединяются в `SC_MOD_ALT`;
|
||||
- CapsLock, NumLock, ScrollLock, Insert и Rus/Lat не являются модификаторами
|
||||
команды;
|
||||
- управляющий ASCII-код имеет приоритет над live-состоянием модификатора;
|
||||
- неизвестная комбинация преобразуется в `SC_CMD_NONE`.
|
||||
|
||||
## 3. Подтверждённые расширенные scan-коды
|
||||
|
||||
Значения уже объявлены в `<conio.h>`:
|
||||
|
||||
| Клавиша | Scan-код | Макрос |
|
||||
|---|---:|---|
|
||||
| F1 | `0x3B` | `KEY_F1` |
|
||||
| F2 | `0x3C` | `KEY_F2` |
|
||||
| F3 | `0x3D` | `KEY_F3` |
|
||||
| F4 | `0x3E` | `KEY_F4` |
|
||||
| F5 | `0x3F` | `KEY_F5` |
|
||||
| F6 | `0x40` | `KEY_F6` |
|
||||
| F7 | `0x41` | `KEY_F7` |
|
||||
| F8 | `0x42` | `KEY_F8` |
|
||||
| F9 | `0x43` | `KEY_F9` |
|
||||
| F10 | `0x44` | `KEY_F10` |
|
||||
| End | `0x51` | `KEY_END` |
|
||||
| Down | `0x52` | `KEY_DOWN` |
|
||||
| PgDn | `0x53` | `KEY_PGDN` |
|
||||
| Left | `0x54` | `KEY_LEFT` |
|
||||
| Delete | `0x55` | `KEY_DEL` |
|
||||
| Right | `0x56` | `KEY_RIGHT` |
|
||||
| Home | `0x57` | `KEY_HOME` |
|
||||
| Up | `0x58` | `KEY_UP` |
|
||||
| PgUp | `0x59` | `KEY_PGUP` |
|
||||
| Insert | `0x50` | `KEY_INS` |
|
||||
|
||||
Все значения таблицы, включая `Insert` и `Delete`, подтверждены P1-пробой в
|
||||
MAME. `F11` и `F12` в P1 не проверялись и остаются неподтверждёнными до
|
||||
появления команды, которая их использует.
|
||||
|
||||
Фактическая последовательность MAME для навигации была:
|
||||
`Up=58`, `Down=52`, `Left=54`, `Right=56`, `Home=57`, `End=51`,
|
||||
`PgUp=59`, `PgDn=53`, `Insert=50`, `Delete=55`. F1–F10 дали непрерывный
|
||||
диапазон `3B..44`.
|
||||
|
||||
## 4. Логические команды
|
||||
|
||||
Численные значения enum не являются стабильным ABI до версии 0.2.
|
||||
|
||||
```c
|
||||
typedef enum {
|
||||
SC_CMD_NONE = 0,
|
||||
|
||||
SC_CMD_CURSOR_UP,
|
||||
SC_CMD_CURSOR_DOWN,
|
||||
SC_CMD_CURSOR_LEFT,
|
||||
SC_CMD_CURSOR_RIGHT,
|
||||
SC_CMD_PAGE_UP,
|
||||
SC_CMD_PAGE_DOWN,
|
||||
SC_CMD_HOME,
|
||||
SC_CMD_END,
|
||||
SC_CMD_PANEL_SWITCH,
|
||||
SC_CMD_OPEN,
|
||||
SC_CMD_PARENT,
|
||||
SC_CMD_ROOT,
|
||||
SC_CMD_REFRESH,
|
||||
SC_CMD_CANCEL,
|
||||
|
||||
SC_CMD_SELECT,
|
||||
SC_CMD_SELECT_MASK,
|
||||
SC_CMD_UNSELECT_MASK,
|
||||
SC_CMD_INVERT_SELECTION,
|
||||
|
||||
SC_CMD_HELP,
|
||||
SC_CMD_USER_MENU,
|
||||
SC_CMD_VIEW,
|
||||
SC_CMD_EDIT,
|
||||
SC_CMD_COPY,
|
||||
SC_CMD_MOVE_RENAME,
|
||||
SC_CMD_MKDIR,
|
||||
SC_CMD_DELETE,
|
||||
SC_CMD_MAIN_MENU,
|
||||
SC_CMD_QUIT,
|
||||
|
||||
SC_CMD_LEFT_DRIVE,
|
||||
SC_CMD_RIGHT_DRIVE,
|
||||
SC_CMD_SWAP_PANELS,
|
||||
SC_CMD_TOGGLE_SHELL,
|
||||
SC_CMD_QUICK_VIEW,
|
||||
SC_CMD_INFO_PANEL,
|
||||
SC_CMD_FIND,
|
||||
SC_CMD_TREE
|
||||
} ScCommand;
|
||||
```
|
||||
|
||||
Дополнительные команды вводятся при появлении соответствующей функции, а не
|
||||
заранее в обработчиках-заглушках.
|
||||
|
||||
## 5. Клавиши PoC 0.1
|
||||
|
||||
### 5.1. Навигация панели
|
||||
|
||||
| Клавиша | Команда | Поведение PoC |
|
||||
|---|---|---|
|
||||
| `Up` | `SC_CMD_CURSOR_UP` | На одну запись вверх |
|
||||
| `Down` | `SC_CMD_CURSOR_DOWN` | На одну запись вниз |
|
||||
| `PgUp` | `SC_CMD_PAGE_UP` | На 27 записей вверх |
|
||||
| `PgDn` | `SC_CMD_PAGE_DOWN` | На 27 записей вниз |
|
||||
| `Home` | `SC_CMD_HOME` | Первая запись |
|
||||
| `End` | `SC_CMD_END` | Последняя запись |
|
||||
| `Left` | `SC_CMD_NONE` | Не используется в одноколоночной панели PoC |
|
||||
| `Right` | `SC_CMD_NONE` | Не используется в одноколоночной панели PoC |
|
||||
| `Tab` | `SC_CMD_PANEL_SWITCH` | Переключить активную панель |
|
||||
| `Enter` | `SC_CMD_OPEN` | Войти в каталог или запустить `.EXE` |
|
||||
| `Ctrl+PgUp` | `SC_CMD_PARENT` | Перейти в родительский каталог |
|
||||
| `Backspace` | `SC_CMD_PARENT` | То же, пока командной строки нет |
|
||||
| `Ctrl+R` | `SC_CMD_REFRESH` | Перечитать активную панель |
|
||||
| `Ctrl+F3` | `SC_CMD_SORT_NAME` | Имя; повторное нажатие меняет направление |
|
||||
| `Ctrl+F4` | `SC_CMD_SORT_EXTENSION` | Расширение; повтор меняет направление |
|
||||
| `Ctrl+F5` | `SC_CMD_SORT_DATE` | Дата/время; повтор меняет направление |
|
||||
| `Ctrl+F6` | `SC_CMD_SORT_SIZE` | Размер; повтор меняет направление |
|
||||
| `Insert` | `SC_CMD_SELECT` | Выбрать/снять текущую запись и перейти вниз |
|
||||
| `*` | `SC_CMD_INVERT_SELECTION` | Инвертировать только файлы панели; каталоги не менятся |
|
||||
|
||||
`SC_CMD_CURSOR_LEFT/RIGHT` сохраняются в enum для будущего многоколоночного
|
||||
режима, но PoC их не генерирует.
|
||||
|
||||
### 5.2. Функциональные клавиши PoC
|
||||
|
||||
| Клавиша | Команда | Состояние |
|
||||
|---|---|---|
|
||||
| `F1` | `SC_CMD_HELP` | Зарезервирована, неактивна |
|
||||
| `F2` | `SC_CMD_USER_MENU` | Зарезервирована, неактивна |
|
||||
| `F3` | `SC_CMD_VIEW` | Зарезервирована, неактивна |
|
||||
| `F4` | `SC_CMD_EDIT` | Зарезервирована, неактивна |
|
||||
| `F5` | `SC_CMD_COPY` | Один файл/каталог либо группа выбранных файлов и directory roots |
|
||||
| `F6` | `SC_CMD_MOVE_RENAME` | Локальный rename одной записи; move/group позже в 0.2 |
|
||||
| `F7` | `SC_CMD_MKDIR` | Создать каталог; 0.2, выполнено |
|
||||
| `F8` | `SC_CMD_DELETE` | Одна запись либо выбранная группа; каталоги группы удаляются рекурсивно после одного подтверждения |
|
||||
| `F9` | `SC_CMD_MAIN_MENU` | Зарезервирована, неактивна |
|
||||
| `F10` | `SC_CMD_QUIT` | Открыть подтверждение штатного выхода |
|
||||
|
||||
PoC не должен выполнять разрушительное действие по неактивной клавише.
|
||||
|
||||
### 5.3. Общие клавиши PoC
|
||||
|
||||
| Клавиша | Команда | Контекст |
|
||||
|---|---|---|
|
||||
| `Esc` | `SC_CMD_CANCEL` | Закрыть сообщение или отменить job |
|
||||
| `Esc` | `SC_CMD_NONE` | Обычный режим панелей |
|
||||
| `Enter` | подтвердить | Диалог сообщения |
|
||||
| `Y`/`N` | да/нет | Диалог подтверждения, если он появится |
|
||||
|
||||
## 6. Контекстная обработка
|
||||
|
||||
Одна клавиша может иметь разное действие в зависимости от режима. Приоритет
|
||||
обработчиков фиксирован:
|
||||
|
||||
1. Активная аварийная ошибка.
|
||||
2. Модальный диалог.
|
||||
3. Активный job.
|
||||
4. Командная строка или полноэкранный pseudo-shell версии 1.0.
|
||||
5. Активная панель.
|
||||
6. Глобальные команды приложения.
|
||||
|
||||
Примеры:
|
||||
|
||||
- Во время копирования `Esc` запрашивает отмену, но `F10` не завершает
|
||||
процесс немедленно.
|
||||
- В диалоге `Enter` подтверждает кнопку, а не открывает файл под курсором.
|
||||
- После закрытия диалога то же событие не передаётся панели повторно.
|
||||
- `F10` во время job игнорируется с подсказкой отменять операцию через `Esc`;
|
||||
подтверждение выхода открывается только после завершения или отмены job.
|
||||
- В режиме панелей печатный символ передаётся однострочному редактору;
|
||||
`Enter` выполняет непустую строку, а при пустой строке открывает запись.
|
||||
- В pseudo-shell `Up/Down` листают историю команд, а не панель; `Ctrl+O`
|
||||
возвращает панели с сохранёнными путями и курсорами.
|
||||
- `Esc` сначала очищает непустую команду, затем закрывает полноэкранный режим;
|
||||
событие не передаётся следующему контексту повторно.
|
||||
|
||||
## 7. Нормализация управляющих ASCII-кодов
|
||||
|
||||
На части клавиатур `Ctrl+буква` может приходить как ASCII `0x01–0x1A` без
|
||||
надёжного сохранения состояния Ctrl. Поэтому ввод должен распознавать
|
||||
следующие значения независимо от `kbd_mod_state()`:
|
||||
|
||||
| ASCII | Комбинация | Команда |
|
||||
|---:|---|---|
|
||||
| `0x12` | `Ctrl+R` | `SC_CMD_REFRESH` |
|
||||
| `0x15` | `Ctrl+U` | `SC_CMD_SWAP_PANELS`, после PoC |
|
||||
| `0x0F` | `Ctrl+O` | `SC_CMD_TOGGLE_SHELL`, обязательно к 1.0 |
|
||||
| `0x11` | `Ctrl+Q` | `SC_CMD_QUICK_VIEW`, после PoC |
|
||||
| `0x0C` | `Ctrl+L` | `SC_CMD_INFO_PANEL`, после PoC |
|
||||
|
||||
`Tab` (`0x09`), `Enter` (`0x0D`), `Esc` (`0x1B`) и `Backspace` (`0x08`)
|
||||
обрабатываются как обычные управляющие ASCII-клавиши.
|
||||
|
||||
P1 в MAME показал второй, фактически основной для текущего DSS путь:
|
||||
|
||||
| Комбинация | ASCII | Raw scan | Base scan | `kbd_mod_state()` | Compact |
|
||||
|---|---:|---:|---:|---:|---:|
|
||||
| `Ctrl+R` | `00` | `93` | `13` | `0028` | `02` |
|
||||
| `Ctrl+PgUp` | `00` | `D9` | `59` | `0028` | `02` |
|
||||
| `Alt+F1` | `00` | `BB` | `3B` | `0014` | `04` |
|
||||
| `Esc` | `1B` | `01` | `01` | `0000` | `00` |
|
||||
|
||||
Таким образом, `sc_input` обязан поддерживать оба представления: сначала
|
||||
управляющий ASCII-код, затем пару `(base scan, modifiers)`. Проверять raw
|
||||
scan `93/D9/BB` прямо в таблице команд нельзя: базовый scan с модификатором
|
||||
получается снятием бита 7. Скриншоты пробы находятся в
|
||||
[`artifacts/mame-p1/keyboard-commander`](../artifacts/mame-p1/keyboard-commander/sprinter/0003.png).
|
||||
|
||||
## 8. Предварительная карта полной версии
|
||||
|
||||
Эта таблица резервирует привычные сочетания VC, но не является требованием
|
||||
PoC.
|
||||
|
||||
| Клавиша | Команда | Планируемая версия |
|
||||
|---|---|---:|
|
||||
| `Insert` | Выделить/снять выделение и перейти вниз | 0.2, выполнено |
|
||||
| `Gray +` или `+` | Выделить по маске | 0.2, обычный `+` выполнен |
|
||||
| `Gray -` или `-` | Снять выделение по маске | 0.2, обычный `-` выполнен |
|
||||
| `Gray *` или `*` | Инвертировать выделение | 0.2, `*` выполнено |
|
||||
| `F1` | Помощь | 0.4 |
|
||||
| `F2` | Пользовательское меню | 0.4 |
|
||||
| `F3` | Просмотр | 0.4 |
|
||||
| `F4` | Редактор | 0.4 |
|
||||
| `F5` | Копирование | 0.1/0.2 |
|
||||
| `F6` | Перемещение/переименование | 0.2, локальный rename выполнен |
|
||||
| `F7` | Создать каталог | 0.2, выполнено |
|
||||
| `F8` | Удалить | 0.2, single и recursive group выполнены |
|
||||
| `F9` | Главное меню | 0.4 |
|
||||
| `F10` | Выход | 0.1 |
|
||||
| `Alt+F1` | Диск левой панели | 0.4 |
|
||||
| `Alt+F2` | Диск правой панели | 0.4 |
|
||||
| `Alt+F7` | Поиск файлов | 0.6 |
|
||||
| `Alt+F10` | Дерево каталогов | 0.6 |
|
||||
| `Ctrl+R` | Перечитать панель | 0.1 |
|
||||
| `Ctrl+F3..F6` | Name/ext/date/size, повтор меняет направление | 0.2 |
|
||||
| `Ctrl+U` | Обменять панели местами | 0.4 |
|
||||
| `Ctrl+O` | Панели / интерактивный полноэкранный pseudo-shell | 0.4/1.0 |
|
||||
| `Ctrl+PgUp` | Родительский каталог | 0.1 |
|
||||
| `Ctrl+\` | Корень текущего диска | 0.2 |
|
||||
| `Ctrl+Q` | Quick view | 0.6 |
|
||||
| `Ctrl+L` | Информационная панель | 0.6 |
|
||||
|
||||
Shift-варианты функциональных клавиш не резервируются до появления
|
||||
конкретной необходимости. Это предотвращает преждевременное копирование всей
|
||||
таблицы VC без соответствующей функции.
|
||||
|
||||
## 9. Нижняя строка клавиш
|
||||
|
||||
Строка 31 содержит десять сегментов шириной по восемь символов. В PoC:
|
||||
|
||||
```text
|
||||
1 Help 2 Menu 3 View 4 Edit 5 Copy 6 Ren 7 Mkdir 8 Delete9 Menu 10 Quit
|
||||
```
|
||||
|
||||
Это логическая схема, а не точная строка байтов. Названия сокращаются до
|
||||
доступной ширины. Поддерживаемые действия (`F5`, `F10`) рисуются активным
|
||||
цветом, остальные — неактивным.
|
||||
|
||||
После добавления модификатора строка клавиш может временно показывать
|
||||
назначения `Alt`/`Ctrl`, но это не входит в PoC.
|
||||
|
||||
## 10. Проверки клавиатуры P1/P2
|
||||
|
||||
В P1 на MAME подтверждены F1–F10, восемь навигационных клавиш,
|
||||
Insert/Delete, Esc, Ctrl+R, Ctrl+PgUp и Alt+F1. Отдельная проба также
|
||||
подтвердила compact-состояния Shift=`01`, Ctrl=`02`, Alt=`04`.
|
||||
|
||||
В P2 остаются поведенческие проверки уже внутри UI:
|
||||
|
||||
1. `Tab`, `Enter` и `Backspace` во всех контекстах.
|
||||
2. Одновременное удержание нескольких модификаторов.
|
||||
3. CapsLock, NumLock и Rus/Lat.
|
||||
4. Отсутствие повторного выполнения события после закрытия диалога.
|
||||
5. Keyboard repeat на границах списка.
|
||||
6. Приём `Esc` во время копирования большого файла.
|
||||
7. Повтор P1-набора на реальном Sprinter.
|
||||
|
||||
Любое расхождение с таблицей сначала оформляется отдельным репро и только
|
||||
затем учитывается в Commander.
|
||||
Reference in New Issue
Block a user