Initial commit

This commit is contained in:
2026-09-06 01:06:40 +08:00
commit 57c4e80f0d
69 changed files with 20940 additions and 0 deletions
+102
View File
@@ -0,0 +1,102 @@
# Режимы подсветки
19 встроенных режимов прошивки плюс выключение.
Номер режима = байт [0] lighting-payload, алиасы заданы в `katana.py` (`MODES`).
Полная таблица с байтами payload — в [PROTOCOL.md](PROTOCOL.md) (раздел «Lighting payload»).
## Таблица режимов
Режимы указаны в порядке их перечисления в фирменной утилите.
| № | Название | Алиас | Цвет | Яркость | Скорость | Направление | Описание |
| --- | -------------------- | ----------- | ----------- | ------- | -------- | ----------- | --------------------------------------------------------------------------------- |
| 1 | Постоянный свет | `static` | моно/спектр | + | + | | статическое свечение всех клавиш |
| 2 | Подсветка нажатых | `keypress` | моно/спектр | + | + | | все выключены, подсвечиваются нажатые |
| 3 | Затухание нажатых | `fade` | моно/спектр | + | + | | все включены, гаснут нажатые |
| 4 | Звёздный | `star` | моно/спектр | + | + | | случайные вспышки после полного затухания |
| 5 | Снежный | `snow` | моно/спектр | + | + | | аналогично, но больше соседних клавиш |
| 6 | Цветочный | `flower` | спектр | + | + | | плавные цвета на каждой клавише без затухания |
| 7 | Дыхание | `breathing` | спектр¹ | + | + | | плавное свечение и затухание всех клавиш |
| 8 | Полный спектр | `spectrum` | спектр | + | + | | плавные цвета на всех клавишах без затухания |
| 9 | Круги | `ripple` | моно/спектр | + | + | | плавные цвета кругами из центра к краям |
| 10 | Водопад | `waterfall` | моно/спектр | + | + | ↑/↓ | спектр по рядам клавиш |
| 11 | Течение | `flow` | моно/спектр | + | + | ←/→ | косые волны в одну сторону без затухания |
| 12 | Вращение | `rotate` | моно/спектр | + | + | ←/→ | волна по кругу вокруг центра |
| 13 | Горизонтальная грань | `h-edge` | моно/спектр | + | + | | все выключены, горизонтальная волна по ряду от нажатой клавиши |
| 14 | Вертикальная грань | `v-edge` | моно/спектр | + | + | | все выключены, косая волна по всем рядам от нажатой клавиши |
| 15 | Рябь по воде | `splash` | моно/спектр | + | + | | все выключены, плавные круги от нажатой клавиши |
| 16 | Бегущая строка | `marquee` | моно/спектр | + | + | ←/→ | все выключены, плавная бегущая подсветка каждой клавиши в каждом ряду сверху вниз |
| 17 | Горы | `mountains` | моно/спектр | + | + | | плавные углы из середины в стороны |
| 18 | Ветер | `wind` | моно/спектр | + | + | ←/→ | косые волны в одну сторону с затуханием |
| 19 | Шаттл | `shuttle` | моно/спектр | + | + | | бегущие строки по чётным/нечётным рядам в обе стороны |
| 20 | Выключена | `off` | | | | | все клавиши погашены |
¹ У breathing цвет из payload игнорируется прошивкой: цикл цвета зашит и гоняет зелёно-жёлто-красную гамму при любом `--color` (проверено на железе, payload совпадает с вендорским — подробности в [PROTOCOL.md](PROTOCOL.md)).
Для моноцветного дыхания аналога нет; если нужен именно красный постоянный свет — используйте `static`.
## Примеры
```
./katana.py off # выключить подсветку
./katana.py mode 1 --color ff00ff # статика, маджента
./katana.py mode static --color magenta # то же самое, алиасами
./katana.py mode breathing # дыхание (цвет зашит в прошивку, см. сноску ¹)
./katana.py mode spectrum --color cyan # полный спектр (спектр игнорирует цвет)
./katana.py mode static --rainbow # статика радугой
./katana.py mode waterfall --color gold --speed 5
./katana.py mode marquee --color red --direction east-west
```
## Аргументы `mode`
### `N`
Номер режима из таблицы выше (десятичный или hex) либо алиас.
Также принимается `off`.
### `--color ЦВЕТ`
Цвет для моно-режимов.
По умолчанию `ffffff`.
В спектр-режимах (`flower`, `spectrum`, `waterfall`...) игнорируется прошивкой.
### `--brightness 1–15`
Яркость.
По умолчанию `15`.
### `--speed 2–15`
Скорость анимации.
По умолчанию `10` (вендорский дефолт).
Для `static` скорость не применяется — прошивке всегда шлётся `10`, при явном другом значении печатается warning.
Значения ниже `2` для анимаций принимаются, но не наблюдались у вендора (warning).
### `--rainbow`
Только для `static`: радужный спектр вместо одного цвета (байт [11] = `01`).
### `--direction`
Направление анимации (байт [11]) для режимов с направлением: `north-south`, `south-north`, `east-west`, `west-east`.
Для остальных режимов команда завершается ошибкой.
Сняты значения: `waterfall` (`north-south`=`02`, `south-north`=`03`), `marquee` (`east-west`=`01`, `west-east`=`00`); для `flow`, `rotate`, `wind` байты уточняются.
### `--flag 0–255`
Переопределение служебного байта [8] payload — без необходимости не трогать.
По умолчанию вендорский (`00` static/star, `01` остальные).
### `--no-save`
Не писать настройки во флеш (пропустить `save`).
По умолчанию save выполняется.
Настройка действует до выключения клавиатуры.
Полезно для экспериментов, чтобы не изнашивать флеш.
## Направление анимации
Задаётся `--direction north-south|south-north|east-west|west-east` (байт [11] payload).
Значения сняты для `waterfall` (02/03) и `marquee` (01/00).
Для `flow`, `rotate`, `wind` применяйте те же опции — значения байта уточняются.
Подробности — [PROTOCOL.md](PROTOCOL.md) (раздел «Байт [11] — подрежим»).
+228
View File
@@ -0,0 +1,228 @@
# Расширение функционала: свои скрипты и анимации
Встроенных команд `katana.py` хватает для настройки подсветки, но настоящий интерес начинается, когда вы пишете собственные скрипты.
Модуль спроектирован как библиотека: класс `Katana` и вспомогательные функции импортируются в любой ваш скрипт одной строкой.
Документ описывает программный интерфейс, его ограничения и готовые приёмы.
Справка по CLI-командам — в [cli/README.md](cli/README.md), низкоуровневые детали протокола — в [PROTOCOL.md](PROTOCOL.md).
## Что даёт per-key API
Прошивка хранит таблицу из 143 слотов `[индекс, R, G, B]` и умеет показывать её как отдельный режим `0x80`.
Ключевое свойство, проверенное на железе: **таблица обновляется живьём**.
Если подсветка уже в режиме `0x80`, каждая новая запись таблицы сразу меняет свечение клавиш — переключать режим повторно не нужно.
Именно это делает возможными анимации: цикл «изменил таблицу → записал → пауза» превращается в эффект.
Второе свойство — чтение живого кадра (`04 f5`): скрипт видит, что сейчас светится, с учётом яркости и активных анимаций.
На этом строятся скрипты, которые дорисовывают поверх текущей картинки, не затирая её.
## Подключение библиотеки
Все примеры предполагают, что скрипт лежит рядом с `katana.py` (или путь добавлен в `sys.path`).
```python
from light import Katana, KEYS_COUNT, resolve_key, build_payload
keyboard = Katana() # находит /dev/hidrawN и открывает его
try:
... # работа с клавиатурой
finally:
keyboard.close() # обязательно закрывать дескриптор
```
Импортируется именно `light`, а не дублируется транспорт: все проверки ACK, контрольных сумм и таймингов уже внутри.
## Справочник API
| Объект | Сигнатура | Что делает |
| ------------------------------------------------ | --------------------------------- | --------------------------------------------------------------------------------------------- |
| `Katana()` | конструктор | Находит hidraw-узел интерфейса 0 и открывает его. |
| `keyboard.close()` | — | Закрывает дескриптор. Вызывайте в `finally`. |
| `keyboard.lighting(payload, save=True)` | payload — 64 байта | Полная транзакция: begin → data-begin → payload → commit → save. Переключает режим подсветки. |
| `keyboard.write_key_table(colors, save=True)` | colors — 143 кортежей `(r, g, b)` | Записывает per-key таблицу (9 пакетов). При активном режиме `0x80` свечение меняется сразу. |
| `keyboard.show_custom(brightness=15, save=True)` | brightness 1–15 | Переключает подсветку в режим `0x80` (показ таблицы). |
| `keyboard.read_frame()` | — | Читает живой кадр, возвращает список из 143 кортежей `(r, g, b)`. |
| `keyboard.reset()` | — | USB port reset: снимает клин прошивки без переподключения. |
| `resolve_key(name)` | `'tab'`, `'tilde'`, `'0x25'` | Имя или символ клавиши → LED-индекс (`None`, если не найдено). |
| `build_payload(mode, rgb, ...)` | см. докстринг | Собирает 64-байтный payload для `lighting()`. |
| `KEYS_COUNT` | константа | Размер таблицы: 143 слота (`0x00`–`0x8e`). |
Имена слотов: индекс — это позиция в таблице, а не номер клавиши.
Карта «индекс → физическая клавиша» — в `keymap.py` (`KEYMAP`, `BLIND`), человекочитаемо: `python3 keymap.py`.
## Ограничения, которые надо знать заранее
### Скорость: ~1 кадр в секунду
Между любыми двумя USB-запросами выдерживается пауза `DELAY = 0.04` с (вендорский тайминг, ускорять не стоит — прошивка теряет пакеты).
Один кадр записи таблицы — это 17 запросов, что даёт измеренные на железе цифры:
| Операция | Время |
| ----------------------------- | ------ |
| `write_key_table(save=False)` | ~0,6 с |
| `write_key_table(save=True)` | ~0,7 с |
| `read_frame()` | ~0,6 с |
| `lighting()` (смена режима) | ~0,4 с |
Практический потолок плавной анимации — **1–1,5 кадра в секунду**.
Эффекты с быстрым движением (бегущая строка) будут дёргаными; хорошо смотрятся медленные волны, дыхание, плавные переливы.
### Флеш-память: не пишите в неё каждый кадр
`save=True` после каждой записи коммитит настройки во флеш-память, у которой ограниченный ресурс перезаписи.
Для анимаций это недопустимо расточительно, поэтому:
- в цикле анимации всегда используйте `save=False`;
- настройка, сохранённая последним `save`, остаётся во флеше и восстанавливается при включении клавиатуры;
- правило проекта: вызовы `./katana.py paint` из шелла — только с `--no-save` (см. AGENTS.md).
Несохранённая сессия не вредит: следующая команда откроет её заново (`begin` ответит `ff` = «сессия уже открыта», это штатно).
Но не оставляйте сессию открытой на часы — при зависании прошивки помогает `katana.py reset`.
### Слепые слоты
39 слотов из 143 ни к какому LED не подключены (список `BLIND` в `keymap.py`).
Прошивка молча принимает в них любой цвет, но светиться ничего не будет — не ищите баг у себя.
## Приём 1. Разовая раскраска скриптом
Скрипт-«пресет»: заливка по вашему алгоритму вместо перечисления `--key` в шелле.
```python
#!/usr/bin/env python3
"""Двухцветная раскраска: буквенный блок — один цвет, остальное — другой."""
import time
from light import Katana, KEYS_COUNT, resolve_key
from keymap import KEYMAP
LETTERS = {resolve_key(l) for l in "qwertyuiopasdfghjklzxcvbnm"}
def make_table(base, accent):
"""143 кортежей (r, g, b): буквам — accent, остальным — base."""
return [accent if i in LETTERS else base for i in range(KEYS_COUNT)]
keyboard = Katana()
try:
keyboard.write_key_table(make_table((30, 0, 40), (255, 120, 0)), save=False)
keyboard.show_custom(brightness=15, save=True) # режим 0x80 + один save
finally:
keyboard.close()
```
Обратите внимание: `save` выполняется один раз — в `show_custom`.
Таблица при этом остаётся несохранённой во флеше, но горит до выключения клавиатуры.
## Приём 2. Анимация: бегущая волна
Каркас любой анимации: подготовить режим `0x80` один раз, затем в цикле менять таблицу.
```python
#!/usr/bin/env python3
"""Синяя волна пробегает по цифровому ряду слева направо."""
import math
import time
from light import Katana, KEYS_COUNT, resolve_key
ROW = [resolve_key(k) for k in "`1234567890-="] # индексы 0x13..0x1f
FRAME_PAUSE = 0.2 # пауза между кадрами
keyboard = Katana()
try:
# один раз включаем режим 0x80 и гасим таблицу
keyboard.write_key_table([(0, 0, 0)] * KEYS_COUNT, save=False)
keyboard.show_custom(brightness=15, save=True)
phase = 0
while True:
table = [(0, 0, 0)] * KEYS_COUNT
for pos, idx in enumerate(ROW):
# волна: яркость синего канала зависит от расстояния до фронта
wave = max(0.0, math.cos((pos - phase) * math.pi / 6))
table[idx] = (0, 0, int(255 * wave))
keyboard.write_key_table(table, save=False)
phase = (phase + 1) % (len(ROW) + 6)
time.sleep(FRAME_PAUSE)
finally:
keyboard.close()
```
Цикл бесконечный — останавливайте `Ctrl+C`, блок `finally` закроет дескриптор.
Полный кадр занимает ~0,8 с (запись + пауза), волна движется заметно плавно, потому что форма синусоиды «размазана» по 13 клавишам.
Советы по анимациям:
- меняйте за кадр всю таблицу целиком — частичные обновления всё равно требуют полной транзакции;
- не пишите `save` внутри цикла никогда;
- гасите таблицу в начале (`[(0, 0, 0)] * KEYS_COUNT`), иначе волна наложится на старую раскраску;
- для «дыхания» масштабируйте цвет всех клавиш одним коэффициентом — это дёшево и выглядит хорошо при 1 FPS.
## Приём 3. Дорисовка поверх живого кадра
`read_frame()` возвращает текущую картинку, поэтому скрипт может добавлять акценты, не затирая остальное.
Это тот же механизм, что у команды `paint --keep`.
```python
frame = keyboard.read_frame() # что светится сейчас
table = list(frame) # копия, чтобы не портить оригинал
table[resolve_key("esc")] = (255, 0, 0)
keyboard.write_key_table(table, save=False)
```
Так работают индикаторы: капс-лок красным, заряд беспроводного режима зелёным, напоминание о перерыве — подсветить ряд цифр после часа работы.
Данные для условия скрипт берёт откуда угодно: файл, сокет, D-Bus, `os.stat`.
Ограничение: в режиме `0x80` кадр — это сама таблица, поэтому «дорисовка поверх анимации прошивки» (например, поверх `spectrum`) даст статичную замену, а не наложение.
Смешивать своё и встроенные эффекты в одном кадре прошивка не умеет — это ограничение железа, а не API.
## Приём 4. Переключение сценариев из шелла
Скриптам не нужен свой CLI, если хочется вызывать их как команды `katana.py`.
Оформите каждый сценарий функцией и выбирайте аргументом:
```python
#!/usr/bin/env python3
"""./my_fx.py wave|breath|off — выбор сценария первым аргументом."""
import sys
def wave(kb): ...
def breath(kb): ...
SCENARIOS = {"wave": wave, "breath": breath}
if __name__ == "__main__":
from light import Katana
name = sys.argv[1] if len(sys.argv) > 1 else "wave"
kb = Katana()
try:
SCENARIOS[name](kb)
finally:
kb.close()
```
Привычные цвета принимайте через `parse_color` из `light` — так ваши скрипты поймут и `ff8800`, и `darkorange`.
## Грабли
- **`pyusb` с `detach_kernel_driver` ломает печать.**
Транспорт — только hidraw-ioctl, как в `katana.py`.
- **Сессию всегда доводите до `save` или закрывайте программой.**
Долгая висящая сессия клинит прошивку; лечение — `katana.py reset`.
- **Не укорачивайте `DELAY`.**
Пауза 0,04 с снята с вендорских захватов; при ускорении прошивка начинает терять пакеты и ACK-и.
- **`read_frame()` возвращает масштабированные яркостью цвета.**
При яркости 15/15 максимум `ee`, а не `ff` — не сравнивайте кадр с записанным цветом «в лоб».
- **Слот `0x6d` всегда читается как `000000`.**
Это null-слот прошивки, даже у вендорской утилиты.
## Идеи для скриптов
- индикатор загрузки CPU или памяти — градиент по функциональному ряду;
- подсветка уведомлений: вспышка волной при новом сообщении;
- «помидор»: 25 минут работы — спокойный цвет, перерыв — зелёная заливка;
- плавный рассвет: медленное нарастание яркости и цвета по утрам;
- визуализация музыки через любой FFT-вход: спектр по рядам клавиатуры;
- световой «миникарт»: подсветка зоны WASD в играх, где это уместно.
Список открытых направлений самого протокола (переназначение клавиш, байты направлений) — в [PROTOCOL.md](PROTOCOL.md) → «Следующие шаги».
+56
View File
@@ -0,0 +1,56 @@
---
description: Установка, udev-правило и решение проблем доступа к устройству.
---
# Установка
## Зависимости
Нужен Python 3.10+.
Зависимости: `pyusb` (для `reset`) и `pyyaml` (для `apply`); сам транспорт работает на голых `fcntl`-ioctl'ах к `/dev/hidraw*`:
```
python3 -m venv .venv
.venv/bin/pip install pyusb pyyaml
```
## udev-правило
Без правила доступ к `/dev/hidraw*` есть только у root.
Файл `70-ganss-katana.rules` даёт доступ группе `plugdev` и через `uaccess` (логин-сессии systemd):
```
SUBSYSTEM=="hidraw", ATTRS{idVendor}=="0c45", ATTRS{idProduct}=="8006", MODE="0660", GROUP="plugdev", TAG+="uaccess"
SUBSYSTEM=="usb", ATTRS{idVendor}=="0c45", ATTRS{idProduct}=="8006", MODE="0660", GROUP="plugdev", TAG+="uaccess"
```
Первая строка — доступ к hidraw-узлам (весь обмен RGB), вторая — к USB-устройству (нужна только для команды `reset`, которая делает USB port reset).
**Установка:**
```
sudo cp 70-ganss-katana.rules /etc/udev/rules.d/ && \
sudo udevadm control --reload-rules && \
sudo udevadm trigger
```
Проверка: `katana.py mode ...` должен работать без `sudo`.
## Проверка устройства
Наличие клавиатуры проще всего проверить по USB ID `0c45:8006`:
```
lsusb | grep -i 0c45
Bus 001 Device 028: ID 0c45:8006 Microdia Dual Mode Camera (8006 VGA)
```
Подпись «Dual Mode Camera (8006 VGA)» — это норма, не пугайтесь.
ID `0c45:8006` принадлежит чипу Sonix SN32, который производитель ставит и в вебкамеры Microdia, и в клавиатуры.
База имён `usb.ids` знает за этим ID только камеру, поэтому `lsusb` показывает её название для любого устройства с этим ID — включая эту клавиатуру.
Реальный тип устройства видно по интерфейсам: 2 HID-интерфейса (boot keyboard и mouse/consumer) в `usb-devices` или `lsusb -d 0c45:8006 -v`.
!!! note "Если не помогло"
Переподключите клавиатуру.
Если пользователь не в группе `plugdev` — `sudo usermod -aG plugdev $USER` и перелогин.
+553
View File
@@ -0,0 +1,553 @@
# GANSS ARDOR_Katana (0c45:8006) — протокол и состояние реверса
> Файл содержит ВСЁ необходимое для продолжения работы: протокол, карту клавиш, открытые вопросы, методику.
> Обновлять по мере находок.
> Пользовательская документация (установка, команды, режимы, свои скрипты) — по ссылкам из [README.md](../README.md).
## Устройство
- Клавиатура GANSS ARDOR_Katana, USB `0C45:8006` (Sonix SN32), 2 HID-интерфейса.
- iface0 = boot keyboard + **конфиг-канал** (feature-репорты rid=0, 64 байта).
- iface1 = consumer/mouse + vendor page 0xFF00 rid=5 (только input, не используется).
- udev-правило `70-ganss-katana.rules` установлено (доступ к hidraw без root).
- hidraw-узел iface0 ищется через `/sys/class/hidraw/*/device` (hid_dev, родитель `*:1.0`) + modalias `hid:b0003g0001v00000C45p00008006`.
## Транспорт (реализовано в katana.py)
Feature-репорты через hidraw ioctl (`HIDIOCSFEATURE`/`HIDIOCGFEATURE`), буфер 65 байт: первый байт = report id (0).
**usbhid не отцепляется** — печать никогда не прерывается.
pyusb-вариант НЕ использовать (отцеплял драйвер).
## Общая транзакция (все команды)
```
SET 04 18 begin ACK: 04 18 00 01 (или ff = сессия уже открыта, ок)
SET 04 13 00*6 01 data-begin ACK: 04 13 00 01
SET <payload 64B> данные (без ACK)
SET 04 02 commit ACK: 04 02 00 01 <LE16 sum(payload)>
SET 04 f0 save (flash) ACK: 04 f0 00 01
```
- ACK-байт [3]: `01` = ok, `00`/`ff` = отказ (залипшая сессия / неверное состояние).
- Контрольная сумма: `sum(payload) & 0xFFFF`, LE, в ACK коммита (байты 4–5).
Проверена на десятках команд вендора и наших записях.
- **Сессию всегда закрывать `f0`**, иначе прошивка клинится: begin отвечает `00`, команды отклоняются.
Лечение: `katana.py reset` (USB port reset, ~2–12 c на переподключение; иногда нужен повторный reset после паузы).
- Вендор всегда шлёт полную транзакцию begin → data → payload → commit → save, даже на каждый чих.
Подражать.
## Lighting payload (блок 1)
```
[0] режим: 1..19 (0x13) — список вендора; 0x80 — custom per-key таблица
[1..3] R G B
[8] flag: 0x00 для режимов 1 и 4, 0x01 для остальных
[9] яркость 0x01..0x0F (вендор: слайдер 15 позиций)
[10] скорость 0x02..0x0F (вендор); для статики (mode 1) всегда 0x0A,
слайдер скорости в UI неактивен — подтверждено katana2-speed
[11] подрежим: моно/радуга для статики, направление анимации (см. ниже)
[14..15] aa 55
```
### Байт [11] — подрежим (снято по color-toggle-*.pcapng)
| Режим | Значение | Смысл |
| ----------------- | ----------- | ---------------------------------- |
| 1 static | `00` / `01` | моно (`--color`) / радужный спектр |
| 10 waterfall | `02` / `03` | север→юг / юг→север |
| 16 marquee (0x10) | `01` / `00` | восток→запад / запад→восток |
Для остальных режимов вендор всегда шлёт `00`.
Направления режимов 11 flow, 12 rotate, 18 wind кодируются тем же байтом (значения не сняты — в захватах переключали только waterfall и marquee).
CLI: `--rainbow`, `--direction north-south|south-north|east-west|west-east`.
- Off = payload из нулей + `aa55` (последний пункт списка вPендора).
- Яркость масштабирует per-key цвета: 15/15 → `ee` (238), 1/15 → `0f`.
- Режим 0x80 отображает таблицу per-key (см. ниже) — это и есть «кастом».
### Таблица режимов (описания вендорской утилиты, docs/COLOR-MODES.md)
Номер = байт [0] payload.
«моно/спектр» — режим рисует одиночный цвет или полный спектр независимо от него.
У режимов 10, 11, 12, 16, 18 есть **направление анимации** (кодировка в payload пока не снята — ждём снимок установки настроек).
Алиасы реализованы в katana.py (`MODES`).
| № | Алиас | Описание | Параметры |
| --- | ----------- | ------------------------------------------------------------ | ----------------------------------- |
| 1 | `static` | Постоянный свет всех клавиш | моно/спектр, яркость |
| 2 | `keypress` | Подсветка нажатых: всё выключено, горят нажатые | моно/спектр, яркость, скорость |
| 3 | `fade` | Затухание нажатых: всё включено, гаснут нажатые | моно/спектр, яркость, скорость |
| 4 | `star` | Звёздный: случайные вспышки после полного затухания | моно/спектр, яркость, скорость |
| 5 | `snow` | Снежный: как звёздный, но больше соседних клавиш | моно/спектр, яркость, скорость |
| 6 | `flower` | Цветочный: плавные цвета на каждой клавише без затухания | спектр, яркость, скорость |
| 7 | `breathing` | Дыхание: плавное свечение и затухание всех клавиш | моно/спектр, яркость, скорость |
| 8 | `spectrum` | Полный спектр: плавные цвета на всех клавишах | спектр, яркость, скорость |
| 9 | `ripple` | Круги: плавные цвета кругами из центра к краям | моно/спектр, яркость, скорость |
| 10 | `waterfall` | Водопад: спектр по рядам клавиш | моно/спектр, яркость, скорость, ↑/↓ |
| 11 | `flow` | Течение: косые волны в одну сторону без затухания | моно/спектр, яркость, скорость, ←/→ |
| 12 | `rotate` | Вращение: волна по кругу вокруг центра | моно/спектр, яркость, скорость, ←/→ |
| 13 | `h-edge` | Горизонтальная грань: волна по ряду от нажатой | моно/спектр, яркость, скорость |
| 14 | `v-edge` | Вертикальная грань: косая волна от нажатой клавиши | моно/спектр, яркость, скорость |
| 15 | `splash` | Рябь по воде: плавные круги от нажатой клавиши | моно/спектр, яркость, скорость |
| 16 | `marquee` | Бегущая строка: подсветка каждой клавиши в ряду | моно/спектр, яркость, скорость, ←/→ |
| 17 | `mountains` | Горы: плавные углы из середины в стороны | моно/спектр, яркость, скорость |
| 18 | `wind` | Ветер: косые волны в одну сторону с затуханием | моно/спектр, яркость, скорость, ←/→ |
| 19 | `shuttle` | Шаттл: бегущие строки по чётным/нечётным рядам в обе стороны | моно/спектр, яркость, скорость |
| — | `off` | Выключена (пункт 20 списка) | all-zero payload |
Переключение «моно/спектр» — байт [11] (для статики `00`=моно, `01`=радуга), направление анимации — тоже байт [11], значения в таблице выше.
## Per-key таблица (кастомная раскраска)
**Запись** (реализовано, работает стабильно):
```
begin
→ SET 04 23 00*6 09
→ ACK
→ 9 пакетов по 64Б: 143 записи [index, R, G, B] (индексы 0x00..0x8e) + 0000 + aa55 (576 Б)
→ commit (ACK сумма = sum(576Б))
→ save
```
Затем lighting payload mode=0x80 показывает таблицу.
**Чтение (04 f5) — РАБОТАЕТ (вендорская схема):**
```
SET 04 f5 +09
→ GET ×9: поток [idx,r,g,b]×16, индексы 0x00,0x10..0x80 (0x00..0x8f)
→ commit (ACK 01, сумма 0000 — payload не писался)
→ save
```
- **НЕ делать begin+data-begin перед f5** — data-begin disarmит поток (ACK status 00, GET-ы возвращают эхо последнего SET).
- Первый GET после SET может быть ACK `04 f5 00 01` (наблюдалось на первом чтении после save у вендора, там же было только 8 пакетов) — читатель пропускает не-данные и ждёт пакеты с ожидаемыми индексами.
- Указатель сбрасывается на 0x00 каждым f5 SET (в рабочем состоянии).
- Ретрай: до 3 попыток, между ними `begin` (переоткрытие контекста).
- Кадр = ЖИВОЕ изображение: на статике — цвет режима (масштаб яркости, 15/15 → ee), на анимации — текущие цвета эффектов, меняются между чтениями.
Слот 0x6d всегда 000000 (null-слот прошивки, даже у вендора).
Слепые слоты в кадре на статике показывают цвет режима (буфер расчётный, физически LED нет).
## Переназначение клавиш (канал 04 11)
**Запись — РАБОТАЕТ** (снято по `raw-data/katana-v1/keybind-mouse-buttons.pcapng`: LCtrl → 5 кнопок мыши по очереди + возврат на default; проверено на железе):
```
begin
→ SET 04 11 00*6 09
→ ACK
→ 9 пакетов по 64Б: 143 записи по 4 байта (позиция слота = LED-индекс клавиши) + 0000 + aa55 (576 Б)
→ commit (ACK сумма = sum(576Б))
→ save
```
Формат блоба совпадает с per-key таблицей, но содержимое записи — назначенное действие, а не цвет.
В отличие от per-key записи, индекс клавиши в записи НЕ дублируется — слот определяется позицией в блобе.
**Содержимое записи** (4 байта):
- `[00, 00, 00, 00]` — действие по умолчанию (клавиша работает как обычно).
- `[01, 01, код, 00]` — кнопка мыши, код в байте [2].
- `[02, маска, код, 00]` — шорткат: маска модификаторов в байте [1],
HID usage ID клавиши (Keyboard/Keypad page 0x07) в байте [2]
(дампы keybind-editor, keybind-hotkeys).
- `[03, usage_lo, usage_hi, 00]` — мультимедиа/веб-действие, байты [1..2] — 16-битный LE usage ID из HID Consumer Page (0x0C) (дамп keybind-multimedia).
- `[06, индекс, режим, счётчик]` — запуск макроса (дампы macros-set, macros-modes).
Индекс 0-based: «Макрос 1» вендорской утилиты = 0.
Режим: `00` — однократно, `01` — повторить `счётчик` раз (наблюдалось 1, 5, 8), `02` — повторять до повторного нажатия.
**Коды кнопок мыши** (байт [2]; значения — степени двойки, вероятно битовая маска, но комбинированные записи железом не проверялись):
| Код | Кнопка |
| ---- | ------------------------------- |
| `01` | ЛКМ (левая) |
| `02` | ПКМ (правая) |
| `04` | СКМ (средняя) |
| `08` | «назад» (боковая) |
| `10` | «вперёд» (боковая) |
Пример из дампа: LCtrl (слот 0x5b) → ЛКМ = запись `[01, 01, 01, 00]` по смещению 91×4 = 364 (пакет 5, смещение 44).
**Шорткаты редактора** (дамп keybind-editor): 9 транзакций, каждая вешает на Caps (слот 0x37) запись `[02, 01, код, 00]`.
Код в байте [2] — HID usage ID буквы, порядок транзакций совпадает с порядком списка функций в UI вендора.
Реализация — `EDITOR_ACTIONS` в katana.py, офлайн-тест по дампу — `tests/test_macro.py` (`test_editor_actions_match_dump`).
Проверено на железе: `caps=copy` и `menu=undo` работают как Ctrl+C/Ctrl+Z.
| Код | Функция | Шорткат |
| ---- | ------------ | ------- |
| `12` | Открыть | Ctrl+O |
| `11` | Создать | Ctrl+N |
| `1d` | Отмена | Ctrl+Z |
| `16` | Сохранить | Ctrl+S |
| `06` | Копировать | Ctrl+C |
| `1b` | Вырезать | Ctrl+X |
| `19` | Вставить | Ctrl+V |
| `09` | Найти | Ctrl+F |
| `04` | Выбрать всё | Ctrl+A |
**Горячие клавиши** (дамп keybind-hotkeys): 10 транзакций, каждая вешает на Caps (слот 0x37) запись — по порядку списка UI вендора:
A, Shift+B, Ctrl+C, Alt+D, Meta+E, Esc, F1, Num1, Fn, «Мой компьютер».
Первые девять — записи типа `02`, десятая — мультимедиа `[03, 94 01, 00]` (usage 0x0194 AL My Computer, см. таблицу выше).
Реализация — `HOTKEY_MODIFIERS`, `HOTKEY_KEYS` и `parse_hotkey()` в katana.py, офлайн-тесты — `tests/test_macro.py` (`test_hotkey_actions_match_dump`, `test_parse_hotkey`).
Проверено на железе: `caps=ctrl+c` (одиночный модификатор) и `caps=ctrl+shift+c` (маска 0x03 — комбинация) работают как ожидается.
**Байт [1] типа `02` — битовая маска модификаторов:**
| Маска | Модификатор |
| ----- | ----------- |
| `00` | без модификатора |
| `01` | Ctrl |
| `02` | Shift |
| `04` | Alt |
| `08` | Meta (Win) |
У шорткатов редактора наблюдался только `01` (Ctrl); дамп keybind-hotkeys подтверждает остальные значения и показывает, что маска — степень двойки.
Комбинации модификаторов (сумма масок, например Ctrl+Shift = `03`) подтверждены на железе: `caps=ctrl+c` и `caps=ctrl+shift+c` работают.
Коды клавиш в байте [2] сверены с HID Usage Tables и дампом: A–E = `04`–`08`, Esc = `29`, F1 = `3A`, Num1 = `59`.
Fn = `AF` — собственный код прошивки: в HID Usage Tables такого usage нет, но вендор шлёт именно его.
| Код | Клавиша | Примечание |
| ---- | ------- | --------------------------------- |
| `04` | A | (буквы `04`–`1D`) |
| `29` | Esc | |
| `3A` | F1 | (F-клавиши `3A`–`45`) |
| `59` | Num1 | (нумпад `58`–`62`, Num0 = `62`) |
| `AF` | Fn | собственный код прошивки, не HID |
**Мультимедиа/веб-действия** (дамп keybind-multimedia): 18 транзакций, каждая вешает на Caps (слот 0x37) запись `[03, usage u16 LE, 00]`.
Порядок транзакций совпадает с порядком списка функций в UI вендора, все usages сверены с HID Usage Tables (Consumer Page 0x0C).
Реализация — `MULTIMEDIA_ACTIONS` в katana.py, офлайн-тест по дампу — `tests/test_macro.py` (`test_multimedia_actions_match_dump`).
| Usage | Функция |
| ------ | ----------------------------------------- |
| `0183` | Плеер (AL Consumer Control Configuration) |
| `00CD` | Воспроизведение/пауза |
| `00B7` | Стоп |
| `00B6` | Предыдущая песня |
| `00B5` | Следующая песня |
| `00E9` | Громкость + |
| `00EA` | Громкость − |
| `00E2` | Отключить звук |
| `0223` | Домашняя страница (AL Internet Browser) |
| `0227` | Веб: обновить (AL Web Refresh) |
| `0226` | Веб: остановить (AL Web Stop) |
| `0224` | Веб: назад (AL Web Back) |
| `0225` | Веб: вперед (AL Web Forward) |
| `022A` | Веб: избранное (AL Favorites) |
| `0221` | Веб: поиск (AL Web Search) |
| `0194` | Мой компьютер (AL My Computer) |
| `0192` | Калькулятор (AL Calculator) |
| `018A` | Электронная почта (AL Email Reader) |
**Известные ограничения:**
- Команда перезаписывает ВСЮ таблицу (вендорская утилита делает так же) — каждый раз шлются все 143 слота.
- Команда чтения текущих переназначений неизвестна (в дампах только запись).
- Установлены пять типов действий: мышь (`[01, 01, ...]`), шорткаты — редактор и горячие клавиши (`[02, маска, ...]`), мультимедиа (`[03, usage, ...]`) и макрос (`[06, ...]`).
Остальные типы (Fn-слой) не исследованы.
## Макросы (канал 04 19 + привязка через 04 11)
Снято по дампам `raw-data/katana-v1/macros-*.pcapng` и вендорскому XML (`test.xml`, `macros-create-test.xml`).
Содержимое макросов хранится в самой прошивке, а не на ПК:
в эксперименте макрос сыграл при отключённой вендорской утилите и другой раскладке («ФЫВА» — те же клавиши A, S, D, F).
### Запись содержимого — канал 04 19
Транзакция отличается от обычной:
```
SET 04 19 begin ACK: 04 19 00 01
SET 04 15 00*6 <число пакетов> data-begin ACK: 04 15 00 01 (эхо числа пакетов в байте [8])
SET <данные, пакетов × 64Б> данные (без ACK)
SET 04 02 commit ACK: 04 02 00 01 <LE16 sum>
```
- Вендор после коммита **не делает save** (04 f0) — в дампе macros-create его нет.
- В байте [8] data-begin — число 64-байтовых пакетов (как у 04 23/04 11, где 09 = 576/64).
- **Модель сохранения (проверена на железе): каждая область (bind-таблица, paint-таблица, режим, макросы) сохраняется во флеш только своим собственным save (04 f0).**
Чужой save чужую область ни сохраняет, ни затирает: remap-save не трогает макросы, macro-save не трогает bind.
Практическое правило: область переживает переподключение только если после её записи был её собственный save.
В apply каждая секция несёт свой save.
- **Запись макросов (04 19) сбивает bind-таблицу и режим подсветки В RAM** (во флеше они остаются).
После записи макросов bind и режим нужно перепослать (apply делает это автоматически).
- **Несколько макросов живут только при записи одним блобом**: каждый вызов 04 19 с блобом, содержащим один слот, обнуляет прочие слоты.
При обращении к ПУСТОМУ слоту прошивка делает fallback на слот 0 (проверено: macro1 при пустом слоте 1 исполнял содержимое macro0).
- Вендорская утилита после записи макросов других save-транзакций не делает — в одиночной операции этого достаточно.
**Формат блоба** (дамп macros-create, 14 пакетов = 896 байт):
- Заголовок 400 байт (0x190) — 100 u32-смещений: смещение данных макроса от начала блоба, 0 = слот пуст.
В дампе: слот 0 → 0x190 (400), слот 1 → 0x1d8 (472).
- На каждый макрос: u32 (число событий × 2), u32 0, затем события по 8 байт:
`[00 00][код][тип][задержка u16 LE][00][50]`.
- Хвост: нули до кратности 64 минус 2 байта + `aa55` (как у per-key блоба).
- Ёмкость по дампу — 896 байт: один макрос вмещает до 60 событий (при пустых остальных слотах).
**Типы событий** (байт [3]): `B0` — клавиша нажата, `30` — отпущена, `90` — кнопка мыши нажата, `10` — отпущена.
**Коды клавиш** (байт [2]):
- Буквы, цифры, F1–F12, модификаторы — совпадают с HID usage ID (сверено: A=04, S=16, Q=14, LCtrl=E0, LAlt=E2, LWin=E3).
- Стрелки — собственные коды прошивки, не HID: Left=`5C`, Right=`5E` (сверено); Up=`5D`, Down=`5F` — предположение по соседству, железом не проверены.
- Медиа — тоже коды прошивки: VolUp=`05`, VolDown=`06` (сверено по XML: VK 175→05, VK 174→06).
- Коды кнопок мыши — те же, что в таблице переназначений (`01` ЛКМ, `02` ПКМ, `04` СКМ).
**Коллизия `05`/`06`:** это одновременно VolUp/VolDown и HID-коды букв B/C.
Как прошивка различает их (и различает ли) — не установлено; вендорская утилита шлёт `05`/`06` именно для громкости.
**Задержки:** в двух событиях вендорского XML стоит `delay_time="0"`, а в блобе прошивки — 10.
Похоже на минимум вендора (2 наблюдения).
Семантика задержки (пауза до или после события) по дампу не определяется — значения просто переносятся как есть.
### Привязка макроса к клавише
Обычная транзакция канала 04 11 (см. «Переназначение клавиш»), запись `[06, индекс, режим, счётчик]`.
Вендор после привязки делает save (в отличие от записи содержимого).
### Вендорский XML
Утилита экспортирует макрос в XML (по файлу на макрос, имя — в `macroinfo`): `item type` `2`/`3` — клавиша вниз/вверх (`value` = VK-код Windows), `4`/`5` — кнопка мыши вниз/вверх (`value`: 1 = ЛКМ, 2 = СКМ, 3 = ПКМ), `delay_time` — мс.
Реализация: `parse_macro_xml()` / `macro_to_xml()` в katana.py, офлайн-тесты — `tests/test_macro.py`
(блоб, собранный из вендорских XML, побайтово совпадает с дампом с точностью до двух задержек «0 → 10»).
**Открытые вопросы:**
- Чтение содержимого макросов из прошивки не найдено (в дампах только запись).
- Смысл u32 «число событий × 2» (возможно, счётчик полусобытий).
- Реальный лимит макросов: заголовок рассчитан на 100 слотов, но ёмкости данных хватает лишь на пару десятков событий суммарно.
- Несохранённое (без 04 f0) содержимое стирается следующим save другой транзакции (проверено) — а вот переживает ли оно переподключение USB, не установлено.
- Коллизия кодов `05`/`06` (громкость против букв B/C).
- Коды Up/Down стрелок (`5D`/`5F` — предположение) и остальные медиа-клавиши.
### Особенность режима 7 (breathing): цвет из payload игнорируется
Проверено на железе серией экспериментов:
- Payload режима 7 побайтово совпадает с вендорским (`07 ff 00 00 … 01 0f 0a … aa 55`), но LED-кадр показывает зелёно-жёлто-красную гамму (R=0, G:B ≈ 5:1) при любом цвете в байтах [1..3]: красный, зелёный и синий дают одну и ту же картинку.
- Цвет честно работает в статике (mode 1: кадр `(238,0,0)` для красного) и в fade (mode 3: кадр красноватый).
- Speed, flag и paint-таблица (0x80) на это не влияют; после `default` поведение то же.
Вывод: у breathing цветовой цикл зашит в прошивку, байты цвета для него не используются (возможно, вендорская утилита показывает то же самое — в её дампе тот же payload). При выборе режима для моноцвета используйте static или fade.
## Карта клавиш (index → физическая клавиша)
Методика: красим 4–8 индексов контрастными цветами, пользователь называет клавиши.
Полная карта — в `keymap.py` (источник данных), ниже сводка.
| Индекс | Клавиша |
| ------------- | ----------------------- |
| `0x00` | (слепой) |
| `0x01` | Esc |
| `0x02` | F1 |
| `0x03` | F2 |
| `0x04` | F3 |
| `0x05` | F4 |
| `0x06` | F5 |
| `0x07` | F6 |
| `0x08` | F7 |
| `0x09` | F8 |
| `0x0a` | F9 |
| `0x0b` | F10 |
| `0x0c` | F11 |
| `0x0d` | F12 |
| `0x0e`–`0x12` | (слепые) |
| `0x13` | ~ (`` ` ``) |
| `0x14` | 1 |
| `0x15` | 2 |
| `0x16` | 3 |
| `0x17` | 4 |
| `0x18` | 5 |
| `0x19` | 6 |
| `0x1a` | 7 |
| `0x1b` | 8 |
| `0x1c` | 9 |
| `0x1d` | 0 |
| `0x1e` | - (_) |
| `0x1f` | = (+) |
| `0x20` | NumLock |
| `0x21` | Num/ |
| `0x22` | Num* |
| `0x23`–`0x24` | (слепые) |
| `0x25` | Tab |
| `0x26` | Q |
| `0x27` | W |
| `0x28` | E |
| `0x29` | R |
| `0x2a` | T |
| `0x2b` | Y |
| `0x2c` | U |
| `0x2d` | I |
| `0x2e` | O |
| `0x2f` | P |
| `0x30` | [ ({) |
| `0x31` | ] (}) |
| `0x32` | Num7 |
| `0x33` | Num8 |
| `0x34` | Num9 |
| `0x35`–`0x36` | (слепые) |
| `0x37` | Caps |
| `0x38` | A |
| `0x39` | S |
| `0x3a` | D |
| `0x3b` | F |
| `0x3c` | G |
| `0x3d` | H |
| `0x3e` | J |
| `0x3f` | K |
| `0x40` | L |
| `0x41` | ; |
| `0x42` | ' |
| `0x43` | \ |
| `0x44` | Num4 |
| `0x45` | Num5 |
| `0x46` | Num6 |
| `0x47`–`0x48` | (слепые) |
| `0x49` | LShift |
| `0x4a` | Z |
| `0x4b` | X |
| `0x4c` | C |
| `0x4d` | V |
| `0x4e` | B |
| `0x4f` | N |
| `0x50` | M |
| `0x51` | , |
| `0x52` | . |
| `0x53` | / |
| `0x54` | RShift |
| `0x55` | Enter |
| `0x56` | Num1 |
| `0x57` | Num2 |
| `0x58` | Num3 |
| `0x59`–`0x5a` | (слепые) |
| `0x5b` | LCtrl |
| `0x5c` | LWin |
| `0x5d` | LAlt |
| `0x5e` | Space |
| `0x5f` | RAlt |
| `0x60` | Fn |
| `0x61` | Menu |
| `0x62` | RCtrl |
| `0x63` | ArrowLeft |
| `0x64` | ArrowDown |
| `0x65` | ArrowUp |
| `0x66` | ArrowRight |
| `0x67` | Backspace |
| `0x68` | Num0 |
| `0x69` | Num. (Del) |
| `0x6a` | NumEnter |
| `0x6b`–`0x6f` | (слепые) |
| `0x70` | PrtSc |
| `0x71` | ScrLk |
| `0x72` | (слепой) |
| `0x73` | Pause |
| `0x74` | Insert |
| `0x75` | Home |
| `0x76` | PgUp |
| `0x77` | Delete |
| `0x78` | End |
| `0x79` | PgDown |
| `0x7a` | Num- |
| `0x7b` | Num+ |
| `0x7c`–`0x8e` | (слепые) |
Итого **104 клавиши**, все 143 слота проверены, все физические клавиши светятся при полной заливке (проверено: «горят ВСЕ клавиши»).
Нумпад полный: NumLock, /, *, -, 7/8/9, 4/5/6, 1/2/3, +, 0, ., Enter.
**Слепые слоты** (39 шт, не соответствуют ни одному LED): 0x00, 0x0e–0x12, 0x23, 0x24, 0x35, 0x36, 0x47, 0x48, 0x59, 0x5a, 0x6b–0x6f, 0x72, 0x7c–0x8e.
Хвост 0x80+ — резерв прошивки под большие раскладки/модели.
**Аномалия 0x80:** в раннем тесте светился синим сам по себе; в финальном тесте (жёлтый) не горел.
Считать слепым, но помнить про аномалию при чтении f5 (в потоке чтения 0x80 показывал 0000ff).
**Урок картирования:** тёмные/холодные цвета (синий) на дальних клавишах пользователь может не заметить — Num- (0x7a) был пропущен в синем тесте, но найден жёлтым при перепроверке слепых слотов группами.
При сомнениях перепроверять слепые слоты яркой заливкой группами.
## Статус утилиты katana.py
### `mode N --color RRGGBB [--brightness 1..15] [--speed 2..15] [--flag]`
Валидация диапазонов.
Для mode 1 speed форсируется 0x0A с warning.
### `off`
Payload нулей + aa55.
### `default`
Вендорский payload 0x80.
### `raw HEX`
Произвольный payload в транзакции.
### `scan --from --to`
Перебор режимов (1..19), каждый с save.
### `reset`
USB port reset (unwedge).
### `paint --all RRGGBB [--key IDX=RRGGBB ...] [--black] [--keep] ...`
Запись таблицы (143 клавиши) + показ mode 0x80.
`--wasd` = четыре `--key` для W/A/S/D.
`--numpad` = 17 `--key` для всего нумпада.
`--alpha` = 26 `--key` для букв A–Z.
`--punct` = 9 `--key` для знаков `[];',./\` и пробела.
`--digits` = 13 `--key` для ряда `` `1234567890-= ``.
`--arrows` = 4 `--key` для стрелок.
`--row1..--row6` = `--key` для горизонтальных рядов полной клавиатуры, включая нумпад (104 клавиши; высокие клавиши нумпада отнесены к ряду начала; состав — ROW_KEYS в katana.py).
`--keep` берёт базой текущий живой кадр (чтение f5), остальные клавиши сохраняют цвета.
В `--key` индексы задаются только в hex (`0x25`), голые цифры — имена клавиш цифрового ряда.
Клавиши со спецсимволами принимаются символом (`[`, `~`, `;`, ...), синонимом (`tilde`, `minus`, `lbracket`, `semicolon`, `backslash`, `numenter`, ... — таблица KEY_SYMBOL_ALIASES в keymap.py) и каноническим именем из keymap.py.
### `keys`
Чтение живого кадра (04 f5).
### `remap --key KEY=ACTION [--key ...] [--clear]`
Таблица переназначений (канал 04 11).
ACTION: мышь (`lmb`/`mouse1`, `rmb`/`mouse2`, `mmb`/`mouse3`, `back`/`mouseback`, `forward`/`mouseforward`), шорткаты редактора (`open`/`new`/`undo`/`save`/`copy`/`cut`/`paste`/`find`/`selectall` — Ctrl+O/N/Z/S/C/X/V/F/A), мультимедиа (`player`, `play`, `stop`, `prev`, `next`, `volup`, `voldown`, `mute`, `home`, `refresh`, `webstop`, `webback`, `webforward`, `favorites`, `websearch`, `mycomputer`, `calculator`, `email`), горячие клавиши (`MOD+КЛАВИША`: `ctrl`/`shift`/`alt`/`meta` + `a`..`z`, `0`..`9`, `f1`..`f12`, `esc`, `tab`, `enter`, `space`, `caps`, `backspace`, `num0`..`num9`, `fn` — например `ctrl+c`, `shift+b`, `meta+e`), `default`/`none`/`off`, макросы (`macro<N>` — однократно, `macro<N>:K` — K повторов, `macro<N>-toggle` — до останова).
`--clear` — вся таблица в default.
ВАЖНО: каждый вызов перезаписывает всю таблицу — не указанные `--key` сбрасываются в default; чтение текущих переназначений неизвестно.
### `macro set N [токены] [--xml FILE] [--save]`
Записать содержимое макроса N (канал 04 19, без save — как вендор; `--save` шлёт 04 f0).
Токены: `[+-]имя[@задержка_мс]` (`+` нажать, `-` отпустить, без знака — нажать и отпустить; имена — MACRO_KEYS/MOUSE_ACTIONS); перед токенами с `-` нужен `--`.
ВАЖНО: перезаписываются ВСЕ слоты макросов — не указанные стираются.
После записи привязать: `remap --key KEY=macro<N>`.
### `macro clear [--save]`
Стереть ВСЕ слоты макросов.
### `macro show FILE` / `macro export FILE [токены] [--name]`
Офлайн: показать события из вендорского XML / сгенерировать вендорский XML из токенов (без обращения к железу).
## Инструменты анализа
- `analyze_pcap.py <capture.pcapng> [out.txt]` — USBPcap → лог SET/GET control-трансферов (merged setup+data для OUT; GET по irpid).
- `raw-data/*.txt` — распарсенные логи всех 5 захватов (katana1 + 4×katana2).
- Захваты: `katana1.pcapng` (базовый реверс), `katana2-color-static` (цвета), `katana2-bright-static` (яркость), `katana2-speed` (скорость), `katana2-modes` (все режимы + off).
В режимах был случайный дубликат клика (mode 8 дважды).
- Сессии записи таблицы клавиш в katana1: события #11 и #36 (0x23, блок 09).
## Следующие шаги
1. ~~Докартировать карту~~ — ЗАВЕРШЕНО (104 клавиши, keymap.py).
2. ~~Починить чтение f5~~ — ЗАВЕРШЕНО (вендорская схема: SET f5 → 9 GET → commit → save; без begin/data-begin; ретраи с валидацией индексов).
3. Именованные пресеты (WASD, дыхание и т.п.) поверх paint — keymap.py готов.
4. ~~Переназначение клавиш: канал 04 20~~ — УТОЧНЕНО: канал `04 11` (не 04 20), формат и мышиные действия сняты и реализованы (см. «Переназначение клавиш»).
Шорткаты редактора (тип `02`) тоже сняты и реализованы (дамп keybind-editor).
Горячие клавиши (тип `02`, маска модификаторов в байте [1]) сняты по дампу keybind-hotkeys и реализованы (`HOTKEY_KEYS`/`HOTKEY_MODIFIERS`, `remap --key KEY=MOD+KEY`).
Осталось: другие типы действий (Fn-слой) и чтение таблицы.
5. ~~Демо-скрипты (радуга, волна) поверх per-key API + живое чтение f5~~ — ЗАВЕРШЕНО, методика описана и проверена ([EXTENDING.md](EXTENDING.md)): таблица обновляется живьём в режиме 0x80, ~1 кадр/с.
6. ~~Макросы: запись содержимого и привязка~~ — ЗАВЕРШЕНО (канал 04 19 + записи `[06, ...]` в 04 11, команда `macro`, см. «Макросы»).
Осталось: чтение содержимого, коллизия кодов 05/06, стрелки Up/Down, остальные медиа-коды.
## Важные грабли (не наступать повторно)
- pyusb + detach_kernel_driver = клавиатура перестаёт печатать.
Только hidraw.
- Сессия без f0 = клин прошивки.
Всегда save.
- После клина: reset может не помочь с первого раза — повторить с паузой 5–10 c.
- f5-чтение без begin+data-begin = мусор (указатель не с начала).
- begin ACK ff = «сессия уже открыта» — это ок, продолжать.
- Слепые слоты молча игнорируются прошивкой (ACK ok, но не горят).
- Пользователь различает цвета приблизительно: «розовый»=маджента, «жёлтый»=жёлтый/олива, «зелёный»=зелёный/тёмнозелёный.
Для картирования использовать максимально контрастные цвета и мало точек за раз.
+90
View File
@@ -0,0 +1,90 @@
# Дампы GANSS ARDOR_Katana (katana-v1)
Сырые данные, на которых построен реверс протокола (см. [PROTOCOL.md](PROTOCOL.md)).
Устройство: клавиатура GANSS ARDOR_Katana, USB `0C45:8006` (Sonix SN32).
## Состав
| Файл | Что это |
| ---------------------------------------------------------- | ----------------------------------------------------------------------------------- |
| `color-presets.pcapng` / `.plain.txt` | выбор цветовых пресетов в фирменной утилите (статика, RGB-цвета) |
| `bright.pcapng` / `.plain.txt` | слайдер яркости (все 15 позиций, диапазон 0x01–0x0F) |
| `animation-speed.pcapng` / `.plain.txt` | слайдер скорости анимаций (диапазон 0x02–0x0F) |
| `color-modes.pcapng` / `.plain.txt` | перебор всех режимов освещения 1–19 + off |
| `color-toggle-rainbow.pcapng` / `.plain.txt` | переключение статики моно/радуга (байт [11]) |
| `color-toggle-direction-north-south.pcapng` / `.plain.txt` | направление водопада ↑/↓ (байт [11]) |
| `color-toggle-direction-east-west.pcapng` | направление бегущей строки ←/→ (байт [11], без .plain.txt) |
| `keybind-mouse-buttons.pcapng` / `.plain.txt` | переназначение LCtrl на 5 кнопок мыши по очереди + возврат на default (канал 04 11) |
| `keybind-editor.pcapng` / `.plain.txt` | переназначение Caps на 9 функций текстового редактора по очереди (канал 04 11, записи `[02 01 код 00]`) |
| `keybind-multimedia.pcapng` / `.plain.txt` | переназначение Caps на 18 мультимедиа/веб-функций по очереди (канал 04 11, записи `[03 usage_le 00]`) |
| `keybind-hotkeys.pcapng` / `.plain.txt` | переназначение Caps на 10 горячих клавиш по очереди: A, Shift+B, Ctrl+C, Alt+D, Meta+E, Esc, F1, Num1, Fn, «Мой компьютер» (канал 04 11, записи `[02 маска код 00]` + одна мультимедиа) |
| `macros-create.pcapng` / `.plain.txt` | запись содержимого двух макросов (канал 04 19) |
| `macros-create-test.xml`, `test.xml` | вендорский XML тех же макросов (экспорт утилиты) |
| `macros-set.pcapng` / `.plain.txt` | привязка макроса к клавише, однократно (канал 04 11, запись `[06, ...]`) |
| `macros-modes.pcapng` / `.plain.txt` | привязка макроса: однократно / N повторов / до останова (канал 04 11) |
| `macros-call.pcapng` / `.plain.txt` | нажатие клавиши с макросом: control-канал чист, отработка идёт через interrupt IN |
| `usb-devices-output.txt` | дескрипторы устройства Linux (вывод `usb-devices`) |
`.pcapng` — сырой захват USB-трафика; `.plain.txt` — тот же трафик, распарсенный в лог control-трансферов SET/GET_REPORT.
## Как получить pcapng (Windows + USBPcap)
Все операции только на Windows.
1. Установить [Wireshark](https://www.wireshark.org/download.html), при установке выбрать `usbpcap`.
2. Установить фирменную утилиту для клавиатуры:
- [ardor-gaming.com](https://ardor-gaming.com/drivers/29524343/katana/)
- [dns-shop.ru](https://www.dns-shop.ru/product/driver/3c23900ab1b2ed20/klaviatura-provodnaa-besprovodnaa-ardor-gaming-katana-cvet-cernyj/)
3. Запустить утилиту, подключить клавиатуру.
4. Запустить Wireshark, внизу выбрать `usbpcap` и начать захват.
5. Произвести нужные операции в утилите настройки.
6. Остановить захват в Wireshark и сохранить файл `<имя>.pcapng`.
Захват должен содержать весь трафик сессий: begin → data-begin → payload → commit → save.
Полезно сделать в начале захвата одно полное действие, чтобы в дамп попала 1 и более целая транзакция.
### При работе в VirtualBox
После установки и запуска фирменной утилиты предоставьте машине доступ к клавиатуре.
![](./vbox-usb.webp)
Настройте общую папку, чтобы в неё сохранять дампы из виртуальной машины на хост.
## Как конвертировать pcapng → plain.txt
На Linux, из корня репозитория:
```
python3 analyze_pcap.py raw-data/katana-v1/color-modes.pcapng raw-data/katana-v1/color-modes.plain.txt
```
Формат строки лога:
```
SET #N if=I t=T rid=R len=L: <hex-байты>
```
- `if` — номер USB-интерфейса (конфиг-канал = `if=0`);
- `t` — bmRequestType: `21` = SET_REPORT (host→device), `a1` = GET_REPORT (device→host);
- `rid` — report id (все команды идут с `rid=00`);
- GET-пакеты склеиваются по `irpid`: setup и data приходят разными записями, парсер сопоставляет их автоматически.
## Как узнать дескрипторы клавиатуры
На Linux с подключённой клавиатурой:
```
usb-devices | grep -B 2 -A 8 'Vendor=0c45' > usb-devices-output.txt
```
В дампе видно: 2 HID-интерфейса (boot keyboard и mouse/consumer), оба под `usbhid`, interrupt-эндпоинты `0x81`/`0x82`.
Конфигурационный канал — feature-репорты интерфейса 0 (эндпоинты управления, не interrupt).
В `lsusb` устройство подписывается «Microdia Dual Mode Camera (8006 VGA)» — это норма: ID `0c45:8006` чипа Sonix SN32 используется и вебкамерами, и клавиатурами, а база `usb.ids` знает за ним только камеру.
Подробнее — в [INSTALL.md](INSTALL.md) → «Проверка устройства».
## Замечания
- Имена файлов оригинальные, включая опечатку `color-pesets.pcapng` (содержимое соответствует color-presets).
- Расшифровка протокола по этим дампам — в [PROTOCOL.md](PROTOCOL.md), парсер — `analyze_pcap.py`, рабочая утилита — `katana.py` (обзор — в [SCRIPTS.md](SCRIPTS.md)).
+73
View File
@@ -0,0 +1,73 @@
# Скрипты репозитория
Состав репозитория и назначение каждого скрипта.
Использование `katana.py` как библиотеки (свои скрипты и анимации) — в [EXTENDING.md](EXTENDING.md).
## Структура репозитория
```
.
├── katana.py Основная CLI-утилита управления подсветкой
├── keymap.py Карта «LED-индекс → физическая клавиша» (104 клавиши)
├── katana.yaml.example Пример YAML-конфига для команды apply
├── analyze_pcap.py Парсер USBPcap-захватов → лог control-трансферов
├── probe.py Исследовательский зонд: чтение feature-репортов
├── 70-ganss-katana.rules udev-правило: доступ к устройству без root
├── tests/ Офлайн-тесты (без железа)
├── docs/ Документация (см. README.md)
└── raw-data/
└── katana-v1/ Сырые дампы (pcapng + распарсенные логи)
```
## keymap.py
Карта LED-индексов, снятая экспериментально (покраска групп индексов контрастными цветами + фиксация, какие клавиши загорелись).
Используется `katana.py` для имён клавиш; отдельно запускается для просмотра:
```
./keymap.py
```
Печатает подтверждённую карту, список слепых слотов (39 шт — резерв прошивки, ни к какому LED не подключены), непроидентифицированные индексы и таблицу алиасов клавиш (`KEY_SYMBOL_ALIASES`).
Методика картирования и открытые вопросы — в [PROTOCOL.md](PROTOCOL.md) (раздел «Карта клавиш»).
## analyze_pcap.py
Парсер захватов USBPcap (pcapng) в человекочитаемый лог control-трансферов.
Нужен только при пополнении `raw-data/` новыми дампами:
```
./analyze_pcap.py <вход.pcapng> [выход.txt]
```
Без второго аргумента пишет `/tmp/tx_log.txt`.
Формат строк и методика снятия захватов — в [RAW-DATA.md](RAW-DATA.md).
## probe.py
Исследовательский зонд времён начала реверса: перебирает report id и читает feature-репорты (только GET, состояние клавиатуры не меняет).
Полезен как минимальный пример hidraw-транспорта:
```
./probe.py [hidrawN]
```
Без аргумента находит все hidraw-узлы клавиатуры сам.
## tests/
Офлайн-тесты (железо не нужно):
```
python3 tests/test_macro.py # макросы, remap-действия, сверка с дампами
python3 tests/test_apply.py # apply: YAML-конфиг → argv команд
python3 tests/test_parsers.py # парсеры, payload, ACK, keymap
python3 tests/test_cli.py # команды CLI на подменном устройстве
```
`test_macro.py` — блоб, собранный из вендорских XML, сверяется побайтово с дампом macros-create, плюс разбор токенов, round-trip XML, hotkey/remap-действия и сверка с дампами keybind-editor/keybind-hotkeys/keybind-multimedia.
`test_apply.py` — пример katana.yaml.example разбирается и превращается в валидные argv существующих команд, проверка отклонения опечаток и неизвестных секций.
`test_parsers.py` — parse_color/parse_mode/check_range, resolve_key (имена, символы, алиасы, hex-индексы), раскладка lighting payload, номера hidraw ioctl, статические проверки ACK Katana и целостность keymap.py (карта, слепые слоты, алиасы, группы клавиш paint).
`test_cli.py` — команды mode/off/default/raw/scan/reset/paint/keys/remap/macro/apply прогоняются через build_parser() и dispatch() с подменным устройством (FakeKatana пишет вызовы в журнал): формирование payload'ов, вендорские дефолты статики, направления анимаций, раскрытие shorthand-групп paint, записи всех типов действий remap, порядок секций и расстановка save'ов в apply, сообщения об ошибках.
Каждый файл запускается и напрямую (`python3 tests/...`), и через pytest (если установлен).
+23
View File
@@ -0,0 +1,23 @@
# Команды утилиты katana.py
Справочник команд и аргументов.
Все команды идут через транзакцию `begin → data → commit → save` и безопасны: печать не прерывается, прошивка остаётся живой.
Исключение — `macro set`/`macro clear`: вендор после записи макросов save не делает (подробности в [PROTOCOL.md](../PROTOCOL.md)).
Низкоуровневое описание транзакций — в [PROTOCOL.md](../PROTOCOL.md).
Режимы подсветки и их аргументы вынесены в отдельный документ: [COLOR-MODES.md](../COLOR-MODES.md).
## Состав справочника
| Документ | Тема |
| ------------------------------------- | ----------------------------------------------------------------------------- |
| [colors.md](colors.md) | Именованные цвета CSS вместо `RRGGBB`. |
| [keys.md](keys.md) | Имена клавиш: канонические, символы, синонимы, hex-индексы. |
| [paint.md](paint.md) | `paint` — per-key раскраска и shorthand-алиасы (`--wasd`, `--row1`…`--row6`). |
| [scan.md](scan.md) | `scan` — визуальный перебор режимов. |
| [raw.md](raw.md) | `raw` — произвольный payload для экспериментов. |
| [remap.md](remap.md) | `remap` — переназначение клавиш на мышь, шорткаты редактора, мультимедиа, горячие клавиши и макросы. |
| [macro.md](macro.md) | `macro` — запись макросов, работа с вендорским XML. |
| [apply.md](apply.md) | `apply` — применение YAML-конфига целиком (профиль настроек). |
| [commands.md](commands.md) | Команды без аргументов: `keys`, `reset`, `off`, `default`. |
| [troubleshooting.md](troubleshooting.md) | Что делать, если команда отклоняется или прошивка залипла. |
+101
View File
@@ -0,0 +1,101 @@
# apply — применение YAML-конфига
Применяет конфиг из YAML-файла: вместо длинных команд — один файл со всеми настройками.
Файл можно хранить в любом месте (например `~/.config/katana.yaml`), в репозитории лежит пример [katana.yaml.example](../../katana.yaml.example).
```
./katana.py apply ~/my-katana.yaml # применить конфиг
./katana.py apply katana.yaml.example # применить пример из репозитория
```
Зависимость: PyYAML (`pip install pyyaml`, см. [INSTALL.md](../INSTALL.md)).
## Порядок применения и сохранение
Секции применяются всегда в одном порядке, независимо от их порядка в файле:
1. `remap` — таблица переназначений (04 11), save;
2. `paint` — per-key раскраска, включает режим 0x80, save;
3. `lighting` — финальный режим подсветки (mode/off/default), перекрывает 0x80 от paint, save;
4. `raw` — произвольный payload (для экспериментов);
5. `macros` — ВСЕ слоты одним блобом (04 19), save;
6. `remap` и `lighting` — **повторно** (если секции были в конфиге), со save.
**Модель сохранения** (проверена на железе): каждая область прошивки (bind-таблица, paint-таблица, режим, макросы) сохраняется во флеш **только своим собственным save** (04 f0) — чужой save чужую область ни сохраняет, ни затирает. Поэтому в apply каждая секция несёт свой save.
**Почему remap и lighting повторяются после макросов:** запись макросов (04 19) сбивает bind-таблицу и режим подсветки **в RAM** (во флеше они остаются). Повторная отправка восстанавливает их в RAM и заодно фиксирует save'ом.
**Почему все макросы одним блобом:** каждый вызов `macro set` обнуляет прочие слоты — несколько макросов нужно писать за одну транзакцию (apply так и делает).
Ключ `save` в секциях конфига **не поддерживается** — apply управляет save'ами сам (написанный по ошибке `save: false` отклоняется как неизвестный ключ).
Каждая секция прогоняется через соответствующую команду CLI — валидация значений та же самая.
Перед каждым шагом печатается `apply [...] ...`, после — итоговый список применённого.
Команды `keys`, `scan`, `reset` в конфиге не нужны: это диагностика, а не состояние.
## Секции
### `macros` — содержимое макросов (см. [macro.md](macro.md))
Все слоты пишутся **одним блобом** (пропуски между номерами — пустые слоты).
Ключ — номер слота 0..99, значение — `tokens` (список) или `xml` (файл).
```yaml
macros:
0:
tokens: ["+lctrl", "a@50", "-lctrl"] # Ctrl+A
1:
xml: raw-data/katana-v1/test.xml
```
### `remap` — переназначение клавиш (см. [remap.md](remap.md))
```yaml
remap:
keys:
caps: macro0 # КЛЮЧ: ДЕЙСТВИЕ — те же, что у remap --key
menu: meta+e
# clear: true # вместо keys: сбросить ВСЕ переназначения
```
### `paint` — раскраска клавиш (см. [paint.md](paint.md))
```yaml
paint:
all: black # база (или black: true / keep: true)
keys:
esc: "ff0000" # КЛЮЧ: ЦВЕТ
wasd: dodgerblue # shorthand-алиасы CLI: wasd, numpad, alpha, punct, digits, arrows
rows:
1: "202020" # ряды 1..6
brightness: 15
```
### `lighting` — режим подсветки (см. [COLOR-MODES.md](../COLOR-MODES.md))
`mode` — имя или номер 1..19, а также `off` и `default` (применяются как команды `off`/`default`).
```yaml
lighting:
mode: static
color: red
brightness: 15 # 1..15
# speed: 5 # 2..15
# rainbow: true # статика: спектр вместо color
# direction: north-south
```
### `raw` — сырой payload (см. [raw.md](raw.md))
```yaml
raw: "80 00 ... aa 55" # hex-строка или список строк
```
## Валидация
- Неизвестные секции и неизвестные ключи внутри секций отклоняются с указанием опечатки.
- `macros`: слот должен иметь либо `tokens`, либо `xml` (не оба и не ни одного).
- Значения проверяются тем же парсером, что и CLI-команды (`parse_color`, `parse_mode`, диапазоны).
Офлайн-тесты — `tests/test_apply.py` (пример конфига разбирается и превращается в валидные argv).
+28
View File
@@ -0,0 +1,28 @@
# Именованные цвета
Вместо `RRGGBB` можно передавать имя из палитры CSS Color Module Level 4 — все 147 стандартных имён (`aliceblue`, `antiquewhite`, `aqua`, ..., `whitesmoke`, `yellow`, `yellowgreen`), включая оба варианта написания серых (`gray`/`grey`, `darkgray`/`darkgrey`, `slategray`/`slategrey`, `dimgray`/`dimgrey`, `lightslategray`/`lightslategrey`, `darkslategray`/`darkslategrey`) и `rebeccapurple`.
Полный список — `COLOR_ALIASES` в [katana.py](../../katana.py).
Наиболее употребимые:
| Имя | Hex | Имя | Hex |
| ---------------- | -------- | ------------------- | -------- |
| `red` | `ff0000` | `orange` | `ffa500` |
| `green` | `008000` | `purple` | `800080` |
| `blue` | `0000ff` | `violet` | `ee82ee` |
| `yellow` | `ffff00` | `magenta`/`fuchsia` | `ff00ff` |
| `cyan`/`aqua` | `00ffff` | `pink` | `ffc0cb` |
| `white` | `ffffff` | `lime` | `00ff00` |
| `black` | `000000` | `teal` | `008080` |
| `gold` | `ffd700` | `silver` | `c0c0c0` |
| `crimson` | `dc143c` | `indigo` | `4b0082` |
| `hotpink` | `ff69b4` | `navy` | `000080` |
| `maroon` | `800000` | `olive` | `808000` |
| `chartreuse` | `7fff00` | `turquoise` | `40e0d0` |
| `coral` | `ff7f50` | `salmon` | `fa8072` |
| `khaki` | `f0e68c` | `orchid` | `da70d6` |
| `gray`/`grey` | `808080` | `whitesmoke` | `f5f5f5` |
Примеры: `--color rebeccapurple`, `--key esc=hotpink`, `paint --black --wasd dodgerblue`.
Имена клавиш, которые принимают команды, описаны в [keys.md](keys.md).
+28
View File
@@ -0,0 +1,28 @@
# Команды без аргументов
```
./katana.py keys # живой кадр
./katana.py reset # разблокировка прошивки
./katana.py off # выключение подсветки
./katana.py default # вендорский payload
```
## Команды
### `off`
Выключить подсветку (all-zero payload).
### `default`
Вендорский дефолтный payload (режим `0x80`, пустая таблица).
### `keys`
Прочитать живой кадр: текущие цвета всех 143 слотов с учётом яркости и анимаций.
Печатается сеткой 16 слотов на строку, `......` = чёрный.
### `reset`
USB port reset без переподключения: снимает залипание прошивки.
Перечисление ~2 с, клавиатура не отваливается от системы.
+61
View File
@@ -0,0 +1,61 @@
# Имена клавиш
В `paint --key КЛЮЧ=ЦВЕТ` (и во всех shorthand-алиасах) клавиша задаётся любым из способов:
**Канонические имена** (US-раскладка, из `keymap.py`): `esc`, `f1`–`f12`, `` ` ``–`0` (цифры и тильда), `-`, `=`, `tab`, `q`–`p`, `[`, `]`, `caps`, `a`–`l`, `;`, `'`, `\`, `enter`, `z`–`m`, `,`, `.`, `/`, `lshift`, `lctrl`, `lwin`, `lalt`, `space`, `ralt`, `fn`, `menu`, `rctrl`, `arrowleft`, `arrowdown`, `arrowup`, `arrowright`, `backspace`, `prtsc`, `scrlk`, `pause`, `insert`, `home`, `pgup`, `delete`, `end`, `pgdown`, а также нумпад: `numlock`, `num/`, `num*`, `num-`, `num7`–`num0`, `num.`, `num+`, `numenter`.
Буквы — строчные или заглавные (`a` = `A`).
**Символы клавиш** пишутся как есть: `` ` ``, `1`–`0`, `-`, `=`, `[`, `]`, `;`, `'`, `\`, `,`, `.`, `/`, `~`.
**Синонимы** (полная таблица — `KEY_SYMBOL_ALIASES` в `keymap.py`; просмотр: `python3 keymap.py`), по клавишам:
| Клавиша | Синонимы |
| ---------------- | --------------------------------------------------------------------- |
| `` ` `` (тильда) | `tilde`, `grave`, `backquote`, `backtick` |
| `-` | `minus`, `dash`, `hyphen` |
| `=` | `equal`, `equals` |
| `[` | `lbracket`, `leftbracket`, `openbracket` |
| `]` | `rbracket`, `rightbracket`, `closebracket` |
| `;` | `semicolon`, `colon` |
| `'` | `quote`, `apostrophe`, `singlequote` |
| `\` | `backslash`, `bslash` |
| `,` | `comma`, `lessthan` |
| `.` | `period`, `dot`, `greaterthan` |
| `/` | `slash`, `question` |
| `space` | `spacebar` |
| `esc` | `escape` |
| `tab` | `tab` |
| `caps` | `capslock` |
| `enter` | `return`, `cr` |
| `backspace` | `bksp` |
| `lshift` | `shift`, `leftshift` |
| `rshift` | `rightshift` |
| `lctrl` | `ctrl`, `leftctrl` |
| `rctrl` | `rightctrl` |
| `lalt` | `alt`, `leftalt` |
| `ralt` | `altgr`, `rightalt` |
| `lwin` | `windows`, `super`, `meta` |
| `menu` | `context`, `apps` |
| `insert` | `ins` |
| `delete` | `del` |
| `pgup` | `pageup` |
| `pgdown` | `pgdn`, `pagedown` |
| `prtsc` | `printscreen`, `prntscr`, `pscr` |
| `scrlk` | `scrolllock`, `slck` |
| `pause` | `break` |
| `arrowleft` | `left`, `leftarrow` |
| `arrowright` | `right`, `rightarrow` |
| `arrowup` | `up`, `uparrow` |
| `arrowdown` | `down`, `downarrow` |
| `numlock` | `numlock` |
| `num/` | `numslash`, `numdivide` |
| `num*` | `numasterisk`, `numtimes` |
| `num-` | `numminus` |
| `num+` | `numplus` |
| `num.` | `numdot`, `numpoint`, `numdecimal`, `numdel`, `numcomma`, `numperiod` |
| `num0`–`num9` | `num0`, `num1`, … `num9` |
| `numenter` | `numenter` |
**Hex-индексы**: `0x00`–`0x8e` — прямой адрес LED-слота (голые цифры без `0x` — имена клавиш цифрового ряда, не индексы).
Цвета для `КЛЮЧ=ЦВЕТ` задаются hex-кодом или именем — см. [colors.md](colors.md).
+69
View File
@@ -0,0 +1,69 @@
# macro — макросы
Записывает содержимое макросов в прошивку (канал 04 19) и работает с вендорским XML.
Формат протокола — в [PROTOCOL.md](../PROTOCOL.md).
Макрос нужно привязать к клавише через `remap --key КЛЮЧ=macro<N>` (индексация 0-based: «Макрос 1» вендорской утилиты = 0).
```
./katana.py macro set 0 -- a@126 s@101 -a@41 f # макрос 0 из токенов
./katana.py macro set 0 --xml test.xml # макрос 0 из вендорского XML
./katana.py remap --key caps=macro0 # привязать к Caps
./katana.py macro clear # стереть все макросы
./katana.py macro show test.xml # показать события из XML (офлайн)
./katana.py macro export my.xml -- +lctrl a@50 -lctrl # сгенерировать XML (офлайн)
```
## Токены событий
Токен: `[+-]имя[@задержка_мс]`.
`+` — нажать, `-` — отпустить, без знака — нажать и отпустить (задержка ставится на отпускание).
Задержка — пауза в мс после события.
Перед токенами, начинающимися с `-`, ставьте разделитель `--`, иначе argparse примет их за опции.
Разбор примера `a@126 s@101 -a@41`:
| Токен | Что делает |
| ------- | ------------------------------------------------------------- |
| `a@126` | нажать и отпустить `A`, после отпускания пауза 126 мс |
| `s@101` | нажать и отпустить `S`, пауза 101 мс |
| `+a` | только нажать `A` (отпустить позже через `-a`) |
| `-a@41` | только отпустить `A` (зажатую раньше через `+a`), пауза 41 мс |
Пример сочетания с модификатором: `+lctrl a@50 -lctrl` — зажать Ctrl, нажать-отпустить A, отпустить Ctrl (Ctrl+A).
Имена клавиш — строчные: буквы `a`–`z`, цифры `1`–`0`, `f1`–`f12`, модификаторы (`lctrl`, `lshift`, `lalt`, `lwin`, `rctrl`, ...), `esc`, `tab`, `enter`, `backspace`, `caps`, `space`, стрелки (`left`, `up`, `right`, `down` — собственные коды прошивки, Up/Down не проверены), громкость (`volup`, `voldown`).
Кнопки мыши — те же имена, что в `remap`: `lmb`, `rmb`, `mmb`, `back`, `forward`.
## Аргументы `macro set`
### `index`
Слот макроса (0-based), `0`–`99`.
### `tokens`
События макроса (см. «Токены событий» выше).
Указывается либо `tokens`, либо `--xml`.
### `--xml ФАЙЛ`
Взять события из вендорского XML.
### `--save`
Отправить `04 f0` после коммита.
По умолчанию выключено: вендор после записи макросов save НЕ делает.
**Важно:** запись перезаписывает ВСЕ слоты макросов — макросы в других слотах стираются.
Несколько макросов записывайте за один вызов (apply так и делает) — см. [apply.md](apply.md).
Ёмкость по дампу — 896 байт блоба: до ~60 событий в один слот.
Чтение содержимого из прошивки не реализовано (канал чтения неизвестен).
Save (`--save`) по умолчанию выключен (как у вендора), но макросы переживают переподключение **только со своим save** — у каждой области прошивки свой save (см. [apply.md](apply.md) → «Порядок применения и сохранение»).
После записи макросов bind-таблица и режим подсветки сбиваются в RAM — перепошлите их (remap + mode).
## `macro show` и `macro export`
Обе команды работают офлайн, без обращения к клавиатуре.
`show файл.xml` печатает события в форме токенов.
`export файл.xml [токены] [--name ИМЯ]` создаёт вендорский XML — такие файлы понимает фирменная утилита.
+100
View File
@@ -0,0 +1,100 @@
# paint — per-key раскраска
```
./katana.py paint --all orange # вся клавиатура оранжевым
./katana.py paint --black --key Tab=green # только Tab зелёным
./katana.py paint --black --key a=red --key s=green --key d=blue
./katana.py paint --black --key 0x25=ff0000 # hex-индекс тоже работает
./katana.py paint --keep --key tilde=red --key semicolon=lime # синонимы клавиш
./katana.py paint --keep --key ~=red --key ;=lime # символы тоже работают
./katana.py paint --black --row1 red --row6 magenta # ряды: F-строка и низ
```
## Аргументы `paint`
### `--all ЦВЕТ`
Залить все 143 слота этим цветом.
Без `--black` незатронутые `--key` слоты получат этот же цвет.
### `--key КЛЮЧ=ЦВЕТ`
Покрасить одну клавишу.
Повторяется сколько нужно (`--key a=red --key s=green`).
КЛЮЧ — имя из `keymap.py` (`Tab`, `a`, `num7`, `esc`, `f12`), символ клавиши (`` ` ``, `1`, `-`, `[`, `;`, `'`, `\`, `,`, `.`, `/`, `~`), синоним (`tilde`, `minus`, `equal`, `lbracket`, `semicolon`, `quote`, `backslash`, `comma`, `period`, `dot`, `slash`, `question`, `shift`, `ctrl`, `alt`, `enter`, `return`, `del`, `ins`, `pgup`, `pgdn`, `left`/`right`/`up`/`down`, `num0`–`num9`, `numplus`, `numminus`, `numdot`, ...) или hex-индекс `0x00`–`0x8e` (голые цифры — имена клавиш цифрового ряда).
ЦВЕТ — hex или имя.
Подробности об именах клавиш — [keys.md](keys.md), о цветах — [colors.md](colors.md).
### `--wasd ЦВЕТ`
Shorthand для четырёх `--key`: покрасить W, A, S, D одним цветом.
Пример: `paint --black --wasd red`.
### `--numpad ЦВЕТ`
Shorthand для `--key`: покрасить весь нумпад одним цветом (NumLock, `/`, `*`, `-`, `7`–`0`, `.`, `+`, Enter).
Пример: `paint --black --numpad blue`.
### `--alpha ЦВЕТ`
Shorthand для `--key`: покрасить все 26 буквенных клавиш (A–Z) одним цветом.
Пример: `paint --black --alpha gold`.
### `--punct ЦВЕТ`
Shorthand для `--key`: покрасить знаковые клавиши основного блока `[`, `]`, `;`, `'`, `\`, `,`, `.`, `/` и пробел одним цветом.
Пример: `paint --black --punct orange`.
### `--digits ЦВЕТ`
Shorthand для `--key`: покрасить цифровой ряд `` ` ``, `1`–`0`, `-`, `=` одним цветом.
Пример: `paint --black --digits cyan`.
### `--arrows ЦВЕТ`
Shorthand для `--key`: покрасить четыре стрелки одним цветом.
Пример: `paint --black --arrows magenta`.
### `--row1`…`--row6 ЦВЕТ`
Shorthand для `--key`: покрасить горизонтальный ряд полной клавиатуры одним цветом (включая нумпад).
Ряд 1 (16 клавиш): `esc`, F1–F12, `prtsc`, `scrlk`, `pause`.
Ряд 2 (21): `` ` ``–`0`, `-`, `=`, `backspace`, `insert`, `home`, `pgup`, `numlock`, `num/`, `num*`, `num-`.
Ряд 3 (21): `tab`, Q–P, `[`, `]`, `\`, `delete`, `end`, `pgdown`, `num7`–`num9`, `num+`.
Ряд 4 (16): `caps`, A–L, `;`, `'`, `enter`, `num4`–`num6`.
Ряд 5 (17): `lshift`, Z–M, `,`, `.`, `/`, `rshift`, `arrowup`, `num1`–`num3`, `numenter`.
Ряд 6 (13): `lctrl`, `lwin`, `lalt`, `space`, `ralt`, `fn`, `menu`, `rctrl`, стрелки, `num0`, `num.`.
Высокие клавиши нумпада (`num+`, `numenter`) отнесены к ряду, где они начинаются физически.
Пример: `paint --black --row1 red --row6 magenta`.
### `--black`
Начать с полностью чёрной таблицы: покрашены будут только перечисленные клавиши.
### `--keep`
Начать с текущего живого кадра (чтение 04 f5): все прочие клавиши сохраняют свои цвета.
Используется только вместе с `--key`.
Цвета читаются в отмасштабированном по яркости виде (максимум `ee`).
### `--brightness 1–15`
Яркость режима `0x80`.
По умолчанию `15`.
### `--no-save`
Не писать во флеш (см. `mode --no-save` в [COLOR-MODES.md](../COLOR-MODES.md)).
По умолчанию save выполняется.
Без `--all` и `--key` команда завершается ошибкой.
Команда пишет таблицу и сразу переключает подсветку в режим `0x80` (custom-таблица).
Имена клавиш и цвета описаны в [keys.md](keys.md) и [colors.md](colors.md).
+23
View File
@@ -0,0 +1,23 @@
# raw — произвольный payload
## Аргументы `raw`
### `hexstr`
Payload до 64 байт (пробелы допустимы).
Короче 64 — дополняется нулями, длиннее — обрезается.
Первые байты: `[0]` режим, `[1..3]` RGB, `[8]` flag, `[9]` яркость, `[10]` скорость, `[11]` подрежим, `[14..15]` = `aa 55`.
### `--no-save`
Не писать во флеш (см. `mode --no-save` в [COLOR-MODES.md](../COLOR-MODES.md)).
По умолчанию save выполняется.
```
./katana.py raw <64 байта hex> [--no-save]
```
Payload отправляется внутри штатной транзакции `begin → data → commit → save`.
Для экспериментов с неописанными байтами.
Формат payload'ов и назначение байтов — в [PROTOCOL.md](../PROTOCOL.md).
+130
View File
@@ -0,0 +1,130 @@
# remap — переназначение клавиш
Переназначает клавиши на кнопки мыши, функции текстового редактора, мультимедиа/веб-действия, эмуляцию горячих клавиш и макросы (канал 04 11, формат — в [PROTOCOL.md](../PROTOCOL.md)).
```
./katana.py remap --key caps=lmb # Caps → левая кнопка мыши
./katana.py remap --key caps=lmb --key esc=back # несколько за раз
./katana.py remap --key caps=default # вернуть стандартное действие
./katana.py remap --key fn=macro0 # Fn → макрос 0 (однократно)
./katana.py remap --key fn=macro0:5 # Fn → макрос 0 пять раз
./katana.py remap --key fn=macro0-toggle # Fn → макрос 0 до повторного нажатия
./katana.py remap --key caps=copy # Caps → копировать (Ctrl+C)
./katana.py remap --key menu=paste --key rctrl=undo # функции редактора
./katana.py remap --key fn=volup # Fn → громкость +
./katana.py remap --key esc=play --key lwin=calc # мультимедиа и калькулятор
./katana.py remap --key caps=ctrl+c # Caps → горячая клавиша Ctrl+C
./katana.py remap --key menu=meta+e # Menu → горячая клавиша Win+E
./katana.py remap --key rctrl=shift+b --key lalt=f1 # Shift+B и F1
./katana.py remap --clear # сбросить ВСЕ переназначения
```
## Аргументы `remap`
### `--key КЛЮЧ=ДЕЙСТВИЕ`
Переназначить одну клавишу.
Повторяется сколько нужно.
КЛЮЧ — те же имена, что в `paint --key` (имена из `keymap.py`, символы, синонимы, hex-индексы).
Действия перечислены ниже.
### Действия `--key`
**Мышь:**
| Имена | Кнопка |
| ------------------------- | ------------------ |
| `lmb`, `mouse1` | левая |
| `rmb`, `mouse2` | правая |
| `mmb`, `mouse3` | средняя |
| `back`, `mouseback` | назад (боковая) |
| `forward`, `mouseforward` | вперёд (боковая) |
**Шорткаты редактора:**
| Имя | Функция | Шорткат |
| ----------- | ------------ | ------- |
| `open` | Открыть | Ctrl+O |
| `new` | Создать | Ctrl+N |
| `undo` | Отмена | Ctrl+Z |
| `save` | Сохранить | Ctrl+S |
| `copy` | Копировать | Ctrl+C |
| `cut` | Вырезать | Ctrl+X |
| `paste` | Вставить | Ctrl+V |
| `find` | Найти | Ctrl+F |
| `selectall` | Выбрать всё | Ctrl+A |
**Мультимедиа и веб:**
| Имя | Функция |
| ------------------------------ | ------------------------ |
| `player` | Плеер |
| `play`, `playpause` | Воспроизведение/пауза |
| `stop` | Стоп |
| `prev`, `prevsong` | Предыдущая песня |
| `next`, `nextsong` | Следующая песня |
| `volup` | Громкость + |
| `voldown` | Громкость − |
| `mute` | Без звука |
| `home`, `homepage` | Домашняя страница |
| `refresh`, `webrefresh` | Веб: обновить |
| `webstop` | Веб: остановить |
| `webback` | Веб: назад |
| `webforward` | Веб: вперед |
| `favorites`, `webfavorites` | Веб: избранное |
| `websearch`, `search` | Веб: поиск |
| `mycomputer`, `computer` | Мой компьютер |
| `calculator`, `calc` | Калькулятор |
| `email` | Электронная почта |
**Горячие клавиши:** `MOD+КЛАВИША` — эмуляция шортката с модификаторами, модификаторы можно комбинировать через `+` (например `ctrl+shift+x`).
Без модификатора тоже работает: `a` — просто клавиша A.
Формат снят по дампу keybind-hotkeys; одиночные модификаторы и комбинации (`ctrl+shift+c`) проверены на железе.
| Модификатор (`MOD`) | Смысл |
| ----------------------- | ----------- |
| `ctrl` | Ctrl |
| `shift` | Shift |
| `alt` | Alt |
| `meta`, `win`, `super` | Meta (Win) |
| Клавиша | Смысл |
| ---------------------- | ---------------------------------- |
| `a`..`z` | буквы |
| `0`..`9` | цифры верхнего ряда |
| `f1`..`f12` | F-клавиши |
| `esc` | Esc |
| `tab` | Tab |
| `enter` | Enter |
| `space` | пробел |
| `caps` | Caps Lock |
| `backspace` | Backspace |
| `num0`..`num9` | цифры нумпада |
| `fn` | Fn (собственный код прошивки) |
Примеры: `ctrl+c` (копировать), `shift+b`, `alt+d`, `meta+e` (Win+E), `esc`, `f1`, `num1`, `fn`.
**Макросы:**
| Формат | Поведение |
| ------------------- | ------------------------------ |
| `macro<N>` | макрос N однократно |
| `macro<N>:K` | макрос N повторить K раз |
| `macro<N>-toggle` | макрос N до повторного нажатия |
**Стандартное действие:** `default`/`none`/`off`.
### `--clear`
Сбросить все переназначения: записывается таблица из одних default-записей.
Нельзя сочетать с `--key`.
### `--no-save`
Не писать во флеш (см. `mode --no-save` в [COLOR-MODES.md](../COLOR-MODES.md)).
**Важно:** каждый вызов перезаписывает ВСЮ таблицу переназначений (как вендорская утилита).
Переназначения, не указанные в текущем вызове `--key`, сбрасываются в default.
Команда чтения текущих переназначений неизвестна — учитывайте это при комбинировании.
Макросы, на которые можно ссылаться через `macro<N>`, записываются командой `macro` — см. [macro.md](macro.md).
+22
View File
@@ -0,0 +1,22 @@
# scan — визуальный перебор режимов
## Аргументы `scan`
| Аргумент | Значения | По умолчанию | Описание |
| -------------- | --------------- | ------------ | ---------------------- |
| `--from` | `1`–`19` | `1` | Первый режим перебора. |
| `--to` | `1`–`19` | `19` | Последний режим. |
| `--color` | hex или имя | `ff0000` | Цвет для всех режимов. |
| `--brightness` | `1`–`15` | `15` | Яркость. |
| `--speed` | `2`–`15` | `10` | Скорость. |
| `--delay` | секунды (float) | `2.0` | Пауза между режимами. |
```
katana.py scan --from 1 --to 19 --delay 2
```
Каждый режим отправляется с записью во флеш.
В конце печатается список принятых и отклонённых прошивкой режимов.
Полезно при реверсе: смотреть на клавиатуру и записывать, какой номер какой эффект показывает.
Сами режимы и их названия — в [COLOR-MODES.md](../COLOR-MODES.md).
+6
View File
@@ -0,0 +1,6 @@
# Если что-то пошло не так
- Команда отклоняется со статусом `00`/`ff` — сессия залипла.
Сначала повторить команду, затем `katana.py reset` (переподключение порта ~2–12 с, клавиатура не отваливается от системы).
- `reset` не помог — выключить/включить клавиатуру физически.
- Подробности и все известные грабли — в [PROTOCOL.md](../PROTOCOL.md) (раздел «Важные грабли»).
Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB