Files
obsidian-vault/family/how-to/virtual-keyboard-bazzite.md
T
2026-05-29 09:01:25 +00:00

7.1 KiB
Executable File

Виртуальная клавиатура на HTPC (Bazzite KDE Wayland)

Связано: htpc | magic4pc-webos

Контекст

HTPC: htpc (192.168.1.86, Bazzite, KDE Plasma 6, Wayland)
Задача: экранная клавиатура для редкого ввода текста без физической клавиатуры.


Изученные варианты

Maliit (официальная KDE клавиатура)

  • Единственный officially supported OSK для KDE Wayland
  • Критический баг (upstream, не Bazzite): появляется один раз, после скрытия повторно не открывается без pkill maliit-keyboard && maliit-keyboard
  • На Bazzite desktop: опция Virtual Keyboard вообще отсутствует в Accessibility Settings
  • Статус: не пригоден для HTPC

Onboard

  • Полнофункциональная клавиатура с modifier keys
  • Работает через XWayland + uinput (GDK_BACKEND=x11 onboard)
  • Не rpm-ostree пакет, требует rpm-ostree install onboard (layered package)
  • Нет трея, нет интеграции с KDE Virtual Keyboard API
  • Статус: рабочий fallback, но хуже vboard

vboard (выбранное решение)

  • Форк: archisman-panigrahi/vboard (оригинал mdev588/vboard заброшен/заархивирован)
  • Наш форк с патчами: mallexxx/vboard ветка htpc-bazzite-patches
  • Python + GTK3 + uinput backend
  • Нативный Wayland на KDE Plasma, трей, регистрируется как Virtual Keyboard

Установка на Bazzite

Зависимости (pip, без rpm-ostree)

pip3 install python-uinput meson ninja

/dev/uinput уже доступен через Steam ACL (user:bazzite:rw- через steam-devices udev rules) — sudo не нужен.

Сборка и установка (user scope)

git clone https://github.com/mallexxx/vboard.git
cd vboard
git checkout htpc-bazzite-patches

meson setup builddir-user --prefix=$HOME/.local
meson compile -C builddir-user
meson install -C builddir-user
# Создаёт KWin rule автоматически

Регистрация как KDE Virtual Keyboard

kwriteconfig6 --file kwinrc --group Plugins --key kwin_wayland_vkbd_plugin 'io.github.archisman-panigrahi.vboard'
kwriteconfig6 --file kwinrc --group Plugins --key VirtualKeyboardEnabled true

Проверить: System Settings → Input Devices → Virtual Keyboard → выбрать Vboard.


Известные проблемы и решения

⚠️ Ввод не работает (NullInputBackend)

Причина: python-uinput из pip не имеет KEY_LESS (есть только в системном пакете).
UInputBackend падает при инициализации → fallback на NullInputBackend → нажатия игнорируются.

Патч (vboard/input_backends.py):

# было:
"<": uinput.KEY_LESS,
# стало:
"<": uinput.KEY_102ND,

KEY_102ND — стандартный keycode для клавиши </> на европейских раскладках, есть в pip-версии.

⚠️ Автопоказ/скрытие по фокусу поля не работает

Причина: vboard не реализует zwp_input_method_v2 Wayland протокол.
KDE запускает его как процесс, но сигналы "show/hide" не передаются.
Решение: оставить как есть — клавиатура висит поверх, управление через трей.

⚠️ Русская раскладка вводит латиницу

Причина: vboard шлёт физические keycodes (KEY_Q и т.д.), система переводит по своей раскладке.
Решение: синхронизировать системную раскладку KDE через D-Bus при переключении (см. патчи ниже).

⚠️ Таскбар исчез при попытке закрепить иконку через kwriteconfig

Причина: неверный group path в plasma-org.kde.plasma.desktop-appletsrc → plasmashell упал.
Решение: plasmashell --replace через SSH.
Правильный способ закрепить иконку: правый клик на ^ → Configure System Tray → Entries → Virtual Keyboard → Always Shown.


Кастомные патчи (ветка htpc-bazzite-patches)

1. Скрыть кнопку закрытия

vboard/window.py:

# было:
self.header.set_show_close_button(True)
# стало:
self.header.set_show_close_button(False)

2. Кнопка переключения EN/RU в хедере

vboard/window.py — в create_settings() после ESC кнопки:

self.lang_button = Gtk.Button(label=self.keyboard_layout.upper())
self.lang_button.connect("clicked", self.cycle_keyboard_layout)
self.lang_button.set_name("esc-button")
self.header.pack_start(self.lang_button)

Новые методы:

def cycle_keyboard_layout(self, widget=None):
    keys = [k for k, _ in KEY_LAYOUT_CHOICES]
    idx = keys.index(self.keyboard_layout) if self.keyboard_layout in keys else 0
    next_key = keys[(idx + 1) % len(keys)]
    self.set_keyboard_layout(next_key)
    self.lang_button.set_label(next_key.upper())
    self.sync_system_layout(next_key)

def sync_system_layout(self, layout_key):
    import subprocess
    layout_map = {"en": "0", "ru": "1"}
    index = layout_map.get(layout_key)
    if index is None:
        return
    try:
        subprocess.Popen([
            "qdbus", "org.kde.keyboard", "/Layouts",
            "org.kde.KeyboardLayouts.setLayout", index
        ], env=dict(__import__("os").environ,
                    DBUS_SESSION_BUS_ADDRESS="unix:path=/run/user/1000/bus"))
    except Exception:
        pass

Индексы en=0, ru=1 соответствуют порядку раскладок в KDE: проверить через
qdbus --literal org.kde.keyboard /Layouts org.kde.KeyboardLayouts.getLayoutsList

3. Только EN/RU раскладки

vboard/constants.py:

KEY_LAYOUT_CHOICES = (
    ("en", "English (US)"),
    ("ru", "Russian"),
)

Управление

# Запустить вручную (обычно KDE делает сам)
XDG_RUNTIME_DIR=/run/user/1000 WAYLAND_DISPLAY=wayland-0 \
  DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus \
  python3 ~/.local/bin/vboard &

# Перезапустить
kill -9 $(pgrep -f vboard)
# KDE перезапустит автоматически через ~3 сек

# Проверить что backend работает
python3 -c "
import sys; sys.path.insert(0, '$HOME/.local/share/vboard')
from vboard.input_backends import UInputBackend
b = UInputBackend(); print('OK')
"