mirror of https://github.com/jetkvm/kvm.git
Update macros to use new keyboard implementation, add keyboard settings to new settings page, update PasteModal to use new keyboard implemention, dropped spanish mappings.
This commit is contained in:
parent
95c14102cd
commit
e53445067e
|
@ -4,21 +4,22 @@ import { Button } from "@/components/Button";
|
|||
import { Combobox } from "@/components/Combobox";
|
||||
import { SelectMenuBasic } from "@/components/SelectMenuBasic";
|
||||
import Card from "@/components/Card";
|
||||
import { keys, modifiers, keyDisplayMap } from "@/keyboardMappings";
|
||||
import { keyDisplayMap } from "@/keyboardMappings/KeyboardLayouts";
|
||||
import { keysUS, modifiersUS } from '../keyboardMappings/layouts/us';
|
||||
import { MAX_KEYS_PER_STEP, DEFAULT_DELAY } from "@/constants/macros";
|
||||
import FieldLabel from "@/components/FieldLabel";
|
||||
|
||||
// Filter out modifier keys since they're handled in the modifiers section
|
||||
const modifierKeyPrefixes = ['Alt', 'Control', 'Shift', 'Meta'];
|
||||
|
||||
const keyOptions = Object.keys(keys)
|
||||
const keyOptions = Object.keys(keysUS)
|
||||
.filter(key => !modifierKeyPrefixes.some(prefix => key.startsWith(prefix)))
|
||||
.map(key => ({
|
||||
value: key,
|
||||
label: keyDisplayMap[key] || key,
|
||||
}));
|
||||
|
||||
const modifierOptions = Object.keys(modifiers).map(modifier => ({
|
||||
const modifierOptions = Object.keys(modifiersUS).map(modifier => ({
|
||||
value: modifier,
|
||||
label: modifier.replace(/^(Control|Alt|Shift|Meta)(Left|Right)$/, "$1 $2"),
|
||||
}));
|
||||
|
|
|
@ -157,9 +157,6 @@ function KeyboardWrapper() {
|
|||
const isKeyCaps = key === "CapsLock";
|
||||
const keyHasShiftModifier = (key.includes("(") && key !== "(") || shift;
|
||||
|
||||
//TODO remove debug logs
|
||||
console.log(layoutName)
|
||||
|
||||
// Handle toggle of layout for shift or caps lock
|
||||
const toggleLayout = () => {
|
||||
if (mappingsEnabled) {
|
||||
|
@ -211,12 +208,6 @@ function KeyboardWrapper() {
|
|||
setIsCapsLockActive(!isCapsLockActive);
|
||||
}
|
||||
|
||||
//TODO remove debug logs
|
||||
console.log(cleanKey)
|
||||
console.log(chars[cleanKey])
|
||||
|
||||
console.log(mappedKey)
|
||||
|
||||
// Collect new active keys and modifiers
|
||||
const newKeys = keys[mappedKey ?? cleanKey] ? [keys[mappedKey ?? cleanKey]] : [];
|
||||
const newModifiers =
|
||||
|
@ -226,8 +217,6 @@ function KeyboardWrapper() {
|
|||
(altRight? modifiers['AltRight'] : 0),
|
||||
].filter(Boolean);
|
||||
|
||||
console.log(newModifiers);
|
||||
|
||||
// Update current keys and modifiers
|
||||
sendKeyboardEvent(newKeys, [...new Set(newModifiers)]);
|
||||
|
||||
|
|
|
@ -262,9 +262,6 @@ export default function WebRTCVideo() {
|
|||
(e: KeyboardEvent, activeModifiers: number[], mappedKeyModifers: { shift: boolean; altLeft: boolean; altRight: boolean; }) => {
|
||||
const { shiftKey, ctrlKey, altKey, metaKey } = e;
|
||||
|
||||
// TODO remove debug logging
|
||||
console.log(shiftKey + " " +ctrlKey + " " +altKey + " " +metaKey + " " +mappedKeyModifers.shift + " "+mappedKeyModifers.altLeft + " "+mappedKeyModifers.altRight + " ")
|
||||
|
||||
const filteredModifiers = activeModifiers.filter(Boolean);
|
||||
// Example: activeModifiers = [0x01, 0x02, 0x04, 0x08]
|
||||
// Assuming 0x01 = ControlLeft, 0x02 = ShiftLeft, 0x04 = AltLeft, 0x08 = MetaLeft
|
||||
|
@ -322,10 +319,7 @@ export default function WebRTCVideo() {
|
|||
e.preventDefault();
|
||||
const prev = useHidStore.getState();
|
||||
const code = e.code;
|
||||
console.log("MAPPING ENABLED: " + settings.keyboardMappingEnabled)
|
||||
var localisedKey = settings.keyboardMappingEnabled ? e.key : code;
|
||||
console.log(e);
|
||||
console.log("Localised Key: " + localisedKey);
|
||||
|
||||
// if (document.activeElement?.id !== "videoFocusTrap") {hH
|
||||
// console.log("KEYUP: Not focusing on the video", document.activeElement);
|
||||
|
@ -346,15 +340,9 @@ export default function WebRTCVideo() {
|
|||
|
||||
const { key: mappedKey, shift, altLeft, altRight } = chars[localisedKey] ?? { key: code };
|
||||
//if (!key) continue;
|
||||
console.log("Mapped Key: " + mappedKey)
|
||||
console.log("Current KB Layout:" + useKeyboardMappingsStore.getLayout());
|
||||
console.log(chars[localisedKey]);
|
||||
|
||||
console.log("Shift: " + shift + ", altLeft: " + altLeft + ", altRight: " + altRight)
|
||||
|
||||
// Add the mapped key to keyState
|
||||
activeKeyState.current.set(e.code, { mappedKey, modifiers: {shift, altLeft, altRight}});
|
||||
console.log(activeKeyState)
|
||||
|
||||
// Add the key to the active keys
|
||||
const newKeys = [...prev.activeKeys, keys[mappedKey]].filter(Boolean);
|
||||
|
@ -401,7 +389,6 @@ export default function WebRTCVideo() {
|
|||
const keyUpHandler = useCallback(
|
||||
(e: KeyboardEvent) => {
|
||||
e.preventDefault();
|
||||
console.log(e)
|
||||
const prev = useHidStore.getState();
|
||||
|
||||
setIsNumLockActive(e.getModifierState("NumLock"));
|
||||
|
@ -421,7 +408,6 @@ export default function WebRTCVideo() {
|
|||
|
||||
// Handle modifier release
|
||||
if (isModifierKey) {
|
||||
console.log("ITS A MODIFER")
|
||||
// Update all affected keys when this modifier is released
|
||||
activeKeyState.current.forEach((value, code) => {
|
||||
const { mappedKey, modifiers: mappedModifiers} = value;
|
||||
|
@ -457,14 +443,11 @@ export default function WebRTCVideo() {
|
|||
.filter(Boolean);
|
||||
};
|
||||
});
|
||||
console.log("prev.activemodifers: " + prev.activeModifiers)
|
||||
console.log("prev.activemodifers.filtered: " + prev.activeModifiers.filter(k => k !== modifiers[e.code]))
|
||||
const newModifiers = handleModifierKeys(
|
||||
e,
|
||||
prev.activeModifiers.filter(k => k !== modifiers[e.code]),
|
||||
{shift: false, altLeft: false, altRight: false}
|
||||
);
|
||||
console.log("New modifiers in keyup: " + newModifiers)
|
||||
|
||||
// Update the keyState
|
||||
/*activeKeyState.current.delete(code);/*.set(code, {
|
||||
|
@ -499,7 +482,6 @@ export default function WebRTCVideo() {
|
|||
|
||||
// Filter out the key that was just released
|
||||
newKeys = newKeys.filter(k => k !== keys[mappedKey]).filter(Boolean);
|
||||
console.log(activeKeyState)
|
||||
|
||||
// Filter out the associated modifier
|
||||
//const newModifiers = prev.activeModifiers.filter(k => k !== modifier).filter(Boolean);
|
||||
|
@ -533,7 +515,6 @@ export default function WebRTCVideo() {
|
|||
);
|
||||
*/
|
||||
|
||||
console.log(e.key);
|
||||
sendKeyboardEvent([...new Set(newKeys)], [...new Set(newModifiers)]);
|
||||
},
|
||||
[
|
||||
|
|
|
@ -9,7 +9,6 @@ import { TextAreaWithLabel } from "@components/TextArea";
|
|||
import { SettingsPageHeader } from "@components/SettingsPageheader";
|
||||
import { useJsonRpc } from "@/hooks/useJsonRpc";
|
||||
import { useHidStore, useRTCStore, useUiStore, useKeyboardMappingsStore } from "@/hooks/stores";
|
||||
import { chars, keys, modifiers } from "@/keyboardMappings";
|
||||
import notifications from "@/notifications";
|
||||
|
||||
const hidKeyboardPayload = (keys: number[], modifier: number) => {
|
||||
|
|
|
@ -497,8 +497,6 @@ export const useHidStore = create<HidState>(set => ({
|
|||
activeKeys: [],
|
||||
activeModifiers: [],
|
||||
updateActiveKeysAndModifiers: ({ keys, modifiers }) => {
|
||||
// TODO remove debug logs
|
||||
console.log("keys: " + keys + "modifiers: " + modifiers)
|
||||
return set({ activeKeys: keys, activeModifiers: modifiers });
|
||||
},
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { useCallback } from "react";
|
||||
import { useCallback, useState, useEffect } from "react";
|
||||
|
||||
import { useHidStore, useRTCStore } from "@/hooks/stores";
|
||||
import { useJsonRpc } from "@/hooks/useJsonRpc";
|
||||
import { keys, modifiers } from "@/keyboardMappings";
|
||||
import { useKeyboardMappingsStore } from "@/hooks/stores";
|
||||
|
||||
export default function useKeyboard() {
|
||||
const [send] = useJsonRpc();
|
||||
|
@ -12,6 +12,17 @@ export default function useKeyboard() {
|
|||
state => state.updateActiveKeysAndModifiers,
|
||||
);
|
||||
|
||||
const [keys, setKeys] = useState(useKeyboardMappingsStore.keys);
|
||||
const [modifiers, setModifiers] = useState(useKeyboardMappingsStore.modifiers);
|
||||
|
||||
useEffect(() => {
|
||||
const unsubscribeKeyboardStore = useKeyboardMappingsStore.subscribe(() => {
|
||||
setKeys(useKeyboardMappingsStore.keys);
|
||||
setModifiers(useKeyboardMappingsStore.modifiers);
|
||||
});
|
||||
return unsubscribeKeyboardStore; // Cleanup on unmount
|
||||
}, []);
|
||||
|
||||
const sendKeyboardEvent = useCallback(
|
||||
(keys: number[], modifiers: number[]) => {
|
||||
if (rpcDataChannel?.readyState !== "open") return;
|
||||
|
|
|
@ -2,7 +2,6 @@ import { keysUKApple, charsUKApple, modifiersUKApple } from './layouts/uk_apple'
|
|||
import { keysUK, charsUK, modifiersUK } from './layouts/uk';
|
||||
import { keysUS, charsUS, modifiersUS } from './layouts/us';
|
||||
import { keysDE_T1, charsDE_T1, modifiersDE_T1 } from './layouts/de_t1';
|
||||
import { keysES, charsES, modifiersES } from './layouts/es';
|
||||
|
||||
export function getKeyboardMappings(layout: string) {
|
||||
switch (layout) {
|
||||
|
@ -24,12 +23,6 @@ export function getKeyboardMappings(layout: string) {
|
|||
chars: charsDE_T1,
|
||||
modifiers: modifiersDE_T1,
|
||||
};
|
||||
case "es-ES":
|
||||
return {
|
||||
keys: keysES,
|
||||
chars: charsES,
|
||||
modifiers: modifiersES,
|
||||
};
|
||||
case "en-US":
|
||||
default:
|
||||
return {
|
||||
|
@ -38,4 +31,188 @@ export function getKeyboardMappings(layout: string) {
|
|||
modifiers: modifiersUS,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const modifierDisplayMap: Record<string, string> = {
|
||||
ControlLeft: "Left Ctrl",
|
||||
ControlRight: "Right Ctrl",
|
||||
ShiftLeft: "Left Shift",
|
||||
ShiftRight: "Right Shift",
|
||||
AltLeft: "Left Alt",
|
||||
AltRight: "Right Alt",
|
||||
MetaLeft: "Left Meta",
|
||||
MetaRight: "Right Meta",
|
||||
} as Record<string, string>;
|
||||
|
||||
export const keyDisplayMap: Record<string, string> = {
|
||||
CtrlAltDelete: "Ctrl + Alt + Delete",
|
||||
AltMetaEscape: "Alt + Meta + Escape",
|
||||
Escape: "esc",
|
||||
Tab: "tab",
|
||||
Backspace: "backspace",
|
||||
Enter: "enter",
|
||||
CapsLock: "caps lock",
|
||||
ShiftLeft: "shift",
|
||||
ShiftRight: "shift",
|
||||
ControlLeft: "ctrl",
|
||||
AltLeft: "alt",
|
||||
AltRight: "alt",
|
||||
MetaLeft: "meta",
|
||||
MetaRight: "meta",
|
||||
Space: " ",
|
||||
Home: "home",
|
||||
PageUp: "pageup",
|
||||
Delete: "delete",
|
||||
End: "end",
|
||||
PageDown: "pagedown",
|
||||
ArrowLeft: "←",
|
||||
ArrowRight: "→",
|
||||
ArrowUp: "↑",
|
||||
ArrowDown: "↓",
|
||||
|
||||
// Letters
|
||||
KeyA: "a", KeyB: "b", KeyC: "c", KeyD: "d", KeyE: "e",
|
||||
KeyF: "f", KeyG: "g", KeyH: "h", KeyI: "i", KeyJ: "j",
|
||||
KeyK: "k", KeyL: "l", KeyM: "m", KeyN: "n", KeyO: "o",
|
||||
KeyP: "p", KeyQ: "q", KeyR: "r", KeyS: "s", KeyT: "t",
|
||||
KeyU: "u", KeyV: "v", KeyW: "w", KeyX: "x", KeyY: "y",
|
||||
KeyZ: "z",
|
||||
|
||||
// Numbers
|
||||
Digit1: "1", Digit2: "2", Digit3: "3", Digit4: "4", Digit5: "5",
|
||||
Digit6: "6", Digit7: "7", Digit8: "8", Digit9: "9", Digit0: "0",
|
||||
|
||||
// Symbols
|
||||
Minus: "-",
|
||||
Equal: "=",
|
||||
BracketLeft: "[",
|
||||
BracketRight: "]",
|
||||
Backslash: "\\",
|
||||
Semicolon: ";",
|
||||
Quote: "'",
|
||||
Comma: ",",
|
||||
Period: ".",
|
||||
Slash: "/",
|
||||
Backquote: "`",
|
||||
IntlBackslash: "\\",
|
||||
|
||||
// Function keys
|
||||
F1: "F1", F2: "F2", F3: "F3", F4: "F4",
|
||||
F5: "F5", F6: "F6", F7: "F7", F8: "F8",
|
||||
F9: "F9", F10: "F10", F11: "F11", F12: "F12",
|
||||
|
||||
// Numpad
|
||||
Numpad0: "Num 0", Numpad1: "Num 1", Numpad2: "Num 2",
|
||||
Numpad3: "Num 3", Numpad4: "Num 4", Numpad5: "Num 5",
|
||||
Numpad6: "Num 6", Numpad7: "Num 7", Numpad8: "Num 8",
|
||||
Numpad9: "Num 9", NumpadAdd: "Num +", NumpadSubtract: "Num -",
|
||||
NumpadMultiply: "Num *", NumpadDivide: "Num /", NumpadDecimal: "Num .",
|
||||
NumpadEnter: "Num Enter",
|
||||
|
||||
// Mappings for Keyboard Layout Mapping
|
||||
"q": "q",
|
||||
"w": "w",
|
||||
"e": "e",
|
||||
"r": "r",
|
||||
"t": "t",
|
||||
"y": "y",
|
||||
"u": "u",
|
||||
"i": "i",
|
||||
"o": "o",
|
||||
"p": "p",
|
||||
"a": "a",
|
||||
"s": "s",
|
||||
"d": "d",
|
||||
"f": "f",
|
||||
"g": "g",
|
||||
"h": "h",
|
||||
"j": "j",
|
||||
"k": "k",
|
||||
"l": "l",
|
||||
"z": "z",
|
||||
"x": "x",
|
||||
"c": "c",
|
||||
"v": "v",
|
||||
"b": "b",
|
||||
"n": "n",
|
||||
"m": "m",
|
||||
|
||||
"Q": "Q",
|
||||
"W": "W",
|
||||
"E": "E",
|
||||
"R": "R",
|
||||
"T": "T",
|
||||
"Y": "Y",
|
||||
"U": "U",
|
||||
"I": "I",
|
||||
"O": "O",
|
||||
"P": "P",
|
||||
"A": "A",
|
||||
"S": "S",
|
||||
"D": "D",
|
||||
"F": "F",
|
||||
"G": "G",
|
||||
"H": "H",
|
||||
"J": "J",
|
||||
"K": "K",
|
||||
"L": "L",
|
||||
"Z": "Z",
|
||||
"X": "X",
|
||||
"C": "C",
|
||||
"V": "V",
|
||||
"B": "B",
|
||||
"N": "N",
|
||||
"M": "M",
|
||||
|
||||
"1": "1",
|
||||
"2": "2",
|
||||
"3": "3",
|
||||
"4": "4",
|
||||
"5": "5",
|
||||
"6": "6",
|
||||
"7": "7",
|
||||
"8": "8",
|
||||
"9": "9",
|
||||
"0": "0",
|
||||
|
||||
"!": "!",
|
||||
"@": "@",
|
||||
"#": "#",
|
||||
"$": "$",
|
||||
"%": "%",
|
||||
"^": "^",
|
||||
"&": "&",
|
||||
"*": "*",
|
||||
"(": "(",
|
||||
")": ")",
|
||||
|
||||
"-": "-",
|
||||
"_": "_",
|
||||
|
||||
"[": "[",
|
||||
"]": "]",
|
||||
"{": "{",
|
||||
"}": "}",
|
||||
|
||||
"|": "|",
|
||||
|
||||
";": ";",
|
||||
":": ":",
|
||||
|
||||
"'": "'",
|
||||
"\"": "\"",
|
||||
|
||||
",": ",",
|
||||
"<": "<",
|
||||
|
||||
".": ".",
|
||||
">": ">",
|
||||
|
||||
"/": "/",
|
||||
"?": "?",
|
||||
|
||||
"`": "`",
|
||||
"~": "~",
|
||||
|
||||
"\\": "\\"
|
||||
};
|
|
@ -1,68 +0,0 @@
|
|||
import { charsUS, keysUS, modifiersUS } from "./us";
|
||||
|
||||
export const keysES = {
|
||||
...keysUS,
|
||||
} as Record<string, number>;
|
||||
|
||||
export const charsES = {
|
||||
...charsUS,
|
||||
|
||||
"ñ": { key: "Semicolon", shift: false },
|
||||
"Ñ": { key: "Semicolon", shift: true },
|
||||
|
||||
"º": { key: "Backquote", shift: false },
|
||||
"ª": { key: "Backquote", shift: true },
|
||||
|
||||
"¡": { key: "Equals", shift: false},
|
||||
|
||||
"¿": { key: "Slash", shift: false, altRight: true },
|
||||
"?": { key: "Slash", shift: true },
|
||||
|
||||
"|": { key: "Digit1", shift: false, altRight: true },
|
||||
|
||||
"@": { key: "Digit2", shift: false, altRight: true },
|
||||
"\"": { key: "Digit2", shift: true },
|
||||
|
||||
"·": { key: "Digit3", shift: false, altRight: true },
|
||||
"#": { key: "Digit3", shift: true },
|
||||
|
||||
"$": { key: "Digit4", shift: true },
|
||||
"€": { key: "Digit5", shift: false, altRight: true },
|
||||
|
||||
"&": { key: "Digit6", shift: true },
|
||||
|
||||
"/": { key: "Digit7", shift: true },
|
||||
"(": { key: "Digit8", shift: true },
|
||||
")": { key: "Digit9", shift: true },
|
||||
"=": { key: "Digit0", shift: true },
|
||||
|
||||
"'": { key: "Quote", shift: false },
|
||||
"?": { key: "Quote", shift: true },
|
||||
|
||||
"-": { key: "Minus", shift: false },
|
||||
"_": { key: "Minus", shift: true },
|
||||
|
||||
"`": { key: "IntlBackslash", shift: false },
|
||||
"^": { key: "IntlBackslash", shift: true },
|
||||
"[": { key: "IntlBackslash", shift: false, altRight: true },
|
||||
"{": { key: "IntlBackslash", shift: true, altRight: true },
|
||||
|
||||
"+": { key: "Equal", shift: true },
|
||||
"]": { key: "Equal", shift: false, altRight: true },
|
||||
"}": { key: "Equal", shift: true, altRight: true },
|
||||
|
||||
"<": { key: "Backslash", shift: false },
|
||||
">": { key: "Backslash", shift: true },
|
||||
|
||||
|
||||
",": { key: "Comma", shift: false },
|
||||
";": { key: "Comma", shift: true },
|
||||
|
||||
".": { key: "Period", shift: false },
|
||||
":": { key: "Period", shift: true },
|
||||
|
||||
} as Record<string, { key: string; shift: boolean; altLeft?: boolean; altRight?: boolean }>;
|
||||
|
||||
export const modifiersES = {
|
||||
...modifiersUS,
|
||||
} as Record<string, number>;
|
|
@ -8,7 +8,7 @@ import { Button } from "@/components/Button";
|
|||
import EmptyCard from "@/components/EmptyCard";
|
||||
import Card from "@/components/Card";
|
||||
import { MAX_TOTAL_MACROS, COPY_SUFFIX, DEFAULT_DELAY } from "@/constants/macros";
|
||||
import { keyDisplayMap, modifierDisplayMap } from "@/keyboardMappings";
|
||||
import { keyDisplayMap, modifierDisplayMap } from "@/keyboardMappings/KeyboardLayouts";
|
||||
import notifications from "@/notifications";
|
||||
import { ConfirmDialog } from "@/components/ConfirmDialog";
|
||||
import LoadingSpinner from "@/components/LoadingSpinner";
|
||||
|
@ -27,6 +27,7 @@ export default function SettingsMacrosRoute() {
|
|||
const [showDeleteConfirm, setShowDeleteConfirm] = useState(false);
|
||||
const [macroToDelete, setMacroToDelete] = useState<KeySequence | null>(null);
|
||||
|
||||
|
||||
const isMaxMacrosReached = useMemo(() =>
|
||||
macros.length >= MAX_TOTAL_MACROS,
|
||||
[macros.length]
|
||||
|
|
|
@ -5,7 +5,7 @@ import MouseIcon from "@/assets/mouse-icon.svg";
|
|||
import PointingFinger from "@/assets/pointing-finger.svg";
|
||||
import { GridCard } from "@/components/Card";
|
||||
import { Checkbox } from "@/components/Checkbox";
|
||||
import { useDeviceSettingsStore, useSettingsStore } from "@/hooks/stores";
|
||||
import { useDeviceSettingsStore, useSettingsStore, useKeyboardMappingsStore } from "@/hooks/stores";
|
||||
import { useJsonRpc } from "@/hooks/useJsonRpc";
|
||||
import notifications from "@/notifications";
|
||||
import { SettingsPageHeader } from "@components/SettingsPageheader";
|
||||
|
@ -36,6 +36,39 @@ export default function SettingsKeyboardMouseRoute() {
|
|||
|
||||
const [send] = useJsonRpc();
|
||||
|
||||
const [keyboardLayout, setKeyboardLayout] = useState("en-US");
|
||||
const [kbMappingEnabled, setKeyboardMapping] = useState(false);
|
||||
|
||||
const keyboardMappingEnabled = useSettingsStore(state => state.keyboardMappingEnabled);
|
||||
const setkeyboardMappingEnabled = useSettingsStore(state => state.setkeyboardMappingEnabled);
|
||||
|
||||
const handleKeyboardLayoutChange = (keyboardLayout: string) => {
|
||||
send("setKeyboardLayout", { kbLayout: keyboardLayout }, resp => {
|
||||
if ("error" in resp) {
|
||||
notifications.error(
|
||||
`Failed to set keyboard layout: ${resp.error.data || "Unknown error"}`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
useKeyboardMappingsStore.setLayout(keyboardLayout)
|
||||
setKeyboardLayout(keyboardLayout);
|
||||
});
|
||||
};
|
||||
|
||||
const handleKeyboardMappingChange = (enabled: boolean) => {
|
||||
send("setKeyboardMappingState", { enabled }, resp => {
|
||||
if ("error" in resp) {
|
||||
notifications.error(
|
||||
`Failed to set keyboard maping state state: ${resp.error.data || "Unknown error"}`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
setkeyboardMappingEnabled(enabled);
|
||||
useKeyboardMappingsStore.setMappingsState(enabled);
|
||||
setKeyboardMapping(enabled);
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
send("getJigglerState", {}, resp => {
|
||||
if ("error" in resp) return;
|
||||
|
@ -48,7 +81,21 @@ export default function SettingsKeyboardMouseRoute() {
|
|||
setScrollSensitivity(resp.result as ScrollSensitivity);
|
||||
});
|
||||
}
|
||||
}, [isScrollSensitivityEnabled, send, setScrollSensitivity]);
|
||||
|
||||
send("getKeyboardLayout", {}, resp => {
|
||||
if ("error" in resp) return;
|
||||
setKeyboardLayout(String(resp.result));
|
||||
useKeyboardMappingsStore.setLayout(String(resp.result))
|
||||
});
|
||||
|
||||
send("getKeyboardMappingState", {}, resp => {
|
||||
if ("error" in resp) return;
|
||||
setKeyboardMapping(resp.result as boolean);
|
||||
setkeyboardMappingEnabled(resp.result as boolean);
|
||||
useKeyboardMappingsStore.setMappingsState(resp.result as boolean);
|
||||
});
|
||||
|
||||
}, [isScrollSensitivityEnabled, send, setScrollSensitivity, setkeyboardMappingEnabled, keyboardMappingEnabled, keyboardLayout, setKeyboardLayout]);
|
||||
|
||||
const handleJigglerChange = (enabled: boolean) => {
|
||||
send("setJigglerState", { enabled }, resp => {
|
||||
|
@ -78,6 +125,7 @@ export default function SettingsKeyboardMouseRoute() {
|
|||
[send, setScrollSensitivity],
|
||||
);
|
||||
|
||||
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<SettingsPageHeader
|
||||
|
@ -183,6 +231,44 @@ export default function SettingsKeyboardMouseRoute() {
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-y-4">
|
||||
<SettingsPageHeader
|
||||
title="Keyboard"
|
||||
description="Customize keyboard behaviour"
|
||||
/>
|
||||
<div className="space-y-4">
|
||||
<SettingsItem
|
||||
title="Enable Keyboard Mapping"
|
||||
description="Enables mapping of keys from your native layout to the layout of the target device"
|
||||
>
|
||||
<Checkbox
|
||||
checked={kbMappingEnabled}
|
||||
onChange={e => {
|
||||
handleKeyboardMappingChange(e.target.checked);
|
||||
}}
|
||||
/>
|
||||
</SettingsItem>
|
||||
<SettingsItem
|
||||
title="Keyboard Layout"
|
||||
description="Set keyboard layout (this should match the target machine)"
|
||||
>
|
||||
<SelectMenuBasic
|
||||
size="SM_Wide"
|
||||
label=""
|
||||
// TODO figure out how to make this selector wider like the EDID one?, (done but not sure if in desired way.)
|
||||
//fullWidth
|
||||
value={keyboardLayout}
|
||||
options={[
|
||||
{ value: "en-US", label: "US" },
|
||||
{ value: "en-GB", label: "UK" },
|
||||
{ value: "en-GB_apple", label: "UK (Apple)" },
|
||||
{ value: "de_DE", label: "German (T1)" },
|
||||
]}
|
||||
onChange={e => handleKeyboardLayoutChange(e.target.value)}
|
||||
/>
|
||||
</SettingsItem>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -148,7 +148,7 @@ export default function SettingsRoute() {
|
|||
>
|
||||
<div className="flex items-center gap-x-2 rounded-md px-2.5 py-2.5 text-sm transition-colors hover:bg-slate-100 dark:hover:bg-slate-700 [.active_&]:bg-blue-50 [.active_&]:!text-blue-700 md:[.active_&]:bg-transparent dark:[.active_&]:bg-blue-900 dark:[.active_&]:!text-blue-200 dark:md:[.active_&]:bg-transparent">
|
||||
<LuKeyboard className="h-4 w-4 shrink-0" />
|
||||
<h1>Mouse</h1>
|
||||
<h1>Mouse & Keyboard</h1>
|
||||
</div>
|
||||
</NavLink>
|
||||
</div>
|
||||
|
|
Loading…
Reference in New Issue