Как устроен проект¶
OpenKatana — это две независимые реализации одной задачи: настроить клавиатуру GANSS ARDOR Katana из Linux.
katana.py делает это из терминала на Python, Katana Studio — в окне на Electron и TypeScript.
Обе работают с одним устройством, одним порядком записи и одним форматом YAML-профиля.
Третья часть проекта — репозиторий документации docs, из которого собирается сайт katana.axenov.dev.
Репозитории katana.py и studio содержат только сведения о запуске, отладке и сборке, а полная документация живёт здесь.
Компоненты¶
| Компонент | Где лежит | Роль |
|---|---|---|
katana.py |
katana.py |
Команды, библиотека Katana, офлайн-тесты, дампы трафика. |
| Katana Studio | studio |
Окно, вкладки, предпросмотр, профили, офлайн-тесты. |
| Документация | docs |
Исходники сайта на Zensical и его сборка. |
Утилита и приложение не зависят друг от друга.
Их связывает профиль: YAML-файл, который применяет ./katana.py apply и читает окно приложения.
Общая схема¶
katana.py ──┐
├── HID feature-репорты ──► клавиатура
Studio ─────┘
Studio ◄── YAML-профиль ──► katana.py
Доступ к устройству¶
Обе реализации отправляют клавиатуре HID feature-репорты через штатный драйвер usbhid.
Драйвер при этом не отцепляется, поэтому печатать можно прямо во время настройки.
На Linux нужен доступ к узлу hidraw: его выдаёт udev-правило 70-ganss-katana.rules.
Правило ставится один раз, после него root не нужен.
Пакет deb приложения ставит правило сам.
На macOS поддержка экспериментальная.
katana.py работает через IOKit напрямую: чтение и запись проверены на железе при выключенном Karabiner.
Katana Studio использует node-hid, и система не разрешает ему запись feature-репортов: окно показывает состояние и живые кадры, но менять настройки не может.
Для полной настройки через приложение нужен Linux.
Очередь операций¶
Прошивка не переносит пересекающиеся транзакции: если отправить две операции одновременно, сессия может «залипнуть». Поэтому и утилита, и приложение выполняют операции по одной.
В приложении за это отвечает KatanaService: он выстраивает вызовы в цепочку, открывает устройство на время операции и закрывает после неё.
Пока операция идёт, кнопки записи в окне недоступны.
Между запросами выдерживается пауза 40 мс, поэтому запись таблицы раскраски занимает около 0,6 секунды, а смена режима — около 0,4 секунды.
Оперативная память и флеш¶
Настройку можно применить двумя способами:
- только в оперативную память — действует до переподключения клавиатуры;
- с записью во флеш — переживает выключение и переподключение.
Флеш-память имеет ограниченный ресурс перезаписи, поэтому все флажки «Записать в устройство» в окне по умолчанию выключены. Предпросмотр раскраски и поток живых кадров во флеш не пишут никогда.
Профиль¶
Профиль — обычный YAML-файл с секциями remap, paint, mode, raw и macro.
Секции названы по командам CLI, а их ключи — по аргументам этих команд.
Приложение пишет две секции по-старому: lighting вместо mode и macros вместо macro.
Такой профиль apply отклонит как неизвестный, поэтому профиль из окна сейчас не переносится в CLI автоматически.
Расхождение записано в todo.md репозитория katana.py.
При применении секции идут в одном порядке: переназначения, раскраска, режим подсветки, произвольный payload и макросы.
Раскраска и режим конфликтуют: раскраска видна только в своём режиме, поэтому при её наличии секция mode пропускается с предупреждением.
Запись макросов сбивает переназначения и режим подсветки в оперативной памяти.
Поэтому после макросов приложение и apply перепосылают эти секции заново.
Живые кадры и предпросмотр¶
Клавиатура умеет отдавать текущий кадр подсветки: цвет каждой клавиши в данный момент. Приложение читает такие кадры потоком, примерно 12–15 кадров в секунду, и показывает их на визуальной клавиатуре.
Поток не пишет во флеш и уступает очередь любой другой операции. Если клавиатура не подключена или кадры не приходят, окно переключается на имитацию режимов.
Имитация считает кадры по формулам, подобранным по записям с железа. Она нужна как наглядная подсказка: точные случайные цвета и фазы прошивки она не повторяет.
Общий код приложения¶
Окно приложения не имеет доступа к Node.js и железу: оно работает с contextIsolation и без nodeIntegration.
Все вызовы идут через мост window.katana, который собирает preload, а выполняет main-процесс.
Код протокола, разбор профиля и типы IPC лежат в src/shared и используются и окном, и main-процессом.
Поэтому подсказки и проверки в окне работают по тем же правилам, что и запись в устройство.
Тесты¶
Обе части проверяются офлайн, без клавиатуры и без второй реализации.
katana.pyпрогоняет команды на подменном устройстве: тесты проверяют байты, порядок секций и разбор профиля.- Katana Studio использует vitest и готовые фикстуры, собранные из Python-версии.
Фикстуры лежат в
studio/tests/fixturesи закоммичены. - Имитация режимов проверяется отдельно: формы волн, периоды и реакция на нажатия.
Фикстуры обновляет генератор misc/make_ts_fixtures.py из Python-репозитория.
Поэтому расхождение между реализациями видно на тестах, а не на клавиатуре.
Сборка и проверки¶
# утилита
cd katana.py
python3 -m venv .venv && .venv/bin/pip install -r requirements.txt
.venv/bin/python -m pytest
# приложение
cd studio
npm ci
npm run typecheck && npm run lint && npm test
npm run build
npm run dist
# документация
cd docs
make site
Запуск и отладка утилиты описаны в разделе Установка, приложения — в разделе Запуск и отладка.
Сборка документации выполняется командой make site из корня репозитория docs.