Source: modules/mouse.js

/**
 * Manages mouse input, tracking position, which buttons are down, and which were just pressed.
 */
export class Mouse{
	/** @type {number} The last known client x-coordinate of the mouse. */
	x = 0;
	/** @type {number} The last known client y-coordinate of the mouse. */
	y = 0;
	/** @private @type {Set<number>} Tracks which buttons are currently held down. */
	#buttonsDown = new Set();
	/** @private @type {Set<number>} Tracks which buttons were just pressed this frame. */
	#buttonsHit = new Set();

	constructor(){
		document.addEventListener('mousemove', this.update.bind(this));
		document.addEventListener('mousedown', this.#onMouseDown.bind(this));
		document.addEventListener('mouseup', this.#onMouseUp.bind(this));
	}

	/**
	 * @private
	 * Updates the mouse coordinates based on the mousemove event.
	 * @param {MouseEvent} event The mouse move event object.
	 */
	update(event) {
		this.x = event.clientX;
		this.y = event.clientY;
	}

	/**
	 * @private
	 * Handles the mousedown event.
	 */
	#onMouseDown(event) {
		const button = (event.button === 1) ? 3 : event.button + 1;
		if (!this.#buttonsDown.has(button)) {
			this.#buttonsHit.add(button);
		}
		this.#buttonsDown.add(button);
	}

	/**
	 * @private
	 * Handles the mouseup event.
	 */
	#onMouseUp(event) {
		const button = (event.button === 1) ? 3 : event.button + 1;
		this.#buttonsDown.delete(button);
	}

	/**
	 * Checks if a specific mouse button is currently held down.
	 * @param {number} button The button to check (1=left, 2=right, 3=middle).
	 * @returns {boolean}
	 */
	mouseDown(button) {
		return this.#buttonsDown.has(button);
	}

	/**
	 * Checks if a specific mouse button was just pressed in the current frame.
	 * This state is cleared at the end of the frame.
	 * @param {number} button The button to check (1=left, 2=right, 3=middle).
	 * @returns {boolean}
	 */
	mouseHit(button) {
		return this.#buttonsHit.has(button);
	}

	/**
	 * @private
	 * Clears all "mouse hit" states. This is called automatically by the engine at the end of each frame.
	 */
	clearHits() {
		this.#buttonsHit.clear();
	}
}