mirror of https://github.com/jetkvm/kvm.git
Compare commits
2 Commits
7622697887
...
5e6da5b782
Author | SHA1 | Date |
---|---|---|
|
5e6da5b782 | |
|
94f6bbd27a |
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"name": "kvm-ui",
|
||||
"version": "2025.08.15.001",
|
||||
"version": "2025.08.15.2119",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "kvm-ui",
|
||||
"version": "2025.08.15.001",
|
||||
"version": "2025.08.15.2119",
|
||||
"dependencies": {
|
||||
"@headlessui/react": "^2.2.7",
|
||||
"@headlessui/tailwindcss": "^0.2.2",
|
||||
|
@ -28,10 +28,10 @@
|
|||
"react": "^19.1.1",
|
||||
"react-animate-height": "^3.2.3",
|
||||
"react-dom": "^19.1.1",
|
||||
"react-hot-toast": "^2.5.2",
|
||||
"react-hot-toast": "^2.6.0",
|
||||
"react-icons": "^5.5.0",
|
||||
"react-router-dom": "^6.22.3",
|
||||
"react-simple-keyboard": "^3.8.109",
|
||||
"react-simple-keyboard": "^3.8.111",
|
||||
"react-use-websocket": "^4.13.0",
|
||||
"react-xtermjs": "^1.0.10",
|
||||
"recharts": "^2.15.3",
|
||||
|
@ -3156,9 +3156,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/electron-to-chromium": {
|
||||
"version": "1.5.201",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.201.tgz",
|
||||
"integrity": "sha512-ZG65vsrLClodGqywuigc+7m0gr4ISoTQttfVh7nfpLv0M7SIwF4WbFNEOywcqTiujs12AUeeXbFyQieDICAIxg==",
|
||||
"version": "1.5.202",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.202.tgz",
|
||||
"integrity": "sha512-NxbYjRmiHcHXV1Ws3fWUW+SLb62isauajk45LUJ/HgIOkUA7jLZu/X2Iif+X9FBNK8QkF9Zb4Q2mcwXCcY30mg==",
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
|
@ -5784,9 +5784,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/react-hot-toast": {
|
||||
"version": "2.5.2",
|
||||
"resolved": "https://registry.npmjs.org/react-hot-toast/-/react-hot-toast-2.5.2.tgz",
|
||||
"integrity": "sha512-Tun3BbCxzmXXM7C+NI4qiv6lT0uwGh4oAfeJyNOjYUejTsm35mK9iCaYLGv8cBz9L5YxZLx/2ii7zsIwPtPUdw==",
|
||||
"version": "2.6.0",
|
||||
"resolved": "https://registry.npmjs.org/react-hot-toast/-/react-hot-toast-2.6.0.tgz",
|
||||
"integrity": "sha512-bH+2EBMZ4sdyou/DPrfgIouFpcRLCJ+HoCA32UoAYHn6T3Ur5yfcDCeSr5mwldl6pFOsiocmrXMuoCJ1vV8bWg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"csstype": "^3.1.3",
|
||||
|
@ -5848,9 +5848,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/react-simple-keyboard": {
|
||||
"version": "3.8.109",
|
||||
"resolved": "https://registry.npmjs.org/react-simple-keyboard/-/react-simple-keyboard-3.8.109.tgz",
|
||||
"integrity": "sha512-FLlivKL4tb5G2cWOo2slOrMEkzzFX0Yg8P7k5qzisN8+TnqUPq+8G7N8D2+0oVkSmfeqZn6PyLCurGSitK4QIQ==",
|
||||
"version": "3.8.111",
|
||||
"resolved": "https://registry.npmjs.org/react-simple-keyboard/-/react-simple-keyboard-3.8.111.tgz",
|
||||
"integrity": "sha512-zR6qeGeH1bhaP8GDMLwRBqpyU98jGUOmuNKZT6Z0056kjR4EVRo99Z/eVCafN0ySKpweQ6x0gVAjxkegy6EDFg==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"react": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "kvm-ui",
|
||||
"private": true,
|
||||
"version": "2025.08.15.001",
|
||||
"version": "2025.08.15.2119",
|
||||
"type": "module",
|
||||
"engines": {
|
||||
"node": "22.15.0"
|
||||
|
@ -39,10 +39,10 @@
|
|||
"react": "^19.1.1",
|
||||
"react-animate-height": "^3.2.3",
|
||||
"react-dom": "^19.1.1",
|
||||
"react-hot-toast": "^2.5.2",
|
||||
"react-hot-toast": "^2.6.0",
|
||||
"react-icons": "^5.5.0",
|
||||
"react-router-dom": "^6.22.3",
|
||||
"react-simple-keyboard": "^3.8.109",
|
||||
"react-simple-keyboard": "^3.8.111",
|
||||
"react-use-websocket": "^4.13.0",
|
||||
"react-xtermjs": "^1.0.10",
|
||||
"recharts": "^2.15.3",
|
||||
|
|
|
@ -36,7 +36,7 @@ export function useJsonRpc(onRequest?: (payload: JsonRpcRequest) => void) {
|
|||
const { rpcDataChannel } = useRTCStore();
|
||||
|
||||
const send = useCallback(
|
||||
(method: string, params: unknown, callback?: (resp: JsonRpcResponse) => void) => {
|
||||
async (method: string, params: unknown, callback?: (resp: JsonRpcResponse) => void) => {
|
||||
if (rpcDataChannel?.readyState !== "open") return;
|
||||
requestCounter++;
|
||||
const payload = { jsonrpc: "2.0", method, params, id: requestCounter };
|
||||
|
@ -61,7 +61,7 @@ export function useJsonRpc(onRequest?: (payload: JsonRpcRequest) => void) {
|
|||
return;
|
||||
}
|
||||
|
||||
if ("error" in payload) console.error(payload.error);
|
||||
if ("error" in payload) console.error("RPC error", payload);
|
||||
if (!payload.id) return;
|
||||
|
||||
const callback = callbackStore.get(payload.id);
|
||||
|
|
|
@ -28,7 +28,7 @@ export default function useKeyboard() {
|
|||
// The device will respond with the keysDownState if it supports the keyPressReport API
|
||||
// or just accept the state if it does not support (returning no result)
|
||||
const sendKeyboardEvent = useCallback(
|
||||
(state: KeysDownState) => {
|
||||
async (state: KeysDownState) => {
|
||||
if (rpcDataChannel?.readyState !== "open") return;
|
||||
|
||||
console.debug(`Send keyboardReport keys: ${state.keys}, modifier: ${state.modifier}`);
|
||||
|
@ -45,13 +45,14 @@ export default function useKeyboard() {
|
|||
setkeyPressReportApiAvailable(true); // if they returned a keysDownState, we ALSO know they also support keyPressReport
|
||||
} else {
|
||||
// older devices versions do not return the keyDownState
|
||||
setKeysDownState(state); // we just pretend they accepted what we sent
|
||||
// so we just pretend they accepted what we sent
|
||||
setKeysDownState(state);
|
||||
setkeyPressReportApiAvailable(false); // we ALSO know they do not support keyPressReport
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
[rpcDataChannel?.readyState, send, setkeyPressReportApiAvailable, setKeysDownState],
|
||||
[rpcDataChannel?.readyState, send, setKeysDownState, setkeyPressReportApiAvailable],
|
||||
);
|
||||
|
||||
// sendKeypressEvent is used to send a single key press/release event to the device.
|
||||
|
@ -61,7 +62,7 @@ export default function useKeyboard() {
|
|||
// In that case we will switch to local key handling and update the keysDownState
|
||||
// in client/browser-side code using simulateDeviceSideKeyHandlingForLegacyDevices.
|
||||
const sendKeypressEvent = useCallback(
|
||||
(key: number, press: boolean) => {
|
||||
async (key: number, press: boolean) => {
|
||||
if (rpcDataChannel?.readyState !== "open") return;
|
||||
|
||||
console.debug(`Send keypressEvent key: ${key}, press: ${press}`);
|
||||
|
@ -90,12 +91,15 @@ export default function useKeyboard() {
|
|||
// resetKeyboardState is used to reset the keyboard state to no keys pressed and no modifiers.
|
||||
// This is useful for macros and when the browser loses focus to ensure that the keyboard state
|
||||
// is clean.
|
||||
const resetKeyboardState = useCallback(() => {
|
||||
console.debug("Resetting keyboard state");
|
||||
keysDownState.keys.fill(0); // Reset the keys buffer to zeros
|
||||
keysDownState.modifier = 0; // Reset the modifier state to zero
|
||||
sendKeyboardEvent(keysDownState);
|
||||
}, [keysDownState, sendKeyboardEvent]);
|
||||
const resetKeyboardState = useCallback(
|
||||
async () => {
|
||||
console.debug("Resetting keyboard state");
|
||||
// Reset the keys buffer to zeros and the modifier state to zero
|
||||
keysDownState.keys.length = hidKeyBufferSize;
|
||||
keysDownState.keys.fill(0);
|
||||
keysDownState.modifier = 0;
|
||||
sendKeyboardEvent(keysDownState);
|
||||
}, [keysDownState, sendKeyboardEvent]);
|
||||
|
||||
// executeMacro is used to execute a macro consisting of multiple steps.
|
||||
// Each step can have multiple keys, multiple modifiers and a delay.
|
||||
|
@ -133,7 +137,7 @@ export default function useKeyboard() {
|
|||
// handling for legacy devices and updates the keysDownState accordingly.
|
||||
// It then sends the full keyboard state to the device.
|
||||
const handleKeyPress = useCallback(
|
||||
(key: number, press: boolean) => {
|
||||
async (key: number, press: boolean) => {
|
||||
if (rpcDataChannel?.readyState !== "open") return;
|
||||
|
||||
if (keyPressReportApiAvailable) {
|
||||
|
@ -143,9 +147,14 @@ export default function useKeyboard() {
|
|||
// if the keyPress api is not available, we need to handle the key locally
|
||||
const downState = simulateDeviceSideKeyHandlingForLegacyDevices(keysDownState, key, press);
|
||||
sendKeyboardEvent(downState); // then we send the full state
|
||||
|
||||
// if we just sent ErrorRollOver, reset to empty state
|
||||
if (downState.keys[0] === hidErrorRollOver) {
|
||||
resetKeyboardState();
|
||||
}
|
||||
}
|
||||
},
|
||||
[keyPressReportApiAvailable, keysDownState, rpcDataChannel?.readyState, sendKeyboardEvent, sendKeypressEvent],
|
||||
[keyPressReportApiAvailable, keysDownState, resetKeyboardState, rpcDataChannel?.readyState, sendKeyboardEvent, sendKeypressEvent],
|
||||
);
|
||||
|
||||
// IMPORTANT: See the keyPressReportApiAvailable comment above for the reason this exists
|
||||
|
@ -154,8 +163,8 @@ export default function useKeyboard() {
|
|||
// for handling key presses and releases. It ensures that the USB gadget
|
||||
// behaves similarly to a real USB HID keyboard. This logic is paralleled
|
||||
// in the device-side code in hid_keyboard.go so make sure to keep them in sync.
|
||||
const keys = state.keys;
|
||||
let modifiers = state.modifier;
|
||||
const keys = state.keys;
|
||||
const modifierMask = hidKeyToModifierMask[key] || 0;
|
||||
|
||||
if (modifierMask !== 0) {
|
||||
|
@ -163,7 +172,6 @@ export default function useKeyboard() {
|
|||
// by setting or clearing the corresponding bit in the modifier byte.
|
||||
// This allows us to track the state of dynamic modifier keys like
|
||||
// Shift, Control, Alt, and Super.
|
||||
console.debug(`Handling modifier key: ${key}, press: ${press}, current modifiers: ${modifiers}, modifier mask: ${modifierMask}`);
|
||||
if (press) {
|
||||
modifiers |= modifierMask;
|
||||
} else {
|
||||
|
@ -173,34 +181,35 @@ export default function useKeyboard() {
|
|||
// handle other keys that are not modifier keys by placing or removing them
|
||||
// from the key buffer since the buffer tracks currently pressed keys
|
||||
let overrun = true;
|
||||
for (let i = 0; i < hidKeyBufferSize && overrun; i++) {
|
||||
for (let i = 0; i < hidKeyBufferSize; i++) {
|
||||
// If we find the key in the buffer the buffer, we either remove it (if press is false)
|
||||
// or do nothing (if down is true) because the buffer tracks currently pressed keys
|
||||
// and if we find a zero byte, we can place the key there (if press is true)
|
||||
if (keys[i] == key || keys[i] == 0) {
|
||||
if (keys[i] === key || keys[i] === 0) {
|
||||
if (press) {
|
||||
keys[i] = key // overwrites the zero byte or the same key if already pressed
|
||||
} else {
|
||||
// we are releasing the key, remove it from the buffer
|
||||
if (keys[i] != 0) {
|
||||
if (keys[i] !== 0) {
|
||||
keys.splice(i, 1);
|
||||
keys.push(0); // add a zero at the end
|
||||
}
|
||||
}
|
||||
overrun = false // We found a slot for the key
|
||||
overrun = false; // We found a slot for the key
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If we reach here it means we didn't find an empty slot or the key in the buffer
|
||||
if (overrun) {
|
||||
if (press) {
|
||||
console.warn(`keyboard buffer overflow, key: ${key} not added`);
|
||||
// Fill all key slots with ErrorRollOver (0x01) to indicate overflow
|
||||
keys.length = 6;
|
||||
keys.fill(hidErrorRollOver);
|
||||
} else {
|
||||
// If we are releasing a key, and we didn't find it in a slot, who cares?
|
||||
console.debug(`key ${key} not found in buffer, nothing to release`)
|
||||
}
|
||||
// If we reach here it means we didn't find an empty slot or the key in the buffer
|
||||
if (overrun) {
|
||||
if (press) {
|
||||
console.warn(`keyboard buffer overflow current keys ${keys}, key: ${key} not added`);
|
||||
// Fill all key slots with ErrorRollOver (0x01) to indicate overflow
|
||||
keys.length = hidKeyBufferSize;
|
||||
keys.fill(hidErrorRollOver);
|
||||
} else {
|
||||
// If we are releasing a key, and we didn't find it in a slot, who cares?
|
||||
console.debug(`key ${key} not found in buffer, nothing to release`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -248,27 +248,27 @@ export default function KvmIdRoute() {
|
|||
reconnectAttempts: 15,
|
||||
reconnectInterval: 1000,
|
||||
onReconnectStop: () => {
|
||||
console.log("Reconnect stopped");
|
||||
console.debug("Reconnect stopped");
|
||||
cleanupAndStopReconnecting();
|
||||
},
|
||||
|
||||
shouldReconnect(event) {
|
||||
console.log("[Websocket] shouldReconnect", event);
|
||||
console.debug("[Websocket] shouldReconnect", event);
|
||||
// TODO: Why true?
|
||||
return true;
|
||||
},
|
||||
|
||||
onClose(event) {
|
||||
console.log("[Websocket] onClose", event);
|
||||
console.debug("[Websocket] onClose", event);
|
||||
// We don't want to close everything down, we wait for the reconnect to stop instead
|
||||
},
|
||||
|
||||
onError(event) {
|
||||
console.log("[Websocket] onError", event);
|
||||
console.error("[Websocket] onError", event);
|
||||
// We don't want to close everything down, we wait for the reconnect to stop instead
|
||||
},
|
||||
onOpen() {
|
||||
console.log("[Websocket] onOpen");
|
||||
console.debug("[Websocket] onOpen");
|
||||
},
|
||||
|
||||
onMessage: message => {
|
||||
|
@ -290,8 +290,8 @@ export default function KvmIdRoute() {
|
|||
const parsedMessage = JSON.parse(message.data);
|
||||
if (parsedMessage.type === "device-metadata") {
|
||||
const { deviceVersion } = parsedMessage.data;
|
||||
console.log("[Websocket] Received device-metadata message");
|
||||
console.log("[Websocket] Device version", deviceVersion);
|
||||
console.debug("[Websocket] Received device-metadata message");
|
||||
console.debug("[Websocket] Device version", deviceVersion);
|
||||
// If the device version is not set, we can assume the device is using the legacy signaling
|
||||
if (!deviceVersion) {
|
||||
console.log("[Websocket] Device is using legacy signaling");
|
||||
|
@ -309,7 +309,7 @@ export default function KvmIdRoute() {
|
|||
|
||||
if (!peerConnection) return;
|
||||
if (parsedMessage.type === "answer") {
|
||||
console.log("[Websocket] Received answer");
|
||||
console.debug("[Websocket] Received answer");
|
||||
const readyForOffer =
|
||||
// If we're making an offer, we don't want to accept an answer
|
||||
!makingOffer &&
|
||||
|
@ -323,7 +323,7 @@ export default function KvmIdRoute() {
|
|||
|
||||
// Set so we don't accept an answer while we're setting the remote description
|
||||
isSettingRemoteAnswerPending.current = parsedMessage.type === "answer";
|
||||
console.log(
|
||||
console.debug(
|
||||
"[Websocket] Setting remote answer pending",
|
||||
isSettingRemoteAnswerPending.current,
|
||||
);
|
||||
|
@ -339,7 +339,7 @@ export default function KvmIdRoute() {
|
|||
// Reset the remote answer pending flag
|
||||
isSettingRemoteAnswerPending.current = false;
|
||||
} else if (parsedMessage.type === "new-ice-candidate") {
|
||||
console.log("[Websocket] Received new-ice-candidate");
|
||||
console.debug("[Websocket] Received new-ice-candidate");
|
||||
const candidate = parsedMessage.data;
|
||||
peerConnection.addIceCandidate(candidate);
|
||||
}
|
||||
|
@ -385,7 +385,7 @@ export default function KvmIdRoute() {
|
|||
return;
|
||||
}
|
||||
|
||||
console.log("Successfully got Remote Session Description. Setting.");
|
||||
console.debug("Successfully got Remote Session Description. Setting.");
|
||||
setLoadingMessage("Setting remote session description...");
|
||||
|
||||
const decodedSd = atob(json.sd);
|
||||
|
@ -396,13 +396,13 @@ export default function KvmIdRoute() {
|
|||
);
|
||||
|
||||
const setupPeerConnection = useCallback(async () => {
|
||||
console.log("[setupPeerConnection] Setting up peer connection");
|
||||
console.debug("[setupPeerConnection] Setting up peer connection");
|
||||
setConnectionFailed(false);
|
||||
setLoadingMessage("Connecting to device...");
|
||||
|
||||
let pc: RTCPeerConnection;
|
||||
try {
|
||||
console.log("[setupPeerConnection] Creating peer connection");
|
||||
console.debug("[setupPeerConnection] Creating peer connection");
|
||||
setLoadingMessage("Creating peer connection...");
|
||||
pc = new RTCPeerConnection({
|
||||
// We only use STUN or TURN servers if we're in the cloud
|
||||
|
@ -412,7 +412,7 @@ export default function KvmIdRoute() {
|
|||
});
|
||||
|
||||
setPeerConnectionState(pc.connectionState);
|
||||
console.log("[setupPeerConnection] Peer connection created", pc);
|
||||
console.debug("[setupPeerConnection] Peer connection created", pc);
|
||||
setLoadingMessage("Setting up connection to device...");
|
||||
} catch (e) {
|
||||
console.error(`[setupPeerConnection] Error creating peer connection: ${e}`);
|
||||
|
@ -424,13 +424,13 @@ export default function KvmIdRoute() {
|
|||
|
||||
// Set up event listeners and data channels
|
||||
pc.onconnectionstatechange = () => {
|
||||
console.log("[setupPeerConnection] Connection state changed", pc.connectionState);
|
||||
console.debug("[setupPeerConnection] Connection state changed", pc.connectionState);
|
||||
setPeerConnectionState(pc.connectionState);
|
||||
};
|
||||
|
||||
pc.onnegotiationneeded = async () => {
|
||||
try {
|
||||
console.log("[setupPeerConnection] Creating offer");
|
||||
console.debug("[setupPeerConnection] Creating offer");
|
||||
makingOffer.current = true;
|
||||
|
||||
const offer = await pc.createOffer();
|
||||
|
@ -462,7 +462,7 @@ export default function KvmIdRoute() {
|
|||
pc.onicegatheringstatechange = event => {
|
||||
const pc = event.currentTarget as RTCPeerConnection;
|
||||
if (pc.iceGatheringState === "complete") {
|
||||
console.log("ICE Gathering completed");
|
||||
console.debug("ICE Gathering completed");
|
||||
setLoadingMessage("ICE Gathering completed");
|
||||
|
||||
if (isLegacySignalingEnabled.current) {
|
||||
|
@ -470,7 +470,7 @@ export default function KvmIdRoute() {
|
|||
legacyHTTPSignaling(pc);
|
||||
}
|
||||
} else if (pc.iceGatheringState === "gathering") {
|
||||
console.log("ICE Gathering Started");
|
||||
console.debug("ICE Gathering Started");
|
||||
setLoadingMessage("Gathering ICE candidates...");
|
||||
}
|
||||
};
|
||||
|
@ -597,11 +597,15 @@ export default function KvmIdRoute() {
|
|||
}
|
||||
|
||||
if (resp.method === "usbState") {
|
||||
setUsbState(resp.params as unknown as USBStates);
|
||||
const usbState = resp.params as unknown as USBStates;
|
||||
console.debug("Setting USB state", usbState);
|
||||
setUsbState(usbState);
|
||||
}
|
||||
|
||||
if (resp.method === "videoInputState") {
|
||||
setHdmiState(resp.params as Parameters<VideoState["setHdmiState"]>[0]);
|
||||
const hdmiState = resp.params as Parameters<VideoState["setHdmiState"]>[0];
|
||||
console.debug("Setting HDMI state", hdmiState);
|
||||
setHdmiState(hdmiState);
|
||||
}
|
||||
|
||||
if (resp.method === "networkState") {
|
||||
|
@ -617,16 +621,14 @@ export default function KvmIdRoute() {
|
|||
|
||||
if (resp.method === "keysDownState") {
|
||||
const downState = resp.params as KeysDownState;
|
||||
|
||||
if (downState) {
|
||||
console.debug("Setting key down state:", downState);
|
||||
setKeysDownState(downState);
|
||||
setkeyPressReportApiAvailable(true); // if they returned a keyDownState, we know they also support keyPressReport
|
||||
}
|
||||
console.debug("Setting key down state:", downState);
|
||||
setKeysDownState(downState);
|
||||
setkeyPressReportApiAvailable(true); // if they returned a keyDownState, we know they also support keyPressReport
|
||||
}
|
||||
|
||||
if (resp.method === "otaState") {
|
||||
const otaState = resp.params as OtaState;
|
||||
console.debug("Setting OTA state", otaState);
|
||||
setOtaState(otaState);
|
||||
|
||||
if (otaState.updating === true) {
|
||||
|
@ -654,9 +656,12 @@ export default function KvmIdRoute() {
|
|||
|
||||
useEffect(() => {
|
||||
if (rpcDataChannel?.readyState !== "open") return;
|
||||
console.log("Requesting video state");
|
||||
send("getVideoState", {}, (resp: JsonRpcResponse) => {
|
||||
if ("error" in resp) return;
|
||||
setHdmiState(resp.result as Parameters<VideoState["setHdmiState"]>[0]);
|
||||
const hdmiState = resp.result as Parameters<VideoState["setHdmiState"]>[0];
|
||||
console.debug("Setting HDMI state", hdmiState);
|
||||
setHdmiState(hdmiState);
|
||||
});
|
||||
}, [rpcDataChannel?.readyState, send, setHdmiState]);
|
||||
|
||||
|
@ -672,12 +677,10 @@ export default function KvmIdRoute() {
|
|||
if ("error" in resp) {
|
||||
console.error("Failed to get keyboard led state", resp.error);
|
||||
return;
|
||||
}
|
||||
const ledState = resp.result as KeyboardLedState;
|
||||
|
||||
if (ledState) {
|
||||
console.debug("Keyboard led state: ", resp.result);
|
||||
setKeyboardLedState(resp.result as KeyboardLedState);
|
||||
} else {
|
||||
const ledState = resp.result as KeyboardLedState;
|
||||
console.debug("Keyboard led state: ", ledState);
|
||||
setKeyboardLedState(ledState);
|
||||
}
|
||||
setNeedLedState(false);
|
||||
});
|
||||
|
@ -696,19 +699,16 @@ export default function KvmIdRoute() {
|
|||
// -32601 means the method is not supported
|
||||
if (resp.error.code === -32601) {
|
||||
// if we don't support key down state, we know key press is also not available
|
||||
console.error("Failed to get key down state, switching to old-school", resp.error);
|
||||
console.warn("Failed to get key down state, switching to old-school", resp.error);
|
||||
setkeyPressReportApiAvailable(false);
|
||||
} else {
|
||||
console.error("Failed to get key down state", resp.error);
|
||||
}
|
||||
} else {
|
||||
const downState = resp.result as KeysDownState;
|
||||
|
||||
if (downState) {
|
||||
console.debug("Keyboard key down state", downState);
|
||||
setKeysDownState(downState);
|
||||
setkeyPressReportApiAvailable(true); // if they returned a keyDownState, we know they also support keyPressReport
|
||||
}
|
||||
console.debug("Keyboard key down state", downState);
|
||||
setKeysDownState(downState);
|
||||
setkeyPressReportApiAvailable(true); // if they returned a keyDownState, we know they also support keyPressReport
|
||||
}
|
||||
setNeedKeyDownState(false);
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue