diff --git a/resources/lang/en.json b/resources/lang/en.json index 6c89617f8b..effc4e7202 100644 --- a/resources/lang/en.json +++ b/resources/lang/en.json @@ -1667,6 +1667,7 @@ "toggle_view_desc": "Alternate view (terrain/countries)", "toggle_visibility": "Toggle Visibility", "unbind": "Unbind", + "unbind_all": "Unbind All", "view_options": "View Options", "zoom_controls": "Zoom Controls", "zoom_in": "Zoom In", diff --git a/src/client/UserSettingModal.ts b/src/client/UserSettingModal.ts index 428afd95dd..0a4a9a2dd4 100644 --- a/src/client/UserSettingModal.ts +++ b/src/client/UserSettingModal.ts @@ -73,6 +73,12 @@ export class UserSettingModal extends BaseModal { this.userKeybinds = validated; } + private unbindAllKeybinds() { + this.userSettings.unbindAllKeybinds(Platform.isMac); + this.loadKeybindsFromStorage(); + this.requestUpdate(); + } + private handleKeybindChange( e: CustomEvent<{ action: string; @@ -366,6 +372,13 @@ export class UserSettingModal extends BaseModal { ${translateText("user_setting.keybinds_hint")} + +

diff --git a/src/core/game/UserSettings.ts b/src/core/game/UserSettings.ts index 7be154af9e..b1b8e6c0b3 100644 --- a/src/core/game/UserSettings.ts +++ b/src/core/game/UserSettings.ts @@ -551,6 +551,18 @@ export class UserSettings { } } + /** + * Unbind every keybind at once: set each default action to "Null" (the same + * sentinel a single per-key Unbind uses), so keybinds() drops them all. + */ + unbindAllKeybinds(isMac: boolean): void { + const unbound: Record = {}; + for (const action of Object.keys(getDefaultKeybinds(isMac))) { + unbound[action] = "Null"; + } + this.setKeybinds(unbound); + } + soundEffectsVolume(): number { return this.getFloat("settings.soundEffectsVolume", 0); } diff --git a/tests/UserSettings.test.ts b/tests/UserSettings.test.ts index b526425858..077fa994e5 100644 --- a/tests/UserSettings.test.ts +++ b/tests/UserSettings.test.ts @@ -1,5 +1,6 @@ import { EFFECTS_KEY, + getDefaultKeybinds, PLAYER_STATS_COLUMNS_KEY, TEAM_STATS_COLUMNS_KEY, UserSettings, @@ -135,3 +136,26 @@ describe("UserSettings stats columns", () => { expect(localStorage.getItem(TEAM_STATS_COLUMNS_KEY)).toBe('["warships"]'); }); }); + +describe("UserSettings unbindAllKeybinds (#4309)", () => { + beforeEach(() => { + localStorage.clear(); + ( + UserSettings as unknown as { cache: Map } + ).cache.clear(); + }); + + it("sets every default keybind action to Null so nothing stays bound", () => { + const s = new UserSettings(); + s.unbindAllKeybinds(false); + + const parsed = s.parsedUserKeybinds(); + const defaults = getDefaultKeybinds(false); + expect(Object.keys(defaults).length).toBeGreaterThan(0); + for (const action of Object.keys(defaults)) { + expect(parsed[action]).toBe("Null"); + } + // keybinds() drops "Null" entries, so no action resolves to a key. + expect(Object.keys(s.keybinds(false))).toHaveLength(0); + }); +});