Skip to content

Глава 5.2: inputs.xml --- Пользовательские клавиши

Главная | << Предыдущая: stringtable.csv | inputs.xml | Следующая: Credits.json >>


Краткое описание: Файл inputs.xml позволяет вашему моду регистрировать пользовательские назначения клавиш, которые отображаются в меню настроек управления игрока. Игроки могут просматривать, переназначать и переключать эти привязки так же, как и стандартные действия. Это стандартный механизм для добавления горячих клавиш в моды DayZ.


Содержание


Обзор

Когда вашему моду нужно, чтобы игрок нажал клавишу --- открыть меню, переключить функцию, отдать команду AI-юниту --- вы регистрируете пользовательское действие ввода в inputs.xml. Движок считывает этот файл при запуске и интегрирует ваши действия в единую систему ввода. Игроки видят ваши назначения клавиш в игровом меню Настройки > Управление, сгруппированные под заголовком, который вы определяете.

Пользовательские привязки идентифицируются уникальным именем действия (по соглашению с префиксом UA от «User Action») и могут иметь привязки по умолчанию, которые игроки могут переназначить по желанию.


Расположение файла

Поместите inputs.xml в подпапку data вашей директории Scripts:

@MyMod/
  Addons/
    MyMod_Scripts.pbo
      Scripts/
        data/
          inputs.xml        <-- Здесь
        3_Game/
        4_World/
        5_Mission/

Некоторые моды размещают его прямо в папке Scripts/. Оба расположения работают. Движок обнаруживает файл автоматически --- регистрация в config.cpp не требуется.


Полная структура XML

Файл inputs.xml состоит из трёх секций, обёрнутых в корневой элемент <modded_inputs>:

xml
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<modded_inputs>
    <inputs>
        <actions>
            <!-- Определения действий размещаются здесь -->
        </actions>

        <sorting name="mymod" loc="STR_MYMOD_INPUT_GROUP">
            <!-- Порядок сортировки для меню настроек -->
        </sorting>
    </inputs>
    <preset>
        <!-- Назначения клавиш по умолчанию размещаются здесь -->
    </preset>
</modded_inputs>

Все три секции --- <actions>, <sorting> и <preset> --- работают вместе, но служат разным целям.


Блок Actions

Блок <actions> объявляет каждое действие ввода, которое предоставляет ваш мод. Каждое действие --- это один элемент <input>.

Синтаксис

xml
<actions>
    <input name="UAMyModOpenMenu" loc="STR_MYMOD_INPUT_OPEN_MENU" />
    <input name="UAMyModToggleHUD" loc="STR_MYMOD_INPUT_TOGGLE_HUD" />
</actions>

Атрибуты

АтрибутОбязателенОписание
nameДаУникальный идентификатор действия. Соглашение: префикс UA (User Action). Используется в скриптах для опроса этого ввода.
locНетКлюч stringtable для отображаемого имени в меню Управление. Без префикса # --- система добавляет его сама.
visibleНетУстановите "false", чтобы скрыть из меню Управление. По умолчанию true.

Соглашение об именовании

Имена действий должны быть глобально уникальными среди всех загруженных модов. Используйте префикс вашего мода:

xml
<input name="UAMyModAdminPanel" loc="STR_MYMOD_INPUT_ADMIN_PANEL" />
<input name="UAExpansionBookToggle" loc="STR_EXPANSION_BOOK_TOGGLE" />
<input name="eAICommandMenu" loc="STR_EXPANSION_AI_COMMAND_MENU" />

Префикс UA является соглашением, но не обязателен. Expansion AI использует eAI в качестве префикса, что тоже работает.


Блок Sorting

Блок <sorting> управляет тем, как ваши привязки отображаются в настройках Управления. Он определяет именованную группу (которая становится заголовком секции) и перечисляет привязки в порядке отображения.

Синтаксис

