summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMaxim Devaev <[email protected]>2024-11-03 18:28:28 +0200
committerMaxim Devaev <[email protected]>2024-11-03 18:28:28 +0200
commitd93639ba8dcd003f82221f4ed99159755f2213c3 (patch)
treecc3291955215ec1455f26922f50de27563d47a5f
parent1e277c0f06f25e67a35a1b2910ed59333f97f6c0 (diff)
hid with granularity prototype
-rw-r--r--kvmd/apps/vnc/server.py6
-rw-r--r--kvmd/plugins/hid/__init__.py13
-rw-r--r--kvmd/plugins/hid/_mcu/__init__.py1
-rw-r--r--kvmd/plugins/hid/bt/__init__.py1
-rw-r--r--kvmd/plugins/hid/ch9329/__init__.py1
-rw-r--r--kvmd/plugins/hid/otg/__init__.py1
-rw-r--r--web/kvm/index.html32
-rw-r--r--web/kvm/navbar-system.pug17
-rw-r--r--web/share/js/kvm/hid.js182
9 files changed, 164 insertions, 90 deletions
diff --git a/kvmd/apps/vnc/server.py b/kvmd/apps/vnc/server.py
index c14bb21f..e8524a38 100644
--- a/kvmd/apps/vnc/server.py
+++ b/kvmd/apps/vnc/server.py
@@ -189,7 +189,11 @@ class _Client(RfbClient): # pylint: disable=too-many-instance-attributes
self.__shared_params.name = name
elif event_type == "hid_state":
- if self._encodings.has_leds_state:
+ if (
+ self._encodings.has_leds_state
+ and ("keyboard" in event)
+ and ("leds" in event["keyboard"])
+ ):
await self._send_leds_state(**event["keyboard"]["leds"])
# =====
diff --git a/kvmd/plugins/hid/__init__.py b/kvmd/plugins/hid/__init__.py
index f7debe1d..73ff5d04 100644
--- a/kvmd/plugins/hid/__init__.py
+++ b/kvmd/plugins/hid/__init__.py
@@ -101,6 +101,19 @@ class BaseHid(BasePlugin): # pylint: disable=too-many-instance-attributes
raise NotImplementedError
async def poll_state(self) -> AsyncGenerator[dict, None]:
+ # ==== Granularity table ====
+ # - enabled -- Full
+ # - online -- Partial
+ # - busy -- Partial
+ # - connected -- Partial, nullable
+ # - keyboard.online -- Partial
+ # - keyboard.outputs -- Partial
+ # - keyboard.leds -- Partial
+ # - mouse.online -- Partial
+ # - mouse.outputs -- Partial, follows with absolute
+ # - mouse.absolute -- Partial, follows with outputs
+ # ===========================
+
yield {}
raise NotImplementedError
diff --git a/kvmd/plugins/hid/_mcu/__init__.py b/kvmd/plugins/hid/_mcu/__init__.py
index a4c903b7..d6f04f76 100644
--- a/kvmd/plugins/hid/_mcu/__init__.py
+++ b/kvmd/plugins/hid/_mcu/__init__.py
@@ -217,6 +217,7 @@ class BaseMcuHid(BaseHid, multiprocessing.Process): # pylint: disable=too-many-
mouse_outputs["active"] = active_mouse
return {
+ "enabled": True,
"online": online,
"busy": bool(state["busy"]),
"connected": (bool(outputs2 & 0b01000000) if outputs2 & 0b10000000 else None),
diff --git a/kvmd/plugins/hid/bt/__init__.py b/kvmd/plugins/hid/bt/__init__.py
index 4d0effb5..0c95a6d5 100644
--- a/kvmd/plugins/hid/bt/__init__.py
+++ b/kvmd/plugins/hid/bt/__init__.py
@@ -141,6 +141,7 @@ class Plugin(BaseHid): # pylint: disable=too-many-instance-attributes
state = await self.__server.get_state()
outputs: dict = {"available": [], "active": ""}
return {
+ "enabled": True,
"online": True,
"busy": False,
"connected": None,
diff --git a/kvmd/plugins/hid/ch9329/__init__.py b/kvmd/plugins/hid/ch9329/__init__.py
index c5d10688..1b235090 100644
--- a/kvmd/plugins/hid/ch9329/__init__.py
+++ b/kvmd/plugins/hid/ch9329/__init__.py
@@ -104,6 +104,7 @@ class Plugin(BaseHid, multiprocessing.Process): # pylint: disable=too-many-inst
absolute = self.__mouse.is_absolute()
leds = await self.__keyboard.get_leds()
return {
+ "enabled": True,
"online": state["online"],
"busy": False,
"connected": None,
diff --git a/kvmd/plugins/hid/otg/__init__.py b/kvmd/plugins/hid/otg/__init__.py
index c95fb7fb..25424257 100644
--- a/kvmd/plugins/hid/otg/__init__.py
+++ b/kvmd/plugins/hid/otg/__init__.py
@@ -134,6 +134,7 @@ class Plugin(BaseHid): # pylint: disable=too-many-instance-attributes
keyboard_state = await self.__keyboard_proc.get_state()
mouse_state = await self.__mouse_current.get_state()
return {
+ "enabled": True,
"online": True,
"busy": False,
"connected": None,
diff --git a/web/kvm/index.html b/web/kvm/index.html
index d2f264df..81eb9753 100644
--- a/web/kvm/index.html
+++ b/web/kvm/index.html
@@ -256,23 +256,21 @@
<button class="row33" data-force-hide-menu id="stream-screenshot-button">&bull; Screenshot</button>
<button class="row33" id="stream-reset-button">Reset stream</button>
</div>
- <div class="feature-disabled" id="hid-outputs">
- <hr>
- <table class="kv">
- <tr class="feature-disabled" id="hid-outputs-keyboard">
- <td>Keyboard mode:</td>
- <td>
- <div class="radio-box" id="hid-outputs-keyboard-box"></div>
- </td>
- </tr>
- <tr class="feature-disabled" id="hid-outputs-mouse">
- <td>Mouse <a target="_blank" href="https://docs.pikvm.org/mouse">mode</a>:</td>
- <td>
- <div class="radio-box" id="hid-outputs-mouse-box"></div>
- </td>
- </tr>
- </table>
- </div>
+ <hr>
+ <table class="kv">
+ <tr class="feature-disabled" id="hid-outputs-keyboard">
+ <td>Keyboard mode:</td>
+ <td>
+ <div class="radio-box" id="hid-outputs-keyboard-box"></div>
+ </td>
+ </tr>
+ <tr class="feature-disabled" id="hid-outputs-mouse">
+ <td>Mouse <a target="_blank" href="https://docs.pikvm.org/mouse">mode</a>:</td>
+ <td>
+ <div class="radio-box" id="hid-outputs-mouse-box"></div>
+ </td>
+ </tr>
+ </table>
<details>
<summary>Keyboard &amp; Mouse (HID) settings</summary>
<div class="spoiler">
diff --git a/web/kvm/navbar-system.pug b/web/kvm/navbar-system.pug
index d10dbee0..6e2a33d2 100644
--- a/web/kvm/navbar-system.pug
+++ b/web/kvm/navbar-system.pug
@@ -71,15 +71,14 @@ li(id="system-dropdown" class="right")
button(data-force-hide-menu data-show-window="stream-window" class="row33") &bull; Show stream
button(data-force-hide-menu id="stream-screenshot-button" class="row33") &bull; Screenshot
button(id="stream-reset-button" class="row33") Reset stream
- div(id="hid-outputs" class="feature-disabled")
- hr
- table(class="kv")
- tr(id="hid-outputs-keyboard", class="feature-disabled")
- td Keyboard mode:
- td #[div(id="hid-outputs-keyboard-box" class="radio-box")]
- tr(id="hid-outputs-mouse", class="feature-disabled")
- td Mouse #[a(target="_blank" href="https://docs.pikvm.org/mouse") mode]:
- td #[div(id="hid-outputs-mouse-box" class="radio-box")]
+ hr
+ table(class="kv")
+ tr(id="hid-outputs-keyboard", class="feature-disabled")
+ td Keyboard mode:
+ td #[div(id="hid-outputs-keyboard-box" class="radio-box")]
+ tr(id="hid-outputs-mouse", class="feature-disabled")
+ td Mouse #[a(target="_blank" href="https://docs.pikvm.org/mouse") mode]:
+ td #[div(id="hid-outputs-mouse-box" class="radio-box")]
details
summary Keyboard &amp; Mouse (HID) settings
div(class="spoiler")
diff --git a/web/share/js/kvm/hid.js b/web/share/js/kvm/hid.js
index e7aa29e6..65bd480d 100644
--- a/web/share/js/kvm/hid.js
+++ b/web/share/js/kvm/hid.js
@@ -35,6 +35,7 @@ export function Hid(__getGeometry, __recorder) {
/************************************************************************/
+ var __state = null;
var __keyboard = null;
var __mouse = null;
@@ -102,8 +103,6 @@ export function Hid(__getGeometry, __recorder) {
/************************************************************************/
self.setSocket = function(ws) {
- tools.el.setEnabled($("hid-reset-button"), ws);
- tools.el.setEnabled($("hid-jiggler-switch"), ws);
if (!ws) {
self.setState(null);
}
@@ -112,78 +111,135 @@ export function Hid(__getGeometry, __recorder) {
};
self.setState = function(state) {
- let has_relative_squash = false;
-
if (state) {
- tools.feature.setEnabled($("hid-jiggler"), state.jiggler.enabled);
- $("hid-jiggler-switch").checked = state.jiggler.active;
+ if (!__state) {
+ __state = {"keyboard": {}, "mouse": {}};
+ }
+ if (state.enabled !== undefined) {
+ __state.enabled = state.enabled; // Currently unused, always true
+ }
+ if (__state.enabled !== undefined) {
+ for (let key of ["online", "busy", "connected", "jiggler"]) {
+ if (state[key] !== undefined) {
+ __state[key] = state[key];
+ }
+ }
+ for (let hid of ["keyboard", "mouse"]) {
+ if (state[hid] === undefined) {
+ state[hid] = {}; // Add some stubs for processing
+ }
+ for (let key of ["online", "outputs", (hid === "keyboard" ? "leds" : "absolute")]) {
+ __state[hid][key] = state[hid][key];
+ }
+ }
+ if (state.connected !== undefined) {
+ tools.feature.setEnabled($("hid-connect"), (__state.connected !== null));
+ $("hid-connect-switch").checked = !!__state.connected;
+ }
+ if (state.jiggler !== undefined) {
+ tools.feature.setEnabled($("hid-jiggler"), __state.jiggler.enabled);
+ $("hid-jiggler-switch").checked = __state.jiggler.active;
+ }
+ if (state.keyboard.outputs !== undefined) {
+ __updateKeyboardOutputs(__state.keyboard.outputs);
+ }
+ if (state.mouse.outputs !== undefined) {
+ __updateMouseOutputs(__state.mouse.outputs, __state.mouse.absolute); // Follows together
+ }
+ if (
+ state.keyboard.online !== undefined || state.keyboard.leds !== undefined
+ || state.online !== undefined || state.busy !== undefined
+ ) {
+ __keyboard.setState(__state.keyboard.online, __state.keyboard.leds, __state.online, __state.busy);
+ }
+ if (
+ state.mouse.online !== undefined || state.mouse.absolute !== undefined
+ || state.online !== undefined || state.busy !== undefined
+ ) {
+ __mouse.setState(__state.mouse.online, __state.mouse.absolute, __state.online, __state.busy);
+ }
+ if (state.online !== undefined || state.busy !== undefined) {
+ tools.radio.setEnabled("hid-outputs-keyboard-radio", (__state.online && !__state.busy));
+ tools.radio.setEnabled("hid-outputs-mouse-radio", (__state.online && !__state.busy));
+ tools.el.setEnabled($("hid-connect-switch"), (__state.online && !__state.busy));
+ }
+ }
+ } else {
+ __state = null;
+ tools.radio.setEnabled("hid-outputs-keyboard-radio", false);
+ tools.radio.setEnabled("hid-outputs-mouse-radio", false);
+ tools.el.setEnabled($("hid-connect-switch"), false);
+ tools.el.setEnabled($("hid-mouse-squash-switch"), false);
+ tools.el.setEnabled($("hid-mouse-sens-slider"), false);
}
- if (state && state.online) {
- let keyboard_outputs = state.keyboard.outputs.available;
- let mouse_outputs = state.mouse.outputs.available;
- if (keyboard_outputs.length) {
- if ($("hid-outputs-keyboard-box").outputs !== keyboard_outputs) {
- let html = "";
- for (let args of [
- ["USB", "usb"],
- ["PS/2", "ps2"],
- ["Off", "disabled"],
- ]) {
- if (keyboard_outputs.includes(args[1])) {
- html += tools.radio.makeItem("hid-outputs-keyboard-radio", args[0], args[1]);
- }
+ tools.el.setEnabled($("hid-reset-button"), __state);
+ tools.el.setEnabled($("hid-jiggler-switch"), __state);
+ };
+
+ var __updateKeyboardOutputs = function(outputs) {
+ let avail = outputs.available;
+ if (avail.length > 0) {
+ let el = $("hid-outputs-keyboard-box");
+ let avail_json = JSON.stringify(avail);
+ if (el.__avail_json !== avail_json) {
+ let html = "";
+ for (let pair of [
+ ["USB", "usb"],
+ ["PS/2", "ps2"],
+ ["Off", "disabled"],
+ ]) {
+ if (avail.includes(pair[1])) {
+ html += tools.radio.makeItem("hid-outputs-keyboard-radio", pair[0], pair[1]);
}
- $("hid-outputs-keyboard-box").innerHTML = html;
- $("hid-outputs-keyboard-box").outputs = keyboard_outputs;
- tools.radio.setOnClick("hid-outputs-keyboard-radio", () => __clickOutputsRadio("keyboard"));
}
- tools.radio.setValue("hid-outputs-keyboard-radio", state.keyboard.outputs.active);
+ el.innerHTML = html;
+ tools.radio.setOnClick("hid-outputs-keyboard-radio", () => __clickOutputsRadio("keyboard"));
+ el.__avail_json = avail_json;
}
- let has_relative = false;
- if (mouse_outputs.length) {
- if ($("hid-outputs-mouse-box").outputs !== mouse_outputs) {
- let html = "";
- for (let args of [
- ["Absolute", "usb", false],
- ["Abs-Win98", "usb_win98", false],
- ["Relative", "usb_rel", true],
- ["PS/2", "ps2", true],
- ["Off", "disabled"],
- ]) {
- if (mouse_outputs.includes(args[1])) {
- html += tools.radio.makeItem("hid-outputs-mouse-radio", args[0], args[1]);
- has_relative = (has_relative || args[2]);
- }
+ tools.radio.setValue("hid-outputs-keyboard-radio", outputs.active);
+ }
+ tools.feature.setEnabled($("hid-outputs-keyboard"), (avail.length > 0));
+ };
+
+ var __updateMouseOutputs = function(outputs, absolute) {
+ let has_relative = null;
+ let has_relative_squash = null;
+ let avail = outputs.available;
+ if (avail.length > 0) {
+ let el = $("hid-outputs-mouse-box");
+ let avail_json = JSON.stringify(avail);
+ if (el.__avail_json !== avail_json) {
+ has_relative = false;
+ let html = "";
+ for (let pair of [
+ ["Absolute", "usb", false],
+ ["Abs-Win98", "usb_win98", false],
+ ["Relative", "usb_rel", true],
+ ["PS/2", "ps2", true],
+ ["Off", "disabled", false],
+ ]) {
+ if (avail.includes(pair[1])) {
+ html += tools.radio.makeItem("hid-outputs-mouse-radio", pair[0], pair[1]);
+ has_relative = (has_relative || pair[2]);
}
- $("hid-outputs-mouse-box").innerHTML = html;
- $("hid-outputs-mouse-box").outputs = mouse_outputs;
- tools.radio.setOnClick("hid-outputs-mouse-radio", () => __clickOutputsRadio("mouse"));
}
- tools.radio.setValue("hid-outputs-mouse-radio", state.mouse.outputs.active);
- has_relative_squash = ["usb_rel", "ps2"].includes(state.mouse.outputs.active);
- } else {
- has_relative = !state.mouse.absolute;
- has_relative_squash = has_relative;
+ el.innerHTML = html;
+ tools.radio.setOnClick("hid-outputs-mouse-radio", () => __clickOutputsRadio("mouse"));
+ el.__avail_json = avail_json;
}
- tools.feature.setEnabled($("hid-outputs"), (keyboard_outputs.length || mouse_outputs.length));
- tools.feature.setEnabled($("hid-outputs-keyboard"), keyboard_outputs.length);
- tools.feature.setEnabled($("hid-outputs-mouse"), mouse_outputs.length);
+ tools.radio.setValue("hid-outputs-mouse-radio", outputs.active);
+ has_relative_squash = (["usb_rel", "ps2"].includes(outputs.active));
+ } else {
+ has_relative = !absolute;
+ has_relative_squash = has_relative;
+ }
+ if (has_relative !== null) {
tools.feature.setEnabled($("hid-mouse-squash"), has_relative);
tools.feature.setEnabled($("hid-mouse-sens"), has_relative);
- tools.feature.setEnabled($("hid-connect"), (state.connected !== null));
- $("hid-connect-switch").checked = !!state.connected;
- }
-
- tools.radio.setEnabled("hid-outputs-keyboard-radio", (state && state.online && !state.busy));
- tools.radio.setEnabled("hid-outputs-mouse-radio", (state && state.online && !state.busy));
- tools.el.setEnabled($("hid-mouse-squash-switch"), (has_relative_squash && !state.busy));
- tools.el.setEnabled($("hid-mouse-sens-slider"), (has_relative_squash && !state.busy));
- tools.el.setEnabled($("hid-connect-switch"), (state && state.online && !state.busy));
-
- if (state) {
- __keyboard.setState(state.keyboard.online, state.keyboard.leds, state.online, state.busy);
- __mouse.setState(state.mouse.online, state.mouse.absolute, state.online, state.busy);
}
+ tools.feature.setEnabled($("hid-outputs-mouse"), (avail.length > 0));
+ tools.el.setEnabled($("hid-mouse-squash-switch"), has_relative_squash);
+ tools.el.setEnabled($("hid-mouse-sens-slider"), has_relative_squash);
};
var __releaseAll = function() {