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-devicesudev 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')
"