mirror of
https://github.com/mofeng-git/One-KVM.git
synced 2025-12-12 17:20:30 +08:00
vnc: common key event handler
This commit is contained in:
parent
8fb4bc6be7
commit
1356187771
@ -34,6 +34,10 @@ from ....logging import get_logger
|
|||||||
from .... import tools
|
from .... import tools
|
||||||
from .... import aiotools
|
from .... import aiotools
|
||||||
|
|
||||||
|
from ....keyboard.keysym import SymmapModifiers
|
||||||
|
from ....keyboard.mappings import EvdevModifiers
|
||||||
|
from ....keyboard.mappings import X11Modifiers
|
||||||
|
from ....keyboard.mappings import AT1_TO_EVDEV
|
||||||
from ....mouse import MouseRange
|
from ....mouse import MouseRange
|
||||||
|
|
||||||
from .errors import RfbError
|
from .errors import RfbError
|
||||||
@ -71,6 +75,7 @@ class RfbClient(RfbClientStream): # pylint: disable=too-many-instance-attribute
|
|||||||
width: int,
|
width: int,
|
||||||
height: int,
|
height: int,
|
||||||
name: str,
|
name: str,
|
||||||
|
symmap: dict[int, dict[int, int]],
|
||||||
scroll_rate: int,
|
scroll_rate: int,
|
||||||
|
|
||||||
vncpasses: set[str],
|
vncpasses: set[str],
|
||||||
@ -89,6 +94,7 @@ class RfbClient(RfbClientStream): # pylint: disable=too-many-instance-attribute
|
|||||||
self._height = height
|
self._height = height
|
||||||
self.__name = name
|
self.__name = name
|
||||||
self.__scroll_rate = scroll_rate
|
self.__scroll_rate = scroll_rate
|
||||||
|
self.__symmap = symmap
|
||||||
|
|
||||||
self.__vncpasses = vncpasses
|
self.__vncpasses = vncpasses
|
||||||
self.__vencrypt = vencrypt
|
self.__vencrypt = vencrypt
|
||||||
@ -105,6 +111,9 @@ class RfbClient(RfbClientStream): # pylint: disable=too-many-instance-attribute
|
|||||||
|
|
||||||
self.__lock = asyncio.Lock()
|
self.__lock = asyncio.Lock()
|
||||||
|
|
||||||
|
# Эти состояния шарить не обязательно - бекенд исключает дублирующиеся события.
|
||||||
|
# Все это нужно только чтобы не посылать лишние события в сокет KVMD
|
||||||
|
self.__modifiers = 0
|
||||||
self.__mouse_buttons: dict[int, bool] = {}
|
self.__mouse_buttons: dict[int, bool] = {}
|
||||||
self.__mouse_move = (-1, -1, -1, -1) # (width, height, X, Y)
|
self.__mouse_move = (-1, -1, -1, -1) # (width, height, X, Y)
|
||||||
|
|
||||||
@ -164,10 +173,7 @@ class RfbClient(RfbClientStream): # pylint: disable=too-many-instance-attribute
|
|||||||
|
|
||||||
# =====
|
# =====
|
||||||
|
|
||||||
async def _on_key_event(self, code: int, state: bool) -> None:
|
async def _on_key_event(self, key: int, state: bool) -> None:
|
||||||
raise NotImplementedError
|
|
||||||
|
|
||||||
async def _on_ext_key_event(self, code: int, state: bool) -> None:
|
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
async def _on_mouse_button_event(self, button: int, state: bool) -> None:
|
async def _on_mouse_button_event(self, button: int, state: bool) -> None:
|
||||||
@ -509,7 +515,64 @@ class RfbClient(RfbClientStream): # pylint: disable=too-many-instance-attribute
|
|||||||
|
|
||||||
async def __handle_key_event(self) -> None:
|
async def __handle_key_event(self) -> None:
|
||||||
(state, code) = await self._read_struct("key event", "? xx L")
|
(state, code) = await self._read_struct("key event", "? xx L")
|
||||||
await self._on_key_event(code, state) # type: ignore
|
state = bool(state)
|
||||||
|
|
||||||
|
is_modifier = self.__switch_modifiers_x11(code, state)
|
||||||
|
variants = self.__symmap.get(code)
|
||||||
|
fake_shift = False
|
||||||
|
|
||||||
|
if variants:
|
||||||
|
if is_modifier:
|
||||||
|
key = variants.get(0)
|
||||||
|
else:
|
||||||
|
key = variants.get(self.__modifiers)
|
||||||
|
if key is None:
|
||||||
|
key = variants.get(0)
|
||||||
|
|
||||||
|
if key is None and self.__modifiers == 0 and SymmapModifiers.SHIFT in variants:
|
||||||
|
# JUMP doesn't send shift events:
|
||||||
|
# - https://github.com/pikvm/pikvm/issues/820
|
||||||
|
key = variants[SymmapModifiers.SHIFT]
|
||||||
|
fake_shift = True
|
||||||
|
|
||||||
|
if key:
|
||||||
|
if fake_shift:
|
||||||
|
await self._on_key_event(EvdevModifiers.SHIFT_LEFT, True)
|
||||||
|
await self._on_key_event(key, state)
|
||||||
|
if fake_shift:
|
||||||
|
await self._on_key_event(EvdevModifiers.SHIFT_LEFT, False)
|
||||||
|
|
||||||
|
def __switch_modifiers_x11(self, code: int, state: bool) -> bool:
|
||||||
|
mod = 0
|
||||||
|
if code in X11Modifiers.SHIFTS:
|
||||||
|
mod = SymmapModifiers.SHIFT
|
||||||
|
elif code == X11Modifiers.ALTGR:
|
||||||
|
mod = SymmapModifiers.ALTGR
|
||||||
|
elif code in X11Modifiers.CTRLS:
|
||||||
|
mod = SymmapModifiers.CTRL
|
||||||
|
if mod == 0:
|
||||||
|
return False
|
||||||
|
if state:
|
||||||
|
self.__modifiers |= mod
|
||||||
|
else:
|
||||||
|
self.__modifiers &= ~mod
|
||||||
|
return True
|
||||||
|
|
||||||
|
def __switch_modifiers_evdev(self, key: int, state: bool) -> bool:
|
||||||
|
mod = 0
|
||||||
|
if key in EvdevModifiers.SHIFTS:
|
||||||
|
mod = SymmapModifiers.SHIFT
|
||||||
|
elif key == EvdevModifiers.ALT_RIGHT:
|
||||||
|
mod = SymmapModifiers.ALTGR
|
||||||
|
elif key in EvdevModifiers.CTRLS:
|
||||||
|
mod = SymmapModifiers.CTRL
|
||||||
|
if mod == 0:
|
||||||
|
return False
|
||||||
|
if state:
|
||||||
|
self.__modifiers |= mod
|
||||||
|
else:
|
||||||
|
self.__modifiers &= ~mod
|
||||||
|
return True
|
||||||
|
|
||||||
async def __handle_pointer_event(self) -> None:
|
async def __handle_pointer_event(self) -> None:
|
||||||
(buttons, to_x, to_y) = await self._read_struct("pointer event", "B HH")
|
(buttons, to_x, to_y) = await self._read_struct("pointer event", "B HH")
|
||||||
@ -559,6 +622,7 @@ class RfbClient(RfbClientStream): # pylint: disable=too-many-instance-attribute
|
|||||||
|
|
||||||
async def __handle_qemu_event(self) -> None:
|
async def __handle_qemu_event(self) -> None:
|
||||||
(sub_type, state, code) = await self._read_struct("QEMU event (key?)", "B H xxxx L")
|
(sub_type, state, code) = await self._read_struct("QEMU event (key?)", "B H xxxx L")
|
||||||
|
state = bool(state)
|
||||||
if sub_type != 0:
|
if sub_type != 0:
|
||||||
raise RfbError(f"Invalid QEMU sub-message type: {sub_type}")
|
raise RfbError(f"Invalid QEMU sub-message type: {sub_type}")
|
||||||
if code == 0xB7:
|
if code == 0xB7:
|
||||||
@ -566,4 +630,7 @@ class RfbClient(RfbClientStream): # pylint: disable=too-many-instance-attribute
|
|||||||
code = 0x54
|
code = 0x54
|
||||||
if code & 0x80:
|
if code & 0x80:
|
||||||
code = (0xE0 << 8) | (code & ~0x80)
|
code = (0xE0 << 8) | (code & ~0x80)
|
||||||
await self._on_ext_key_event(code, bool(state))
|
key = AT1_TO_EVDEV.get(code, 0)
|
||||||
|
if key:
|
||||||
|
self.__switch_modifiers_evdev(key, state) # Предполагаем, что модификаторы всегда известны
|
||||||
|
await self._on_key_event(key, state)
|
||||||
|
|||||||
@ -31,11 +31,7 @@ import async_lru
|
|||||||
|
|
||||||
from ...logging import get_logger
|
from ...logging import get_logger
|
||||||
|
|
||||||
from ...keyboard.keysym import SymmapModifiers
|
|
||||||
from ...keyboard.keysym import build_symmap
|
from ...keyboard.keysym import build_symmap
|
||||||
from ...keyboard.mappings import EvdevModifiers
|
|
||||||
from ...keyboard.mappings import X11Modifiers
|
|
||||||
from ...keyboard.mappings import AT1_TO_EVDEV
|
|
||||||
from ...keyboard.magic import BaseMagicHandler
|
from ...keyboard.magic import BaseMagicHandler
|
||||||
|
|
||||||
from ...clients.kvmd import KvmdClientWs
|
from ...clients.kvmd import KvmdClientWs
|
||||||
@ -100,6 +96,7 @@ class _Client(RfbClient, BaseMagicHandler): # pylint: disable=too-many-instance
|
|||||||
tls_timeout=tls_timeout,
|
tls_timeout=tls_timeout,
|
||||||
x509_cert_path=x509_cert_path,
|
x509_cert_path=x509_cert_path,
|
||||||
x509_key_path=x509_key_path,
|
x509_key_path=x509_key_path,
|
||||||
|
symmap=symmap,
|
||||||
scroll_rate=scroll_rate,
|
scroll_rate=scroll_rate,
|
||||||
vncpasses=vncpasses,
|
vncpasses=vncpasses,
|
||||||
vencrypt=vencrypt,
|
vencrypt=vencrypt,
|
||||||
@ -111,7 +108,6 @@ class _Client(RfbClient, BaseMagicHandler): # pylint: disable=too-many-instance
|
|||||||
self.__desired_fps = desired_fps
|
self.__desired_fps = desired_fps
|
||||||
self.__mouse_output = mouse_output
|
self.__mouse_output = mouse_output
|
||||||
self.__keymap_name = keymap_name
|
self.__keymap_name = keymap_name
|
||||||
self.__symmap = symmap
|
|
||||||
|
|
||||||
self.__kvmd = kvmd
|
self.__kvmd = kvmd
|
||||||
self.__streamers = streamers
|
self.__streamers = streamers
|
||||||
@ -128,10 +124,6 @@ class _Client(RfbClient, BaseMagicHandler): # pylint: disable=too-many-instance
|
|||||||
self.__fb_queue: "asyncio.Queue[dict]" = asyncio.Queue()
|
self.__fb_queue: "asyncio.Queue[dict]" = asyncio.Queue()
|
||||||
self.__fb_has_key = False
|
self.__fb_has_key = False
|
||||||
|
|
||||||
# Эти состояния шарить не обязательно - бекенд исключает дублирующиеся события.
|
|
||||||
# Все это нужно только чтобы не посылать лишние жсоны в сокет KVMD
|
|
||||||
self.__modifiers = 0
|
|
||||||
|
|
||||||
self.__clipboard = ""
|
self.__clipboard = ""
|
||||||
|
|
||||||
self.__info_host = ""
|
self.__info_host = ""
|
||||||
@ -349,72 +341,9 @@ class _Client(RfbClient, BaseMagicHandler): # pylint: disable=too-many-instance
|
|||||||
|
|
||||||
# =====
|
# =====
|
||||||
|
|
||||||
async def _on_key_event(self, code: int, state: bool) -> None:
|
async def _on_key_event(self, key: int, state: bool) -> None:
|
||||||
assert self.__stage1_authorized.is_passed()
|
assert self.__stage1_authorized.is_passed()
|
||||||
|
|
||||||
is_modifier = self.__switch_modifiers_x11(code, state)
|
|
||||||
variants = self.__symmap.get(code)
|
|
||||||
fake_shift = False
|
|
||||||
|
|
||||||
if variants:
|
|
||||||
if is_modifier:
|
|
||||||
key = variants.get(0)
|
|
||||||
else:
|
|
||||||
key = variants.get(self.__modifiers)
|
|
||||||
if key is None:
|
|
||||||
key = variants.get(0)
|
|
||||||
|
|
||||||
if key is None and self.__modifiers == 0 and SymmapModifiers.SHIFT in variants:
|
|
||||||
# JUMP doesn't send shift events:
|
|
||||||
# - https://github.com/pikvm/pikvm/issues/820
|
|
||||||
key = variants[SymmapModifiers.SHIFT]
|
|
||||||
fake_shift = True
|
|
||||||
|
|
||||||
if key:
|
|
||||||
if fake_shift:
|
|
||||||
await self._magic_handle_key(EvdevModifiers.SHIFT_LEFT, True)
|
|
||||||
await self._magic_handle_key(key, state)
|
await self._magic_handle_key(key, state)
|
||||||
if fake_shift:
|
|
||||||
await self._magic_handle_key(EvdevModifiers.SHIFT_LEFT, False)
|
|
||||||
|
|
||||||
async def _on_ext_key_event(self, code: int, state: bool) -> None:
|
|
||||||
assert self.__stage1_authorized.is_passed()
|
|
||||||
key = AT1_TO_EVDEV.get(code, 0)
|
|
||||||
if key:
|
|
||||||
self.__switch_modifiers_evdev(key, state) # Предполагаем, что модификаторы всегда известны
|
|
||||||
await self._magic_handle_key(key, state)
|
|
||||||
|
|
||||||
def __switch_modifiers_x11(self, key: int, state: bool) -> bool:
|
|
||||||
mod = 0
|
|
||||||
if key in X11Modifiers.SHIFTS:
|
|
||||||
mod = SymmapModifiers.SHIFT
|
|
||||||
elif key == X11Modifiers.ALTGR:
|
|
||||||
mod = SymmapModifiers.ALTGR
|
|
||||||
elif key in X11Modifiers.CTRLS:
|
|
||||||
mod = SymmapModifiers.CTRL
|
|
||||||
if mod == 0:
|
|
||||||
return False
|
|
||||||
if state:
|
|
||||||
self.__modifiers |= mod
|
|
||||||
else:
|
|
||||||
self.__modifiers &= ~mod
|
|
||||||
return True
|
|
||||||
|
|
||||||
def __switch_modifiers_evdev(self, key: int, state: bool) -> bool:
|
|
||||||
mod = 0
|
|
||||||
if key in EvdevModifiers.SHIFTS:
|
|
||||||
mod = SymmapModifiers.SHIFT
|
|
||||||
elif key == EvdevModifiers.ALT_RIGHT:
|
|
||||||
mod = SymmapModifiers.ALTGR
|
|
||||||
elif key in EvdevModifiers.CTRLS:
|
|
||||||
mod = SymmapModifiers.CTRL
|
|
||||||
if mod == 0:
|
|
||||||
return False
|
|
||||||
if state:
|
|
||||||
self.__modifiers |= mod
|
|
||||||
else:
|
|
||||||
self.__modifiers &= ~mod
|
|
||||||
return True
|
|
||||||
|
|
||||||
async def _on_magic_switch_prev(self) -> None:
|
async def _on_magic_switch_prev(self) -> None:
|
||||||
assert self.__kvmd_session
|
assert self.__kvmd_session
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user