diff --git a/frontend/src/ts/commandline/commandline.ts b/frontend/src/ts/commandline/commandline.ts index ec27b45a5..0d94deaf4 100644 --- a/frontend/src/ts/commandline/commandline.ts +++ b/frontend/src/ts/commandline/commandline.ts @@ -352,9 +352,14 @@ async function showCommands(): Promise { configIcon = ``; } } else if (configKey !== undefined) { - const valueIsIncluded = - command.configValueMode === "include" && - ( + let isActive; + + if (command.configValueMode === "funbox") { + isActive = (Config[configKey] as string) + .split("#") + .includes(command.configValue as string); + } else if (command.configValueMode === "include") { + isActive = ( Config[configKey] as ( | string | number @@ -363,8 +368,11 @@ async function showCommands(): Promise { | undefined )[] ).includes(command.configValue); - const valueIsTheSame = Config[configKey] === command.configValue; - if (valueIsIncluded || valueIsTheSame) { + } else { + isActive = Config[configKey] === command.configValue; + } + + if (isActive) { firstActive = firstActive ?? index; configIcon = ``; } else { diff --git a/frontend/src/ts/commandline/lists/funbox.ts b/frontend/src/ts/commandline/lists/funbox.ts index f8c984bc3..9faf2fa9f 100644 --- a/frontend/src/ts/commandline/lists/funbox.ts +++ b/frontend/src/ts/commandline/lists/funbox.ts @@ -33,7 +33,8 @@ for (const funbox of getAllFunboxes()) { sticky: true, alias: funbox.alias, configValue: funbox.name, - configValueMode: "include", + //todo remove funbox mode once Config.funbox is changed to an array + configValueMode: "funbox", exec: (): void => { Funbox.toggleFunbox(funbox.name); ManualRestart.set(); diff --git a/frontend/src/ts/commandline/types.ts b/frontend/src/ts/commandline/types.ts index 4932b274d..8e382fdfc 100644 --- a/frontend/src/ts/commandline/types.ts +++ b/frontend/src/ts/commandline/types.ts @@ -25,7 +25,7 @@ export type Command = { defaultValue?: () => string; configKey?: keyof Config; configValue?: string | number | boolean | number[]; - configValueMode?: "include"; + configValueMode?: "include" | "funbox"; exec?: (options: CommandExecOptions) => void; hover?: () => void; available?: () => boolean; diff --git a/frontend/src/ts/controllers/input-controller.ts b/frontend/src/ts/controllers/input-controller.ts index e5c261711..bedbdbdbc 100644 --- a/frontend/src/ts/controllers/input-controller.ts +++ b/frontend/src/ts/controllers/input-controller.ts @@ -39,6 +39,7 @@ import { findSingleActiveFunboxWithFunction, getActiveFunboxesWithFunction, isFunboxActiveWithProperty, + getActiveFunboxNames, } from "../test/funbox/list"; let dontInsertSpace = false; @@ -1128,14 +1129,21 @@ $(document).on("keydown", async (event) => { Config.oppositeShiftMode === "keymap" && Config.keymapLayout !== "overrideSync" ) { - const keymapLayout = await JSONData.getLayout(Config.keymapLayout).catch( + let keymapLayout = await JSONData.getLayout(Config.keymapLayout).catch( () => undefined ); + if (keymapLayout === undefined) { Notifications.add("Failed to load keymap layout", -1); return; } + + const funbox = getActiveFunboxNames().includes("layout_mirror"); + if (funbox) { + keymapLayout = KeyConverter.mirrorLayoutKeys(keymapLayout); + } + const keycode = KeyConverter.layoutKeyToKeycode(event.key, keymapLayout); correctShiftUsed = diff --git a/frontend/src/ts/elements/keymap.ts b/frontend/src/ts/elements/keymap.ts index ad99c667e..8f1fc31f8 100644 --- a/frontend/src/ts/elements/keymap.ts +++ b/frontend/src/ts/elements/keymap.ts @@ -13,6 +13,7 @@ import { capsState } from "../test/caps-warning"; import * as ShiftTracker from "../test/shift-tracker"; import * as AltTracker from "../test/alt-tracker"; import * as KeyConverter from "../utils/key-converter"; +import { getActiveFunboxNames } from "../test/funbox/list"; const stenoKeys: JSONData.Layout = { keymapShowTopRow: true, @@ -393,6 +394,11 @@ export async function refresh( layoutData = stenoKeys; } + const funbox = getActiveFunboxNames().includes("layout_mirror"); + if (funbox) { + layoutData = KeyConverter.mirrorLayoutKeys(layoutData); + } + const isISO = layoutData.type === "iso"; let keymapElement = ""; diff --git a/frontend/src/ts/test/funbox/funbox-functions.ts b/frontend/src/ts/test/funbox/funbox-functions.ts index 6e550f51c..4a4da520b 100644 --- a/frontend/src/ts/test/funbox/funbox-functions.ts +++ b/frontend/src/ts/test/funbox/funbox-functions.ts @@ -326,6 +326,20 @@ const list: Partial> = { return Strings.capitalizeFirstLetterOfEachWord(word); }, }, + layout_mirror: { + applyConfig(): void { + let layout = Config.layout; + if (Config.layout === "default") { + layout = "qwerty"; + } + UpdateConfig.setLayout(layout, true); + UpdateConfig.setKeymapLayout("overrideSync", true); + }, + rememberSettings(): void { + save("keymapMode", Config.keymapMode, UpdateConfig.setKeymapMode); + save("layout", Config.layout, UpdateConfig.setLayout); + }, + }, layoutfluid: { applyConfig(): void { const layout = Config.customLayoutfluid.split("#")[0] ?? "qwerty"; diff --git a/frontend/src/ts/test/layout-emulator.ts b/frontend/src/ts/test/layout-emulator.ts index ec6bc6984..18ca48bc6 100644 --- a/frontend/src/ts/test/layout-emulator.ts +++ b/frontend/src/ts/test/layout-emulator.ts @@ -3,6 +3,9 @@ import * as Misc from "../utils/misc"; import * as JSONData from "../utils/json-data"; import { capsState } from "./caps-warning"; import * as Notifications from "../elements/notifications"; +import * as KeyConverter from "../utils/key-converter"; + +import { getActiveFunboxNames } from "./funbox/list"; let isAltGrPressed = false; const isPunctuationPattern = /\p{P}/u; @@ -41,6 +44,11 @@ export async function getCharFromEvent( return null; } + const funbox = getActiveFunboxNames().includes("layout_mirror"); + if (funbox) { + layout = KeyConverter.mirrorLayoutKeys(layout); + } + let keyEventCodes: string[] = []; if (layout.type === "ansi") { diff --git a/frontend/src/ts/utils/key-converter.ts b/frontend/src/ts/utils/key-converter.ts index 7f34677b6..0acabb4d7 100644 --- a/frontend/src/ts/utils/key-converter.ts +++ b/frontend/src/ts/utils/key-converter.ts @@ -280,3 +280,36 @@ export function keycodeToKeyboardSide(keycode: Keycode): { return { leftSide: left, rightSide: right }; } + +/** + * Returns a copy of the given layout with the rows mirrored + * @param layout Layout object from our JSON data (e.g., `layouts["qwerty"]`) + * @returns layout Layout object from our JSON data (e.g., `layouts["qwerty"]`) + */ +export function mirrorLayoutKeys(layout: JSONData.Layout): JSONData.Layout { + const reverse_index = [11, 10, 10, 10, 10]; + const mirror_keys: JSONData.Keys = { + row1: [ + ...[...layout.keys.row1.slice(0, reverse_index[0])].reverse(), + ...layout.keys.row1.slice(reverse_index[0]), + ], + row2: [ + ...[...layout.keys.row2.slice(0, reverse_index[1])].reverse(), + ...layout.keys.row2.slice(reverse_index[1]), + ], + row3: [ + ...[...layout.keys.row3.slice(0, reverse_index[2])].reverse(), + ...layout.keys.row3.slice(reverse_index[2]), + ], + row4: [ + ...[...layout.keys.row4.slice(0, reverse_index[3])].reverse(), + ...layout.keys.row4.slice(reverse_index[3]), + ], + row5: [ + ...[...layout.keys.row5.slice(0, reverse_index[4])].reverse(), + ...layout.keys.row5.slice(reverse_index[4]), + ], + }; + const layoutCopy: JSONData.Layout = { ...layout, keys: mirror_keys }; + return layoutCopy; +} diff --git a/packages/funbox/src/list.ts b/packages/funbox/src/list.ts index bb8947204..5ea4a20c5 100644 --- a/packages/funbox/src/list.ts +++ b/packages/funbox/src/list.ts @@ -62,7 +62,6 @@ const list: Record = { }, frontendFunctions: ["applyConfig", "rememberSettings"], }, - tts: { canGetPb: true, difficultyLevel: 1, @@ -130,6 +129,14 @@ const list: Record = { frontendFunctions: ["alterText"], name: "capitals", }, + layout_mirror: { + description: "Mirror the keyboard layout", + canGetPb: true, + difficultyLevel: 1, + properties: ["changesLayout"], + frontendFunctions: ["applyConfig", "rememberSettings"], + name: "layout_mirror", + }, layoutfluid: { description: "Switch between layouts specified below proportionately to the length of the test.", diff --git a/packages/funbox/src/types.ts b/packages/funbox/src/types.ts index ff4463b2a..f9f065e85 100644 --- a/packages/funbox/src/types.ts +++ b/packages/funbox/src/types.ts @@ -10,6 +10,7 @@ export type FunboxName = | "arrows" | "rAnDoMcAsE" | "capitals" + | "layout_mirror" | "layoutfluid" | "earthquake" | "space_balls"