173 lines
7.1 KiB
Markdown
173 lines
7.1 KiB
Markdown
# Виртуальная клавиатура на 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')
|
|
"
|
|
```
|