|
|
|
|
@ -1,141 +0,0 @@
|
|
|
|
|
#+TITLE: Keyboard Controller — план реализации
|
|
|
|
|
|
|
|
|
|
План для приложения из readme.org: HID-контроллер (клавиатура, мышь,
|
|
|
|
|
тачпад) поверх SuperCollider, управление Ndef/Tdef, минимальный
|
|
|
|
|
визуальный фидбек. Целевая платформа — Linux, ноутбуки ThinkPad.
|
|
|
|
|
|
|
|
|
|
* Решения (зафиксированы из questions.org)
|
|
|
|
|
|
|
|
|
|
- Приоритет устройств: клавиатура + тачпад. TrackPoint не приоритет.
|
|
|
|
|
- Кнопки мыши/тачпада: минимум две, по возможности захватить максимум.
|
|
|
|
|
- Оси тачпада: для начала абсолютные.
|
|
|
|
|
- Скетч самодостаточный — демо-Ndef внутри, не тянет готовые
|
|
|
|
|
NodeDictionary-инструменты.
|
|
|
|
|
- Отдельный инструмент, но будет применён в перформансе
|
|
|
|
|
(24_09_2026_gig).
|
|
|
|
|
- Минимальный набор действий достаточен: toggle / inc / dec /
|
|
|
|
|
play/stop / free.
|
|
|
|
|
- «Держать-пока-нажата» (gate) — требование, KeyUp обязателен.
|
|
|
|
|
- Фидбек: GUI-окно с текстовым содержимым (не пост-окно).
|
|
|
|
|
- Форма: несколько файлов с одной точкой входа.
|
|
|
|
|
|
|
|
|
|
* Принцип
|
|
|
|
|
|
|
|
|
|
Не «демо», а рабочий шаблон-каркас: одна точка входа, декларативная
|
|
|
|
|
привязка HID-событий к действиям, слои разделены. Основа — HIDdef
|
|
|
|
|
(аналог MIDIdef) плюс словари привязок. Всё состояние — в глобалах
|
|
|
|
|
~ (прокси-пространстве), чтобы быстро править из REPL.
|
|
|
|
|
|
|
|
|
|
* Этапы
|
|
|
|
|
|
|
|
|
|
** 1. Доступ к HID-устройствам из-под Linux
|
|
|
|
|
Основная и часто незаметная проблема: sclang без привилегий не видит
|
|
|
|
|
/dev/hidraw*. Нужно решить ДО кода:
|
|
|
|
|
- проверить, что устройства видны: ~HID.findAvailable~ и
|
|
|
|
|
~HID.postAvailable~ из REPL;
|
|
|
|
|
- если пусто — udev-правило, разрешающее чтение hidraw для нужной
|
|
|
|
|
группы (или запуск от рута для прототипа);
|
|
|
|
|
- зафиксировать точные ID устройств (vendor/product) ThinkPad, чтобы
|
|
|
|
|
не открывать «всё подряд».
|
|
|
|
|
|
|
|
|
|
** 2. Слой открытия устройств
|
|
|
|
|
- Сканирование ~HID.findAvailable~;
|
|
|
|
|
- выбор целевого устройства по vendor/product, а не по индексу;
|
|
|
|
|
- ~HID.open(id)~ → держим объект устройства в ~~device~;
|
|
|
|
|
- graceful-fallback: если устройства нет, скетч не падает, а печатает
|
|
|
|
|
предупреждение и ждёт.
|
|
|
|
|
|
|
|
|
|
** 3. Слой привязок (словарь обработчиков)
|
|
|
|
|
Декларативная таблица: ключ → действие. Значение — либо event-словарь
|
|
|
|
|
(структурированное действие над Ndef/Tdef), либо напрямую функция
|
|
|
|
|
(произвольный обработчик). Примерная форма:
|
|
|
|
|
|
|
|
|
|
#+begin_src sclang
|
|
|
|
|
~bindings = IdentityDictionary[
|
|
|
|
|
// клавиша -> Ndef-цель + параметр (event-словарь)
|
|
|
|
|
\q -> (type: \toggle, ndef: \d, param: \gate),
|
|
|
|
|
\w -> (type: \inc, ndef: \d, param: \freq, step: 10),
|
|
|
|
|
\e -> (type: \dec, ndef: \d, param: \freq, step: 10),
|
|
|
|
|
\r -> (type: \playTdef, tdef: \loop),
|
|
|
|
|
// клавиша -> произвольная функция (просто выполняется)
|
|
|
|
|
\space -> { "space hit".postln; ~something.value },
|
|
|
|
|
];
|
|
|
|
|
#+end_src
|
|
|
|
|
|
|
|
|
|
Разделяем сами обработчики (механику) и карту привязок (настройку),
|
|
|
|
|
чтобы менять раскладку не трогая логику. Диспетчер действия различает
|
|
|
|
|
значение по типу: `isFunction` → вызвать напрямую; иначе — разобрать
|
|
|
|
|
по `type` (event-словарь). Это даёт «сырой» побег: можно вешать на
|
|
|
|
|
клавишу любую функцию без добавления нового типа действия.
|
|
|
|
|
|
|
|
|
|
** 4. HIDdef: KeyDown / KeyUp
|
|
|
|
|
- клавиатура: value == 1 (нажатие) / value == 0 (отпускание);
|
|
|
|
|
- поддержка обеих фаз — это требование из readme (KeyUp нужен,
|
|
|
|
|
например, для gate=0 у нот / для «держать-пока-нажата»);
|
|
|
|
|
- HIDdef c фильтром по usagePage/usage клавиатуры.
|
|
|
|
|
|
|
|
|
|
** 5. Мышь / тачпад
|
|
|
|
|
- кнопки мыши/тачпада — как клавиши (нажатие/отпускание);
|
|
|
|
|
- движение тачпада: оси X/Y (Generic Desktop usage 0x30/0x31),
|
|
|
|
|
маппинг на параметры (например, pan, freq, амплитуда);
|
|
|
|
|
- прочие события тачпада (wheel, multitouch) — опционально, по
|
|
|
|
|
наличию в device.elements конкретного устройства.
|
|
|
|
|
|
|
|
|
|
** 6. Действия над Ndef/Tdef (плюс «сырые» функции)
|
|
|
|
|
Типы действий из карты привязок (event-словари):
|
|
|
|
|
- toggle параметра (gate, bypass);
|
|
|
|
|
- inc/dec значения параметра с шагом и clamp по ControlSpec;
|
|
|
|
|
- play/stop Tdef;
|
|
|
|
|
- free Ndef;
|
|
|
|
|
- переключение пресетов.
|
|
|
|
|
Используем ~Ndef(<name>).set(...)~ и ~Tdef(<name>).play/stop~.
|
|
|
|
|
|
|
|
|
|
Помимо структурированных действий, значение привязки может быть
|
|
|
|
|
произвольной Function — диспетчер её просто вызывает (`~action.value`).
|
|
|
|
|
Это «побег» для любых обработчиков, не влезающих в типы выше: запуск
|
|
|
|
|
отдельных функций, посыл OSC, манипуляции с ~env, что угодно. Разбор
|
|
|
|
|
в диспетчере: `if (action.isFunction) { action.value } { ~dispatch[action.type].(action) }`.
|
|
|
|
|
|
|
|
|
|
** 7. Минимальный визуальный фидбек
|
|
|
|
|
GUI-окно с текстовым содержимым (Window + StaticText): одна строка =
|
|
|
|
|
один активный Ndef/Tdef и его текущие параметры; подсветка изменённого
|
|
|
|
|
параметра. Без полноценных слайдеров — только текстовый фидбек
|
|
|
|
|
состояния.
|
|
|
|
|
|
|
|
|
|
** 8. Структура файлов (внутри keyboard-controller/)
|
|
|
|
|
#+begin_src text
|
|
|
|
|
readme.org — описание (уже есть)
|
|
|
|
|
plan.org — этот план
|
|
|
|
|
controller.scd — точка входа, скелет скетча
|
|
|
|
|
bindings.scd — карта привязок (словарь)
|
|
|
|
|
actions.scd — реализация действий (toggle/inc/dec/...)
|
|
|
|
|
#+end_src
|
|
|
|
|
|
|
|
|
|
Либо всё в одном .scd на старте — разделить позже, когда вырастет.
|
|
|
|
|
|
|
|
|
|
* Порядок работ
|
|
|
|
|
1. Поднять доступ к HID (udev), подтвердить видимость устройств.
|
|
|
|
|
2. Минимальный скетч: открыть устройство, повесить один HIDdef на
|
|
|
|
|
одну клавишу, печатать нажатия.
|
|
|
|
|
3. Добавить карту привязок + действия toggle/inc/dec.
|
|
|
|
|
4. Подключить Ndef (например, из NodeDictionary) как управляемую цель.
|
|
|
|
|
5. Добавить KeyUp-семантику (gate / держать-пока-нажата).
|
|
|
|
|
6. Добавить оси тачпада и кнопки мыши.
|
|
|
|
|
7. Визуальный фидбек.
|
|
|
|
|
8. Отполировать fallback-пути (устройство отвалилось, нет HID).
|
|
|
|
|
|
|
|
|
|
* Риски / на что смотреть
|
|
|
|
|
- TrackPoint на ThinkPad часто НЕ HID-тачпад, а PS/2-мышь через evdev —
|
|
|
|
|
его HID-слой может не видеть. По решениям — не приоритет, можно
|
|
|
|
|
не покрывать.
|
|
|
|
|
- Имена классов: в SC это HIDdef / HIDFunc (строчная d), HIDDeviceService,
|
|
|
|
|
GeneralHID. В readme написано «HIDDef» — сверять с документацией
|
|
|
|
|
конкретной версии SC 3.14.
|
|
|
|
|
- usagePage/usage клавиш могут отличаться от ожидаемых — печатать
|
|
|
|
|
сырые event-поля при отладке (page, usage, value) прежде чем
|
|
|
|
|
зашивать их в привязки.
|
|
|
|
|
- Несколько одинаковых устройств (внешняя клавиатура + встроенная) —
|
|
|
|
|
отличать по vendor/product/id, не по индексу списка.
|
|
|
|
|
- Абсолютные оси тачпада на разных устройствах дают разные диапазоны —
|
|
|
|
|
нормировать (делить на логический максимум) прежде чем маппить на
|
|
|
|
|
ControlSpec параметра.
|