16c16,112 < Заметим, однако, что в иксах всё нам нужное уже заложено из коробки: есть чудесные клавиши с keysym = ISO_First_Group для переключения на первую раскладку, ISO_Last_Group для переключения, соответственно, на последнюю, и ISO_Next_Group для переключения в цикле. И всё, что нам нужно - это эмулировать нажатие ISO_First_Group, мы достигнем искомого. А что у нас есть такого старого, доброго и привычного для эмуляции всякого нажатия и движения в иксах? Прави \ No newline at end of file --- > Заметим, однако, что в иксах всё нам нужное уже заложено из коробки: есть чудесные клавиши с keysym = ISO_First_Group для переключения на первую раскладку, ISO_Last_Group для переключения, соответственно, на последнюю, и ISO_Next_Group для переключения в цикле. И всё, что нам нужно - это эмулировать нажатие ISO_First_Group, мы достигнем искомого. А что у нас есть такого старого, доброго и привычного для эмуляции всякого нажатия и движения в иксах? Правильно, `xdotool`. > > И тут мы встречаем первый в нашей истории жирный такой нюанс: в `xdotool` есть давно известный... то ли баг, то ли так и было задумано. В общем, xdotool перед эмуляцией клавиш программно сбрасывает все "модификаторы ввода", к коим относят и всё связанное с раскладкой. Так что эмулировать ISO_First_Group легче лёгкого, да только вот эффект это даст ровно нулевой. И исправлять это поведение никто, кажется, не планирует. > > Ладно, не огорчаемся, ловим рабочий способ. Есть ведь другой эмулятор, работоспособный: виртуальная экранная клавиатура `xvkbd`, которую мы поставим (посредством `doas pkg_add xvkbd`) и добьемся искомого поведения вызовом: `xvkbd -text '\[ISO_Next_Group]'` (будучи вызванной с опцией -text эта программа никаких экранных клавиатур не рисует, а просто эмулирует ввод переданного текста). Собственно, всё, решение найдено, на этом повествование можно было бы заканчивать. Вписывайте в `~/.config/i3/config` строчку вроде `bindsym $mod+1 workspace number $ws1; exec "xvkbd -text '\[ISO_First_Group]'"` и вуаля. Ну для полного вуаля можно еще добавить оное к комбинации клавиш для запуска программ, у меня вот так: > ``` > bindcode $mod+40 exec "xvkbd -text '\[ISO_First_Group]'; rofi -show combi -modes combi -combi-modes 'drun,run,window' -show-icons -icon-theme 'Adwaita' -drun-match-fields 'name,exec' -font 'FantasqueSansM Nerd Font Regular 18'" > ``` > И в скрипт для блокировки экрана тоже можно вписать `xvkbd -text '\[ISO_First_Group]'`. Всё. > > Но как быть пуристам и минималистам, которые не хотят тащить в систему пусть крохотную, но все-таки избыточную программу? А давайте напишем сами мини-переключалку, которая будет делать ровно то, что нам надо и ничего больше, использовать исключительно X11 API и не иметь никаких зависимостей, окромя самих иксов? Ловите: > ```C > #include > #include > #include > #include > #include > > void printHelpMessage() { > printf("syntax : \n --help - this message \n"); > printf(" --set N - set layout N, 0 = first, 1 = second... \n\n"); > return; > } > > void setKbdLayout(int layoutId) { > > /* Вызовом функции XOpenDisplay подключаемся к Х-серверу. > В качестве аргумента displayName передаем NULL - это оз- > начает, что будет выбран сервер по умолчанию, данные о > котором хранятся в переменной окружения DISPLAY */ > > Display* _display; > char* displayName = ""; > _display = XOpenDisplay(displayName); > > /* Используя XksUseCoreKeyboard мы указываем основную кла- > виатуру без необходимости определения ее идентификатора */ > > int _deviceId = XkbUseCoreKbd; > > /* Устанавливаем заданную раскладку и закрываем соединение > с X-сервером */ > > XkbLockGroup(_display, _deviceId, layoutId); > XCloseDisplay(_display); > return; > } > > int main(int argc, char **argv) { > > /* Займемся обработкой параметров командной строки. */ > > if (argc <= 1) { > printHelpMessage(); > } > else if (!strcmp(argv[1], "--set")) { > if(argc <= 2) { > printf("'set' operation requires a parameter.\n"); > } else { > int res = atoi(argv[2]); > setKbdLayout(res); > } > } > else if (!strcmp(argv[1], "--help")) { > printHelpMessage(); > } > else { > printf("\nUnknown parameter!\n"); > printHelpMessage(); > } > > return 0; > > } > ``` > > Сохраним этот код в файлик с названием вроде swxkb.c и скомпилируем в OpenBSD так: `clang -o swxkb swxkb.c -L/usr/X11R6/lib -lX11`. Впрочем, с тем же успехом оно скомпилируется и в любом Linux-дистрибутиве при помощи gcc (разве что, может потребоваться установка пакета libx11-dev или чего-то наподобие, в OpenBSD оно идет из коробки с иксами). По использованию - там в коде хелп виднеется. Куда вызов вписать - выше по тексту указано. > > Ну и под занавес. Если вдруг потребуется скриптом раскладку не только устанавливать, но и узнавать текущуюю, то сделать это можно вот так: > ```sh > #!/bin/sh > > COMMAND=$(xset -q | grep LED | awk '{ print $10 }') > > case "$COMMAND" in > "00000000"|"00000001") LAYOUT="en" ;; > "00000010"|"00000011") LAYOUT="ru" ;; > *) LAYOUT="??" ;; > esac > > echo $LAYOUT > ``` > > Наслаждайтесь. > > P.S. Ностальгия... лет, наверное, не менее 12-ти назад я уже решал подобную задачу - настраивая под себя i3 (или даже вовсе wmii) под Arch Linux на Asus EeePC 901. Тогда я нашел готовую реализацию, что-то минималистичное в AUR. До чего же приятно иногда окунуться в прошлое! >