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
This commit is contained in:
Marc Brooks 2025-05-23 06:21:53 -05:00 committed by Siyuan Miao
parent 0cee284561
commit 188195b7f6
2 changed files with 33 additions and 20 deletions

View File

@ -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 { LuCornerDownLeft } from "react-icons/lu";
import { ExclamationCircleIcon } from "@heroicons/react/16/solid"; import { ExclamationCircleIcon } from "@heroicons/react/16/solid";
import { useClose } from "@headlessui/react"; import { useClose } from "@headlessui/react";
@ -39,6 +39,13 @@ export default function PasteModal() {
state => state.setKeyboardLayout, 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(() => { useEffect(() => {
send("getKeyboardLayout", {}, resp => { send("getKeyboardLayout", {}, resp => {
if ("error" in resp) return; if ("error" in resp) return;
@ -56,14 +63,13 @@ export default function PasteModal() {
setPasteMode(false); setPasteMode(false);
setDisableVideoFocusTrap(false); setDisableVideoFocusTrap(false);
if (rpcDataChannel?.readyState !== "open" || !TextAreaRef.current) return; if (rpcDataChannel?.readyState !== "open" || !TextAreaRef.current) return;
if (!keyboardLayout) return; if (!safeKeyboardLayout) return;
if (!chars[keyboardLayout]) return; if (!chars[safeKeyboardLayout]) 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 { key, shift, altRight, deadKey, accentKey } = chars[safeKeyboardLayout][char]
if (!key) continue; if (!key) continue;
const keyz = [ keys[key] ]; const keyz = [ keys[key] ];
@ -98,7 +104,7 @@ export default function PasteModal() {
console.error(error); console.error(error);
notifications.error("Failed to paste text"); notifications.error("Failed to paste text");
} }
}, [rpcDataChannel?.readyState, send, setDisableVideoFocusTrap, setPasteMode, keyboardLayout]); }, [rpcDataChannel?.readyState, send, setDisableVideoFocusTrap, setPasteMode, safeKeyboardLayout]);
useEffect(() => { useEffect(() => {
if (TextAreaRef.current) { if (TextAreaRef.current) {
@ -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 => !chars[safeKeyboardLayout][char]),
), ),
]; ];
@ -169,7 +175,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: {layouts[keyboardLayout]} Sending text using keyboard layout: {layouts[safeKeyboardLayout]}
</p> </p>
</div> </div>
</div> </div>

View File

@ -1,4 +1,4 @@
import { useCallback, useEffect } from "react"; import { useCallback, useEffect, useMemo } from "react";
import { useSettingsStore } from "@/hooks/stores"; import { useSettingsStore } from "@/hooks/stores";
import { useJsonRpc } from "@/hooks/useJsonRpc"; import { useJsonRpc } from "@/hooks/useJsonRpc";
@ -16,6 +16,13 @@ export default function SettingsKeyboardRoute() {
state => state.setKeyboardLayout, 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]);
const layoutOptions = Object.entries(layouts).map(([code, language]) => { return { value: code, label: language } }) const layoutOptions = Object.entries(layouts).map(([code, language]) => { return { value: code, label: language } })
const [send] = useJsonRpc(); const [send] = useJsonRpc();
@ -60,7 +67,7 @@ export default function SettingsKeyboardRoute() {
size="SM" size="SM"
label="" label=""
fullWidth fullWidth
value={keyboardLayout} value={safeKeyboardLayout}
onChange={onKeyboardLayoutChange} onChange={onKeyboardLayoutChange}
options={layoutOptions} options={layoutOptions}
/> />