Перехватчик событий клавиатуры на уровне ядра (evdev) для быстрого преобразования текста между английской и русской раскладками через двойное нажатие Shift.
Быстрая установка:
git clone https://github.com/kabobik/lswitch.git && cd lswitch && bash scripts/install.sh- ✅ Конвертация текста по двойному Shift — нажми Shift дважды быстро, и текст конвертируется
- ✅ Перехват на уровне ядра — через
/dev/input/, работает во всех приложениях - ✅ Конвертация слова или выделения — последнее напечатанное слово ИЛИ выделенный текст
- ✅ EN ⟷ RU — английский ↔ русский
- ✅ Автоопределение раскладки — по n-граммам и словарю
- ✅ Самообучающийся словарь — учится на истории ошибок пользователя
- ✅ GUI иконка в трее — быстрые переключатели и полное окно настроек через PyQt6
- ✅ Настройки без перезапуска — все параметры активной сессии применяются на лету
- ✅ systemd служба — автозапуск GUI при входе в систему
| Компонент | Назначение | Критичность |
|---|---|---|
| Python 3.11+ | Основной интерпретатор | Критично |
| evdev | Чтение событий клавиатуры из /dev/input/ |
Критично |
| python-xlib | Определение раскладки, X11 | Критично |
| pyudev | Мониторинг hot-plug устройств | Критично |
| PyQt6 + QtDBus | GUI и KDE Wayland layout backend | Критично для Wayland |
| wl-clipboard | Clipboard fallback для Wayland (wl-copy/wl-paste) |
Критично для Wayland |
| qt6-wayland | Qt Wayland platform plugin | Критично для Wayland |
Hunspell EN/RU .dic |
Системные префиксы и защита исходных слов | Опционально* |
* Без полной пары EN/RU безопасная системная префиксная конвертация
отключается; user_dict и n-gram fallback остаются доступны.
Display Server: X11 и KDE Plasma Wayland
git clone https://github.com/kabobik/lswitch.git
cd lswitch
bash scripts/install.shСкрипт автоматически:
- Проверит Python 3.11+ и все зависимости
- Установит недостающие пакеты через
aptна Ubuntu/Debian илиpacmanна Arch Linux - Проверит EN/RU Hunspell/MySpell-словари и предложит установить недостающие
- Скопирует приложение в
~/.local/share/lswitch/ - Создаст команду
lswitchв~/.local/bin/ - Установит udev правила, иконку, ярлык в меню
- Предложит включить GUI автозапуск через
~/.config/autostart/
input применяются только после logout.
Скачайте .deb из Releases или соберите сами:
bash scripts/build-deb.sh
sudo dpkg -i build/lswitch_2.0.0_all.deb
sudo apt install -f # если нужны зависимости# Если ставили через install.sh:
bash scripts/install.sh --remove
# Если ставили через .deb:
sudo apt remove lswitchПосле запуска иконка LSwitch появляется в системном трее. Правая кнопка мыши — меню управления:
- Переключить авто-конвертацию
- Переключить самообучающийся словарь
- Открыть
Настройки… - Статус текущего процесса
- Debug Monitor (если включено отладочное журналирование)
Окно настроек содержит пять страниц и все параметры config.toml.
Применить сохраняет значения и обновляет работающий процесс, OK делает то
же и закрывает окно, а Отмена отбрасывает несохранённый draft. Зависимые
поля визуально отключаются вместе с родительской функцией, но введённые в них
значения не теряются. Значки ⓘ рядом с параметрами показывают локализованные
описания при наведении. Ошибка проверки ресурса или записи файла не оставляет
частично применённую конфигурацию.
Параметры текущего X11/Wayland adapter-а меняются сразу. Настройки другой
графической платформы скрыты, но их значения сохраняются в config.toml и
будут использованы при запуске соответствующей сессии. Если тип графической
сессии определить не удалось, окно показывает обе платформенные группы и
предупреждает, что LSwitch может работать некорректно.
При включённом debug пункт Debug Monitor открывает две независимые вкладки.
Конвертации показывает, почему проверенное слово было преобразовано или
оставлено: достигнутые правила, словарные и N-граммные факты, выбранный режим и
отдельный результат фактического исполнения. Попытки mid-word одного слова
сгруппированы, доступны фильтры, поиск, пауза отображения, очистка и явное
копирование выбранной трассы. Вкладка Состояние содержит прежний монитор
буфера и событий.
Пока слово вводится, его MID_WORD-трасса явно помечена как активная и
обновляется на месте. Если произошло раннее преобразование, трасса сразу
финализируется, а хвост видимого слова и завершающий Space повторно не
подаются детекторам. Для неконвертированного слова mid-word и boundary-записи
сохраняют общий correlation ID.
История трассировки хранится только в памяти (до 200 записей), собирается при
эффективном debug/--trace и полностью очищается при его выключении. В
обычный лог и конфигурацию содержимое набираемых слов автоматически не
записывается.
Ручные сценарии проверки собраны в
docs/CONVERSION_TRACE_MANUAL_TESTING.md.
mkdir -p ~/.config/autostart
cp ~/.local/share/applications/lswitch-control.desktop ~/.config/autostart/
sed -i "s|^Exec=.*|Exec=$HOME/.local/bin/lswitch --replace|" ~/.config/autostart/lswitch-control.desktopscripts/install.sh делает это автоматически, если согласиться на включение автозапуска.
Запуск через desktop autostart предпочтителен для X11/Wayland, потому что процесс наследует окружение пользовательской графической сессии.
lswitch # запуск с GUI
lswitch --debug # с отладочными сообщениями
lswitch --trace # с трассировкой всех событий
lswitch --replace # явный совместимый флаг замены экземпляра
lswitch --diagnose-wayland # диагностика KDE Wayland backend
lswitch --diagnose-wayland-switch-test # диагностика + тест переключения раскладкиЕдинственный экземпляр: при обычном запуске LSwitch автоматически останавливает предыдущий процесс и запускает новый.
--replaceсохранён для совместимости и используется в systemd unit и ярлыке приложения.
- Перехват: LSwitch слушает события клавиатуры через
/dev/input/(evdev) - Детектор двойного Shift: При двух нажатиях Shift с интервалом <
double_click_timeoutсек — срабатывание - Получение текста: Извлекает последнее слово из внутреннего буфера событий ИЛИ выделение (X11 PRIMARY)
- Конвертация: Посимвольное преобразование EN ↔ RU через таблицу маппинга
- Вставка: Удаляет оригинал (Backspace × N) и «перепечатывает» конвертированный текст через виртуальную клавиатуру
- Раскладка результата: Переключается прямо на целевую раскладку через
XKB/D-Bus, а проверяемую
layout_switch_keyиспользует как резервный способ.switch_layout_after_convertопределяет, оставить целевую раскладку или восстановить исходную после ввода результата.
| Введи (не та раскладка) | Двойной Shift | Результат |
|---|---|---|
ghbdtn |
→ | привет (+ переключает на RU) |
привет |
→ | ghbdtn (+ переключает на EN) |
ghbdtn vbh (выделено) |
→ | привет мир |
Hello world (выделено) |
→ | Руддщ цщкдв |
Конфиг: ~/.config/lswitch/config.toml.
# LSwitch configuration
#
# Wayland selection strategies:
# auto - read PRIMARY selection first, fallback to clipboard copy/paste
# clipboard_copy - always use clipboard copy/paste flow
# primary_selection - read PRIMARY and replace selection by direct UInput typing
# disabled - disable Wayland selection conversion
# Maximum interval between two Shift presses, seconds.
double_click_timeout = 0.3
# Enable live DEBUG logging and Debug Monitor; --trace remains an override.
debug = false
# Keep the result layout after conversion; false restores the previous layout.
switch_layout_after_convert = true
# Verified fallback shortcut; direct XKB/D-Bus target switching has priority.
layout_switch_key = "Alt+Shift"
# Enable user/system decisions while typing and n-gram fallback at a boundary.
auto_switch = false
# Minimum whole-word length for boundary n-gram fallback; 0 adds no restriction.
auto_switch_threshold = 0
# Minimum prefix length before system dictionary detection starts.
mid_word_min_prefix_len = 4
# Use system Hunspell/MySpell dictionaries while typing and for source veto.
system_dict_enabled = true
# Optional readable .dic paths; empty values enable auto-discovery.
system_dict_en_path = ""
system_dict_ru_path = ""
# Enable the self-learning user dictionary.
user_dict_enabled = false
# Minimum user dictionary score required to affect detection.
user_dict_min_weight = 2
# Wayland selection conversion mode.
wayland_selection_strategy = "auto"
# Common input/conversion timings, seconds.
[timing]
# Delay between virtual key press and release.
key_press_delay = 0.001
# Delay between successive virtual key taps.
key_repeat_delay = 0.001
# After layout switch before replaying typed word.
retype_before_replay_delay = 0.05
# After layout switch before direct selection typing.
direct_type_after_layout_switch_delay = 0.03
# After layout switch before undo replay.
undo_before_replay_delay = 0.03
# After layout switch before auto-conversion replay.
auto_before_replay_delay = 0.03
# After auto-conversion replay before final Space handling.
auto_before_space_delay = 0.01
# X11-only selection timings, seconds.
[x11_selection_timing]
# PRIMARY selection polling interval.
poll_interval = 0.5
# After writing clipboard before Ctrl+V.
paste_delay = 0.02
# After Ctrl+V before restoring clipboard.
restore_delay = 0.05
# After Ctrl+Shift+Left before reading PRIMARY.
expand_selection_delay = 0.05
# Wayland-only system timings, seconds.
[wayland_timing]
# Timeout for wl-copy/wl-paste helper commands.
wl_clipboard_timeout = 1.0
# Wayland-only selection timings, seconds.
[wayland_selection_timing]
# Maximum wait for Ctrl+C to update clipboard.
copy_wait_timeout = 1.0
# Clipboard poll interval after copy shortcut.
copy_poll_interval = 0.05
# Delay before trying fallback copy shortcut.
copy_retry_delay = 0.1
# After writing clipboard before Ctrl+V.
paste_delay = 0.12
# After Ctrl+V before restoring clipboard.
restore_delay = 0.15
# After Ctrl+Shift+Left before reading selection.
expand_selection_delay = 0.2Параметры:
double_click_timeout— максимальный интервал между двумя Shift (сек)switch_layout_after_convert—trueоставляет раскладку результата;falseвосстанавливает раскладку, активную до конвертацииlayout_switch_key— резервная комбинация (Alt+Shift,Ctrl+Shift,Meta+Space,CapsLock); прямое переключение на target через XKB/D-Bus имеет приоритет. Legacy-форматы вродеAlt_L+Shift_Lпринимаются и сохраняются в каноническом видеdebug— live-переключение уровняINFO/DEBUGи пункта Debug Monitor; запущенный с--traceпроцесс сохраняет уровеньTRACEauto_switch— единый переключатель автоматического pipeline: точные решенияuser_dict, системные префиксы во время набора и n-gram fallback на границеauto_switch_threshold— минимальная длина целого слова только для n-gram fallback; точные пользовательские и системные mid-word решения от неё не зависятmid_word_min_prefix_len— минимальная длина префикса только для проверки по системным словарямsystem_dict_enabled— использовать системные Hunspell/MySpell словари для префиксов во время набора и точной защиты исходного слова на границеsystem_dict_en_path,system_dict_ru_path— необязательные явные пути к английскому и русскому.dic; путь должен указывать на существующий читаемый обычный файл, пустое значение включает автоопределение. Под полями GUI показывает фактически активный путь, способ выбора и число загруженных словuser_dict_enabled— самообучающийся словарьwayland_selection_strategy— стратегия selection-конвертации на Wayland:"auto"сначала читает PRIMARY безCtrl+C, затем использует clipboard fallback;"clipboard_copy"всегда использует copy/paste flow;"primary_selection"читает PRIMARY и заменяет выделение прямым набором безCtrl+C/Ctrl+V;"disabled"отключает selection-конвертацию на Wayland[timing]— общие задержки виртуальной клавиатуры и replay после смены раскладки[x11_selection_timing]— X11-only задержки polling, expand, paste и restore для selection[wayland_timing]— Wayland-only системные задержки clipboard backend-а[wayland_selection_timing]— Wayland-only задержки copy/paste/restore и expand для selection
Для автоматической обработки включите auto_switch = true. LSwitch использует
только обнаруженные /usr/share/hunspell/*.dic, MySpell-словари или явно
указанные .dic; встроенного мини-словаря больше нет. Оба языка загружаются
одним снимком. Если отсутствует хотя бы один системный словарь, безопасная
префиксная конвертация отключается, но точные решения user_dict и строгий
n-gram fallback на Space продолжают работать.
Порядок во время набора: точное решение user_dict → резервирование его
префикса → системные source/target-префиксы. На Space, если слово ещё не было
конвертировано: точный user_dict → точная защита исходным системным словарём →
n-gram (target_score > 0 и разница оценок > 0.05). Целевой системный словарь
на Space повторно не запускает конвертацию.
Пользовательский словарь хранится отдельно: ~/.config/lswitch/user_dict.toml.
Он запоминает не "правильные слова", а решения для текста, набранного в конкретной раскладке:
[convert.en]
"ghbdtn" = 2
[keep.en]
"hello" = 2
[convert.ru]
"руддщ" = 2
[keep.ru]
"привет" = 2Число — это уверенность. Итоговый score считается как convert - keep; когда abs(score) достигает user_dict_min_weight, правило начинает влиять на автоопределение.
Словарь изменяется только явными действиями Shift+Shift: ручной конвертацией
или отменой автоматической. Автоматического подтверждения по следующему пробелу нет.
Все изменения из окна настроек и быстрых переключателей tray применяются без
перезапуска. Если TOML изменён внешним редактором, отправьте работающему
процессу SIGHUP:
kill -HUP "$(cat "${XDG_RUNTIME_DIR:-/run/user/$UID}/lswitch.pid")"Внешний файл проходит ту же валидацию и подготовку runtime. При ошибке текущая
конфигурация процесса продолжает работать; исправьте TOML и повторите SIGHUP.
Пошаговые проверки GUI приведены в
docs/GUI_SETTINGS_MANUAL_TESTING.md.
lswitch/
├── app.py # Точка входа и главный цикл
├── cli.py # Аргументы командной строки
├── config.py # Загрузка и сохранение конфига
│
├── core/ # Ядро: состояния, события, конвертация
│ ├── state_manager.py # FSM состояний (IDLE/TYPING/CONVERTING...)
│ ├── event_manager.py # Маршрутизация evdev событий
│ ├── event_bus.py # Внутренняя шина событий
│ ├── conversion_engine.py # Движок конвертации текста
│ └── text_converter.py # Посимвольная конвертация EN ↔ RU
│
├── input/ # Работа с устройствами ввода
│ ├── device_manager.py # Сканирование и hot-plug /dev/input/
│ ├── virtual_keyboard.py # Виртуальная клавиатура (uinput)
│ └── key_mapper.py # Маппинг keycode → символ
│
├── intelligence/ # Умные функции
│ ├── auto_detector.py # Авто-определение раскладки
│ ├── ngram_analyzer.py # N-грамм анализ
│ ├── dictionary_service.py # Словарный сервис
│ └── user_dictionary.py # Пользовательский словарь
│
├── platform/ # Платформо-зависимый код
│ ├── clipboard.py # Работа с буфером обмена
│ └── selection_adapter.py # X11 PRIMARY selection
│
└── ui/ # Графический интерфейс
├── tray_icon.py # Иконка в системном трее
├── context_menu.py # Меню трея
├── debug_monitor.py # Контейнер вкладок Debug Monitor
├── conversion_trace_tab.py # Путь решений и исполнения конвертации
└── config_dialog.py # Диалог настроек
pytest tests/ -v # все тесты
pytest tests/ --cov=lswitch # с покрытием кода
pytest tests/test_conversion_engine.py -v # конкретный модуль📊 Статус: 30 тестовых модулей
sudo usermod -a -G input $USER
# Затем перелогинитьсяУбедитесь, что systemd user unit запускается внутри графической сессии и видит DISPLAY или WAYLAND_DISPLAY, затем перезапустите его:
systemctl --user restart lswitchlswitch --replace --debug # запуск с отладкой вручнуюgit clone https://github.com/kabobik/lswitch.git
cd lswitch
# Установить в editable режиме (для разработки)
pip install -e ".[gui,dev]"
# Запустить тесты
pytest tests/ -v
# Запустить с трассировкой событий
lswitch --traceMIT License — см. LICENSE
Anton — 2024-2026
- Вдохновлено Punto Switcher от Яндекса
- Использует python-evdev для перехвата клавиатуры
- PyQt6 для GUI
⭐ Понравилось? Поставьте звезду на GitHub!