dual mouse mode

This commit is contained in:
Maxim Devaev 2021-07-24 02:37:10 +03:00
parent a33efcaef3
commit 37060de4c3
8 changed files with 73 additions and 14 deletions

View File

@ -3,3 +3,4 @@
KERNEL=="video[0-9]*", SUBSYSTEM=="video4linux", KERNELS=="3f801000.csi|3f801000.csi1", ATTR{name}=="unicam-image", GROUP="kvmd", SYMLINK+="kvmd-video", TAG+="systemd"
KERNEL=="hidg0", GROUP="kvmd", SYMLINK+="kvmd-hid-keyboard"
KERNEL=="hidg1", GROUP="kvmd", SYMLINK+="kvmd-hid-mouse"
KERNEL=="hidg2", GROUP="kvmd", SYMLINK+="kvmd-hid-mouse-alt"

View File

@ -3,3 +3,4 @@
KERNEL=="video[0-9]*", SUBSYSTEM=="video4linux", KERNELS=="fe801000.csi|fe801000.csi1", ATTR{name}=="unicam-image", GROUP="kvmd", SYMLINK+="kvmd-video", TAG+="systemd"
KERNEL=="hidg0", GROUP="kvmd", SYMLINK+="kvmd-hid-keyboard"
KERNEL=="hidg1", GROUP="kvmd", SYMLINK+="kvmd-hid-mouse"
KERNEL=="hidg2", GROUP="kvmd", SYMLINK+="kvmd-hid-mouse-alt"

View File

@ -3,3 +3,4 @@
KERNEL=="video[0-9]*", SUBSYSTEM=="video4linux", KERNELS=="20801000.csi|20801000.csi1", ATTR{name}=="unicam-image", GROUP="kvmd", SYMLINK+="kvmd-video", TAG+="systemd"
KERNEL=="hidg0", GROUP="kvmd", SYMLINK+="kvmd-hid-keyboard"
KERNEL=="hidg1", GROUP="kvmd", SYMLINK+="kvmd-hid-mouse"
KERNEL=="hidg2", GROUP="kvmd", SYMLINK+="kvmd-hid-mouse-alt"

View File

@ -3,3 +3,4 @@
KERNEL=="video[0-9]*", SUBSYSTEM=="video4linux", SUBSYSTEMS=="usb", ATTR{index}=="0", GROUP="kvmd", SYMLINK+="kvmd-video"
KERNEL=="hidg0", GROUP="kvmd", SYMLINK+="kvmd-hid-keyboard"
KERNEL=="hidg1", GROUP="kvmd", SYMLINK+="kvmd-hid-mouse"
KERNEL=="hidg2", GROUP="kvmd", SYMLINK+="kvmd-hid-mouse-alt"

View File

@ -3,3 +3,4 @@
KERNEL=="video[0-9]*", SUBSYSTEM=="video4linux", PROGRAM="/usr/bin/kvmd-udev-hdmiusb-check rpi4 %b", ATTR{index}=="0", GROUP="kvmd", SYMLINK+="kvmd-video"
KERNEL=="hidg0", GROUP="kvmd", SYMLINK+="kvmd-hid-keyboard"
KERNEL=="hidg1", GROUP="kvmd", SYMLINK+="kvmd-hid-mouse"
KERNEL=="hidg2", GROUP="kvmd", SYMLINK+="kvmd-hid-mouse-alt"

View File

@ -3,4 +3,5 @@
KERNEL=="video[0-9]*", SUBSYSTEM=="video4linux", KERNELS=="fe801000.csi|fe801000.csi1", ATTR{name}=="unicam-image", GROUP="kvmd", SYMLINK+="kvmd-video", TAG+="systemd"
KERNEL=="hidg0", GROUP="kvmd", SYMLINK+="kvmd-hid-keyboard"
KERNEL=="hidg1", GROUP="kvmd", SYMLINK+="kvmd-hid-mouse"
KERNEL=="hidg2", GROUP="kvmd", SYMLINK+="kvmd-hid-mouse-alt"
KERNEL=="sd[a-z]", SUBSYSTEM=="block", KERNELS=="1-1.4:1.0", GROUP="kvmd", SYMLINK+="kvmd-msd-aum"

View File

@ -212,6 +212,12 @@ def _cmd_start(config: Section) -> None:
absolute=config.kvmd.hid.mouse.absolute,
horizontal_wheel=config.kvmd.hid.mouse.horizontal_wheel,
))
if config.kvmd.hid.mouse_alt.device:
logger.info("===== Required HID-Mouse ALT =====")
_create_hid(gadget_path, config_path, 2, make_mouse_hid(
absolute=(not config.kvmd.hid.mouse.absolute),
horizontal_wheel=config.kvmd.hid.mouse_alt.horizontal_wheel,
))
if config.kvmd.msd.type == "otg":
logger.info("===== Required MSD =====")

View File

