Skip to content

Fix: Missing binds in settings#3963

Open
sardidefcon wants to merge 4 commits into
openfrontio:mainfrom
sardidefcon:fix-rebind-certain-keys
Open

Fix: Missing binds in settings#3963
sardidefcon wants to merge 4 commits into
openfrontio:mainfrom
sardidefcon:fix-rebind-certain-keys

Conversation

@sardidefcon
Copy link
Copy Markdown
Contributor

@sardidefcon sardidefcon commented May 18, 2026

If this PR fixes an issue, link it below. If not, delete these two lines.
Resolves #3962

Description:

Settings have been added to allow binding keys that could not be customized.

The following actions are now configurable from the keybinds settings menu:

  • Reset Graphics (previously hardcoded to Alt+R)
graphics
  • Select All Warships (previously hardcoded to F)
  • Warship Box Select (previously hardcoded to Shift+LeftClick)
warships

I've encountered several errors when trying to bind key combinations with Alt+
To support Alt+ key combinations, the keybind system was extended:

  • The keybind parser and event matcher now handle Alt+ prefixes alongside the existing Shift+ support
  • The keybind capture component now records Alt+Key combinations correctly

When I was testing it, I realized that using Alt+Key typed special characters, so:

  • Special characters produced by Alt+Key on certain keyboards and OS layouts (e.g. Alt+R®) are prevented by using the physical key code instead of the character value

Mouse click binding

Additionally, I noticed that it wasn't possible to bind mouse clicks (Left Click or Right Click). I've fixed this by making mouse clicks bindable, but limiting it to only being bound with a specific key combination
(e.g. Shift+Left or Alt+Right)

The behavior is a bit erratic; I've tried to correct several aspects so that it works. Clicking on the "bind box" resets the function to bind the key, forcing you to click outside of it. I've fixed this, and now the only way to bind a Key+Click is by clicking directly on this "bind box."

When it came to binding the right click, the classic browser options menu would open. I've added a flag to prevent this from happening so that the right click can be bound correctly.

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
  • 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:

sardidefcon

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 18, 2026

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: 50cf38d9-e867-46bf-a71d-cc8681c98640

📥 Commits

Reviewing files that changed from the base of the PR and between de4458e and ca67d5a.

📒 Files selected for processing (3)
  • resources/lang/en.json
  • src/client/InputHandler.ts
  • tests/InputHandler.test.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • resources/lang/en.json
  • tests/InputHandler.test.ts
  • src/client/InputHandler.ts

Walkthrough

Adds configurable keybinds for graphics reset, select-all warships, and box-select hold; implements Alt+ parsing/display/capture, updates InputHandler behavior and defaults, adds UI controls, localization strings, and tests.

Changes

Keybind customization

Layer / File(s) Summary
Keybind parsing & display formatting
src/client/InputHandler.ts, src/client/Utils.ts
Parse Shift+ and Alt+ prefixes into { shift, alt, code } and format Alt+-prefixed keys for UI display.
SettingKeybind capture UI & mouse-binding
src/client/components/baseComponents/setting/SettingKeybind.ts
Start capture on mousedown, suppress contextmenu for right-click capture, support Shift/Alt + mouse buttons, and normalize stored/display values for modifier binds.
InputHandler integration and behavior
src/client/InputHandler.ts
Add shiftKeybindHeld state; use keybind matching for keyboard/pointer actions; skip pan/drag while box-select held; dispatch pointer-keybind actions early; update reset/select-all checks to use keybind utilities (default Alt+KeyR).
UserSettingModal UI & defaults
src/client/UserSettingModal.ts, src/core/game/UserSettings.ts
Add resetGfx, selectAllWarships, and shiftKey keybind controls in settings modal; change resetGfx default to Alt+KeyR.
Localization
resources/lang/en.json
Add English labels and descriptions for user_setting.reset_gfx, user_setting.reset_gfx_desc, user_setting.shift_key, user_setting.shift_key_desc, user_setting.select_all_warships, and user_setting.select_all_warships_desc.
Tests
tests/InputHandler.test.ts, tests/core/game/UserSettingsKeybinds.test.ts
Update shift-drag tests to dispatch ShiftLeft keyboard events; add tests asserting default keybind strings and platform-aware modifierKey behavior.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

Keys once fixed like anchors in sand,
Alt and Shift now answer your hand.
Capture on press, display made plain,
Rebind the controls — ships steer again. 🎮✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.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 'Fix: Missing binds in settings' accurately summarizes the main change: exposing previously hardcoded keybinds (Reset Graphics, Select All Warships, Warship Box Select) as configurable settings.
Description check ✅ Passed The description is comprehensive and directly related to the changeset, detailing which keys are now configurable, how Alt+ support was added, mouse click binding implementation, and special character handling.
Linked Issues check ✅ Passed The PR fully addresses #3962 by making Alt+R (Reset Graphics), F (Select All Warships), and Shift+LeftClick (Warship Box Select) configurable through the keybinds settings menu, resolving the reported inability to rebind these hardcoded keys.
Out of Scope Changes check ✅ Passed All changes are in scope: keybind system enhancements to support Alt+ and mouse bindings, UI updates to keybind settings, localization strings for new settings, tests for new functionality, and configuration of the three previously hardcoded actions.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


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 and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

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 877-885: The new keybindMatchesEvent supports modifiers but
several runtime checks (notably the selectAllWarships handler and any places
using a raw shiftKey comparison) still compare only e.code, so saved combos with
Alt+/Shift+ never fire; update those checks to use keybindMatchesEvent (or
parseKeybind + compare shift/alt) against the configured keybind string instead
of raw e.code—specifically replace any direct e.code or e.shiftKey/e.altKey
comparisons in the selectAllWarships logic and the shiftKey check with calls to
keybindMatchesEvent(event, configuredKeybind) so modifier-aware bindings are
honored.

In `@src/client/UserSettingModal.ts`:
- Around line 651-669: The new warship keybind controls allow modifier combos
that the runtime doesn't support; update the keybind-saving flow to
validate/normalize binds for the affected actions (e.g.,
action="selectAllWarships" and action="shiftKey") by changing
handleKeybindChange to detect modifier-inclusive combos and either strip
modifiers or reject them (fallback to this.defaultKeybinds.selectAllWarships)
before persisting, and ensure getKeyValue/getKeyChar are consistent with that
normalized format so saved values cannot be a modifier-only or
modifier-combination that won’t match at runtime.

In `@src/core/game/UserSettings.ts`:
- Line 36: Change introduces a default keybind change for the resetGfx key
(symbol: resetGfx) on the UserSettings default map; add a unit test that asserts
the new default (e.g., "Alt+KeyR") is present in the UserSettings defaults and
that any consumer logic reading UserSettings.defaultKeybinds (or the
UserSettings class/constructor) returns the updated value. Place the test
alongside existing core tests for UserSettings (or create one in the same test
suite) and include an assertion that deserializing/loading UserSettings
preserves the new default keybind so CI catches regressions.
🪄 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: 27f5d38e-6764-452e-b3c9-ab9e01c6936f

📥 Commits

Reviewing files that changed from the base of the PR and between 2e17fb5 and 7b853a8.

📒 Files selected for processing (6)
  • resources/lang/en.json
  • src/client/InputHandler.ts
  • src/client/UserSettingModal.ts
  • src/client/Utils.ts
  • src/client/components/baseComponents/setting/SettingKeybind.ts
  • src/core/game/UserSettings.ts

Comment thread src/client/InputHandler.ts
Comment on lines +651 to +669
<setting-keybind
action="selectAllWarships"
label=${translateText("user_setting.select_all_warships")}
description=${translateText("user_setting.select_all_warships_desc")}
.defaultKey=${this.defaultKeybinds.selectAllWarships}
.value=${this.getKeyValue("selectAllWarships")}
.display=${this.getKeyChar("selectAllWarships")}
@change=${this.handleKeybindChange}
></setting-keybind>

<setting-keybind
action="shiftKey"
label=${translateText("user_setting.shift_key")}
description=${translateText("user_setting.shift_key_desc")}
.defaultKey=${this.defaultKeybinds.shiftKey}
.value=${this.getKeyValue("shiftKey")}
.display=${this.getKeyChar("shiftKey")}
@change=${this.handleKeybindChange}
></setting-keybind>
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.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

New warship keybind settings can save combos that gameplay may not execute.

These new controls accept modifier combos, but runtime matching for these actions is still not fully modifier-aware. Users can configure valid-looking binds that won’t trigger.

🤖 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/UserSettingModal.ts` around lines 651 - 669, The new warship
keybind controls allow modifier combos that the runtime doesn't support; update
the keybind-saving flow to validate/normalize binds for the affected actions
(e.g., action="selectAllWarships" and action="shiftKey") by changing
handleKeybindChange to detect modifier-inclusive combos and either strip
modifiers or reject them (fallback to this.defaultKeybinds.selectAllWarships)
before persisting, and ensure getKeyValue/getKeyChar are consistent with that
normalized format so saved values cannot be a modifier-only or
modifier-combination that won’t match at runtime.

Comment thread src/core/game/UserSettings.ts
@github-project-automation github-project-automation Bot moved this from Triage to Development in OpenFront Release Management May 18, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

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)

449-455: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Fix shiftKey keybind default to prevent activation failure.

keybindMatchesEvent checks e.shiftKey === parsed.shift. The default "ShiftLeft" parses as {shift: false, alt: false, code: "ShiftLeft"}. When pressing Shift, the event has e.shiftKey = true, but parsed.shift = false, so the condition fails and box-select mode never activates.

Change the default to "Shift+ShiftLeft" or use a different key binding that works with the current logic, such as "KeyB" (with a Shift+ prefix if shift-modification is needed).

🤖 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 449 - 455, The shift keybind default
is incorrect: update the default keybind used by InputHandler so parsed.shift is
true (e.g., change the default from "ShiftLeft" to "Shift+ShiftLeft" or pick a
different binding like "KeyB"/"Shift+KeyB") so keybindMatchesEvent(e, ...) will
succeed; then verify behavior in methods keybindMatchesEvent, the shift handling
block that sets shiftKeybindHeld, the uiState.ghostStructure check that calls
setGhostStructure(null), and the canvas.style.cursor change to "crosshair" still
work as expected.
♻️ Duplicate comments (1)
src/client/InputHandler.ts (1)

524-527: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Use keybindMatchesEvent for selectAllWarships to support modifiers.

This still uses raw e.code comparison. If the user configures selectAllWarships as Alt+KeyF or Shift+KeyF, it will never trigger because modifiers aren't checked.

Fix with modifier-aware matching
-      if (e.code === this.keybinds.selectAllWarships) {
+      if (this.keybindMatchesEvent(e, this.keybinds.selectAllWarships)) {
         e.preventDefault();
         this.eventBus.emit(new SelectAllWarshipsEvent());
       }
🤖 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 524 - 527, Replace the raw e.code
comparison for the selectAllWarships keybind with the modifier-aware helper: use
keybindMatchesEvent(this.keybinds.selectAllWarships, e) inside InputHandler (the
block that currently checks e.code === this.keybinds.selectAllWarships), and
keep the existing e.preventDefault() and this.eventBus.emit(new
SelectAllWarshipsEvent()) when it returns true so configured modifiers
(Alt/Shift/Ctrl) are respected.
🧹 Nitpick comments (1)
src/client/components/baseComponents/setting/SettingKeybind.ts (1)

122-133: ⚖️ Poor tradeoff

Consider consistent display formatting for Alt+ bindings.

Shift+ displays Shift+B (using e.key), but Alt+ displays Alt+KeyR (using e.code). This inconsistency is intentional to avoid special characters, but might confuse users who see key names for Shift+ and code names for Alt+.

If formatKeyForDisplay() in Utils handles this, ignore this comment. Otherwise, consider extracting the letter from codes like KeyRR for consistent display.

🤖 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/components/baseComponents/setting/SettingKeybind.ts` around lines
122 - 133, In SettingKeybind (the block building code/displayKey using e.code
and e.key) the Alt+ branch uses e.code (e.g. "KeyR") while Shift+ uses e.key
(e.g. "B"), causing inconsistent UX; update the Alt+ formatting to produce a
consistent human-readable display by normalizing e.code (strip common prefixes
like "Key"/"Digit"/"Numpad" to the actual character) or call the shared helper
formatKeyForDisplay() if available, so displayKey for Alt+ bindings becomes
"Alt+R" instead of "Alt+KeyR" while keeping code as `Alt+${e.code}` and
preserving existing behavior for other branches.
🤖 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 915-973: The swapDirection pointer action currently emits
SwapRocketDirectionEvent(true) which forces upward direction; change the action
in dispatchPointerKeybindActions for keybinds.swapDirection to emit new
SwapRocketDirectionEvent(!this.uiState.rocketDirectionUp) so the pointer binding
toggles the rocket direction the same way the keyboard handler does (see the
keyboard toggle that reads this.uiState.rocketDirectionUp).
- Around line 895-899: The MOUSE_BUTTON_NAMES map currently exposes button 2
("MouseRight") and keybindMatchesPointerEvent() does not filter it, allowing
right-clicks to be recorded as keybinds; update the code so right-click is
excluded by removing the 2: "MouseRight" entry from MOUSE_BUTTON_NAMES and/or
add an explicit guard in keybindMatchesPointerEvent() to return false when
event.button === 2, ensuring only MouseLeft (0) and MouseMiddle (1) are
considered for keybind matching.

---

Outside diff comments:
In `@src/client/InputHandler.ts`:
- Around line 449-455: The shift keybind default is incorrect: update the
default keybind used by InputHandler so parsed.shift is true (e.g., change the
default from "ShiftLeft" to "Shift+ShiftLeft" or pick a different binding like
"KeyB"/"Shift+KeyB") so keybindMatchesEvent(e, ...) will succeed; then verify
behavior in methods keybindMatchesEvent, the shift handling block that sets
shiftKeybindHeld, the uiState.ghostStructure check that calls
setGhostStructure(null), and the canvas.style.cursor change to "crosshair" still
work as expected.

---

Duplicate comments:
In `@src/client/InputHandler.ts`:
- Around line 524-527: Replace the raw e.code comparison for the
selectAllWarships keybind with the modifier-aware helper: use
keybindMatchesEvent(this.keybinds.selectAllWarships, e) inside InputHandler (the
block that currently checks e.code === this.keybinds.selectAllWarships), and
keep the existing e.preventDefault() and this.eventBus.emit(new
SelectAllWarshipsEvent()) when it returns true so configured modifiers
(Alt/Shift/Ctrl) are respected.

---

Nitpick comments:
In `@src/client/components/baseComponents/setting/SettingKeybind.ts`:
- Around line 122-133: In SettingKeybind (the block building code/displayKey
using e.code and e.key) the Alt+ branch uses e.code (e.g. "KeyR") while Shift+
uses e.key (e.g. "B"), causing inconsistent UX; update the Alt+ formatting to
produce a consistent human-readable display by normalizing e.code (strip common
prefixes like "Key"/"Digit"/"Numpad" to the actual character) or call the shared
helper formatKeyForDisplay() if available, so displayKey for Alt+ bindings
becomes "Alt+R" instead of "Alt+KeyR" while keeping code as `Alt+${e.code}` and
preserving existing behavior for other branches.
🪄 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: 07c23345-6aae-4037-a48f-857cd2fd436e

📥 Commits

Reviewing files that changed from the base of the PR and between 7b853a8 and f2949fb.

📒 Files selected for processing (3)
  • src/client/InputHandler.ts
  • src/client/Utils.ts
  • src/client/components/baseComponents/setting/SettingKeybind.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/client/Utils.ts

Comment on lines +895 to +899
private static readonly MOUSE_BUTTON_NAMES: Record<number, string> = {
0: "MouseLeft",
1: "MouseMiddle",
2: "MouseRight",
};
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.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search for tests covering MouseRight keybind behavior
rg -n 'MouseRight.*keybind|keybind.*MouseRight' --type=ts

# Check if MouseRight is exposed in UI defaults
rg -n 'MouseRight' src/core/game/UserSettings.ts src/client/UserSettingModal.ts

Repository: openfrontio/OpenFrontIO

Length of output: 49


🏁 Script executed:

# Find all usages of MOUSE_BUTTON_NAMES
rg -n 'MOUSE_BUTTON_NAMES' src/client/ --type=ts

# Check how keybind actions are initialized and filtered
rg -n 'keybind.*action|action.*keybind' src/client/InputHandler.ts --type=ts -A 3

# Look for context menu handling that might conflict with MouseRight
rg -n 'contextmenu|context.menu|rightclick|right.click' src/client/ --type=ts -i

