diff --git a/.gitignore b/.gitignore index 08efa873a..b84cea885 100644 --- a/.gitignore +++ b/.gitignore @@ -1,21 +1,15 @@ -# Folders -.claude/ -.clinic/ -.idea/ build/ -coverage/ node_modules/ out/ - -# this is autogenerated by script -src/assets/ - static/ - -# Files -.DS_Store -.env* -CLAUDE.md +coverage/ +TODO.txt resources/images/.DS_Store resources/.DS_Store -TODO.txt +.env* +.DS_Store +.clinic/ +CLAUDE.md +.idea/ +# this is autogenerated by script +src/assets/ diff --git a/src/client/InputHandler.ts b/src/client/InputHandler.ts index 6ba019843..e8d13c932 100644 --- a/src/client/InputHandler.ts +++ b/src/client/InputHandler.ts @@ -153,12 +153,6 @@ export class InputHandler { private activeKeys = new Set(); private keybinds: Record = {}; - private readonly isMacReal = /Mac/.test(navigator.userAgent); - isMac(): boolean { - // Method exists so we can mock during tests - return this.isMacReal; - } - private readonly PAN_SPEED = 5; private readonly ZOOM_SPEED = 10; @@ -192,6 +186,9 @@ export class InputHandler { console.warn("Invalid keybinds JSON:", e); } + // Mac users might have different keybinds + const isMac = /Mac/.test(navigator.userAgent); + this.keybinds = { toggleView: "Space", centerCamera: "KeyC", @@ -205,9 +202,8 @@ export class InputHandler { attackRatioUp: "KeyY", boatAttack: "KeyB", groundAttack: "KeyG", - // Mac users might have different keybinds - modifierKey: this.isMac() ? "MetaLeft" : "ControlLeft", swapDirection: "KeyU", + modifierKey: isMac ? "MetaLeft" : "ControlLeft", altKey: "AltLeft", buildCity: "Digit1", buildFactory: "Digit2", @@ -452,15 +448,13 @@ export class InputHandler { } private onPointerDown(event: PointerEvent) { - // Handle middle mouse button (wheel click) for auto-upgrade - if (this.isMiddleMouseButton(event.button)) { + if (event.button === 1) { event.preventDefault(); this.eventBus.emit(new AutoUpgradeEvent(event.clientX, event.clientY)); return; } - // Ignore right mouse button and other non-left buttons - if (!this.isLeftMouseButton(event.button)) { + if (event.button > 0) { return; } @@ -481,14 +475,12 @@ export class InputHandler { } onPointerUp(event: PointerEvent) { - // Prevent default behavior for middle mouse button, but don't process further - if (this.isMiddleMouseButton(event.button)) { + if (event.button === 1) { event.preventDefault(); return; } - // Ignore right mouse button and other non-left buttons - if (!this.isLeftMouseButton(event.button)) { + if (event.button > 0) { return; } this.pointerDown = false; @@ -498,27 +490,15 @@ export class InputHandler { this.eventBus.emit(new ShowBuildMenuEvent(event.clientX, event.clientY)); return; } - if (this.isAltKeyPressed(event)) { this.eventBus.emit(new ShowEmojiMenuEvent(event.clientX, event.clientY)); return; } - // If Ctrl is held down (for example, on a Mac which doesn't have a right-click) - // then Ctrl+Click is used to open context menu. - // - // Without this conditional, Ctrl+click causes the player to attack someone - // if they are not allied, effectively removing ability to ally with bots/nations. - if (this.isMac() && this.activeKeys.has("ControlLeft")) { - this.eventBus.emit(new ContextMenuEvent(event.clientX, event.clientY)); - return; - } - const dist = Math.abs(event.x - this.lastPointerDownX) + Math.abs(event.y - this.lastPointerDownY); if (dist < 10) { - // Handle touch events separately (prevents both touch and click events from firing) if (event.pointerType === "touch") { this.eventBus.emit(new TouchEvent(event.x, event.y)); event.preventDefault(); @@ -552,18 +532,17 @@ export class InputHandler { } private onPointerMove(event: PointerEvent) { - if (this.isMiddleMouseButton(event.button)) { + if (event.button === 1) { event.preventDefault(); return; } - if (!this.isLeftMouseButton(event.button)) { + if (event.button > 0) { return; } this.pointers.set(event.pointerId, event); - // When not dragging, just track mouse position for hover effects if (!this.pointerDown) { this.eventBus.emit(new MouseOverEvent(event.clientX, event.clientY)); return; @@ -593,7 +572,6 @@ export class InputHandler { private onContextMenu(event: MouseEvent) { event.preventDefault(); - // If placing a structure, right-click cancels instead of opening context menu if (this.uiState.ghostStructure !== null) { this.setGhostStructure(null); return; @@ -661,12 +639,4 @@ export class InputHandler { (this.keybinds.altKey === "MetaLeft" && event.metaKey) ); } - - private isMiddleMouseButton(button: number): boolean { - return button === 1; - } - - private isLeftMouseButton(button: number): boolean { - return button === 0; - } } diff --git a/tests/InputHandler.test.ts b/tests/InputHandler.test.ts index a74793a96..e854cb11a 100644 --- a/tests/InputHandler.test.ts +++ b/tests/InputHandler.test.ts @@ -1,9 +1,4 @@ -import { - AutoUpgradeEvent, - ContextMenuEvent, - InputHandler, - MouseUpEvent, -} from "../src/client/InputHandler"; +import { AutoUpgradeEvent, InputHandler } from "../src/client/InputHandler"; import { EventBus } from "../src/core/EventBus"; class MockPointerEvent { @@ -457,46 +452,4 @@ describe("InputHandler AutoUpgrade", () => { spy.mockRestore(); }); }); - - describe("Mac Ctrl+Click Context Menu", () => { - test("should create context menu with Ctrl+Click on Mac, but not attack", () => { - // Mock isMac() to return true - vi.spyOn(inputHandler as any, "isMac").mockReturnValue(true); - const mockEmit = vi.spyOn(eventBus, "emit"); - - // Simulate ControlLeft being held - inputHandler["activeKeys"].add("ControlLeft"); - - // Simulate a pointer down first (to set pointerDown state) - const pointerDownEvent = new PointerEvent("pointerdown", { - button: 0, - clientX: 100, - clientY: 200, - pointerId: 1, - }); - inputHandler["onPointerDown"](pointerDownEvent); - mockEmit.mockClear(); - - // Now trigger pointer up - const pointerUpEvent = new PointerEvent("pointerup", { - button: 0, - clientX: 100, - clientY: 200, - pointerId: 1, - }); - inputHandler["onPointerUp"](pointerUpEvent); - - // Verify ContextMenuEvent was emitted with correct coordinates - expect(mockEmit).toHaveBeenCalledTimes(1); - // If MouseUp is fired, that would cause an attack - which we do not want. - expect(mockEmit).not.toHaveBeenCalledWith(expect.any(MouseUpEvent)); - expect(mockEmit).toHaveBeenCalledWith(expect.any(ContextMenuEvent)); - expect(mockEmit).toHaveBeenCalledWith( - expect.objectContaining({ - x: 100, - y: 200, - }), - ); - }); - }); });