feat(funbox): add layout mirror (@megalodon2710) (#6463)

### Description

Added layout mirror item in the funbox with functionality.

Tweaked how active funbox items are detected in the commandline (names
included in other names no long appear as active if the item they're
included in is active).

### Checks

- [ ] Adding quotes?
- [ ] Make sure to include translations for the quotes in the
description (or another comment) so we can verify their content.
- [ ] Adding a language or a theme?
- [ ] If is a language, did you edit `_list.json`, `_groups.json` and
add `languages.json`?
  - [ ] If is a theme, did you add the theme.css?
- Also please add a screenshot of the theme, it would be extra awesome
if you do so!
- [X] Check if any open issues are related to this PR; if so, be sure to
tag them below.
- [X] Make sure the PR title follows the Conventional Commits standard.
(https://www.conventionalcommits.org for more info)
- [X] Make sure to include your GitHub username prefixed with @ inside
parentheses at the end of the PR title.

<!-- label(optional scope): pull request title (@your_github_username)
-->

<!-- I know I know they seem boring but please do them, they help us and
you will find out it also helps you.-->

Closes #5573

<!-- the issue(s) your PR resolves if any (delete if that is not the
case) -->
<!-- please also reference any issues and or PRs related to your pull
request -->
<!-- Also remove it if you are not following any issues. -->

<!-- pro tip: you can mention an issue, PR, or discussion on GitHub by
referencing its hash number e.g:
[#1234](https://github.com/monkeytypegame/monkeytype/pull/1234) -->

<!-- pro tip: you can press . (dot or period) in the code tab of any
GitHub repo to get access to GitHub's VS Code web editor Enjoy! :) -->

---------

Co-authored-by: jeffrey <jeffrey.tiger@telecom-paris.fr>
Co-authored-by: Miodec <jack@monkeytype.com>
This commit is contained in:
megalodon2710 2025-04-17 16:10:19 +02:00 committed by GitHub
parent 6acaeb41f1
commit bf002c02ec
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 95 additions and 9 deletions

View file

@ -352,9 +352,14 @@ async function showCommands(): Promise<void> {
configIcon = `<i class="fas fa-fw"></i>`;
}
} 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<void> {
| 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 = `<i class="fas fa-fw fa-check"></i>`;
} else {

View file

@ -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();

View file

@ -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;

View file

@ -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 =

View file

@ -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 = "";

View file

@ -326,6 +326,20 @@ const list: Partial<Record<FunboxName, FunboxFunctions>> = {
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";

View file

@ -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") {

View file

@ -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;
}

View file

@ -62,7 +62,6 @@ const list: Record<FunboxName, FunboxMetadata> = {
},
frontendFunctions: ["applyConfig", "rememberSettings"],
},
tts: {
canGetPb: true,
difficultyLevel: 1,
@ -130,6 +129,14 @@ const list: Record<FunboxName, FunboxMetadata> = {
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.",

View file

@ -10,6 +10,7 @@ export type FunboxName =
| "arrows"
| "rAnDoMcAsE"
| "capitals"
| "layout_mirror"
| "layoutfluid"
| "earthquake"
| "space_balls"