summaryrefslogtreecommitdiff
path: root/kvmd/plugins/hid/otg
diff options
context:
space:
mode:
Diffstat (limited to 'kvmd/plugins/hid/otg')
-rw-r--r--kvmd/plugins/hid/otg/__init__.py52
-rw-r--r--kvmd/plugins/hid/otg/device.py26
-rw-r--r--kvmd/plugins/hid/otg/keyboard.py12
3 files changed, 41 insertions, 49 deletions
diff --git a/kvmd/plugins/hid/otg/__init__.py b/kvmd/plugins/hid/otg/__init__.py
index 84c2803e..0684a674 100644
--- a/kvmd/plugins/hid/otg/__init__.py
+++ b/kvmd/plugins/hid/otg/__init__.py
@@ -20,17 +20,12 @@
# ========================================================================== #
-import asyncio
-import concurrent.futures
-import multiprocessing
-import multiprocessing.queues
-import queue
-import functools
-
from typing import Dict
from typing import AsyncGenerator
from typing import Any
+from .... import aiomulti
+
from ....yamlconf import Option
from ....validators.basic import valid_bool
@@ -54,10 +49,10 @@ class Plugin(BaseHid):
noop: bool,
) -> None:
- self.__changes_queue: multiprocessing.queues.Queue = multiprocessing.Queue()
+ self.__state_notifier = aiomulti.AioProcessNotifier()
- self.__keyboard_proc = KeyboardProcess(noop=noop, changes_queue=self.__changes_queue, **keyboard)
- self.__mouse_proc = MouseProcess(noop=noop, changes_queue=self.__changes_queue, **mouse)
+ self.__keyboard_proc = KeyboardProcess(noop=noop, state_notifier=self.__state_notifier, **keyboard)
+ self.__mouse_proc = MouseProcess(noop=noop, state_notifier=self.__state_notifier, **mouse)
@classmethod
def get_plugin_options(cls) -> Dict:
@@ -81,31 +76,30 @@ class Plugin(BaseHid):
self.__keyboard_proc.start()
self.__mouse_proc.start()
- def get_state(self) -> Dict:
- keyboard_state = self.__keyboard_proc.get_state()
- mouse_state = self.__mouse_proc.get_state()
+ async def get_state(self) -> Dict:
+ keyboard_state = await self.__keyboard_proc.get_state()
+ mouse_state = await self.__mouse_proc.get_state()
return {
"online": (keyboard_state["online"] and mouse_state["online"]),
- "keyboard": {"features": {"leds": True}, **keyboard_state},
+ "keyboard": {
+ "online": keyboard_state["online"],
+ "leds": {
+ "caps": keyboard_state["caps"],
+ "scroll": keyboard_state["scroll"],
+ "num": keyboard_state["num"],
+ },
+ },
"mouse": mouse_state,
}
async def poll_state(self) -> AsyncGenerator[Dict, None]:
- loop = asyncio.get_running_loop()
- wait_for_changes = functools.partial(self.__changes_queue.get, timeout=1)
- with concurrent.futures.ThreadPoolExecutor(max_workers=1) as executor:
- prev_state: Dict = {}
- while True:
- state = self.get_state()
- if state != prev_state:
- yield state
- prev_state = state
- while True:
- try:
- await loop.run_in_executor(executor, wait_for_changes)
- break
- except queue.Empty:
- pass
+ prev_state: Dict = {}
+ while True:
+ state = await self.get_state()
+ if state != prev_state:
+ yield state
+ prev_state = state
+ await self.__state_notifier.wait()
async def reset(self) -> None:
self.__keyboard_proc.send_reset_event()
diff --git a/kvmd/plugins/hid/otg/device.py b/kvmd/plugins/hid/otg/device.py
index 0fbb63cb..37cb7b07 100644
--- a/kvmd/plugins/hid/otg/device.py
+++ b/kvmd/plugins/hid/otg/device.py
@@ -30,12 +30,13 @@ import errno
import time
from typing import Dict
-from typing import Any
import setproctitle
from ....logging import get_logger
+from .... import aiomulti
+
# =====
class BaseEvent:
@@ -48,7 +49,7 @@ class BaseDeviceProcess(multiprocessing.Process): # pylint: disable=too-many-in
name: str,
read_size: int,
initial_state: Dict,
- changes_queue: multiprocessing.queues.Queue,
+ state_notifier: aiomulti.AioProcessNotifier,
device_path: str,
select_timeout: float,
@@ -61,7 +62,6 @@ class BaseDeviceProcess(multiprocessing.Process): # pylint: disable=too-many-in
self.__name = name
self.__read_size = read_size
- self.__changes_queue = changes_queue
self.__device_path = device_path
self.__select_timeout = select_timeout
@@ -71,7 +71,7 @@ class BaseDeviceProcess(multiprocessing.Process): # pylint: disable=too-many-in
self.__fd = -1
self.__events_queue: multiprocessing.queues.Queue = multiprocessing.Queue()
- self.__state_shared = multiprocessing.Manager().dict(online=True, **initial_state) # type: ignore
+ self.__state_flags = aiomulti.AioSharedFlags({"online": True, **initial_state}, state_notifier)
self.__stop_event = multiprocessing.Event()
def run(self) -> None:
@@ -100,8 +100,8 @@ class BaseDeviceProcess(multiprocessing.Process): # pylint: disable=too-many-in
self.__close_device()
- def get_state(self) -> Dict:
- return dict(self.__state_shared)
+ async def get_state(self) -> Dict:
+ return (await self.__state_flags.get())
# =====
@@ -111,6 +111,9 @@ class BaseDeviceProcess(multiprocessing.Process): # pylint: disable=too-many-in
def _process_read_report(self, report: bytes) -> None:
pass
+ def _update_state(self, **kwargs: bool) -> None:
+ self.__state_flags.update(**kwargs)
+
# =====
def _stop(self) -> None:
@@ -134,11 +137,6 @@ class BaseDeviceProcess(multiprocessing.Process): # pylint: disable=too-many-in
if close:
self.__close_device()
- def _update_state(self, key: str, value: Any) -> None:
- if self.__state_shared[key] != value:
- self.__state_shared[key] = value
- self.__changes_queue.put(None)
-
# =====
def __write_report(self, report: bytes) -> bool:
@@ -153,7 +151,7 @@ class BaseDeviceProcess(multiprocessing.Process): # pylint: disable=too-many-in
try:
written = os.write(self.__fd, report)
if written == len(report):
- self._update_state("online", True)
+ self.__state_flags.update(online=True)
return True
else:
logger.error("HID-%s write() error: written (%s) != report length (%d)",
@@ -223,7 +221,7 @@ class BaseDeviceProcess(multiprocessing.Process): # pylint: disable=too-many-in
if self.__fd >= 0:
try:
if select.select([], [self.__fd], [], self.__select_timeout)[1]:
- self._update_state("online", True)
+ self.__state_flags.update(online=True)
return True
else:
logger.debug("HID-%s is busy/unplugged (write select)", self.__name)
@@ -231,7 +229,7 @@ class BaseDeviceProcess(multiprocessing.Process): # pylint: disable=too-many-in
logger.error("Can't select() for write HID-%s: %s: %s", self.__name, type(err).__name__, err)
self.__close_device()
- self._update_state("online", False)
+ self.__state_flags.update(online=False)
return False
def __close_device(self) -> None:
diff --git a/kvmd/plugins/hid/otg/keyboard.py b/kvmd/plugins/hid/otg/keyboard.py
index 6c9ddfed..fb964d8a 100644
--- a/kvmd/plugins/hid/otg/keyboard.py
+++ b/kvmd/plugins/hid/otg/keyboard.py
@@ -68,7 +68,7 @@ class KeyboardProcess(BaseDeviceProcess):
super().__init__(
name="keyboard",
read_size=1,
- initial_state={"leds": {"caps": False, "scroll": False, "num": False}},
+ initial_state={"caps": False, "scroll": False, "num": False},
**kwargs,
)
@@ -98,11 +98,11 @@ class KeyboardProcess(BaseDeviceProcess):
def _process_read_report(self, report: bytes) -> None:
# https://wiki.osdev.org/USB_Human_Interface_Devices#LED_lamps
assert len(report) == 1, report
- self._update_state("leds", {
- "caps": bool(report[0] & 2),
- "scroll": bool(report[0] & 4),
- "num": bool(report[0] & 1),
- })
+ self._update_state(
+ caps=bool(report[0] & 2),
+ scroll=bool(report[0] & 4),
+ num=bool(report[0] & 1),
+ )
# =====