From bf84660c8bdbc1a850c5dc767f114013eddd8762 Mon Sep 17 00:00:00 2001 From: luckfox-eng29 Date: Fri, 8 May 2026 09:59:04 +0800 Subject: [PATCH] feat(keyboard): update keyboard layouts and key display mappings for multiple languages Signed-off-by: luckfox-eng29 --- internal/hidrpc/hidrpc.go | 6 +++ internal/hidrpc/message.go | 4 ++ internal/usbgadget/hid_keyboard.go | 12 +++--- ui/src/keyboardLayouts/cs_CZ.ts | 28 +++++++++----- ui/src/keyboardLayouts/de_CH.ts | 11 +++++- ui/src/keyboardLayouts/de_DE.ts | 10 ++++- ui/src/keyboardLayouts/fr_BE.ts | 30 +++++++++++---- ui/src/keyboardLayouts/fr_CH.ts | 16 ++++++-- ui/src/keyboardLayouts/fr_FR.ts | 18 ++++++++- ui/src/keyboardLayouts/nb_NO.ts | 8 ++-- ui/src/keyboardLayouts/sl_SI.ts | 11 +++++- .../keyboard/KeyboardPanel.tsx | 16 ++++++-- .../core/bar_bottom/BottomBarMobile.tsx | 10 ++++- ui/src/layout/core/bar_bottom/BottomBarPC.tsx | 8 ++++ .../core/desktop/hooks/useKeyboardEvents.ts | 37 ++++++++++++++++--- usb.go | 8 ++++ 16 files changed, 190 insertions(+), 43 deletions(-) diff --git a/internal/hidrpc/hidrpc.go b/internal/hidrpc/hidrpc.go index 5f61a45..de4d3b4 100644 --- a/internal/hidrpc/hidrpc.go +++ b/internal/hidrpc/hidrpc.go @@ -3,6 +3,7 @@ package hidrpc import "fmt" type Handler interface { + HandleHandshake(version byte) error HandleKeyboardReport(modifier byte, keys []byte) error HandleKeypressReport(key byte, press bool) error HandleKeypressKeepAlive() error @@ -25,6 +26,11 @@ func (s *Server) HandleMessage(data []byte) error { } switch msg.Type { + case MessageTypeHandshake: + if len(msg.Data) < 1 { + return fmt.Errorf("invalid handshake length: %d", len(msg.Data)) + } + return s.handler.HandleHandshake(msg.Data[0]) case MessageTypeKeyboardReport: if len(msg.Data) < 7 { return fmt.Errorf("invalid keyboard report length: %d", len(msg.Data)) diff --git a/internal/hidrpc/message.go b/internal/hidrpc/message.go index ff751cf..429f349 100644 --- a/internal/hidrpc/message.go +++ b/internal/hidrpc/message.go @@ -30,6 +30,10 @@ func MarshalKeyboardReport(modifier byte, keys []byte) []byte { return data } +func MarshalHandshake(version byte) []byte { + return []byte{MessageTypeHandshake, version} +} + func MarshalKeypressReport(key byte, press bool) []byte { data := make([]byte, 3) data[0] = MessageTypeKeypressReport diff --git a/internal/usbgadget/hid_keyboard.go b/internal/usbgadget/hid_keyboard.go index b09b215..c9d21de 100644 --- a/internal/usbgadget/hid_keyboard.go +++ b/internal/usbgadget/hid_keyboard.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "os" + "os/exec" "reflect" "strings" "time" @@ -211,15 +212,16 @@ func (u *UsbGadget) OpenKeyboardHidFile() error { } func (u *UsbGadget) keyboardWriteHidFile(data []byte) error { - if err := u.openKeyboardHidFile(); err != nil { - return err + var parts []string + for _, b := range data { + parts = append(parts, fmt.Sprintf("\\x%02x", b)) } + hexString := strings.Join(parts, "") - _, err := u.keyboardHidFile.Write(data) + cmd := exec.Command("sh", "-c", fmt.Sprintf("echo -n -e '%s' > /dev/hidg0", hexString)) + err := cmd.Run() if err != nil { u.logWithSupression("keyboardWriteHidFile", 100, u.log, err, "failed to write to hidg0") - u.keyboardHidFile.Close() - u.keyboardHidFile = nil return err } u.resetLogSuppressionCounter("keyboardWriteHidFile") diff --git a/ui/src/keyboardLayouts/cs_CZ.ts b/ui/src/keyboardLayouts/cs_CZ.ts index 9131554..8e73c45 100644 --- a/ui/src/keyboardLayouts/cs_CZ.ts +++ b/ui/src/keyboardLayouts/cs_CZ.ts @@ -99,11 +99,11 @@ export const chars = { "Ẇ": { key: "KeyW", shift: true, accentKey: keyOverdot }, X: { key: "KeyX", shift: true }, "Ẋ": { key: "KeyX", shift: true, accentKey: keyOverdot }, - Y: { key: "KeyY", shift: true }, - "Ý": { key: "KeyY", shift: true, accentKey: keyAcute }, - "Ẏ": { key: "KeyY", shift: true, accentKey: keyOverdot }, - Z: { key: "KeyZ", shift: true }, - "Ż": { key: "KeyZ", shift: true, accentKey: keyOverdot }, + Y: { key: "KeyZ", shift: true }, + "Ý": { key: "KeyZ", shift: true, accentKey: keyAcute }, + "Ẏ": { key: "KeyZ", shift: true, accentKey: keyOverdot }, + Z: { key: "KeyY", shift: true }, + "Ż": { key: "KeyY", shift: true, accentKey: keyOverdot }, a: { key: "KeyA" }, "ä": { key: "KeyA", accentKey: keyTrema }, "â": { key: "KeyA", accentKey: keyHat }, @@ -191,10 +191,10 @@ export const chars = { x: { key: "KeyX" }, "#": { key: "KeyX", altRight: true }, "ẋ": { key: "KeyX", accentKey: keyOverdot }, - y: { key: "KeyY" }, - "ẏ": { key: "KeyY", accentKey: keyOverdot }, - z: { key: "KeyZ" }, - "ż": { key: "KeyZ", accentKey: keyOverdot }, + y: { key: "KeyZ" }, + "ẏ": { key: "KeyZ", accentKey: keyOverdot }, + z: { key: "KeyY" }, + "ż": { key: "KeyY", accentKey: keyOverdot }, ";": { key: "Backquote" }, "°": { key: "Backquote", shift: true, deadKey: true }, "+": { key: "Digit1" }, @@ -245,11 +245,19 @@ export const chars = { Tab: { key: "Tab" }, } as Record; +const cs_CZ_keyDisplayMap = { + ...keyDisplayMap, + KeyY: "z", + KeyZ: "y", + "(KeyY)": "Z", + "(KeyZ)": "Y", +} as Record; + export const cs_CZ: KeyboardLayout = { isoCode, name, chars, - keyDisplayMap, + keyDisplayMap: cs_CZ_keyDisplayMap, modifierDisplayMap, virtualKeyboard, }; diff --git a/ui/src/keyboardLayouts/de_CH.ts b/ui/src/keyboardLayouts/de_CH.ts index 62dad8c..6621e71 100644 --- a/ui/src/keyboardLayouts/de_CH.ts +++ b/ui/src/keyboardLayouts/de_CH.ts @@ -1,5 +1,6 @@ import { KeyboardLayout, KeyCombo } from "../keyboardLayouts" import { modifierDisplayMap, keyDisplayMap, virtualKeyboard } from "./en_US" +export { keyDisplayMap } from "./en_US"; const name = "Schwiizerdütsch"; const isoCode = "de-CH"; @@ -166,11 +167,19 @@ export const chars = { Tab: { key: "Tab" }, } as Record; +export const de_CH_keyDisplayMap = { + ...keyDisplayMap, + KeyY: "z", + KeyZ: "y", + "(KeyY)": "Z", + "(KeyZ)": "Y", +} as Record; + export const de_CH: KeyboardLayout = { isoCode, name, chars, - keyDisplayMap, + keyDisplayMap: de_CH_keyDisplayMap, modifierDisplayMap, virtualKeyboard, }; diff --git a/ui/src/keyboardLayouts/de_DE.ts b/ui/src/keyboardLayouts/de_DE.ts index 5974333..4d52bb0 100644 --- a/ui/src/keyboardLayouts/de_DE.ts +++ b/ui/src/keyboardLayouts/de_DE.ts @@ -153,11 +153,19 @@ export const chars = { Tab: { key: "Tab" }, } as Record; +const de_DE_keyDisplayMap = { + ...keyDisplayMap, + KeyY: "z", + KeyZ: "y", + "(KeyY)": "Z", + "(KeyZ)": "Y", +} as Record; + export const de_DE: KeyboardLayout = { isoCode, name, chars, - keyDisplayMap, + keyDisplayMap: de_DE_keyDisplayMap, modifierDisplayMap, virtualKeyboard, }; diff --git a/ui/src/keyboardLayouts/fr_BE.ts b/ui/src/keyboardLayouts/fr_BE.ts index 10cbed9..e514372 100644 --- a/ui/src/keyboardLayouts/fr_BE.ts +++ b/ui/src/keyboardLayouts/fr_BE.ts @@ -58,10 +58,10 @@ export const chars = { "Ù": { key: "KeyU", shift: true, accentKey: keyGrave }, "Ũ": { key: "KeyU", shift: true, accentKey: keyTilde }, V: { key: "KeyV", shift: true }, - W: { key: "KeyW", shift: true }, + W: { key: "KeyZ", shift: true }, X: { key: "KeyX", shift: true }, - Y: { key: "KeyZ", shift: true }, - Z: { key: "KeyY", shift: true }, + Y: { key: "KeyY", shift: true }, + Z: { key: "KeyW", shift: true }, a: { key: "KeyQ" }, "ä": { key: "KeyQ", accentKey: keyTrema }, "â": { key: "KeyQ", accentKey: keyHat }, @@ -106,10 +106,10 @@ export const chars = { "ú": { key: "KeyU", accentKey: keyAcute }, "ũ": { key: "KeyU", accentKey: keyTilde }, v: { key: "KeyV" }, - w: { key: "KeyW" }, + w: { key: "KeyZ" }, x: { key: "KeyX" }, - y: { key: "KeyZ" }, - z: { key: "KeyY" }, + y: { key: "KeyY" }, + z: { key: "KeyW" }, "²": { key: "Backquote" }, "³": { key: "Backquote", shift: true }, "&": { key: "Digit1" }, @@ -168,11 +168,27 @@ export const chars = { Tab: { key: "Tab" }, } as Record; +const fr_BE_keyDisplayMap = { + ...keyDisplayMap, + KeyA: "q", + KeyQ: "a", + KeyW: "z", + KeyZ: "w", + Semicolon: "m", + KeyM: ",", + "(KeyA)": "Q", + "(KeyQ)": "A", + "(KeyW)": "Z", + "(KeyZ)": "W", + "(Semicolon)": "M", + "(KeyM)": "?", +} as Record; + export const fr_BE: KeyboardLayout = { isoCode, name, chars, - keyDisplayMap, + keyDisplayMap: fr_BE_keyDisplayMap, modifierDisplayMap, virtualKeyboard, }; diff --git a/ui/src/keyboardLayouts/fr_CH.ts b/ui/src/keyboardLayouts/fr_CH.ts index 46f836b..0bf6b29 100644 --- a/ui/src/keyboardLayouts/fr_CH.ts +++ b/ui/src/keyboardLayouts/fr_CH.ts @@ -1,6 +1,6 @@ import { KeyboardLayout, KeyCombo } from "../keyboardLayouts" -import { chars as chars_de_CH } from "./de_CH" -import { modifierDisplayMap, keyDisplayMap, virtualKeyboard } from "./en_US" +import { chars as chars_de_CH, de_CH_keyDisplayMap } from "./de_CH" +import { modifierDisplayMap, virtualKeyboard } from "./en_US" const name = "Français de Suisse"; const isoCode = "fr-CH"; @@ -15,11 +15,21 @@ export const chars = { "ä": { key: "Quote", shift: true }, } as Record; +const fr_CH_keyDisplayMap = { + ...de_CH_keyDisplayMap, + BracketLeft: "è", + "(BracketLeft)": "ü", + Semicolon: "é", + "(Semicolon)": "ö", + Quote: "à", + "(Quote)": "ä", +} as Record; + export const fr_CH: KeyboardLayout = { isoCode, name, chars, - keyDisplayMap, + keyDisplayMap: fr_CH_keyDisplayMap, modifierDisplayMap, virtualKeyboard, }; diff --git a/ui/src/keyboardLayouts/fr_FR.ts b/ui/src/keyboardLayouts/fr_FR.ts index ef4f96f..8edc645 100644 --- a/ui/src/keyboardLayouts/fr_FR.ts +++ b/ui/src/keyboardLayouts/fr_FR.ts @@ -140,11 +140,27 @@ export const chars = { Tab: { key: "Tab" }, } as Record; +const fr_FR_keyDisplayMap = { + ...keyDisplayMap, + KeyA: "q", + KeyQ: "a", + KeyW: "z", + KeyZ: "w", + Semicolon: "m", + KeyM: ",", + "(KeyA)": "Q", + "(KeyQ)": "A", + "(KeyW)": "Z", + "(KeyZ)": "W", + "(Semicolon)": "M", + "(KeyM)": "?", +} as Record; + export const fr_FR: KeyboardLayout = { isoCode, name, chars, - keyDisplayMap, + keyDisplayMap: fr_FR_keyDisplayMap, modifierDisplayMap, virtualKeyboard, }; diff --git a/ui/src/keyboardLayouts/nb_NO.ts b/ui/src/keyboardLayouts/nb_NO.ts index a3aadbf..4a86314 100644 --- a/ui/src/keyboardLayouts/nb_NO.ts +++ b/ui/src/keyboardLayouts/nb_NO.ts @@ -60,8 +60,8 @@ export const chars = { V: { key: "KeyV", shift: true }, W: { key: "KeyW", shift: true }, X: { key: "KeyX", shift: true }, - Y: { key: "KeyZ", shift: true }, - Z: { key: "KeyY", shift: true }, + Y: { key: "KeyY", shift: true }, + Z: { key: "KeyZ", shift: true }, a: { key: "KeyA" }, "ä": { key: "KeyA", accentKey: keyTrema }, "á": { key: "KeyA", accentKey: keyAcute }, @@ -112,8 +112,8 @@ export const chars = { v: { key: "KeyV" }, w: { key: "KeyW" }, x: { key: "KeyX" }, - y: { key: "KeyZ" }, - z: { key: "KeyY" }, + y: { key: "KeyY" }, + z: { key: "KeyZ" }, "|": { key: "Backquote" }, "§": { key: "Backquote", shift: true }, 1: { key: "Digit1" }, diff --git a/ui/src/keyboardLayouts/sl_SI.ts b/ui/src/keyboardLayouts/sl_SI.ts index 80f6273..2988c36 100644 --- a/ui/src/keyboardLayouts/sl_SI.ts +++ b/ui/src/keyboardLayouts/sl_SI.ts @@ -146,12 +146,19 @@ export const chars = { Delete: { key: "Delete" }, } as Record; +const sl_SI_keyDisplayMap = { + ...en_US.keyDisplayMap, + KeyY: "z", + KeyZ: "y", + "(KeyY)": "Z", + "(KeyZ)": "Y", +} as Record; + export const sl_SI: KeyboardLayout = { isoCode: isoCode, name: name, chars: chars, - // TODO need to localize these maps and layouts - keyDisplayMap: en_US.keyDisplayMap, + keyDisplayMap: sl_SI_keyDisplayMap, modifierDisplayMap: en_US.modifierDisplayMap, virtualKeyboard: en_US.virtualKeyboard, }; diff --git a/ui/src/layout/components_bottom/keyboard/KeyboardPanel.tsx b/ui/src/layout/components_bottom/keyboard/KeyboardPanel.tsx index fc766df..18233f4 100644 --- a/ui/src/layout/components_bottom/keyboard/KeyboardPanel.tsx +++ b/ui/src/layout/components_bottom/keyboard/KeyboardPanel.tsx @@ -6,7 +6,7 @@ import { CloseOutlined } from '@ant-design/icons'; import { useReactAt } from "i18n-auto-extractor/react"; import ScrollThrottlingSelect, { Option } from "@components/ScrollThrottlingSelect"; -import { layouts } from "@/keyboardLayouts"; +import { layouts, keyboards } from "@/keyboardLayouts"; import { KeyboardLedSync, useSettingsStore } from "@/hooks/stores"; import { useJsonRpc } from "@/hooks/useJsonRpc"; import notifications from "@/notifications"; @@ -24,11 +24,21 @@ const KeyboardPanel: React.FC = () => { const [layoutOptions, setLayoutOptions] = useState(); const [maxShowCount, setMaxShowCount] = useState(3); + + const layoutAbbrevMap = useMemo(() => { + const map: Record = {}; + keyboards.forEach(kb => { + const oldCode = kb.isoCode.replace("-", "_"); + map[oldCode] = oldCode; + }); + return map; + }, []); + useEffect(() => { const curLayoutOptions = (() => { const options = Object.entries(layouts).map(([code, language]) => ({ value: code, - label: language, + label: `${language} (${layoutAbbrevMap[code] || code})`, })); const currentLayout = keyboardLayout ?? ""; @@ -47,7 +57,7 @@ const KeyboardPanel: React.FC = () => { return options; })(); setLayoutOptions(curLayoutOptions); - }, [layouts, keyboardLayout]); + }, [layouts, keyboardLayout, layoutAbbrevMap]); const safeKeyboardLayout = useMemo(() => { if (keyboardLayout && keyboardLayout.length > 0) diff --git a/ui/src/layout/core/bar_bottom/BottomBarMobile.tsx b/ui/src/layout/core/bar_bottom/BottomBarMobile.tsx index 560615f..10f8aac 100644 --- a/ui/src/layout/core/bar_bottom/BottomBarMobile.tsx +++ b/ui/src/layout/core/bar_bottom/BottomBarMobile.tsx @@ -1,4 +1,4 @@ -import React, { useCallback, useEffect, useState } from "react"; +import React, { useCallback, useEffect, useMemo, useState } from "react"; import { Button as AntdButton, Typography } from "antd"; import { useReactAt } from "i18n-auto-extractor/react"; import KeyboardSVG from "@assets/second/keyboard.svg?react"; @@ -25,6 +25,7 @@ import { useVpnStore, } from "@/hooks/stores"; import { useJsonRpc } from "@/hooks/useJsonRpc"; +import { keyboards } from "@/keyboardLayouts"; import { button_primary_color, dark_bd_style, @@ -47,7 +48,13 @@ const views = [ export default function BottomBarMobile() { const { $at } = useReactAt(); const keyboardLedState = useHidStore(state => state.keyboardLedState); + const keyboardLayout = useSettingsStore(state => state.keyboardLayout); const { isDark } = useTheme(); + + const layoutAbbrev = useMemo(() => { + if (!keyboardLayout) return "en_US"; + return keyboardLayout; + }, [keyboardLayout]); const setDisableFocusTrap = useUiStore(state => state.setDisableVideoFocusTrap); const toggleSidebarView = useUiStore(state => state.toggleSidebarView); const forceHttp = useSettingsStore(state => state.forceHttp); @@ -144,6 +151,7 @@ export default function BottomBarMobile() { + {layoutAbbrev}
state.keyboardLedState); + const keyboardLayout = useSettingsStore(state => state.keyboardLayout); const isTurnServerInUse = useRTCStore(state => state.isTurnServerInUse); + const layoutAbbrev = useMemo(() => { + if (!keyboardLayout) return "en_US"; + return keyboardLayout; + }, [keyboardLayout]); + const [hostname, setHostname] = useState(""); const [send] = useJsonRpc(); const peerConnection = useRTCStore(state => state.peerConnection); @@ -164,6 +171,7 @@ export default function BottomBarPC() { ledState={keyboardLedState?.scroll_lock} text={$at("Scroll")} /> + {layoutAbbrev}
} align="left" diff --git a/ui/src/layout/core/desktop/hooks/useKeyboardEvents.ts b/ui/src/layout/core/desktop/hooks/useKeyboardEvents.ts index a1a0f91..cb51a54 100644 --- a/ui/src/layout/core/desktop/hooks/useKeyboardEvents.ts +++ b/ui/src/layout/core/desktop/hooks/useKeyboardEvents.ts @@ -3,6 +3,7 @@ import { useCallback } from "react"; import useKeyboard from "@/hooks/useKeyboard"; import { useHidStore, useSettingsStore, useUiStore } from "@/hooks/stores"; import { keys, modifiers } from "@/keyboardMappings"; +import { keyboards } from "@/keyboardLayouts"; import { eventMatchesShortcut } from "@/utils/shortcuts"; export const useKeyboardEvents = ( @@ -18,6 +19,28 @@ export const useKeyboardEvents = ( const pasteShortcutEnabled = useSettingsStore(state => state.pasteShortcutEnabled); const pasteShortcut = useSettingsStore(state => state.pasteShortcut); const isOcrMode = useUiStore(state => state.isOcrMode); + const keyboardLayout = useSettingsStore(state => state.keyboardLayout); + + const remapCode = useCallback((code: string, key: string): string => { + const modifierCodes = ["ControlLeft", "ControlRight", "ShiftLeft", "ShiftRight", "AltLeft", "AltRight", "MetaLeft", "MetaRight", "CapsLock", "Tab", "Enter", "Backspace", "Delete", "Insert", "Home", "End", "PageUp", "PageDown", "ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight", "Escape", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12", "PrintScreen", "ScrollLock", "Pause", "ContextMenu", "Menu"]; + if (modifierCodes.includes(code)) return code; + if (code.startsWith("Digit") || code.startsWith("Numpad")) return code; + if (code.startsWith("Key") && code.length === 4) { + const letter = code.charAt(3); + if (letter >= "A" && letter <= "Z") { + const isoCode = (keyboardLayout || "en-US").replace("_", "-"); + const layout = keyboards.find(k => k.isoCode === isoCode); + if (layout && layout.chars) { + const charLower = key.toLowerCase(); + const charEntry = layout.chars[charLower] || layout.chars[key]; + if (charEntry && charEntry.key && typeof charEntry.key === "string" && charEntry.key !== code) { + return charEntry.key; + } + } + } + } + return code; + }, [keyboardLayout]); const handleModifierKeys = useCallback((e: KeyboardEvent, activeModifiers: number[]) => { const { shiftKey, ctrlKey, altKey, metaKey } = e; @@ -59,6 +82,8 @@ export const useKeyboardEvents = ( code = "IntlBackslash"; } + code = remapCode(code, key); + const newKeys = [...prev.activeKeys, keys[code]].filter(Boolean); const newModifiers = handleModifierKeys(e, [...prev.activeModifiers, modifiers[code]]); @@ -77,13 +102,15 @@ export const useKeyboardEvents = ( // Still update the full state for legacy compatibility and UI display sendKeyboardEvent([...new Set(newKeys)], [...new Set(newModifiers)]); - }, [handleModifierKeys, sendKeyboardEvent, sendKeypress, isKeyboardLedManagedByHost, setIsNumLockActive, setIsCapsLockActive, setIsScrollLockActive, pasteShortcutEnabled, pasteShortcut, pasteCaptureRef, isReinitializingGadget, isOcrMode]); + }, [handleModifierKeys, remapCode, sendKeyboardEvent, sendKeypress, isKeyboardLedManagedByHost, setIsNumLockActive, setIsCapsLockActive, setIsScrollLockActive, pasteShortcutEnabled, pasteShortcut, pasteCaptureRef, isReinitializingGadget, isOcrMode]); const keyUpHandler = useCallback((e: KeyboardEvent) => { if (isOcrMode) return; if (isReinitializingGadget) return; e.preventDefault(); const prev = useHidStore.getState(); + const key = e.key; + let code = remapCode(e.code, key); if (!isKeyboardLedManagedByHost) { setIsNumLockActive(e.getModifierState("NumLock")); @@ -91,21 +118,21 @@ export const useKeyboardEvents = ( setIsScrollLockActive(e.getModifierState("ScrollLock")); } - const newKeys = prev.activeKeys.filter(k => k !== keys[e.code]).filter(Boolean); + const newKeys = prev.activeKeys.filter(k => k !== keys[code]).filter(Boolean); const newModifiers = handleModifierKeys( e, - prev.activeModifiers.filter(k => k !== modifiers[e.code]), + prev.activeModifiers.filter(k => k !== modifiers[code]), ); // Send per-key release event - const hidKey = keys[e.code]; + const hidKey = keys[code]; if (hidKey !== undefined) { sendKeypress(hidKey, false); } // Still update the full state for legacy compatibility and UI display sendKeyboardEvent([...new Set(newKeys)], [...new Set(newModifiers)]); - }, [handleModifierKeys, sendKeyboardEvent, sendKeypress, isKeyboardLedManagedByHost, setIsNumLockActive, setIsCapsLockActive, setIsScrollLockActive, isOcrMode]); + }, [handleModifierKeys, remapCode, sendKeyboardEvent, sendKeypress, isKeyboardLedManagedByHost, setIsNumLockActive, setIsCapsLockActive, setIsScrollLockActive, isOcrMode, isReinitializingGadget]); const setupKeyboardEvents = useCallback(() => { const abortController = new AbortController(); diff --git a/usb.go b/usb.go index c4bfb8e..22be6ec 100644 --- a/usb.go +++ b/usb.go @@ -157,6 +157,14 @@ type hidRpcHandler struct { session *Session } +func (h *hidRpcHandler) HandleHandshake(version byte) error { + if h.session.HidChannel != nil { + handshakeData := hidrpc.MarshalHandshake(version) + return h.session.HidChannel.Send(handshakeData) + } + return nil +} + func (h *hidRpcHandler) HandleKeyboardReport(modifier byte, keys []byte) error { return rpcKeyboardReport(modifier, keys) }