xml
<sorting name="mymod" loc="STR_MYMOD_INPUT_GROUP">
    <input name="UAMyModOpenMenu" />
    <input name="UAMyModToggleHUD" />
    <input name="UAMyModSpecialAction" />
</sorting>

Атрибуты

АтрибутОбязателенОписание
nameДаВнутренний идентификатор этой группы сортировки
locДаКлюч stringtable для заголовка группы, отображаемого в Настройки > Управление

Как это выглядит

В настройках Управления игрок видит:

[MyMod]                          <-- из loc блока sorting
  Open Menu .............. [Y]   <-- из loc привязки + preset
  Toggle HUD ............. [H]   <-- из loc привязки + preset

В меню настроек отображаются только привязки, перечисленные в блоке <sorting>. Привязки, определённые в <actions>, но не указанные в <sorting>, молча регистрируются, но невидимы для игрока (даже если visible не установлен явно в false).


Блок Preset (привязки по умолчанию)

Блок <preset> назначает клавиши по умолчанию для ваших действий. Это клавиши, с которых игрок начинает до любой настройки.

Простая привязка клавиши

xml
<preset>
    <input name="UAMyModOpenMenu">
        <btn name="kY"/>
    </input>
</preset>

Это привязывает клавишу Y по умолчанию для UAMyModOpenMenu.

Без клавиши по умолчанию

Если вы не включите действие в блок <preset>, у него не будет привязки по умолчанию. Игрок должен будет вручную назначить клавишу в Настройки > Управление. Это уместно для необязательных или продвинутых привязок.


Комбинации с модификаторами

Чтобы потребовать клавишу-модификатор (Ctrl, Shift, Alt), вложите элементы <btn>:

Ctrl + Левая кнопка мыши

xml
<input name="eAISetWaypoint">
    <btn name="kLControl">
        <btn name="mBLeft"/>
    </btn>
</input>

Внешний <btn> --- это модификатор; внутренний <btn> --- это основная клавиша. Игрок должен удерживать модификатор и затем нажать основную клавишу.

Shift + Клавиша

xml
<input name="UAMyModQuickAction">
    <btn name="kLShift">
        <btn name="kQ"/>
    </btn>
</input>

Правила вложенности

  • Внешний <btn> всегда является модификатором (удерживается)
  • Внутренний <btn> является триггером (нажимается при удержании модификатора)
  • Обычно используется только один уровень вложенности; более глубокая вложенность не протестирована и не рекомендуется

Скрытые привязки

Используйте visible="false", чтобы зарегистрировать привязку, которую игрок не может видеть или переназначить в меню Управление. Это полезно для внутренних привязок, используемых кодом вашего мода, которые не должны настраиваться игроком.

xml
<actions>
    <input name="eAITestInput" visible="false" />
    <input name="UAExpansionConfirm" loc="" visible="false" />
</actions>

Скрытые привязки всё равно могут иметь назначения клавиш по умолчанию в блоке <preset>:

xml
<preset>
    <input name="eAITestInput">
        <btn name="kY"/>
    </input>
</preset>

Несколько клавиш по умолчанию

Действие может иметь несколько клавиш по умолчанию. Перечислите несколько элементов <btn> как соседние:

xml
<input name="UAExpansionConfirm">
    <btn name="kReturn" />
    <btn name="kNumpadEnter" />
</input>

И Enter, и Numpad Enter будут вызывать UAExpansionConfirm. Это полезно для действий, где несколько физических клавиш должны соответствовать одному логическому действию.


Доступ к привязкам из скрипта

Получение API ввода

Весь доступ к вводу идёт через GetUApi(), который возвращает глобальный API пользовательских действий:

c
UAInput input = GetUApi().GetInputByName("UAMyModOpenMenu");

Опрос в OnUpdate

Пользовательские привязки обычно опрашиваются в MissionGameplay.OnUpdate() или аналогичных покадровых обратных вызовах:

c
modded class MissionGameplay
{
    override void OnUpdate(float timeslice)
    {
        super.OnUpdate(timeslice);

        UAInput input = GetUApi().GetInputByName("UAMyModOpenMenu");

        if (input.LocalPress())
        {
            // Клавиша была нажата в этом кадре
            OpenMyModMenu();
        }
    }
}

Альтернатива: использование имени привязки напрямую

Многие моды проверяют ввод инлайн, используя методы UAInputAPI со строковыми именами:

c
override void OnUpdate(float timeslice)
{
    super.OnUpdate(timeslice);

    Input input = GetGame().GetInput();

    if (input.LocalPress("UAMyModOpenMenu", false))
    {
        OpenMyModMenu();
    }
}

Параметр false в LocalPress("name", false) указывает, что проверка не должна поглощать событие ввода.


Справочник по методам ввода

Получив ссылку на UAInput (через GetUApi().GetInputByName()) или используя класс Input напрямую, эти методы определяют различные состояния ввода:

МетодВозвращаетКогда true
LocalPress()boolКлавиша была нажата в этом кадре (однократное срабатывание при нажатии)
LocalRelease()boolКлавиша была отпущена в этом кадре (однократное срабатывание при отпускании)
LocalClick()boolКлавиша была нажата и быстро отпущена (тап)
LocalHold()boolКлавиша удерживается в течение пороговой длительности
LocalDoubleClick()boolКлавиша была нажата дважды быстро
LocalValue()floatТекущее аналоговое значение (0.0 или 1.0 для цифровых клавиш; переменное для аналоговых осей)

Паттерны использования

Переключение по нажатию:

c
if (input.LocalPress("UAMyModToggle", false))
{
    m_IsEnabled = !m_IsEnabled;
}

Удержание для активации, отпускание для деактивации:

c
if (input.LocalPress("eAICommandMenu", false))
{
    ShowCommandWheel();
}

if (input.LocalRelease("eAICommandMenu", false) || input.LocalValue("eAICommandMenu", false) == 0)
{
    HideCommandWheel();
}

Действие по двойному нажатию:

c
if (input.LocalDoubleClick("UAMyModSpecial", false))
{
    PerformSpecialAction();
}

Удержание для длительного действия:

c
if (input.LocalHold("UAExpansionGPSToggle"))
{
    ToggleGPSMode();
}

Подавление и отключение ввода

ForceDisable

Временно отключает конкретную привязку. Обычно используется при открытии меню для предотвращения срабатывания игровых действий, пока активен UI:

c
// Отключить ввод, пока меню открыто
GetUApi().GetInputByName("UAMyModToggle").ForceDisable(true);

// Включить обратно при закрытии меню
GetUApi().GetInputByName("UAMyModToggle").ForceDisable(false);

SupressNextFrame

Подавляет всю обработку ввода на следующий кадр. Используется при переходах контекста ввода (например, закрытие меню) для предотвращения однокадрового «пробоя» ввода:

c
GetUApi().SupressNextFrame(true);

UpdateControls

После изменения состояний ввода вызовите UpdateControls(), чтобы применить изменения немедленно:

c
GetUApi().GetInputByName("UAExpansionBookToggle").ForceDisable(false);
GetUApi().UpdateControls();

Исключения ввода

Стандартная система миссий предоставляет группы исключений. Когда меню активно, вы можете исключить категории ввода:

c
// Подавить игровой ввод, пока инвентарь открыт
AddActiveInputExcludes({"inventory"});

// Восстановить при закрытии
RemoveActiveInputExcludes({"inventory"});

Справочник имён клавиш

Имена клавиш, используемые в атрибуте <btn name="">, следуют определённому соглашению об именовании. Ниже приведён полный справочник.

Клавиши клавиатуры

КатегорияИмена клавиш
БуквыkA, kB, kC, kD, kE, kF, kG, kH, kI, kJ, kK, kL, kM, kN, kO, kP, kQ, kR, kS, kT, kU, kV, kW, kX, kY, kZ
Цифры (верхний ряд)k0, k1, k2, k3, k4, k5, k6, k7, k8, k9
Функциональные клавишиkF1, kF2, kF3, kF4, kF5, kF6, kF7, kF8, kF9, kF10, kF11, kF12
МодификаторыkLControl, kRControl, kLShift, kRShift, kLAlt, kRAlt
НавигацияkUp, kDown, kLeft, kRight, kHome, kEnd, kPageUp, kPageDown
РедактированиеkReturn, kBackspace, kDelete, kInsert, kSpace, kTab, kEscape
Цифровая клавиатураkNumpad0 ... kNumpad9, kNumpadEnter, kNumpadPlus, kNumpadMinus, kNumpadMultiply, kNumpadDivide, kNumpadDecimal
ПунктуацияkMinus, kEquals, kLBracket, kRBracket, kBackslash, kSemicolon, kApostrophe, kComma, kPeriod, kSlash, kGrave
БлокировкиkCapsLock, kNumLock, kScrollLock

Кнопки мыши

ИмяКнопка
mBLeftЛевая кнопка мыши
mBRightПравая кнопка мыши
mBMiddleСредняя кнопка мыши (нажатие колеса прокрутки)
mBExtra1Кнопка мыши 4 (боковая кнопка назад)
mBExtra2Кнопка мыши 5 (боковая кнопка вперёд)

Оси мыши

ИмяОсь
mAxisXГоризонтальное перемещение мыши
mAxisYВертикальное перемещение мыши
mWheelUpПрокрутка колеса вверх
mWheelDownПрокрутка колеса вниз

Паттерн именования

  • Клавиатура: префикс k + имя клавиши (например, kT, kF5, kLControl)
  • Кнопки мыши: префикс mB + имя кнопки (например, mBLeft, mBRight)
  • Оси мыши: префикс m + имя оси (например, mAxisX, mWheelUp)

Реальные примеры

DayZ Expansion AI

Хорошо структурированный inputs.xml с видимыми назначениями клавиш, скрытыми отладочными привязками и комбинациями с модификаторами:

xml
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<modded_inputs>
    <inputs>
        <actions>
            <input name="eAICommandMenu" loc="STR_EXPANSION_AI_COMMAND_MENU"/>
            <input name="eAISetWaypoint" loc="STR_EXPANSION_AI_SET_WAYPOINT"/>
            <input name="eAITestInput" visible="false" />
            <input name="eAITestLRIncrease" visible="false" />
            <input name="eAITestLRDecrease" visible="false" />
            <input name="eAITestUDIncrease" visible="false" />
            <input name="eAITestUDDecrease" visible="false" />
        </actions>

        <sorting name="expansion" loc="STR_EXPANSION_LABEL">
            <input name="eAICommandMenu" />
            <input name="eAISetWaypoint" />
            <input name="eAITestInput" />
            <input name="eAITestLRIncrease" />
            <input name="eAITestLRDecrease" />
            <input name="eAITestUDIncrease" />
            <input name="eAITestUDDecrease" />
        </sorting>
    </inputs>
    <preset>
        <input name="eAICommandMenu">
            <btn name="kT"/>
        </input>
        <input name="eAISetWaypoint">
            <btn name="kLControl">
                <btn name="mBLeft"/>
            </btn>
        </input>
        <input name="eAITestInput">
            <btn name="kY"/>
        </input>
        <input name="eAITestLRIncrease">
            <btn name="kRight"/>
        </input>
        <input name="eAITestLRDecrease">
            <btn name="kLeft"/>
        </input>
        <input name="eAITestUDIncrease">
            <btn name="kUp"/>
        </input>
        <input name="eAITestUDDecrease">
            <btn name="kDown"/>
        </input>
    </preset>
</modded_inputs>

Ключевые наблюдения:

  • eAICommandMenu привязан к T --- виден в настройках, игрок может переназначить
  • eAISetWaypoint использует комбинацию Ctrl + Левый клик с модификатором
  • Тестовые привязки имеют visible="false" --- скрыты от игроков, но доступны в коде

DayZ Expansion Market

Минимальный inputs.xml для скрытой служебной привязки с несколькими клавишами по умолчанию:

xml
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<modded_inputs>
    <inputs>
        <actions>
            <input name="UAExpansionConfirm" loc="" visible="false" />
        </actions>
    </inputs>
    <preset>
        <input name="UAExpansionConfirm">
            <btn name="kReturn" />
            <btn name="kNumpadEnter" />
        </input>
    </preset>
</modded_inputs>

Ключевые наблюдения:

  • Скрытая привязка (visible="false") с пустым loc --- никогда не показывается в настройках
  • Две клавиши по умолчанию: и Enter, и Numpad Enter вызывают одно и то же действие
  • Блок <sorting> отсутствует --- не нужен, поскольку привязка скрыта

Полный начальный шаблон

Минимальный, но полный шаблон для нового мода:

xml
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<modded_inputs>
    <inputs>
        <actions>
            <input name="UAMyModOpenMenu" loc="STR_MYMOD_INPUT_OPEN_MENU" />
            <input name="UAMyModQuickAction" loc="STR_MYMOD_INPUT_QUICK_ACTION" />
        </actions>

        <sorting name="mymod" loc="STR_MYMOD_INPUT_GROUP">
            <input name="UAMyModOpenMenu" />
            <input name="UAMyModQuickAction" />
        </sorting>
    </inputs>
    <preset>
        <input name="UAMyModOpenMenu">
            <btn name="kF6"/>
        </input>
        <!-- UAMyModQuickAction не имеет клавиши по умолчанию; игрок должен назначить -->
    </preset>
</modded_inputs>

С соответствующим stringtable.csv:

csv
"Language","original","english"
"STR_MYMOD_INPUT_GROUP","My Mod","My Mod"
"STR_MYMOD_INPUT_OPEN_MENU","Open Menu","Open Menu"
"STR_MYMOD_INPUT_QUICK_ACTION","Quick Action","Quick Action"

Распространённые ошибки

Использование # в атрибуте loc

xml
<!-- НЕПРАВИЛЬНО -->
<input name="UAMyAction" loc="#STR_MYMOD_ACTION" />

<!-- ПРАВИЛЬНО -->
<input name="UAMyAction" loc="STR_MYMOD_ACTION" />

Система ввода автоматически добавляет # перед значением. Если вы добавите его сами, произойдёт двойной префикс, и поиск не найдёт строку.

Коллизии имён действий

Если два мода определят UAOpenMenu, работать будет только один. Всегда используйте префикс вашего мода:

xml
<input name="UAMyModOpenMenu" />     <!-- Хорошо -->
<input name="UAOpenMenu" />          <!-- Рискованно -->

Пропущенная запись в Sorting

Если вы определите действие в <actions>, но забудете перечислить его в <sorting>, действие будет работать в коде, но будет невидимо в меню Управление. У игрока не будет возможности переназначить его.

Забыли определить в Actions

Если вы укажете привязку в <sorting> или <preset>, но никогда не определите её в <actions>, движок молча проигнорирует её.

Конфликтующие клавиши

Выбор клавиш, конфликтующих со стандартными привязками (например, W, A, S, D, Tab, I), приводит к одновременному срабатыванию и вашего действия, и стандартного. Используйте менее распространённые клавиши (F5-F12, клавиши цифровой клавиатуры) или комбинации с модификаторами для безопасности.