@ -24,8 +24,10 @@ from typing import Tuple
from typing import Dict
from typing import Iterable
from typing import AsyncGenerator
from typing import Optional
from typing import Any
from .... import tools
from .... import aiomulti
from ....yamlconf import Option
@ -43,11 +45,12 @@ from .mouse import MouseProcess
# =====
class Plugin(BaseHid):
class Plugin(BaseHid): # pylint: disable=too-many-instance-attributes
def __init__( # pylint: disable=super-init-not-called
self,
keyboard: Dict[str, Any],
mouse: Dict[str, Any],
mouse_alt: Dict[str, Any],
noop: bool,
udc: str, # XXX: Not from options, see /kvmd/apps/kvmd/__init__.py for details
) -> None:
@ -56,8 +59,25 @@ class Plugin(BaseHid):
self.__udc = UsbDeviceController(udc)
self.__keyboard_proc = KeyboardProcess(udc=self.__udc, noop=noop, notifier=self.__notifier, **keyboard)
self.__mouse_proc = MouseProcess(udc=self.__udc, noop=noop, notifier=self.__notifier, **mouse)
common = {
"udc": self.__udc,
"noop": noop,
"notifier": self.__notifier,
}
self.__keyboard_proc = KeyboardProcess(**common, **keyboard)
self.__mouse_current = self.__mouse_proc = MouseProcess(**common, **mouse)
self.__mouse_alt_proc: Optional[MouseProcess] = None
self.__output_to_mouse: Dict[str, MouseProcess] = {}
self.__mouse_to_output: Dict[MouseProcess, str] = {}
if mouse_alt["device_path"]:
self.__mouse_alt_proc = MouseProcess(absolute=(not mouse["absolute"]), **common, **mouse_alt)
self.__output_to_mouse = {
"usb": (self.__mouse_proc if mouse["absolute"] else self.__mouse_alt_proc),
"usb_rel": (self.__mouse_alt_proc if mouse["absolute"] else self.__mouse_proc),
}
self.__mouse_to_output = tools.swapped_kvs(self.__output_to_mouse)
@classmethod
def get_plugin_options(cls) -> Dict:
@ -76,6 +96,14 @@ class Plugin(BaseHid):
"absolute": Option(True, type=valid_bool),
"horizontal_wheel": Option(True, type=valid_bool),
},
"mouse_alt": {
"device": Option("", type=valid_abs_path, if_empty="", unpack_as="device_path"),
"select_timeout": Option(0.1, type=valid_float_f01),
"queue_timeout": Option(0.1, type=valid_float_f01),
"write_retries": Option(150, type=valid_int_f1),
# No absolute option here, initialized by (not mouse.absolute)
"horizontal_wheel": Option(True, type=valid_bool),
},
"noop": Option(False, type=valid_bool),
}
@ -83,11 +111,12 @@ class Plugin(BaseHid):
self.__udc.find()
self.__keyboard_proc.start()
self.__mouse_proc.start()
if self.__mouse_alt_proc:
self.__mouse_alt_proc.start()
async def get_state(self) -> Dict:
keyboard_state = await self.__keyboard_proc.get_state()
mouse_state = await self.__mouse_proc.get_state()
outputs: Dict = {"available": [], "active": ""}
mouse_state = await self.__mouse_current.get_state()
return {
"online": True,
"busy": False,
@ -99,9 +128,15 @@ class Plugin(BaseHid):
"scroll": keyboard_state["scroll"],
"num": keyboard_state["num"],
},
"outputs": outputs,
"outputs": {"available": [], "active": ""},
},
"mouse": {
"outputs": {
"available": list(self.__output_to_mouse),
"active": (self.__mouse_to_output[self.__mouse_current] if self.__mouse_alt_proc else ""),
},
**mouse_state,
},
"mouse": {**mouse_state, "outputs": outputs},
}
async def poll_state(self) -> AsyncGenerator[Dict, None]:
@ -115,13 +150,17 @@ class Plugin(BaseHid):
async def reset(self) -> None:
self.__keyboard_proc.send_reset_event()
self.__mouse_proc.send_reset_event()
self.__mouse_current.send_reset_event()
async def cleanup(self) -> None:
try:
self.__keyboard_proc.cleanup()
finally:
self.__mouse_proc.cleanup()
try:
self.__mouse_proc.cleanup()
finally:
if self.__mouse_alt_proc:
self.__mouse_alt_proc.cleanup()
# =====
@ -129,17 +168,25 @@ class Plugin(BaseHid):
self.__keyboard_proc.send_key_events(keys)
def send_mouse_button_event(self, button: str, state: bool) -> None:
self.__mouse_proc.send_button_event(button, state)
self.__mouse_current.send_button_event(button, state)
def send_mouse_move_event(self, to_x: int, to_y: int) -> None:
self.__mouse_proc.send_move_event(to_x, to_y)
self.__mouse_current.send_move_event(to_x, to_y)
def send_mouse_relative_event(self, delta_x: int, delta_y: int) -> None:
self.__mouse_proc.send_relative_event(delta_x, delta_y)
self.__mouse_current.send_relative_event(delta_x, delta_y)
def send_mouse_wheel_event(self, delta_x: int, delta_y: int) -> None:
self.__mouse_proc.send_wheel_event(delta_x, delta_y)
self.__mouse_current.send_wheel_event(delta_x, delta_y)
def set_params(self, keyboard_output: Optional[str]=None, mouse_output: Optional[str]=None) -> None:
_ = keyboard_output
if mouse_output != self.__mouse_to_output[self.__mouse_current]:
if mouse_output in self.__output_to_mouse:
self.__mouse_current.send_clear_event()
self.__mouse_current = self.__output_to_mouse[mouse_output]
self.__notifier.notify()
def clear_events(self) -> None:
self.__keyboard_proc.send_clear_event()
self.__mouse_proc.send_clear_event()
self.__mouse_current.send_clear_event()