346 lines
29 KiB
Markdown
346 lines
29 KiB
Markdown
---
|
||
type: tech
|
||
topic: keyboard
|
||
tags:
|
||
- karabiner
|
||
- keyboard
|
||
- macos
|
||
- input-sources
|
||
- russian-layout
|
||
- caps-lock
|
||
- devices-remap
|
||
created: 2026-09-15T00:00:00.000Z
|
||
updated: 2026-09-15T00:00:00.000Z
|
||
---
|
||
|
||
# Karabiner-Elements — конфиг, раскладки, символы
|
||
|
||
Конфиг клавиатуры Mac (Karabiner-Elements). Правила подмены символов в русской раскладке (RussianWin), переключение раскладок, горячие клавиши.
|
||
|
||
## Файлы конфига
|
||
|
||
| Путь | Назначение |
|
||
|---|---|
|
||
| `~/Documents/karabiner.json` | **Рабочая копия** (канон, редактируется) |
|
||
| `~/.config/karabiner/karabiner.json` | **Живой** конфиг — его читает Karabiner |
|
||
| `~/Documents/karabiner.json.bak` | Бэкап рабочей копии |
|
||
| `~/Documents/karabiner.json.bak.20260915` | Бэкап перед первой правкой Caps-фикса (md5 `2ad1f7e1c8c8807739b636cc0650a527`) |
|
||
| `~/.config/karabiner/assets/complex_modifications/*.json` | Импортированные наборы правил (не редактируются вручную) |
|
||
|
||
### ⚠️ Расхождение канона и живого файла (обнаружено 2026-09-15)
|
||
|
||
На 2026-09-15 при первом осмотре **рабочая копия и живой конфиг РАЗЛИЧАЛИСЬ**:
|
||
|
||
| Файл | md5 (при осмотре) | Права |
|
||
|---|---|---|
|
||
| `~/Documents/karabiner.json` | `2ad1f7e1c8c8807739b636cc0650a527` | — |
|
||
| `~/.config/karabiner/karabiner.json` | `3d12713ff32ad49cb4d20a5f7b284746` | **`-rw-------` (600)** |
|
||
|
||
**Два вывода, требующих внимания:**
|
||
1. Живой конфиг имел права **600** вместо нужных **644**. По известному поведению Karabiner это прямой риск: при restrictive-правах Karabiner **молча сбрасывает конфиг на дефолт** (спрашивает про тип виртуальной клавиатуры, все complex_modifications пропадают). Обязательно `chmod 644` после каждого `cp`. **Статус: исправлено** — после правок живой файл приведён к `644`.
|
||
2. md5 не совпадали → расхождение канона и живого. Причина не установлена; `~/.config/karabiner/karabiner.json` меньшего размера (111 KB) чем канон (156 KB), в нём присутствуют лишние файлы-артефакты (`karabiner new.json`, `karabiner.json.06072026.bak`). После правок канон и живой были синхронизированы (`cp` канон→живой). **Перед любой правкой сверять содержимое, не заливать канон поверх живого слепо.**
|
||
|
||
### Состояние файлов на конец сессии 2026-09-15
|
||
|
||
Откат выполнен: живой конфиг = `~/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[]`.
|
||
|
||
Группы правил (индекс → название → число манипуляторов):
|
||
|
||
| # | Правило | Манипуляторов |
|
||
|---|---|---|
|
||
| 0 | Launch Apps HotKeys | 43 |
|
||
| 1 | Russian @ from opt+cmd+2 | 1 |
|
||
| 2 | Xcode Keyboard helpers | 7 |
|
||
| 3 | F Keys | 8 |
|
||
| 4 | Media Keys, F Keys | 11 |
|
||
| 5 | Smart Quotes | 8 |
|
||
| 6 | EN/ABC symbol keys | 4 |
|
||
| 7 | **Russian symbol keys** | **27** |
|
||
| 8 | Cmd+Space to switch language in RDP | 1 |
|
||
| 9 | Remap Keys in Microsoft Remote Desktop | 1 |
|
||
| 10 | Disable Cmd+H Hide (rev 2) | 1 |
|
||
| 11 | Sleep | 1 |
|
||
| 12 | Window Resize Mode | 4 |
|
||
|
||
Все RU-символьные ремапы живут в группе **#7 `Russian symbol keys`**.
|
||
|
||
## Ключевой паттерн группы «Russian symbol keys»
|
||
|
||
Каждый манипулятор:
|
||
- `from` — клавиша + `modifiers.mandatory`
|
||
- `to` — key_code + `modifiers` (обычно `right_shift` / `right_option` — правые модификаторы, чтобы не конфликтовать с левыми)
|
||
- `conditions`: `[{ "input_sources": [{"language": "ru"}], "type": "input_source_if" }]` — срабатывает **только в русской раскладке**
|
||
|
||
### Таблица ремапов (27 манипуляторов)
|
||
|
||
| RU-нажатие | Символ | Как реализовано |
|
||
|---|---|---|
|
||
| opt+4 ($) | ₽ | `8` + right_option |
|
||
| ₽ (opt+8) | € | opt+shift+4 |
|
||
| opt+shift+4 (€) | $ | `4` + right_option |
|
||
| opt+е (†) | € | opt+shift+4 |
|
||
| opt+9 («) | [ | grave + left_option |
|
||
| opt+0 (») | ] | grave + left_option+left_shift |
|
||
| ё | [ | grave + left_option |
|
||
| shift+ё | ] | grave + left_option+left_shift |
|
||
| opt+[ | [ | grave + left_option |
|
||
| opt+] | ] | grave + left_option+left_shift |
|
||
| opt+shift+[ | { | shift+9 |
|
||
| opt+shift+] | } | shift+0 |
|
||
| **opt+slash** | **/** | `backslash` + right_shift |
|
||
| **opt+shift+slash** | **?** | **`7` + right_shift** ← см. раздел про Caps Lock |
|
||
| opt+; (ж) | ; | `4` + right_shift |
|
||
| opt+shift+; (Ж) | : | `6` + right_shift |
|
||
| opt+' (э) | ' | `o` + right_option |
|
||
| opt+2 (") | « | close_bracket + right_option |
|
||
| opt+shift+2 (") | » | close_bracket + right_option+right_shift |
|
||
| backslash | ё | grave_accent_and_tilde |
|
||
| backslash | Ë | grave + right_shift |
|
||
| § | § | non_us_backslash + left_option |
|
||
| shift+§ (±) | ± | `f` + left_shift+left_option |
|
||
| opt+, (<) | < | comma + right_shift+right_option |
|
||
| opt+. (>) | > | period + right_shift+right_option |
|
||
| opt+shift+, (≤) | ≤ | comma + right_option |
|
||
| opt+shift+. (≥) | ≥ | period + right_option |
|
||
|
||
### Особый случай: `@` (в отдельной группе #1)
|
||
|
||
`@` нет ни в одной русской раскладке → используется `select_input_source` (временно переключиться на ABC, набрать, вернуться):
|
||
|
||
```json
|
||
{
|
||
"description": "Russian @ from opt+cmd+2",
|
||
"from": { "key_code": "2", "modifiers": { "mandatory": ["left_command", "option"] } },
|
||
"to": [
|
||
{ "select_input_source": { "input_source_id": "com.apple.keylayout.ABC", "language": "en" } },
|
||
{ "key_code": "2", "modifiers": ["right_shift"] },
|
||
{ "select_input_source": { "input_source_id": "com.apple.keylayout.RussianWin", "language": "ru" } }
|
||
],
|
||
"type": "basic",
|
||
"conditions": [
|
||
{ "input_sources": [{ "language": "ru" }], "type": "input_source_if" }
|
||
]
|
||
}
|
||
```
|
||
|
||
**Это рабочий образец для символов, которых нет в RU-раскладке.** Основной минус — короткий визуальный фликер раскладки.
|
||
|
||
## 🔴 Проблема: Caps Lock ломает подстановку `?`
|
||
|
||
**Запрос (2026-09-15):** в русской раскладке `opt+shift+/` без Caps вводит `?`, **при активном Caps Lock вводит `Ї`**.
|
||
|
||
### ✅ Диагноз (ПОДТВЕРЖДЁН Alex, 2026-09-15)
|
||
|
||
**Правило не срабатывает при активном Caps Lock.** Подтверждено Alex напрямую.
|
||
|
||
Следствие: нажатие не перехватывается манипулятором, уходит в систему напрямую, и RussianWin отдаёт свой **стандартный символ** на позиции `opt+shift+/` — это и есть `Ї`. `Ї` — не результат инверсии выхода `to`, а именно «сырой» системный символ, который возникает, когда Karabiner пропускает нажатие.
|
||
|
||
Это подтверждается и косвенно: если бы правило срабатывало, на выход пошёл бы `7`+shift, и Caps инвертировал бы его в другой символ — но не в `Ї`.
|
||
|
||
### ⚠️ Что НЕ является причиной
|
||
|
||
- **Смена модификатора `option` → `command` в `from`** — не имеет отношения к делу, комбинация-триггер тут не при чём.
|
||
- **Инверсия выхода `to` под Caps** — этой гипотезы придерживался агент в первой части сессии, она **неверна**. Лечить надо входную часть (`from`), а не выходную (`to`).
|
||
|
||
### Правка (подготовлена, ждёт подтверждения Alex)
|
||
|
||
Добавить `caps_lock` в **`optional`** модификаторы `from`, оставив `mandatory` нетронутым:
|
||
|
||
```json
|
||
"from": {
|
||
"key_code": "slash",
|
||
"modifiers": {
|
||
"mandatory": ["option", "shift"],
|
||
"optional": ["caps_lock"]
|
||
}
|
||
}
|
||
```
|
||
|
||
**Почему именно так (важно, не повторить ошибку):**
|
||
- **`shift` НЕЛЬЗЯ переводить из `mandatory` в `optional`.** Shift — часть combo `opt+shift+/`. Если сделать его опциональным, правило начнёт срабатывать и на `opt+/`, что сломает соседнее правило `opt+slash -> /`. Это предложение агента было ошибочным, Alex его отклонил.
|
||
- `mandatory: ["option","shift"]` остаётся как есть — оба обязательны.
|
||
- Активный Caps перестаёт блокировать матч за счёт его явного указания в `optional`.
|
||
- `to` (`7`+`right_shift`), `conditions`, `description` — не трогать.
|
||
|
||
**Незакрытый риск:** Alex поставил вопрос — не инвертирует ли Caps и выход `to` (`7`+`right_shift`)? Если при Caps правило сработает, но на выходе снова получится не `?` — потребуется дополнительно сбрасывать Caps в `to`. Определяется только проверкой фактом после применения.
|
||
|
||
### Ошибки агента в этой сессии — НЕ повторять
|
||
|
||
| Что было сделано | Результат | Вывод |
|
||
|---|---|---|
|
||
| Замена `to.modifiers`: `right_shift` → `right_option` | Вместо `?` пошёл `&` | В RussianWin `opt+7` = `&`. Менять модификатор в `to` вслепую нельзя — раскладка не является аналогом US |
|
||
| Замена `from.modifiers.mandatory`: `["option","shift"]` → `["option"]` + `optional:["shift"]` | Не применено (черновик) | Сломало бы `opt+/` — shift обязателен, он часть combo |
|
||
| Гипотеза «Caps инвертирует выход `to`» | Неверна | Реальная причина — матч `from` не проходит |
|
||
|
||
**Корневая ошибка:** агент дважды правил конфиг **без подтверждённого диагноза**, гадая между `from` и `to`. Оба раза мимо; первая правка попала в живой конфиг и сломала Alex раскладку (`&`), пришлось откатывать. **Правило: не править, пока причина не подтверждена фактом (EventViewer / прямой ответ Alex).**
|
||
|
||
### Процедура правки (когда решение будет принято)
|
||
|
||
1. Сверить `~/Documents/karabiner.json` и `~/.config/karabiner/karabiner.json` — **сначала понять, где свежие правки** (md5 разные!).
|
||
2. Бэкап: `cp ~/Documents/karabiner.json ~/Documents/karabiner.json.bak.20260915`
|
||
3. Правка рабочей копии через `jq` (не sed, не in-place). **Проверить diff изменённых путей** — должен измениться ровно один путь:
|
||
```bash
|
||
/usr/bin/jq '.profiles[0].complex_modifications.rules[7].manipulators[13].from.modifiers
|
||
= {"mandatory":["option","shift"],"optional":["caps_lock"]}' \
|
||
~/Documents/karabiner.json > /tmp/k.json \
|
||
&& /usr/bin/jq -e . /tmp/k.json > /dev/null \
|
||
&& diff <(/usr/bin/jq -r 'paths(scalars) as $p | "\($p|join("."))=\(getpath($p))"' ~/Documents/karabiner.json) \
|
||
<(/usr/bin/jq -r 'paths(scalars) as $p | "\($p|join("."))=\(getpath($p))"' /tmp/k.json)
|
||
```
|
||
Индексы: группа `"Russian symbol keys"` = **7**, правило `alt+shift+slash -> ? (shift+7)` = **13**.
|
||
4. Заливка в живой конфиг + права:
|
||
```bash
|
||
cp /tmp/k.json ~/Documents/karabiner.json
|
||
cp ~/Documents/karabiner.json ~/.config/karabiner/karabiner.json
|
||
chmod 644 ~/.config/karabiner/karabiner.json # ОБЯЗАТЕЛЬНО
|
||
```
|
||
5. Проверка: Karabiner подхватывает изменения немедленно, рестарт не нужен. Набрать `opt+shift+/` при **включённом Caps** → должно быть `?`; при выключенном → тоже `?` (регрессии быть не должно).
|
||
6. **Откат:**
|
||
```bash
|
||
cp ~/Documents/karabiner.json.bak.20260915 ~/.config/karabiner/karabiner.json
|
||
chmod 644 ~/.config/karabiner/karabiner.json
|
||
```
|
||
|
||
### Альтернатива, если фикс через `optional: caps_lock` не сработает
|
||
|
||
Заменить `to` на трёхшаговую цепочку через ABC-раскладку (как в правиле `@`): переключиться на ABC → `slash` + `right_shift` (Shift+/ = `?` на US, Caps на пунктуацию не влияет) → вернуться в RussianWin:
|
||
|
||
```json
|
||
"to": [
|
||
{ "select_input_source": { "input_source_id": "com.apple.keylayout.ABC", "language": "en" } },
|
||
{ "key_code": "slash", "modifiers": ["right_shift"] },
|
||
{ "select_input_source": { "input_source_id": "com.apple.keylayout.RussianWin", "language": "ru" } }
|
||
]
|
||
```
|
||
|
||
Минус — короткий фликер раскладки. Применять только если `optional: caps_lock` не даёт результата.
|
||
|
||
### Черновик правки `to` (собран, НЕ применён)
|
||
|
||
Файл `/tmp/k3.json` — версия с `to` через ABC. В живой конфиг и канон **не заливался**. `diff` показал изменение только путей внутри `manipulators.13.to`.
|
||
|
||
### Терминологическая поправка
|
||
|
||
Alex в изначальном запросе назвал комбинацию `cmd+shift+/`, но фактическое правило в конфиге — `opt+shift+/` (`alt+shift+slash`). Правила на `cmd+shift+/` в конфиге **нет вообще** (проверено: ни одного манипулятора с `key_code: "slash"` + `command` в `mandatory`). Работаем с существующим правилом `opt+shift+/`.
|
||
|
||
## 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` в первой сессии привело к порче раскладки и откату.
|
||
- **Не мешать кириллицу с 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 перед правкой.
|
||
- **Перед применением правки проверять diff `jq paths(scalars)`** — должен измениться ровно ожидаемый путь и ничего больше. Это ловит и ошибку индекса, и случайные изменения.
|
||
|
||
## Input Sources на этой системе
|
||
|
||
| Раскладка | Тип | ID |
|
||
|---|---|---|
|
||
| ABC (US) | Keyboard Layout | `com.apple.keylayout.ABC` |
|
||
| RussianWin | Keyboard Layout | `com.apple.keylayout.RussianWin` |
|
||
| Unicode Hex Input | Keyboard Layout | — |
|
||
|
||
Список: `defaults read ~/Library/Preferences/com.apple.HIToolbox.plist AppleEnabledInputSources`
|
||
|
||
## Связанные правила по флагам Caps (для справки)
|
||
|
||
Проверено на 2026-09-15: ссылок на `caps_lock` ни в `key_code`, ни в `from`/`to` в конфиге **нет** (0 совпадений). Ни один манипулятор не декларирует Caps в `optional` — именно поэтому Caps-состояние ломает матчинг у правил, где `shift` обязателен.
|
||
|
||
## References
|
||
|
||
- [Karabiner select_input_source](https://karabiner-elements.pqrs.org/docs/json/complex-modifications-manipulator-definition/to/select-input-source/)
|
||
- [KE complex_modifications JSON spec](https://karabiner-elements.pqrs.org/docs/json/complex-modifications-manipulator-definition/basic/)
|