mirror of
https://github.com/luckfox-eng29/kvm.git
synced 2026-05-26 08:05:08 +02:00
feat(keyboard): update keyboard layouts and key display mappings for multiple languages
Signed-off-by: luckfox-eng29 <eng29@luckfox.com>
This commit is contained in:
@@ -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<string, KeyCombo>;
|
||||
|
||||
const cs_CZ_keyDisplayMap = {
|
||||
...keyDisplayMap,
|
||||
KeyY: "z",
|
||||
KeyZ: "y",
|
||||
"(KeyY)": "Z",
|
||||
"(KeyZ)": "Y",
|
||||
} as Record<string, string>;
|
||||
|
||||
export const cs_CZ: KeyboardLayout = {
|
||||
isoCode,
|
||||
name,
|
||||
chars,
|
||||
keyDisplayMap,
|
||||
keyDisplayMap: cs_CZ_keyDisplayMap,
|
||||
modifierDisplayMap,
|
||||
virtualKeyboard,
|
||||
};
|
||||
|
||||
@@ -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<string, KeyCombo>;
|
||||
|
||||
export const de_CH_keyDisplayMap = {
|
||||
...keyDisplayMap,
|
||||
KeyY: "z",
|
||||
KeyZ: "y",
|
||||
"(KeyY)": "Z",
|
||||
"(KeyZ)": "Y",
|
||||
} as Record<string, string>;
|
||||
|
||||
export const de_CH: KeyboardLayout = {
|
||||
isoCode,
|
||||
name,
|
||||
chars,
|
||||
keyDisplayMap,
|
||||
keyDisplayMap: de_CH_keyDisplayMap,
|
||||
modifierDisplayMap,
|
||||
virtualKeyboard,
|
||||
};
|
||||
|
||||
@@ -153,11 +153,19 @@ export const chars = {
|
||||
Tab: { key: "Tab" },
|
||||
} as Record<string, KeyCombo>;
|
||||
|
||||
const de_DE_keyDisplayMap = {
|
||||
...keyDisplayMap,
|
||||
KeyY: "z",
|
||||
KeyZ: "y",
|
||||
"(KeyY)": "Z",
|
||||
"(KeyZ)": "Y",
|
||||
} as Record<string, string>;
|
||||
|
||||
export const de_DE: KeyboardLayout = {
|
||||
isoCode,
|
||||
name,
|
||||
chars,
|
||||
keyDisplayMap,
|
||||
keyDisplayMap: de_DE_keyDisplayMap,
|
||||
modifierDisplayMap,
|
||||
virtualKeyboard,
|
||||
};
|
||||
|
||||
@@ -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<string, KeyCombo>;
|
||||
|
||||
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<string, string>;
|
||||
|
||||
export const fr_BE: KeyboardLayout = {
|
||||
isoCode,
|
||||
name,
|
||||
chars,
|
||||
keyDisplayMap,
|
||||
keyDisplayMap: fr_BE_keyDisplayMap,
|
||||
modifierDisplayMap,
|
||||
virtualKeyboard,
|
||||
};
|
||||
|
||||
@@ -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<string, KeyCombo>;
|
||||
|
||||
const fr_CH_keyDisplayMap = {
|
||||
...de_CH_keyDisplayMap,
|
||||
BracketLeft: "è",
|
||||
"(BracketLeft)": "ü",
|
||||
Semicolon: "é",
|
||||
"(Semicolon)": "ö",
|
||||
Quote: "à",
|
||||
"(Quote)": "ä",
|
||||
} as Record<string, string>;
|
||||
|
||||
export const fr_CH: KeyboardLayout = {
|
||||
isoCode,
|
||||
name,
|
||||
chars,
|
||||
keyDisplayMap,
|
||||
keyDisplayMap: fr_CH_keyDisplayMap,
|
||||
modifierDisplayMap,
|
||||
virtualKeyboard,
|
||||
};
|
||||
|
||||
@@ -140,11 +140,27 @@ export const chars = {
|
||||
Tab: { key: "Tab" },
|
||||
} as Record<string, KeyCombo>;
|
||||
|
||||
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<string, string>;
|
||||
|
||||
export const fr_FR: KeyboardLayout = {
|
||||
isoCode,
|
||||
name,
|
||||
chars,
|
||||
keyDisplayMap,
|
||||
keyDisplayMap: fr_FR_keyDisplayMap,
|
||||
modifierDisplayMap,
|
||||
virtualKeyboard,
|
||||
};
|
||||
|
||||
@@ -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" },
|
||||
|
||||
@@ -146,12 +146,19 @@ export const chars = {
|
||||
Delete: { key: "Delete" },
|
||||
} as Record<string, KeyCombo>;
|
||||
|
||||
const sl_SI_keyDisplayMap = {
|
||||
...en_US.keyDisplayMap,
|
||||
KeyY: "z",
|
||||
KeyZ: "y",
|
||||
"(KeyY)": "Z",
|
||||
"(KeyZ)": "Y",
|
||||
} as Record<string, string>;
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
@@ -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<Option[]>();
|
||||
const [maxShowCount, setMaxShowCount] = useState(3);
|
||||
|
||||
const layoutAbbrevMap = useMemo(() => {
|
||||
const map: Record<string, string> = {};
|
||||
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)
|
||||
|
||||
@@ -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() {
|
||||
<LedStatusButton ledState={keyboardLedState?.num_lock} text={$at("Num")} />
|
||||
<LedStatusButton ledState={keyboardLedState?.caps_lock} text={$at("Caps")} />
|
||||
<LedStatusButton ledState={keyboardLedState?.scroll_lock} text={$at("Scroll")} />
|
||||
<span className="pl-2 text-xs opacity-70">{layoutAbbrev}</span>
|
||||
</div>
|
||||
<div className="w-[20%] flex flex-row flex-wrap items-center justify-end">
|
||||
<AntdButton
|
||||
|
||||
@@ -27,6 +27,7 @@ import {
|
||||
useVpnStore,
|
||||
} from "@/hooks/stores";
|
||||
import { keys, modifiers } from "@/keyboardMappings";
|
||||
import { keyboards } from "@/keyboardLayouts";
|
||||
import BottomPopoverButton from "@components/PopoverButton";
|
||||
import MousePanel from "@components/MousePanel";
|
||||
import KeyboardPanel from "@/layout/components_bottom/keyboard/KeyboardPanel";
|
||||
@@ -57,8 +58,14 @@ export default function BottomBarPC() {
|
||||
|
||||
|
||||
const keyboardLedState = useHidStore(state => 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")}
|
||||
/>
|
||||
<span className="pl-1 text-xs opacity-70" style={{ fontSize: 12 }}>{layoutAbbrev}</span>
|
||||
</div>
|
||||
}
|
||||
align="left"
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user