Skip to content

Input handler.ts rework#4225

Merged
Celant merged 42 commits into
openfrontio:mainfrom
TKTK123456:InputHandler.ts-Rework
Jun 30, 2026
Merged

Input handler.ts rework#4225
Celant merged 42 commits into
openfrontio:mainfrom
TKTK123456:InputHandler.ts-Rework

Conversation

@TKTK123456

@TKTK123456 TKTK123456 commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Before opening a PR: discuss new features on Discord first, and file bugs or small improvements as issues. 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.

Screenshot from 2026-06-13 20-49-56

Please complete the following:

  • I have added screenshots for all UI updates
  • I process any text displayed to the user through translateText() and I've added it to the en.json file
  • 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

@coderabbitai

coderabbitai Bot commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 7b3b2f35-f581-43ca-92b4-71f7b00131e9

📥 Commits

Reviewing files that changed from the base of the PR and between fa17f8c and ed12b7e.

📒 Files selected for processing (1)
  • src/client/UserSettingModal.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/client/UserSettingModal.ts

Walkthrough

InputHandler now uses a shortcut registry, tracks the configured Alt key in activeKeys, updates build-key matching, and adds an Alt key setting with matching translations and tests.

Changes

Keyboard registry and Alt key configuration

Layer / File(s) Summary
Registry type and infrastructure
src/client/InputHandler.ts
Adds the keybind entry shape with handler and condition list, introduces a keybind-to-entry registry, generalizes key matching to accept keyboard events or synthesized { shiftKey, code } objects, adds the registry append helper, and clears the registry during destroy.
Initialize: register all keybinds
src/client/InputHandler.ts
Registers shortcut handlers through the registry helper, including repeat-gated pause and game-speed actions, Alt-gated refresh graphics, forced toggle-view state changes, and build ghost activation gated by build-key conditions.
Key tracking and modifier detection
src/core/game/UserSettings.ts, src/client/UserSettingModal.ts, resources/lang/en.json
Adds the default altKey binding, allows the Alt key to be edited in settings, permits the AltLeft swap with emojiMenuModifier, and adds translations for the graphics refresh modifier text.
Test coverage for registry behavior and build keys
tests/InputHandler.test.ts
Verifies that digit keys still set the correct ghost structure when build keybinds use Numpad aliases, and checks that the registry keeps multiple handlers for the same key string.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • openfrontio/OpenFrontIO#4175: Both PRs modify src/client/InputHandler.ts and related keybind settings to change modifier-key handling with tracked key state.

Suggested reviewers

  • evanpelle

Poem

Keys now gather in a tidy line,
Alt and build binds start to shine.
One registry hums, calm and neat,
With tests to keep each path complete.
TypeScript dances, clear and light.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and clearly reflects the InputHandler refactor.
Description check ✅ Passed The description is related to the refactor and the new keybind and UI updates.
Linked Issues check ✅ Passed The PR centralizes InputHandler key handling with activeKeys and makes keybinds easier to add, matching #4193.
Out of Scope Changes check ✅ Passed The locale, settings, and tests changes support the refactor and do not appear unrelated to the issue.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/client/InputHandler.ts (1)

1-1: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Prettier formatting issues reported by CI.

