// TOUCH CONTROLS – simulate real keyCode events if ('ontouchstart' in window || navigator.maxTouchPoints > 0) { const pressed = new Set(); // track which "keyCodes" are down function dispatchKey(type, keyCodeStr) { const keyCode = parseInt(keyCodeStr, 10); if (!keyCode) return; // Create old-style KeyboardEvent with keyCode (needed for this emulator) const event = document.createEvent ? document.createEvent('KeyboardEvent') : new KeyboardEvent(type); // Modern way to set keyCode (works in most browsers) if (event.initKeyboardEvent) { event.initKeyboardEvent( type, true, true, window, false, false, false, false, keyCode, keyCode ); } else { // Fallback for newer KeyboardEvent constructors Object.defineProperties(event, { keyCode: { value: keyCode, writable: true }, which: { value: keyCode, writable: true } }); } // Also try dispatching on document, window, and canvas document.dispatchEvent(event); window.dispatchEvent(event); document.getElementById('screen')?.dispatchEvent(event); } document.querySelectorAll('[data-keycode]').forEach(el => { const keyCode = el.dataset.keycode; el.addEventListener('touchstart', e => { e.preventDefault(); // stops scrolling/zoom on mobile if (!pressed.has(keyCode)) { pressed.add(keyCode); dispatchKey('keydown', keyCode); } }, { passive: false }); el.addEventListener('touchend', e => { e.preventDefault(); if (pressed.has(keyCode)) { pressed.delete(keyCode); dispatchKey('keyup', keyCode); } }, { passive: false }); el.addEventListener('touchcancel', e => { e.preventDefault(); if (pressed.has(keyCode)) { pressed.delete(keyCode); dispatchKey('keyup', keyCode); } }, { passive: false }); // Optional: visual feedback on press el.addEventListener('touchstart', () => el.classList.add('pressed')); el.addEventListener('touchend touchcancel', () => el.classList.remove('pressed')); }); }