mirror of
https://github.com/mofeng-git/One-KVM.git
synced 2026-01-29 00:51:53 +08:00
win95 runtime switching
This commit is contained in:
@@ -7,7 +7,7 @@ platform = atmelavr
|
||||
board = micro
|
||||
framework = arduino
|
||||
lib_deps =
|
||||
git+https://github.com/mdevaev/HID#f12b7d633f7437552707d6ccd411204cf36601f2
|
||||
git+https://github.com/mdevaev/HID#a8877bc878a1a2f39d993a3defa750b6ec1b2ee0
|
||||
git+https://github.com/Harvie/ps2dev#v0.0.3
|
||||
digitalWriteFast@1.0.0
|
||||
extra_scripts =
|
||||
@@ -25,7 +25,7 @@ build_flags =
|
||||
-DHID_SET_USB_KBD
|
||||
-DHID_SET_USB_MOUSE_ABS
|
||||
# ----- The USB ABS fix for Windows 98 (https://github.com/pikvm/pikvm/issues/159) -----
|
||||
# -DHID_USB_ABS_WIN98_FIX
|
||||
# -DHID_WITH_USB_WIN98
|
||||
# ----- PS2 keyboard only -----
|
||||
# -DHID_WITH_PS2
|
||||
# -DHID_SET_PS2_KBD
|
||||
|
||||
@@ -102,6 +102,8 @@ static void _initOutputs() {
|
||||
outputs |= PROTO::OUTPUTS1::MOUSE::USB_REL;
|
||||
# elif defined(HID_WITH_PS2) && defined(HID_SET_PS2_MOUSE)
|
||||
outputs |= PROTO::OUTPUTS1::MOUSE::PS2;
|
||||
# elif defined(HID_WITH_USB) && defined(HID_WITH_USB_WIN98) && defined(HID_SET_USB_MOUSE_WIN98)
|
||||
outputs |= PROTO::OUTPUTS1::MOUSE::USB_WIN98;
|
||||
# endif
|
||||
|
||||
# ifdef HID_DYNAMIC
|
||||
@@ -122,7 +124,8 @@ static void _initOutputs() {
|
||||
uint8_t mouse = outputs & PROTO::OUTPUTS1::MOUSE::MASK;
|
||||
switch (mouse) {
|
||||
# ifdef HID_WITH_USB
|
||||
case PROTO::OUTPUTS1::MOUSE::USB_ABS: _usb_mouse_abs = new UsbMouseAbsolute(); break;
|
||||
case PROTO::OUTPUTS1::MOUSE::USB_ABS:
|
||||
case PROTO::OUTPUTS1::MOUSE::USB_WIN98: _usb_mouse_abs = new UsbMouseAbsolute(); break;
|
||||
case PROTO::OUTPUTS1::MOUSE::USB_REL: _usb_mouse_rel = new UsbMouseRelative(); break;
|
||||
# endif
|
||||
}
|
||||
@@ -140,7 +143,12 @@ static void _initOutputs() {
|
||||
|
||||
switch (mouse) {
|
||||
# ifdef HID_WITH_USB
|
||||
case PROTO::OUTPUTS1::MOUSE::USB_ABS: _usb_mouse_abs->begin(); break;
|
||||
case PROTO::OUTPUTS1::MOUSE::USB_ABS:
|
||||
# ifdef HID_WITH_USB_WIN98
|
||||
case PROTO::OUTPUTS1::MOUSE::USB_WIN98:
|
||||
# endif
|
||||
_usb_mouse_abs->begin(mouse == PROTO::OUTPUTS1::MOUSE::USB_WIN98);
|
||||
break;
|
||||
case PROTO::OUTPUTS1::MOUSE::USB_REL: _usb_mouse_rel->begin(); break;
|
||||
# endif
|
||||
}
|
||||
@@ -286,7 +294,11 @@ static void _sendResponse(uint8_t code) {
|
||||
}
|
||||
if (_usb_mouse_abs) {
|
||||
response[1] |= _usb_mouse_abs->getOfflineAs(PROTO::PONG::MOUSE_OFFLINE);
|
||||
if (_usb_mouse_abs->isWin98FixEnabled()) {
|
||||
response[2] |= PROTO::OUTPUTS1::MOUSE::USB_WIN98;
|
||||
} else {
|
||||
response[2] |= PROTO::OUTPUTS1::MOUSE::USB_ABS;
|
||||
}
|
||||
} else if (_usb_mouse_rel) {
|
||||
response[1] |= _usb_mouse_rel->getOfflineAs(PROTO::PONG::MOUSE_OFFLINE);
|
||||
response[2] |= PROTO::OUTPUTS1::MOUSE::USB_REL;
|
||||
@@ -299,6 +311,9 @@ static void _sendResponse(uint8_t code) {
|
||||
# endif
|
||||
# ifdef HID_WITH_USB
|
||||
response[3] |= PROTO::OUTPUTS2::HAS_USB;
|
||||
# ifdef HID_WITH_USB_WIN98
|
||||
response[3] |= PROTO::OUTPUTS2::HAS_USB_WIN98;
|
||||
# endif
|
||||
# endif
|
||||
# ifdef HID_WITH_PS2
|
||||
response[3] |= PROTO::OUTPUTS2::HAS_PS2;
|
||||
|
||||
@@ -57,6 +57,7 @@ namespace PROTO {
|
||||
const uint8_t USB_ABS = 0b00001000;
|
||||
const uint8_t USB_REL = 0b00010000;
|
||||
const uint8_t PS2 = 0b00011000;
|
||||
const uint8_t USB_WIN98 = 0b00100000;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -65,6 +66,7 @@ namespace PROTO {
|
||||
const uint8_t CONNECTED = 0b01000000;
|
||||
const uint8_t HAS_USB = 0b00000001;
|
||||
const uint8_t HAS_PS2 = 0b00000010;
|
||||
const uint8_t HAS_USB_WIN98 = 0b00000100;
|
||||
}
|
||||
|
||||
namespace CMD {
|
||||
|
||||
@@ -149,11 +149,13 @@ class UsbMouseAbsolute {
|
||||
public:
|
||||
UsbMouseAbsolute() {}
|
||||
|
||||
void begin() {
|
||||
void begin(bool win98_fix) {
|
||||
_mouse.begin();
|
||||
#ifdef HID_USB_ABS_WIN98_FIX
|
||||
_mouse.setWin98Fix(true);
|
||||
#endif
|
||||
_mouse.setWin98FixEnabled(win98_fix);
|
||||
}
|
||||
|
||||
bool isWin98FixEnabled() {
|
||||
return _mouse.isWin98FixEnabled();
|
||||
}
|
||||
|
||||
void clear() {
|
||||
|
||||
@@ -179,12 +179,21 @@ class BaseMcuHid(BaseHid, multiprocessing.Process): # pylint: disable=too-many-
|
||||
|
||||
if outputs1 & 0b10000000: # Dynamic
|
||||
if outputs2 & 0b00000001: # USB
|
||||
keyboard_outputs["available"].extend(["usb", "disabled"])
|
||||
mouse_outputs["available"].extend(["usb", "usb_rel", "disabled"])
|
||||
keyboard_outputs["available"].append("usb")
|
||||
mouse_outputs["available"].extend(["usb", "usb_rel"])
|
||||
|
||||
if outputs2 & 0b00000100: # USB WIN98
|
||||
mouse_outputs["available"].append("usb_win98")
|
||||
|
||||
if outputs2 & 0b00000010: # PS/2
|
||||
keyboard_outputs["available"].extend(["ps2", "disabled"])
|
||||
mouse_outputs["available"].extend(["ps2", "disabled"])
|
||||
keyboard_outputs["available"].append("ps2")
|
||||
mouse_outputs["available"].append("ps2")
|
||||
|
||||
if keyboard_outputs["available"]:
|
||||
keyboard_outputs["available"].append("disabled")
|
||||
|
||||
if mouse_outputs["available"]:
|
||||
mouse_outputs["available"].append("disabled")
|
||||
|
||||
active_keyboard = get_active_keyboard(outputs1)
|
||||
if active_keyboard in keyboard_outputs["available"]:
|
||||
|
||||
@@ -67,6 +67,7 @@ _MOUSE_NAMES_TO_CODES = {
|
||||
"usb": 0b00001000,
|
||||
"usb_rel": 0b00010000,
|
||||
"ps2": 0b00011000,
|
||||
"usb_win98": 0b00100000,
|
||||
}
|
||||
_MOUSE_CODES_TO_NAMES = tools.swapped_kvs(_MOUSE_NAMES_TO_CODES)
|
||||
|
||||
|
||||
@@ -27,7 +27,6 @@ from typing import AsyncGenerator
|
||||
from typing import Optional
|
||||
from typing import Any
|
||||
|
||||
from .... import tools
|
||||
from .... import aiomulti
|
||||
|
||||
from ....yamlconf import Option
|
||||
@@ -59,30 +58,31 @@ class Plugin(BaseHid): # pylint: disable=too-many-instance-attributes
|
||||
|
||||
self.__udc = UsbDeviceController(udc)
|
||||
|
||||
win98_fix = mouse.pop("absolute_win98_fix")
|
||||
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] = {}
|
||||
self.__mouses: Dict[str, MouseProcess] = {}
|
||||
if mouse_alt["device_path"]:
|
||||
self.__mouse_alt_proc = MouseProcess(
|
||||
absolute=(not mouse["absolute"]),
|
||||
absolute_win98_fix=mouse["absolute_win98_fix"],
|
||||
**common,
|
||||
**mouse_alt,
|
||||
)
|
||||
self.__output_to_mouse = {
|
||||
self.__mouses = {
|
||||
"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)
|
||||
if win98_fix:
|
||||
# На самом деле мультимышка и win95 не зависят друг от друга,
|
||||
# но так было проще реализовать переключение режимов
|
||||
self.__mouses["usb_win98"] = self.__mouses["usb"]
|
||||
|
||||
@classmethod
|
||||
def get_plugin_options(cls) -> Dict:
|
||||
@@ -139,8 +139,8 @@ class Plugin(BaseHid): # pylint: disable=too-many-instance-attributes
|
||||
},
|
||||
"mouse": {
|
||||
"outputs": {
|
||||
"available": list(self.__output_to_mouse),
|
||||
"active": (self.__mouse_to_output[self.__mouse_current] if self.__mouse_alt_proc else ""),
|
||||
"available": list(self.__mouses),
|
||||
"active": self.__get_current_mouse_mode(),
|
||||
},
|
||||
**mouse_state,
|
||||
},
|
||||
@@ -157,7 +157,9 @@ class Plugin(BaseHid): # pylint: disable=too-many-instance-attributes
|
||||
|
||||
async def reset(self) -> None:
|
||||
self.__keyboard_proc.send_reset_event()
|
||||
self.__mouse_current.send_reset_event()
|
||||
self.__mouse_proc.send_reset_event()
|
||||
if self.__mouse_alt_proc:
|
||||
self.__mouse_alt_proc.send_reset_event()
|
||||
|
||||
async def cleanup(self) -> None:
|
||||
try:
|
||||
@@ -188,12 +190,23 @@ class Plugin(BaseHid): # pylint: disable=too-many-instance-attributes
|
||||
|
||||
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:
|
||||
if mouse_output in self.__mouses and mouse_output != self.__get_current_mouse_mode():
|
||||
self.__mouse_current.send_clear_event()
|
||||
self.__mouse_current = self.__output_to_mouse[mouse_output]
|
||||
self.__mouse_current = self.__mouses[mouse_output]
|
||||
self.__mouse_current.set_win98_fix(mouse_output == "usb_win98")
|
||||
self.__notifier.notify()
|
||||
|
||||
def clear_events(self) -> None:
|
||||
self.__keyboard_proc.send_clear_event()
|
||||
self.__mouse_current.send_clear_event()
|
||||
self.__mouse_proc.send_clear_event()
|
||||
if self.__mouse_alt_proc:
|
||||
self.__mouse_alt_proc.send_clear_event()
|
||||
|
||||
# =====
|
||||
|
||||
def __get_current_mouse_mode(self) -> str:
|
||||
if len(self.__mouses) == 0:
|
||||
return ""
|
||||
if self.__mouse_current.is_absolute():
|
||||
return ("usb_win98" if self.__mouse_current.get_win98_fix() else "usb")
|
||||
return "usb_rel"
|
||||
|
||||
@@ -124,14 +124,23 @@ class MouseButtonEvent(BaseEvent):
|
||||
class MouseMoveEvent(BaseEvent):
|
||||
to_x: int
|
||||
to_y: int
|
||||
win98_fix: bool = False
|
||||
to_fixed_x: int = 0
|
||||
to_fixed_y: int = 0
|
||||
|
||||
def __post_init__(self) -> None:
|
||||
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))
|
||||
to_fixed_x = MouseRange.remap(self.to_x, 0, MouseRange.MAX)
|
||||
to_fixed_y = MouseRange.remap(self.to_y, 0, MouseRange.MAX)
|
||||
if self.win98_fix:
|
||||
# https://github.com/pikvm/pikvm/issues/159
|
||||
# For some reason, the correct implementation of this fix
|
||||
# is a shift to the left, and not to the right, as in VirtualBox
|
||||
to_fixed_x <<= 1
|
||||
to_fixed_y <<= 1
|
||||
object.__setattr__(self, "to_fixed_x", to_fixed_x)
|
||||
object.__setattr__(self, "to_fixed_y", to_fixed_y)
|
||||
|
||||
|
||||
@dataclasses.dataclass(frozen=True)
|
||||
|
||||
@@ -42,7 +42,6 @@ from .events import make_mouse_report
|
||||
class MouseProcess(BaseDeviceProcess):
|
||||
def __init__(self, **kwargs: Any) -> None:
|
||||
self.__absolute: bool = kwargs.pop("absolute")
|
||||
self.__absolute_win98_fix: bool = kwargs.pop("absolute_win98_fix")
|
||||
self.__horizontal_wheel: bool = kwargs.pop("horizontal_wheel")
|
||||
|
||||
super().__init__(
|
||||
@@ -55,6 +54,16 @@ class MouseProcess(BaseDeviceProcess):
|
||||
self.__pressed_buttons = 0
|
||||
self.__x = 0 # For absolute
|
||||
self.__y = 0
|
||||
self.__win98_fix = False
|
||||
|
||||
def is_absolute(self) -> bool:
|
||||
return self.__absolute
|
||||
|
||||
def set_win98_fix(self, enabled: bool) -> None:
|
||||
self.__win98_fix = enabled
|
||||
|
||||
def get_win98_fix(self) -> bool:
|
||||
return self.__win98_fix
|
||||
|
||||
def cleanup(self) -> None:
|
||||
self._stop()
|
||||
@@ -82,7 +91,7 @@ class MouseProcess(BaseDeviceProcess):
|
||||
|
||||
def send_move_event(self, to_x: int, to_y: int) -> None:
|
||||
if self.__absolute:
|
||||
self._queue_event(MouseMoveEvent(to_x, to_y))
|
||||
self._queue_event(MouseMoveEvent(to_x, to_y, self.__win98_fix))
|
||||
|
||||
def send_relative_event(self, delta_x: int, delta_y: int) -> None:
|
||||
if not self.__absolute:
|
||||
@@ -144,12 +153,6 @@ class MouseProcess(BaseDeviceProcess):
|
||||
assert relative_event is None
|
||||
move_x = self.__x
|
||||
move_y = self.__y
|
||||
if self.__absolute_win98_fix:
|
||||
# https://github.com/pikvm/pikvm/issues/159
|
||||
# For some reason, the correct implementation of this fix
|
||||
# is a shift to the left, and not to the right, as in VirtualBox
|
||||
move_x <<= 1
|
||||
move_y <<= 1
|
||||
else:
|
||||
assert self.__x == self.__y == 0
|
||||
if relative_event is not None:
|
||||
|
||||
@@ -37,7 +37,7 @@ def valid_hid_keyboard_output(arg: Any) -> str:
|
||||
|
||||
|
||||
def valid_hid_mouse_output(arg: Any) -> str:
|
||||
return check_string_in_list(arg, "Mouse output", ["usb", "usb_rel", "ps2", "disabled"])
|
||||
return check_string_in_list(arg, "Mouse output", ["usb", "usb_win98", "usb_rel", "ps2", "disabled"])
|
||||
|
||||
|
||||
def valid_hid_key(arg: Any) -> str:
|
||||
|
||||
@@ -10,6 +10,9 @@ kvmd:
|
||||
device: /dev/null
|
||||
mouse:
|
||||
device: /dev/null
|
||||
# absolute_win98_fix: true
|
||||
# mouse_alt:
|
||||
# device: /dev/null
|
||||
noop: true
|
||||
|
||||
msd:
|
||||
|
||||
@@ -133,6 +133,7 @@ export function Hid(__getResolution) {
|
||||
let html = "";
|
||||
for (let args of [
|
||||
["USB", "usb", false],
|
||||
["USB Win98", "usb_win98", false],
|
||||
["USB Relative", "usb_rel", true],
|
||||
["PS/2", "ps2", true],
|
||||
["Off", "disabled"],
|
||||
|
||||
Reference in New Issue
Block a user