# Виртуальная клавиатура на 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](https://github.com/archisman-panigrahi/vboard) (оригинал mdev588/vboard заброшен/заархивирован) - Наш форк с патчами: [mallexxx/vboard](https://github.com/mallexxx/vboard) ветка `htpc-bazzite-patches` - Python + GTK3 + uinput backend - Нативный Wayland на KDE Plasma, трей, регистрируется как Virtual Keyboard --- ## Установка на Bazzite ### Зависимости (pip, без rpm-ostree) ```bash pip3 install python-uinput meson ninja ``` > `/dev/uinput` уже доступен через Steam ACL (`user:bazzite:rw-` через `steam-devices` udev rules) — sudo не нужен. ### Сборка и установка (user scope) ```bash 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 ```bash 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`): ```python # было: "<": 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`: ```python # было: self.header.set_show_close_button(True) # стало: self.header.set_show_close_button(False) ``` ### 2. Кнопка переключения EN/RU в хедере `vboard/window.py` — в `create_settings()` после ESC кнопки: ```python 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) ``` Новые методы: ```python 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`: ```python KEY_LAYOUT_CHOICES = ( ("en", "English (US)"), ("ru", "Russian"), ) ``` --- ## Управление ```bash # Запустить вручную (обычно 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') " ```