Ми}{@лbI4

Блог хеллоуворлдщика

Индикатор раскладки клавиатуры для tint2 [Часть 1]

13.04.2022 linux, tint2, xkb, debian, клавиатура, bash

Индиктор раскладки клавиатуры вещь нужная. И на мое удивление, для tint2 и Openbox ничего не нашлось. Те, что я использовал раньше, более не работают. Но мы и сами с усами. Сделаем!

Требования простые до безобразия:

  • это должно работать как executor для tint2;
  • не имееть дополнительных зависимостей;
  • простое;
  • желательно на Bash.

Сначала было желание реализовать переключение раскладки клавиатуры кликом мыши по индикатору, но удовлетворяющего меня способа не было найдено. Решил, что сделаю потом, когда решу переписать на C.

Если кому-то захочется добавить переключение раскладки, то через пакет xdotool она переключается вызовом xdotool key Mode_switch. Еще есть вариант через setxkbmap -layout [layouts]. Но лично меня оба варианта не устроили.

Входные данные следующие:

  • X11;
  • tint2;
  • наличие двух языков: английский и русский.

У меня в системе всегда идет первым английский и потом русский, потому что английским я пользуюсь чаще всего.

100 % способа извлечения текущий раскладки клавиатуры без использования "сишной" библиотеки libxkbfile - нет. Но есть один, который работает уже из коробки с X11 - утилита xset - и вполне себе. Правда, мы завязываемся не на данных о раскладке, а на данных индикации клавиатуры, таких как CapsLock, ScrollLock, NumLock и т.п. И с учетом того, что моей задачей является переключение между двумя языками и переключение через нажатие CapsLock - этот вариант мне подходит. Дешево и сердито.

Выполняя команду

xset -q | grep LED | awk '{ print $10 }'

методом тыка было определено, что третий бит отвечает за CapsLock: 00001000 с включенным, а 00000000 с выключенным.

Для tint2 я решил, что вместо текста раскладки (US, RU) пусть будут SVG-иконки флагов. Иконки флагов взял отсюда. И нам потребуется еще одна иконка, на случай обработки исключения - отсутствие флага для раскладки. Например, такая. Итого у нас три иконки: flag-ru.svg, flag-us.svg и no-flag.svg. Иконки положил по адресу ~/.local/share/keyboard-layout/.

С учетом раскладки клавиатуры в /etc/default/keyboard (там у меня XKBLAYOUT="us,ru"), было решено, что CapsLock=0 - US, а CapsLock=1 - RU.

В итоге я накидал следующий скрипт на Bash:

#!/usr/bin/env bash

# keyboard-layout [command] - The helper for xkb* utilities.
#
# Commands:
# switch  -   Switch layout of keyboard.
# status  -   Return layout indicator icon.

usage() {
  cat <<EOF
$0 [command] - The helper for xkb* utilities.

Commands:
switch  -   Switch layout of keyboard.
status  -   Return layout indicator icon.
EOF
}

get_status() {
  local code=$(xset -q | grep LED | awk '{ print $10 }')
  case "${code:4:1}" in
    '0')
      local code='us'
      ;;

    '1')
      local code='ru'
      ;;

    *)
      local code=''
      ;;
  esac

  if [ -z $code ]; then
    local icon="no-flag.svg"
  else
    local icon="flag-${code}.svg"
  fi
  echo -n "/home/$(whoami)/.local/share/keyboard-layout/${icon}"
}

switch_layout() {
  # TODO
}

case "$1" in
  'switch')
    switch_layout
    ;;

  'status')
    get_status
    ;;

  *)
    usage
    ;;
esac

exit 0

Как можно заметить, переключение раскладки запланировано, но не реализовано. Фигурирует наивное "TODO" в функции switch_layout. Как-нибудь сделаю, но не сегодня.

Конфигурация для tint2:

execp = new
execp_command = ~/.local/bin/keyboard-layout status
execp_interval = 1
execp_lclick_command = ~/.local/bin/keyboard-layout switch
execp_has_icon = 1
execp_cache_icon = 1
execp_icon_w = 22
execp_tooltip =

Левый клик мыши, для переключения раскладки, также решил сразу заложить в конфигурацию tint2. Пусть будет. Есть не просит, на работу не влияет. Зато потом, как скрипт допишу, сразу будет все работать. Ну или просто будет глаза мозолить и напоминать о том, что я хотел это сделать.

И конечно же, результат работы:

Я согласен с тем, что вариант переключения по индикации CapsLock не самое лучшее решение, но в данном случае для меня оно самое быстрое. Если у вас больше двух языков, то этот вариант не подойдет, т.к. флаг индикации рассчитан на два значения (0 и 1).