Перейти к содержанию

Как устроен проект

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.