| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="UTF-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"> |
| <title>GBA.js - Touch Enabled</title> |
| <link rel="stylesheet" href="resources/main.css"> |
| <style> |
| body, html { |
| margin: 0; |
| padding: 0; |
| height: 100%; |
| overflow: hidden; |
| touch-action: manipulation; |
| background: #000; |
| } |
| #screen-container { |
| position: relative; |
| width: 100%; |
| height: 100%; |
| max-width: 100vw; |
| max-height: 100vh; |
| display: flex; |
| justify-content: center; |
| align-items: center; |
| background: #111; |
| } |
| #screen { |
| width: 100%; |
| height: auto; |
| max-width: 100%; |
| max-height: 100%; |
| image-rendering: pixelated; |
| touch-action: none; |
| } |
| #touchControls { |
| position: absolute; |
| inset: 0; |
| pointer-events: none; |
| display: none; |
| z-index: 10; |
| padding: 2vmin; |
| box-sizing: border-box; |
| } |
| #dpad, #faceButtons { |
| pointer-events: auto; |
| } |
| button { |
| font-size: 4vmin; |
| font-weight: bold; |
| color: white; |
| border: none; |
| border-radius: 50%; |
| opacity: 0.6; |
| touch-action: manipulation; |
| user-select: none; |
| -webkit-tap-highlight-color: transparent; |
| } |
| button:active { |
| opacity: 0.9; |
| } |
| #dpad { |
| display: grid; |
| grid-template-columns: repeat(3, 18vmin); |
| grid-template-rows: repeat(3, 18vmin); |
| gap: 1vmin; |
| } |
| #faceButtons { |
| display: flex; |
| flex-direction: column; |
| align-items: flex-end; |
| gap: 2vmin; |
| } |
| .shoulder { |
| width: 18vmin; |
| height: 10vmin; |
| border-radius: 10vmin; |
| background: rgba(200,200,200,0.5); |
| font-size: 3.5vmin; |
| } |
| .start-select { |
| width: 18vmin; |
| height: 10vmin; |
| border-radius: 8vmin; |
| background: rgba(0,180,0,0.5); |
| font-size: 3vmin; |
| } |
| #a { background: rgba(255,80,80,0.7); width: 22vmin; height: 22vmin; } |
| #b { background: rgba(80,80,255,0.7); width: 22vmin; height: 22vmin; } |
| |
| @media (orientation: landscape) { |
| #touchControls { flex-direction: row; justify-content: space-between; align-items: flex-end; } |
| #dpad { grid-template-columns: repeat(3, 14vmin); grid-template-rows: repeat(3, 14vmin); } |
| #faceButtons { flex-direction: row; align-items: flex-end; gap: 4vmin; } |
| #faceButtons > div { flex-direction: column; } |
| } |
| |
| @media (orientation: portrait) { |
| #touchControls { flex-direction: column; justify-content: flex-end; } |
| #dpad { align-self: flex-start; } |
| #faceButtons { align-self: flex-end; } |
| } |
| </style> |
|
|
| <script src="js/util.js"></script> |
| <script src="js/core.js"></script> |
| <script src="js/arm.js"></script> |
| <script src="js/thumb.js"></script> |
| <script src="js/mmu.js"></script> |
| <script src="js/io.js"></script> |
| <script src="js/audio.js"></script> |
| <script src="js/video.js"></script> |
| <script src="js/video/proxy.js"></script> |
| <script src="js/video/software.js"></script> |
| <script src="js/irq.js"></script> |
| <script src="js/keypad.js"></script> |
| <script src="js/sio.js"></script> |
| <script src="js/savedata.js"></script> |
| <script src="js/gpio.js"></script> |
| <script src="js/gba.js"></script> |
| <script src="resources/xhr.js"></script> |
|
|
| <script> |
| |
| |
| |
| window.onload = function() { |
| if (gba && FileReader) { |
| var canvas = document.getElementById('screen'); |
| gba.setCanvas(canvas); |
| gba.logLevel = gba.LOG_ERROR; |
| |
| loadRom('resources/bios.bin', function(bios) { |
| gba.setBios(bios); |
| }); |
| |
| |
| |
| |
| if ('ontouchstart' in window || navigator.maxTouchPoints > 0) { |
| document.getElementById('touchControls').style.display = 'flex'; |
| |
| canvas.style.width = '100%'; |
| canvas.style.height = 'auto'; |
| canvas.style.maxHeight = '85vh'; |
| } |
| |
| setupTouchControls(); |
| } else { |
| |
| } |
| }; |
| |
| |
| |
| function setupTouchControls() { |
| function press(code) { |
| window.dispatchEvent(new KeyboardEvent('keydown', {keyCode: code, bubbles: true})); |
| } |
| function release(code) { |
| window.dispatchEvent(new KeyboardEvent('keyup', {keyCode: code, bubbles: true})); |
| } |
| |
| |
| const keys = { |
| up: 38, |
| down: 40, |
| left: 37, |
| right: 39, |
| a: 88, |
| b: 90, |
| l: 65, |
| r: 83, |
| start: 13, |
| select: 16 |
| }; |
| |
| |
| ['up','down','left','right','a','b','l','r','start','select'].forEach(id => { |
| const btn = document.getElementById(id); |
| if (btn) { |
| btn.addEventListener('touchstart', e => { e.preventDefault(); press(keys[id]); }); |
| btn.addEventListener('touchend', e => { e.preventDefault(); release(keys[id]); }); |
| btn.addEventListener('touchcancel',e => { e.preventDefault(); release(keys[id]); }); |
| } |
| }); |
| } |
| </script> |
| </head> |
| <body> |
| <div id="screen-container"> |
| <canvas id="screen" width="480" height="320"></canvas> |
| </div> |
|
|
| <section id="controls"> |
| |
| <div id="preload"> |
| <button class="bigbutton" id="select" onclick="document.getElementById('loader').click()">SELECT</button> |
| <input id="loader" type="file" accept=".gba" onchange="run(this.files[0]);"> |
| <button onclick="document.getElementById('saveloader').click()">Upload Savegame</button> |
| <input id="saveloader" type="file" onchange="uploadSavedataPending(this.files[0]);"> |
| </div> |
| <div id="ingame" class="hidden"> |
| <button id="pause" class="bigbutton" onclick="togglePause()">PAUSE</button> |
| <button class="bigbutton" onclick="reset()">RESET</button> |
| <button onclick="gba.downloadSavedata()">Download Savegame</button> |
| <button onclick="screenshot()">Screenshot</button> |
| |
| </div> |
| </section> |
|
|
| |
| <div id="touchControls"> |
| |
| <div id="dpad"> |
| <button id="up">β</button> |
| <button id="left">β</button> |
| <button id="right">β</button> |
| <button id="down">β</button> |
| </div> |
|
|
| |
| <div id="faceButtons"> |
| <div> |
| <button id="l" class="shoulder">L</button> |
| <button id="r" class="shoulder">R</button> |
| </div> |
| <div> |
| <button id="select" class="start-select">Select</button> |
| <button id="start" class="start-select">Start</button> |
| </div> |
| <div> |
| <button id="b">B</button> |
| <button id="a">A</button> |
| </div> |
| </div> |
| </div> |
|
|
| </body> |
| </html> |