From c77ed5f8b185fb059412964cd0b81a9067ac8440 Mon Sep 17 00:00:00 2001 From: bijx Date: Wed, 24 Dec 2025 09:36:58 -0500 Subject: [PATCH] Feat: Keybind user settings directly update instruction page hotkeys (#2669) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description: Currently the instructions page not only has hardcoded keybinds for the hotkeys section, but they're also not updated (`1` and `2` are written as decreasing and increasing attack ratio instead of `T` and `Y`). This fix introduces a function in the `HelpModal` to get the keybinds from the local storage and render the keys in the instructions section dynamically. Special keys (like Arrow keys and Shift) are handled, as well as support for the keys on a Mac computer (i.e. `⌘`). ### Video Demo https://github.com/user-attachments/assets/2d6c6ee9-5e5d-4c7e-83df-363a345afe4d ## Please complete the following: - [x] I have added screenshots for all UI updates - [x] I process any text displayed to the user through translateText() and I've added it to the en.json file - [x] I have added relevant tests to the test directory - [x] I confirm I have thoroughly tested these changes and take full responsibility for any bugs introduced ## Please put your Discord username so you can be contacted if a bug or regression is found: bijx --- src/client/HelpModal.ts | 120 +++++++++++++++++++++++++++++++++++----- 1 file changed, 106 insertions(+), 14 deletions(-) diff --git a/src/client/HelpModal.ts b/src/client/HelpModal.ts index 1b840c27b..3f47b2c8d 100644 --- a/src/client/HelpModal.ts +++ b/src/client/HelpModal.ts @@ -1,6 +1,6 @@ import { LitElement, html } from "lit"; -import { customElement, query } from "lit/decorators.js"; -import { getAltKey, getModifierKey, translateText } from "../client/Utils"; +import { customElement, query, state } from "lit/decorators.js"; +import { translateText } from "../client/Utils"; import "./components/Difficulties"; import "./components/Maps"; @@ -10,6 +10,7 @@ export class HelpModal extends LitElement { open: () => void; close: () => void; }; + @state() private keybinds: Record = this.getKeybinds(); createRenderRoot() { return this; @@ -25,6 +26,15 @@ export class HelpModal extends LitElement { super.disconnectedCallback(); } + private isKeybindObject(v: unknown): v is { value: string } { + return ( + typeof v === "object" && + v !== null && + "value" in v && + typeof (v as any).value === "string" + ); + } + private handleKeyDown = (e: KeyboardEvent) => { if (e.code === "Escape") { e.preventDefault(); @@ -32,7 +42,80 @@ export class HelpModal extends LitElement { } }; + private getKeybinds(): Record { + let saved: Record = {}; + try { + const parsed = JSON.parse( + localStorage.getItem("settings.keybinds") ?? "{}", + ); + saved = Object.fromEntries( + Object.entries(parsed) + .map(([k, v]) => { + if (this.isKeybindObject(v)) return [k, v.value]; + if (typeof v === "string") return [k, v]; + return [k, undefined]; + }) + .filter(([, v]) => typeof v === "string" && v !== "Null"), + ) as Record; + } catch (e) { + console.warn("Invalid keybinds JSON:", e); + } + + const isMac = /Mac/.test(navigator.userAgent); + return { + toggleView: "Space", + centerCamera: "KeyC", + moveUp: "KeyW", + moveDown: "KeyS", + moveLeft: "KeyA", + moveRight: "KeyD", + zoomOut: "KeyQ", + zoomIn: "KeyE", + attackRatioDown: "KeyT", + attackRatioUp: "KeyY", + shiftKey: "ShiftLeft", + modifierKey: isMac ? "MetaLeft" : "ControlLeft", + altKey: "AltLeft", + resetGfx: "KeyR", + ...saved, + }; + } + + private getKeyLabel(code: string): string { + if (!code) return ""; + + const specialLabels: Record = { + ShiftLeft: "⇧ Shift", + ShiftRight: "⇧ Shift", + ControlLeft: "Ctrl", + ControlRight: "Ctrl", + AltLeft: "Alt", + AltRight: "Alt", + MetaLeft: "⌘", + MetaRight: "⌘", + Space: "Space", + ArrowUp: "↑", + ArrowDown: "↓", + ArrowLeft: "←", + ArrowRight: "→", + }; + + if (specialLabels[code]) return specialLabels[code]; + if (code.startsWith("Key") && code.length === 4) return code.slice(3); + if (code.startsWith("Digit")) return code.slice(5); + if (code.startsWith("Numpad")) return `Num ${code.slice(6)}`; + + return code; + } + + private renderKey(code: string) { + const label = this.getKeyLabel(code); + return html`${label}`; + } + render() { + const keybinds = this.keybinds; + return html` - Space + ${this.renderKey(keybinds.toggleView)} ${translateText("help_modal.action_alt_view")}
- ⇧ Shift + ${this.renderKey(keybinds.shiftKey)} +
@@ -71,7 +154,7 @@ export class HelpModal extends LitElement {
- ${getModifierKey()} + ${this.renderKey(keybinds.modifierKey)} +
@@ -84,7 +167,7 @@ export class HelpModal extends LitElement {
- ${getAltKey()} + ${this.renderKey(keybinds.altKey)} +
@@ -95,28 +178,36 @@ export class HelpModal extends LitElement { ${translateText("help_modal.action_emote")} - C + ${this.renderKey(keybinds.centerCamera)} ${translateText("help_modal.action_center")} - Q / E + + ${this.renderKey(keybinds.zoomOut)} / + ${this.renderKey(keybinds.zoomIn)} + ${translateText("help_modal.action_zoom")} - W A - S D + ${this.renderKey(keybinds.moveUp)} + ${this.renderKey(keybinds.moveLeft)} + ${this.renderKey(keybinds.moveDown)} + ${this.renderKey(keybinds.moveRight)} ${translateText("help_modal.action_move_camera")} - 1 / 2 + + ${this.renderKey(keybinds.attackRatioDown)} / + ${this.renderKey(keybinds.attackRatioUp)} + ${translateText("help_modal.action_ratio_change")}
- ⇧ Shift + ${this.renderKey(keybinds.shiftKey)} +
@@ -133,8 +224,8 @@ export class HelpModal extends LitElement { - ${getAltKey()} + - R + ${this.renderKey(keybinds.altKey)} + + ${this.renderKey(keybinds.resetGfx)} ${translateText("help_modal.action_reset_gfx")} @@ -600,6 +691,7 @@ export class HelpModal extends LitElement { } public open() { + this.keybinds = this.getKeybinds(); this.modalEl?.open(); }