From 5f1e53f24a8d00e5bfab79f074b0bd678b0b89c6 Mon Sep 17 00:00:00 2001 From: William Johnstone Date: Mon, 3 Feb 2025 00:39:53 +0000 Subject: [PATCH] Fully implemented layout setting and switching in the UI. Updated PasteModal to add more clarity to error message. Begin working on key remapping in WebRTC (working to a reasonable degree). --- dev_deploy.sh | 1 + ui/src/components/WebRTCVideo.tsx | 68 ++++++++++++++++++--- ui/src/components/popovers/PasteModal.tsx | 2 +- ui/src/keyboardMappings/layouts/uk_apple.ts | 2 +- ui/src/keyboardMappings/layouts/us.ts | 2 +- 5 files changed, 65 insertions(+), 10 deletions(-) diff --git a/dev_deploy.sh b/dev_deploy.sh index a106395..72bb6dd 100755 --- a/dev_deploy.sh +++ b/dev_deploy.sh @@ -71,6 +71,7 @@ export LD_LIBRARY_PATH=/oem/usr/lib:\$LD_LIBRARY_PATH # Kill any existing instances of the application killall jetkvm_app || true killall jetkvm_app_debug || true +killall jetkvm_native || true # Navigate to the directory where the binary will be stored cd "$REMOTE_PATH" diff --git a/ui/src/components/WebRTCVideo.tsx b/ui/src/components/WebRTCVideo.tsx index 61b1f9a..9b16045 100644 --- a/ui/src/components/WebRTCVideo.tsx +++ b/ui/src/components/WebRTCVideo.tsx @@ -19,11 +19,17 @@ import { ConnectionErrorOverlay, HDMIErrorOverlay, LoadingOverlay } from "./Vide export default function WebRTCVideo() { const [keys, setKeys] = useState(useKeyboardMappingsStore.keys); + const [chars, setChars] = useState(useKeyboardMappingsStore.chars); const [modifiers, setModifiers] = useState(useKeyboardMappingsStore.modifiers); + // TODO move this into stores as well as I think this will need to be used in InfoBar + // This map is used to maintain consistency between localised key mappings + const activeKeyState = useRef>(new Map()); + useEffect(() => { const unsubscribeKeyboardStore = useKeyboardMappingsStore.subscribe(() => { - setKeys(useKeyboardMappingsStore.keys); + setKeys(useKeyboardMappingsStore.keys); + setChars(useKeyboardMappingsStore.chars); setModifiers(useKeyboardMappingsStore.modifiers); }); return unsubscribeKeyboardStore; // Cleanup on unmount @@ -217,9 +223,9 @@ export default function WebRTCVideo() { e.preventDefault(); const prev = useHidStore.getState(); let code = e.code; - const key = e.key; + const localisedKey = e.key; console.log(e); - console.log(key); + console.log("Localised Key: " + localisedKey); // if (document.activeElement?.id !== "videoFocusTrap") {hH // console.log("KEYUP: Not focusing on the video", document.activeElement); @@ -232,25 +238,42 @@ export default function WebRTCVideo() { setIsCapsLockActive(e.getModifierState("CapsLock")); setIsScrollLockActive(e.getModifierState("ScrollLock")); - if (code == "IntlBackslash" && ["`", "~"].includes(key)) { + /*if (code == "IntlBackslash" && ["`", "~"].includes(key)) { code = "Backquote"; } else if (code == "Backquote" && ["§", "±"].includes(key)) { code = "IntlBackslash"; - } + }*/ + + const { key: mappedKey, shift, altLeft, altRight } = chars[localisedKey] ?? { key: e.code }; + //if (!key) continue; + console.log("Mapped Key: " + mappedKey) + console.log("Current KB Layout:" + useKeyboardMappingsStore.getLayout()); + + // Build the modifier bitmask + const modifier = + (shift ? modifiers["ShiftLeft"] : 0) | + (altLeft ? modifiers["AltLeft"] : 0) | + (altRight ? modifiers["AltRight"] : 0); // This is important for a lot of keyboard layouts, right and left alt have different functions + + // Add the mapped key to keyState + activeKeyState.current.set(e.code, { mappedKey, modifiers: modifier }); + console.log(activeKeyState) // Add the key to the active keys - const newKeys = [...prev.activeKeys, keys[code]].filter(Boolean); + const newKeys = [...prev.activeKeys, keys[mappedKey]].filter(Boolean); // Add the modifier to the active modifiers const newModifiers = handleModifierKeys(e, [ ...prev.activeModifiers, modifiers[code], + modifier, //Is this bad, will we have duplicate modifiers? ]); // When pressing the meta key + another key, the key will never trigger a keyup // event, so we need to clear the keys after a short delay // https://bugs.chromium.org/p/chromium/issues/detail?id=28089 // https://bugzilla.mozilla.org/show_bug.cgi?id=1299553 + // TODO add this to the activekey state if (e.metaKey) { setTimeout(() => { const prev = useHidStore.getState(); @@ -283,14 +306,44 @@ export default function WebRTCVideo() { setIsCapsLockActive(e.getModifierState("CapsLock")); setIsScrollLockActive(e.getModifierState("ScrollLock")); + // Retrieve the mapped key and modifiers from keyState + const keyInfo = activeKeyState.current.get(e.code); + if (!keyInfo) return; // Ignore if no record exists + + const { mappedKey, modifiers: modifier } = keyInfo; + + // Remove the key from keyState + activeKeyState.current.delete(e.code); + + // Filter out the key that was just released + const newKeys = prev.activeKeys.filter(k => k !== keys[mappedKey]).filter(Boolean); + console.log(activeKeyState) + + // Filter out the associated modifier + //const newModifiers = prev.activeModifiers.filter(k => k !== modifier).filter(Boolean); + const newModifiers = handleModifierKeys( + e, + prev.activeModifiers.filter(k => k !== modifier), + ); + /* + const { key: mappedKey/*, shift, altLeft, altRight*//* } = chars[e.key] ?? { key: e.code }; + //if (!key) continue; + console.log("Mapped Key: " + mappedKey) + // Build the modifier bitmask + /*const modifier = + (shift ? modifiers["ShiftLeft"] : 0) | + (altLeft ? modifiers["AltLeft"] : 0) | + (altRight ? modifiers["AltRight"] : 0); // This is important for a lot of keyboard layouts, right and left alt have different functions*//* + // Filtering out the key that was just released (keys[e.code]) - const newKeys = prev.activeKeys.filter(k => k !== keys[e.code]).filter(Boolean); + const newKeys = prev.activeKeys.filter(k => k !== keys[mappedKey]).filter(Boolean); // Filter out the modifier that was just released const newModifiers = handleModifierKeys( e, prev.activeModifiers.filter(k => k !== modifiers[e.code]), ); + */ console.log(e.key); sendKeyboardEvent([...new Set(newKeys)], [...new Set(newModifiers)]); @@ -321,6 +374,7 @@ export default function WebRTCVideo() { return () => { abortController.abort(); + activeKeyState.current.clear(); }; }, [keyDownHandler, keyUpHandler, resetKeyboardState, sendKeyboardEvent], diff --git a/ui/src/components/popovers/PasteModal.tsx b/ui/src/components/popovers/PasteModal.tsx index 2387888..9728cb8 100644 --- a/ui/src/components/popovers/PasteModal.tsx +++ b/ui/src/components/popovers/PasteModal.tsx @@ -141,7 +141,7 @@ export default function PasteModal() {
- The following characters won't be pasted:{" "} + The following characters won't be pasted as the current keyboard layout does not contain a valid mapping:{" "} {invalidChars.join(", ")}
diff --git a/ui/src/keyboardMappings/layouts/uk_apple.ts b/ui/src/keyboardMappings/layouts/uk_apple.ts index d257f43..24d974e 100644 --- a/ui/src/keyboardMappings/layouts/uk_apple.ts +++ b/ui/src/keyboardMappings/layouts/uk_apple.ts @@ -16,7 +16,7 @@ export const charsUKApple = { "£": { key: "Digit3", shift: true }, "@": { key: "Digit2", shift: true }, "\"": { key: "Quote", shift: true }, -} as Record; +} as Record; // Modifiers are typically the same between UK and US layouts export const modifiersUKApple = { diff --git a/ui/src/keyboardMappings/layouts/us.ts b/ui/src/keyboardMappings/layouts/us.ts index 15a0071..a5395c2 100644 --- a/ui/src/keyboardMappings/layouts/us.ts +++ b/ui/src/keyboardMappings/layouts/us.ts @@ -200,7 +200,7 @@ export const charsUS = { "\n": { key: "Enter", shift: false }, Enter: { key: "Enter", shift: false }, Tab: { key: "Tab", shift: false }, -} as Record; +} as Record; export const modifiersUS = { ControlLeft: 0x01,