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:
William Johnstone 2025-04-12 17:01:43 +01:00
parent 95c14102cd
commit e53445067e
No known key found for this signature in database
GPG Key ID: 89703D0D4B3BB0FE
11 changed files with 293 additions and 118 deletions

View File

@ -4,21 +4,22 @@ import { Button } from "@/components/Button";
import { Combobox } from "@/components/Combobox"; import { Combobox } from "@/components/Combobox";
import { SelectMenuBasic } from "@/components/SelectMenuBasic"; import { SelectMenuBasic } from "@/components/SelectMenuBasic";
import Card from "@/components/Card"; 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 { MAX_KEYS_PER_STEP, DEFAULT_DELAY } from "@/constants/macros";
import FieldLabel from "@/components/FieldLabel"; import FieldLabel from "@/components/FieldLabel";
// Filter out modifier keys since they're handled in the modifiers section // Filter out modifier keys since they're handled in the modifiers section
const modifierKeyPrefixes = ['Alt', 'Control', 'Shift', 'Meta']; const modifierKeyPrefixes = ['Alt', 'Control', 'Shift', 'Meta'];
const keyOptions = Object.keys(keys) const keyOptions = Object.keys(keysUS)
.filter(key => !modifierKeyPrefixes.some(prefix => key.startsWith(prefix))) .filter(key => !modifierKeyPrefixes.some(prefix => key.startsWith(prefix)))
.map(key => ({ .map(key => ({
value: key, value: key,
label: keyDisplayMap[key] || key, label: keyDisplayMap[key] || key,
})); }));
const modifierOptions = Object.keys(modifiers).map(modifier => ({ const modifierOptions = Object.keys(modifiersUS).map(modifier => ({
value: modifier, value: modifier,
label: modifier.replace(/^(Control|Alt|Shift|Meta)(Left|Right)$/, "$1 $2"), label: modifier.replace(/^(Control|Alt|Shift|Meta)(Left|Right)$/, "$1 $2"),
})); }));

View File

