Input handler.ts rework (#4225)

> **Before opening a PR:** discuss new features on
[Discord](https://discord.gg/K9zernJB5z) first, and file bugs or small
improvements as
[issues](https://github.com/openfrontio/OpenFrontIO/issues/new/choose).
You must be assigned to an `approved` issue — unsolicited PRs will be
auto-closed.

**Add approved & assigned issue number here:**

Resolves #4193 

## Description:

Use activeKeys set in places where it is checking if a key is being
pressed in a different way, and it makes more sense to use the
activeKeys set. Make the overall code of the InputHandler.ts file more
consistent and to make it easier to add new keybinds in the future.

<img width="1920" height="1080" alt="Screenshot from 2026-06-13
20-49-56"
src="https://github.com/user-attachments/assets/94f6f81c-7278-4bca-845c-2442b6caea39"
/>


## 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

## Please put your Discord username so you can be contacted if a bug or
regression is found:

tktk1234567
This commit is contained in:
TKTK123456
2026-06-30 14:17:25 +00:00
committed by GitHub
parent 200f276ab2
commit 0d2179f5f3
5 changed files with 283 additions and 135 deletions
+56
View File
@@ -636,6 +636,62 @@ describe("InputHandler AutoUpgrade", () => {
});
});
describe("Digit keys still set ghost structure when bound to Numpad", () => {
beforeEach(() => {
inputHandler.destroy();
testSettings.setKeybinds({
buildCity: "Numpad1",
buildMIRV: "Numpad0",
});
const uiState: UIState = {
attackRatio: 20,
ghostStructure: null,
rocketDirectionUp: true,
} as UIState;
inputHandler = new InputHandler(
mockGameView,
uiState,
mockCanvas,
eventBus,
);
inputHandler.initialize();
});
test("Digit1 sets ghost structure to City when buildCity is Numpad1", () => {
window.dispatchEvent(
new KeyboardEvent("keyup", { code: "Digit1", key: "1" }),
);
expect(inputHandler["uiState"].ghostStructure).toBe(UnitType.City);
});
test("Digit0 sets ghost structrue to MIRV when buildMIRV is Numpad0", () => {
window.dispatchEvent(
new KeyboardEvent("keyup", { code: "Digit0", key: "0" }),
);
expect(inputHandler["uiState"].ghostStructure).toBe(UnitType.MIRV);
});
});
describe("InputHandler keybind registry", () => {
function makeHandler() {
return new InputHandler(
{} as any, // gameView
{} as any, // uiState
document.createElement("div"), // canvas
{} as any, // eventBus
);
}
test("two actions bound to the same key are both kept (no overwrite)", () => {
const ih = makeHandler() as any;
ih.keybindAndEvent = [];
ih.addKeybindAndEvent("KeyX", () => {});
ih.addKeybindAndEvent("KeyX", () => {});
const entries = ih.keybindAndEvent.filter(
([k]: [string, unknown]) => k === "KeyX",
);
expect(entries.length).toBe(2); // would have been 1 with the old Map
});
});
describe("Build keybind two-phase matching (exact code first, then digit/Numpad alias)", () => {
beforeEach(() => {
inputHandler.destroy();