Run npx prettier --write src/client/InputHandler.ts to fix the code style issues flagged by the pipeline.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/client/InputHandler.ts` at line 1, This file has Prettier style
violations; run the formatter and commit the changes by executing npx prettier
--write src/client/InputHandler.ts (or run the project's format script) to
update formatting for the InputHandler module; after formatting, verify that
imports like EventBus and GameEvent and any exported class/function in
InputHandler.ts still compile and then re-run CI.

Source: Pipeline failures

🧹 Nitpick comments (1)
src/client/InputHandler.ts (1)

929-941: ⚡ Quick win

Typo in JSDoc and consider a typed structure.

  1. Line 932: "exectued""executed"

  2. The array-based convention [action, ...conditions] works but requires knowing the index contract. A typed object would be clearer and catch misuse at compile time:

interface KeybindEntry {
  action: (e: KeyboardEvent) => void;
  conditions?: Array<(e: KeyboardEvent) => boolean>;
}
private keybindAndEvent = new Map<string, KeybindEntry>();

This makes the structure explicit and gives proper types for actions (void) vs conditions (boolean).

🔤 Minimal fix for typo
-   * `@param` event The code to be exectued when this keybind is pressed
+   * `@param` event The code to be executed when this keybind is pressed
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/client/InputHandler.ts` around lines 929 - 941, Fix the JSDoc typo
("exectued" → "executed") and replace the fragile array convention used by
keybindAndEvent with a typed object: define a KeybindEntry (with action: (e:
KeyboardEvent) => void and optional conditions: Array<(e: KeyboardEvent) =>
boolean>), change the Map type to Map<string, KeybindEntry>, and update
addKeybindAndEvent to accept an action and conditions with those explicit types
(use the symbol addKeybindAndEvent and keybindAndEvent to locate the code); also
update any code that reads from keybindAndEvent to use entry.action and
entry.conditions and adjust return/usage expectations accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/client/InputHandler.ts`:
- Around line 580-592: Rename the misspelled local variable
allConditionsFullfiled to allConditionsFulfilled in the loop inside the
InputHandler logic that iterates over this.keybindAndEvent (the block that uses
keybindMatchesEvent and item[1].slice(1)), updating every reference (assignment,
checks, and the continue branch) to the new name to keep readability consistent;
ensure the same corrected name is used throughout that function scope and no
other behavior changes are introduced.

---

Outside diff comments:
In `@src/client/InputHandler.ts`:
- Line 1: This file has Prettier style violations; run the formatter and commit
the changes by executing npx prettier --write src/client/InputHandler.ts (or run
the project's format script) to update formatting for the InputHandler module;
after formatting, verify that imports like EventBus and GameEvent and any
exported class/function in InputHandler.ts still compile and then re-run CI.

---

Nitpick comments:
In `@src/client/InputHandler.ts`:
- Around line 929-941: Fix the JSDoc typo ("exectued" → "executed") and replace
the fragile array convention used by keybindAndEvent with a typed object: define
a KeybindEntry (with action: (e: KeyboardEvent) => void and optional conditions:
Array<(e: KeyboardEvent) => boolean>), change the Map type to Map<string,
KeybindEntry>, and update addKeybindAndEvent to accept an action and conditions
with those explicit types (use the symbol addKeybindAndEvent and keybindAndEvent
to locate the code); also update any code that reads from keybindAndEvent to use
entry.action and entry.conditions and adjust return/usage expectations
accordingly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 09de9720-a581-40ca-9829-091e215d1987

📥 Commits

Reviewing files that changed from the base of the PR and between 1db02ac and d6b9cd9.

📒 Files selected for processing (1)
  • src/client/InputHandler.ts

Comment thread src/client/InputHandler.ts Outdated
@github-project-automation github-project-automation Bot moved this from Triage to Development in OpenFront Release Management Jun 11, 2026
@TKTK123456

Copy link
Copy Markdown
Contributor Author

@coderabbitai help

@coderabbitai

coderabbitai Bot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

CodeRabbit commands

These commands are invoked using PR/Issue comments.

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai rate limit to show your current review rate limit status.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai evaluate custom pre-merge check --instructions <custom-checks-instructions> --name <custom-checks-title> [--mode <error|warning>] to validate the custom pre-merge checks instructions. Defaults to error when --mode is omitted.
  • @coderabbitai ignore pre-merge checks to override pre-merge checks and get an approval on PR.
  • @coderabbitai run pre-merge checks to run pre-merge checks on the pull request.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai emit path instructions to emit generated path-specific review instructions for this repository.
  • @coderabbitai resolve merge conflict to automatically resolve merge conflicts.
  • @coderabbitai autofix to automatically fix issues identified in unresolved review comments.
  • @coderabbitai resolve to resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai generate configuration to create a PR that adds the current resolved configuration as .coderabbit.yaml (or show it if already present).
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore or @coderabbit ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit configuration file (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • You can also validate your configuration using the online YAML validator.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, support, documentation and community

  • Visit our status page to check the current availability of CodeRabbit.
  • Create a ticket on our support page for assistance with any issues or questions.
  • Visit our documentation site for detailed information on how to use CodeRabbit.
  • Join our Discord community to connect with other users and get help from the community.
  • Follow us on X/Twitter for updates and announcements.

@TKTK123456

Copy link
Copy Markdown
Contributor Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Full review finished.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/client/InputHandler.ts`:
- Around line 317-333: Prettier formatting errors are caused by the block that
defines and transforms buildKeybinds in InputHandler.ts; reformat this section
(variable buildKeybinds, the .map using this.keybinds, the push of numpad keys,
and the for-loop) to match the project's Prettier rules by running the formatter
(run `prettier --write src/client/InputHandler.ts`) or apply equivalent
formatting changes so the file passes CI.
- Around line 317-333: The build keybind registration only adds Numpad0..Numpad9
extras so pressing Digit1 when the keybind is set to Numpad1 bypasses the
fallback; update the registration logic in InputHandler (the buildKeybinds array
mapping and the subsequent push of extras) to also include the Digit0..Digit9
counterparts for each Numpad key (or add a small helper that, for any "NumpadX"
adds both "NumpadX" and "DigitX") so resolveBuildKeybind() will be reached on
both Numpad and Digit keyups; apply the same dual-registration change to the
analogous block around lines 335-347 to cover all build-related keybinds.
- Around line 299-301: Remove the debug console.log calls from the input hot
paths: delete the console.log("TogglePerformanceOverlayEvent") inside the
addKeybindAndEvent handler that emits TogglePerformanceOverlayEvent (and any
other console.log added in the same file during init, e.g., the one around line
334-335). Locate the usages of addKeybindAndEvent and the init/startup code in
InputHandler (search for the string "TogglePerformanceOverlayEvent" and
"console.log") and simply remove the console.log statements so the handler only
calls this.eventBus.emit(new TogglePerformanceOverlayEvent()) and initialization
code has no noisy logs.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: d0ddfca9-2f39-45ab-94f4-fd62e41f7d9b

