diff --git a/ui/src/components/popovers/PasteModal.tsx b/ui/src/components/popovers/PasteModal.tsx index 26e4b82..70b3067 100644 --- a/ui/src/components/popovers/PasteModal.tsx +++ b/ui/src/components/popovers/PasteModal.tsx @@ -1,4 +1,4 @@ -import { useCallback, useEffect, useRef, useState } from "react"; +import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import { LuCornerDownLeft } from "react-icons/lu"; import { ExclamationCircleIcon } from "@heroicons/react/16/solid"; import { useClose } from "@headlessui/react"; @@ -39,6 +39,13 @@ export default function PasteModal() { state => state.setKeyboardLayout, ); + // this ensures we always get the original en-US if it hasn't been set yet + const safeKeyboardLayout = useMemo(() => { + if (keyboardLayout && keyboardLayout.length > 0) + return keyboardLayout; + return "en-US"; + }, [keyboardLayout]); + useEffect(() => { send("getKeyboardLayout", {}, resp => { if ("error" in resp) return; @@ -56,29 +63,28 @@ export default function PasteModal() { setPasteMode(false); setDisableVideoFocusTrap(false); if (rpcDataChannel?.readyState !== "open" || !TextAreaRef.current) return; - if (!keyboardLayout) return; - if (!chars[keyboardLayout]) return; - + if (!safeKeyboardLayout) return; + if (!chars[safeKeyboardLayout]) return; const text = TextAreaRef.current.value; try { for (const char of text) { - const { key, shift, altRight, deadKey, accentKey } = chars[keyboardLayout][char] + const { key, shift, altRight, deadKey, accentKey } = chars[safeKeyboardLayout][char] if (!key) continue; - const keyz = [ keys[key] ]; - const modz = [ modifierCode(shift, altRight) ]; + const keyz = [ keys[key] ]; + const modz = [ modifierCode(shift, altRight) ]; - if (deadKey) { + if (deadKey) { keyz.push(keys["Space"]); modz.push(noModifier); - } - if (accentKey) { + } + if (accentKey) { keyz.unshift(keys[accentKey.key]) modz.unshift(modifierCode(accentKey.shift, accentKey.altRight)) - } + } - for (const [index, kei] of keyz.entries()) { + for (const [index, kei] of keyz.entries()) { await new Promise((resolve, reject) => { send( "keyboardReport", @@ -92,13 +98,13 @@ export default function PasteModal() { }, ); }); - } + } } } catch (error) { console.error(error); notifications.error("Failed to paste text"); } - }, [rpcDataChannel?.readyState, send, setDisableVideoFocusTrap, setPasteMode, keyboardLayout]); + }, [rpcDataChannel?.readyState, send, setDisableVideoFocusTrap, setPasteMode, safeKeyboardLayout]); useEffect(() => { if (TextAreaRef.current) { @@ -148,7 +154,7 @@ export default function PasteModal() { // @ts-expect-error TS doesn't recognize Intl.Segmenter in some environments [...new Intl.Segmenter().segment(value)] .map(x => x.segment) - .filter(char => !chars[keyboardLayout][char]), + .filter(char => !chars[safeKeyboardLayout][char]), ), ]; @@ -167,11 +173,11 @@ export default function PasteModal() { )} -
+

- Sending text using keyboard layout: {layouts[keyboardLayout]} + Sending text using keyboard layout: {layouts[safeKeyboardLayout]}

-
+
diff --git a/ui/src/routes/devices.$id.settings.keyboard.tsx b/ui/src/routes/devices.$id.settings.keyboard.tsx index 8849e61..0f266e9 100644 --- a/ui/src/routes/devices.$id.settings.keyboard.tsx +++ b/ui/src/routes/devices.$id.settings.keyboard.tsx @@ -1,4 +1,4 @@ -import { useCallback, useEffect } from "react"; +import { useCallback, useEffect, useMemo } from "react"; import { KeyboardLedSync, useSettingsStore } from "@/hooks/stores"; import { useJsonRpc } from "@/hooks/useJsonRpc"; @@ -20,6 +20,13 @@ export default function SettingsKeyboardRoute() { state => state.setKeyboardLedSync, ); + // this ensures we always get the original en-US if it hasn't been set yet + const safeKeyboardLayout = useMemo(() => { + if (keyboardLayout && keyboardLayout.length > 0) + return keyboardLayout; + return "en-US"; + }, [keyboardLayout]); + const layoutOptions = Object.entries(layouts).map(([code, language]) => { return { value: code, label: language } }) const ledSyncOptions = [ { value: "auto", label: "Automatic" }, @@ -69,7 +76,7 @@ export default function SettingsKeyboardRoute() { size="SM" label="" fullWidth - value={keyboardLayout} + value={safeKeyboardLayout} onChange={onKeyboardLayoutChange} options={layoutOptions} />