From 1b5062c504bd8db351dc91fe62ad3bbee40cfaa2 Mon Sep 17 00:00:00 2001 From: Marc Brooks Date: Fri, 23 May 2025 06:21:53 -0500 Subject: [PATCH 1/2] fix(ui): Default the keyboardLayout to en-US if not set (#512) The recent fix to PasteModal will silently fail a paste if the keyboardLayout hasn't been selected in the settings yet, then when you look in Settings it looks like it's set to Belgian, but it's really just blank. Set it to default to en-US in both these places so it works like it did previously. Fixes #492 --- ui/src/components/popovers/PasteModal.tsx | 42 +++++++++++-------- .../routes/devices.$id.settings.keyboard.tsx | 11 ++++- 2 files changed, 33 insertions(+), 20 deletions(-) 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} /> From 7e64a529f89364a732b9f76c44949bbb7d52bf76 Mon Sep 17 00:00:00 2001 From: Alex Goodkind Date: Fri, 23 May 2025 05:38:15 -0700 Subject: [PATCH 2/2] chore: add VSCode extensions for improved development environment (#509) --- .devcontainer/devcontainer.json | 15 ++++++++++++++- .vscode/settings.json | 3 +++ 2 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 .vscode/settings.json diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 7da2970..aa803f6 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -9,6 +9,19 @@ }, "mounts": [ "source=${localEnv:HOME}/.ssh,target=/home/vscode/.ssh,type=bind,consistency=cached" - ] + ], + "customizations": { + "vscode": { + "extensions": [ + "bradlc.vscode-tailwindcss", + "GitHub.vscode-pull-request-github", + "dbaeumer.vscode-eslint", + "golang.go", + "ms-vscode.makefile-tools", + "esbenp.prettier-vscode", + "github.vscode-github-actions" + ] + } + } } diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..de91a5d --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "tailwindCSS.classFunctions": ["cva", "cx"] +} \ No newline at end of file