📥 Commits

Reviewing files that changed from the base of the PR and between 1db02ac and d8e52eb.

📒 Files selected for processing (1)
  • src/client/InputHandler.ts

Comment thread src/client/InputHandler.ts
Comment thread src/client/InputHandler.ts
coderabbitai[bot]
coderabbitai Bot previously approved these changes Jun 12, 2026
@TKTK123456

Copy link
Copy Markdown
Contributor Author

@coderabbitai resume

@coderabbitai

coderabbitai Bot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Reviews resumed.

@iiamlewis

Copy link
Copy Markdown
Contributor

@TKTK123456 (via Discord):

okay

@Celant

Celant commented Jun 29, 2026

Copy link
Copy Markdown
Member

Thanks for the work on this — the refactor approach is sound and worth having. There are two confirmed gameplay regressions that need fixing before this can merge, plus two smaller items worth addressing.

Blocking

  1. selectAllWarships breaks when Shift is held — the old code used e.code === this.keybinds.selectAllWarships (shift-agnostic), but routing it through keybindMatchesEvent in the new loop now requires e.shiftKey === false. A player holding Shift for warship box-selection who presses F to select all warships will find nothing happens. Fix: add an (e) => !e.shiftKey condition to that addKeybindAndEvent call, or keep that one entry on the old plain-code check.

  2. AltRight (and other right-side modifier keys) no longer trigger the graphics refreshisAltKeyHeld used the browser's event.altKey flag, which is true for either physical Alt key. The replacement this.activeKeys.has(this.keybinds.altKey) only tracks the exact configured key code ("AltLeft"), so pressing physical AltRight silently does nothing. Same issue for ControlRight/ControlLeft, MetaRight/MetaLeft, etc. Fix: either add both left and right siblings to the activeKeys tracking list, or check event.altKey directly in the condition instead of going through activeKeys.

