[2026-09-15] eagle: personal/tech/karabiner-keyboard-config.md

This commit is contained in:
Alexey Martemyanov
2026-09-15 13:04:08 +06:00
parent 48c9c72b58
commit 6f32e314a6
+88 -1
View File
@@ -8,6 +8,7 @@ tags:
- input-sources
- russian-layout
- caps-lock
- devices-remap
created: 2026-09-15T00:00:00.000Z
updated: 2026-09-15T00:00:00.000Z
---
@@ -43,6 +44,88 @@ updated: 2026-09-15T00:00:00.000Z
Откат выполнен: живой конфиг = `~/Documents/karabiner.json.bak.20260915`, md5 `2ad1f7e1c8c8807739b636cc0650a527`, права `644`. Правило `#13` группы `#7` — в исходном виде (`to` = `7`+`right_shift`, `from.mandatory` = `["option","shift"]`). **Задача Caps-фикса НЕ решена.**
## 🔴🔴 ГЛАВНАЯ НАХОДКА: `right_control` ремапнут в `devices[].simple_modifications`
**Дата:** 2026-09-15 (вторая сессия). **Запрос Alex:** «почему сломались комбинации переключения аппов (`right_control+…`)?»
### Симптом
`right_control+x` вместо запуска Xcode печатает **`≈`**. Аналогично ломаются все остальные app-комбо.
### ✅ ДИАГНОЗ (подтверждён фактом из конфига)
**Физическая правая Control НЕ приходит в систему как `right_control`.** Она ремапится на уровне устройства. В `profiles[0].devices[].simple_modifications` живого конфига (версия 155 937 байт) прописано:
```json
{ "from": { "key_code": "right_control" }, "to": [{ "key_code": "right_option" }] },
{ "from": { "key_code": "right_option" }, "to": [{ "key_code": "right_command" }] }
```
Присутствует у **всех трёх** клавиатур в `devices[]` (vid 1204/pid 257, vid 1133/pid 49948, vid 1267/pid 259).
**Следствие:** Karabiner видит нажатие как `right_option`. Все **43** манипулятора группы `#0 Launch Apps HotKeys` ждут в `from.modifiers.mandatory` ровно `right_control`. Такого нажатия не приходит **никогда** → правило не матчится → нажатие уходит в систему напрямую → RussianWin отдаёт свой стандартный символ на `opt+x`, а это `≈`.
**Механизм идентичен случаю с `Ї`** (см. раздел про Caps Lock): «сырой» символ раскладки = признак того, что Karabiner пропустил нажатие. Не вывод `to`, а провал матча `from`.
### Почему это вылезло именно после отката
| Версия конфига | Размер | Секция `devices[]` | Комбо `right_control+…` |
|---|---|---|---|
| `karabiner.json.new` (текущая рабочая, md5 `4f643933…`) | 96 877 | **ремапа `right_control→right_option` НЕТ** | **работают** |
| `karabiner.json.bak.20260915` (откат, md5 `2ad1f7e1…`) | 155 937 | ремап есть | **мертвы** |
Разница в 59 KB — это в основном старая обвязка в `devices[].simple_modifications` (включая `application→right_control`, `left_command↔left_option`, consumer-keys на F7F12).
### Ошибки агента в этой сессии — НЕ повторять
| Что было сделано | Вывод |
|---|---|
| Откат на `.bak.20260915` **без предварительного diff** `devices[]` | Снёс рабочую обвязку и убил 43 app-комбо. Откат «на бэкап» ≠ откат к рабочему состоянию: бэкап может быть старше по структуре, а не только по правкам |
| Поиск причины в `complex_modifications` (правила `r0 m7`/`m8`, `device_if`) | Правила были целы и идентичны. Причина лежала в **другой секции** конфига — `devices[].simple_modifications`. При «правило не срабатывает» проверять **обе** секции |
| Гипотеза «Karabiner потерял Input Monitoring» / «не та клавиатура» | Мимо. Процессы Karabiner живы, конфиг валиден. Причина — ремап внутри самого конфига |
| Просьба к Alex самому нажать комбо для проверки | **Алекс это отверг** — задачу решать агенту, не перекладывать проверку на пользователя. Скрейпить факты из файлов, а не спрашивать |
### 🔎 Ключевая диагностическая процедура: «правило есть, но не срабатывает»
1. Проверить, что **сам `from`-модификатор вообще доходит** до Karabiner. Искать его в `devices[].simple_modifications`:
```bash
/usr/bin/jq -r '.profiles[0].devices[].simple_modifications[] | "\(.from.key_code) -> \(.to[0].key_code)"' ~/.config/karabiner/karabiner.json
```
**Если нужный модификатор там переназначен — все правила на него мертвы.** Это первое, что надо смотреть, а не содержимое `complex_modifications`.
2. Сверить число правил на целевой модификатор: `/usr/bin/jq '[.profiles[0].complex_modifications.rules[].manipulators[] | select((.from.modifiers.mandatory // []) | index("right_control"))] | length'`
3. Только после этого смотреть `device_if`-условия и `to`.
### ⚠️ Что НЕ является причиной
- «`to` содержит `shell_command`, значит не может печатать символы» — **верно технически, но это следствие, не причина.** `shell_command` просто не даёт вывода в раскладку; `` приходит из системы, потому что матч провалился. Не путать: сам факт `shell_command` не ломает запуск приложения.
- Отсутствие `optional: caps_lock` — к `right_control`-комбо отношения не имеет.
- Права 644 / md5 канона и живого — были в порядке, конфиг не сбрасывался.
### Пути решения (обсуждались, ждут выбора Alex)
**Вариант A — вернуть `.new` (текущее рабочее состояние, ремапа нет):**
```bash
cp ~/Documents/karabiner.json.new ~/Documents/karabiner.json
cp ~/Documents/karabiner.json ~/.config/karabiner/karabiner.json
chmod 644 ~/.config/karabiner/karabiner.json
```
Плюс: app-комбо оживают, правило `#13` в исходном виде. Минус: теряется старая обвязка `application→right_control`, `left_command↔left_option`, consumer-keys на F7F12 (нужно проверить, пользуется ли Alex ими).
**Вариант B — оставить обвязку и переписать комбо:** заменить `right_control` → `right_option` в `from.modifiers.mandatory` у 43 манипуляторов группы `#0`. Риск: `right_option` уже занят под ремап `right_option→right_command`, и в той же `devices[]`-секции может возникнуть конфликт; перед правкой проверить diff по всем 43 путям.
**Статус: НЕ применено. Ждёт команды Alex.**
### Файловое состояние на конец второй сессии
| Файл | md5 | Размер | Роль |
|---|---|---|---|
| `~/Documents/karabiner.json` | `2ad1f7e1c8c8807739b636cc0650a527` | 155 937 | канон (откаченный, app-комбо мертвы) |
| `~/.config/karabiner/karabiner.json` | `2ad1f7e1c8c8807739b636cc0650a527` | 155 937, права **644** | живой = канон |
| `~/Documents/karabiner.json.new` | `4f643933f9565330fd2111973c865563` | 96 877 | **рабочая версия, app-комбо живы** |
| `~/Documents/karabiner.json.bak.20260915` | `2ad1f7e1c8c8807739b636cc0650a527` | 155 937 | бэкап, на который откатились |
| `~/Documents/karabiner.json.bak.20260915.keep` | `2ad1f7e1c8c8807739b636cc0650a527` | 155 937 | страховочная копия бэкапа |
| `~/Documents/karabiner.json.bak` | `44ca420798be5ab38ff3c1d54c1c6fb9` | 153 847, Jun 15 | старый бэкап |
## Структура профиля (на 2026-09-15)
Один профиль: `Default profile`, `selected=true`. `simple_modifications` — пустой (0). Все правила — в `complex_modifications.rules[]`.
@@ -228,11 +311,15 @@ Alex в изначальном запросе назвал комбинацию
## Pitfalls
- **🔴 ПЕРВЫМ ДЕЛОМ ПРОВЕРЯТЬ `devices[].simple_modifications`.** Если нужный `from`-модификатор там переназначен (в этой системе `right_control → right_option`), то **все** правила на него в `complex_modifications` мертвы, сколько бы их ни было. Симптом: вместо действия печатается «сырой» символ раскладки (`opt+x` → ``). Правило «не срабатывает» ≠ ошибка в правиле; проверять **обе** секции конфига, а не только `complex_modifications`.
- **Откат «на бэкап» ≠ откат к рабочему состоянию.** Перед откатом делать `diff` по структуре (`devices[]`, число правил, размер), а не только по целевой правке. `.bak.20260915` (155 937) структурно старше и содержит ремап, которого нет в рабочей версии (96 877) — откат на него убил 43 app-комбо. Хранить рабочие снимки как `.new` до подтверждения, что откат вернул работоспособность.
- **Не перекладывать проверку на Alex.** Просьба «нажми комбо и скажи, что произошло» была отвергнута. Задачу решает агент: факты вытаскивать из файлов конфига, логов и процессов, а не спрашивать пользователя.
- **Права 600 → молчаливый сброс конфига.** `cp` сохраняет режим ИСТОЧНИКА, а не целевого файла. После каждого `cp` в `~/.config/karabiner/karabiner.json` → `chmod 644`. Симптомы сброса: Karabiner спрашивает про тип виртуальной клавиатуры, все complex_modifications исчезли.
- **Правила без явного условия Caps Lock.** Каждый манипулятор, чей `from` содержит `shift`, при активном Caps Lock **может перестать матчиться вообще** — нажатие уходит в систему и раскладка отдаёт свой стандартный символ (для `opt+shift+/` в RussianWin это `Ї`). Лечится добавлением `"optional": ["caps_lock"]` в `from.modifiers`, не трогая `mandatory`.
- **Не переводить `shift` из `mandatory` в `optional`.** Если shift — часть combo (как в `opt+shift+/`), это расширит правило на более короткое сочетание (`opt+/`) и сломает соседнее правило.
- **Не менять модификатор в `to` вслепую.** RussianWin **не является** аналогом US-раскладки: `opt+7` там = `&`, а не `?`. Замена `right_shift` → `right_option` в `to` даёт мусорный символ. Сначала проверить, что реально лежит на позиции в раскладке.
- **Не править конфиг без подтверждённого диагноза.** Определить, ломается ли матч `from` или инвертируется выход `to` — можно только фактом (EventViewer или прямой ответ пользователя). Гадание между `from` и `to` в этой сессии привело к порче раскладки и откату.
- **Не править конфиг без подтверждённого диагноза.** Определить, ломается ли матч `from` или инвертируется выход `to` — можно только фактом (EventViewer / прямой ответ пользователя). Гадание между `from` и `to` в первой сессии привело к порче раскладки и откату.
- **Не мешать кириллицу с ASCII в shell-командах.** Поиск кириллических `key_code` строкой в `jq` (`== "х"`) блокируется tirith как `confusable_text`. Использовать регулярку по диапазону: `test("[^\\x00-\\x7F]")` — без кириллицы в командной строке.
- **Именование модификаторов:** `left_command`/`right_command` (не `left_gui`); для левого option достаточно `option`; `right_shift`/`right_option` указывать явно.
- **Цепочка `select_input_source` → key → `select_input_source`** выполняется мгновенно, задержки не нужны, но даёт короткий фликер раскладки.
- **Живой файл и канон разъезжаются** — проверять md5 перед правкой.