Files
obsidian-vault/personal/tech/karabiner-keyboard-config.md
T

259 lines
19 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
type: tech
topic: keyboard
tags:
- karabiner
- keyboard
- macos
- input-sources
- russian-layout
- caps-lock
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-фикса НЕ решена.**
## Структура профиля (на 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
- **Права 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` в этой сессии привело к порче раскладки и откату.
- **Именование модификаторов:** `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/)