Repository: openfrontio/OpenFrontIO

Length of output: 3796


🏁 Script executed:

# Find keybindMatchesPointerEvent implementation
rg -n 'keybindMatchesPointerEvent' src/client/InputHandler.ts -A 20

# Check if there's filtering of button 2 in keybind logic
rg -n 'e\.button|button.*2|MouseRight' src/client/InputHandler.ts -B 2 -A 2

# Look for keybind defaults/configuration
rg -n 'keybind.*default|default.*keybind' src/core/game/UserSettings.ts -A 3

Repository: openfrontio/OpenFrontIO

Length of output: 2031


🏁 Script executed:

# Check keybind defaults in UserSettings
rg -n 'keybinds|Keybind' src/core/game/UserSettings.ts -A 2 -B 2

# Look for any MouseRight in default keybinds
rg -n 'MouseRight' src/core/game/ --type=ts

# Check what keybinds are actually bound by default
rg -n 'boatAttack|boatMove' src/core/game/UserSettings.ts

Repository: openfrontio/OpenFrontIO

Length of output: 1566


🏁 Script executed:

# Get the full getDefaultKeybinds function
rg -n 'export function getDefaultKeybinds' src/core/game/UserSettings.ts -A 50

# Check if any default keybinds use mouse buttons
rg -n 'MouseLeft|MouseMiddle|MouseRight' src/core/game/UserSettings.ts

Repository: openfrontio/OpenFrontIO

Length of output: 1731


Remove MouseRight from keybind support to match established constraints.

The MOUSE_BUTTON_NAMES constant includes button 2 (MouseRight), and keybindMatchesPointerEvent() has no filtering, allowing MouseRight to be recorded and matched as a keybind action. This violates the established pattern: only MouseLeft and MouseMiddle should be supported for keybind actions. MouseRight must be reserved to prevent conflicts with context menu behavior.

Remove the MouseRight entry from MOUSE_BUTTON_NAMES or add filtering in keybindMatchesPointerEvent() to skip button 2.

🤖 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 895 - 899, The MOUSE_BUTTON_NAMES
map currently exposes button 2 ("MouseRight") and keybindMatchesPointerEvent()
does not filter it, allowing right-clicks to be recorded as keybinds; update the
code so right-click is excluded by removing the 2: "MouseRight" entry from
MOUSE_BUTTON_NAMES and/or add an explicit guard in keybindMatchesPointerEvent()
to return false when event.button === 2, ensuring only MouseLeft (0) and
MouseMiddle (1) are considered for keybind matching.

Comment on lines +915 to 973
private dispatchPointerKeybindActions(event: PointerEvent): boolean {
const actions: Array<[string, () => void]> = [
[
this.keybinds.boatAttack,
() => this.eventBus.emit(new DoBoatAttackEvent()),
],
[
this.keybinds.groundAttack,
() => this.eventBus.emit(new DoGroundAttackEvent()),
],
[
this.keybinds.retaliateAttack,
() => this.eventBus.emit(new DoRetaliateAttackEvent()),
],
[
this.keybinds.requestAlliance,
() => this.eventBus.emit(new DoRequestAllianceEvent()),
],
[
this.keybinds.breakAlliance,
() => this.eventBus.emit(new DoBreakAllianceEvent()),
],
[
this.keybinds.swapDirection,
() => this.eventBus.emit(new SwapRocketDirectionEvent(true)),
],
[
this.keybinds.selectAllWarships,
() => this.eventBus.emit(new SelectAllWarshipsEvent()),
],
[
this.keybinds.centerCamera,
() => this.eventBus.emit(new CenterCameraEvent()),
],
[
this.keybinds.pauseGame,
() => this.eventBus.emit(new TogglePauseIntentEvent()),
],
[
this.keybinds.gameSpeedUp,
() => this.eventBus.emit(new GameSpeedUpIntentEvent()),
],
[
this.keybinds.gameSpeedDown,
() => this.eventBus.emit(new GameSpeedDownIntentEvent()),
],
[
this.keybinds.resetGfx ?? "Alt+KeyR",
() => this.eventBus.emit(new RefreshGraphicsEvent()),
],
];
for (const [keybind, action] of actions) {
if (this.keybindMatchesPointerEvent(event, keybind)) {
action();
return true;
}
}
return false;
}
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.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Fix swapDirection to toggle instead of forcing true.

Line 939 hardcodes true, but the keyboard handler at line 550 toggles based on !this.uiState.rocketDirectionUp. Mouse and keyboard bindings should have identical behavior.

Proposed fix
       [
         this.keybinds.swapDirection,
-        () => this.eventBus.emit(new SwapRocketDirectionEvent(true)),
+        () => {
+          const nextDirection = !this.uiState.rocketDirectionUp;
+          this.eventBus.emit(new SwapRocketDirectionEvent(nextDirection));
+        },
       ],
🤖 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 915 - 973, The swapDirection pointer
action currently emits SwapRocketDirectionEvent(true) which forces upward
direction; change the action in dispatchPointerKeybindActions for
keybinds.swapDirection to emit new
SwapRocketDirectionEvent(!this.uiState.rocketDirectionUp) so the pointer binding
toggles the rocket direction the same way the keyboard handler does (see the
keyboard toggle that reads this.uiState.rocketDirectionUp).

@sardidefcon
Copy link
Copy Markdown
Contributor Author

@coderabbitai full review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 18, 2026

✅ Actions performed

Full review triggered.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (2)
tests/core/game/UserSettingsKeybinds.test.ts (2)

14-16: 💤 Low value

Consider testing both platform modes for consistency.

Same observation as the selectAllWarships test above—testing both platform flags would improve consistency with the resetGfx and modifierKey tests.

📝 Suggested addition
 test("shiftKey (warship box select) defaults to ShiftLeft", () => {
   expect(getDefaultKeybinds(false).shiftKey).toBe("ShiftLeft");
+  expect(getDefaultKeybinds(true).shiftKey).toBe("ShiftLeft");
 });
🤖 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 `@tests/core/game/UserSettingsKeybinds.test.ts` around lines 14 - 16, The test
only asserts getDefaultKeybinds(false).shiftKey; add the same assertion for the
other platform mode to ensure consistency: call
getDefaultKeybinds(true).shiftKey and expect it toBe("ShiftLeft") (referencing
the test in UserSettingsKeybinds.test.ts and the getDefaultKeybinds function) so
both platform flags are covered like the other tests (resetGfx, modifierKey).

10-12: 💤 Low value

Consider testing both platform modes for consistency.

The resetGfx test above checks both getDefaultKeybinds(false) and getDefaultKeybinds(true), but this test only checks false. While selectAllWarships likely doesn't vary by platform, testing both would make the test suite more consistent and future-proof against platform-specific changes.

📝 Suggested addition
 test("selectAllWarships defaults to KeyF", () => {
   expect(getDefaultKeybinds(false).selectAllWarships).toBe("KeyF");
+  expect(getDefaultKeybinds(true).selectAllWarships).toBe("KeyF");
 });
🤖 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 `@tests/core/game/UserSettingsKeybinds.test.ts` around lines 10 - 12, The test
only asserts getDefaultKeybinds(false).selectAllWarships; update the
"selectAllWarships defaults to KeyF" test to assert both platform modes by also
calling getDefaultKeybinds(true).selectAllWarships and expecting "KeyF" so the
spec checks both platform variants (referencing getDefaultKeybinds and the
selectAllWarships property).
🤖 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 579-586: The keyup handler only compares e.code to
parsedShiftKey.code so combo binds like "Alt+KeyR" latch if the modifier is
released first; update the logic in the InputHandler keyup branch (where
parseKeybind(this.keybinds.shiftKey) is used and shiftKeybindHeld is set) to
also detect when the modifier is no longer held (instead of only matching
e.code). Concretely, after getting parsedShiftKey from parseKeybind, clear
shiftKeybindHeld and reset the cursor when either e.code === parsedShiftKey.code
OR the modifier state for that bind is false (use
e.getModifierState(parsedShiftKey.modifier) or the relevant event property like
e.altKey/e.ctrlKey/e.metaKey as appropriate), and keep the existing guard that
selectionBoxActive and multiSelectionActive prevent resetting. Ensure you
reference parseKeybind, keybinds.shiftKey, shiftKeybindHeld, selectionBoxActive
and multiSelectionActive when making the change.
- Around line 217-218: The flag shiftKeybindHeld can remain true if the window
blurs while the hold key is down; update the existing blur cleanup block (the
blur/visibilitychange handler that clears other transient input state) to
explicitly set this.shiftKeybindHeld = false so the boxed-select/pan-drag mode
is reset when focus returns.

---

Nitpick comments:
In `@tests/core/game/UserSettingsKeybinds.test.ts`:
- Around line 14-16: The test only asserts getDefaultKeybinds(false).shiftKey;
add the same assertion for the other platform mode to ensure consistency: call
getDefaultKeybinds(true).shiftKey and expect it toBe("ShiftLeft") (referencing
the test in UserSettingsKeybinds.test.ts and the getDefaultKeybinds function) so
both platform flags are covered like the other tests (resetGfx, modifierKey).
- Around line 10-12: The test only asserts
getDefaultKeybinds(false).selectAllWarships; update the "selectAllWarships
defaults to KeyF" test to assert both platform modes by also calling
getDefaultKeybinds(true).selectAllWarships and expecting "KeyF" so the spec
checks both platform variants (referencing getDefaultKeybinds and the
selectAllWarships property).
🪄 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: b432229c-810d-4c0d-baf7-c656279e5f30

📥 Commits

Reviewing files that changed from the base of the PR and between 2e17fb5 and de4458e.

📒 Files selected for processing (8)
  • resources/lang/en.json
  • src/client/InputHandler.ts
  • src/client/UserSettingModal.ts
  • src/client/Utils.ts
  • src/client/components/baseComponents/setting/SettingKeybind.ts
  • src/core/game/UserSettings.ts
  • tests/InputHandler.test.ts
  • tests/core/game/UserSettingsKeybinds.test.ts

Comment on lines +217 to +218
// True while the configured shiftKey (box-select hold key) is held down
private shiftKeybindHeld: boolean = false;
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.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Reset shiftKeybindHeld on blur to prevent stuck input mode.

If the window blurs while the hold key is down, this flag can stay true and keep pan-drag blocked after focus returns. Clear it in the existing blur cleanup block with the other transient input state.

Proposed fix
     window.addEventListener("blur", () => {
       this.activeKeys.clear();
+      this.shiftKeybindHeld = false;
       if (this.alternateView) {
         this.alternateView = false;
         this.eventBus.emit(new AlternateViewEvent(false));
       }
🤖 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 217 - 218, The flag shiftKeybindHeld
can remain true if the window blurs while the hold key is down; update the
existing blur cleanup block (the blur/visibilitychange handler that clears other
transient input state) to explicitly set this.shiftKeybindHeld = false so the
boxed-select/pan-drag mode is reset when focus returns.

Comment on lines +579 to 586
// Reset crosshair when box-select key is released (unless selection box or multi-selection still active)
const parsedShiftKey = this.parseKeybind(this.keybinds.shiftKey);
if (e.code === parsedShiftKey.code) {
this.shiftKeybindHeld = false;
if (!this.selectionBoxActive && !this.multiSelectionActive) {
this.canvas.style.cursor = "";
}
}
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.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Release logic should also handle modifier-first keyup for combo binds.

This reset checks only e.code === parsedShiftKey.code. For binds like Alt+KeyR, releasing Alt first leaves shiftKeybindHeld latched until KeyR is released.

🤖 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 579 - 586, The keyup handler only
compares e.code to parsedShiftKey.code so combo binds like "Alt+KeyR" latch if
the modifier is released first; update the logic in the InputHandler keyup
branch (where parseKeybind(this.keybinds.shiftKey) is used and shiftKeybindHeld
is set) to also detect when the modifier is no longer held (instead of only
matching e.code). Concretely, after getting parsedShiftKey from parseKeybind,
clear shiftKeybindHeld and reset the cursor when either e.code ===
parsedShiftKey.code OR the modifier state for that bind is false (use
e.getModifierState(parsedShiftKey.modifier) or the relevant event property like
e.altKey/e.ctrlKey/e.metaKey as appropriate), and keep the existing guard that
selectionBoxActive and multiSelectionActive prevent resetting. Ensure you
reference parseKeybind, keybinds.shiftKey, shiftKeybindHeld, selectionBoxActive
and multiSelectionActive when making the change.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Development

Development

Successfully merging this pull request may close these issues.

Unable to Rebind Certain Keys

1 participant