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 { 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"),
|
||||||
}));
|
}));
|
||||||
|
|
|
@ -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)]);
|
||||||
|
|
||||||
|
|
|
@ -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)]);
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
|
|
|
@ -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) => {
|
||||||
|
|
|
@ -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 });
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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",
|
||||||
|
|
||||||
|
"!": "!",
|
||||||
|
"@": "@",
|
||||||
|
"#": "#",
|
||||||
|
"$": "$",
|
||||||
|
"%": "%",
|
||||||
|
"^": "^",
|
||||||
|
"&": "&",
|
||||||
|
"*": "*",
|
||||||
|
"(": "(",
|
||||||
|
")": ")",
|
||||||
|
|
||||||
|
"-": "-",
|
||||||
|
"_": "_",
|
||||||
|
|
||||||
|
"[": "[",
|
||||||
|
"]": "]",
|
||||||
|
"{": "{",
|
||||||
|
"}": "}",
|
||||||
|
|
||||||
|
"|": "|",
|
||||||
|
|
||||||
|
";": ";",
|
||||||
|
":": ":",
|
||||||
|
|
||||||
|
"'": "'",
|
||||||
|
"\"": "\"",
|
||||||
|
|
||||||
|
",": ",",
|
||||||
|
"<": "<",
|
||||||
|
|
||||||
|
".": ".",
|
||||||
|
">": ">",
|
||||||
|
|
||||||
|
"/": "/",
|
||||||
|
"?": "?",
|
||||||
|
|
||||||
|
"`": "`",
|
||||||
|
"~": "~",
|
||||||
|
|
||||||
|
"\\": "\\"
|
||||||
|
};
|
|
@ -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 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]
|
||||||
|
|
|
@ -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>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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>
|
||||||
|
|
Loading…
Reference in New Issue