From 40b1c70be030c1a155eea3945b12c49a26782842 Mon Sep 17 00:00:00 2001 From: William Johnstone Date: Tue, 25 Feb 2025 00:44:17 +0000 Subject: [PATCH] Added German (T1) mappings, UK mappings, updated UK apple mappings. Added functionality to disable keyboard mapping. --- config.go | 30 +++--- jsonrpc.go | 108 +++++++++++--------- ui/src/components/SelectMenuBasic.tsx | 1 + ui/src/components/WebRTCVideo.tsx | 25 +++-- ui/src/components/popovers/PasteModal.tsx | 5 +- ui/src/components/sidebar/settings.tsx | 44 +++++++- ui/src/hooks/stores.ts | 36 ++++++- ui/src/keyboardMappings/KeyboardLayouts.ts | 14 +++ ui/src/keyboardMappings/layouts/de_t1.ts | 69 +++++++++++++ ui/src/keyboardMappings/layouts/uk.ts | 24 +++++ ui/src/keyboardMappings/layouts/uk_apple.ts | 1 + 11 files changed, 279 insertions(+), 78 deletions(-) create mode 100644 ui/src/keyboardMappings/layouts/de_t1.ts diff --git a/config.go b/config.go index 3ae4066..eb707c5 100644 --- a/config.go +++ b/config.go @@ -12,25 +12,27 @@ type WakeOnLanDevice struct { } type Config struct { - CloudURL string `json:"cloud_url"` - CloudToken string `json:"cloud_token"` - GoogleIdentity string `json:"google_identity"` - JigglerEnabled bool `json:"jiggler_enabled"` - AutoUpdateEnabled bool `json:"auto_update_enabled"` - KeyboardLayout string `json:"keyboard_layout"` - IncludePreRelease bool `json:"include_pre_release"` - HashedPassword string `json:"hashed_password"` - LocalAuthToken string `json:"local_auth_token"` - LocalAuthMode string `json:"localAuthMode"` //TODO: fix it with migration - WakeOnLanDevices []WakeOnLanDevice `json:"wake_on_lan_devices"` + CloudURL string `json:"cloud_url"` + CloudToken string `json:"cloud_token"` + GoogleIdentity string `json:"google_identity"` + JigglerEnabled bool `json:"jiggler_enabled"` + AutoUpdateEnabled bool `json:"auto_update_enabled"` + KeyboardLayout string `json:"keyboard_layout"` + KeyboardMappingEnabled bool `json:"keyboard_mapping_enabled"` + IncludePreRelease bool `json:"include_pre_release"` + HashedPassword string `json:"hashed_password"` + LocalAuthToken string `json:"local_auth_token"` + LocalAuthMode string `json:"localAuthMode"` //TODO: fix it with migration + WakeOnLanDevices []WakeOnLanDevice `json:"wake_on_lan_devices"` } const configPath = "/userdata/kvm_config.json" var defaultConfig = &Config{ - CloudURL: "https://api.jetkvm.com", - AutoUpdateEnabled: true, // Set a default value - KeyboardLayout: "us", + CloudURL: "https://api.jetkvm.com", + AutoUpdateEnabled: true, // Set a default value + KeyboardLayout: "us", + KeyboardMappingEnabled: false, } var config *Config diff --git a/jsonrpc.go b/jsonrpc.go index f7543bb..c859fc5 100644 --- a/jsonrpc.go +++ b/jsonrpc.go @@ -143,6 +143,18 @@ func rpcSetKeyboardLayout(KeyboardLayout string) (string, error) { return KeyboardLayout, nil } +func rpcGetKeyboardMappingState() (bool, error) { + return config.KeyboardMappingEnabled, nil +} + +func rpcSetKeyboardMappingState(enabled bool) (bool, error) { + config.KeyboardMappingEnabled = enabled + if err := SaveConfig(); err != nil { + return config.KeyboardMappingEnabled, fmt.Errorf("failed to save config: %w", err) + } + return enabled, nil +} + var streamFactor = 1.0 func rpcGetStreamQualityFactor() (float64, error) { @@ -521,51 +533,53 @@ func rpcResetConfig() error { // TODO: replace this crap with code generator var rpcHandlers = map[string]RPCHandler{ - "ping": {Func: rpcPing}, - "getDeviceID": {Func: rpcGetDeviceID}, - "deregisterDevice": {Func: rpcDeregisterDevice}, - "getCloudState": {Func: rpcGetCloudState}, - "keyboardReport": {Func: rpcKeyboardReport, Params: []string{"modifier", "keys"}}, - "absMouseReport": {Func: rpcAbsMouseReport, Params: []string{"x", "y", "buttons"}}, - "wheelReport": {Func: rpcWheelReport, Params: []string{"wheelY"}}, - "getVideoState": {Func: rpcGetVideoState}, - "getUSBState": {Func: rpcGetUSBState}, - "unmountImage": {Func: rpcUnmountImage}, - "rpcMountBuiltInImage": {Func: rpcMountBuiltInImage, Params: []string{"filename"}}, - "setJigglerState": {Func: rpcSetJigglerState, Params: []string{"enabled"}}, - "getJigglerState": {Func: rpcGetJigglerState}, - "sendWOLMagicPacket": {Func: rpcSendWOLMagicPacket, Params: []string{"macAddress"}}, - "getKeyboardLayout": {Func: rpcGetKeyboardLayout}, - "setKeyboardLayout": {Func: rpcSetKeyboardLayout, Params: []string{"kbLayout"}}, - "getStreamQualityFactor": {Func: rpcGetStreamQualityFactor}, - "setStreamQualityFactor": {Func: rpcSetStreamQualityFactor, Params: []string{"factor"}}, - "getAutoUpdateState": {Func: rpcGetAutoUpdateState}, - "setAutoUpdateState": {Func: rpcSetAutoUpdateState, Params: []string{"enabled"}}, - "getEDID": {Func: rpcGetEDID}, - "setEDID": {Func: rpcSetEDID, Params: []string{"edid"}}, - "getDevChannelState": {Func: rpcGetDevChannelState}, - "setDevChannelState": {Func: rpcSetDevChannelState, Params: []string{"enabled"}}, - "getUpdateStatus": {Func: rpcGetUpdateStatus}, - "tryUpdate": {Func: rpcTryUpdate}, - "getDevModeState": {Func: rpcGetDevModeState}, - "setDevModeState": {Func: rpcSetDevModeState, Params: []string{"enabled"}}, - "getSSHKeyState": {Func: rpcGetSSHKeyState}, - "setSSHKeyState": {Func: rpcSetSSHKeyState, Params: []string{"sshKey"}}, - "setMassStorageMode": {Func: rpcSetMassStorageMode, Params: []string{"mode"}}, - "getMassStorageMode": {Func: rpcGetMassStorageMode}, - "isUpdatePending": {Func: rpcIsUpdatePending}, - "getUsbEmulationState": {Func: rpcGetUsbEmulationState}, - "setUsbEmulationState": {Func: rpcSetUsbEmulationState, Params: []string{"enabled"}}, - "checkMountUrl": {Func: rpcCheckMountUrl, Params: []string{"url"}}, - "getVirtualMediaState": {Func: rpcGetVirtualMediaState}, - "getStorageSpace": {Func: rpcGetStorageSpace}, - "mountWithHTTP": {Func: rpcMountWithHTTP, Params: []string{"url", "mode"}}, - "mountWithWebRTC": {Func: rpcMountWithWebRTC, Params: []string{"filename", "size", "mode"}}, - "mountWithStorage": {Func: rpcMountWithStorage, Params: []string{"filename", "mode"}}, - "listStorageFiles": {Func: rpcListStorageFiles}, - "deleteStorageFile": {Func: rpcDeleteStorageFile, Params: []string{"filename"}}, - "startStorageFileUpload": {Func: rpcStartStorageFileUpload, Params: []string{"filename", "size"}}, - "getWakeOnLanDevices": {Func: rpcGetWakeOnLanDevices}, - "setWakeOnLanDevices": {Func: rpcSetWakeOnLanDevices, Params: []string{"params"}}, - "resetConfig": {Func: rpcResetConfig}, + "ping": {Func: rpcPing}, + "getDeviceID": {Func: rpcGetDeviceID}, + "deregisterDevice": {Func: rpcDeregisterDevice}, + "getCloudState": {Func: rpcGetCloudState}, + "keyboardReport": {Func: rpcKeyboardReport, Params: []string{"modifier", "keys"}}, + "absMouseReport": {Func: rpcAbsMouseReport, Params: []string{"x", "y", "buttons"}}, + "wheelReport": {Func: rpcWheelReport, Params: []string{"wheelY"}}, + "getVideoState": {Func: rpcGetVideoState}, + "getUSBState": {Func: rpcGetUSBState}, + "unmountImage": {Func: rpcUnmountImage}, + "rpcMountBuiltInImage": {Func: rpcMountBuiltInImage, Params: []string{"filename"}}, + "setJigglerState": {Func: rpcSetJigglerState, Params: []string{"enabled"}}, + "getJigglerState": {Func: rpcGetJigglerState}, + "sendWOLMagicPacket": {Func: rpcSendWOLMagicPacket, Params: []string{"macAddress"}}, + "getKeyboardLayout": {Func: rpcGetKeyboardLayout}, + "setKeyboardLayout": {Func: rpcSetKeyboardLayout, Params: []string{"kbLayout"}}, + "setKeyboardMappingState": {Func: rpcSetKeyboardMappingState, Params: []string{"enabled"}}, + "getKeyboardMappingState": {Func: rpcGetKeyboardMappingState}, + "getStreamQualityFactor": {Func: rpcGetStreamQualityFactor}, + "setStreamQualityFactor": {Func: rpcSetStreamQualityFactor, Params: []string{"factor"}}, + "getAutoUpdateState": {Func: rpcGetAutoUpdateState}, + "setAutoUpdateState": {Func: rpcSetAutoUpdateState, Params: []string{"enabled"}}, + "getEDID": {Func: rpcGetEDID}, + "setEDID": {Func: rpcSetEDID, Params: []string{"edid"}}, + "getDevChannelState": {Func: rpcGetDevChannelState}, + "setDevChannelState": {Func: rpcSetDevChannelState, Params: []string{"enabled"}}, + "getUpdateStatus": {Func: rpcGetUpdateStatus}, + "tryUpdate": {Func: rpcTryUpdate}, + "getDevModeState": {Func: rpcGetDevModeState}, + "setDevModeState": {Func: rpcSetDevModeState, Params: []string{"enabled"}}, + "getSSHKeyState": {Func: rpcGetSSHKeyState}, + "setSSHKeyState": {Func: rpcSetSSHKeyState, Params: []string{"sshKey"}}, + "setMassStorageMode": {Func: rpcSetMassStorageMode, Params: []string{"mode"}}, + "getMassStorageMode": {Func: rpcGetMassStorageMode}, + "isUpdatePending": {Func: rpcIsUpdatePending}, + "getUsbEmulationState": {Func: rpcGetUsbEmulationState}, + "setUsbEmulationState": {Func: rpcSetUsbEmulationState, Params: []string{"enabled"}}, + "checkMountUrl": {Func: rpcCheckMountUrl, Params: []string{"url"}}, + "getVirtualMediaState": {Func: rpcGetVirtualMediaState}, + "getStorageSpace": {Func: rpcGetStorageSpace}, + "mountWithHTTP": {Func: rpcMountWithHTTP, Params: []string{"url", "mode"}}, + "mountWithWebRTC": {Func: rpcMountWithWebRTC, Params: []string{"filename", "size", "mode"}}, + "mountWithStorage": {Func: rpcMountWithStorage, Params: []string{"filename", "mode"}}, + "listStorageFiles": {Func: rpcListStorageFiles}, + "deleteStorageFile": {Func: rpcDeleteStorageFile, Params: []string{"filename"}}, + "startStorageFileUpload": {Func: rpcStartStorageFileUpload, Params: []string{"filename", "size"}}, + "getWakeOnLanDevices": {Func: rpcGetWakeOnLanDevices}, + "setWakeOnLanDevices": {Func: rpcSetWakeOnLanDevices, Params: []string{"params"}}, + "resetConfig": {Func: rpcResetConfig}, } diff --git a/ui/src/components/SelectMenuBasic.tsx b/ui/src/components/SelectMenuBasic.tsx index eb4c540..f515eb3 100644 --- a/ui/src/components/SelectMenuBasic.tsx +++ b/ui/src/components/SelectMenuBasic.tsx @@ -24,6 +24,7 @@ type SelectMenuProps = Pick< const sizes = { XS: "h-[24.5px] pl-3 pr-8 text-xs", SM: "h-[32px] pl-3 pr-8 text-[13px]", + SM_Wide: "h-[32px] pl-3 pr-8 mr-5 text-[13px]", MD: "h-[40px] pl-4 pr-10 text-sm", LG: "h-[48px] pl-4 pr-10 px-5 text-base", }; diff --git a/ui/src/components/WebRTCVideo.tsx b/ui/src/components/WebRTCVideo.tsx index c636bdc..080a21f 100644 --- a/ui/src/components/WebRTCVideo.tsx +++ b/ui/src/components/WebRTCVideo.tsx @@ -17,6 +17,10 @@ import useKeyboard from "@/hooks/useKeyboard"; import { useJsonRpc } from "@/hooks/useJsonRpc"; import { ConnectionErrorOverlay, HDMIErrorOverlay, LoadingOverlay } from "./VideoOverlay"; +// TODO Implement keyboard lock API to resolve #127 +// https://developer.chrome.com/docs/capabilities/web-apis/keyboard-lock +// An appropriate error message will need to be displayed in order to alert users to browser compatibility issues. + export default function WebRTCVideo() { const [keys, setKeys] = useState(useKeyboardMappingsStore.keys); const [chars, setChars] = useState(useKeyboardMappingsStore.chars); @@ -155,8 +159,6 @@ export default function WebRTCVideo() { // Invert the scroll value to match expected behavior const invertedScroll = -roundedScroll; - // TODO remove debug logs - console.log("wheelReport", { wheelY: invertedScroll }); send("wheelReport", { wheelY: invertedScroll }); // TODO this is making scrolling feel slow and sluggish, also throwing a violation in chrome @@ -179,7 +181,7 @@ export default function WebRTCVideo() { // TODO remove debug logging console.log(shiftKey + " " +ctrlKey + " " +altKey + " " +metaKey + " " +mappedKeyModifers.shift + " "+mappedKeyModifers.altLeft + " "+mappedKeyModifers.altRight + " ") - const filteredModifiers = activeModifiers.filter(Boolean);3 + const filteredModifiers = activeModifiers.filter(Boolean); // Example: activeModifiers = [0x01, 0x02, 0x04, 0x08] // Assuming 0x01 = ControlLeft, 0x02 = ShiftLeft, 0x04 = AltLeft, 0x08 = MetaLeft return ( @@ -210,8 +212,13 @@ export default function WebRTCVideo() { modifier => altKey || mappedKeyModifers.altLeft || + (modifier !== modifiers["AltLeft"]), + ) + .filter( + modifier => + altKey || mappedKeyModifers.altRight || - (modifier !== modifiers["AltLeft"] && modifier !== modifiers["AltRight"]), + (modifier !== modifiers["AltRight"]) ) // Meta: Keep if Meta is pressed or if the key isn't a Meta key // Example: If metaKey is true, keep all modifiers @@ -230,8 +237,9 @@ export default function WebRTCVideo() { async (e: KeyboardEvent) => { e.preventDefault(); const prev = useHidStore.getState(); - let code = e.code; - const localisedKey = e.key; + const code = e.code; + console.log("MAPPING ENABLED: " + settings.keyboardMappingEnabled) + var localisedKey = settings.keyboardMappingEnabled ? e.key : code; console.log(e); console.log("Localised Key: " + localisedKey); @@ -282,12 +290,12 @@ export default function WebRTCVideo() { // 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 - // TODO set this to remove from activekeystate as well if (e.metaKey) { setTimeout(() => { const prev = useHidStore.getState(); sendKeyboardEvent([], newModifiers || prev.activeModifiers); + activeKeyState.current.delete("MetaLeft"); + activeKeyState.current.delete("MetaRight"); }, 10); } @@ -302,6 +310,7 @@ export default function WebRTCVideo() { chars, keys, modifiers, + settings, ], ); diff --git a/ui/src/components/popovers/PasteModal.tsx b/ui/src/components/popovers/PasteModal.tsx index 9728cb8..66c2694 100644 --- a/ui/src/components/popovers/PasteModal.tsx +++ b/ui/src/components/popovers/PasteModal.tsx @@ -79,7 +79,7 @@ export default function PasteModal() { } catch (error) { notifications.error("Failed to paste text"); } - }, [rpcDataChannel?.readyState, send, setDisableVideoFocusTrap, setPasteMode]); + }, [rpcDataChannel?.readyState, send, setDisableVideoFocusTrap, setPasteMode, chars, keys, modifiers]); useEffect(() => { if (TextAreaRef.current) { @@ -144,6 +144,9 @@ export default function PasteModal() { The following characters won't be pasted as the current keyboard layout does not contain a valid mapping:{" "} {invalidChars.join(", ")} + + Tip: You can set your desired keyboard layout in settings, and remember to enable keyboard mapping. + )} diff --git a/ui/src/components/sidebar/settings.tsx b/ui/src/components/sidebar/settings.tsx index a6c3fe1..4e8d37c 100644 --- a/ui/src/components/sidebar/settings.tsx +++ b/ui/src/components/sidebar/settings.tsx @@ -79,6 +79,7 @@ export default function SettingsSidebar() { const settings = useSettingsStore(); const [send] = useJsonRpc(); const [keyboardLayout, setKeyboardLayout] = useState("us"); + const [kbMappingEnabled, setKeyboardMapping] = useState(false); const [streamQuality, setStreamQuality] = useState("1"); const [autoUpdate, setAutoUpdate] = useState(true); const [devChannel, setDevChannel] = useState(false); @@ -161,6 +162,20 @@ export default function SettingsSidebar() { }); }; + const handleKeyboardMappingChange = (enabled: boolean) => { + send("setKeyboardMappingState", { enabled }, resp => { + if ("error" in resp) { + notifications.error( + `Failed to set keyboard maping state state: ${resp.error.data || "Unknown error"}`, + ); + return; + } + settings.setkeyboardMappingEnabled(enabled); + useKeyboardMappingsStore.setMappingsState(enabled); + setKeyboardMapping(enabled); + }); + }; + const handleStreamQualityChange = (factor: string) => { send("setStreamQualityFactor", { factor: Number(factor) }, resp => { if ("error" in resp) { @@ -295,6 +310,13 @@ export default function SettingsSidebar() { useKeyboardMappingsStore.setLayout(String(resp.result)) }); + send("getKeyboardMappingState", {}, resp => { + if ("error" in resp) return; + setKeyboardMapping(resp.result as boolean); + settings.setkeyboardMappingEnabled(resp.result as boolean); + useKeyboardMappingsStore.setMappingsState(resp.result as boolean); + }); + send("getStreamQualityFactor", {}, resp => { if ("error" in resp) return; setStreamQuality(String(resp.result)); @@ -536,20 +558,32 @@ export default function SettingsSidebar() { description="Customize keyboard behaviour" />
+ + { + handleKeyboardMappingChange(e.target.checked); + }} + /> + handleKeyboardLayoutChange(e.target.value)} /> diff --git a/ui/src/hooks/stores.ts b/ui/src/hooks/stores.ts index 6118b0b..f1c4923 100644 --- a/ui/src/hooks/stores.ts +++ b/ui/src/hooks/stores.ts @@ -265,6 +265,9 @@ interface SettingsState { mouseMode: string; setMouseMode: (mode: string) => void; + keyboardMappingEnabled: boolean; + setkeyboardMappingEnabled: (enabled: boolean) => void; + debugMode: boolean; setDebugMode: (enabled: boolean) => void; @@ -276,6 +279,9 @@ interface SettingsState { export const useSettingsStore = create( persist( set => ({ + keyboardMappingEnabled: false, + setkeyboardMappingEnabled: enabled => set({keyboardMappingEnabled: enabled}), + isCursorHidden: false, setCursorVisibility: enabled => set({ isCursorHidden: enabled }), @@ -535,18 +541,42 @@ export const useLocalAuthModalStore = create(set => ({ class KeyboardMappingsStore { private _layout: string = 'us'; private _subscribers: (() => void)[] = []; + private _mappingsEnabled: boolean = false; public keys = getKeyboardMappings(this._layout).keys; public chars = getKeyboardMappings(this._layout).chars; public modifiers = getKeyboardMappings(this._layout).modifiers; + private mappedKeys = getKeyboardMappings(this._layout).keys; + private mappedChars = getKeyboardMappings(this._layout).chars; + private mappedModifiers = 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.mappedKeys = updatedMappings.keys; + this.mappedChars = updatedMappings.chars; + this.mappedModifiers = updatedMappings.modifiers; + if (this._mappingsEnabled) { + this.keys = this.mappedKeys; + this.chars = this.mappedChars; + this.modifiers = this.mappedModifiers; + this._notifySubscribers(); + } + } + + setMappingsState(enabled: boolean) { + this._mappingsEnabled = enabled; + if (this._mappingsEnabled) { + this.keys = this.mappedKeys; + this.chars = this.mappedChars; + this.modifiers = this.mappedModifiers; + } else { + this.keys = getKeyboardMappings('us').keys; + this.chars = getKeyboardMappings('us').chars; + this.modifiers = getKeyboardMappings('us').modifiers; + } this._notifySubscribers(); } diff --git a/ui/src/keyboardMappings/KeyboardLayouts.ts b/ui/src/keyboardMappings/KeyboardLayouts.ts index b631d76..11fd798 100644 --- a/ui/src/keyboardMappings/KeyboardLayouts.ts +++ b/ui/src/keyboardMappings/KeyboardLayouts.ts @@ -1,5 +1,7 @@ import {keysUKApple, charsUKApple, modifiersUKApple } from './layouts/uk_apple'; +import {keysUK, charsUK, modifiersUK } from './layouts/uk'; import {keysUS, charsUS, modifiersUS } from './layouts/us'; +import { keysDE_T1, charsDE_T1, modifiersDE_T1 } from './layouts/de_t1'; export function getKeyboardMappings(layout: string) { switch (layout) { @@ -9,6 +11,18 @@ export function getKeyboardMappings(layout: string) { chars: charsUKApple, modifiers: modifiersUKApple, }; + case "uk": + return { + keys: keysUK, + chars: charsUK, + modifiers: modifiersUK, + }; + case "de_t1": + return { + keys: keysDE_T1, + chars: charsDE_T1, + modifiers: modifiersDE_T1, + }; case "us": default: return { diff --git a/ui/src/keyboardMappings/layouts/de_t1.ts b/ui/src/keyboardMappings/layouts/de_t1.ts new file mode 100644 index 0000000..8fd7bfa --- /dev/null +++ b/ui/src/keyboardMappings/layouts/de_t1.ts @@ -0,0 +1,69 @@ +import { charsUS, keysUS, modifiersUS } from "./us"; + +export const keysDE_T1 = { + ...keysUS, +} as Record; + +export const charsDE_T1 = { + ...charsUS, + + "y": { key: "KeyZ", shift: false }, + "Y": { key: "KeyZ", shift: true }, + "z": { key: "KeyY", shift: false }, + "Z": { key: "KeyY", shift: true }, + + "ä": { key: "Quote", shift: false }, + "Ä": { key: "Quote", shift: true }, + "ö": { key: "Semicolon", shift: false }, + "Ö": { key: "Semicolon", shift: true }, + "ü": { key: "BracketLeft", shift: false }, + "Ü": { key: "BracketLeft", shift: true }, + "ß": { key: "Minus", shift: false }, + "?": { key: "Minus", shift: true }, + + "§": { key: "Digit3", shift: true }, + "°": { key: "Backquote", shift: true }, + + "@": { key: "KeyQ", shift: false, altRight: true }, + "\"": { key: "Digit2", shift: true }, + + "#": { key: "Backslash", shift: false }, + "'": { key: "Backslash", shift: true }, + + ".": { key: "Period", shift: false }, + ":": { key: "Period", shift: true }, + ",": { key: "Comma", shift: false }, + ";": { key: "Comma", shift: true }, + + "-": { key: "Slash", shift: false }, + "_": { key: "Slash", shift: true }, + + "*": { key: "BracketRight", shift: true }, + "+": { key: "BracketRight", shift: false }, + "=": { key: "Digit0", shift: true }, + "~": { key: "BracketRight", shift: false, altRight: true }, + "{": { key: "Digit7", shift: false, altRight: true }, + "}": { key: "Digit0", shift: false, altRight: true }, + "[": { key: "Digit8", shift: false, altRight: true }, + "]": { key: "Digit9", shift: false, altRight: true }, + + "\\": { key: "Minus", shift: false, altRight: true }, + "|": { key: "IntlBackslash", shift: true, altRight: true }, + + "<": { key: "IntlBackslash", shift: false }, + ">": { key: "IntlBackslash", shift: true }, + + "^": {key: "Backquote", shift: false}, + + "€": { key: "KeyE", shift: false, altRight: true }, + + "²": {key: "Digit2", shift: false, altRight: true }, + "³": {key: "Digit3", shift: false, altRight: true }, + + "μ": {key: "KeyM", shift: false, altRight: true }, + +} as Record; + +export const modifiersDE_T1 = { + ...modifiersUS, +} as Record; \ No newline at end of file diff --git a/ui/src/keyboardMappings/layouts/uk.ts b/ui/src/keyboardMappings/layouts/uk.ts index e69de29..f64979f 100644 --- a/ui/src/keyboardMappings/layouts/uk.ts +++ b/ui/src/keyboardMappings/layouts/uk.ts @@ -0,0 +1,24 @@ +import { charsUS, keysUS, modifiersUS } from "./us"; + +export const keysUK = { + ...keysUS, +} as Record; + +export const charsUK = { + ...charsUS, + "`": { key: "Backquote", shift: false }, + "~": { key: "Backslash", shift: true }, + "\\": { key: "IntlBacklash", shift: false }, + "|": { key: "IntlBacklash", shift: true }, + "#": { key: "Backslash", shift: false }, + "£": { key: "Digit3", shift: true }, + "@": { key: "Quote", shift: true }, + "\"": { key: "Digit2", shift: true }, + "¬": { key: "Backquote", shift: true }, + "¦": { key: "Backquote", shift: false, altRight: true }, + "€": { key: "Digit4", shift: false, altRight: true }, +} as Record; + +export const modifiersUK = { + ...modifiersUS, +} as Record; \ No newline at end of file diff --git a/ui/src/keyboardMappings/layouts/uk_apple.ts b/ui/src/keyboardMappings/layouts/uk_apple.ts index c5ec7f9..fef400f 100644 --- a/ui/src/keyboardMappings/layouts/uk_apple.ts +++ b/ui/src/keyboardMappings/layouts/uk_apple.ts @@ -16,6 +16,7 @@ export const charsUKApple = { "£": { key: "Digit3", shift: true }, "@": { key: "Digit2", shift: true }, "\"": { key: "Quote", shift: true }, + "¬": { key: "KeyL", shift: false, altLeft: true}, } as Record; // Modifiers are typically the same between UK and US layouts