@ -157,9 +157,6 @@ function KeyboardWrapper() {
const isKeyCaps = key === "CapsLock"; const isKeyCaps = key === "CapsLock";
const keyHasShiftModifier = (key.includes("(") && key !== "(") || shift; const keyHasShiftModifier = (key.includes("(") && key !== "(") || shift;
//TODO remove debug logs
console.log(layoutName)
// Handle toggle of layout for shift or caps lock // Handle toggle of layout for shift or caps lock
const toggleLayout = () => { const toggleLayout = () => {
if (mappingsEnabled) { if (mappingsEnabled) {
@ -211,12 +208,6 @@ function KeyboardWrapper() {
setIsCapsLockActive(!isCapsLockActive); setIsCapsLockActive(!isCapsLockActive);
} }
//TODO remove debug logs
console.log(cleanKey)
console.log(chars[cleanKey])
console.log(mappedKey)
// Collect new active keys and modifiers // Collect new active keys and modifiers
const newKeys = keys[mappedKey ?? cleanKey] ? [keys[mappedKey ?? cleanKey]] : []; const newKeys = keys[mappedKey ?? cleanKey] ? [keys[mappedKey ?? cleanKey]] : [];
const newModifiers = const newModifiers =
@ -226,8 +217,6 @@ function KeyboardWrapper() {
(altRight? modifiers['AltRight'] : 0), (altRight? modifiers['AltRight'] : 0),
].filter(Boolean); ].filter(Boolean);
console.log(newModifiers);
// Update current keys and modifiers // Update current keys and modifiers
sendKeyboardEvent(newKeys, [...new Set(newModifiers)]); sendKeyboardEvent(newKeys, [...new Set(newModifiers)]);

View File

@ -262,9 +262,6 @@ export default function WebRTCVideo() {
(e: KeyboardEvent, activeModifiers: number[], mappedKeyModifers: { shift: boolean; altLeft: boolean; altRight: boolean; }) => { (e: KeyboardEvent, activeModifiers: number[], mappedKeyModifers: { shift: boolean; altLeft: boolean; altRight: boolean; }) => {
const { shiftKey, ctrlKey, altKey, metaKey } = e; 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); const filteredModifiers = activeModifiers.filter(Boolean);
// Example: activeModifiers = [0x01, 0x02, 0x04, 0x08] // Example: activeModifiers = [0x01, 0x02, 0x04, 0x08]
// Assuming 0x01 = ControlLeft, 0x02 = ShiftLeft, 0x04 = AltLeft, 0x08 = MetaLeft // Assuming 0x01 = ControlLeft, 0x02 = ShiftLeft, 0x04 = AltLeft, 0x08 = MetaLeft
@ -322,10 +319,7 @@ export default function WebRTCVideo() {
e.preventDefault(); e.preventDefault();
const prev = useHidStore.getState(); const prev = useHidStore.getState();
const code = e.code; const code = e.code;
console.log("MAPPING ENABLED: " + settings.keyboardMappingEnabled)
var localisedKey = settings.keyboardMappingEnabled ? e.key : code; var localisedKey = settings.keyboardMappingEnabled ? e.key : code;
console.log(e);
console.log("Localised Key: " + localisedKey);
// if (document.activeElement?.id !== "videoFocusTrap") {hH // if (document.activeElement?.id !== "videoFocusTrap") {hH
// console.log("KEYUP: Not focusing on the video", document.activeElement); // 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 }; const { key: mappedKey, shift, altLeft, altRight } = chars[localisedKey] ?? { key: code };
//if (!key) continue; //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 // Add the mapped key to keyState
activeKeyState.current.set(e.code, { mappedKey, modifiers: {shift, altLeft, altRight}}); activeKeyState.current.set(e.code, { mappedKey, modifiers: {shift, altLeft, altRight}});
console.log(activeKeyState)
// Add the key to the active keys // Add the key to the active keys
const newKeys = [...prev.activeKeys, keys[mappedKey]].filter(Boolean); const newKeys = [...prev.activeKeys, keys[mappedKey]].filter(Boolean);
@ -401,7 +389,6 @@ export default function WebRTCVideo() {
const keyUpHandler = useCallback( const keyUpHandler = useCallback(
(e: KeyboardEvent) => { (e: KeyboardEvent) => {
e.preventDefault(); e.preventDefault();
console.log(e)
const prev = useHidStore.getState(); const prev = useHidStore.getState();
setIsNumLockActive(e.getModifierState("NumLock")); setIsNumLockActive(e.getModifierState("NumLock"));
@ -421,7 +408,6 @@ export default function WebRTCVideo() {
// Handle modifier release // Handle modifier release
if (isModifierKey) { if (isModifierKey) {
console.log("ITS A MODIFER")
// Update all affected keys when this modifier is released // Update all affected keys when this modifier is released
activeKeyState.current.forEach((value, code) => { activeKeyState.current.forEach((value, code) => {
const { mappedKey, modifiers: mappedModifiers} = value; const { mappedKey, modifiers: mappedModifiers} = value;
@ -457,14 +443,11 @@ export default function WebRTCVideo() {
.filter(Boolean); .filter(Boolean);
}; };
}); });
console.log("prev.activemodifers: " + prev.activeModifiers)
console.log("prev.activemodifers.filtered: " + prev.activeModifiers.filter(k => k !== modifiers[e.code]))
const newModifiers = handleModifierKeys( const newModifiers = handleModifierKeys(
e, e,
prev.activeModifiers.filter(k => k !== modifiers[e.code]), prev.activeModifiers.filter(k => k !== modifiers[e.code]),
{shift: false, altLeft: false, altRight: false} {shift: false, altLeft: false, altRight: false}
); );
console.log("New modifiers in keyup: " + newModifiers)
// Update the keyState // Update the keyState
/*activeKeyState.current.delete(code);/*.set(code, { /*activeKeyState.current.delete(code);/*.set(code, {
@ -499,7 +482,6 @@ export default function WebRTCVideo() {
// Filter out the key that was just released // Filter out the key that was just released
newKeys = newKeys.filter(k => k !== keys[mappedKey]).filter(Boolean); newKeys = newKeys.filter(k => k !== keys[mappedKey]).filter(Boolean);
console.log(activeKeyState)
// Filter out the associated modifier // Filter out the associated modifier
//const newModifiers = prev.activeModifiers.filter(k => k !== modifier).filter(Boolean); //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)]); sendKeyboardEvent([...new Set(newKeys)], [...new Set(newModifiers)]);
}, },
[ [

View File

@ -9,7 +9,6 @@ import { TextAreaWithLabel } from "@components/TextArea";
import { SettingsPageHeader } from "@components/SettingsPageheader"; import { SettingsPageHeader } from "@components/SettingsPageheader";
import { useJsonRpc } from "@/hooks/useJsonRpc"; import { useJsonRpc } from "@/hooks/useJsonRpc";
import { useHidStore, useRTCStore, useUiStore, useKeyboardMappingsStore } from "@/hooks/stores"; import { useHidStore, useRTCStore, useUiStore, useKeyboardMappingsStore } from "@/hooks/stores";
import { chars, keys, modifiers } from "@/keyboardMappings";
import notifications from "@/notifications"; import notifications from "@/notifications";
const hidKeyboardPayload = (keys: number[], modifier: number) => { const hidKeyboardPayload = (keys: number[], modifier: number) => {

View File

@ -497,8 +497,6 @@ export const useHidStore = create<HidState>(set => ({
activeKeys: [], activeKeys: [],
activeModifiers: [], activeModifiers: [],
updateActiveKeysAndModifiers: ({ keys, modifiers }) => { updateActiveKeysAndModifiers: ({ keys, modifiers }) => {
// TODO remove debug logs
console.log("keys: " + keys + "modifiers: " + modifiers)
return set({ activeKeys: keys, activeModifiers: modifiers }); return set({ activeKeys: keys, activeModifiers: modifiers });
}, },

View File

@ -1,8 +1,8 @@
import { useCallback } from "react"; import { useCallback, useState, useEffect } from "react";
import { useHidStore, useRTCStore } from "@/hooks/stores"; import { useHidStore, useRTCStore } from "@/hooks/stores";
import { useJsonRpc } from "@/hooks/useJsonRpc"; import { useJsonRpc } from "@/hooks/useJsonRpc";
import { keys, modifiers } from "@/keyboardMappings"; import { useKeyboardMappingsStore } from "@/hooks/stores";
export default function useKeyboard() { export default function useKeyboard() {
const [send] = useJsonRpc(); const [send] = useJsonRpc();
@ -12,6 +12,17 @@ export default function useKeyboard() {
state => state.updateActiveKeysAndModifiers, 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( const sendKeyboardEvent = useCallback(
(keys: number[], modifiers: number[]) => { (keys: number[], modifiers: number[]) => {
if (rpcDataChannel?.readyState !== "open") return; if (rpcDataChannel?.readyState !== "open") return;

View File

@ -2,7 +2,6 @@ import { keysUKApple, charsUKApple, modifiersUKApple } from './layouts/uk_apple'
import { keysUK, charsUK, modifiersUK } from './layouts/uk'; import { keysUK, charsUK, modifiersUK } from './layouts/uk';
import { keysUS, charsUS, modifiersUS } from './layouts/us'; import { keysUS, charsUS, modifiersUS } from './layouts/us';
import { keysDE_T1, charsDE_T1, modifiersDE_T1 } from './layouts/de_t1'; import { keysDE_T1, charsDE_T1, modifiersDE_T1 } from './layouts/de_t1';
import { keysES, charsES, modifiersES } from './layouts/es';
export function getKeyboardMappings(layout: string) { export function getKeyboardMappings(layout: string) {
switch (layout) { switch (layout) {
@ -24,12 +23,6 @@ export function getKeyboardMappings(layout: string) {
chars: charsDE_T1, chars: charsDE_T1,
modifiers: modifiersDE_T1, modifiers: modifiersDE_T1,
}; };
case "es-ES":
return {
keys: keysES,
chars: charsES,
modifiers: modifiersES,
};
case "en-US": case "en-US":
default: default:
return { return {
@ -38,4 +31,188 @@ export function getKeyboardMappings(layout: string) {
modifiers: modifiersUS, 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",
"!": "!",
"@": "@",
"#": "#",
"$": "$",
"%": "%",
"^": "^",
"&": "&",
"*": "*",
"(": "(",
")": ")",
"-": "-",
"_": "_",
"[": "[",
"]": "]",
"{": "{",
"}": "}",
"|": "|",
";": ";",
":": ":",
"'": "'",
"\"": "\"",
",": ",",
"<": "<",
".": ".",
">": ">",
"/": "/",
"?": "?",
"`": "`",
"~": "~",
"\\": "\\"
};

View File

@ -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>;

View File

@ -8,7 +8,7 @@ import { Button } from "@/components/Button";
import EmptyCard from "@/components/EmptyCard"; import EmptyCard from "@/components/EmptyCard";
import Card from "@/components/Card"; import Card from "@/components/Card";
import { MAX_TOTAL_MACROS, COPY_SUFFIX, DEFAULT_DELAY } from "@/constants/macros"; 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 notifications from "@/notifications";
import { ConfirmDialog } from "@/components/ConfirmDialog"; import { ConfirmDialog } from "@/components/ConfirmDialog";
import LoadingSpinner from "@/components/LoadingSpinner"; import LoadingSpinner from "@/components/LoadingSpinner";
@ -27,6 +27,7 @@ export default function SettingsMacrosRoute() {
const [showDeleteConfirm, setShowDeleteConfirm] = useState(false); const [showDeleteConfirm, setShowDeleteConfirm] = useState(false);
const [macroToDelete, setMacroToDelete] = useState<KeySequence | null>(null); const [macroToDelete, setMacroToDelete] = useState<KeySequence | null>(null);
const isMaxMacrosReached = useMemo(() => const isMaxMacrosReached = useMemo(() =>
macros.length >= MAX_TOTAL_MACROS, macros.length >= MAX_TOTAL_MACROS,
[macros.length] [macros.length]

View File

@ -5,7 +5,7 @@ import MouseIcon from "@/assets/mouse-icon.svg";
import PointingFinger from "@/assets/pointing-finger.svg"; import PointingFinger from "@/assets/pointing-finger.svg";
import { GridCard } from "@/components/Card"; import { GridCard } from "@/components/Card";
import { Checkbox } from "@/components/Checkbox"; import { Checkbox } from "@/components/Checkbox";
import { useDeviceSettingsStore, useSettingsStore } from "@/hooks/stores"; import { useDeviceSettingsStore, useSettingsStore, useKeyboardMappingsStore } from "@/hooks/stores";
import { useJsonRpc } from "@/hooks/useJsonRpc"; import { useJsonRpc } from "@/hooks/useJsonRpc";
import notifications from "@/notifications"; import notifications from "@/notifications";
import { SettingsPageHeader } from "@components/SettingsPageheader"; import { SettingsPageHeader } from "@components/SettingsPageheader";
@ -36,6 +36,39 @@ export default function SettingsKeyboardMouseRoute() {
const [send] = useJsonRpc(); 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(() => { useEffect(() => {
send("getJigglerState", {}, resp => { send("getJigglerState", {}, resp => {
if ("error" in resp) return; if ("error" in resp) return;
@ -48,7 +81,21 @@ export default function SettingsKeyboardMouseRoute() {
setScrollSensitivity(resp.result as ScrollSensitivity); 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) => { const handleJigglerChange = (enabled: boolean) => {
send("setJigglerState", { enabled }, resp => { send("setJigglerState", { enabled }, resp => {
@ -78,6 +125,7 @@ export default function SettingsKeyboardMouseRoute() {
[send, setScrollSensitivity], [send, setScrollSensitivity],
); );
return ( return (
<div className="space-y-4"> <div className="space-y-4">
<SettingsPageHeader <SettingsPageHeader
@ -183,6 +231,44 @@ export default function SettingsKeyboardMouseRoute() {
</div> </div>
</div> </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> </div>
); );
} }

View File

@ -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"> <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" /> <LuKeyboard className="h-4 w-4 shrink-0" />
<h1>Mouse</h1> <h1>Mouse & Keyboard</h1>
</div> </div>
</NavLink> </NavLink>
</div> </div>