Поддержка MacOS (проверено в Tahoe)

This commit is contained in:
2026-09-06 17:13:34 +08:00
parent 57c4e80f0d
commit 4515b39090
24 changed files with 590 additions and 65 deletions
+3 -3
View File
@@ -2,7 +2,7 @@
19 встроенных режимов прошивки плюс выключение.
Номер режима = байт [0] lighting-payload, алиасы заданы в `katana.py` (`MODES`).
Полная таблица с байтами payload — в [PROTOCOL.md](PROTOCOL.md) (раздел «Lighting payload»).
Полная таблица с байтами payload — в [protocol.md](protocol.md) (раздел «Lighting payload»).
## Таблица режимов
@@ -31,7 +31,7 @@
| 19 | Шаттл | `shuttle` | моно/спектр | + | + | | бегущие строки по чётным/нечётным рядам в обе стороны |
| 20 | Выключена | `off` | | | | | все клавиши погашены |
¹ У breathing цвет из payload игнорируется прошивкой: цикл цвета зашит и гоняет зелёно-жёлто-красную гамму при любом `--color` (проверено на железе, payload совпадает с вендорским — подробности в [PROTOCOL.md](PROTOCOL.md)).
¹ У breathing цвет из payload игнорируется прошивкой: цикл цвета зашит и гоняет зелёно-жёлто-красную гамму при любом `--color` (проверено на железе, payload совпадает с вендорским — подробности в [protocol.md](protocol.md)).
Для моноцветного дыхания аналога нет; если нужен именно красный постоянный свет — используйте `static`.
## Примеры
@@ -99,4 +99,4 @@
Задаётся `--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] — подрежим»).
Подробности — [protocol.md](protocol.md) (раздел «Байт [11] — подрежим»).
+2 -2
View File
@@ -4,7 +4,7 @@
Модуль спроектирован как библиотека: класс `Katana` и вспомогательные функции импортируются в любой ваш скрипт одной строкой.
Документ описывает программный интерфейс, его ограничения и готовые приёмы.
Справка по CLI-командам — в [cli/README.md](cli/README.md), низкоуровневые детали протокола — в [PROTOCOL.md](PROTOCOL.md).
Справка по CLI-командам — в [cli/README.md](cli/README.md), низкоуровневые детали протокола — в [protocol.md](protocol.md).
## Что даёт per-key API
@@ -225,4 +225,4 @@ if __name__ == "__main__":
- визуализация музыки через любой FFT-вход: спектр по рядам клавиатуры;
- световой «миникарт»: подсветка зоны WASD в играх, где это уместно.
Список открытых направлений самого протокола (переназначение клавиш, байты направлений) — в [PROTOCOL.md](PROTOCOL.md) → «Следующие шаги».
Список открытых направлений самого протокола (переназначение клавиш, байты направлений) — в [protocol.md](protocol.md) → «Следующие шаги».
+25 -1
View File
@@ -7,7 +7,7 @@ description: Установка, udev-правило и решение проб
## Зависимости
Нужен Python 3.10+.
Зависимости: `pyusb` (для `reset`) и `pyyaml` (для `apply`); сам транспорт работает на голых `fcntl`-ioctl'ах к `/dev/hidraw*`:
Зависимости: `pyusb` (для `reset`) и `pyyaml` (для `apply`); сам транспорт работает на голых `fcntl`-ioctl'ах к `/dev/hidraw*` (на Linux) или через hidapi (на macOS, см. ниже):
```
python3 -m venv .venv
@@ -54,3 +54,27 @@ ID `0c45:8006` принадлежит чипу Sonix SN32, который про
Переподключите клавиатуру.
Если пользователь не в группе `plugdev` — `sudo usermod -aG plugdev $USER` и перелогин.
## Установка на macOS
Экспериментальная поддержка: транспорт работает через IOKit напрямую (ctypes),
сторонние HID-библиотеки не нужны, udev-правило не нужно.
```
python3 -m venv .venv
.venv/bin/pip install pyusb pyyaml
```
macOS выдаёт доступ к HID-клавиатурам вручную:
**Системные настройки → Конфиденциальность и безопасность → «Input Monitoring»** —
добавьте приложение, из которого запускается `katana.py` (Terminal, iTerm2, VS Code),
включите его и **перезапустите приложение** (разрешение подхватывается только новым процессом).
Без разрешения `katana.py` выведет подсказку об этом.
Важно: утилиты, перехватывающие клавиатуры (Karabiner-Elements и подобные),
открывают их в монопольном режиме — пока Karabiner работает, открыть устройство нельзя
(ошибка `kIOReturnExclusiveAccess`). Выйдите из Karabiner на время настройки
или исключите ARDOR_Katana в его настройках (вкладка Devices).
Проверить, кто мешает, можно диагностикой `misc/iokit_probe.py` (см. [scripts.md](scripts.md)).
Транспорт выбирается автоматически: на macOS — IOKit, на Linux — hidraw-ioctl.
+26 -2
View File
@@ -18,6 +18,30 @@ Feature-репорты через hidraw ioctl (`HIDIOCSFEATURE`/`HIDIOCGFEATURE
**usbhid не отцепляется** — печать никогда не прерывается.
pyusb-вариант НЕ использовать (отцеплял драйвер).
### macOS (экспериментально, класс `KatanaMacOS`)
Тот же протокол поверх IOKit напрямую (ctypes, без сторонних библиотек):
`IOHIDDeviceSetReport` / `IOHIDDeviceGetReport` с `kIOHIDReportTypeFeature` —
семантика 1:1 с hidraw, feature-репорты rid=0, 64 байта данных.
Устройство ищется через `IOServiceGetMatchingServices("IOHIDDevice")` + `IOHIDDeviceGetProperty`:
выбирается клавиатура 0C45:8006 с PrimaryUsagePage=1, PrimaryUsage=6 (boot keyboard = интерфейс 0).
Выбор транспорта автоматический по `sys.platform` (`open_katana()`): darwin → IOKit, остальное → hidraw.
Грабли macOS (все проверены на железе):
- у IOKit своя нумерация типов репортов: Input=0, Output=1, **Feature=2**;
с Output прошивка отвечает мусором (1 байт `04`);
- `IOServiceMatching` возвращает CFDictionaryRef — без явного `restype = c_void_p`
ctypes обрезает указатель и процесс падает segfault'ом;
- `IOHIDDeviceGetProperty` принимает IOHIDDeviceRef (от `IOHIDDeviceCreate`),
а не registry entry — с entry процесс падает segfault'ом;
плоских `idVendor` в свойствах реестра нет — только через GetProperty;
- доступ к HID-клавиатурам выдаётся вручную: Системные настройки → Конфиденциальность и безопасность → «Input Monitoring» для приложения-терминала, затем перезапуск терминала;
- Karabiner-Elements (и подобные утилиты) захватывает клавиатуры монопольно — пока он работает, `IOHIDDeviceOpen` возвращает `kIOReturnExclusiveAccess` (0xE00002C5); проверено диагностикой `misc/iokit_probe.py`;
- `reset` (pyusb) на macOS работает (проверено: USB port reset проходит);
- udev-правило не нужно.
Проверка на железе (macOS, Karabiner выключен): mode/paint/keys/remap/macro/reset — работают.
## Общая транзакция (все команды)
```
@@ -65,7 +89,7 @@ CLI: `--rainbow`, `--direction north-south|south-north|east-west|west-east`.
- Яркость масштабирует per-key цвета: 15/15 → `ee` (238), 1/15 → `0f`.
- Режим 0x80 отображает таблицу per-key (см. ниже) — это и есть «кастом».
### Таблица режимов (описания вендорской утилиты, docs/COLOR-MODES.md)
### Таблица режимов (описания вендорской утилиты, docs/color-modes.md)
Номер = байт [0] payload.
«моно/спектр» — режим рисует одиночный цвет или полный спектр независимо от него.
@@ -535,7 +559,7 @@ ACTION: мышь (`lmb`/`mouse1`, `rmb`/`mouse2`, `mmb`/`mouse3`, `back`/`mouseb
Шорткаты редактора (тип `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 кадр/с.
5. ~~Демо-скрипты (радуга, волна) поверх per-key API + живое чтение f5~~ — ЗАВЕРШЕНО, методика описана и проверена ([extending.md](extending.md)): таблица обновляется живьём в режиме 0x80, ~1 кадр/с.
6. ~~Макросы: запись содержимого и привязка~~ — ЗАВЕРШЕНО (канал 04 19 + записи `[06, ...]` в 04 11, команда `macro`, см. «Макросы»).
Осталось: чтение содержимого, коллизия кодов 05/06, стрелки Up/Down, остальные медиа-коды.
+4 -4
View File
@@ -1,6 +1,6 @@
# Дампы GANSS ARDOR_Katana (katana-v1)
Сырые данные, на которых построен реверс протокола (см. [PROTOCOL.md](PROTOCOL.md)).
Сырые данные, на которых построен реверс протокола (см. [protocol.md](protocol.md)).
Устройство: клавиатура GANSS ARDOR_Katana, USB `0C45:8006` (Sonix SN32).
## Состав
@@ -56,7 +56,7 @@
На Linux, из корня репозитория:
```
python3 analyze_pcap.py raw-data/katana-v1/color-modes.pcapng raw-data/katana-v1/color-modes.plain.txt
./misc/analyze_pcap.py raw-data/katana-v1/color-modes.pcapng raw-data/katana-v1/color-modes.plain.txt
```
Формат строки лога:
@@ -82,9 +82,9 @@ usb-devices | grep -B 2 -A 8 'Vendor=0c45' > usb-devices-output.txt
Конфигурационный канал — feature-репорты интерфейса 0 (эндпоинты управления, не interrupt).
В `lsusb` устройство подписывается «Microdia Dual Mode Camera (8006 VGA)» — это норма: ID `0c45:8006` чипа Sonix SN32 используется и вебкамерами, и клавиатурами, а база `usb.ids` знает за ним только камеру.
Подробнее — в [INSTALL.md](INSTALL.md) → «Проверка устройства».
Подробнее — в [install.md](install.md) → «Проверка устройства».
## Замечания
- Имена файлов оригинальные, включая опечатку `color-pesets.pcapng` (содержимое соответствует color-presets).
- Расшифровка протокола по этим дампам — в [PROTOCOL.md](PROTOCOL.md), парсер — `analyze_pcap.py`, рабочая утилита — `katana.py` (обзор — в [SCRIPTS.md](SCRIPTS.md)).
- Расшифровка протокола по этим дампам — в [protocol.md](protocol.md), парсер — `analyze_pcap.py`, рабочая утилита — `katana.py` (обзор — в [scripts.md](scripts.md)).
+28 -10
View File
@@ -1,18 +1,20 @@
# Скрипты репозитория
Состав репозитория и назначение каждого скрипта.
Использование `katana.py` как библиотеки (свои скрипты и анимации) — в [EXTENDING.md](EXTENDING.md).
Использование `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
├── katana.yaml.example Пример YAML-конфига для команды apply
├── katana.py Основная CLI-утилита управления подсветкой
├── misc/
│ ├── keymap.py Карта «LED-индекс → физическая клавиша» (104 клавиши)
│ ├── analyze_pcap.py Парсер USBPcap-захватов → лог control-трансферов
│ ├── probe.py Исследовательский зонд: чтение feature-репортов
│ └── iokit_probe.py Диагностика открытия HID на macOS (код IOReturn)
├── tests/ Офлайн-тесты (без железа)
├── docs/ Документация (см. README.md)
└── raw-data/
@@ -29,7 +31,7 @@
```
Печатает подтверждённую карту, список слепых слотов (39 шт — резерв прошивки, ни к какому LED не подключены), непроидентифицированные индексы и таблицу алиасов клавиш (`KEY_SYMBOL_ALIASES`).
Методика картирования и открытые вопросы — в [PROTOCOL.md](PROTOCOL.md) (раздел «Карта клавиш»).
Методика картирования и открытые вопросы — в [protocol.md](protocol.md) (раздел «Карта клавиш»).
## analyze_pcap.py
@@ -41,19 +43,34 @@
```
Без второго аргумента пишет `/tmp/tx_log.txt`.
Формат строк и методика снятия захватов — в [RAW-DATA.md](RAW-DATA.md).
Формат строк и методика снятия захватов — в [raw-data.md](raw-data.md).
## probe.py
## misc/probe.py
Исследовательский зонд времён начала реверса: перебирает report id и читает feature-репорты (только GET, состояние клавиатуры не меняет).
Полезен как минимальный пример hidraw-транспорта:
```
./probe.py [hidrawN]
./misc/probe.py [hidrawN]
```
Без аргумента находит все hidraw-узлы клавиатуры сам.
## misc/iokit_probe.py
Диагностика macOS-only: открывает HID-сервис клавиатуры через IOKit напрямую
(ctypes, сторонних библиотек не нужно) и печатает точный код `IOReturn` от
`IOHIDDeviceOpen`. Полезен, когда katana.py сообщает только «open failed»:
```
.venv/bin/python misc/iokit_probe.py
```
Интерпретация результата: `0x00000000` — права есть (проблема в софте),
`0xE00002C1` — нет разрешения «Input Monitoring»,
`0xE00002C5` (`kIOReturnExclusiveAccess`) — устройство захвачено монопольно
(типичный случай — Karabiner-Elements).
## tests/
Офлайн-тесты (железо не нужно):
@@ -63,6 +80,7 @@ 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 на подменном устройстве
python3 tests/test_transport.py # выбор транспорта Linux/macOS, IOKit-обмен
```
`test_macro.py` — блоб, собранный из вендорских XML, сверяется побайтово с дампом macros-create, плюс разбор токенов, round-trip XML, hotkey/remap-действия и сверка с дампами keybind-editor/keybind-hotkeys/keybind-multimedia.
+3 -3
View File
@@ -2,10 +2,10 @@
Справочник команд и аргументов.
Все команды идут через транзакцию `begin → data → commit → save` и безопасны: печать не прерывается, прошивка остаётся живой.
Исключение — `macro set`/`macro clear`: вендор после записи макросов save не делает (подробности в [PROTOCOL.md](../PROTOCOL.md)).
Низкоуровневое описание транзакций — в [PROTOCOL.md](../PROTOCOL.md).
Исключение — `macro set`/`macro clear`: вендор после записи макросов save не делает (подробности в [protocol.md](../protocol.md)).
Низкоуровневое описание транзакций — в [protocol.md](../protocol.md).
Режимы подсветки и их аргументы вынесены в отдельный документ: [COLOR-MODES.md](../COLOR-MODES.md).
Режимы подсветки и их аргументы вынесены в отдельный документ: [color-modes.md](../color-modes.md).
## Состав справочника
+2 -2
View File
@@ -8,7 +8,7 @@
./katana.py apply katana.yaml.example # применить пример из репозитория
```
Зависимость: PyYAML (`pip install pyyaml`, см. [INSTALL.md](../INSTALL.md)).
Зависимость: PyYAML (`pip install pyyaml`, см. [install.md](../install.md)).
## Порядок применения и сохранение
@@ -72,7 +72,7 @@ paint:
brightness: 15
```
### `lighting` — режим подсветки (см. [COLOR-MODES.md](../COLOR-MODES.md))
### `lighting` — режим подсветки (см. [color-modes.md](../color-modes.md))
`mode` — имя или номер 1..19, а также `off` и `default` (применяются как команды `off`/`default`).
+1 -1
View File
@@ -1,7 +1,7 @@
# macro — макросы
Записывает содержимое макросов в прошивку (канал 04 19) и работает с вендорским XML.
Формат протокола — в [PROTOCOL.md](../PROTOCOL.md).
Формат протокола — в [protocol.md](../protocol.md).
Макрос нужно привязать к клавише через `remap --key КЛЮЧ=macro<N>` (индексация 0-based: «Макрос 1» вендорской утилиты = 0).
+1 -1
View File
@@ -91,7 +91,7 @@ Shorthand для `--key`: покрасить горизонтальный ряд
### `--no-save`
Не писать во флеш (см. `mode --no-save` в [COLOR-MODES.md](../COLOR-MODES.md)).
Не писать во флеш (см. `mode --no-save` в [color-modes.md](../color-modes.md)).
По умолчанию save выполняется.
Без `--all` и `--key` команда завершается ошибкой.
+2 -2
View File
@@ -10,7 +10,7 @@ Payload до 64 байт (пробелы допустимы).
### `--no-save`
Не писать во флеш (см. `mode --no-save` в [COLOR-MODES.md](../COLOR-MODES.md)).
Не писать во флеш (см. `mode --no-save` в [color-modes.md](../color-modes.md)).
По умолчанию save выполняется.
```
@@ -20,4 +20,4 @@ Payload до 64 байт (пробелы допустимы).
Payload отправляется внутри штатной транзакции `begin → data → commit → save`.
Для экспериментов с неописанными байтами.
Формат payload'ов и назначение байтов — в [PROTOCOL.md](../PROTOCOL.md).
Формат payload'ов и назначение байтов — в [protocol.md](../protocol.md).
+2 -2
View File
@@ -1,6 +1,6 @@
# remap — переназначение клавиш
Переназначает клавиши на кнопки мыши, функции текстового редактора, мультимедиа/веб-действия, эмуляцию горячих клавиш и макросы (канал 04 11, формат — в [PROTOCOL.md](../PROTOCOL.md)).
Переназначает клавиши на кнопки мыши, функции текстового редактора, мультимедиа/веб-действия, эмуляцию горячих клавиш и макросы (канал 04 11, формат — в [protocol.md](../protocol.md)).
```
./katana.py remap --key caps=lmb # Caps → левая кнопка мыши
@@ -121,7 +121,7 @@
### `--no-save`
Не писать во флеш (см. `mode --no-save` в [COLOR-MODES.md](../COLOR-MODES.md)).
Не писать во флеш (см. `mode --no-save` в [color-modes.md](../color-modes.md)).
**Важно:** каждый вызов перезаписывает ВСЮ таблицу переназначений (как вендорская утилита).
Переназначения, не указанные в текущем вызове `--key`, сбрасываются в default.
+1 -1
View File
@@ -19,4 +19,4 @@ katana.py scan --from 1 --to 19 --delay 2
В конце печатается список принятых и отклонённых прошивкой режимов.
Полезно при реверсе: смотреть на клавиатуру и записывать, какой номер какой эффект показывает.
Сами режимы и их названия — в [COLOR-MODES.md](../COLOR-MODES.md).
Сами режимы и их названия — в [color-modes.md](../color-modes.md).
+1 -1
View File
@@ -3,4 +3,4 @@
- Команда отклоняется со статусом `00`/`ff` — сессия залипла.
Сначала повторить команду, затем `katana.py reset` (переподключение порта ~2–12 с, клавиатура не отваливается от системы).
- `reset` не помог — выключить/включить клавиатуру физически.
- Подробности и все известные грабли — в [PROTOCOL.md](../PROTOCOL.md) (раздел «Важные грабли»).
- Подробности и все известные грабли — в [protocol.md](../protocol.md) (раздел «Важные грабли»).