Initial commit
This commit is contained in:
@@ -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] — подрежим»).
|
||||
@@ -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) → «Следующие шаги».
|
||||
@@ -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` и перелогин.
|
||||
@@ -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, но не горят).
|
||||
- Пользователь различает цвета приблизительно: «розовый»=маджента, «жёлтый»=жёлтый/олива, «зелёный»=зелёный/тёмнозелёный.
|
||||
Для картирования использовать максимально контрастные цвета и мало точек за раз.
|
||||
@@ -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
|
||||
|
||||
После установки и запуска фирменной утилиты предоставьте машине доступ к клавиатуре.
|
||||
|
||||

|
||||
|
||||
Настройте общую папку, чтобы в неё сохранять дампы из виртуальной машины на хост.
|
||||
|
||||
## Как конвертировать 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)).
|
||||
@@ -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 (если установлен).
|
||||
@@ -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) | Что делать, если команда отклоняется или прошивка залипла. |
|
||||
@@ -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).
|
||||
@@ -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).
|
||||
@@ -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 с, клавиатура не отваливается от системы.
|
||||
@@ -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).
|
||||
@@ -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 — такие файлы понимает фирменная утилита.
|
||||
@@ -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).
|
||||
@@ -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).
|
||||
@@ -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).
|
||||
@@ -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).
|
||||
@@ -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 |
Reference in New Issue
Block a user