diff --git a/ui/src/components/ActionBar.tsx b/ui/src/components/ActionBar.tsx index 6a8e75e..4f79d7e 100644 --- a/ui/src/components/ActionBar.tsx +++ b/ui/src/components/ActionBar.tsx @@ -264,7 +264,10 @@ export default function Actionbar({ theme="light" text="Settings" LeadingIcon={LuSettings} - onClick={() => navigateTo("/settings")} + onClick={() => { + setDisableVideoFocusTrap(true); + navigateTo("/settings") + }} /> diff --git a/ui/src/components/MacroForm.tsx b/ui/src/components/MacroForm.tsx index f74c4ae..6240a8a 100644 --- a/ui/src/components/MacroForm.tsx +++ b/ui/src/components/MacroForm.tsx @@ -1,17 +1,18 @@ import { useState } from "react"; import { LuPlus } from "react-icons/lu"; -import { KeySequence } from "@/hooks/stores"; import { Button } from "@/components/Button"; -import { InputFieldWithLabel, FieldError } from "@/components/InputField"; +import FieldLabel from "@/components/FieldLabel"; import Fieldset from "@/components/Fieldset"; +import { InputFieldWithLabel, FieldError } from "@/components/InputField"; import { MacroStepCard } from "@/components/MacroStepCard"; import { DEFAULT_DELAY, MAX_STEPS_PER_MACRO, MAX_KEYS_PER_STEP, } from "@/constants/macros"; -import FieldLabel from "@/components/FieldLabel"; +import { KeySequence } from "@/hooks/stores"; +import { useKeyboardLayout } from "@/hooks/useKeyboardLayout"; interface ValidationErrors { name?: string; @@ -44,6 +45,7 @@ export function MacroForm({ const [keyQueries, setKeyQueries] = useState>({}); const [errors, setErrors] = useState({}); const [errorMessage, setErrorMessage] = useState(null); + const { keyboard } = useKeyboardLayout(); const showTemporaryError = (message: string) => { setErrorMessage(message); @@ -234,6 +236,7 @@ export function MacroForm({ } onDelayChange={delay => handleDelayChange(stepIndex, delay)} isLastStep={stepIndex === (macro.steps?.length || 0) - 1} + keyboard={keyboard} /> ))} diff --git a/ui/src/components/MacroStepCard.tsx b/ui/src/components/MacroStepCard.tsx index 8642c28..c9d3822 100644 --- a/ui/src/components/MacroStepCard.tsx +++ b/ui/src/components/MacroStepCard.tsx @@ -4,19 +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 { MAX_KEYS_PER_STEP, DEFAULT_DELAY } from "@/constants/macros"; import FieldLabel from "@/components/FieldLabel"; +import { MAX_KEYS_PER_STEP, DEFAULT_DELAY } from "@/constants/macros"; +import { KeyboardLayout } from "@/keyboardLayouts"; +import { keys, modifiers } from "@/keyboardMappings"; // 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 = (keyDisplayMap: Record) => { + return Object.keys(keys) .filter(key => !modifierKeyPrefixes.some(prefix => key.startsWith(prefix))) .map(key => ({ value: key, label: keyDisplayMap[key] || key, })); +} const modifierOptions = Object.keys(modifiers).map(modifier => ({ value: modifier, @@ -67,6 +70,7 @@ interface MacroStepCardProps { onModifierChange: (modifiers: string[]) => void; onDelayChange: (delay: number) => void; isLastStep: boolean; + keyboard: KeyboardLayout } const ensureArray = (arr: T[] | null | undefined): T[] => { @@ -84,11 +88,14 @@ export function MacroStepCard({ keyQuery, onModifierChange, onDelayChange, - isLastStep + isLastStep, + keyboard }: MacroStepCardProps) { + const { keyDisplayMap } = keyboard; + const getFilteredKeys = () => { const selectedKeys = ensureArray(step.keys); - const availableKeys = keyOptions.filter(option => !selectedKeys.includes(option.value)); + const availableKeys = keyOptions(keyDisplayMap).filter(option => !selectedKeys.includes(option.value)); if (keyQuery === '') { return availableKeys; diff --git a/ui/src/components/VirtualKeyboard.tsx b/ui/src/components/VirtualKeyboard.tsx index 2c66dd8..b2cabf7 100644 --- a/ui/src/components/VirtualKeyboard.tsx +++ b/ui/src/components/VirtualKeyboard.tsx @@ -14,7 +14,8 @@ import DetachIconRaw from "@/assets/detach-icon.svg"; import { cx } from "@/cva.config"; import { useHidStore, useUiStore } from "@/hooks/stores"; import useKeyboard from "@/hooks/useKeyboard"; -import { keyDisplayMap, keys } from "@/keyboardMappings"; +import { useKeyboardLayout } from "@/hooks/useKeyboardLayout"; +import { keys } from "@/keyboardMappings"; export const DetachIcon = ({ className }: { className?: string }) => { return Detach Icon; @@ -36,6 +37,8 @@ function KeyboardWrapper() { const [position, setPosition] = useState({ x: 0, y: 0 }); const [newPosition, setNewPosition] = useState({ x: 0, y: 0 }); + const { keyboard } = useKeyboardLayout(); + /* // These will be used to display the currently pressed keys and modifiers on the virtual keyboard @@ -253,29 +256,9 @@ function KeyboardWrapper() { buttons: "CtrlAltDelete AltMetaEscape CtrlAltBackspace", }, ]} - display={keyDisplayMap} - layout={{ - default: [ - "CtrlAltDelete AltMetaEscape CtrlAltBackspace", - "Escape F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12", - "Backquote Digit1 Digit2 Digit3 Digit4 Digit5 Digit6 Digit7 Digit8 Digit9 Digit0 Minus Equal Backspace", - "Tab KeyQ KeyW KeyE KeyR KeyT KeyY KeyU KeyI KeyO KeyP BracketLeft BracketRight Backslash", - "CapsLock KeyA KeyS KeyD KeyF KeyG KeyH KeyJ KeyK KeyL Semicolon Quote Enter", - "ShiftLeft KeyZ KeyX KeyC KeyV KeyB KeyN KeyM Comma Period Slash ShiftRight", - "ControlLeft MetaLeft AltLeft Space AltRight MetaRight CtrlRight", - ], - shift: [ - "CtrlAltDelete AltMetaEscape CtrlAltBackspace", - "Escape F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12", - "(Backquote) (Digit1) (Digit2) (Digit3) (Digit4) (Digit5) (Digit6) (Digit7) (Digit8) (Digit9) (Digit0) (Minus) (Equal) (Backspace)", - "Tab (KeyQ) (KeyW) (KeyE) (KeyR) (KeyT) (KeyY) (KeyU) (KeyI) (KeyO) (KeyP) (BracketLeft) (BracketRight) (Backslash)", - "CapsLock (KeyA) (KeyS) (KeyD) (KeyF) (KeyG) (KeyH) (KeyJ) (KeyK) (KeyL) (Semicolon) (Quote) Enter", - "ShiftLeft (KeyZ) (KeyX) (KeyC) (KeyV) (KeyB) (KeyN) (KeyM) (Comma) (Period) (Slash) ShiftRight", - "ControlLeft MetaLeft AltLeft Space AltRight MetaRight CtrlRight", - ], - }} + display={keyboard.keyDisplayMap} + layout={keyboard.virtualKeyboard.main} disableButtonHold={true} - syncInstanceInputs={true} debug={false} /> @@ -285,26 +268,20 @@ function KeyboardWrapper() { theme="simple-keyboard hg-theme-default hg-layout-default" layoutName={layoutName} onKeyPress={onKeyDown} - display={keyDisplayMap} - layout={{ - default: ["PrintScreen ScrollLock Pause", "Insert Home PageUp", "Delete End PageDown"], - shift: ["(PrintScreen) ScrollLock (Pause)", "Insert Home PageUp", "Delete End PageDown"], - }} - syncInstanceInputs={true} + display={keyboard.keyDisplayMap} + layout={keyboard.virtualKeyboard.control} debug={false} /> + { /* TODO add optional number pad */ } diff --git a/ui/src/components/popovers/PasteModal.tsx b/ui/src/components/popovers/PasteModal.tsx index 0b69718..50a5317 100644 --- a/ui/src/components/popovers/PasteModal.tsx +++ b/ui/src/components/popovers/PasteModal.tsx @@ -10,7 +10,8 @@ import { SettingsPageHeader } from "@components/SettingsPageheader"; import { useJsonRpc } from "@/hooks/useJsonRpc"; import { useHidStore, useRTCStore, useUiStore, useSettingsStore } from "@/hooks/stores"; import { keys, modifiers } from "@/keyboardMappings"; -import { KeyStroke, KeyboardLayout, selectedKeyboard } from "@/keyboardLayouts"; +import { KeyStroke } from "@/keyboardLayouts"; +import { useKeyboardLayout } from "@/hooks/useKeyboardLayout"; import notifications from "@/notifications"; const hidKeyboardPayload = (modifier: number, keys: number[]) => { @@ -18,8 +19,8 @@ const hidKeyboardPayload = (modifier: number, keys: number[]) => { }; const modifierCode = (shift?: boolean, altRight?: boolean) => { - return (shift ? modifiers["ShiftLeft"] : 0) - | (altRight ? modifiers["AltRight"] : 0) + return (shift ? modifiers.ShiftLeft : 0) + | (altRight ? modifiers.AltRight : 0) } const noModifier = 0 @@ -34,15 +35,8 @@ export default function PasteModal() { const [invalidChars, setInvalidChars] = useState([]); const close = useClose(); - const { keyboardLayout, setKeyboardLayout } = useSettingsStore(); - - // this ensures we always get the en-US if it hasn't been set yet - // and if we get en_US from the backend, we convert it to en-US - const safeKeyboardLayout = useMemo(() => { - if (keyboardLayout && keyboardLayout.length > 0) - return keyboardLayout.replace("en_US", "en-US"); - return "en-US"; - }, [keyboardLayout]); + const { setKeyboardLayout } = useSettingsStore(); + const { keyboard } = useKeyboardLayout(); useEffect(() => { send("getKeyboardLayout", {}, resp => { @@ -62,7 +56,6 @@ export default function PasteModal() { setDisableVideoFocusTrap(false); if (rpcDataChannel?.readyState !== "open" || !TextAreaRef.current) return; - const keyboard: KeyboardLayout = selectedKeyboard(safeKeyboardLayout); if (!keyboard) return; const text = TextAreaRef.current.value; @@ -109,7 +102,7 @@ export default function PasteModal() { ); }); } - }, [rpcDataChannel?.readyState, safeKeyboardLayout, send, setDisableVideoFocusTrap, setPasteModeEnabled]); + }, [keyboard, rpcDataChannel?.readyState, send, setDisableVideoFocusTrap, setPasteModeEnabled]); useEffect(() => { if (TextAreaRef.current) { @@ -159,7 +152,7 @@ export default function PasteModal() { // @ts-expect-error TS doesn't recognize Intl.Segmenter in some environments [...new Intl.Segmenter().segment(value)] .map(x => x.segment) - .filter(char => !selectedKeyboard(safeKeyboardLayout).chars[char]), + .filter(char => !keyboard.chars[char]), ), ]; @@ -180,7 +173,7 @@ export default function PasteModal() {

- Sending text using keyboard layout: {selectedKeyboard(safeKeyboardLayout).name} + Sending text using keyboard layout: {keyboard.isoCode}-{keyboard.name}

diff --git a/ui/src/hooks/useKeyboard.ts b/ui/src/hooks/useKeyboard.ts index df09730..8086c4e 100644 --- a/ui/src/hooks/useKeyboard.ts +++ b/ui/src/hooks/useKeyboard.ts @@ -6,9 +6,7 @@ import { hidKeyToModifierMask, keys, modifiers } from "@/keyboardMappings"; export default function useKeyboard() { const { send } = useJsonRpc(); - const { rpcDataChannel } = useRTCStore(); - const { keysDownState, setKeysDownState } = useHidStore(); // INTRODUCTION: The earlier version of the JetKVM device shipped with all keyboard state @@ -23,8 +21,8 @@ export default function useKeyboard() { // getKeysDownState API. const { keyPressReportApiAvailable, setkeyPressReportApiAvailable} = useHidStore(); - // sendKeyboardEvent is used to send the full keyboard state to the device for macro handling and resetting keyboard state. - // It sends the keys currently pressed and the modifier state. + // sendKeyboardEvent is used to send the full keyboard state to the device for macro handling + // and resetting keyboard state. It sends the keys currently pressed and the modifier state. // The device will respond with the keysDownState if it supports the keyPressReport API // or just accept the state if it does not support (returning no result) const sendKeyboardEvent = useCallback( @@ -93,7 +91,6 @@ export default function useKeyboard() { // is clean. const resetKeyboardState = useCallback( async () => { - console.debug("Resetting keyboard state"); // Reset the keys buffer to zeros and the modifier state to zero keysDownState.keys.length = hidKeyBufferSize; keysDownState.keys.fill(0); diff --git a/ui/src/hooks/useKeyboardLayout.ts b/ui/src/hooks/useKeyboardLayout.ts new file mode 100644 index 0000000..4d4fbcc --- /dev/null +++ b/ui/src/hooks/useKeyboardLayout.ts @@ -0,0 +1,22 @@ +import { useMemo } from "react"; + +import { useSettingsStore } from "@/hooks/stores"; +import { KeyboardLayout, selectedKeyboard } from "@/keyboardLayouts"; + +export function useKeyboardLayout(): { keyboard: KeyboardLayout } { + const { keyboardLayout } = useSettingsStore(); + + const isoCode = useMemo(() => { + console.log("Current keyboard layout from store:", keyboardLayout); + if (keyboardLayout && keyboardLayout.length > 0) + return keyboardLayout.replace("en_US", "en-US"); + return "en-US"; + }, [keyboardLayout]); + + const keyboard = useMemo(() => { + console.log("Selected keyboard layout:", isoCode); + return selectedKeyboard(isoCode); + }, [isoCode]); + + return { keyboard }; +} \ No newline at end of file diff --git a/ui/src/keyboardLayouts.ts b/ui/src/keyboardLayouts.ts index 3d262eb..bc646bc 100644 --- a/ui/src/keyboardLayouts.ts +++ b/ui/src/keyboardLayouts.ts @@ -2,11 +2,16 @@ export interface KeyStroke { modifier: number; keys: number[]; } export interface KeyInfo { key: string | number; shift?: boolean, altRight?: boolean } export interface KeyCombo extends KeyInfo { deadKey?: boolean, accentKey?: KeyInfo } export interface KeyboardLayout { - isoCode: string, - name: string, - chars: Record, - keyDisplayMap: Record, - virtualKeyboard: { main: { default: string[], shift: string[] }, control?: { default: string[], shift?: string[] }, controlSection?: { default: string[], shift?: string[] } } + isoCode: string; + name: string; + chars: Record; + modifierDisplayMap: Record; + keyDisplayMap: Record; + virtualKeyboard: { + main: { default: string[], shift: string[] }, + control?: { default: string[], shift?: string[] }, + arrows?: { default: string[] } + }; } // to add a new layout, create a file like the above and add it to the list @@ -27,8 +32,8 @@ import { sv_SE } from "@/keyboardLayouts/sv_SE" export const keyboards: KeyboardLayout[] = [ cs_CZ, de_CH, de_DE, en_UK, en_US, es_ES, fr_BE, fr_CH, fr_FR, it_IT, nb_NO, pl_PL_t, sv_SE ]; export const selectedKeyboard = (isoCode: string): KeyboardLayout => { - // fallback to original behaviour of en-US if no isoCode given - return keyboards.find(keyboard => keyboard.isoCode == isoCode) + // fallback to original behaviour of en-US if no isoCode given or matching layout not found + return keyboards.find(keyboard => keyboard.isoCode == isoCode) ?? keyboards.find(keyboard => keyboard.isoCode == "en-US")!; }; diff --git a/ui/src/keyboardLayouts/cs_CZ.ts b/ui/src/keyboardLayouts/cs_CZ.ts index e4f8822..c02be70 100644 --- a/ui/src/keyboardLayouts/cs_CZ.ts +++ b/ui/src/keyboardLayouts/cs_CZ.ts @@ -1,17 +1,20 @@ import { KeyboardLayout, KeyCombo } from "../keyboardLayouts" -const name = "Čeština"; +import { en_US } from "./en_US" // for fallback of keyDisplayMap, modifierDisplayMap, and virtualKeyboard -const keyTrema = { key: "Backslash" } // tréma (umlaut), two dots placed above a vowel -const keyAcute = { key: "Equal" } // accent aigu (acute accent), mark ´ placed above the letter -const keyHat = { key: "Digit3", shift: true, altRight: true } // accent circonflexe (accent hat), mark ^ placed above the letter -const keyCaron = { key: "Equal", shift: true } // caron or haček (inverted hat), mark ˇ placed above the letter -const keyGrave = { key: "Digit7", shift: true, altRight: true } // accent grave, mark ` placed above the letter -const keyTilde = { key: "Digit1", shift: true, altRight: true } // tilde, mark ~ placed above the letter -const keyRing = { key: "Backquote", shift: true } // kroužek (little ring), mark ° placed above the letter -const keyOverdot = { key: "Digit8", shift: true, altRight: true } // overdot (dot above), mark ˙ placed above the letter -const keyHook = { key: "Digit6", shift: true, altRight: true } // ogonoek (little hook), mark ˛ placed beneath a letter -const keyCedille = { key: "Equal", shift: true, altRight: true } // accent cedille (cedilla), mark ¸ placed beneath a letter +const name = "Čeština"; +const isoCode = "cs-CZ"; + +const keyTrema: KeyCombo = { key: "Backslash" } // tréma (umlaut), two dots placed above a vowel +const keyAcute: KeyCombo = { key: "Equal" } // accent aigu (acute accent), mark ´ placed above the letter +const keyHat: KeyCombo = { key: "Digit3", shift: true, altRight: true } // accent circonflexe (accent hat), mark ^ placed above the letter +const keyCaron: KeyCombo = { key: "Equal", shift: true } // caron or haček (inverted hat), mark ˇ placed above the letter +const keyGrave: KeyCombo = { key: "Digit7", shift: true, altRight: true } // accent grave, mark ` placed above the letter +const keyTilde: KeyCombo = { key: "Digit1", shift: true, altRight: true } // tilde, mark ~ placed above the letter +const keyRing: KeyCombo = { key: "Backquote", shift: true } // kroužek (little ring), mark ° placed above the letter +const keyOverdot: KeyCombo = { key: "Digit8", shift: true, altRight: true } // overdot (dot above), mark ˙ placed above the letter +const keyHook: KeyCombo = { key: "Digit6", shift: true, altRight: true } // ogonoek (little hook), mark ˛ placed beneath a letter +const keyCedille: KeyCombo = { key: "Equal", shift: true, altRight: true } // accent cedille (cedilla), mark ¸ placed beneath a letter const chars = { A: { key: "KeyA", shift: true }, @@ -244,7 +247,11 @@ const chars = { } as Record; export const cs_CZ: KeyboardLayout = { - isoCode: "cs-CZ", + isoCode: isoCode, name: name, - chars: chars + chars: chars, + // TODO need to localize these maps and layouts + keyDisplayMap: en_US.keyDisplayMap, + modifierDisplayMap: en_US.modifierDisplayMap, + virtualKeyboard: en_US.virtualKeyboard }; \ No newline at end of file diff --git a/ui/src/keyboardLayouts/de_CH.ts b/ui/src/keyboardLayouts/de_CH.ts index 4743bcf..8776409 100644 --- a/ui/src/keyboardLayouts/de_CH.ts +++ b/ui/src/keyboardLayouts/de_CH.ts @@ -1,12 +1,15 @@ import { KeyboardLayout, KeyCombo } from "../keyboardLayouts" -const name = "Schwiizerdütsch"; +import { en_US } from "./en_US" // for fallback of keyDisplayMap, modifierDisplayMap, and virtualKeyboard -const keyTrema = { key: "BracketRight" } // tréma (umlaut), two dots placed above a vowel -const keyAcute = { key: "Minus", altRight: true } // accent aigu (acute accent), mark ´ placed above the letter -const keyHat = { key: "Equal" } // accent circonflexe (accent hat), mark ^ placed above the letter -const keyGrave = { key: "Equal", shift: true } // accent grave, mark ` placed above the letter -const keyTilde = { key: "Equal", altRight: true } // tilde, mark ~ placed above the letter +const name = "Schwiizerdütsch"; +const isoCode = "de-CH"; + +const keyTrema: KeyCombo = { key: "BracketRight" } // tréma (umlaut), two dots placed above a vowel +const keyAcute: KeyCombo = { key: "Minus", altRight: true } // accent aigu (acute accent), mark ´ placed above the letter +const keyHat: KeyCombo = { key: "Equal" } // accent circonflexe (accent hat), mark ^ placed above the letter +const keyGrave: KeyCombo = { key: "Equal", shift: true } // accent grave, mark ` placed above the letter +const keyTilde: KeyCombo = { key: "Equal", altRight: true } // tilde, mark ~ placed above the letter const chars = { A: { key: "KeyA", shift: true }, @@ -164,8 +167,22 @@ const chars = { Tab: { key: "Tab" }, } as Record; +const keyDisplayMap = { + ...en_US.keyDisplayMap, + BracketLeft: "è", + "(BracketLeft)": "ü", + Semicolon: "é", + "(Semicolon)": "ö", + Quote: "à", + "(Quote)": "ä", +} as Record; + export const de_CH: KeyboardLayout = { - isoCode: "de-CH", + isoCode: isoCode, name: name, - chars: chars + chars: chars, + keyDisplayMap: keyDisplayMap, + // TODO need to localize these maps and layouts + modifierDisplayMap: en_US.modifierDisplayMap, + virtualKeyboard: en_US.virtualKeyboard }; \ No newline at end of file diff --git a/ui/src/keyboardLayouts/de_DE.ts b/ui/src/keyboardLayouts/de_DE.ts index 89b7eed..69710a1 100644 --- a/ui/src/keyboardLayouts/de_DE.ts +++ b/ui/src/keyboardLayouts/de_DE.ts @@ -1,10 +1,13 @@ import { KeyboardLayout, KeyCombo } from "../keyboardLayouts" -const name = "Deutsch"; +import { en_US } from "./en_US" // for fallback of keyDisplayMap, modifierDisplayMap, and virtualKeyboard -const keyAcute = { key: "Equal" } // accent aigu (acute accent), mark ´ placed above the letter -const keyHat = { key: "Backquote" } // accent circonflexe (accent hat), mark ^ placed above the letter -const keyGrave = { key: "Equal", shift: true } // accent grave, mark ` placed above the letter +const name = "Deutsch"; +const isoCode = "de-DE"; + +const keyAcute: KeyCombo = { key: "Equal" } // accent aigu (acute accent), mark ´ placed above the letter +const keyHat: KeyCombo = { key: "Backquote" } // accent circonflexe (accent hat), mark ^ placed above the letter +const keyGrave: KeyCombo = { key: "Equal", shift: true } // accent grave, mark ` placed above the letter const chars = { A: { key: "KeyA", shift: true }, @@ -152,7 +155,11 @@ const chars = { } as Record; export const de_DE: KeyboardLayout = { - isoCode: "de-DE", + isoCode: isoCode, name: name, - chars: chars + chars: chars, + // TODO need to localize these maps and layouts + keyDisplayMap: en_US.keyDisplayMap, + modifierDisplayMap: en_US.modifierDisplayMap, + virtualKeyboard: en_US.virtualKeyboard }; \ No newline at end of file diff --git a/ui/src/keyboardLayouts/en_UK.ts b/ui/src/keyboardLayouts/en_UK.ts index a5ef779..5341f0f 100644 --- a/ui/src/keyboardLayouts/en_UK.ts +++ b/ui/src/keyboardLayouts/en_UK.ts @@ -1,6 +1,9 @@ import { KeyboardLayout, KeyCombo } from "../keyboardLayouts" +import { en_US } from "./en_US" // for fallback of keyDisplayMap, modifierDisplayMap, and virtualKeyboard + const name = "English (UK)"; +const isoCode = "en-UK"; const chars = { A: { key: "KeyA", shift: true }, @@ -107,7 +110,11 @@ const chars = { } as Record export const en_UK: KeyboardLayout = { - isoCode: "en-UK", + isoCode: isoCode, name: name, - chars: chars + chars: chars, + // TODO need to localize these maps and layouts + keyDisplayMap: en_US.keyDisplayMap, + modifierDisplayMap: en_US.modifierDisplayMap, + virtualKeyboard: en_US.virtualKeyboard }; \ No newline at end of file diff --git a/ui/src/keyboardLayouts/en_US.ts b/ui/src/keyboardLayouts/en_US.ts index 5a085ff..33293e8 100644 --- a/ui/src/keyboardLayouts/en_US.ts +++ b/ui/src/keyboardLayouts/en_US.ts @@ -125,36 +125,49 @@ export const chars = { Delete: { key: "Delete" }, } as Record +export const modifierDisplayMap: Record = { + ControlLeft: "Left Ctrl", + ControlRight: "Right Ctrl", + ShiftLeft: "Left Shift", + ShiftRight: "Right Shift", + AltLeft: "Left Alt", + AltRight: "Right Alt", + MetaLeft: "Left Meta", + MetaRight: "Right Meta", + AltGr: "AltGr", +} as Record; + export const keyDisplayMap: Record = { CtrlAltDelete: "Ctrl + Alt + Delete", AltMetaEscape: "Alt + Meta + Escape", CtrlAltBackspace: "Ctrl + Alt + Backspace", - Escape: "Esc", - Tab: "Tab", - Backspace: "Backspace", - "(Backspace)": "Backspace", - Enter: "Enter", - CapsLock: "Caps Lock", - ShiftLeft: "Shift", - ShiftRight: "Shift", - ControlLeft: "Ctrl", + AltGraph: "AltGr", AltLeft: "Alt", AltRight: "Alt", - AltGraph: "AltGr", - MetaLeft: "Meta", - MetaRight: "Meta", - Space: " ", - Insert: "Insert", - Home: "Home", - PageUp: "PgUp", - Delete: "Delete", - End: "End", - PageDown: "PgDn", - Clear: "Clear", + ArrowDown: "↓", ArrowLeft: "←", ArrowRight: "→", ArrowUp: "↑", - ArrowDown: "↓", + Backspace: "Backspace", + "(Backspace)": "Backspace", + CapsLock: "Caps Lock", + Clear: "Clear", + ControlLeft: "Ctrl", + ControlRight: "Ctrl", + Delete: "Delete", + End: "End", + Enter: "Enter", + Escape: "Esc", + Home: "Home", + Insert: "Insert", + MetaLeft: "Meta", + MetaRight: "Meta", + PageDown: "PgDn", + PageUp: "PgUp", + ShiftLeft: "Shift", + ShiftRight: "Shift", + Space: " ", + Tab: "Tab", // Letters KeyA: "a", KeyB: "b", KeyC: "c", KeyD: "d", KeyE: "e", @@ -220,9 +233,9 @@ export const keyDisplayMap: Record = { NumpadDelete: "Del", NumLock: "Num Lock", // Modals - PrintScreen: "PrtSc", ScrollLock: "Scroll Lock", Pause: "Pause", - "(PrintScreen)": "SysRq", "(Pause)": "Break", - SystemRequest: "SysRq", Break: "Break" + PrintScreen: "Prt Sc", ScrollLock: "Scr Lk", Pause: "Pause", + "(PrintScreen)": "Sys Rq", "(Pause)": "Break", + SystemRequest: "Sys Rq", Break: "Break" }; export const virtualKeyboard = { @@ -246,7 +259,7 @@ export const virtualKeyboard = { "ControlLeft MetaLeft AltLeft Space AltGr MetaRight Menu ControlRight", ] }, - controlSection: { + control: { default: [ "PrintScreen ScrollLock Pause", "Insert Home PageUp", @@ -259,7 +272,7 @@ export const virtualKeyboard = { ], }, - simpleArrows: { + arrows: { default: [ "ArrowUp", "ArrowLeft ArrowDown ArrowRight"], @@ -290,4 +303,6 @@ export const en_US: KeyboardLayout = { keyDisplayMap, modifierDisplayMap, virtualKeyboard -}; \ No newline at end of file +}; + + diff --git a/ui/src/keyboardLayouts/es_ES.ts b/ui/src/keyboardLayouts/es_ES.ts index 9eb1d6a..ab7762b 100644 --- a/ui/src/keyboardLayouts/es_ES.ts +++ b/ui/src/keyboardLayouts/es_ES.ts @@ -1,12 +1,15 @@ import { KeyboardLayout, KeyCombo } from "../keyboardLayouts" -const name = "Español"; +import { en_US } from "./en_US" // for fallback of keyDisplayMap, modifierDisplayMap, and virtualKeyboard -const keyTrema = { key: "Quote", shift: true } // tréma (umlaut), two dots placed above a vowel -const keyAcute = { key: "Quote" } // accent aigu (acute accent), mark ´ placed above the letter -const keyHat = { key: "BracketRight", shift: true } // accent circonflexe (accent hat), mark ^ placed above the letter -const keyGrave = { key: "BracketRight" } // accent grave, mark ` placed above the letter -const keyTilde = { key: "Key4", altRight: true } // tilde, mark ~ placed above the letter +const name = "Español"; +const isoCode = "es-ES"; + +const keyTrema: KeyCombo = { key: "Quote", shift: true } // tréma (umlaut), two dots placed above a vowel +const keyAcute: KeyCombo = { key: "Quote" } // accent aigu (acute accent), mark ´ placed above the letter +const keyHat: KeyCombo = { key: "BracketRight", shift: true } // accent circonflexe (accent hat), mark ^ placed above the letter +const keyGrave: KeyCombo = { key: "BracketRight" } // accent grave, mark ` placed above the letter +const keyTilde: KeyCombo = { key: "Key4", altRight: true } // tilde, mark ~ placed above the letter const chars = { A: { key: "KeyA", shift: true }, @@ -168,7 +171,11 @@ const chars = { } as Record; export const es_ES: KeyboardLayout = { - isoCode: "es-ES", + isoCode: isoCode, name: name, - chars: chars + chars: chars, + // TODO need to localize these maps and layouts + keyDisplayMap: en_US.keyDisplayMap, + modifierDisplayMap: en_US.modifierDisplayMap, + virtualKeyboard: en_US.virtualKeyboard }; \ No newline at end of file diff --git a/ui/src/keyboardLayouts/fr_BE.ts b/ui/src/keyboardLayouts/fr_BE.ts index bd417e0..fb5a79b 100644 --- a/ui/src/keyboardLayouts/fr_BE.ts +++ b/ui/src/keyboardLayouts/fr_BE.ts @@ -1,12 +1,15 @@ import { KeyboardLayout, KeyCombo } from "../keyboardLayouts" -const name = "Belgisch Nederlands"; +import { en_US } from "./en_US" // for fallback of keyDisplayMap, modifierDisplayMap, and virtualKeyboard -const keyTrema = { key: "BracketLeft", shift: true } // tréma (umlaut), two dots placed above a vowel -const keyHat = { key: "BracketLeft" } // accent circonflexe (accent hat), mark ^ placed above the letter -const keyAcute = { key: "Semicolon", altRight: true } // accent aigu (acute accent), mark ´ placed above the letter -const keyGrave = { key: "Quote", shift: true } // accent grave, mark ` placed above the letter -const keyTilde = { key: "Slash", altRight: true } // tilde, mark ~ placed above the letter +const name = "Belgisch Nederlands"; +const isoCode = "nl-BE"; + +const keyTrema: KeyCombo = { key: "BracketLeft", shift: true } // tréma (umlaut), two dots placed above a vowel +const keyHat: KeyCombo = { key: "BracketLeft" } // accent circonflexe (accent hat), mark ^ placed above the letter +const keyAcute: KeyCombo = { key: "Semicolon", altRight: true } // accent aigu (acute accent), mark ´ placed above the letter +const keyGrave: KeyCombo = { key: "Quote", shift: true } // accent grave, mark ` placed above the letter +const keyTilde: KeyCombo = { key: "Slash", altRight: true } // tilde, mark ~ placed above the letter const chars = { A: { key: "KeyQ", shift: true }, @@ -167,7 +170,11 @@ const chars = { } as Record; export const fr_BE: KeyboardLayout = { - isoCode: "fr-BE", + isoCode: isoCode, name: name, - chars: chars + chars: chars, + // TODO need to localize these maps and layouts + keyDisplayMap: en_US.keyDisplayMap, + modifierDisplayMap: en_US.modifierDisplayMap, + virtualKeyboard: en_US.virtualKeyboard }; \ No newline at end of file diff --git a/ui/src/keyboardLayouts/fr_CH.ts b/ui/src/keyboardLayouts/fr_CH.ts index 0ba8cb4..d0a70f3 100644 --- a/ui/src/keyboardLayouts/fr_CH.ts +++ b/ui/src/keyboardLayouts/fr_CH.ts @@ -3,6 +3,7 @@ import { KeyboardLayout, KeyCombo } from "../keyboardLayouts" import { de_CH } from "./de_CH" const name = "Français de Suisse"; +const isoCode = "fr-CH"; const chars = { ...de_CH.chars, @@ -14,8 +15,22 @@ const chars = { "ä": { key: "Quote", shift: true }, } as Record; +const keyDisplayMap = { + ...de_CH.keyDisplayMap, + "BracketLeft": "è", + "BracketLeftShift": "ü", + "Semicolon": "é", + "SemicolonShift": "ö", + "Quote": "à", + "QuoteShift": "ä", +} as Record; + export const fr_CH: KeyboardLayout = { - isoCode: "fr-CH", + isoCode: isoCode, name: name, - chars: chars + chars: chars, + keyDisplayMap: keyDisplayMap, + // TODO need to localize these maps and layouts + modifierDisplayMap: de_CH.modifierDisplayMap, + virtualKeyboard: de_CH.virtualKeyboard }; diff --git a/ui/src/keyboardLayouts/fr_FR.ts b/ui/src/keyboardLayouts/fr_FR.ts index 29d5104..2ac5e74 100644 --- a/ui/src/keyboardLayouts/fr_FR.ts +++ b/ui/src/keyboardLayouts/fr_FR.ts @@ -1,9 +1,12 @@ import { KeyboardLayout, KeyCombo } from "../keyboardLayouts" -const name = "Français"; +import { en_US } from "./en_US" // for fallback of keyDisplayMap, modifierDisplayMap, and virtualKeyboard -const keyTrema = { key: "BracketLeft", shift: true } // tréma (umlaut), two dots placed above a vowel -const keyHat = { key: "BracketLeft" } // accent circonflexe (accent hat), mark ^ placed above the letter +const name = "Français"; +const isoCode = "fr-FR"; + +const keyTrema: KeyCombo = { key: "BracketLeft", shift: true } // tréma (umlaut), two dots placed above a vowel +const keyHat: KeyCombo = { key: "BracketLeft" } // accent circonflexe (accent hat), mark ^ placed above the letter const chars = { A: { key: "KeyQ", shift: true }, @@ -139,7 +142,11 @@ const chars = { } as Record; export const fr_FR: KeyboardLayout = { - isoCode: "fr-FR", + isoCode: isoCode, name: name, - chars: chars + chars: chars, + // TODO need to localize these maps and layouts + keyDisplayMap: en_US.keyDisplayMap, + modifierDisplayMap: en_US.modifierDisplayMap, + virtualKeyboard: en_US.virtualKeyboard }; \ No newline at end of file diff --git a/ui/src/keyboardLayouts/it_IT.ts b/ui/src/keyboardLayouts/it_IT.ts index 0ff6e24..160b0fc 100644 --- a/ui/src/keyboardLayouts/it_IT.ts +++ b/ui/src/keyboardLayouts/it_IT.ts @@ -1,6 +1,9 @@ import { KeyboardLayout, KeyCombo } from "../keyboardLayouts" +import { en_US } from "./en_US" // for fallback of keyDisplayMap, modifierDisplayMap, and virtualKeyboard + const name = "Italiano"; +const isoCode = "it-IT"; const chars = { A: { key: "KeyA", shift: true }, @@ -113,7 +116,11 @@ const chars = { } as Record; export const it_IT: KeyboardLayout = { - isoCode: "it-IT", + isoCode: isoCode, name: name, - chars: chars + chars: chars, + // TODO need to localize these maps and layouts + keyDisplayMap: en_US.keyDisplayMap, + modifierDisplayMap: en_US.modifierDisplayMap, + virtualKeyboard: en_US.virtualKeyboard }; \ No newline at end of file diff --git a/ui/src/keyboardLayouts/nb_NO.ts b/ui/src/keyboardLayouts/nb_NO.ts index 4dae9c8..25043d9 100644 --- a/ui/src/keyboardLayouts/nb_NO.ts +++ b/ui/src/keyboardLayouts/nb_NO.ts @@ -1,12 +1,15 @@ import { KeyboardLayout, KeyCombo } from "../keyboardLayouts" -const name = "Norsk bokmål"; +import { en_US } from "./en_US" // for fallback of keyDisplayMap, modifierDisplayMap, and virtualKeyboard -const keyTrema = { key: "BracketRight" } // tréma (umlaut), two dots placed above a vowel -const keyAcute = { key: "Equal", altRight: true } // accent aigu (acute accent), mark ´ placed above the letter -const keyHat = { key: "BracketRight", shift: true } // accent circonflexe (accent hat), mark ^ placed above the letter -const keyGrave = { key: "Equal", shift: true } // accent grave, mark ` placed above the letter -const keyTilde = { key: "BracketRight", altRight: true } // tilde, mark ~ placed above the letter +const name = "Norsk bokmål"; +const isoCode = "nb-NO"; + +const keyTrema: KeyCombo = { key: "BracketRight" } // tréma (umlaut), two dots placed above a vowel +const keyAcute: KeyCombo = { key: "Equal", altRight: true } // accent aigu (acute accent), mark ´ placed above the letter +const keyHat: KeyCombo = { key: "BracketRight", shift: true } // accent circonflexe (accent hat), mark ^ placed above the letter +const keyGrave: KeyCombo = { key: "Equal", shift: true } // accent grave, mark ` placed above the letter +const keyTilde: KeyCombo = { key: "BracketRight", altRight: true } // tilde, mark ~ placed above the letter const chars = { A: { key: "KeyA", shift: true }, @@ -167,7 +170,11 @@ const chars = { } as Record; export const nb_NO: KeyboardLayout = { - isoCode: "nb-NO", + isoCode: isoCode, name: name, - chars: chars + chars: chars, + // TODO need to localize these maps and layouts + keyDisplayMap: en_US.keyDisplayMap, + modifierDisplayMap: en_US.modifierDisplayMap, + virtualKeyboard: en_US.virtualKeyboard }; \ No newline at end of file diff --git a/ui/src/keyboardLayouts/pl_PL_t.ts b/ui/src/keyboardLayouts/pl_PL_t.ts index c2dec3e..50974d3 100644 --- a/ui/src/keyboardLayouts/pl_PL_t.ts +++ b/ui/src/keyboardLayouts/pl_PL_t.ts @@ -1,17 +1,20 @@ import { KeyboardLayout, KeyCombo } from "../keyboardLayouts" -const name = "Polski (Programista)"; +import { en_US } from "./en_US" // for fallback of keyDisplayMap, modifierDisplayMap, and virtualKeyboard -const keyAcute = { key: "Quote" } // accent aigu (acute accent), mark ´ placed above the letter -const keyCedilla = { key: "OEM_2", altRight: true } // Cedilla mark ¸ placed below the letter in the center -const keyDiaresis = { key: "Plus", shift: true } // Diaresis (not umlaut!), two dots placed above a vowel to indicate each vowel should be pronounce -const keyDotAbove = { key: "", } // Dot above, single TODO! -const keyDoubleAcute = { key: "˝" } // Double acute mark ˝, placed above the letter in the center -const keyGrave = { key: "BracketRight" } // accent grave mark ` placed above the letter -const keyHacek = { key: "", } // TODO! -const keyHat = { key: "BracketRight", shift: true } // accent circonflexe (accent hat), mark ^ placed above the letter -const keyOgonek = { key: ""} // Ogonek mark ˛ placed below the letter on the right side -const keyTylda = { key: "Backquote", altRight: true } // Tilde mark ~ placed above the letter +const name = "Polski (Programista)"; +const isoCode = "pl-PL-t"; + +const keyAcute: KeyCombo = { key: "Quote" } // accent aigu (acute accent), mark ´ placed above the letter +const keyCedilla: KeyCombo = { key: "OEM_2", altRight: true } // Cedilla mark ¸ placed below the letter in the center +const keyDiaresis: KeyCombo = { key: "Plus", shift: true } // Diaresis (not umlaut!), two dots placed above a vowel to indicate each vowel should be pronounce +const keyDotAbove: KeyCombo = { key: "", } // Dot above, single TODO! +const keyDoubleAcute: KeyCombo = { key: "˝" } // Double acute mark ˝, placed above the letter in the center +const keyGrave: KeyCombo = { key: "BracketRight" } // accent grave mark ` placed above the letter +const keyHacek: KeyCombo = { key: "", } // TODO! +const keyHat: KeyCombo = { key: "BracketRight", shift: true } // accent circonflexe (accent hat), mark ^ placed above the letter +const keyOgonek: KeyCombo = { key: ""} // Ogonek mark ˛ placed below the letter on the right side +const keyTylda: KeyCombo = { key: "Backquote", altRight: true } // Tilde mark ~ placed above the letter const chars = { A: { key: "KeyA", shift: true }, @@ -231,8 +234,11 @@ const chars = { Tab: { key: "Tab" }, } as Record; -export const pl_PL_T: KeyboardLayout = { - isoCode: "pl-PL-t", +export const pl_PL_t: KeyboardLayout = { + isoCode: isoCode, name: name, - chars: chars + chars: chars, + keyDisplayMap: en_US.keyDisplayMap, + modifierDisplayMap: en_US.modifierDisplayMap, + virtualKeyboard: en_US.virtualKeyboard }; \ No newline at end of file diff --git a/ui/src/keyboardLayouts/sv_SE.ts b/ui/src/keyboardLayouts/sv_SE.ts index fbde3d0..388ddf9 100644 --- a/ui/src/keyboardLayouts/sv_SE.ts +++ b/ui/src/keyboardLayouts/sv_SE.ts @@ -1,12 +1,15 @@ import { KeyboardLayout, KeyCombo } from "../keyboardLayouts" -const name = "Svenska"; +import { en_US } from "./en_US" // for fallback of keyDisplayMap, modifierDisplayMap, and virtualKeyboard -const keyTrema = { key: "BracketRight" } // tréma (umlaut), two dots placed above a vowel -const keyAcute = { key: "Equal" } // accent aigu (acute accent), mark ´ placed above the letter -const keyHat = { key: "BracketRight", shift: true } // accent circonflexe (accent hat), mark ^ placed above the letter -const keyGrave = { key: "Equal", shift: true } // accent grave, mark ` placed above the letter -const keyTilde = { key: "BracketRight", altRight: true } // tilde, mark ~ placed above the letter +const name = "Svenska"; +const isoCode = "sv-SE"; + +const keyTrema: KeyCombo = { key: "BracketRight" } // tréma (umlaut), two dots placed above a vowel +const keyAcute: KeyCombo = { key: "Equal" } // accent aigu (acute accent), mark ´ placed above the letter +const keyHat: KeyCombo = { key: "BracketRight", shift: true } // accent circonflexe (accent hat), mark ^ placed above the letter +const keyGrave: KeyCombo = { key: "Equal", shift: true } // accent grave, mark ` placed above the letter +const keyTilde: KeyCombo = { key: "BracketRight", altRight: true } // tilde, mark ~ placed above the letter const chars = { A: { key: "KeyA", shift: true }, @@ -164,7 +167,11 @@ const chars = { } as Record; export const sv_SE: KeyboardLayout = { - isoCode: "sv-SE", + isoCode: isoCode, name: name, - chars: chars + chars: chars, + // TODO need to localize these maps and layouts + keyDisplayMap: en_US.keyDisplayMap, + modifierDisplayMap: en_US.modifierDisplayMap, + virtualKeyboard: en_US.virtualKeyboard }; \ No newline at end of file diff --git a/ui/src/keyboardMappings.ts b/ui/src/keyboardMappings.ts index b862701..a571926 100644 --- a/ui/src/keyboardMappings.ts +++ b/ui/src/keyboardMappings.ts @@ -236,20 +236,22 @@ export const keys = { } as Record; export const deadKeys = { - 0x005e: "Circumflex", - 0x02c7: "Caron", - 0x00b7: "Dot", - 0x02d8: "Breve", - 0x002c: "Comma", - 0x00b0: "Kreis", - 0x00b4: "Acute", - 0x00a8: "Umlaut", - 0x0060: "Grave", - 0x007e: "Tilde", - 0x02dd: "DoubleAcute", - 0x02db: "Ogonek", - 0x00b8: "Cedilla", -} as Record + Acute: 0x00b4, + Breve: 0x02d8, + Caron: 0x02c7, + Cedilla: 0x00b8, + Circumflex: 0x005e, // or 0x02c6? + Comma: 0x002c, + Dot: 0x00b7, + DoubleAcute: 0x02dd, + Grave: 0x0060, + Kreis: 0x00b0, + Ogonek: 0x02db, + Ring: 0x02da, + Slash: 0x02f8, + Tilde: 0x007e, + Umlaut: 0x00a8, +} as Record export const modifiers = { ControlLeft: 0x01, @@ -271,116 +273,4 @@ export const hidKeyToModifierMask = { 0xe5: modifiers.ShiftRight, 0xe6: modifiers.AltRight, 0xe7: modifiers.MetaRight, -} as Record; - -export const modifierDisplayMap: Record = { - ControlLeft: "Left Ctrl", - ControlRight: "Right Ctrl", - ShiftLeft: "Left Shift", - ShiftRight: "Right Shift", - AltLeft: "Left Alt", - AltRight: "Right Alt", - MetaLeft: "Left Meta", - MetaRight: "Right Meta", - AltGr: "AltGr", -} as Record; - -export const keyDisplayMap: Record = { - AltMetaEscape: "Alt + Meta + Escape", - CtrlAltBackspace: "Ctrl + Alt + Backspace", - CtrlAltDelete: "Ctrl + Alt + Delete", - - AltGraph: "alt gr", - AltLeft: "alt", - AltRight: "alt", - ArrowDown: "↓", - ArrowLeft: "←", - ArrowRight: "→", - ArrowUp: "↑", - Backspace: "backspace", - "(Backspace)": "backspace", - CapsLock: "caps lock", - ControlLeft: "ctrl", - Delete: "delete", - End: "end", - Enter: "enter", - Escape: "esc", - Home: "home", - Insert: "insert", - MetaLeft: "meta", - MetaRight: "meta", - PageDown: "page down", - PageUp: "page up", - ShiftLeft: "shift", - ShiftRight: "shift", - Space: " ", - Tab: "tab", - - // 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", - - // Capital 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", - - // Shifted Numbers - "(Digit1)": "!", "(Digit2)": "@", "(Digit3)": "#", "(Digit4)": "$", "(Digit5)": "%", - "(Digit6)": "^", "(Digit7)": "&", "(Digit8)": "*", "(Digit9)": "(", "(Digit0)": ")", - - // Symbols - Minus: "-", - "(Minus)": "_", - Equal: "=", - "(Equal)": "+", - BracketLeft: "[", - "(BracketLeft)": "{", - BracketRight: "]", - "(BracketRight)": "}", - Backslash: "\\", - "(Backslash)": "|", - Semicolon: ";", - "(Semicolon)": ":", - Quote: "'", - "(Quote)": "\"", - Comma: ",", - "(Comma)": "<", - Period: ".", - "(Period)": ">", - Slash: "/", - "(Slash)": "?", - Backquote: "`", - "(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 .", - NumpadEqual: "Num =", NumpadEnter: "Num Enter", - NumLock: "Num Lock", - - // Modals - PrintScreen: "prt sc", ScrollLock: "scr lk", Pause: "pause", - "(PrintScreen)": "sys rq", "(Pause)": "break", - SystemRequest: "sys rq", Break: "break" -}; +} as Record; \ No newline at end of file diff --git a/ui/src/routes/devices.$id.settings.keyboard.tsx b/ui/src/routes/devices.$id.settings.keyboard.tsx index d740ffb..bdc65cd 100644 --- a/ui/src/routes/devices.$id.settings.keyboard.tsx +++ b/ui/src/routes/devices.$id.settings.keyboard.tsx @@ -1,28 +1,20 @@ -import { useCallback, useEffect, useMemo } from "react"; +import { useCallback, useEffect } from "react"; import { useSettingsStore } from "@/hooks/stores"; import { useJsonRpc } from "@/hooks/useJsonRpc"; -import notifications from "@/notifications"; +import { useKeyboardLayout } from "@/hooks/useKeyboardLayout"; import { SettingsPageHeader } from "@components/SettingsPageheader"; -import { keyboardOptions } from "@/keyboardLayouts"; import { Checkbox } from "@/components/Checkbox"; - -import { SelectMenuBasic } from "../components/SelectMenuBasic"; +import { SelectMenuBasic } from "@/components/SelectMenuBasic"; +import { keyboardOptions } from "@/keyboardLayouts"; +import notifications from "@/notifications"; import { SettingsItem } from "./devices.$id.settings"; export default function SettingsKeyboardRoute() { - const { keyboardLayout, setKeyboardLayout } = useSettingsStore(); + const { setKeyboardLayout } = useSettingsStore(); const { showPressedKeys, setShowPressedKeys } = useSettingsStore(); - - // this ensures we always get the en-US if it hasn't been set yet - // and if we get en_US from the backend, we convert it to en-US - const safeKeyboardLayout = useMemo(() => { - if (keyboardLayout && keyboardLayout.length > 0) - return keyboardLayout.replace("en_US", "en-US"); - return "en-US"; - }, [keyboardLayout]); - + const { keyboard } = useKeyboardLayout(); const layoutOptions = keyboardOptions(); const { send } = useJsonRpc(); @@ -30,21 +22,25 @@ export default function SettingsKeyboardRoute() { useEffect(() => { send("getKeyboardLayout", {}, resp => { if ("error" in resp) return; - setKeyboardLayout(resp.result as string); + const isoCode = resp.result as string; + console.log("Fetched keyboard layout from backend:", isoCode); + if (isoCode && isoCode.length > 0) { + setKeyboardLayout(isoCode); + } }); }, [send, setKeyboardLayout]); const onKeyboardLayoutChange = useCallback( (e: React.ChangeEvent) => { - const layout = e.target.value; - send("setKeyboardLayout", { layout }, resp => { + const isoCode = e.target.value; + send("setKeyboardLayout", { layout: isoCode }, resp => { if ("error" in resp) { notifications.error( `Failed to set keyboard layout: ${resp.error.data || "Unknown error"}`, ); } - notifications.success("Keyboard layout set successfully"); - setKeyboardLayout(layout); + notifications.success("Keyboard layout set successfully to " + isoCode); + setKeyboardLayout(isoCode); }); }, [send, setKeyboardLayout], @@ -58,7 +54,6 @@ export default function SettingsKeyboardRoute() { />
- { /* this menu item could be renamed to plain "Keyboard layout" in the future, when also the virtual keyboard layout mappings are being implemented */ } diff --git a/ui/src/routes/devices.$id.settings.macros.tsx b/ui/src/routes/devices.$id.settings.macros.tsx index fd9270b..7e147f4 100644 --- a/ui/src/routes/devices.$id.settings.macros.tsx +++ b/ui/src/routes/devices.$id.settings.macros.tsx @@ -17,10 +17,10 @@ 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 notifications from "@/notifications"; import { ConfirmDialog } from "@/components/ConfirmDialog"; import LoadingSpinner from "@/components/LoadingSpinner"; +import { useKeyboardLayout } from "@/hooks/useKeyboardLayout"; const normalizeSortOrders = (macros: KeySequence[]): KeySequence[] => { return macros.map((macro, index) => ({ @@ -35,6 +35,7 @@ export default function SettingsMacrosRoute() { const [actionLoadingId, setActionLoadingId] = useState(null); const [showDeleteConfirm, setShowDeleteConfirm] = useState(false); const [macroToDelete, setMacroToDelete] = useState(null); + const { keyboard } = useKeyboardLayout(); const isMaxMacrosReached = useMemo( () => macros.length >= MAX_TOTAL_MACROS, @@ -185,7 +186,7 @@ export default function SettingsMacrosRoute() { step.modifiers.map((modifier, idx) => ( - {modifierDisplayMap[modifier] || modifier} + {keyboard.modifierDisplayMap[modifier] || modifier} {idx < step.modifiers.length - 1 && ( @@ -210,7 +211,7 @@ export default function SettingsMacrosRoute() { step.keys.map((key, idx) => ( - {keyDisplayMap[key] || key} + {keyboard.keyDisplayMap[key] || key} {idx < step.keys.length - 1 && ( @@ -297,8 +298,10 @@ export default function SettingsMacrosRoute() { actionLoadingId, handleDeleteMacro, handleMoveMacro, + keyboard.modifierDisplayMap, + keyboard.keyDisplayMap, handleDuplicateMacro, - navigate, + navigate ], ); diff --git a/ui/src/routes/devices.$id.settings.tsx b/ui/src/routes/devices.$id.settings.tsx index 0309ce9..6c9314c 100644 --- a/ui/src/routes/devices.$id.settings.tsx +++ b/ui/src/routes/devices.$id.settings.tsx @@ -17,14 +17,13 @@ import { useResizeObserver } from "usehooks-ts"; import Card from "@/components/Card"; import { LinkButton } from "@/components/Button"; +import { FeatureFlag } from "@/components/FeatureFlag"; import LoadingSpinner from "@/components/LoadingSpinner"; import { useUiStore } from "@/hooks/stores"; import useKeyboard from "@/hooks/useKeyboard"; -import { FeatureFlag } from "../components/FeatureFlag"; import { cx } from "../cva.config"; - /* TODO: Migrate to using URLs instead of the global state. To simplify the refactoring, we'll keep the global state for now. */ export default function SettingsRoute() { const location = useLocation(); @@ -65,16 +64,10 @@ export default function SettingsRoute() { }, [width]); useEffect(() => { - // disable focus trap setTimeout(() => { - // Reset keyboard state. In case the user is pressing a key while enabling the sidebar - resetKeyboardState(); setDisableVideoFocusTrap(true); - // For some reason, the focus trap is not disabled immediately - // so we need to blur the active element - (document.activeElement as HTMLElement)?.blur(); - console.debug("Just disabled focus trap"); - }, 300); + resetKeyboardState(); + }, 500); return () => { setDisableVideoFocusTrap(false);