import { getConfig } from './config.js'; import { EventEmitter, EventTypes } from './event.js'; import { InputHandler, LayerHandler } from './handler.js'; export function createInputHandler(canvas, scene) { const eventEmitter = new EventEmitter(); const inputHandler = new InputHandler(canvas); let cameraControlsEnabled = true; // Attach DOM events to trigger eventEmitter function attachDomEvents() { window.addEventListener('keydown', (e) => { eventEmitter.emit(EventTypes.KEY_DOWN, e); }); window.addEventListener('keyup', (e) => { eventEmitter.emit(EventTypes.KEY_UP, e); }); window.addEventListener('keypress', (e) => { eventEmitter.emit(EventTypes.KEY_PRESS, e); // Emit TEXT_INPUT for single characters if (e.key.length === 1) { eventEmitter.emit(EventTypes.TEXT_INPUT, e.key); } }); canvas.addEventListener('mousemove', (e) => { eventEmitter.emit(EventTypes.MOUSE_MOVE, e); }); canvas.addEventListener('mousedown', (e) => { eventEmitter.emit(EventTypes.MOUSE_DOWN, e); }); canvas.addEventListener('mouseup', (e) => { eventEmitter.emit(EventTypes.MOUSE_UP, e); }); canvas.addEventListener('wheel', (e) => { eventEmitter.emit(EventTypes.MOUSE_WHEEL, e); }, { passive: false }); canvas.addEventListener('click', (e) => { eventEmitter.emit(EventTypes.CLICK, e); }); } function setupCameraControls() { const config = getConfig(); const moveSpeed = config?.camera?.moveSpeed || 10; const zoomSpeed = config?.camera?.zoomSpeed || 0.1; const inverted = config?.controls?.inverted || false; const moveDir = inverted ? 1 : -1; eventEmitter.on(EventTypes.KEY_DOWN, (e) => { if (!cameraControlsEnabled) return; switch (e.key.toLowerCase()) { case 'w': scene.camera.moveBy(0, moveSpeed * moveDir); break; case 's': scene.camera.moveBy(0, -moveSpeed * moveDir); break; case 'a': scene.camera.moveBy(-moveSpeed * moveDir, 0); break; case 'd': scene.camera.moveBy(moveSpeed * moveDir, 0); break; case '+': case '=': scene.camera.zoomBy(1 + zoomSpeed); break; case '-': case '_': scene.camera.zoomBy(1 - zoomSpeed); break; } }); eventEmitter.on(EventTypes.MOUSE_WHEEL, (e) => { if (!cameraControlsEnabled) return; const zoomFactor = e.deltaY > 0 ? 0.9 : 1.1; scene.camera.zoomBy(zoomFactor); e.preventDefault(); }); } function setupLayerHandlers() { scene.getLayers().forEach(layer => { const handlers = [ new LayerHandler(EventTypes.KEY_DOWN, (e, layer) => layer.handleKeyDown?.(e)), new LayerHandler(EventTypes.MOUSE_MOVE, (e, layer) => { const pos = inputHandler.getMousePosition(e); layer.handleMouseMove?.(pos.x, pos.y); }), new LayerHandler(EventTypes.CLICK, (e, layer) => { const pos = inputHandler.getMousePosition(e); layer.handleClick?.(pos.x, pos.y, scene.camera); }), new LayerHandler(EventTypes.MOUSE_WHEEL, (e, layer) => layer.handleWheel?.(e)) ]; handlers.forEach(handler => { handler.bind(layer); inputHandler.addHandler(handler.eventType, handler); }); }); } attachDomEvents(); setupCameraControls(); setupLayerHandlers(); return { listenForKey: (key, callback) => eventEmitter.on(EventTypes.KEY_DOWN, (e) => { if (e.key === key) callback(e); }), removeKeyListener: (key, callback) => eventEmitter.off(EventTypes.KEY_DOWN, (e) => { if (e.key === key) callback(e); }), addTextInputListener: (callback) => eventEmitter.on(EventTypes.TEXT_INPUT, callback), removeTextInputListener: (callback) => eventEmitter.off(EventTypes.TEXT_INPUT, callback), removeAllListeners: () => eventEmitter.clear(), enableCameraControls: () => { cameraControlsEnabled = true; }, disableCameraControls: () => { cameraControlsEnabled = false; }, on: (event, callback) => eventEmitter.on(event, callback), off: (event, callback) => eventEmitter.off(event, callback), cleanup: () => { eventEmitter.clear(); inputHandler.disable(); } }; }