# 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-коды Значения уже объявлены в ``: | Клавиша | 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.