diff options
Diffstat (limited to 'kvmd/keyboard')
-rw-r--r-- | kvmd/keyboard/keysym.py | 17 | ||||
-rw-r--r-- | kvmd/keyboard/printer.py | 65 |
2 files changed, 62 insertions, 20 deletions
diff --git a/kvmd/keyboard/keysym.py b/kvmd/keyboard/keysym.py index c744e675..6ba7bd48 100644 --- a/kvmd/keyboard/keysym.py +++ b/kvmd/keyboard/keysym.py @@ -41,15 +41,19 @@ class SymmapModifiers: CTRL: int = 0x4 -def build_symmap(path: str) -> dict[int, dict[int, str]]: +def build_symmap(path: str) -> dict[int, dict[int, str]]: # x11 keysym -> [(modifiers, webkey), ...] # https://github.com/qemu/qemu/blob/95a9457fd44ad97c518858a4e1586a5498f9773c/ui/keymaps.c logger = get_logger() symmap: dict[int, dict[int, str]] = {} for (src, items) in [ - ("<builtin>", list(X11_TO_AT1.items())), (path, list(_read_keyboard_layout(path).items())), + ("<builtin>", list(X11_TO_AT1.items())), ]: + # Пока лучшая логика - самые первые записи в файле раскладки + # должны иметь приоритет над следующими, а дефолтный маппинг + # только дополняет отсутствующие значения. + for (code, keys) in items: for key in keys: web_name = AT1_TO_WEB.get(key.code) @@ -62,14 +66,15 @@ def build_symmap(path: str) -> dict[int, dict[int, str]]: logger.error("Invalid modifier key at mapping %s: %s / %s", src, web_name, key) continue - if code not in symmap: - symmap[code] = {} - symmap[code][ + modifiers = ( 0 | (SymmapModifiers.SHIFT if key.shift else 0) | (SymmapModifiers.ALTGR if key.altgr else 0) | (SymmapModifiers.CTRL if key.ctrl else 0) - ] = web_name + ) + if code not in symmap: + symmap[code] = {} + symmap[code].setdefault(modifiers, web_name) return symmap diff --git a/kvmd/keyboard/printer.py b/kvmd/keyboard/printer.py index a2003a18..a29355b6 100644 --- a/kvmd/keyboard/printer.py +++ b/kvmd/keyboard/printer.py @@ -20,6 +20,9 @@ # ========================================================================== # +import ctypes +import ctypes.util + from typing import Generator from .keysym import SymmapModifiers @@ -27,15 +30,40 @@ from .mappings import WebModifiers # ===== +def _load_libxkbcommon() -> ctypes.CDLL: + path = ctypes.util.find_library("xkbcommon") + if not path: + raise RuntimeError("Where is libxkbcommon?") + assert path + lib = ctypes.CDLL(path) + for (name, restype, argtypes) in [ + ("xkb_utf32_to_keysym", ctypes.c_uint32, [ctypes.c_uint32]), + ]: + func = getattr(lib, name) + if not func: + raise RuntimeError(f"Where is libc.{name}?") + setattr(func, "restype", restype) + setattr(func, "argtypes", argtypes) + return lib + + +_libxkbcommon = _load_libxkbcommon() + + +def _ch_to_keysym(ch: str) -> int: + assert len(ch) == 1 + return _libxkbcommon.xkb_utf32_to_keysym(ord(ch)) + + +# ===== def text_to_web_keys( # pylint: disable=too-many-branches text: str, symmap: dict[int, dict[int, str]], - shift_key: str=WebModifiers.SHIFT_LEFT, ) -> Generator[tuple[str, bool], None, None]: - assert shift_key in WebModifiers.SHIFTS + shift = False + altgr = False - shifted = False for ch in text: # https://stackoverflow.com/questions/12343987/convert-ascii-character-to-x11-keycode # https://www.ascii-code.com @@ -57,25 +85,34 @@ def text_to_web_keys( # pylint: disable=too-many-branches if not ch.isprintable(): continue try: - keys = symmap[ord(ch)] + keys = symmap[_ch_to_keysym(ch)] except Exception: continue - for (modifiers, key) in reversed(keys.items()): - if (modifiers & SymmapModifiers.ALTGR) or (modifiers & SymmapModifiers.CTRL): + for (modifiers, key) in keys.items(): + if modifiers & SymmapModifiers.CTRL: # Not supported yet continue - if modifiers & SymmapModifiers.SHIFT and not shifted: - yield (shift_key, True) - shifted = True - elif not (modifiers & SymmapModifiers.SHIFT) and shifted: - yield (shift_key, False) - shifted = False + if modifiers & SymmapModifiers.SHIFT and not shift: + yield (WebModifiers.SHIFT_LEFT, True) + shift = True + elif not (modifiers & SymmapModifiers.SHIFT) and shift: + yield (WebModifiers.SHIFT_LEFT, False) + shift = False + + if modifiers & SymmapModifiers.ALTGR and not altgr: + yield (WebModifiers.ALT_RIGHT, True) + altgr = True + elif not (modifiers & SymmapModifiers.ALTGR) and altgr: + yield (WebModifiers.ALT_RIGHT, False) + altgr = False yield (key, True) yield (key, False) break - if shifted: - yield (shift_key, False) + if shift: + yield (WebModifiers.SHIFT_LEFT, False) + if altgr: + yield (WebModifiers.ALT_RIGHT, False) |