From 6f32e314a6b19b5d3cc71f5ad1431ea112277259 Mon Sep 17 00:00:00 2001 From: Alexey Martemyanov Date: Tue, 15 Sep 2026 13:04:08 +0600 Subject: [PATCH] [2026-09-15] eagle: personal/tech/karabiner-keyboard-config.md --- personal/tech/karabiner-keyboard-config.md | 89 +++++++++++++++++++++- 1 file changed, 88 insertions(+), 1 deletion(-) diff --git a/personal/tech/karabiner-keyboard-config.md b/personal/tech/karabiner-keyboard-config.md index ffaa6f35..14a1e83b 100644 --- a/personal/tech/karabiner-keyboard-config.md +++ b/personal/tech/karabiner-keyboard-config.md @@ -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 на F7–F12). + +### Ошибки агента в этой сессии — НЕ повторять + +| Что было сделано | Вывод | +|---|---| +| Откат на `.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 на F7–F12 (нужно проверить, пользуется ли 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 перед правкой.