/**
* Чистое чтение навигации меню: без Pixi, тестируется изолированно.
* Движок не привязан к раскладке — имена действий даёт сцена (биндятся игрой).
* Порядок событий за тик: cancel → move → (adjust XOR confirm) → extra.
*/
/** Карта действий меню (все — имена действий InputManager). */
export interface MenuActionMap {
up: string;
down: string;
/** Активировать выбранный пункт. */
confirm: string;
/** Назад / закрыть панель. */
cancel: string;
/** Подстройка значения (настройки); нажатые left/right подавляют confirm. */
left?: string;
right?: string;
/** Прочие действия сцены (удаление сейва, открытие сумки и т.п.). */
extra?: readonly string[];
}
export type MenuNavEvent =
| { kind: 'move'; delta: -1 | 1; index: number }
| { kind: 'adjust'; delta: -1 | 1; index: number }
| { kind: 'confirm'; index: number }
| { kind: 'cancel' }
| { kind: 'action'; action: string; index: number };
/** Источник «нажато в этом тике» — InputManager (или заглушка в тестах). */
export interface MenuInputSource {
isActionJustPressed(action: string): boolean;
}
/** Прочитать навигационные события за один тик. */
export function readMenuInput(input: MenuInputSource, index: number, map: MenuActionMap): MenuNavEvent[] {
if (input.isActionJustPressed(map.cancel)) return [{ kind: 'cancel' }];
const events: MenuNavEvent[] = [];
if (input.isActionJustPressed(map.up)) events.push({ kind: 'move', delta: -1, index });
else if (input.isActionJustPressed(map.down)) events.push({ kind: 'move', delta: 1, index });
// left/right перекрывают confirm: в настройках Enter не должен давать двойной шаг
const left = map.left !== undefined && input.isActionJustPressed(map.left);
const right = map.right !== undefined && input.isActionJustPressed(map.right);
if (left || right) events.push({ kind: 'adjust', delta: right ? 1 : -1, index });
else if (input.isActionJustPressed(map.confirm)) events.push({ kind: 'confirm', index });
for (const action of map.extra ?? []) {
if (input.isActionJustPressed(action)) events.push({ kind: 'action', action, index });
}
return events;
}