mirror of https://github.com/jetkvm/kvm.git
Move keyboardmapping store to stores.ts, simplified some things, updated settings.tsx to set the keyboard layout properly.
This commit is contained in:
parent
0e855adc35
commit
7c40e2e011
|
@ -5,18 +5,18 @@ import {
|
|||
useRTCStore,
|
||||
useSettingsStore,
|
||||
useVideoStore,
|
||||
useKeyboardMappingsStore,
|
||||
} from "@/hooks/stores";
|
||||
import { useEffect, useState } from "react";
|
||||
import { keyboardMappingsStore } from "@/keyboardMappings/KeyboardMappingStore";
|
||||
|
||||
export default function InfoBar() {
|
||||
const [keys, setKeys] = useState(keyboardMappingsStore.keys);
|
||||
const [modifiers, setModifiers] = useState(keyboardMappingsStore.modifiers);
|
||||
const [keys, setKeys] = useState(useKeyboardMappingsStore.keys);
|
||||
const [modifiers, setModifiers] = useState(useKeyboardMappingsStore.modifiers);
|
||||
|
||||
useEffect(() => {
|
||||
const unsubscribeKeyboardStore = keyboardMappingsStore.subscribe(() => {
|
||||
setKeys(keyboardMappingsStore.keys);
|
||||
setModifiers(keyboardMappingsStore.modifiers);
|
||||
const unsubscribeKeyboardStore = useKeyboardMappingsStore.subscribe(() => {
|
||||
setKeys(useKeyboardMappingsStore.keys);
|
||||
setModifiers(useKeyboardMappingsStore.modifiers);
|
||||
});
|
||||
return unsubscribeKeyboardStore; // Cleanup on unmount
|
||||
}, []);
|
||||
|
|
|
@ -4,11 +4,9 @@ import { Button } from "@components/Button";
|
|||
import Card from "@components/Card";
|
||||
import { ChevronDownIcon } from "@heroicons/react/16/solid";
|
||||
import "react-simple-keyboard/build/css/index.css";
|
||||
import { useHidStore, useUiStore } from "@/hooks/stores";
|
||||
import { useHidStore, useUiStore, useKeyboardMappingsStore } from "@/hooks/stores";
|
||||
import { Transition } from "@headlessui/react";
|
||||
import { cx } from "@/cva.config";
|
||||
//import { keys, modifiers } from "@/keyboardMappings/KeyboardMappingStore";
|
||||
import { keyboardMappingsStore } from "@/keyboardMappings/KeyboardMappingStore";
|
||||
import useKeyboard from "@/hooks/useKeyboard";
|
||||
import DetachIconRaw from "@/assets/detach-icon.svg";
|
||||
import AttachIconRaw from "@/assets/attach-icon.svg";
|
||||
|
@ -22,13 +20,13 @@ const AttachIcon = ({ className }: { className?: string }) => {
|
|||
};
|
||||
|
||||
function KeyboardWrapper() {
|
||||
const [keys, setKeys] = useState(keyboardMappingsStore.keys);
|
||||
const [modifiers, setModifiers] = useState(keyboardMappingsStore.modifiers);
|
||||
const [keys, setKeys] = useState(useKeyboardMappingsStore.keys);
|
||||
const [modifiers, setModifiers] = useState(useKeyboardMappingsStore.modifiers);
|
||||
|
||||
useEffect(() => {
|
||||
const unsubscribeKeyboardStore = keyboardMappingsStore.subscribe(() => {
|
||||
setKeys(keyboardMappingsStore.keys);
|
||||
setModifiers(keyboardMappingsStore.modifiers);
|
||||
const unsubscribeKeyboardStore = useKeyboardMappingsStore.subscribe(() => {
|
||||
setKeys(useKeyboardMappingsStore.keys);
|
||||
setModifiers(useKeyboardMappingsStore.modifiers);
|
||||
});
|
||||
return unsubscribeKeyboardStore; // Cleanup on unmount
|
||||
}, []);
|
||||
|
|
|
@ -6,8 +6,8 @@ import {
|
|||
useSettingsStore,
|
||||
useUiStore,
|
||||
useVideoStore,
|
||||
useKeyboardMappingsStore,
|
||||
} from "@/hooks/stores";
|
||||
import { keyboardMappingsStore } from "@/keyboardMappings/KeyboardMappingStore";
|
||||
import { useResizeObserver } from "@/hooks/useResizeObserver";
|
||||
import { cx } from "@/cva.config";
|
||||
import VirtualKeyboard from "@components/VirtualKeyboard";
|
||||
|
@ -18,13 +18,13 @@ import { useJsonRpc } from "@/hooks/useJsonRpc";
|
|||
import { ConnectionErrorOverlay, HDMIErrorOverlay, LoadingOverlay } from "./VideoOverlay";
|
||||
|
||||
export default function WebRTCVideo() {
|
||||
const [keys, setKeys] = useState(keyboardMappingsStore.keys);
|
||||
const [modifiers, setModifiers] = useState(keyboardMappingsStore.modifiers);
|
||||
const [keys, setKeys] = useState(useKeyboardMappingsStore.keys);
|
||||
const [modifiers, setModifiers] = useState(useKeyboardMappingsStore.modifiers);
|
||||
|
||||
useEffect(() => {
|
||||
const unsubscribeKeyboardStore = keyboardMappingsStore.subscribe(() => {
|
||||
setKeys(keyboardMappingsStore.keys);
|
||||
setModifiers(keyboardMappingsStore.modifiers);
|
||||
const unsubscribeKeyboardStore = useKeyboardMappingsStore.subscribe(() => {
|
||||
setKeys(useKeyboardMappingsStore.keys);
|
||||
setModifiers(useKeyboardMappingsStore.modifiers);
|
||||
});
|
||||
return unsubscribeKeyboardStore; // Cleanup on unmount
|
||||
}, []);
|
||||
|
@ -218,12 +218,15 @@ export default function WebRTCVideo() {
|
|||
const prev = useHidStore.getState();
|
||||
let code = e.code;
|
||||
const key = e.key;
|
||||
console.log(e);
|
||||
console.log(key);
|
||||
|
||||
// if (document.activeElement?.id !== "videoFocusTrap") {
|
||||
// if (document.activeElement?.id !== "videoFocusTrap") {hH
|
||||
// console.log("KEYUP: Not focusing on the video", document.activeElement);
|
||||
// return;
|
||||
// }
|
||||
console.log(document.activeElement);
|
||||
//
|
||||
// console.log(document.activeElement);
|
||||
|
||||
setIsNumLockActive(e.getModifierState("NumLock"));
|
||||
setIsCapsLockActive(e.getModifierState("CapsLock"));
|
||||
|
@ -289,6 +292,7 @@ export default function WebRTCVideo() {
|
|||
prev.activeModifiers.filter(k => k !== modifiers[e.code]),
|
||||
);
|
||||
|
||||
console.log(e.key);
|
||||
sendKeyboardEvent([...new Set(newKeys)], [...new Set(newModifiers)]);
|
||||
},
|
||||
[
|
||||
|
|
|
@ -3,28 +3,27 @@ import { GridCard } from "@components/Card";
|
|||
import { TextAreaWithLabel } from "@components/TextArea";
|
||||
import { SectionHeader } from "@components/SectionHeader";
|
||||
import { useJsonRpc } from "@/hooks/useJsonRpc";
|
||||
import { useHidStore, useRTCStore, useUiStore } from "@/hooks/stores";
|
||||
import { useHidStore, useRTCStore, useUiStore, useKeyboardMappingsStore } from "@/hooks/stores";
|
||||
import notifications from "../../notifications";
|
||||
import { useCallback, useEffect, useRef, useState } from "react";
|
||||
import { LuCornerDownLeft } from "react-icons/lu";
|
||||
import { ExclamationCircleIcon } from "@heroicons/react/16/solid";
|
||||
import { useClose } from "@headlessui/react";
|
||||
import { keyboardMappingsStore } from "@/keyboardMappings/KeyboardMappingStore";
|
||||
|
||||
const hidKeyboardPayload = (keys: number[], modifier: number) => {
|
||||
return { keys, modifier };
|
||||
};
|
||||
|
||||
export default function PasteModal() {
|
||||
const [keys, setKeys] = useState(keyboardMappingsStore.keys);
|
||||
const [chars, setChars] = useState(keyboardMappingsStore.chars);
|
||||
const [modifiers, setModifiers] = useState(keyboardMappingsStore.modifiers);
|
||||
const [keys, setKeys] = useState(useKeyboardMappingsStore.keys);
|
||||
const [chars, setChars] = useState(useKeyboardMappingsStore.chars);
|
||||
const [modifiers, setModifiers] = useState(useKeyboardMappingsStore.modifiers);
|
||||
|
||||
useEffect(() => {
|
||||
const unsubscribeKeyboardStore = keyboardMappingsStore.subscribe(() => {
|
||||
setKeys(keyboardMappingsStore.keys);
|
||||
setChars(keyboardMappingsStore.chars);
|
||||
setModifiers(keyboardMappingsStore.modifiers);
|
||||
const unsubscribeKeyboardStore = useKeyboardMappingsStore.subscribe(() => {
|
||||
setKeys(useKeyboardMappingsStore.keys);
|
||||
setChars(useKeyboardMappingsStore.chars);
|
||||
setModifiers(useKeyboardMappingsStore.modifiers);
|
||||
});
|
||||
return unsubscribeKeyboardStore; // Cleanup on unmount
|
||||
}, []);
|
||||
|
@ -54,13 +53,14 @@ export default function PasteModal() {
|
|||
|
||||
try {
|
||||
for (const char of text) {
|
||||
const { key, shift, alt } = chars[char] ?? {};
|
||||
const { key, shift, altLeft, altRight } = chars[char] ?? {};
|
||||
if (!key) continue;
|
||||
|
||||
// Build the modifier bitmask
|
||||
const modifier =
|
||||
(shift ? modifiers["ShiftLeft"] : 0) |
|
||||
(alt ? modifiers["AltLeft"] : 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
|
||||
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
send(
|
||||
|
|
|
@ -4,6 +4,7 @@ import {
|
|||
useSettingsStore,
|
||||
useUiStore,
|
||||
useUpdateStore,
|
||||
useKeyboardMappingsStore,
|
||||
} from "@/hooks/stores";
|
||||
import { Checkbox } from "@components/Checkbox";
|
||||
import { Button, LinkButton } from "@components/Button";
|
||||
|
@ -25,8 +26,6 @@ import LocalAuthPasswordDialog from "@/components/LocalAuthPasswordDialog";
|
|||
import { LocalDevice } from "@routes/devices.$id";
|
||||
import { useRevalidator } from "react-router-dom";
|
||||
import { ShieldCheckIcon } from "@heroicons/react/20/solid";
|
||||
import { keyboardMappingsStore } from "@/keyboardMappings/KeyboardMappingStore";
|
||||
import { KeyboardLayout } from "@/keyboardMappings/KeyboardLayouts";
|
||||
|
||||
export function SettingsItem({
|
||||
title,
|
||||
|
@ -157,8 +156,7 @@ export default function SettingsSidebar() {
|
|||
);
|
||||
return;
|
||||
}
|
||||
// TODO set this to update to the actual layout chosen
|
||||
keyboardMappingsStore.setLayout(KeyboardLayout.UKApple)
|
||||
useKeyboardMappingsStore.setLayout(keyboardLayout)
|
||||
setKeyboardLayout(keyboardLayout);
|
||||
});
|
||||
};
|
||||
|
@ -294,6 +292,7 @@ export default function SettingsSidebar() {
|
|||
send("getKeyboardLayout", {}, resp => {
|
||||
if ("error" in resp) return;
|
||||
setKeyboardLayout(String(resp.result));
|
||||
useKeyboardMappingsStore.setLayout(String(resp.result))
|
||||
});
|
||||
|
||||
send("getStreamQualityFactor", {}, resp => {
|
||||
|
@ -545,7 +544,7 @@ export default function SettingsSidebar() {
|
|||
size="SM"
|
||||
label=""
|
||||
// TODO figure out how to make this selector wider like the EDID one?
|
||||
//fullWidth
|
||||
//fullWidthƒ
|
||||
value={keyboardLayout}
|
||||
options={[
|
||||
{ value: "uk", label: "GB" },
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { create } from "zustand";
|
||||
import { createJSONStorage, persist } from "zustand/middleware";
|
||||
import { getKeyboardMappings } from "@/keyboardMappings/KeyboardLayouts";
|
||||
|
||||
// Utility function to append stats to a Map
|
||||
const appendStatToMap = <T extends { timestamp: number }>(
|
||||
|
@ -528,3 +529,39 @@ export const useLocalAuthModalStore = create<LocalAuthModalState>(set => ({
|
|||
setModalView: view => set({ modalView: view }),
|
||||
setErrorMessage: message => set({ errorMessage: message }),
|
||||
}));
|
||||
|
||||
class KeyboardMappingsStore {
|
||||
private _layout: string = 'us';
|
||||
private _subscribers: (() => void)[] = [];
|
||||
|
||||
public keys = getKeyboardMappings(this._layout).keys;
|
||||
public chars = getKeyboardMappings(this._layout).chars;
|
||||
public modifiers = getKeyboardMappings(this._layout).modifiers;
|
||||
|
||||
setLayout(newLayout: string) {
|
||||
if (this._layout === newLayout) return;
|
||||
this._layout = newLayout;
|
||||
const updatedMappings = getKeyboardMappings(newLayout);
|
||||
this.keys = updatedMappings.keys;
|
||||
this.chars = updatedMappings.chars;
|
||||
this.modifiers = updatedMappings.modifiers;
|
||||
this._notifySubscribers();
|
||||
}
|
||||
|
||||
getLayout() {
|
||||
return this._layout;
|
||||
}
|
||||
|
||||
subscribe(callback: () => void) {
|
||||
this._subscribers.push(callback);
|
||||
return () => {
|
||||
this._subscribers = this._subscribers.filter(sub => sub !== callback); // Cleanup
|
||||
};
|
||||
}
|
||||
|
||||
private _notifySubscribers() {
|
||||
this._subscribers.forEach(callback => callback());
|
||||
}
|
||||
}
|
||||
|
||||
export const useKeyboardMappingsStore = new KeyboardMappingsStore();
|
|
@ -1,20 +1,15 @@
|
|||
import {keysUKApple, charsUKApple, modifiersUKApple } from './layouts/uk_apple';
|
||||
import {keysUS, charsUS, modifiersUS } from './layouts/us';
|
||||
|
||||
export enum KeyboardLayout {
|
||||
US = "us",
|
||||
UKApple = "uk_apple",
|
||||
}
|
||||
|
||||
export function getKeyboardMappings(layout: KeyboardLayout) {
|
||||
switch (layout) {
|
||||
case KeyboardLayout.UKApple:
|
||||
return {
|
||||
keys: keysUKApple,
|
||||
chars: charsUKApple,
|
||||
modifiers: modifiersUKApple,
|
||||
};
|
||||
case KeyboardLayout.US:
|
||||
export function getKeyboardMappings(layout: string) {
|
||||
switch (layout) {
|
||||
case "uk_apple":
|
||||
return {
|
||||
keys: keysUKApple,
|
||||
chars: charsUKApple,
|
||||
modifiers: modifiersUKApple,
|
||||
};
|
||||
case "us":
|
||||
default:
|
||||
return {
|
||||
keys: keysUS,
|
||||
|
@ -22,4 +17,4 @@ export function getKeyboardMappings(layout: KeyboardLayout) {
|
|||
modifiers: modifiersUS,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
import { getKeyboardMappings, KeyboardLayout } from "@/keyboardMappings/KeyboardLayouts";
|
||||
|
||||
// TODO Move this in with all the other stores?
|
||||
|
||||
class KeyboardMappingsStore {
|
||||
private _layout: KeyboardLayout = KeyboardLayout.US;
|
||||
private _subscribers: (() => void)[] = [];
|
||||
|
||||
public keys = getKeyboardMappings(this._layout).keys;
|
||||
public chars = getKeyboardMappings(this._layout).chars;
|
||||
public modifiers = getKeyboardMappings(this._layout).modifiers;
|
||||
|
||||
setLayout(newLayout: KeyboardLayout) {
|
||||
if (this._layout === newLayout) return;
|
||||
this._layout = newLayout;
|
||||
const updatedMappings = getKeyboardMappings(newLayout);
|
||||
this.keys = updatedMappings.keys;
|
||||
this.chars = updatedMappings.chars;
|
||||
this.modifiers = updatedMappings.modifiers;
|
||||
this._notifySubscribers();
|
||||
}
|
||||
|
||||
getLayout() {
|
||||
return this._layout;
|
||||
}
|
||||
|
||||
subscribe(callback: () => void) {
|
||||
this._subscribers.push(callback);
|
||||
return () => {
|
||||
this._subscribers = this._subscribers.filter(sub => sub !== callback); // Cleanup
|
||||
};
|
||||
}
|
||||
|
||||
private _notifySubscribers() {
|
||||
this._subscribers.forEach(callback => callback());
|
||||
}
|
||||
}
|
||||
|
||||
export const keyboardMappingsStore = new KeyboardMappingsStore();
|
|
@ -12,11 +12,11 @@ export const charsUKApple = {
|
|||
"~": { key: "Backquote", shift: true },
|
||||
"\\" : { key: "Backslash", shift: false },
|
||||
"|": { key: "Backslash", shift: true },
|
||||
"#": { key: "Digit3", shift: false, alt: true },
|
||||
"#": { key: "Digit3", shift: false, altLeft: true },
|
||||
"£": { key: "Digit3", shift: true },
|
||||
"@": { key: "Digit2", shift: true },
|
||||
"\"": { key: "Quote", shift: true },
|
||||
} as Record<string, { key: string | number; shift: boolean; alt?: boolean; }>;
|
||||
} as Record<string, { key: string | number; shift: boolean; altLeft?: boolean; altRight?: boolean; }>;
|
||||
|
||||
// Modifiers are typically the same between UK and US layouts
|
||||
export const modifiersUKApple = {
|
||||
|
|
|
@ -200,8 +200,8 @@ export const charsUS = {
|
|||
"\n": { key: "Enter", shift: false },
|
||||
Enter: { key: "Enter", shift: false },
|
||||
Tab: { key: "Tab", shift: false },
|
||||
} as Record<string, { key: string | number; shift: boolean; alt?: boolean; }>;
|
||||
|
||||
} as Record<string, { key: string | number; shift: boolean; altLeft?: boolean; altRight?: boolean; }>;
|
||||
|
||||
export const modifiersUS = {
|
||||
ControlLeft: 0x01,
|
||||
ControlRight: 0x10,
|
||||
|
|
Loading…
Reference in New Issue