summaryrefslogtreecommitdiff
path: root/kvmd
diff options
context:
space:
mode:
authorDevaev Maxim <[email protected]>2020-10-08 12:18:38 +0300
committerDevaev Maxim <[email protected]>2020-10-08 12:18:38 +0300
commitf1910f7c8ec085eece1adc56ff999527881e71d9 (patch)
tree4f3cb6c481a7d0f29b91fa8ccc9e320f3a29b73b /kvmd
parent920f648d6526217009f8ee4dc6e943a28a4886db (diff)
more correct keymap handling
Diffstat (limited to 'kvmd')
-rw-r--r--kvmd/apps/kvmd/api/hid.py5
-rw-r--r--kvmd/apps/vnc/server.py20
-rw-r--r--kvmd/keyboard/keysym.py128
-rw-r--r--kvmd/keyboard/mappings.py310
-rw-r--r--kvmd/keyboard/mappings.py.mako2
-rw-r--r--kvmd/keyboard/printer.py35
6 files changed, 271 insertions, 229 deletions
diff --git a/kvmd/apps/kvmd/api/hid.py b/kvmd/apps/kvmd/api/hid.py
index 90bf53ff..573ed48c 100644
--- a/kvmd/apps/kvmd/api/hid.py
+++ b/kvmd/apps/kvmd/api/hid.py
@@ -42,7 +42,6 @@ from ....validators.kvm import valid_hid_mouse_move
from ....validators.kvm import valid_hid_mouse_button
from ....validators.kvm import valid_hid_mouse_wheel
-from ....keyboard.keysym import SymmapWebKey
from ....keyboard.keysym import build_symmap
from ....keyboard.printer import text_to_web_keys
@@ -98,7 +97,7 @@ class HidApi:
self.__hid.send_key_events(text_to_web_keys(text, symmap))
return make_json_response()
- def __ensure_symmap(self, keymap_name: str) -> Dict[int, SymmapWebKey]:
+ def __ensure_symmap(self, keymap_name: str) -> Dict[int, Dict[int, str]]:
keymap_name = valid_printable_filename(keymap_name, "keymap")
path = os.path.join(self.__keymaps_dir_path, keymap_name)
try:
@@ -110,7 +109,7 @@ class HidApi:
return self.__inner_ensure_symmap(path, st.st_mtime)
@functools.lru_cache(maxsize=10)
- def __inner_ensure_symmap(self, path: str, mtime: int) -> Dict[int, SymmapWebKey]:
+ def __inner_ensure_symmap(self, path: str, mtime: int) -> Dict[int, Dict[int, str]]:
_ = mtime # For LRU
return build_symmap(path)
diff --git a/kvmd/apps/vnc/server.py b/kvmd/apps/vnc/server.py
index f552e026..41fd0487 100644
--- a/kvmd/apps/vnc/server.py
+++ b/kvmd/apps/vnc/server.py
@@ -33,7 +33,7 @@ import aiohttp
from ...logging import get_logger
-from ...keyboard.keysym import SymmapWebKey
+from ...keyboard.keysym import switch_symmap_modifiers
from ...keyboard.keysym import build_symmap
from ...clients.kvmd import KvmdClientWs
@@ -72,7 +72,7 @@ class _Client(RfbClient): # pylint: disable=too-many-instance-attributes
desired_fps: int,
keymap_name: str,
- symmap: Dict[int, SymmapWebKey],
+ symmap: Dict[int, Dict[int, str]],
kvmd: KvmdClient,
streamer: StreamerClient,
@@ -119,6 +119,8 @@ class _Client(RfbClient): # pylint: disable=too-many-instance-attributes
self.__lock = asyncio.Lock()
+ self.__modifiers = 0
+
# =====
async def run(self) -> None:
@@ -238,10 +240,18 @@ class _Client(RfbClient): # pylint: disable=too-many-instance-attributes
# =====
async def _on_key_event(self, code: int, state: bool) -> None:
+ (is_modifier, self.__modifiers) = switch_symmap_modifiers(self.__modifiers, code, state)
if self.__kvmd_ws:
- web_key = self.__symmap.get(code)
- if web_key is not None:
- await self.__kvmd_ws.send_key_event(web_key.name, state)
+ web_keys = self.__symmap.get(code)
+ if web_keys:
+ if is_modifier:
+ web_key = web_keys.get(0)
+ else:
+ web_key = web_keys.get(self.__modifiers)
+ if web_key is None:
+ web_key = web_keys.get(0)
+ if web_key is not None:
+ await self.__kvmd_ws.send_key_event(web_key, state)
async def _on_pointer_event(self, buttons: Dict[str, bool], wheel: Dict[str, int], move: Dict[str, int]) -> None:
if self.__kvmd_ws:
diff --git a/kvmd/keyboard/keysym.py b/kvmd/keyboard/keysym.py
index e3695b3c..0f3568ed 100644
--- a/kvmd/keyboard/keysym.py
+++ b/kvmd/keyboard/keysym.py
@@ -20,10 +20,11 @@
# ========================================================================== #
-import dataclasses
import pkgutil
import functools
+from typing import Tuple
+from typing import List
from typing import Dict
import Xlib.keysymdef
@@ -36,39 +37,58 @@ from .mappings import AT1_TO_WEB
# =====
[email protected](frozen=True)
-class SymmapWebKey:
- name: str
- shift: bool
- altgr: bool
- ctrl: bool
-
-
-def build_symmap(path: str) -> Dict[int, SymmapWebKey]:
+class SymmapModifiers:
+ SHIFT: int = 0x1
+ ALTGR: int = 0x2
+ CTRL: int = 0x4
+
+
+def switch_symmap_modifiers(modifiers: int, code: int, state: bool) -> Tuple[bool, int]:
+ mod = 0
+ if code == 65505 or code == 65506: # XK_Shift_L, XK_Shift_R
+ mod = SymmapModifiers.SHIFT
+ elif code == 65027: # AltGR aka XK_ISO_Level3_Shift
+ mod = SymmapModifiers.ALTGR
+ elif code == 65507 or code == 65508: # XK_Control_L, XK_Control_R
+ mod = SymmapModifiers.CTRL
+ if mod == 0:
+ return (False, modifiers)
+ if state:
+ modifiers |= mod
+ else:
+ modifiers &= ~mod
+ return (True, modifiers)
+
+
+def build_symmap(path: str) -> Dict[int, Dict[int, str]]:
# https://github.com/qemu/qemu/blob/95a9457fd44ad97c518858a4e1586a5498f9773c/ui/keymaps.c
logger = get_logger()
- symmap: Dict[int, SymmapWebKey] = {}
+ symmap: Dict[int, Dict[int, str]] = {}
for (src, items) in [
("<builtin>", list(X11_TO_AT1.items())),
(path, list(_read_keyboard_layout(path).items())),
]:
- for (code, key) in items:
- web_name = AT1_TO_WEB.get(key.code)
- if web_name is not None:
- if (
- (web_name in ["ShiftLeft", "ShiftRight"] and key.shift) # pylint: disable=too-many-boolean-expressions
- or (web_name in ["AltLeft", "AltRight"] and key.altgr)
- or (web_name in ["ControlLeft", "ControlRight"] and key.ctrl)
- ):
- logger.error("Invalid modifier key at mapping %s: %s / %s", src, web_name, key)
- continue
- symmap[code] = SymmapWebKey(
- name=web_name,
- shift=key.shift,
- altgr=key.altgr,
- ctrl=key.ctrl,
- )
+ for (code, keys) in items:
+ for key in keys:
+ web_name = AT1_TO_WEB.get(key.code)
+ if web_name is not None:
+ if (
+ (web_name in ["ShiftLeft", "ShiftRight"] and key.shift) # pylint: disable=too-many-boolean-expressions
+ or (web_name in ["AltLeft", "AltRight"] and key.altgr)
+ or (web_name in ["ControlLeft", "ControlRight"] and key.ctrl)
+ ):
+ logger.error("Invalid modifier key at mapping %s: %s / %s", src, web_name, key)
+ continue
+
+ if code not in symmap:
+ symmap[code] = {}
+ symmap[code][
+ 0
+ | (SymmapModifiers.SHIFT if key.shift else 0)
+ | (SymmapModifiers.ALTGR if key.altgr else 0)
+ | (SymmapModifiers.CTRL if key.ctrl else 0)
+ ] = web_name
return symmap
@@ -100,14 +120,14 @@ def _resolve_keysym(name: str) -> int:
return 0
-def _read_keyboard_layout(path: str) -> Dict[int, At1Key]: # Keysym to evdev (at1)
+def _read_keyboard_layout(path: str) -> Dict[int, List[At1Key]]: # Keysym to evdev (at1)
logger = get_logger(0)
logger.info("Reading keyboard layout %s ...", path)
with open(path) as layout_file:
lines = list(map(str.strip, layout_file.read().split("\n")))
- layout: Dict[int, At1Key] = {}
+ layout: Dict[int, List[At1Key]] = {}
for (lineno, line) in enumerate(lines):
if len(line) == 0 or line.startswith(("#", "map ", "include ")):
continue
@@ -115,26 +135,32 @@ def _read_keyboard_layout(path: str) -> Dict[int, At1Key]: # Keysym to evdev (a
parts = line.split()
if len(parts) >= 2:
x11_code = _resolve_keysym(parts[0])
- if x11_code != 0:
- try:
- at1_code = int(parts[1], 16)
- except ValueError as err:
- logger.error("Syntax error at %s:%d: %s", path, lineno, err)
- continue
- rest = parts[2:]
-
- layout[x11_code] = At1Key(
- code=at1_code,
- shift=("shift" in rest),
- altgr=("altgr" in rest),
- ctrl=("ctrl" in rest),
- )
-
- if "addupper" in rest:
- x11_code = _resolve_keysym(parts[0].upper())
- if x11_code != 0:
- layout[x11_code] = At1Key(
- code=at1_code,
- shift=True,
- )
+ if x11_code == 0:
+ continue
+
+ try:
+ at1_code = int(parts[1], 16)
+ except ValueError as err:
+ logger.error("Syntax error at %s:%d: %s", path, lineno, err)
+ continue
+ rest = parts[2:]
+
+ if x11_code not in layout:
+ layout[x11_code] = []
+ layout[x11_code].append(At1Key(
+ code=at1_code,
+ shift=("shift" in rest),
+ altgr=("altgr" in rest),
+ ctrl=("ctrl" in rest),
+ ))
+
+ if "addupper" in rest:
+ x11_code = _resolve_keysym(parts[0].upper())
+ if x11_code != 0:
+ if x11_code not in layout:
+ layout[x11_code] = []
+ layout[x11_code].append(At1Key(
+ code=at1_code,
+ shift=True,
+ ))
return layout
diff --git a/kvmd/keyboard/mappings.py b/kvmd/keyboard/mappings.py
index b4bebbf3..310c50a0 100644
--- a/kvmd/keyboard/mappings.py
+++ b/kvmd/keyboard/mappings.py
@@ -163,161 +163,161 @@ class At1Key:
X11_TO_AT1 = {
- 65307: At1Key(code=1, shift=False), # XK_Escape
- 33: At1Key(code=2, shift=True), # XK_exclam
- 49: At1Key(code=2, shift=False), # XK_1
- 50: At1Key(code=3, shift=False), # XK_2
- 64: At1Key(code=3, shift=True), # XK_at
- 35: At1Key(code=4, shift=True), # XK_numbersign
- 51: At1Key(code=4, shift=False), # XK_3
- 36: At1Key(code=5, shift=True), # XK_dollar
- 52: At1Key(code=5, shift=False), # XK_4
- 37: At1Key(code=6, shift=True), # XK_percent
- 53: At1Key(code=6, shift=False), # XK_5
- 54: At1Key(code=7, shift=False), # XK_6
- 94: At1Key(code=7, shift=True), # XK_asciicircum
- 38: At1Key(code=8, shift=True), # XK_ampersand
- 55: At1Key(code=8, shift=False), # XK_7
- 42: At1Key(code=9, shift=True), # XK_asterisk
- 56: At1Key(code=9, shift=False), # XK_8
- 40: At1Key(code=10, shift=True), # XK_parenleft
- 57: At1Key(code=10, shift=False), # XK_9
- 41: At1Key(code=11, shift=True), # XK_parenright
- 48: At1Key(code=11, shift=False), # XK_0
- 45: At1Key(code=12, shift=False), # XK_minus
- 95: At1Key(code=12, shift=True), # XK_underscore
- 43: At1Key(code=13, shift=True), # XK_plus
- 61: At1Key(code=13, shift=False), # XK_equal
- 65288: At1Key(code=14, shift=False), # XK_BackSpace
- 65289: At1Key(code=15, shift=False), # XK_Tab
- 81: At1Key(code=16, shift=True), # XK_Q
- 113: At1Key(code=16, shift=False), # XK_q
- 87: At1Key(code=17, shift=True), # XK_W
- 119: At1Key(code=17, shift=False), # XK_w
- 69: At1Key(code=18, shift=True), # XK_E
- 101: At1Key(code=18, shift=False), # XK_e
- 82: At1Key(code=19, shift=True), # XK_R
- 114: At1Key(code=19, shift=False), # XK_r
- 84: At1Key(code=20, shift=True), # XK_T
- 116: At1Key(code=20, shift=False), # XK_t
- 89: At1Key(code=21, shift=True), # XK_Y
- 121: At1Key(code=21, shift=False), # XK_y
- 85: At1Key(code=22, shift=True), # XK_U
- 117: At1Key(code=22, shift=False), # XK_u
- 73: At1Key(code=23, shift=True), # XK_I
- 105: At1Key(code=23, shift=False), # XK_i
- 79: At1Key(code=24, shift=True), # XK_O
- 111: At1Key(code=24, shift=False), # XK_o
- 80: At1Key(code=25, shift=True), # XK_P
- 112: At1Key(code=25, shift=False), # XK_p
- 91: At1Key(code=26, shift=False), # XK_bracketleft
- 123: At1Key(code=26, shift=True), # XK_braceleft
- 93: At1Key(code=27, shift=False), # XK_bracketright
- 125: At1Key(code=27, shift=True), # XK_braceright
- 65293: At1Key(code=28, shift=False), # XK_Return
- 65507: At1Key(code=29, shift=False), # XK_Control_L
- 65: At1Key(code=30, shift=True), # XK_A
- 97: At1Key(code=30, shift=False), # XK_a
- 83: At1Key(code=31, shift=True), # XK_S
- 115: At1Key(code=31, shift=False), # XK_s
- 68: At1Key(code=32, shift=True), # XK_D
- 100: At1Key(code=32, shift=False), # XK_d
- 70: At1Key(code=33, shift=True), # XK_F
- 102: At1Key(code=33, shift=False), # XK_f
- 71: At1Key(code=34, shift=True), # XK_G
- 103: At1Key(code=34, shift=False), # XK_g
- 72: At1Key(code=35, shift=True), # XK_H
- 104: At1Key(code=35, shift=False), # XK_h
- 74: At1Key(code=36, shift=True), # XK_J
- 106: At1Key(code=36, shift=False), # XK_j
- 75: At1Key(code=37, shift=True), # XK_K
- 107: At1Key(code=37, shift=False), # XK_k
- 76: At1Key(code=38, shift=True), # XK_L
- 108: At1Key(code=38, shift=False), # XK_l
- 58: At1Key(code=39, shift=True), # XK_colon
- 59: At1Key(code=39, shift=False), # XK_semicolon
- 34: At1Key(code=40, shift=True), # XK_quotedbl
- 39: At1Key(code=40, shift=False), # XK_apostrophe
- 96: At1Key(code=41, shift=False), # XK_grave
- 126: At1Key(code=41, shift=True), # XK_asciitilde
- 65505: At1Key(code=42, shift=False), # XK_Shift_L
- 92: At1Key(code=43, shift=False), # XK_backslash
- 124: At1Key(code=43, shift=True), # XK_bar
- 90: At1Key(code=44, shift=True), # XK_Z
- 122: At1Key(code=44, shift=False), # XK_z
- 88: At1Key(code=45, shift=True), # XK_X
- 120: At1Key(code=45, shift=False), # XK_x
- 67: At1Key(code=46, shift=True), # XK_C
- 99: At1Key(code=46, shift=False), # XK_c
- 86: At1Key(code=47, shift=True), # XK_V
- 118: At1Key(code=47, shift=False), # XK_v
- 66: At1Key(code=48, shift=True), # XK_B
- 98: At1Key(code=48, shift=False), # XK_b
- 78: At1Key(code=49, shift=True), # XK_N
- 110: At1Key(code=49, shift=False), # XK_n
- 77: At1Key(code=50, shift=True), # XK_M
- 109: At1Key(code=50, shift=False), # XK_m
- 44: At1Key(code=51, shift=False), # XK_comma
- 60: At1Key(code=51, shift=True), # XK_less
- 46: At1Key(code=52, shift=False), # XK_period
- 62: At1Key(code=52, shift=True), # XK_greater
- 47: At1Key(code=53, shift=False), # XK_slash
- 63: At1Key(code=53, shift=True), # XK_question
- 65506: At1Key(code=54, shift=False), # XK_Shift_R
- 215: At1Key(code=55, shift=False), # XK_multiply
- 65513: At1Key(code=56, shift=False), # XK_Alt_L
- 32: At1Key(code=57, shift=False), # XK_space
- 65509: At1Key(code=58, shift=False), # XK_Caps_Lock
- 65470: At1Key(code=59, shift=False), # XK_F1
- 65471: At1Key(code=60, shift=False), # XK_F2
- 65472: At1Key(code=61, shift=False), # XK_F3
- 65473: At1Key(code=62, shift=False), # XK_F4
- 65474: At1Key(code=63, shift=False), # XK_F5
- 65475: At1Key(code=64, shift=False), # XK_F6
- 65476: At1Key(code=65, shift=False), # XK_F7
- 65477: At1Key(code=66, shift=False), # XK_F8
- 65478: At1Key(code=67, shift=False), # XK_F9
- 65479: At1Key(code=68, shift=False), # XK_F10
- 65407: At1Key(code=69, shift=False), # XK_Num_Lock
- 65300: At1Key(code=70, shift=False), # XK_Scroll_Lock
- 65463: At1Key(code=71, shift=False), # XK_KP_7
- 65464: At1Key(code=72, shift=False), # XK_KP_8
- 65465: At1Key(code=73, shift=False), # XK_KP_9
- 65453: At1Key(code=74, shift=False), # XK_KP_Subtract
- 65460: At1Key(code=75, shift=False), # XK_KP_4
- 65461: At1Key(code=76, shift=False), # XK_KP_5
- 65462: At1Key(code=77, shift=False), # XK_KP_6
- 65451: At1Key(code=78, shift=False), # XK_KP_Add
- 65457: At1Key(code=79, shift=False), # XK_KP_1
- 65458: At1Key(code=80, shift=False), # XK_KP_2
- 65459: At1Key(code=81, shift=False), # XK_KP_3
- 65456: At1Key(code=82, shift=False), # XK_KP_0
- 65454: At1Key(code=83, shift=False), # XK_KP_Decimal
- 65301: At1Key(code=84, shift=False), # XK_Sys_Req
- 65480: At1Key(code=87, shift=False), # XK_F11
- 65481: At1Key(code=88, shift=False), # XK_F12
- 65421: At1Key(code=57372, shift=False), # XK_KP_Enter
- 65508: At1Key(code=57373, shift=False), # XK_Control_R
- 65455: At1Key(code=57397, shift=False), # XK_KP_Divide
- 65027: At1Key(code=57400, shift=False), # XK_ISO_Level3_Shift
- 65514: At1Key(code=57400, shift=False), # XK_Alt_R
- 65299: At1Key(code=57414, shift=False), # XK_Pause
- 65360: At1Key(code=57415, shift=False), # XK_Home
- 65362: At1Key(code=57416, shift=False), # XK_Up
- 65365: At1Key(code=57417, shift=False), # XK_Page_Up
- 65361: At1Key(code=57419, shift=False), # XK_Left
- 65363: At1Key(code=57421, shift=False), # XK_Right
- 65367: At1Key(code=57423, shift=False), # XK_End
- 65364: At1Key(code=57424, shift=False), # XK_Down
- 65366: At1Key(code=57425, shift=False), # XK_Page_Down
- 65379: At1Key(code=57426, shift=False), # XK_Insert
- 65535: At1Key(code=57427, shift=False), # XK_Delete
- 65511: At1Key(code=57435, shift=False), # XK_Meta_L
- 65515: At1Key(code=57435, shift=False), # XK_Super_L
- 65512: At1Key(code=57436, shift=False), # XK_Meta_R
- 65516: At1Key(code=57436, shift=False), # XK_Super_R
- 65383: At1Key(code=57437, shift=False), # XK_Menu
- 269025071: At1Key(code=57438, shift=False), # XK_XF86_Sleep
+ 65307: [At1Key(code=1, shift=False)], # XK_Escape
+ 33: [At1Key(code=2, shift=True)], # XK_exclam
+ 49: [At1Key(code=2, shift=False)], # XK_1
+ 50: [At1Key(code=3, shift=False)], # XK_2
+ 64: [At1Key(code=3, shift=True)], # XK_at
+ 35: [At1Key(code=4, shift=True)], # XK_numbersign
+ 51: [At1Key(code=4, shift=False)], # XK_3
+ 36: [At1Key(code=5, shift=True)], # XK_dollar
+ 52: [At1Key(code=5, shift=False)], # XK_4
+ 37: [At1Key(code=6, shift=True)], # XK_percent
+ 53: [At1Key(code=6, shift=False)], # XK_5
+ 54: [At1Key(code=7, shift=False)], # XK_6
+ 94: [At1Key(code=7, shift=True)], # XK_asciicircum
+ 38: [At1Key(code=8, shift=True)], # XK_ampersand
+ 55: [At1Key(code=8, shift=False)], # XK_7
+ 42: [At1Key(code=9, shift=True)], # XK_asterisk
+ 56: [At1Key(code=9, shift=False)], # XK_8
+ 40: [At1Key(code=10, shift=True)], # XK_parenleft
+ 57: [At1Key(code=10, shift=False)], # XK_9
+ 41: [At1Key(code=11, shift=True)], # XK_parenright
+ 48: [At1Key(code=11, shift=False)], # XK_0
+ 45: [At1Key(code=12, shift=False)], # XK_minus
+ 95: [At1Key(code=12, shift=True)], # XK_underscore
+ 43: [At1Key(code=13, shift=True)], # XK_plus
+ 61: [At1Key(code=13, shift=False)], # XK_equal
+ 65288: [At1Key(code=14, shift=False)], # XK_BackSpace
+ 65289: [At1Key(code=15, shift=False)], # XK_Tab
+ 81: [At1Key(code=16, shift=True)], # XK_Q
+ 113: [At1Key(code=16, shift=False)], # XK_q
+ 87: [At1Key(code=17, shift=True)], # XK_W
+ 119: [At1Key(code=17, shift=False)], # XK_w
+ 69: [At1Key(code=18, shift=True)], # XK_E
+ 101: [At1Key(code=18, shift=False)], # XK_e
+ 82: [At1Key(code=19, shift=True)], # XK_R
+ 114: [At1Key(code=19, shift=False)], # XK_r
+ 84: [At1Key(code=20, shift=True)], # XK_T
+ 116: [At1Key(code=20, shift=False)], # XK_t
+ 89: [At1Key(code=21, shift=True)], # XK_Y
+ 121: [At1Key(code=21, shift=False)], # XK_y
+ 85: [At1Key(code=22, shift=True)], # XK_U
+ 117: [At1Key(code=22, shift=False)], # XK_u
+ 73: [At1Key(code=23, shift=True)], # XK_I
+ 105: [At1Key(code=23, shift=False)], # XK_i
+ 79: [At1Key(code=24, shift=True)], # XK_O
+ 111: [At1Key(code=24, shift=False)], # XK_o
+ 80: [At1Key(code=25, shift=True)], # XK_P
+ 112: [At1Key(code=25, shift=False)], # XK_p
+ 91: [At1Key(code=26, shift=False)], # XK_bracketleft
+ 123: [At1Key(code=26, shift=True)], # XK_braceleft
+ 93: [At1Key(code=27, shift=False)], # XK_bracketright
+ 125: [At1Key(code=27, shift=True)], # XK_braceright
+ 65293: [At1Key(code=28, shift=False)], # XK_Return
+ 65507: [At1Key(code=29, shift=False)], # XK_Control_L
+ 65: [At1Key(code=30, shift=True)], # XK_A
+ 97: [At1Key(code=30, shift=False)], # XK_a
+ 83: [At1Key(code=31, shift=True)], # XK_S
+ 115: [At1Key(code=31, shift=False)], # XK_s
+ 68: [At1Key(code=32, shift=True)], # XK_D
+ 100: [At1Key(code=32, shift=False)], # XK_d
+ 70: [At1Key(code=33, shift=True)], # XK_F
+ 102: [At1Key(code=33, shift=False)], # XK_f
+ 71: [At1Key(code=34, shift=True)], # XK_G
+ 103: [At1Key(code=34, shift=False)], # XK_g
+ 72: [At1Key(code=35, shift=True)], # XK_H
+ 104: [At1Key(code=35, shift=False)], # XK_h
+ 74: [At1Key(code=36, shift=True)], # XK_J
+ 106: [At1Key(code=36, shift=False)], # XK_j
+ 75: [At1Key(code=37, shift=True)], # XK_K
+ 107: [At1Key(code=37, shift=False)], # XK_k
+ 76: [At1Key(code=38, shift=True)], # XK_L
+ 108: [At1Key(code=38, shift=False)], # XK_l
+ 58: [At1Key(code=39, shift=True)], # XK_colon
+ 59: [At1Key(code=39, shift=False)], # XK_semicolon
+ 34: [At1Key(code=40, shift=True)], # XK_quotedbl
+ 39: [At1Key(code=40, shift=False)], # XK_apostrophe
+ 96: [At1Key(code=41, shift=False)], # XK_grave
+ 126: [At1Key(code=41, shift=True)], # XK_asciitilde
+ 65505: [At1Key(code=42, shift=False)], # XK_Shift_L
+ 92: [At1Key(code=43, shift=False)], # XK_backslash
+ 124: [At1Key(code=43, shift=True)], # XK_bar
+ 90: [At1Key(code=44, shift=True)], # XK_Z
+ 122: [At1Key(code=44, shift=False)], # XK_z
+ 88: [At1Key(code=45, shift=True)], # XK_X
+ 120: [At1Key(code=45, shift=False)], # XK_x
+ 67: [At1Key(code=46, shift=True)], # XK_C
+ 99: [At1Key(code=46, shift=False)], # XK_c
+ 86: [At1Key(code=47, shift=True)], # XK_V
+ 118: [At1Key(code=47, shift=False)], # XK_v
+ 66: [At1Key(code=48, shift=True)], # XK_B
+ 98: [At1Key(code=48, shift=False)], # XK_b
+ 78: [At1Key(code=49, shift=True)], # XK_N
+ 110: [At1Key(code=49, shift=False)], # XK_n
+ 77: [At1Key(code=50, shift=True)], # XK_M
+ 109: [At1Key(code=50, shift=False)], # XK_m
+ 44: [At1Key(code=51, shift=False)], # XK_comma
+ 60: [At1Key(code=51, shift=True)], # XK_less
+ 46: [At1Key(code=52, shift=False)], # XK_period
+ 62: [At1Key(code=52, shift=True)], # XK_greater
+ 47: [At1Key(code=53, shift=False)], # XK_slash
+ 63: [At1Key(code=53, shift=True)], # XK_question
+ 65506: [At1Key(code=54, shift=False)], # XK_Shift_R
+ 215: [At1Key(code=55, shift=False)], # XK_multiply
+ 65513: [At1Key(code=56, shift=False)], # XK_Alt_L
+ 32: [At1Key(code=57, shift=False)], # XK_space
+ 65509: [At1Key(code=58, shift=False)], # XK_Caps_Lock
+ 65470: [At1Key(code=59, shift=False)], # XK_F1
+ 65471: [At1Key(code=60, shift=False)], # XK_F2
+ 65472: [At1Key(code=61, shift=False)], # XK_F3
+ 65473: [At1Key(code=62, shift=False)], # XK_F4
+ 65474: [At1Key(code=63, shift=False)], # XK_F5
+ 65475: [At1Key(code=64, shift=False)], # XK_F6
+ 65476: [At1Key(code=65, shift=False)], # XK_F7
+ 65477: [At1Key(code=66, shift=False)], # XK_F8
+ 65478: [At1Key(code=67, shift=False)], # XK_F9
+ 65479: [At1Key(code=68, shift=False)], # XK_F10
+ 65407: [At1Key(code=69, shift=False)], # XK_Num_Lock
+ 65300: [At1Key(code=70, shift=False)], # XK_Scroll_Lock
+ 65463: [At1Key(code=71, shift=False)], # XK_KP_7
+ 65464: [At1Key(code=72, shift=False)], # XK_KP_8
+ 65465: [At1Key(code=73, shift=False)], # XK_KP_9
+ 65453: [At1Key(code=74, shift=False)], # XK_KP_Subtract
+ 65460: [At1Key(code=75, shift=False)], # XK_KP_4
+ 65461: [At1Key(code=76, shift=False)], # XK_KP_5
+ 65462: [At1Key(code=77, shift=False)], # XK_KP_6
+ 65451: [At1Key(code=78, shift=False)], # XK_KP_Add
+ 65457: [At1Key(code=79, shift=False)], # XK_KP_1
+ 65458: [At1Key(code=80, shift=False)], # XK_KP_2
+ 65459: [At1Key(code=81, shift=False)], # XK_KP_3
+ 65456: [At1Key(code=82, shift=False)], # XK_KP_0
+ 65454: [At1Key(code=83, shift=False)], # XK_KP_Decimal
+ 65301: [At1Key(code=84, shift=False)], # XK_Sys_Req
+ 65480: [At1Key(code=87, shift=False)], # XK_F11
+ 65481: [At1Key(code=88, shift=False)], # XK_F12
+ 65421: [At1Key(code=57372, shift=False)], # XK_KP_Enter
+ 65508: [At1Key(code=57373, shift=False)], # XK_Control_R
+ 65455: [At1Key(code=57397, shift=False)], # XK_KP_Divide
+ 65027: [At1Key(code=57400, shift=False)], # XK_ISO_Level3_Shift
+ 65514: [At1Key(code=57400, shift=False)], # XK_Alt_R
+ 65299: [At1Key(code=57414, shift=False)], # XK_Pause
+ 65360: [At1Key(code=57415, shift=False)], # XK_Home
+ 65362: [At1Key(code=57416, shift=False)], # XK_Up
+ 65365: [At1Key(code=57417, shift=False)], # XK_Page_Up
+ 65361: [At1Key(code=57419, shift=False)], # XK_Left
+ 65363: [At1Key(code=57421, shift=False)], # XK_Right
+ 65367: [At1Key(code=57423, shift=False)], # XK_End
+ 65364: [At1Key(code=57424, shift=False)], # XK_Down
+ 65366: [At1Key(code=57425, shift=False)], # XK_Page_Down
+ 65379: [At1Key(code=57426, shift=False)], # XK_Insert
+ 65535: [At1Key(code=57427, shift=False)], # XK_Delete
+ 65511: [At1Key(code=57435, shift=False)], # XK_Meta_L
+ 65515: [At1Key(code=57435, shift=False)], # XK_Super_L
+ 65512: [At1Key(code=57436, shift=False)], # XK_Meta_R
+ 65516: [At1Key(code=57436, shift=False)], # XK_Super_R
+ 65383: [At1Key(code=57437, shift=False)], # XK_Menu
+ 269025071: [At1Key(code=57438, shift=False)], # XK_XF86_Sleep
}
diff --git a/kvmd/keyboard/mappings.py.mako b/kvmd/keyboard/mappings.py.mako
index 35b3b281..1c13b8a9 100644
--- a/kvmd/keyboard/mappings.py.mako
+++ b/kvmd/keyboard/mappings.py.mako
@@ -62,7 +62,7 @@ class At1Key:
X11_TO_AT1 = {
% for km in sorted(keymap, key=operator.attrgetter("at1_code")):
% for x11_key in sorted(km.x11_keys, key=(lambda key: (key.code, key.shift))):
- ${x11_key.code}: At1Key(code=${km.at1_code}, shift=${x11_key.shift}), # ${x11_key.name}
+ ${x11_key.code}: [At1Key(code=${km.at1_code}, shift=${x11_key.shift})], # ${x11_key.name}
% endfor
% endfor
}
diff --git a/kvmd/keyboard/printer.py b/kvmd/keyboard/printer.py
index 2fb7d756..acef102b 100644
--- a/kvmd/keyboard/printer.py
+++ b/kvmd/keyboard/printer.py
@@ -24,13 +24,13 @@ from typing import Tuple
from typing import Dict
from typing import Generator
-from .keysym import SymmapWebKey
+from .keysym import SymmapModifiers
# =====
def text_to_web_keys(
text: str,
- symmap: Dict[int, SymmapWebKey],
+ symmap: Dict[int, Dict[int, str]],
shift_key: str="ShiftLeft",
) -> Generator[Tuple[str, bool], None, None]:
@@ -40,25 +40,32 @@ def text_to_web_keys(
for ch in text:
try:
code = ord(ch)
- if not (0x20 <= code <= 0x7E):
+ if 0x20 <= code <= 0x7E:
# https://stackoverflow.com/questions/12343987/convert-ascii-character-to-x11-keycode
# https://www.ascii-code.com
+ keys = symmap[code]
+ elif code == 0x0A: # Enter:
+ keys = {0: "Enter"}
+ else:
continue
- key = symmap[code]
except Exception:
continue
- if key.altgr or key.ctrl:
- continue # Not supported yet
- if key.shift and not shifted:
- yield (shift_key, True)
- shifted = True
- elif not key.shift and shifted:
- yield (shift_key, False)
- shifted = False
+ for (modifiers, key) in reversed(keys.items()):
+ if (modifiers & SymmapModifiers.ALTGR) or (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
- yield (key.name, True)
- yield (key.name, False)
+ yield (key, True)
+ yield (key, False)
+ break
if shifted:
yield (shift_key, False)