Non-blocking but worth fixing

  1. keybindAndEvent isn't cleared in destroy() — not a production bug today since a fresh InputHandler instance is constructed per game, but if initialize() were ever called twice on the same instance every handler would fire twice. A this.keybindAndEvent = [] at the top of initialize() would make it safe.

  2. Conflict bypass in UserSettingModal hardcodes "AltLeft" — the special-case logic that lets altKey and emojiMenuModifier share a key checks value === "AltLeft". A user who remaps altKey to "AltRight" and then tries to set emojiMenuModifier to "AltRight" will get a spurious conflict error. Replace the hardcoded string with value === activeKeybinds["altKey"] (and symmetric) so any shared value between the two is permitted.

Fix the two blocking items and this should be good to go.

@iiamlewis

Copy link
Copy Markdown
Contributor

@TKTK123456 (via Discord):

<@107073252286824448> the reason I didn't fix the selectAllWarship issue is so that there is no conflict because you can rebind shift f to something else as well

@iiamlewis

Copy link
Copy Markdown
Contributor

@TKTK123456 (via Discord):

so it would be two things using the shift f keybind

@iiamlewis

Copy link
Copy Markdown
Contributor

@Celant (via Discord):

As long as <@1334886860538904679> is happy with that caveat, then that's fine. Just sort number 2, and optionally 3 and 4, and we can get it merged :)

(For Lewis, this change basically means that Shift+F no longer 'accidentally' works and selects all warships. You have to explicitly let go of shift, or remap it to Shift+F intentionally. The current original behaviour is that it'll select all warships if you hit F, whether or not you're holding shift too)

@iiamlewis

Copy link
Copy Markdown
Contributor

@TKTK123456 (via Discord):

<@107073252286824448> fixed 2. 3 & 4

@TKTK123456

Copy link
Copy Markdown
Contributor Author

@coderabbitai resume

@coderabbitai

coderabbitai Bot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Reviews resumed.

coderabbitai[bot]
coderabbitai Bot previously approved these changes Jun 30, 2026
@Celant

Celant commented Jun 30, 2026

Copy link
Copy Markdown
Member

Almost there — just one small ask before merge. The fix for #4 added a second copy-pasted block for "AltRight", but the same result can be achieved with a single condition that covers any shared value:

if (
  (action === "emojiMenuModifier" && activeKeybinds["altKey"] === value) ||
  (action === "altKey" && activeKeybinds["emojiMenuModifier"] === value)
) {
  isEmojiMenuModAndAltKeyConflict = true;
}

This replaces both the "AltLeft" and "AltRight" blocks and correctly handles any value the two keys might share. Once that's in, we're good to merge.

@iiamlewis

Copy link
Copy Markdown
Contributor

@TKTK123456 (via Discord):

<@107073252286824448> the problem with that is that we only want the "AltLeft" and "AltRight" code to be bypassed

@iiamlewis

Copy link
Copy Markdown
Contributor

@TKTK123456 (via Discord):

so I am going to add && (value === "AltLeft" || "AltRight") to the end of the if statment

@iiamlewis

Copy link
Copy Markdown
Contributor

@Celant (via Discord):

Ah sorry, I see what you mean

@iiamlewis

Copy link
Copy Markdown
Contributor

@Celant (via Discord):

Yeah that works. Ping once that's pushed and I'll merge

@iiamlewis

Copy link
Copy Markdown
Contributor

@TKTK123456 (via Discord):

<@107073252286824448> pushed

@iiamlewis

Copy link
Copy Markdown
Contributor

@Celant (via Discord):

Sweet, just waiting for CI then I'll merge

@iiamlewis

Copy link
Copy Markdown
Contributor

@TKTK123456 (via Discord):

okay

@iiamlewis

Copy link
Copy Markdown
Contributor

@TKTK123456 (via Discord):

the CI is done

@github-project-automation github-project-automation Bot moved this from Development to Final Review in OpenFront Release Management Jun 30, 2026
@Celant Celant added this pull request to the merge queue Jun 30, 2026
Merged via the queue into openfrontio:main with commit 0d2179f Jun 30, 2026
10 checks passed
@github-project-automation github-project-automation Bot moved this from Final Review to Complete in OpenFront Release Management Jun 30, 2026
@TKTK123456 TKTK123456 deleted the InputHandler.ts-Rework branch June 30, 2026 14:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Complete

Development

Successfully merging this pull request may close these issues.

InputHandler.ts rework

5 participants