This commit is contained in:
Marc Brooks 2025-05-22 11:07:11 +02:00 committed by GitHub
commit 72f2c3a146
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
17 changed files with 217 additions and 134 deletions

View File

@ -10,11 +10,11 @@ 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 { layouts, chars } from "@/keyboardLayouts"; import { KeyStroke, KeyboardLayout, selectedKeyboard } from "@/keyboardLayouts";
import notifications from "@/notifications"; import notifications from "@/notifications";
const hidKeyboardPayload = (keys: number[], modifier: number) => { const hidKeyboardPayload = (modifier: number, keys: number[]) => {
return { keys, modifier }; return { modifier, keys };
}; };
const modifierCode = (shift?: boolean, altRight?: boolean) => { const modifierCode = (shift?: boolean, altRight?: boolean) => {
@ -57,47 +57,53 @@ export default function PasteModal() {
setDisableVideoFocusTrap(false); setDisableVideoFocusTrap(false);
if (rpcDataChannel?.readyState !== "open" || !TextAreaRef.current) return; if (rpcDataChannel?.readyState !== "open" || !TextAreaRef.current) return;
if (!keyboardLayout) return; if (!keyboardLayout) return;
if (!chars[keyboardLayout]) return; const keyboard: KeyboardLayout = selectedKeyboard(keyboardLayout);
if (!keyboard) return;
const text = TextAreaRef.current.value; const text = TextAreaRef.current.value;
try { try {
for (const char of text) { for (const char of text) {
const { key, shift, altRight, deadKey, accentKey } = chars[keyboardLayout][char] const keyprops = keyboard.chars[char];
if (!keyprops) continue;
const { key, shift, altRight, deadKey, accentKey } = keyprops;
if (!key) continue; if (!key) continue;
const keyz = [ keys[key] ]; // if this is an accented character, we need to send that accent FIRST
const modz = [ modifierCode(shift, altRight) ]; if (accentKey) {
await sendKeystroke({modifier: modifierCode(accentKey.shift, accentKey.altRight), keys: [ keys[accentKey.key] ] })
}
if (deadKey) { // now send the actual key
keyz.push(keys["Space"]); await sendKeystroke({ modifier: modifierCode(shift, altRight), keys: [ keys[key] ]});
modz.push(noModifier);
}
if (accentKey) {
keyz.unshift(keys[accentKey.key])
modz.unshift(modifierCode(accentKey.shift, accentKey.altRight))
}
for (const [index, kei] of keyz.entries()) { // if what was requested was a dead key, we need to send an unmodified space to emit
await new Promise<void>((resolve, reject) => { // just the accent character
send( if (deadKey) {
"keyboardReport", await sendKeystroke({ modifier: noModifier, keys: [ keys["Space"] ] });
hidKeyboardPayload([kei], modz[index]), }
params => {
if ("error" in params) return reject(params.error); // now send a message with no keys down to "release" the keys
send("keyboardReport", hidKeyboardPayload([], 0), params => { await sendKeystroke({ modifier: 0, keys: [] });
if ("error" in params) return reject(params.error);
resolve();
});
},
);
});
}
} }
} catch (error) { } catch (error) {
console.error(error); console.error("Failed to paste text:", error);
notifications.error("Failed to paste text"); notifications.error("Failed to paste text");
} }
async function sendKeystroke(stroke: KeyStroke) {
await new Promise<void>((resolve, reject) => {
send(
"keyboardReport",
hidKeyboardPayload(stroke.modifier, stroke.keys),
params => {
if ("error" in params) return reject(params.error);
resolve();
}
);
});
}
}, [rpcDataChannel?.readyState, send, setDisableVideoFocusTrap, setPasteMode, keyboardLayout]); }, [rpcDataChannel?.readyState, send, setDisableVideoFocusTrap, setPasteMode, keyboardLayout]);
useEffect(() => { useEffect(() => {
@ -148,7 +154,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 => !chars[keyboardLayout][char]), .filter(char => !selectedKeyboard(keyboardLayout).chars[char]),
), ),
]; ];
@ -167,11 +173,11 @@ export default function PasteModal() {
)} )}
</div> </div>
</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: {layouts[keyboardLayout]} Sending text using keyboard layout: {selectedKeyboard(keyboardLayout).name}
</p> </p>
</div> </div>
</div> </div>
</div> </div>
</div> </div>

View File

@ -884,5 +884,5 @@ export const useMacrosStore = create<MacrosState>((set, get) => ({
} finally { } finally {
set({ loading: false }); set({ loading: false });
} }
}, }
})); }));

View File

@ -1,45 +1,31 @@
import { chars as chars_fr_BE, name as name_fr_BE } from "@/keyboardLayouts/fr_BE" export interface KeyStroke { modifier: number; keys: number[]; }
import { chars as chars_cs_CZ, name as name_cs_CZ } from "@/keyboardLayouts/cs_CZ" export interface KeyInfo { key: string | number; shift?: boolean, altRight?: boolean }
import { chars as chars_en_UK, name as name_en_UK } from "@/keyboardLayouts/en_UK" export interface KeyCombo extends KeyInfo { deadKey?: boolean, accentKey?: KeyInfo }
import { chars as chars_en_US, name as name_en_US } from "@/keyboardLayouts/en_US" export interface KeyboardLayout { isoCode: string, name: string, chars: Record<string, KeyCombo> }
import { chars as chars_fr_FR, name as name_fr_FR } from "@/keyboardLayouts/fr_FR"
import { chars as chars_de_DE, name as name_de_DE } from "@/keyboardLayouts/de_DE"
import { chars as chars_it_IT, name as name_it_IT } from "@/keyboardLayouts/it_IT"
import { chars as chars_nb_NO, name as name_nb_NO } from "@/keyboardLayouts/nb_NO"
import { chars as chars_es_ES, name as name_es_ES } from "@/keyboardLayouts/es_ES"
import { chars as chars_sv_SE, name as name_sv_SE } from "@/keyboardLayouts/sv_SE"
import { chars as chars_fr_CH, name as name_fr_CH } from "@/keyboardLayouts/fr_CH"
import { chars as chars_de_CH, name as name_de_CH } from "@/keyboardLayouts/de_CH"
type KeyInfo = { key: string | number; shift?: boolean, altRight?: boolean } // to add a new layout, create a file like the above and add it to the list
export type KeyCombo = KeyInfo & { deadKey?: boolean, accentKey?: KeyInfo } import { cs_CZ } from "@/keyboardLayouts/cs_CZ"
import { de_CH } from "@/keyboardLayouts/de_CH"
import { de_DE } from "@/keyboardLayouts/de_DE"
import { en_US } from "@/keyboardLayouts/en_US"
import { en_UK } from "@/keyboardLayouts/en_UK"
import { es_ES } from "@/keyboardLayouts/es_ES"
import { fr_BE } from "@/keyboardLayouts/fr_BE"
import { fr_CH } from "@/keyboardLayouts/fr_CH"
import { fr_FR } from "@/keyboardLayouts/fr_FR"
import { it_IT } from "@/keyboardLayouts/it_IT"
import { nb_NO } from "@/keyboardLayouts/nb_NO"
import { sv_SE } from "@/keyboardLayouts/sv_SE"
export const layouts: Record<string, string> = { 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, sv_SE ];
be_FR: name_fr_BE,
cs_CZ: name_cs_CZ,
en_UK: name_en_UK,
en_US: name_en_US,
fr_FR: name_fr_FR,
de_DE: name_de_DE,
it_IT: name_it_IT,
nb_NO: name_nb_NO,
es_ES: name_es_ES,
sv_SE: name_sv_SE,
fr_CH: name_fr_CH,
de_CH: name_de_CH,
}
export const chars: Record<string, Record<string, KeyCombo>> = { export const selectedKeyboard = (isoCode: string): KeyboardLayout => {
be_FR: chars_fr_BE, // fallback to original behaviour of en-US if no isoCode given
cs_CZ: chars_cs_CZ, return keyboards.find(keyboard => keyboard.isoCode == (isoCode ?? "en-US"))!;
en_UK: chars_en_UK,
en_US: chars_en_US,
fr_FR: chars_fr_FR,
de_DE: chars_de_DE,
it_IT: chars_it_IT,
nb_NO: chars_nb_NO,
es_ES: chars_es_ES,
sv_SE: chars_sv_SE,
fr_CH: chars_fr_CH,
de_CH: chars_de_CH,
}; };
export const keyboardOptions = () => {
return keyboards.map((keyboard) => {
return { label: keyboard.name, value: keyboard.isoCode }
});
}