Лучшие практики

  • Всегда добавляйте к именам действий префикс UA + название вашего мода (например, UAMyModOpenMenu). Общие имена вроде UAOpenMenu будут конфликтовать с другими модами.
  • Указывайте атрибут loc для каждой видимой привязки и определяйте соответствующий ключ stringtable. Без этого в меню Управление отобразится сырое имя действия.
  • Выбирайте нераспространённые клавиши по умолчанию (F5-F12, цифровая клавиатура) или комбинации с модификаторами (Ctrl+клавиша), чтобы минимизировать конфликты со стандартными и популярными модовыми назначениями.
  • Всегда перечисляйте видимые привязки в блоке <sorting>. Привязка, определённая в <actions>, но отсутствующая в <sorting>, невидима для игрока и не может быть переназначена.
  • Кэшируйте ссылку UAInput из GetUApi().GetInputByName() в переменной-члене вместо того, чтобы вызывать её каждый кадр в OnUpdate. Поиск по строке имеет накладные расходы.

Теория vs Практика

Что говорит документация и как на самом деле работает в рантайме.

КонцепцияТеорияРеальность
visible="false" скрывает из меню УправлениеПривязка зарегистрирована, но невидимаСкрытые привязки всё равно появляются в списке блока <sorting> в некоторых версиях DayZ. Отсутствие в <sorting> --- надёжный способ скрыть привязки
LocalPress() срабатывает один раз при нажатииОднократное срабатывание в кадре нажатия клавишиЕсли игра «подтормаживает» (низкий FPS), LocalPress() может быть полностью пропущен. Для критических действий также проверяйте LocalValue() > 0 как запасной вариант
Комбинации с модификаторами через вложенные <btn>Внешний --- модификатор, внутренний --- триггерКлавиша-модификатор сама по себе также регистрируется как нажатие на свою собственную привязку (например, kLControl --- это ещё и стандартное приседание). Игрок, удерживающий Ctrl+Клик, также присядет
ForceDisable(true) подавляет вводВвод полностью игнорируетсяForceDisable сохраняется до явного повторного включения. Если ваш мод вылетит или UI закроется без вызова ForceDisable(false), ввод останется отключённым до перезапуска игры
Несколько соседних <btn>Обе клавиши вызывают одно действиеРаботает корректно, но меню Управление отображает только первую клавишу. Игрок может видеть и переназначить первую клавишу, но может не знать о существовании второй по умолчанию

Совместимость и влияние

  • Мульти-мод: Коллизии имён действий --- основной риск. Если два мода определят UAOpenMenu, работать будет только один, и конфликт произойдёт молча. Движок не выдаёт предупреждений о дублировании имён действий между модами.
  • Производительность: Опрос ввода через GetUApi().GetInputByName() включает поиск по хешу строки. Опрос 5-10 привязок за кадр ничтожен, но кэширование ссылки UAInput всё же рекомендуется для модов с большим количеством привязок.
  • Версия: Формат inputs.xml и структура <modded_inputs> стабильны с DayZ 1.0. Атрибут visible был добавлен позже (примерно в 1.08) --- в более ранних версиях все привязки всегда видны в меню Управление.

Наблюдения из реальных модов

ПаттернМодПодробности
Комбинация с модификатором Ctrl+ClickExpansion AIeAISetWaypoint использует вложенные <btn name="kLControl"><btn name="mBLeft"/> для Ctrl+Левый клик при размещении путевых точек AI
Скрытые служебные привязкиExpansion MarketUAExpansionConfirm имеет visible="false" с двумя клавишами (Enter + Numpad Enter) для внутренней логики подтверждения
ForceDisable при открытии менюCOT, VPPАдмин-панели вызывают ForceDisable(true) на игровых привязках при открытии панели и ForceDisable(false) при закрытии, чтобы предотвратить движение персонажа при наборе текста
Кэширование UAInput в переменной-членеDabsFrameworkСохраняет результат GetUApi().GetInputByName() в поле класса при инициализации, опрашивает кэшированную ссылку в OnUpdate, чтобы избежать покадрового поиска по строке

Released under CC BY-SA 4.0 | Code examples under MIT License