This commit is contained in:
Devaev Maxim
2020-11-20 05:05:20 +03:00
parent 7f43440cae
commit 649a57e842
6 changed files with 118 additions and 42 deletions

View File

@@ -55,45 +55,58 @@ static Ps2Keyboard *_ps2_kbd = NULL;
#ifdef HID_DYNAMIC #ifdef HID_DYNAMIC
static bool _reset_required = false; static bool _reset_required = false;
static void _setOutputs(uint8_t outputs) { static int _readOutputs(void) {
uint8_t data[8];
eeprom_read_block(data, 0, 8);
if (data[0] != PROTO::MAGIC || PROTO::crc16(data, 6) != PROTO::merge8(data[6], data[7])) {
return -1;
}
return data[1];
}
static void _writeOutputs(uint8_t mask, uint8_t outputs, bool force) {
int old = 0;
if (!force) {
old = _readOutputs();
if (old < 0) {
old = 0;
}
}
uint8_t data[8] = {0}; uint8_t data[8] = {0};
data[0] = PROTO::MAGIC; data[0] = PROTO::MAGIC;
data[1] = outputs; data[1] = (old & ~mask) | outputs;
PROTO::split16(PROTO::crc16(data, 6), &data[6], &data[7]); PROTO::split16(PROTO::crc16(data, 6), &data[6], &data[7]);
eeprom_update_block(data, 0, 8); eeprom_update_block(data, 0, 8);
} }
#endif #endif
static void _initOutputs() { static void _initOutputs() {
uint8_t data[8]; int outputs;
# ifdef HID_DYNAMIC # ifdef HID_DYNAMIC
eeprom_read_block(data, 0, 8); outputs = _readOutputs();
if ( if (outputs < 0) {
PROTO::crc16(data, 6) != PROTO::merge8(data[6], data[7])
|| data[0] != PROTO::MAGIC
) {
# endif # endif
data[1] = 0; outputs = 0;
# if defined(HID_WITH_USB) && defined(HID_SET_USB_KBD) # if defined(HID_WITH_USB) && defined(HID_SET_USB_KBD)
data[1] |= PROTO::OUTPUTS::KEYBOARD::USB; outputs |= PROTO::OUTPUTS::KEYBOARD::USB;
# elif defined(HID_WITH_PS2) && defined(HID_SET_PS2_KBD) # elif defined(HID_WITH_PS2) && defined(HID_SET_PS2_KBD)
data[1] |= PROTO::OUTPUTS::KEYBOARD::PS2; outputs |= PROTO::OUTPUTS::KEYBOARD::PS2;
# endif # endif
# if defined(HID_WITH_USB) && defined(HID_SET_USB_MOUSE_ABS) # if defined(HID_WITH_USB) && defined(HID_SET_USB_MOUSE_ABS)
data[1] |= PROTO::OUTPUTS::MOUSE::USB_ABS; outputs |= PROTO::OUTPUTS::MOUSE::USB_ABS;
# elif defined(HID_WITH_USB) && defined(HID_SET_USB_MOUSE_REL) # elif defined(HID_WITH_USB) && defined(HID_SET_USB_MOUSE_REL)
data[1] |= PROTO::OUTPUTS::MOUSE::USB_REL; outputs |= PROTO::OUTPUTS::MOUSE::USB_REL;
# elif defined(HID_WITH_PS2) && defined(HID_SET_PS2_MOUSE) # elif defined(HID_WITH_PS2) && defined(HID_SET_PS2_MOUSE)
data[1] |= PROTO::OUTPUTS::MOUSE::PS2; outputs |= PROTO::OUTPUTS::MOUSE::PS2;
# endif # endif
# ifdef HID_DYNAMIC # ifdef HID_DYNAMIC
_setOutputs(data[1]); _writeOutputs(0xFF, outputs, true);
} }
# endif # endif
uint8_t kbd = data[1] & PROTO::OUTPUTS::KEYBOARD::MASK; uint8_t kbd = outputs & PROTO::OUTPUTS::KEYBOARD::MASK;
switch (kbd) { switch (kbd) {
# ifdef HID_WITH_USB # ifdef HID_WITH_USB
case PROTO::OUTPUTS::KEYBOARD::USB: _usb_kbd = new UsbKeyboard(); break; case PROTO::OUTPUTS::KEYBOARD::USB: _usb_kbd = new UsbKeyboard(); break;
@@ -103,7 +116,7 @@ static void _initOutputs() {
# endif # endif
} }
uint8_t mouse = data[1] & PROTO::OUTPUTS::MOUSE::MASK; uint8_t mouse = outputs & PROTO::OUTPUTS::MOUSE::MASK;
switch (mouse) { switch (mouse) {
# ifdef HID_WITH_USB # ifdef HID_WITH_USB
case PROTO::OUTPUTS::MOUSE::USB_ABS: _usb_mouse_abs = new UsbMouseAbsolute(); break; case PROTO::OUTPUTS::MOUSE::USB_ABS: _usb_mouse_abs = new UsbMouseAbsolute(); break;
@@ -132,9 +145,16 @@ static void _initOutputs() {
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
static void _cmdSetOutputs(const uint8_t *data) { // 1 bytes static void _cmdSetKeyboard(const uint8_t *data) { // 1 bytes
# ifdef HID_DYNAMIC # ifdef HID_DYNAMIC
_setOutputs(data[0]); _writeOutputs(PROTO::OUTPUTS::KEYBOARD::MASK, data[0], false);
_reset_required = true;
# endif
}
static void _cmdSetMouse(const uint8_t *data) { // 1 bytes
# ifdef HID_DYNAMIC
_writeOutputs(PROTO::OUTPUTS::KEYBOARD::MASK, data[0], false);
_reset_required = true; _reset_required = true;
# endif # endif
} }
@@ -209,7 +229,8 @@ static uint8_t _handleRequest(const uint8_t *data) { // 8 bytes
# define HANDLE(_handler) { _handler(data + 2); return PROTO::PONG::OK; } # define HANDLE(_handler) { _handler(data + 2); return PROTO::PONG::OK; }
switch (data[1]) { switch (data[1]) {
case PROTO::CMD::PING: return PROTO::PONG::OK; case PROTO::CMD::PING: return PROTO::PONG::OK;
case PROTO::CMD::SET_OUTPUTS: HANDLE(_cmdSetOutputs); case PROTO::CMD::SET_KEYBOARD: HANDLE(_cmdSetKeyboard);
case PROTO::CMD::SET_MOUSE: HANDLE(_cmdSetMouse);
case PROTO::CMD::CLEAR_HID: HANDLE(_cmdClearHid); case PROTO::CMD::CLEAR_HID: HANDLE(_cmdClearHid);
case PROTO::CMD::KEYBOARD::KEY: HANDLE(_cmdKeyEvent); case PROTO::CMD::KEYBOARD::KEY: HANDLE(_cmdKeyEvent);
case PROTO::CMD::MOUSE::BUTTON: HANDLE(_cmdMouseButtonEvent); case PROTO::CMD::MOUSE::BUTTON: HANDLE(_cmdMouseButtonEvent);

View File

@@ -65,10 +65,11 @@ namespace PROTO {
} }
namespace CMD { namespace CMD {
const uint8_t PING = 0x01; const uint8_t PING = 0x01;
const uint8_t REPEAT = 0x02; const uint8_t REPEAT = 0x02;
const uint8_t SET_OUTPUTS = 0x03; const uint8_t SET_KEYBOARD = 0x03;
const uint8_t CLEAR_HID = 0x10; const uint8_t SET_MOUSE = 0x04;
const uint8_t CLEAR_HID = 0x10;
namespace KEYBOARD { namespace KEYBOARD {
const uint8_t KEY = 0x11; const uint8_t KEY = 0x11;

View File

@@ -57,14 +57,22 @@ class BaseHid(BasePlugin):
raise NotImplementedError raise NotImplementedError
def send_mouse_move_event(self, to_x: int, to_y: int) -> None: def send_mouse_move_event(self, to_x: int, to_y: int) -> None:
raise NotImplementedError _ = to_x
_ = to_y
def send_mouse_relative_event(self, delta_x: int, delta_y: int) -> None: def send_mouse_relative_event(self, delta_x: int, delta_y: int) -> None:
raise NotImplementedError _ = delta_x
_ = delta_y
def send_mouse_wheel_event(self, delta_x: int, delta_y: int) -> None: def send_mouse_wheel_event(self, delta_x: int, delta_y: int) -> None:
raise NotImplementedError raise NotImplementedError
def set_keyboard_output(self, output: str) -> None:
_ = output
def set_mouse_output(self, output: str) -> None:
_ = output
def clear_events(self) -> None: def clear_events(self) -> None:
raise NotImplementedError raise NotImplementedError

View File

@@ -55,7 +55,11 @@ from .gpio import Gpio
from .proto import REQUEST_PING from .proto import REQUEST_PING
from .proto import REQUEST_REPEAT from .proto import REQUEST_REPEAT
from .proto import RESPONSE_LEGACY_OK from .proto import RESPONSE_LEGACY_OK
from .proto import KEYBOARD_CODES_TO_NAMES
from .proto import MOUSE_CODES_TO_NAMES
from .proto import BaseEvent from .proto import BaseEvent
from .proto import SetKeyboardOutputEvent
from .proto import SetMouseOutputEvent
from .proto import ClearEvent from .proto import ClearEvent
from .proto import KeyEvent from .proto import KeyEvent
from .proto import MouseButtonEvent from .proto import MouseButtonEvent
@@ -164,24 +168,24 @@ class BaseMcuHid(BaseHid, multiprocessing.Process): # pylint: disable=too-many-
keyboard_outputs: Dict = {"available": {}, "active": ""} keyboard_outputs: Dict = {"available": {}, "active": ""}
mouse_outputs: Dict = {"available": {}, "active": ""} mouse_outputs: Dict = {"available": {}, "active": ""}
if outputs & 0b10000000: # Dynamic if outputs & 0b10000000: # Dynamic
if features & 0b00000001: # USB if features & 0b00000001: # USB
keyboard_outputs["available"]["usb"] = {"name": "USB"} keyboard_outputs["available"]["usb"] = {"name": "USB"}
mouse_outputs["available"]["usb_abs"] = {"name": "USB", "absolute": True} mouse_outputs["available"]["usb"] = {"name": "USB", "absolute": True}
mouse_outputs["available"]["usb_rel"] = {"name": "USB Relative", "absolute": False} mouse_outputs["available"]["usb_rel"] = {"name": "USB Relative", "absolute": False}
if features & 0b00000010: # PS/2 if features & 0b00000010: # PS/2
keyboard_outputs["available"]["ps2"] = {"name": "PS/2"} keyboard_outputs["available"]["ps2"] = {"name": "PS/2"}
mouse_outputs["available"]["ps2"] = {"name": "PS/2"} mouse_outputs["available"]["ps2"] = {"name": "PS/2"}
keyboard_outputs["active"] = { active = KEYBOARD_CODES_TO_NAMES.get(outputs & 0b00000111, "")
0b00000001: "usb", if active in keyboard_outputs["available"]:
0b00000011: "ps2", keyboard_outputs["active"] = active
}.get(outputs & 0b00000111, "")
mouse_outputs["active"] = { active = MOUSE_CODES_TO_NAMES.get(outputs & 0b00111000, "")
0b00001000: "usb_abs", if active in mouse_outputs["available"]:
0b00010000: "usb_rel", mouse_outputs["active"] = active
0b00011000: "ps2",
}.get(outputs & 0b00111000, "")
return { return {
"online": online, "online": online,
@@ -251,10 +255,18 @@ class BaseMcuHid(BaseHid, multiprocessing.Process): # pylint: disable=too-many-
def send_mouse_wheel_event(self, delta_x: int, delta_y: int) -> None: def send_mouse_wheel_event(self, delta_x: int, delta_y: int) -> None:
self.__queue_event(MouseWheelEvent(delta_x, delta_y)) self.__queue_event(MouseWheelEvent(delta_x, delta_y))
def clear_events(self) -> None: def set_keyboard_output(self, output: str) -> None:
# FIXME: Если очистка производится со стороны процесса хида, то возможна гонка между # FIXME: Если очистка производится со стороны процесса хида, то возможна гонка между
# очисткой и добавлением события _ClearEvent. Неприятно, но не смертельно. # очисткой и добавлением нового события. Неприятно, но не смертельно.
# Починить блокировкой после перехода на асинхронные очереди. # Починить блокировкой после перехода на асинхронные очереди.
tools.clear_queue(self.__events_queue)
self.__queue_event(SetKeyboardOutputEvent(output))
def set_mouse_output(self, output: str) -> None:
tools.clear_queue(self.__events_queue)
self.__queue_event(SetMouseOutputEvent(output))
def clear_events(self) -> None:
tools.clear_queue(self.__events_queue) tools.clear_queue(self.__events_queue)
self.__queue_event(ClearEvent()) self.__queue_event(ClearEvent())

View File

@@ -32,6 +32,44 @@ class BaseEvent:
raise NotImplementedError raise NotImplementedError
KEYBOARD_NAMES_TO_CODES = {
"usb": 0b00000001,
"ps2": 0b00000011,
}
KEYBOARD_CODES_TO_NAMES = {value: key for (key, value) in KEYBOARD_NAMES_TO_CODES.items()}
@dataclasses.dataclass(frozen=True)
class SetKeyboardOutputEvent(BaseEvent):
keyboard: str
def __post_init__(self) -> None:
assert not self.keyboard or self.keyboard in KEYBOARD_NAMES_TO_CODES
def make_request(self) -> bytes:
code = KEYBOARD_NAMES_TO_CODES.get(self.keyboard, 0)
return _make_request(struct.pack(">BBxxx", 0x03, code))
MOUSE_NAMES_TO_CODES = {
"usb": 0b00001000,
"usb_rel": 0b00010000,
"ps2": 0b00011000,
}
MOUSE_CODES_TO_NAMES = {value: key for (key, value) in MOUSE_NAMES_TO_CODES.items()}
@dataclasses.dataclass(frozen=True)
class SetMouseOutputEvent(BaseEvent):
mouse: str
def __post_init__(self) -> None:
assert not self.mouse or self.mouse in MOUSE_NAMES_TO_CODES
def make_request(self) -> bytes:
return _make_request(struct.pack(">BBxxx", 0x04, MOUSE_NAMES_TO_CODES.get(self.mouse, 0)))
class ClearEvent(BaseEvent): class ClearEvent(BaseEvent):
def make_request(self) -> bytes: def make_request(self) -> bytes:
return _make_request(b"\x10\x00\x00\x00\x00") return _make_request(b"\x10\x00\x00\x00\x00")

View File

@@ -181,10 +181,6 @@ class Plugin(BaseHid): # pylint: disable=too-many-instance-attributes
def send_mouse_button_event(self, button: str, state: bool) -> None: def send_mouse_button_event(self, button: str, state: bool) -> None:
self.__server.queue_event(MouseButtonEvent(button, state)) self.__server.queue_event(MouseButtonEvent(button, state))
def send_mouse_move_event(self, to_x: int, to_y: int) -> None:
_ = to_x # No absolute events
_ = to_y
def send_mouse_relative_event(self, delta_x: int, delta_y: int) -> None: def send_mouse_relative_event(self, delta_x: int, delta_y: int) -> None:
self.__server.queue_event(MouseRelativeEvent(delta_x, delta_y)) self.__server.queue_event(MouseRelativeEvent(delta_x, delta_y))