mirror of
https://github.com/mofeng-git/One-KVM.git
synced 2026-02-01 10:31:54 +08:00
hid leds
This commit is contained in:
@@ -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()
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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),
|
||||
)
|
||||
|
||||
# =====
|
||||
|
||||
|
||||
Reference in New Issue
Block a user