mirror of https://github.com/jetkvm/kvm.git
Centralized keyboard layout and localized display maps
This commit is contained in:
parent
6cd8a7ae95
commit
1a58f1cad0
|
@ -264,7 +264,10 @@ export default function Actionbar({
|
||||||
theme="light"
|
theme="light"
|
||||||
text="Settings"
|
text="Settings"
|
||||||
LeadingIcon={LuSettings}
|
LeadingIcon={LuSettings}
|
||||||
onClick={() => navigateTo("/settings")}
|
onClick={() => {
|
||||||
|
setDisableVideoFocusTrap(true);
|
||||||
|
navigateTo("/settings")
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -1,17 +1,18 @@
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { LuPlus } from "react-icons/lu";
|
import { LuPlus } from "react-icons/lu";
|
||||||
|
|
||||||
import { KeySequence } from "@/hooks/stores";
|
|
||||||
import { Button } from "@/components/Button";
|
import { Button } from "@/components/Button";
|
||||||
import { InputFieldWithLabel, FieldError } from "@/components/InputField";
|
import FieldLabel from "@/components/FieldLabel";
|
||||||
import Fieldset from "@/components/Fieldset";
|
import Fieldset from "@/components/Fieldset";
|
||||||
|
import { InputFieldWithLabel, FieldError } from "@/components/InputField";
|
||||||
import { MacroStepCard } from "@/components/MacroStepCard";
|
import { MacroStepCard } from "@/components/MacroStepCard";
|
||||||
import {
|
import {
|
||||||
DEFAULT_DELAY,
|
DEFAULT_DELAY,
|
||||||
MAX_STEPS_PER_MACRO,
|
MAX_STEPS_PER_MACRO,
|
||||||
MAX_KEYS_PER_STEP,
|
MAX_KEYS_PER_STEP,
|
||||||
} from "@/constants/macros";
|
} from "@/constants/macros";
|
||||||
import FieldLabel from "@/components/FieldLabel";
|
import { KeySequence } from "@/hooks/stores";
|
||||||
|
import { useKeyboardLayout } from "@/hooks/useKeyboardLayout";
|
||||||
|
|
||||||
interface ValidationErrors {
|
interface ValidationErrors {
|
||||||
name?: string;
|
name?: string;
|
||||||
|
@ -44,6 +45,7 @@ export function MacroForm({
|
||||||
const [keyQueries, setKeyQueries] = useState<Record<number, string>>({});
|
const [keyQueries, setKeyQueries] = useState<Record<number, string>>({});
|
||||||
const [errors, setErrors] = useState<ValidationErrors>({});
|
const [errors, setErrors] = useState<ValidationErrors>({});
|
||||||
const [errorMessage, setErrorMessage] = useState<string | null>(null);
|
const [errorMessage, setErrorMessage] = useState<string | null>(null);
|
||||||
|
const { keyboard } = useKeyboardLayout();
|
||||||
|
|
||||||
const showTemporaryError = (message: string) => {
|
const showTemporaryError = (message: string) => {
|
||||||
setErrorMessage(message);
|
setErrorMessage(message);
|
||||||
|
@ -234,6 +236,7 @@ export function MacroForm({
|
||||||
}
|
}
|
||||||
onDelayChange={delay => handleDelayChange(stepIndex, delay)}
|
onDelayChange={delay => handleDelayChange(stepIndex, delay)}
|
||||||
isLastStep={stepIndex === (macro.steps?.length || 0) - 1}
|
isLastStep={stepIndex === (macro.steps?.length || 0) - 1}
|
||||||
|
keyboard={keyboard}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -4,19 +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 { MAX_KEYS_PER_STEP, DEFAULT_DELAY } from "@/constants/macros";
|
|
||||||
import FieldLabel from "@/components/FieldLabel";
|
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
|
// 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 = (keyDisplayMap: Record<string, string>) => {
|
||||||
|
return Object.keys(keys)
|
||||||
.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(modifiers).map(modifier => ({
|
||||||
value: modifier,
|
value: modifier,
|
||||||
|
@ -67,6 +70,7 @@ interface MacroStepCardProps {
|
||||||
onModifierChange: (modifiers: string[]) => void;
|
onModifierChange: (modifiers: string[]) => void;
|
||||||
onDelayChange: (delay: number) => void;
|
onDelayChange: (delay: number) => void;
|
||||||
isLastStep: boolean;
|
isLastStep: boolean;
|
||||||
|
keyboard: KeyboardLayout
|
||||||
}
|
}
|
||||||
|
|
||||||
const ensureArray = <T,>(arr: T[] | null | undefined): T[] => {
|
const ensureArray = <T,>(arr: T[] | null | undefined): T[] => {
|
||||||
|
@ -84,11 +88,14 @@ export function MacroStepCard({
|
||||||
keyQuery,
|
keyQuery,
|
||||||
onModifierChange,
|
onModifierChange,
|
||||||
onDelayChange,
|
onDelayChange,
|
||||||
isLastStep
|
isLastStep,
|
||||||
|
keyboard
|
||||||
}: MacroStepCardProps) {
|
}: MacroStepCardProps) {
|
||||||
|
const { keyDisplayMap } = keyboard;
|
||||||
|
|
||||||
const getFilteredKeys = () => {
|
const getFilteredKeys = () => {
|
||||||
const selectedKeys = ensureArray(step.keys);
|
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 === '') {
|
if (keyQuery === '') {
|
||||||
return availableKeys;
|
return availableKeys;
|
||||||
|
|
|
@ -14,7 +14,8 @@ import DetachIconRaw from "@/assets/detach-icon.svg";
|
||||||
import { cx } from "@/cva.config";
|
import { cx } from "@/cva.config";
|
||||||
import { useHidStore, useUiStore } from "@/hooks/stores";
|
import { useHidStore, useUiStore } from "@/hooks/stores";
|
||||||
import useKeyboard from "@/hooks/useKeyboard";
|
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 }) => {
|
export const DetachIcon = ({ className }: { className?: string }) => {
|
||||||
return <img src={DetachIconRaw} alt="Detach Icon" className={className} />;
|
return <img src={DetachIconRaw} alt="Detach Icon" className={className} />;
|
||||||
|
@ -36,6 +37,8 @@ function KeyboardWrapper() {
|
||||||
const [position, setPosition] = useState({ x: 0, y: 0 });
|
const [position, setPosition] = useState({ x: 0, y: 0 });
|
||||||
const [newPosition, setNewPosition] = 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
|
// 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",
|
buttons: "CtrlAltDelete AltMetaEscape CtrlAltBackspace",
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
display={keyDisplayMap}
|
display={keyboard.keyDisplayMap}
|
||||||
layout={{
|
layout={keyboard.virtualKeyboard.main}
|
||||||
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",
|
|
||||||
],
|
|
||||||
}}
|
|
||||||
disableButtonHold={true}
|
disableButtonHold={true}
|
||||||
syncInstanceInputs={true}
|
|
||||||
debug={false}
|
debug={false}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
@ -285,26 +268,20 @@ function KeyboardWrapper() {
|
||||||
theme="simple-keyboard hg-theme-default hg-layout-default"
|
theme="simple-keyboard hg-theme-default hg-layout-default"
|
||||||
layoutName={layoutName}
|
layoutName={layoutName}
|
||||||
onKeyPress={onKeyDown}
|
onKeyPress={onKeyDown}
|
||||||
display={keyDisplayMap}
|
display={keyboard.keyDisplayMap}
|
||||||
layout={{
|
layout={keyboard.virtualKeyboard.control}
|
||||||
default: ["PrintScreen ScrollLock Pause", "Insert Home PageUp", "Delete End PageDown"],
|
|
||||||
shift: ["(PrintScreen) ScrollLock (Pause)", "Insert Home PageUp", "Delete End PageDown"],
|
|
||||||
}}
|
|
||||||
syncInstanceInputs={true}
|
|
||||||
debug={false}
|
debug={false}
|
||||||
/>
|
/>
|
||||||
<Keyboard
|
<Keyboard
|
||||||
baseClass="simple-keyboard-arrows"
|
baseClass="simple-keyboard-arrows"
|
||||||
theme="simple-keyboard hg-theme-default hg-layout-default"
|
theme="simple-keyboard hg-theme-default hg-layout-default"
|
||||||
onKeyPress={onKeyDown}
|
onKeyPress={onKeyDown}
|
||||||
display={keyDisplayMap}
|
display={keyboard.keyDisplayMap}
|
||||||
layout={{
|
layout={keyboard.virtualKeyboard.arrows}
|
||||||
default: ["ArrowUp", "ArrowLeft ArrowDown ArrowRight"],
|
|
||||||
}}
|
|
||||||
syncInstanceInputs={true}
|
|
||||||
debug={false}
|
debug={false}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
{ /* TODO add optional number pad */ }
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
|
@ -10,7 +10,8 @@ import { SettingsPageHeader } from "@components/SettingsPageheader";
|
||||||
import { useJsonRpc } from "@/hooks/useJsonRpc";
|
import { useJsonRpc } from "@/hooks/useJsonRpc";
|
||||||
import { useHidStore, useRTCStore, useUiStore, useSettingsStore } from "@/hooks/stores";
|
import { useHidStore, useRTCStore, useUiStore, useSettingsStore } from "@/hooks/stores";
|
||||||
import { keys, modifiers } from "@/keyboardMappings";
|
import { keys, modifiers } from "@/keyboardMappings";
|
||||||
import { KeyStroke, KeyboardLayout, selectedKeyboard } from "@/keyboardLayouts";
|
import { KeyStroke } from "@/keyboardLayouts";
|
||||||
|
import { useKeyboardLayout } from "@/hooks/useKeyboardLayout";
|
||||||
import notifications from "@/notifications";
|
import notifications from "@/notifications";
|
||||||
|
|
||||||
const hidKeyboardPayload = (modifier: number, keys: number[]) => {
|
const hidKeyboardPayload = (modifier: number, keys: number[]) => {
|
||||||
|
@ -18,8 +19,8 @@ const hidKeyboardPayload = (modifier: number, keys: number[]) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const modifierCode = (shift?: boolean, altRight?: boolean) => {
|
const modifierCode = (shift?: boolean, altRight?: boolean) => {
|
||||||
return (shift ? modifiers["ShiftLeft"] : 0)
|
return (shift ? modifiers.ShiftLeft : 0)
|
||||||
| (altRight ? modifiers["AltRight"] : 0)
|
| (altRight ? modifiers.AltRight : 0)
|
||||||
}
|
}
|
||||||
const noModifier = 0
|
const noModifier = 0
|
||||||
|
|
||||||
|
@ -34,15 +35,8 @@ export default function PasteModal() {
|
||||||
const [invalidChars, setInvalidChars] = useState<string[]>([]);
|
const [invalidChars, setInvalidChars] = useState<string[]>([]);
|
||||||
const close = useClose();
|
const close = useClose();
|
||||||
|
|
||||||
const { keyboardLayout, setKeyboardLayout } = useSettingsStore();
|
const { setKeyboardLayout } = useSettingsStore();
|
||||||
|
const { keyboard } = useKeyboardLayout();
|
||||||
// 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]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
send("getKeyboardLayout", {}, resp => {
|
send("getKeyboardLayout", {}, resp => {
|
||||||
|
@ -62,7 +56,6 @@ export default function PasteModal() {
|
||||||
setDisableVideoFocusTrap(false);
|
setDisableVideoFocusTrap(false);
|
||||||
|
|
||||||
if (rpcDataChannel?.readyState !== "open" || !TextAreaRef.current) return;
|
if (rpcDataChannel?.readyState !== "open" || !TextAreaRef.current) return;
|
||||||
const keyboard: KeyboardLayout = selectedKeyboard(safeKeyboardLayout);
|
|
||||||
if (!keyboard) return;
|
if (!keyboard) return;
|
||||||
|
|
||||||
const text = TextAreaRef.current.value;
|
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(() => {
|
useEffect(() => {
|
||||||
if (TextAreaRef.current) {
|
if (TextAreaRef.current) {
|
||||||
|
@ -159,7 +152,7 @@ export default function PasteModal() {
|
||||||
// @ts-expect-error TS doesn't recognize Intl.Segmenter in some environments
|
// @ts-expect-error TS doesn't recognize Intl.Segmenter in some environments
|
||||||
[...new Intl.Segmenter().segment(value)]
|
[...new Intl.Segmenter().segment(value)]
|
||||||
.map(x => x.segment)
|
.map(x => x.segment)
|
||||||
.filter(char => !selectedKeyboard(safeKeyboardLayout).chars[char]),
|
.filter(char => !keyboard.chars[char]),
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -180,7 +173,7 @@ export default function PasteModal() {
|
||||||
</div>
|
</div>
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
<p className="text-xs text-slate-600 dark:text-slate-400">
|
<p className="text-xs text-slate-600 dark:text-slate-400">
|
||||||
Sending text using keyboard layout: {selectedKeyboard(safeKeyboardLayout).name}
|
Sending text using keyboard layout: {keyboard.isoCode}-{keyboard.name}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -6,9 +6,7 @@ import { hidKeyToModifierMask, keys, modifiers } from "@/keyboardMappings";
|
||||||
|
|
||||||
export default function useKeyboard() {
|
export default function useKeyboard() {
|
||||||
const { send } = useJsonRpc();
|
const { send } = useJsonRpc();
|
||||||
|
|
||||||
const { rpcDataChannel } = useRTCStore();
|
const { rpcDataChannel } = useRTCStore();
|
||||||
|
|
||||||
const { keysDownState, setKeysDownState } = useHidStore();
|
const { keysDownState, setKeysDownState } = useHidStore();
|
||||||
|
|
||||||
// INTRODUCTION: The earlier version of the JetKVM device shipped with all keyboard state
|
// INTRODUCTION: The earlier version of the JetKVM device shipped with all keyboard state
|
||||||
|
@ -23,8 +21,8 @@ export default function useKeyboard() {
|
||||||
// getKeysDownState API.
|
// getKeysDownState API.
|
||||||
const { keyPressReportApiAvailable, setkeyPressReportApiAvailable} = useHidStore();
|
const { keyPressReportApiAvailable, setkeyPressReportApiAvailable} = useHidStore();
|
||||||
|
|
||||||
// sendKeyboardEvent is used to send the full keyboard state to the device for macro handling and resetting keyboard state.
|
// sendKeyboardEvent is used to send the full keyboard state to the device for macro handling
|
||||||
// It sends the keys currently pressed and the modifier state.
|
// 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
|
// 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)
|
// or just accept the state if it does not support (returning no result)
|
||||||
const sendKeyboardEvent = useCallback(
|
const sendKeyboardEvent = useCallback(
|
||||||
|
@ -93,7 +91,6 @@ export default function useKeyboard() {
|
||||||
// is clean.
|
// is clean.
|
||||||
const resetKeyboardState = useCallback(
|
const resetKeyboardState = useCallback(
|
||||||
async () => {
|
async () => {
|
||||||
console.debug("Resetting keyboard state");
|
|
||||||
// Reset the keys buffer to zeros and the modifier state to zero
|
// Reset the keys buffer to zeros and the modifier state to zero
|
||||||
keysDownState.keys.length = hidKeyBufferSize;
|
keysDownState.keys.length = hidKeyBufferSize;
|
||||||
keysDownState.keys.fill(0);
|
keysDownState.keys.fill(0);
|
||||||
|
|
|
@ -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 };
|
||||||
|
}
|
|
@ -2,11 +2,16 @@ export interface KeyStroke { modifier: number; keys: number[]; }
|
||||||
export interface KeyInfo { key: string | number; shift?: boolean, altRight?: boolean }
|
export interface KeyInfo { key: string | number; shift?: boolean, altRight?: boolean }
|
||||||
export interface KeyCombo extends KeyInfo { deadKey?: boolean, accentKey?: KeyInfo }
|
export interface KeyCombo extends KeyInfo { deadKey?: boolean, accentKey?: KeyInfo }
|
||||||
export interface KeyboardLayout {
|
export interface KeyboardLayout {
|
||||||
isoCode: string,
|
isoCode: string;
|
||||||
name: string,
|
name: string;
|
||||||
chars: Record<string, KeyCombo>,
|
chars: Record<string, KeyCombo>;
|
||||||
keyDisplayMap: Record<string, string>,
|
modifierDisplayMap: Record<string, string>;
|
||||||
virtualKeyboard: { main: { default: string[], shift: string[] }, control?: { default: string[], shift?: string[] }, controlSection?: { default: string[], shift?: string[] } }
|
keyDisplayMap: Record<string, string>;
|
||||||
|
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
|
// to add a new layout, create a file like the above and add it to the list
|
||||||
|
@ -27,7 +32,7 @@ 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 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 => {
|
export const selectedKeyboard = (isoCode: string): KeyboardLayout => {
|
||||||
// fallback to original behaviour of en-US if no isoCode given
|
// fallback to original behaviour of en-US if no isoCode given or matching layout not found
|
||||||
return keyboards.find(keyboard => keyboard.isoCode == isoCode)
|
return keyboards.find(keyboard => keyboard.isoCode == isoCode)
|
||||||
?? keyboards.find(keyboard => keyboard.isoCode == "en-US")!;
|
?? keyboards.find(keyboard => keyboard.isoCode == "en-US")!;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,17 +1,20 @@
|
||||||
import { KeyboardLayout, KeyCombo } from "../keyboardLayouts"
|
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 name = "Čeština";
|
||||||
const keyAcute = { key: "Equal" } // accent aigu (acute accent), mark ´ placed above the letter
|
const isoCode = "cs-CZ";
|
||||||
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 keyTrema: KeyCombo = { key: "Backslash" } // tréma (umlaut), two dots placed above a vowel
|
||||||
const keyGrave = { key: "Digit7", shift: true, altRight: true } // accent grave, mark ` placed above the letter
|
const keyAcute: KeyCombo = { key: "Equal" } // accent aigu (acute accent), mark ´ placed above the letter
|
||||||
const keyTilde = { key: "Digit1", shift: true, altRight: true } // tilde, mark ~ placed above the letter
|
const keyHat: KeyCombo = { key: "Digit3", shift: true, altRight: true } // accent circonflexe (accent hat), mark ^ placed above the letter
|
||||||
const keyRing = { key: "Backquote", shift: true } // kroužek (little ring), mark ° placed above the letter
|
const keyCaron: KeyCombo = { key: "Equal", shift: true } // caron or haček (inverted hat), mark ˇ placed above the letter
|
||||||
const keyOverdot = { key: "Digit8", shift: true, altRight: true } // overdot (dot above), mark ˙ placed above the letter
|
const keyGrave: KeyCombo = { key: "Digit7", shift: true, altRight: true } // accent grave, mark ` placed above the letter
|
||||||
const keyHook = { key: "Digit6", shift: true, altRight: true } // ogonoek (little hook), mark ˛ placed beneath a letter
|
const keyTilde: KeyCombo = { key: "Digit1", shift: true, altRight: true } // tilde, mark ~ placed above the letter
|
||||||
const keyCedille = { key: "Equal", shift: true, altRight: true } // accent cedille (cedilla), mark ¸ placed beneath a 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 = {
|
const chars = {
|
||||||
A: { key: "KeyA", shift: true },
|
A: { key: "KeyA", shift: true },
|
||||||
|
@ -244,7 +247,11 @@ const chars = {
|
||||||
} as Record<string, KeyCombo>;
|
} as Record<string, KeyCombo>;
|
||||||
|
|
||||||
export const cs_CZ: KeyboardLayout = {
|
export const cs_CZ: KeyboardLayout = {
|
||||||
isoCode: "cs-CZ",
|
isoCode: isoCode,
|
||||||
name: name,
|
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
|
||||||
};
|
};
|
|
@ -1,12 +1,15 @@
|
||||||
import { KeyboardLayout, KeyCombo } from "../keyboardLayouts"
|
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 name = "Schwiizerdütsch";
|
||||||
const keyAcute = { key: "Minus", altRight: true } // accent aigu (acute accent), mark ´ placed above the letter
|
const isoCode = "de-CH";
|
||||||
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 keyTrema: KeyCombo = { key: "BracketRight" } // tréma (umlaut), two dots placed above a vowel
|
||||||
const keyTilde = { key: "Equal", altRight: true } // tilde, mark ~ placed above the letter
|
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 = {
|
const chars = {
|
||||||
A: { key: "KeyA", shift: true },
|
A: { key: "KeyA", shift: true },
|
||||||
|
@ -164,8 +167,22 @@ const chars = {
|
||||||
Tab: { key: "Tab" },
|
Tab: { key: "Tab" },
|
||||||
} as Record<string, KeyCombo>;
|
} as Record<string, KeyCombo>;
|
||||||
|
|
||||||
|
const keyDisplayMap = {
|
||||||
|
...en_US.keyDisplayMap,
|
||||||
|
BracketLeft: "è",
|
||||||
|
"(BracketLeft)": "ü",
|
||||||
|
Semicolon: "é",
|
||||||
|
"(Semicolon)": "ö",
|
||||||
|
Quote: "à",
|
||||||
|
"(Quote)": "ä",
|
||||||
|
} as Record<string, string>;
|
||||||
|
|
||||||
export const de_CH: KeyboardLayout = {
|
export const de_CH: KeyboardLayout = {
|
||||||
isoCode: "de-CH",
|
isoCode: isoCode,
|
||||||
name: name,
|
name: name,
|
||||||
chars: chars
|
chars: chars,
|
||||||
|
keyDisplayMap: keyDisplayMap,
|
||||||
|
// TODO need to localize these maps and layouts
|
||||||
|
modifierDisplayMap: en_US.modifierDisplayMap,
|
||||||
|
virtualKeyboard: en_US.virtualKeyboard
|
||||||
};
|
};
|
|
@ -1,10 +1,13 @@
|
||||||
import { KeyboardLayout, KeyCombo } from "../keyboardLayouts"
|
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 name = "Deutsch";
|
||||||
const keyHat = { key: "Backquote" } // accent circonflexe (accent hat), mark ^ placed above the letter
|
const isoCode = "de-DE";
|
||||||
const keyGrave = { key: "Equal", shift: true } // accent grave, mark ` placed above the letter
|
|
||||||
|
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 = {
|
const chars = {
|
||||||
A: { key: "KeyA", shift: true },
|
A: { key: "KeyA", shift: true },
|
||||||
|
@ -152,7 +155,11 @@ const chars = {
|
||||||
} as Record<string, KeyCombo>;
|
} as Record<string, KeyCombo>;
|
||||||
|
|
||||||
export const de_DE: KeyboardLayout = {
|
export const de_DE: KeyboardLayout = {
|
||||||
isoCode: "de-DE",
|
isoCode: isoCode,
|
||||||
name: name,
|
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
|
||||||
};
|
};
|
|
@ -1,6 +1,9 @@
|
||||||
import { KeyboardLayout, KeyCombo } from "../keyboardLayouts"
|
import { KeyboardLayout, KeyCombo } from "../keyboardLayouts"
|
||||||
|
|
||||||
|
import { en_US } from "./en_US" // for fallback of keyDisplayMap, modifierDisplayMap, and virtualKeyboard
|
||||||
|
|
||||||
const name = "English (UK)";
|
const name = "English (UK)";
|
||||||
|
const isoCode = "en-UK";
|
||||||
|
|
||||||
const chars = {
|
const chars = {
|
||||||
A: { key: "KeyA", shift: true },
|
A: { key: "KeyA", shift: true },
|
||||||
|
@ -107,7 +110,11 @@ const chars = {
|
||||||
} as Record<string, KeyCombo>
|
} as Record<string, KeyCombo>
|
||||||
|
|
||||||
export const en_UK: KeyboardLayout = {
|
export const en_UK: KeyboardLayout = {
|
||||||
isoCode: "en-UK",
|
isoCode: isoCode,
|
||||||
name: name,
|
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
|
||||||
};
|
};
|
|
@ -125,36 +125,49 @@ export const chars = {
|
||||||
Delete: { key: "Delete" },
|
Delete: { key: "Delete" },
|
||||||
} as Record<string, KeyCombo>
|
} as Record<string, KeyCombo>
|
||||||
|
|
||||||
|
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",
|
||||||
|
AltGr: "AltGr",
|
||||||
|
} as Record<string, string>;
|
||||||
|
|
||||||
export const keyDisplayMap: Record<string, string> = {
|
export const keyDisplayMap: Record<string, string> = {
|
||||||
CtrlAltDelete: "Ctrl + Alt + Delete",
|
CtrlAltDelete: "Ctrl + Alt + Delete",
|
||||||
AltMetaEscape: "Alt + Meta + Escape",
|
AltMetaEscape: "Alt + Meta + Escape",
|
||||||
CtrlAltBackspace: "Ctrl + Alt + Backspace",
|
CtrlAltBackspace: "Ctrl + Alt + Backspace",
|
||||||
Escape: "Esc",
|
AltGraph: "AltGr",
|
||||||
Tab: "Tab",
|
|
||||||
Backspace: "Backspace",
|
|
||||||
"(Backspace)": "Backspace",
|
|
||||||
Enter: "Enter",
|
|
||||||
CapsLock: "Caps Lock",
|
|
||||||
ShiftLeft: "Shift",
|
|
||||||
ShiftRight: "Shift",
|
|
||||||
ControlLeft: "Ctrl",
|
|
||||||
AltLeft: "Alt",
|
AltLeft: "Alt",
|
||||||
AltRight: "Alt",
|
AltRight: "Alt",
|
||||||
AltGraph: "AltGr",
|
ArrowDown: "↓",
|
||||||
MetaLeft: "Meta",
|
|
||||||
MetaRight: "Meta",
|
|
||||||
Space: " ",
|
|
||||||
Insert: "Insert",
|
|
||||||
Home: "Home",
|
|
||||||
PageUp: "PgUp",
|
|
||||||
Delete: "Delete",
|
|
||||||
End: "End",
|
|
||||||
PageDown: "PgDn",
|
|
||||||
Clear: "Clear",
|
|
||||||
ArrowLeft: "←",
|
ArrowLeft: "←",
|
||||||
ArrowRight: "→",
|
ArrowRight: "→",
|
||||||
ArrowUp: "↑",
|
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
|
// Letters
|
||||||
KeyA: "a", KeyB: "b", KeyC: "c", KeyD: "d", KeyE: "e",
|
KeyA: "a", KeyB: "b", KeyC: "c", KeyD: "d", KeyE: "e",
|
||||||
|
@ -220,9 +233,9 @@ export const keyDisplayMap: Record<string, string> = {
|
||||||
NumpadDelete: "Del", NumLock: "Num Lock",
|
NumpadDelete: "Del", NumLock: "Num Lock",
|
||||||
|
|
||||||
// Modals
|
// Modals
|
||||||
PrintScreen: "PrtSc", ScrollLock: "Scroll Lock", Pause: "Pause",
|
PrintScreen: "Prt Sc", ScrollLock: "Scr Lk", Pause: "Pause",
|
||||||
"(PrintScreen)": "SysRq", "(Pause)": "Break",
|
"(PrintScreen)": "Sys Rq", "(Pause)": "Break",
|
||||||
SystemRequest: "SysRq", Break: "Break"
|
SystemRequest: "Sys Rq", Break: "Break"
|
||||||
};
|
};
|
||||||
|
|
||||||
export const virtualKeyboard = {
|
export const virtualKeyboard = {
|
||||||
|
@ -246,7 +259,7 @@ export const virtualKeyboard = {
|
||||||
"ControlLeft MetaLeft AltLeft Space AltGr MetaRight Menu ControlRight",
|
"ControlLeft MetaLeft AltLeft Space AltGr MetaRight Menu ControlRight",
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
controlSection: {
|
control: {
|
||||||
default: [
|
default: [
|
||||||
"PrintScreen ScrollLock Pause",
|
"PrintScreen ScrollLock Pause",
|
||||||
"Insert Home PageUp",
|
"Insert Home PageUp",
|
||||||
|
@ -259,7 +272,7 @@ export const virtualKeyboard = {
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
||||||
simpleArrows: {
|
arrows: {
|
||||||
default: [
|
default: [
|
||||||
"ArrowUp",
|
"ArrowUp",
|
||||||
"ArrowLeft ArrowDown ArrowRight"],
|
"ArrowLeft ArrowDown ArrowRight"],
|
||||||
|
@ -291,3 +304,5 @@ export const en_US: KeyboardLayout = {
|
||||||
modifierDisplayMap,
|
modifierDisplayMap,
|
||||||
virtualKeyboard
|
virtualKeyboard
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,15 @@
|
||||||
import { KeyboardLayout, KeyCombo } from "../keyboardLayouts"
|
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 name = "Español";
|
||||||
const keyAcute = { key: "Quote" } // accent aigu (acute accent), mark ´ placed above the letter
|
const isoCode = "es-ES";
|
||||||
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 keyTrema: KeyCombo = { key: "Quote", shift: true } // tréma (umlaut), two dots placed above a vowel
|
||||||
const keyTilde = { key: "Key4", altRight: true } // tilde, mark ~ placed above the letter
|
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 = {
|
const chars = {
|
||||||
A: { key: "KeyA", shift: true },
|
A: { key: "KeyA", shift: true },
|
||||||
|
@ -168,7 +171,11 @@ const chars = {
|
||||||
} as Record<string, KeyCombo>;
|
} as Record<string, KeyCombo>;
|
||||||
|
|
||||||
export const es_ES: KeyboardLayout = {
|
export const es_ES: KeyboardLayout = {
|
||||||
isoCode: "es-ES",
|
isoCode: isoCode,
|
||||||
name: name,
|
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
|
||||||
};
|
};
|
|
@ -1,12 +1,15 @@
|
||||||
import { KeyboardLayout, KeyCombo } from "../keyboardLayouts"
|
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 name = "Belgisch Nederlands";
|
||||||
const keyHat = { key: "BracketLeft" } // accent circonflexe (accent hat), mark ^ placed above the letter
|
const isoCode = "nl-BE";
|
||||||
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 keyTrema: KeyCombo = { key: "BracketLeft", shift: true } // tréma (umlaut), two dots placed above a vowel
|
||||||
const keyTilde = { key: "Slash", altRight: true } // tilde, mark ~ placed above the letter
|
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 = {
|
const chars = {
|
||||||
A: { key: "KeyQ", shift: true },
|
A: { key: "KeyQ", shift: true },
|
||||||
|
@ -167,7 +170,11 @@ const chars = {
|
||||||
} as Record<string, KeyCombo>;
|
} as Record<string, KeyCombo>;
|
||||||
|
|
||||||
export const fr_BE: KeyboardLayout = {
|
export const fr_BE: KeyboardLayout = {
|
||||||
isoCode: "fr-BE",
|
isoCode: isoCode,
|
||||||
name: name,
|
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
|
||||||
};
|
};
|
|
@ -3,6 +3,7 @@ import { KeyboardLayout, KeyCombo } from "../keyboardLayouts"
|
||||||
import { de_CH } from "./de_CH"
|
import { de_CH } from "./de_CH"
|
||||||
|
|
||||||
const name = "Français de Suisse";
|
const name = "Français de Suisse";
|
||||||
|
const isoCode = "fr-CH";
|
||||||
|
|
||||||
const chars = {
|
const chars = {
|
||||||
...de_CH.chars,
|
...de_CH.chars,
|
||||||
|
@ -14,8 +15,22 @@ const chars = {
|
||||||
"ä": { key: "Quote", shift: true },
|
"ä": { key: "Quote", shift: true },
|
||||||
} as Record<string, KeyCombo>;
|
} as Record<string, KeyCombo>;
|
||||||
|
|
||||||
|
const keyDisplayMap = {
|
||||||
|
...de_CH.keyDisplayMap,
|
||||||
|
"BracketLeft": "è",
|
||||||
|
"BracketLeftShift": "ü",
|
||||||
|
"Semicolon": "é",
|
||||||
|
"SemicolonShift": "ö",
|
||||||
|
"Quote": "à",
|
||||||
|
"QuoteShift": "ä",
|
||||||
|
} as Record<string, string>;
|
||||||
|
|
||||||
export const fr_CH: KeyboardLayout = {
|
export const fr_CH: KeyboardLayout = {
|
||||||
isoCode: "fr-CH",
|
isoCode: isoCode,
|
||||||
name: name,
|
name: name,
|
||||||
chars: chars
|
chars: chars,
|
||||||
|
keyDisplayMap: keyDisplayMap,
|
||||||
|
// TODO need to localize these maps and layouts
|
||||||
|
modifierDisplayMap: de_CH.modifierDisplayMap,
|
||||||
|
virtualKeyboard: de_CH.virtualKeyboard
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
import { KeyboardLayout, KeyCombo } from "../keyboardLayouts"
|
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 name = "Français";
|
||||||
const keyHat = { key: "BracketLeft" } // accent circonflexe (accent hat), mark ^ placed above the letter
|
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 = {
|
const chars = {
|
||||||
A: { key: "KeyQ", shift: true },
|
A: { key: "KeyQ", shift: true },
|
||||||
|
@ -139,7 +142,11 @@ const chars = {
|
||||||
} as Record<string, KeyCombo>;
|
} as Record<string, KeyCombo>;
|
||||||
|
|
||||||
export const fr_FR: KeyboardLayout = {
|
export const fr_FR: KeyboardLayout = {
|
||||||
isoCode: "fr-FR",
|
isoCode: isoCode,
|
||||||
name: name,
|
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
|
||||||
};
|
};
|
|
@ -1,6 +1,9 @@
|
||||||
import { KeyboardLayout, KeyCombo } from "../keyboardLayouts"
|
import { KeyboardLayout, KeyCombo } from "../keyboardLayouts"
|
||||||
|
|
||||||
|
import { en_US } from "./en_US" // for fallback of keyDisplayMap, modifierDisplayMap, and virtualKeyboard
|
||||||
|
|
||||||
const name = "Italiano";
|
const name = "Italiano";
|
||||||
|
const isoCode = "it-IT";
|
||||||
|
|
||||||
const chars = {
|
const chars = {
|
||||||
A: { key: "KeyA", shift: true },
|
A: { key: "KeyA", shift: true },
|
||||||
|
@ -113,7 +116,11 @@ const chars = {
|
||||||
} as Record<string, KeyCombo>;
|
} as Record<string, KeyCombo>;
|
||||||
|
|
||||||
export const it_IT: KeyboardLayout = {
|
export const it_IT: KeyboardLayout = {
|
||||||
isoCode: "it-IT",
|
isoCode: isoCode,
|
||||||
name: name,
|
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
|
||||||
};
|
};
|
|
@ -1,12 +1,15 @@
|
||||||
import { KeyboardLayout, KeyCombo } from "../keyboardLayouts"
|
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 name = "Norsk bokmål";
|
||||||
const keyAcute = { key: "Equal", altRight: true } // accent aigu (acute accent), mark ´ placed above the letter
|
const isoCode = "nb-NO";
|
||||||
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 keyTrema: KeyCombo = { key: "BracketRight" } // tréma (umlaut), two dots placed above a vowel
|
||||||
const keyTilde = { key: "BracketRight", altRight: true } // tilde, mark ~ placed above the letter
|
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 = {
|
const chars = {
|
||||||
A: { key: "KeyA", shift: true },
|
A: { key: "KeyA", shift: true },
|
||||||
|
@ -167,7 +170,11 @@ const chars = {
|
||||||
} as Record<string, KeyCombo>;
|
} as Record<string, KeyCombo>;
|
||||||
|
|
||||||
export const nb_NO: KeyboardLayout = {
|
export const nb_NO: KeyboardLayout = {
|
||||||
isoCode: "nb-NO",
|
isoCode: isoCode,
|
||||||
name: name,
|
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
|
||||||
};
|
};
|
|
@ -1,17 +1,20 @@
|
||||||
import { KeyboardLayout, KeyCombo } from "../keyboardLayouts"
|
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 name = "Polski (Programista)";
|
||||||
const keyCedilla = { key: "OEM_2", altRight: true } // Cedilla mark ¸ placed below the letter in the center
|
const isoCode = "pl-PL-t";
|
||||||
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 keyAcute: KeyCombo = { key: "Quote" } // accent aigu (acute accent), mark ´ placed above the letter
|
||||||
const keyDoubleAcute = { key: "˝" } // Double acute mark ˝, placed above the letter in the center
|
const keyCedilla: KeyCombo = { key: "OEM_2", altRight: true } // Cedilla mark ¸ placed below the letter in the center
|
||||||
const keyGrave = { key: "BracketRight" } // accent grave mark ` placed above the letter
|
const keyDiaresis: KeyCombo = { key: "Plus", shift: true } // Diaresis (not umlaut!), two dots placed above a vowel to indicate each vowel should be pronounce
|
||||||
const keyHacek = { key: "", } // TODO!
|
const keyDotAbove: KeyCombo = { key: "", } // Dot above, single TODO!
|
||||||
const keyHat = { key: "BracketRight", shift: true } // accent circonflexe (accent hat), mark ^ placed above the letter
|
const keyDoubleAcute: KeyCombo = { key: "˝" } // Double acute mark ˝, placed above the letter in the center
|
||||||
const keyOgonek = { key: ""} // Ogonek mark ˛ placed below the letter on the right side
|
const keyGrave: KeyCombo = { key: "BracketRight" } // accent grave mark ` placed above the letter
|
||||||
const keyTylda = { key: "Backquote", altRight: true } // Tilde 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 = {
|
const chars = {
|
||||||
A: { key: "KeyA", shift: true },
|
A: { key: "KeyA", shift: true },
|
||||||
|
@ -231,8 +234,11 @@ const chars = {
|
||||||
Tab: { key: "Tab" },
|
Tab: { key: "Tab" },
|
||||||
} as Record<string, KeyCombo>;
|
} as Record<string, KeyCombo>;
|
||||||
|
|
||||||
export const pl_PL_T: KeyboardLayout = {
|
export const pl_PL_t: KeyboardLayout = {
|
||||||
isoCode: "pl-PL-t",
|
isoCode: isoCode,
|
||||||
name: name,
|
name: name,
|
||||||
chars: chars
|
chars: chars,
|
||||||
|
keyDisplayMap: en_US.keyDisplayMap,
|
||||||
|
modifierDisplayMap: en_US.modifierDisplayMap,
|
||||||
|
virtualKeyboard: en_US.virtualKeyboard
|
||||||
};
|
};
|
|
@ -1,12 +1,15 @@
|
||||||
import { KeyboardLayout, KeyCombo } from "../keyboardLayouts"
|
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 name = "Svenska";
|
||||||
const keyAcute = { key: "Equal" } // accent aigu (acute accent), mark ´ placed above the letter
|
const isoCode = "sv-SE";
|
||||||
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 keyTrema: KeyCombo = { key: "BracketRight" } // tréma (umlaut), two dots placed above a vowel
|
||||||
const keyTilde = { key: "BracketRight", altRight: true } // tilde, mark ~ placed above the letter
|
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 = {
|
const chars = {
|
||||||
A: { key: "KeyA", shift: true },
|
A: { key: "KeyA", shift: true },
|
||||||
|
@ -164,7 +167,11 @@ const chars = {
|
||||||
} as Record<string, KeyCombo>;
|
} as Record<string, KeyCombo>;
|
||||||
|
|
||||||
export const sv_SE: KeyboardLayout = {
|
export const sv_SE: KeyboardLayout = {
|
||||||
isoCode: "sv-SE",
|
isoCode: isoCode,
|
||||||
name: name,
|
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
|
||||||
};
|
};
|
|
@ -236,20 +236,22 @@ export const keys = {
|
||||||
} as Record<string, number>;
|
} as Record<string, number>;
|
||||||
|
|
||||||
export const deadKeys = {
|
export const deadKeys = {
|
||||||
0x005e: "Circumflex",
|
Acute: 0x00b4,
|
||||||
0x02c7: "Caron",
|
Breve: 0x02d8,
|
||||||
0x00b7: "Dot",
|
Caron: 0x02c7,
|
||||||
0x02d8: "Breve",
|
Cedilla: 0x00b8,
|
||||||
0x002c: "Comma",
|
Circumflex: 0x005e, // or 0x02c6?
|
||||||
0x00b0: "Kreis",
|
Comma: 0x002c,
|
||||||
0x00b4: "Acute",
|
Dot: 0x00b7,
|
||||||
0x00a8: "Umlaut",
|
DoubleAcute: 0x02dd,
|
||||||
0x0060: "Grave",
|
Grave: 0x0060,
|
||||||
0x007e: "Tilde",
|
Kreis: 0x00b0,
|
||||||
0x02dd: "DoubleAcute",
|
Ogonek: 0x02db,
|
||||||
0x02db: "Ogonek",
|
Ring: 0x02da,
|
||||||
0x00b8: "Cedilla",
|
Slash: 0x02f8,
|
||||||
} as Record<number, string>
|
Tilde: 0x007e,
|
||||||
|
Umlaut: 0x00a8,
|
||||||
|
} as Record<string, number>
|
||||||
|
|
||||||
export const modifiers = {
|
export const modifiers = {
|
||||||
ControlLeft: 0x01,
|
ControlLeft: 0x01,
|
||||||
|
@ -272,115 +274,3 @@ export const hidKeyToModifierMask = {
|
||||||
0xe6: modifiers.AltRight,
|
0xe6: modifiers.AltRight,
|
||||||
0xe7: modifiers.MetaRight,
|
0xe7: modifiers.MetaRight,
|
||||||
} as Record<number, number>;
|
} as Record<number, number>;
|
||||||
|
|
||||||
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",
|
|
||||||
AltGr: "AltGr",
|
|
||||||
} as Record<string, string>;
|
|
||||||
|
|
||||||
export const keyDisplayMap: Record<string, string> = {
|
|
||||||
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"
|
|
||||||
};
|
|
||||||
|
|
|
@ -1,28 +1,20 @@
|
||||||
import { useCallback, useEffect, useMemo } from "react";
|
import { useCallback, useEffect } from "react";
|
||||||
|
|
||||||
import { useSettingsStore } from "@/hooks/stores";
|
import { useSettingsStore } from "@/hooks/stores";
|
||||||
import { useJsonRpc } from "@/hooks/useJsonRpc";
|
import { useJsonRpc } from "@/hooks/useJsonRpc";
|
||||||
import notifications from "@/notifications";
|
import { useKeyboardLayout } from "@/hooks/useKeyboardLayout";
|
||||||
import { SettingsPageHeader } from "@components/SettingsPageheader";
|
import { SettingsPageHeader } from "@components/SettingsPageheader";
|
||||||
import { keyboardOptions } from "@/keyboardLayouts";
|
|
||||||
import { Checkbox } from "@/components/Checkbox";
|
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";
|
import { SettingsItem } from "./devices.$id.settings";
|
||||||
|
|
||||||
export default function SettingsKeyboardRoute() {
|
export default function SettingsKeyboardRoute() {
|
||||||
const { keyboardLayout, setKeyboardLayout } = useSettingsStore();
|
const { setKeyboardLayout } = useSettingsStore();
|
||||||
const { showPressedKeys, setShowPressedKeys } = useSettingsStore();
|
const { showPressedKeys, setShowPressedKeys } = useSettingsStore();
|
||||||
|
const { keyboard } = useKeyboardLayout();
|
||||||
// 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 layoutOptions = keyboardOptions();
|
const layoutOptions = keyboardOptions();
|
||||||
|
|
||||||
const { send } = useJsonRpc();
|
const { send } = useJsonRpc();
|
||||||
|
@ -30,21 +22,25 @@ export default function SettingsKeyboardRoute() {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
send("getKeyboardLayout", {}, resp => {
|
send("getKeyboardLayout", {}, resp => {
|
||||||
if ("error" in resp) return;
|
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]);
|
}, [send, setKeyboardLayout]);
|
||||||
|
|
||||||
const onKeyboardLayoutChange = useCallback(
|
const onKeyboardLayoutChange = useCallback(
|
||||||
(e: React.ChangeEvent<HTMLSelectElement>) => {
|
(e: React.ChangeEvent<HTMLSelectElement>) => {
|
||||||
const layout = e.target.value;
|
const isoCode = e.target.value;
|
||||||
send("setKeyboardLayout", { layout }, resp => {
|
send("setKeyboardLayout", { layout: isoCode }, resp => {
|
||||||
if ("error" in resp) {
|
if ("error" in resp) {
|
||||||
notifications.error(
|
notifications.error(
|
||||||
`Failed to set keyboard layout: ${resp.error.data || "Unknown error"}`,
|
`Failed to set keyboard layout: ${resp.error.data || "Unknown error"}`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
notifications.success("Keyboard layout set successfully");
|
notifications.success("Keyboard layout set successfully to " + isoCode);
|
||||||
setKeyboardLayout(layout);
|
setKeyboardLayout(isoCode);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
[send, setKeyboardLayout],
|
[send, setKeyboardLayout],
|
||||||
|
@ -58,7 +54,6 @@ export default function SettingsKeyboardRoute() {
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
{ /* this menu item could be renamed to plain "Keyboard layout" in the future, when also the virtual keyboard layout mappings are being implemented */ }
|
|
||||||
<SettingsItem
|
<SettingsItem
|
||||||
title="Paste text"
|
title="Paste text"
|
||||||
description="Keyboard layout of target operating system"
|
description="Keyboard layout of target operating system"
|
||||||
|
@ -67,7 +62,7 @@ export default function SettingsKeyboardRoute() {
|
||||||
size="SM"
|
size="SM"
|
||||||
label=""
|
label=""
|
||||||
fullWidth
|
fullWidth
|
||||||
value={safeKeyboardLayout}
|
value={keyboard.isoCode}
|
||||||
onChange={onKeyboardLayoutChange}
|
onChange={onKeyboardLayoutChange}
|
||||||
options={layoutOptions}
|
options={layoutOptions}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -17,10 +17,10 @@ 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 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";
|
||||||
|
import { useKeyboardLayout } from "@/hooks/useKeyboardLayout";
|
||||||
|
|
||||||
const normalizeSortOrders = (macros: KeySequence[]): KeySequence[] => {
|
const normalizeSortOrders = (macros: KeySequence[]): KeySequence[] => {
|
||||||
return macros.map((macro, index) => ({
|
return macros.map((macro, index) => ({
|
||||||
|
@ -35,6 +35,7 @@ export default function SettingsMacrosRoute() {
|
||||||
const [actionLoadingId, setActionLoadingId] = useState<string | null>(null);
|
const [actionLoadingId, setActionLoadingId] = useState<string | null>(null);
|
||||||
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 { keyboard } = useKeyboardLayout();
|
||||||
|
|
||||||
const isMaxMacrosReached = useMemo(
|
const isMaxMacrosReached = useMemo(
|
||||||
() => macros.length >= MAX_TOTAL_MACROS,
|
() => macros.length >= MAX_TOTAL_MACROS,
|
||||||
|
@ -185,7 +186,7 @@ export default function SettingsMacrosRoute() {
|
||||||
step.modifiers.map((modifier, idx) => (
|
step.modifiers.map((modifier, idx) => (
|
||||||
<Fragment key={`mod-${idx}`}>
|
<Fragment key={`mod-${idx}`}>
|
||||||
<span className="font-medium text-slate-600 dark:text-slate-200">
|
<span className="font-medium text-slate-600 dark:text-slate-200">
|
||||||
{modifierDisplayMap[modifier] || modifier}
|
{keyboard.modifierDisplayMap[modifier] || modifier}
|
||||||
</span>
|
</span>
|
||||||
{idx < step.modifiers.length - 1 && (
|
{idx < step.modifiers.length - 1 && (
|
||||||
<span className="text-slate-400 dark:text-slate-600">
|
<span className="text-slate-400 dark:text-slate-600">
|
||||||
|
@ -210,7 +211,7 @@ export default function SettingsMacrosRoute() {
|
||||||
step.keys.map((key, idx) => (
|
step.keys.map((key, idx) => (
|
||||||
<Fragment key={`key-${idx}`}>
|
<Fragment key={`key-${idx}`}>
|
||||||
<span className="font-medium text-blue-600 dark:text-blue-400">
|
<span className="font-medium text-blue-600 dark:text-blue-400">
|
||||||
{keyDisplayMap[key] || key}
|
{keyboard.keyDisplayMap[key] || key}
|
||||||
</span>
|
</span>
|
||||||
{idx < step.keys.length - 1 && (
|
{idx < step.keys.length - 1 && (
|
||||||
<span className="text-slate-400 dark:text-slate-600">
|
<span className="text-slate-400 dark:text-slate-600">
|
||||||
|
@ -297,8 +298,10 @@ export default function SettingsMacrosRoute() {
|
||||||
actionLoadingId,
|
actionLoadingId,
|
||||||
handleDeleteMacro,
|
handleDeleteMacro,
|
||||||
handleMoveMacro,
|
handleMoveMacro,
|
||||||
|
keyboard.modifierDisplayMap,
|
||||||
|
keyboard.keyDisplayMap,
|
||||||
handleDuplicateMacro,
|
handleDuplicateMacro,
|
||||||
navigate,
|
navigate
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -17,14 +17,13 @@ import { useResizeObserver } from "usehooks-ts";
|
||||||
|
|
||||||
import Card from "@/components/Card";
|
import Card from "@/components/Card";
|
||||||
import { LinkButton } from "@/components/Button";
|
import { LinkButton } from "@/components/Button";
|
||||||
|
import { FeatureFlag } from "@/components/FeatureFlag";
|
||||||
import LoadingSpinner from "@/components/LoadingSpinner";
|
import LoadingSpinner from "@/components/LoadingSpinner";
|
||||||
import { useUiStore } from "@/hooks/stores";
|
import { useUiStore } from "@/hooks/stores";
|
||||||
import useKeyboard from "@/hooks/useKeyboard";
|
import useKeyboard from "@/hooks/useKeyboard";
|
||||||
|
|
||||||
import { FeatureFlag } from "../components/FeatureFlag";
|
|
||||||
import { cx } from "../cva.config";
|
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. */
|
/* 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() {
|
export default function SettingsRoute() {
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
|
@ -65,16 +64,10 @@ export default function SettingsRoute() {
|
||||||
}, [width]);
|
}, [width]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// disable focus trap
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
// Reset keyboard state. In case the user is pressing a key while enabling the sidebar
|
|
||||||
resetKeyboardState();
|
|
||||||
setDisableVideoFocusTrap(true);
|
setDisableVideoFocusTrap(true);
|
||||||
// For some reason, the focus trap is not disabled immediately
|
resetKeyboardState();
|
||||||
// so we need to blur the active element
|
}, 500);
|
||||||
(document.activeElement as HTMLElement)?.blur();
|
|
||||||
console.debug("Just disabled focus trap");
|
|
||||||
}, 300);
|
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
setDisableVideoFocusTrap(false);
|
setDisableVideoFocusTrap(false);
|
||||||
|
|
Loading…
Reference in New Issue