Add SayoDevice support, 15 key pads and theme styles

Second protocol family (8089:000b) behind a new backend seam, 15 key and 3 knob pads, Knobs North plus the style and colour grid, Windows import fix, window resize fix.
This commit is contained in:
Mohamed Mahjoub
2026-10-08 22:14:31 +01:00
parent 6e25e350e0
commit 6a419eb3b6
34 changed files with 3410 additions and 572 deletions

View File

@@ -20,7 +20,6 @@ the desktop; it just gets a copy.
"""
import errno
import fcntl
import glob
import json
import os
@@ -31,6 +30,14 @@ import signal
import subprocess
import sys
import time
try:
import fcntl
except ImportError:
# Windows has none. Everything that needs it is Linux only anyway, and
# each use checks. Importing this module must not fail, because app.py
# imports it to build the window.
fcntl = None
from dataclasses import dataclass
from pathlib import Path
@@ -265,9 +272,17 @@ class VirtualKeyboard:
and the first paste would otherwise go missing.
"""
def __init__(self, path=UINPUT, _open=os.open, _ioctl=fcntl.ioctl,
def __init__(self, path=UINPUT, _open=os.open, _ioctl=None,
_write=os.write, _sleep=time.sleep):
import struct
# Resolved here, not in the signature: a default argument is
# evaluated when the module is imported, which on Windows would
# crash before the window ever got a chance to open.
if _ioctl is None:
if fcntl is None:
raise OSError("a virtual keyboard needs /dev/uinput, which "
"this system hasn't got")
_ioctl = fcntl.ioctl
self._struct, self._write, self._sleep = struct, _write, _sleep
self.fd = _open(path, os.O_WRONLY | os.O_NONBLOCK)
_ioctl(self.fd, _UI_SET_EVBIT, _EV_KEY)
@@ -570,6 +585,10 @@ def listen(debug=False, log=print):
"""
lock_path = runtime_dir() / LOCK
lock_path.parent.mkdir(parents=True, exist_ok=True)
if fcntl is None:
log("Background actions are Linux only for now: they need /dev/uinput "
"to type, and a file lock to keep one copy running.")
return 1
lock = open(lock_path, "a+")
try:
fcntl.flock(lock, fcntl.LOCK_EX | fcntl.LOCK_NB)