View File

@ -1,6 +1,6 @@
import { KeyCombo } from "../keyboardLayouts" import { KeyboardLayout, KeyCombo } from "../keyboardLayouts"
export const name = "Čeština"; const name = "Čeština";
const keyTrema = { key: "Backslash" } // tréma (umlaut), two dots placed above a vowel 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 keyAcute = { key: "Equal" } // accent aigu (acute accent), mark ´ placed above the letter
@ -13,7 +13,7 @@ const keyOverdot = { key: "Digit8", shift: true, altRight: true } // overdot (do
const keyHook = { key: "Digit6", shift: true, altRight: true } // ogonoek (little hook), mark ˛ placed beneath a 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 keyCedille = { key: "Equal", shift: true, altRight: true } // accent cedille (cedilla), mark ¸ placed beneath a letter
export const chars = { const chars = {
A: { key: "KeyA", shift: true }, A: { key: "KeyA", shift: true },
"Ä": { key: "KeyA", shift: true, accentKey: keyTrema }, "Ä": { key: "KeyA", shift: true, accentKey: keyTrema },
"Á": { key: "KeyA", shift: true, accentKey: keyAcute }, "Á": { key: "KeyA", shift: true, accentKey: keyAcute },
@ -242,3 +242,9 @@ export const chars = {
Enter: { key: "Enter" }, Enter: { key: "Enter" },
Tab: { key: "Tab" }, Tab: { key: "Tab" },
} as Record<string, KeyCombo>; } as Record<string, KeyCombo>;
export const cs_CZ: KeyboardLayout = {
isoCode: "cs-CZ",
name: name,
chars: chars
};

View File

@ -1,6 +1,6 @@
import { KeyCombo } from "../keyboardLayouts" import { KeyboardLayout, KeyCombo } from "../keyboardLayouts"
export const name = "Schwiizerdütsch"; const name = "Schwiizerdütsch";
const keyTrema = { key: "BracketRight" } // tréma (umlaut), two dots placed above a vowel 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 keyAcute = { key: "Minus", altRight: true } // accent aigu (acute accent), mark ´ placed above the letter
@ -8,7 +8,7 @@ const keyHat = { key: "Equal" } // accent circonflexe (accent hat), mark ^ place
const keyGrave = { key: "Equal", shift: true } // accent grave, 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 keyTilde = { key: "Equal", altRight: true } // tilde, mark ~ placed above the letter
export const chars = { const chars = {
A: { key: "KeyA", shift: true }, A: { key: "KeyA", shift: true },
"Ä": { key: "KeyA", shift: true, accentKey: keyTrema }, "Ä": { key: "KeyA", shift: true, accentKey: keyTrema },
"Á": { key: "KeyA", shift: true, accentKey: keyAcute }, "Á": { key: "KeyA", shift: true, accentKey: keyAcute },
@ -163,3 +163,9 @@ export const chars = {
Enter: { key: "Enter" }, Enter: { key: "Enter" },
Tab: { key: "Tab" }, Tab: { key: "Tab" },
} as Record<string, KeyCombo>; } as Record<string, KeyCombo>;
export const de_CH: KeyboardLayout = {
isoCode: "de-CH",
name: name,
chars: chars
};

View File

@ -1,12 +1,12 @@
import { KeyCombo } from "../keyboardLayouts" import { KeyboardLayout, KeyCombo } from "../keyboardLayouts"
export const name = "Deutsch"; const name = "Deutsch";
const keyAcute = { key: "Equal" } // accent aigu (acute accent), mark ´ placed above the letter 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 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 keyGrave = { key: "Equal", shift: true } // accent grave, mark ` placed above the letter
export const chars = { const chars = {
A: { key: "KeyA", shift: true }, A: { key: "KeyA", shift: true },
"Á": { key: "KeyA", shift: true, accentKey: keyAcute }, "Á": { key: "KeyA", shift: true, accentKey: keyAcute },
"Â": { key: "KeyA", shift: true, accentKey: keyHat }, "Â": { key: "KeyA", shift: true, accentKey: keyHat },
@ -150,3 +150,9 @@ export const chars = {
Enter: { key: "Enter" }, Enter: { key: "Enter" },
Tab: { key: "Tab" }, Tab: { key: "Tab" },
} as Record<string, KeyCombo>; } as Record<string, KeyCombo>;
export const de_DE: KeyboardLayout = {
isoCode: "de-DE",
name: name,
chars: chars
};

View File

@ -1,8 +1,8 @@
import { KeyCombo } from "../keyboardLayouts" import { KeyboardLayout, KeyCombo } from "../keyboardLayouts"
export const name = "English (UK)"; const name = "English (UK)";
export const chars = { const chars = {
A: { key: "KeyA", shift: true }, A: { key: "KeyA", shift: true },
B: { key: "KeyB", shift: true }, B: { key: "KeyB", shift: true },
C: { key: "KeyC", shift: true }, C: { key: "KeyC", shift: true },
@ -105,3 +105,9 @@ export const chars = {
Enter: { key: "Enter" }, Enter: { key: "Enter" },
Tab: { key: "Tab" }, Tab: { key: "Tab" },
} as Record<string, KeyCombo> } as Record<string, KeyCombo>
export const en_UK: KeyboardLayout = {
isoCode: "en-UK",
name: name,
chars: chars
};

View File

@ -1,8 +1,8 @@
import { KeyCombo } from "../keyboardLayouts" import { KeyboardLayout, KeyCombo } from "../keyboardLayouts"
export const name = "English (US)"; const name = "English (US)";
export const chars = { const chars = {
A: { key: "KeyA", shift: true }, A: { key: "KeyA", shift: true },
B: { key: "KeyB", shift: true }, B: { key: "KeyB", shift: true },
C: { key: "KeyC", shift: true }, C: { key: "KeyC", shift: true },
@ -111,3 +111,9 @@ export const chars = {
Insert: { key: "Insert", shift: false }, Insert: { key: "Insert", shift: false },
Delete: { key: "Delete", shift: false }, Delete: { key: "Delete", shift: false },
} as Record<string, KeyCombo> } as Record<string, KeyCombo>
export const en_US: KeyboardLayout = {
isoCode: "en-US",
name: name,
chars: chars
};

View File

@ -1,6 +1,6 @@
import { KeyCombo } from "../keyboardLayouts" import { KeyboardLayout, KeyCombo } from "../keyboardLayouts"
export const name = "Español"; const name = "Español";
const keyTrema = { key: "Quote", shift: true } // tréma (umlaut), two dots placed above a vowel 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 keyAcute = { key: "Quote" } // accent aigu (acute accent), mark ´ placed above the letter
@ -8,7 +8,7 @@ const keyHat = { key: "BracketRight", shift: true } // accent circonflexe (accen
const keyGrave = { key: "BracketRight" } // accent grave, 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 keyTilde = { key: "Key4", altRight: true } // tilde, mark ~ placed above the letter
export const chars = { const chars = {
A: { key: "KeyA", shift: true }, A: { key: "KeyA", shift: true },
"Ä": { key: "KeyA", shift: true, accentKey: keyTrema }, "Ä": { key: "KeyA", shift: true, accentKey: keyTrema },
"Á": { key: "KeyA", shift: true, accentKey: keyAcute }, "Á": { key: "KeyA", shift: true, accentKey: keyAcute },
@ -166,3 +166,9 @@ export const chars = {
Enter: { key: "Enter" }, Enter: { key: "Enter" },
Tab: { key: "Tab" }, Tab: { key: "Tab" },
} as Record<string, KeyCombo>; } as Record<string, KeyCombo>;
export const es_ES: KeyboardLayout = {
isoCode: "es-ES",
name: name,
chars: chars
};

View File

@ -1,6 +1,6 @@
import { KeyCombo } from "../keyboardLayouts" import { KeyboardLayout, KeyCombo } from "../keyboardLayouts"
export const name = "Belgisch Nederlands"; const name = "Belgisch Nederlands";
const keyTrema = { key: "BracketLeft", shift: true } // tréma (umlaut), two dots placed above a vowel 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 keyHat = { key: "BracketLeft" } // accent circonflexe (accent hat), mark ^ placed above the letter
@ -8,7 +8,7 @@ const keyAcute = { key: "Semicolon", altRight: true } // accent aigu (acute acce
const keyGrave = { key: "Quote", shift: true } // accent grave, 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 keyTilde = { key: "Slash", altRight: true } // tilde, mark ~ placed above the letter
export const chars = { const chars = {
A: { key: "KeyQ", shift: true }, A: { key: "KeyQ", shift: true },
"Ä": { key: "KeyQ", shift: true, accentKey: keyTrema }, "Ä": { key: "KeyQ", shift: true, accentKey: keyTrema },
"Â": { key: "KeyQ", shift: true, accentKey: keyHat }, "Â": { key: "KeyQ", shift: true, accentKey: keyHat },
@ -165,3 +165,9 @@ export const chars = {
Enter: { key: "Enter" }, Enter: { key: "Enter" },
Tab: { key: "Tab" }, Tab: { key: "Tab" },
} as Record<string, KeyCombo>; } as Record<string, KeyCombo>;
export const fr_BE: KeyboardLayout = {
isoCode: "fr-BE",
name: name,
chars: chars
};

View File

@ -1,10 +1,11 @@
import { KeyCombo } from "../keyboardLayouts" import { KeyboardLayout, KeyCombo } from "../keyboardLayouts"
import { chars as chars_de_CH } from "./de_CH"
export const name = "Français de Suisse"; import { de_CH } from "./de_CH"
export const chars = { const name = "Français de Suisse";
...chars_de_CH,
const chars = {
...de_CH.chars,
"è": { key: "BracketLeft" }, "è": { key: "BracketLeft" },
"ü": { key: "BracketLeft", shift: true }, "ü": { key: "BracketLeft", shift: true },
"é": { key: "Semicolon" }, "é": { key: "Semicolon" },
@ -12,3 +13,9 @@ export const chars = {
"à": { key: "Quote" }, "à": { key: "Quote" },
"ä": { key: "Quote", shift: true }, "ä": { key: "Quote", shift: true },
} as Record<string, KeyCombo>; } as Record<string, KeyCombo>;
export const fr_CH: KeyboardLayout = {
isoCode: "fr-CH",
name: name,
chars: chars
};

View File

@ -1,11 +1,11 @@
import { KeyCombo } from "../keyboardLayouts" import { KeyboardLayout, KeyCombo } from "../keyboardLayouts"
export const name = "Français"; const name = "Français";
const keyTrema = { key: "BracketLeft", shift: true } // tréma (umlaut), two dots placed above a vowel 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 keyHat = { key: "BracketLeft" } // accent circonflexe (accent hat), mark ^ placed above the letter
export const chars = { const chars = {
A: { key: "KeyQ", shift: true }, A: { key: "KeyQ", shift: true },
"Ä": { key: "KeyQ", shift: true, accentKey: keyTrema }, "Ä": { key: "KeyQ", shift: true, accentKey: keyTrema },
"Â": { key: "KeyQ", shift: true, accentKey: keyHat }, "Â": { key: "KeyQ", shift: true, accentKey: keyHat },
@ -137,3 +137,9 @@ export const chars = {
Enter: { key: "Enter" }, Enter: { key: "Enter" },
Tab: { key: "Tab" }, Tab: { key: "Tab" },
} as Record<string, KeyCombo>; } as Record<string, KeyCombo>;
export const fr_FR: KeyboardLayout = {
isoCode: "fr-FR",
name: name,
chars: chars
};

View File

@ -1,8 +1,8 @@
import { KeyCombo } from "../keyboardLayouts" import { KeyboardLayout, KeyCombo } from "../keyboardLayouts"
export const name = "Italiano"; const name = "Italiano";
export const chars = { const chars = {
A: { key: "KeyA", shift: true }, A: { key: "KeyA", shift: true },
B: { key: "KeyB", shift: true }, B: { key: "KeyB", shift: true },
C: { key: "KeyC", shift: true }, C: { key: "KeyC", shift: true },
@ -111,3 +111,9 @@ export const chars = {
Enter: { key: "Enter" }, Enter: { key: "Enter" },
Tab: { key: "Tab" }, Tab: { key: "Tab" },
} as Record<string, KeyCombo>; } as Record<string, KeyCombo>;
export const it_IT: KeyboardLayout = {
isoCode: "it-IT",
name: name,
chars: chars
};

View File

@ -1,6 +1,6 @@
import { KeyCombo } from "../keyboardLayouts" import { KeyboardLayout, KeyCombo } from "../keyboardLayouts"
export const name = "Norsk bokmål"; const name = "Norsk bokmål";
const keyTrema = { key: "BracketRight" } // tréma (umlaut), two dots placed above a vowel 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 keyAcute = { key: "Equal", altRight: true } // accent aigu (acute accent), mark ´ placed above the letter
@ -8,7 +8,7 @@ const keyHat = { key: "BracketRight", shift: true } // accent circonflexe (accen
const keyGrave = { key: "Equal", shift: true } // accent grave, 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 keyTilde = { key: "BracketRight", altRight: true } // tilde, mark ~ placed above the letter
export const chars = { const chars = {
A: { key: "KeyA", shift: true }, A: { key: "KeyA", shift: true },
"Ä": { key: "KeyA", shift: true, accentKey: keyTrema }, "Ä": { key: "KeyA", shift: true, accentKey: keyTrema },
"Á": { key: "KeyA", shift: true, accentKey: keyAcute }, "Á": { key: "KeyA", shift: true, accentKey: keyAcute },
@ -165,3 +165,9 @@ export const chars = {
Enter: { key: "Enter" }, Enter: { key: "Enter" },
Tab: { key: "Tab" }, Tab: { key: "Tab" },
} as Record<string, KeyCombo>; } as Record<string, KeyCombo>;
export const nb_NO: KeyboardLayout = {
isoCode: "nb-NO",
name: name,
chars: chars
};

View File

@ -1,6 +1,6 @@
import { KeyCombo } from "../keyboardLayouts" import { KeyboardLayout, KeyCombo } from "../keyboardLayouts"
export const name = "Svenska"; const name = "Svenska";
const keyTrema = { key: "BracketRight" } // tréma (umlaut), two dots placed above a vowel 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 keyAcute = { key: "Equal" } // accent aigu (acute accent), mark ´ placed above the letter
@ -8,7 +8,7 @@ const keyHat = { key: "BracketRight", shift: true } // accent circonflexe (accen
const keyGrave = { key: "Equal", shift: true } // accent grave, 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 keyTilde = { key: "BracketRight", altRight: true } // tilde, mark ~ placed above the letter
export const chars = { const chars = {
A: { key: "KeyA", shift: true }, A: { key: "KeyA", shift: true },
"Á": { key: "KeyA", shift: true, accentKey: keyAcute }, "Á": { key: "KeyA", shift: true, accentKey: keyAcute },
"Â": { key: "KeyA", shift: true, accentKey: keyHat }, "Â": { key: "KeyA", shift: true, accentKey: keyHat },
@ -162,3 +162,9 @@ export const chars = {
Enter: { key: "Enter" }, Enter: { key: "Enter" },
Tab: { key: "Tab" }, Tab: { key: "Tab" },
} as Record<string, KeyCombo>; } as Record<string, KeyCombo>;
export const sv_SE: KeyboardLayout = {
isoCode: "sv-SE",
name: name,
chars: chars
};

View File

@ -1,17 +1,19 @@
// Key codes and modifiers correspond to definitions in the // Key codes and modifiers correspond to definitions in the
// [Linux USB HID gadget driver](https://www.kernel.org/doc/Documentation/usb/gadget_hid.txt) // [Linux USB HID gadget driver](https://www.kernel.org/doc/Documentation/usb/gadget_hid.txt)
// [Section 10. Keyboard/Keypad Page 0x07](https://usb.org/sites/default/files/hut1_21.pdf)
export const keys = { export const keys = {
ArrowDown: 0x51, ArrowDown: 0x51,
ArrowLeft: 0x50, ArrowLeft: 0x50,
ArrowRight: 0x4f, ArrowRight: 0x4f,
ArrowUp: 0x52, ArrowUp: 0x52,
Backquote: 0x35, Backquote: 0x35, // aka Grave
Backslash: 0x31, Backslash: 0x31,
Backspace: 0x2a, Backspace: 0x2a,
BracketLeft: 0x2f, BracketLeft: 0x2f, // aka LeftBrace
BracketRight: 0x30, BracketRight: 0x30, // aka RightBrace
CapsLock: 0x39, CapsLock: 0x39,
Comma: 0x36, Comma: 0x36,
Compose: 0x65,
ContextMenu: 0, ContextMenu: 0,
Delete: 0x4c, Delete: 0x4c,
Digit0: 0x27, Digit0: 0x27,
@ -40,10 +42,21 @@ export const keys = {
F10: 0x43, F10: 0x43,
F11: 0x44, F11: 0x44,
F12: 0x45, F12: 0x45,
F13: 0x68, F14: 0x69,
F15: 0x6a,
F16: 0x6b,
F17: 0x6c,
F18: 0x6d,
F19: 0x6e,
F20: 0x6f,
F21: 0x70,
F22: 0x71,
F23: 0x72,
F24: 0x73,
Home: 0x4a, Home: 0x4a,
HashTilde: 0x32, // non-US # and ~
Insert: 0x49, Insert: 0x49,
IntlBackslash: 0x64, IntlBackslash: 0x64, // non-US \ and |
KeyA: 0x04, KeyA: 0x04,
KeyB: 0x05, KeyB: 0x05,
KeyC: 0x06, KeyC: 0x06,
@ -72,30 +85,35 @@ export const keys = {
KeyZ: 0x1d, KeyZ: 0x1d,
KeypadExclamation: 0xcf, KeypadExclamation: 0xcf,
Minus: 0x2d, Minus: 0x2d,
NumLock: 0x53, None: 0x00,
Numpad0: 0x62, NumLock: 0x53, // and Clear
Numpad1: 0x59, Numpad0: 0x62, // and Insert
Numpad2: 0x5a, Numpad1: 0x59, // and End
Numpad3: 0x5b, Numpad2: 0x5a, // and Down Arrow
Numpad4: 0x5c, Numpad3: 0x5b, // and Page Down
Numpad4: 0x5c, // and Left Arrow
Numpad5: 0x5d, Numpad5: 0x5d,
Numpad6: 0x5e, Numpad6: 0x5e, // and Right Arrow
Numpad7: 0x5f, Numpad7: 0x5f, // and Home
Numpad8: 0x60, Numpad8: 0x60, // and Up Arrow
Numpad9: 0x61, Numpad9: 0x61, // and Page Up
NumpadAdd: 0x57, NumpadAdd: 0x57,
NumpadComma: 0x85,
NumpadDecimal: 0x63,
NumpadDivide: 0x54, NumpadDivide: 0x54,
NumpadEnter: 0x58, NumpadEnter: 0x58,
NumpadEqual: 0x67, NumpadEqual: 0x67,
NumpadLeftParen: 0xb6,
NumpadMultiply: 0x55, NumpadMultiply: 0x55,
NumpadRightParen: 0xb7,
NumpadSubtract: 0x56, NumpadSubtract: 0x56,
NumpadDecimal: 0x63,
PageDown: 0x4e, PageDown: 0x4e,
PageUp: 0x4b, PageUp: 0x4b,
Period: 0x37, Period: 0x37,
PrintScreen: 0x46, PrintScreen: 0x46,
Pause: 0x48, Pause: 0x48,
Quote: 0x34, Power: 0x66,
Quote: 0x34, // aka Single Quote or Apostrophe
ScrollLock: 0x47, ScrollLock: 0x47,
Semicolon: 0x33, Semicolon: 0x33,
Slash: 0x38, Slash: 0x38,

View File

@ -4,7 +4,7 @@ import { useSettingsStore } from "@/hooks/stores";
import { useJsonRpc } from "@/hooks/useJsonRpc"; import { useJsonRpc } from "@/hooks/useJsonRpc";
import notifications from "@/notifications"; import notifications from "@/notifications";
import { SettingsPageHeader } from "@components/SettingsPageheader"; import { SettingsPageHeader } from "@components/SettingsPageheader";
import { layouts } from "@/keyboardLayouts"; import { keyboardOptions } from "@/keyboardLayouts";
import { SelectMenuBasic } from "../components/SelectMenuBasic"; import { SelectMenuBasic } from "../components/SelectMenuBasic";
@ -16,7 +16,7 @@ export default function SettingsKeyboardRoute() {
state => state.setKeyboardLayout, state => state.setKeyboardLayout,
); );
const layoutOptions = Object.entries(layouts).map(([code, language]) => { return { value: code, label: language } }) const layoutOptions = keyboardOptions();
const [send] = useJsonRpc(); const [send] = useJsonRpc();