mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-07-14 18:06:37 +00:00
Enhance InputHandler to allow using NumPad (#3317)
## Description: Adds **Enter** and **Numpad Enter** as confirmation for placing a ghost structure after selecting a building with hotkeys (1–0 or numpad). Players can cancel with Esc but previously had to click to confirm; they can now confirm with Enter or Numpad Enter at the current cursor position. This supports keyboard-only or mouse + numpad workflows (e.g. one hand on numpad for select + confirm, one on mouse for aiming). ## 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: .wozniakpl
This commit is contained in:
@@ -17,6 +17,7 @@ import { TileRef } from "../../../core/game/GameMap";
|
||||
import { GameUpdateType } from "../../../core/game/GameUpdates";
|
||||
import { GameView, UnitView } from "../../../core/game/GameView";
|
||||
import {
|
||||
ConfirmGhostStructureEvent,
|
||||
GhostStructureChangedEvent,
|
||||
MouseMoveEvent,
|
||||
MouseUpEvent,
|
||||
@@ -43,6 +44,11 @@ import {
|
||||
} from "./StructureDrawingUtils";
|
||||
import bitmapFont from "/fonts/round_6x6_modified.xml?url";
|
||||
|
||||
/** True for nuke types (AtomBomb, HydrogenBomb): ghost is preserved after placement so user can place multiple or keep selection (Enter/key confirm). */
|
||||
export function shouldPreserveGhostAfterBuild(unitType: UnitType): boolean {
|
||||
return unitType === UnitType.AtomBomb || unitType === UnitType.HydrogenBomb;
|
||||
}
|
||||
|
||||
extend([a11yPlugin]);
|
||||
|
||||
class StructureRenderInfo {
|
||||
@@ -92,6 +98,7 @@ export class StructureIconsLayer implements Layer {
|
||||
> = new Map(Structures.types.map((type) => [type, { visible: true }]));
|
||||
private lastGhostQueryAt: number;
|
||||
private visibilityStateDirty = true;
|
||||
private pendingConfirm: MouseUpEvent | null = null;
|
||||
private hasHiddenStructure = false;
|
||||
potentialUpgrade: StructureRenderInfo | undefined;
|
||||
|
||||
@@ -171,7 +178,12 @@ export class StructureIconsLayer implements Layer {
|
||||
);
|
||||
this.eventBus.on(MouseMoveEvent, (e) => this.moveGhost(e));
|
||||
|
||||
this.eventBus.on(MouseUpEvent, (e) => this.createStructure(e));
|
||||
this.eventBus.on(MouseUpEvent, (e) => this.requestConfirmStructure(e));
|
||||
this.eventBus.on(ConfirmGhostStructureEvent, () =>
|
||||
this.requestConfirmStructure(
|
||||
new MouseUpEvent(this.mousePos.x, this.mousePos.y),
|
||||
),
|
||||
);
|
||||
|
||||
window.addEventListener("resize", () => this.resizeCanvas());
|
||||
await this.setupRenderer();
|
||||
@@ -307,7 +319,10 @@ export class StructureIconsLayer implements Layer {
|
||||
this.ghostUnit.container.filters = [];
|
||||
}
|
||||
|
||||
if (!this.ghostUnit) return;
|
||||
if (!this.ghostUnit) {
|
||||
this.pendingConfirm = null;
|
||||
return;
|
||||
}
|
||||
|
||||
const unit = buildables.find(
|
||||
(u) => u.type === this.ghostUnit!.buildableUnit.type,
|
||||
@@ -322,6 +337,7 @@ export class StructureIconsLayer implements Layer {
|
||||
this.ghostUnit.container.filters = [
|
||||
new OutlineFilter({ thickness: 2, color: "rgba(255, 0, 0, 1)" }),
|
||||
];
|
||||
this.pendingConfirm = null;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -369,6 +385,14 @@ export class StructureIconsLayer implements Layer {
|
||||
: Math.min(1, scale / ICON_SCALE_FACTOR_ZOOMED_OUT);
|
||||
this.ghostUnit.container.scale.set(s);
|
||||
this.ghostUnit.range?.scale.set(this.transformHandler.scale);
|
||||
|
||||
if (this.pendingConfirm !== null) {
|
||||
const ev = this.pendingConfirm;
|
||||
this.pendingConfirm = null;
|
||||
if (this.isGhostReadyForConfirm()) {
|
||||
this.createStructure(ev);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -399,6 +423,30 @@ export class StructureIconsLayer implements Layer {
|
||||
.fill({ color: 0x000000, alpha: 0.65 });
|
||||
}
|
||||
|
||||
/**
|
||||
* True when the ghost exists and buildableUnit has been refreshed (canBuild or canUpgrade set).
|
||||
* Used to avoid running createStructure before renderGhost's async buildables() has updated the ghost.
|
||||
*/
|
||||
private isGhostReadyForConfirm(): boolean {
|
||||
if (!this.ghostUnit) return false;
|
||||
const bu = this.ghostUnit.buildableUnit;
|
||||
return bu.canBuild !== false || bu.canUpgrade !== false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Request confirm (place/upgrade): run createStructure now if ghost is ready, otherwise defer until
|
||||
* renderGhost's buildables() callback has updated the ghost. Shared by Enter (ConfirmGhostStructureEvent)
|
||||
* and mouse click (MouseUpEvent) so numpad-select-then-confirm works.
|
||||
*/
|
||||
private requestConfirmStructure(e: MouseUpEvent): void {
|
||||
if (!this.ghostUnit && !this.uiState.ghostStructure) return;
|
||||
if (this.isGhostReadyForConfirm()) {
|
||||
this.createStructure(e);
|
||||
} else {
|
||||
this.pendingConfirm = e;
|
||||
}
|
||||
}
|
||||
|
||||
private createStructure(e: MouseUpEvent) {
|
||||
if (!this.ghostUnit) return;
|
||||
if (
|
||||
@@ -420,6 +468,7 @@ export class StructureIconsLayer implements Layer {
|
||||
this.ghostUnit.buildableUnit.type,
|
||||
),
|
||||
);
|
||||
this.removeGhostStructure();
|
||||
} else if (this.ghostUnit.buildableUnit.canBuild) {
|
||||
const unitType = this.ghostUnit.buildableUnit.type;
|
||||
const rocketDirectionUp =
|
||||
@@ -433,8 +482,12 @@ export class StructureIconsLayer implements Layer {
|
||||
rocketDirectionUp,
|
||||
),
|
||||
);
|
||||
if (!shouldPreserveGhostAfterBuild(unitType)) {
|
||||
this.removeGhostStructure();
|
||||
}
|
||||
} else {
|
||||
this.removeGhostStructure();
|
||||
}
|
||||
this.removeGhostStructure();
|
||||
}
|
||||
|
||||
private moveGhost(e: MouseMoveEvent) {
|
||||
@@ -489,6 +542,7 @@ export class StructureIconsLayer implements Layer {
|
||||
}
|
||||
|
||||
private clearGhostStructure() {
|
||||
this.pendingConfirm = null;
|
||||
if (this.ghostUnit) {
|
||||
this.ghostUnit.container.destroy();
|
||||
this.ghostUnit.range?.destroy();
|
||||
|
||||
Reference in New Issue
Block a user