From a66221a494e35ab070d13291ce82928797bf95d4 Mon Sep 17 00:00:00 2001 From: Devaev Maxim Date: Fri, 26 Mar 2021 21:32:21 +0300 Subject: fixed mouse remap --- kvmd/apps/__init__.py | 10 ++++++---- kvmd/apps/kvmd/api/hid.py | 21 +++++++++++++++------ kvmd/apps/vnc/rfb/__init__.py | 7 +++++-- kvmd/mouse.py | 34 ++++++++++++++++++++++++++++++++++ kvmd/plugins/hid/_mcu/proto.py | 6 ++++-- kvmd/plugins/hid/otg/events.py | 10 ++++++---- kvmd/tools.py | 5 +++++ kvmd/validators/hid.py | 6 ++++-- 8 files changed, 79 insertions(+), 20 deletions(-) create mode 100644 kvmd/mouse.py (limited to 'kvmd') diff --git a/kvmd/apps/__init__.py b/kvmd/apps/__init__.py index aa724979..cb5666b9 100644 --- a/kvmd/apps/__init__.py +++ b/kvmd/apps/__init__.py @@ -39,6 +39,8 @@ import pygments.formatters from .. import tools +from ..mouse import MouseRange + from ..plugins import UnknownPluginError from ..plugins.auth import get_auth_service_class from ..plugins.hid import get_hid_class @@ -367,13 +369,13 @@ def _get_config_scheme() -> Dict: "keymap": Option("/usr/share/kvmd/keymaps/en-us", type=valid_abs_file), "mouse_x_range": { - "min": Option(-32768, type=valid_hid_mouse_move), - "max": Option(32767, type=valid_hid_mouse_move), + "min": Option(MouseRange.MIN, type=valid_hid_mouse_move), + "max": Option(MouseRange.MAX, type=valid_hid_mouse_move), }, "mouse_y_range": { - "min": Option(-32768, type=valid_hid_mouse_move), - "max": Option(32767, type=valid_hid_mouse_move), + "min": Option(MouseRange.MIN, type=valid_hid_mouse_move), + "max": Option(MouseRange.MAX, type=valid_hid_mouse_move), }, # Dynamic content diff --git a/kvmd/apps/kvmd/api/hid.py b/kvmd/apps/kvmd/api/hid.py index d9a39a00..418e065d 100644 --- a/kvmd/apps/kvmd/api/hid.py +++ b/kvmd/apps/kvmd/api/hid.py @@ -33,6 +33,8 @@ from aiohttp.web import Request from aiohttp.web import Response from aiohttp.web import WebSocketResponse +from ....mouse import MouseRange + from ....plugins.hid import BaseHid from ....validators import raise_error @@ -169,11 +171,11 @@ class HidApi: @exposed_ws("mouse_move") async def __ws_mouse_move_handler(self, _: WebSocketResponse, event: Dict) -> None: try: - to_x = valid_hid_mouse_move(event["to"]["x"], *self.__mouse_x_range) - to_y = valid_hid_mouse_move(event["to"]["y"], *self.__mouse_y_range) + to_x = valid_hid_mouse_move(event["to"]["x"]) + to_y = valid_hid_mouse_move(event["to"]["y"]) except Exception: return - self.__hid.send_mouse_move_event(to_x, to_y) + self.__send_mouse_move_event_remapped(to_x, to_y) @exposed_ws("mouse_relative") async def __ws_mouse_relative_handler(self, _: WebSocketResponse, event: Dict) -> None: @@ -232,9 +234,9 @@ class HidApi: @exposed_http("POST", "/hid/events/send_mouse_move") async def __events_send_mouse_move_handler(self, request: Request) -> Response: - to_x = valid_hid_mouse_move(request.query.get("to_x"), *self.__mouse_x_range) - to_y = valid_hid_mouse_move(request.query.get("to_y"), *self.__mouse_y_range) - self.__hid.send_mouse_move_event(to_x, to_y) + to_x = valid_hid_mouse_move(request.query.get("to_x")) + to_y = valid_hid_mouse_move(request.query.get("to_y")) + self.__send_mouse_move_event_remapped(to_x, to_y) return make_json_response() @exposed_http("POST", "/hid/events/send_mouse_relative") @@ -245,6 +247,13 @@ class HidApi: async def __events_send_mouse_wheel_handler(self, request: Request) -> Response: return self.__process_delta_request(request, self.__hid.send_mouse_wheel_event) + def __send_mouse_move_event_remapped(self, to_x: int, to_y: int) -> None: + if self.__mouse_x_range != MouseRange.RANGE: + to_x = MouseRange.remap(to_x, *self.__mouse_x_range) + if self.__mouse_y_range != MouseRange.RANGE: + to_y = MouseRange.remap(to_y, *self.__mouse_y_range) + self.__hid.send_mouse_move_event(to_x, to_y) + def __process_delta_request(self, request: Request, handler: Callable[[int, int], None]) -> Response: delta_x = valid_hid_mouse_delta(request.query.get("delta_x")) delta_y = valid_hid_mouse_delta(request.query.get("delta_y")) diff --git a/kvmd/apps/vnc/rfb/__init__.py b/kvmd/apps/vnc/rfb/__init__.py index 48805f27..8eff691a 100644 --- a/kvmd/apps/vnc/rfb/__init__.py +++ b/kvmd/apps/vnc/rfb/__init__.py @@ -32,8 +32,11 @@ from typing import Coroutine from ....logging import get_logger +from .... import tools from .... import aiotools +from ....mouse import MouseRange + from .errors import RfbError from .errors import RfbConnectionError @@ -444,8 +447,8 @@ class RfbClient(RfbClientStream): # pylint: disable=too-many-instance-attribute "y": (-4 if buttons & 0x10 else (4 if buttons & 0x8 else 0)), }, move={ - "x": round(to_x / self._width * 65535 + -32768), - "y": round(to_y / self._height * 65535 + -32768), + "x": tools.remap(to_x, 0, self._width, *MouseRange.RANGE), + "y": tools.remap(to_y, 0, self._height, *MouseRange.RANGE), }, ) diff --git a/kvmd/mouse.py b/kvmd/mouse.py new file mode 100644 index 00000000..53fa98b5 --- /dev/null +++ b/kvmd/mouse.py @@ -0,0 +1,34 @@ +# ========================================================================== # +# # +# KVMD - The main Pi-KVM daemon. # +# # +# Copyright (C) 2018-2021 Maxim Devaev # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see . # +# # +# ========================================================================== # + + +from . import tools + + +# ===== +class MouseRange: + MIN = -32768 + MAX = 32767 + RANGE = (MIN, MAX) + + @classmethod + def remap(cls, value: int, out_min: int, out_max: int) -> int: + return tools.remap(value, cls.MIN, cls.MAX, out_min, out_max) diff --git a/kvmd/plugins/hid/_mcu/proto.py b/kvmd/plugins/hid/_mcu/proto.py index 90f47508..bc3feafa 100644 --- a/kvmd/plugins/hid/_mcu/proto.py +++ b/kvmd/plugins/hid/_mcu/proto.py @@ -25,6 +25,8 @@ import struct from ....keyboard.mappings import KEYMAP +from ....mouse import MouseRange + from .... import tools @@ -143,8 +145,8 @@ class MouseMoveEvent(BaseEvent): to_y: int def __post_init__(self) -> None: - assert -32768 <= self.to_x <= 32767 - assert -32768 <= self.to_y <= 32767 + assert MouseRange.MIN <= self.to_x <= MouseRange.MAX + assert MouseRange.MIN <= self.to_y <= MouseRange.MAX def make_request(self) -> bytes: return _make_request(struct.pack(">Bhh", 0x12, self.to_x, self.to_y)) diff --git a/kvmd/plugins/hid/otg/events.py b/kvmd/plugins/hid/otg/events.py index 09fd2a5a..229f4faa 100644 --- a/kvmd/plugins/hid/otg/events.py +++ b/kvmd/plugins/hid/otg/events.py @@ -31,6 +31,8 @@ from typing import Union from ....keyboard.mappings import OtgKey from ....keyboard.mappings import KEYMAP +from ....mouse import MouseRange + # ===== class BaseEvent: @@ -126,10 +128,10 @@ class MouseMoveEvent(BaseEvent): to_fixed_y: int = 0 def __post_init__(self) -> None: - assert -32768 <= self.to_x <= 32767 - assert -32768 <= self.to_y <= 32767 - object.__setattr__(self, "to_fixed_x", (self.to_x + 32768) // 2) - object.__setattr__(self, "to_fixed_y", (self.to_y + 32768) // 2) + assert MouseRange.MIN <= self.to_x <= MouseRange.MAX + assert MouseRange.MIN <= self.to_y <= MouseRange.MAX + object.__setattr__(self, "to_fixed_x", MouseRange.remap(self.to_x, 0, MouseRange.MAX)) + object.__setattr__(self, "to_fixed_y", MouseRange.remap(self.to_y, 0, MouseRange.MAX)) @dataclasses.dataclass(frozen=True) diff --git a/kvmd/tools.py b/kvmd/tools.py index d6077938..6237280b 100644 --- a/kvmd/tools.py +++ b/kvmd/tools.py @@ -32,6 +32,11 @@ from typing import Hashable from typing import TypeVar +# ===== +def remap(value: int, in_min: int, in_max: int, out_min: int, out_max: int) -> int: + return (value - in_min) * (out_max - out_min) // (in_max - in_min) + out_min + + # ===== def efmt(err: Exception) -> str: return f"{type(err).__name__}: {err}" diff --git a/kvmd/validators/hid.py b/kvmd/validators/hid.py index bb7e26e1..f47a516c 100644 --- a/kvmd/validators/hid.py +++ b/kvmd/validators/hid.py @@ -24,6 +24,8 @@ from typing import Any from ..keyboard.mappings import KEYMAP +from ..mouse import MouseRange + from . import check_string_in_list from .basic import valid_number @@ -42,9 +44,9 @@ def valid_hid_key(arg: Any) -> str: return check_string_in_list(arg, "Keyboard key", KEYMAP, lower=False) -def valid_hid_mouse_move(arg: Any, move_min: int=-32768, move_max: int=32767) -> int: +def valid_hid_mouse_move(arg: Any) -> int: arg = valid_number(arg, name="Mouse move") - return min(max(move_min, arg), move_max) + return min(max(MouseRange.MIN, arg), MouseRange.MAX) def valid_hid_mouse_button(arg: Any) -> str: -- cgit v1.2.3