lucky / Touch.html
Studytime171's picture
Duplicate from Studytime171/Lalitgangwani
89610f7
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>GBA.js</title>
<link rel="stylesheet" href="resources/main.css">
<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>
var gba;
var runCommands = [];
var debug = null;
try {
gba = new GameBoyAdvance();
gba.keypad.eatInput = true;
gba.setLogger(function(level, error) {
console.log(error);
gba.pause();
var screen = document.getElementById('screen');
if (screen.getAttribute('class') == 'dead') {
console.log('We appear to have crashed multiple times without reseting.');
return;
}
var crash = document.createElement('img');
crash.setAttribute('id', 'crash');
crash.setAttribute('src', 'resources/crash.png');
screen.parentElement.insertBefore(crash, screen);
screen.setAttribute('class', 'dead');
});
} catch (exception) {
gba = null;
}
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 (!gba.audio.context) {
// Remove the sound box if sound isn't available
var soundbox = document.getElementById('sound');
soundbox.parentElement.removeChild(soundbox);
}
if (window.navigator.appName == 'Microsoft Internet Explorer') {
// Remove the pixelated option if it doesn't work
var pixelatedBox = document.getElementById('pixelated');
pixelatedBox.parentElement.removeChild(pixelatedBox);
}
// Detect touch device and show controls
if ('ontouchstart' in window || navigator.maxTouchPoints > 0) {
document.getElementById('touchControls').style.display = 'flex';
// Make canvas responsive on mobile
canvas.style.width = '100%';
canvas.style.height = 'auto';
}
// Wire up touch events to simulate key presses
setupTouchControls();
} else {
var dead = document.getElementById('controls');
dead.parentElement.removeChild(dead);
}
}
function fadeOut(id, nextId, kill) {
var e = document.getElementById(id);
var e2 = document.getElementById(nextId);
if (!e) {
return;
}
var removeSelf = function() {
if (kill) {
e.parentElement.removeChild(e);
} else {
e.setAttribute('class', 'dead');
e.removeEventListener('webkitTransitionEnd', removeSelf);
e.removeEventListener('oTransitionEnd', removeSelf);
e.removeEventListener('transitionend', removeSelf);
}
if (e2) {
e2.setAttribute('class', 'hidden');
setTimeout(function() {
e2.removeAttribute('class');
}, 0);
}
}
e.addEventListener('webkitTransitionEnd', removeSelf, false);
e.addEventListener('oTransitionEnd', removeSelf, false);
e.addEventListener('transitionend', removeSelf, false);
e.setAttribute('class', 'hidden');
}
function run(file) {
var dead = document.getElementById('loader');
dead.value = '';
var load = document.getElementById('select');
load.textContent = 'Loading...';
load.removeAttribute('onclick');
var pause = document.getElementById('pause');
pause.textContent = "PAUSE";
gba.loadRomFromFile(file, function(result) {
if (result) {
for (var i = 0; i < runCommands.length; ++i) {
runCommands[i]();
}
runCommands = [];
fadeOut('preload', 'ingame');
fadeOut('instructions', null, true);
gba.runStable();
} else {
load.textContent = 'FAILED';
setTimeout(function() {
load.textContent = 'SELECT';
load.onclick = function() {
document.getElementById('loader').click();
}
}, 3000);
}
});
}
function reset() {
gba.pause();
gba.reset();
var load = document.getElementById('select');
load.textContent = 'SELECT';
var crash = document.getElementById('crash');
if (crash) {
var context = gba.targetCanvas.getContext('2d');
context.clearRect(0, 0, 480, 320);
gba.video.drawCallback();
crash.parentElement.removeChild(crash);
var canvas = document.getElementById('screen');
canvas.removeAttribute('class');
} else {
lcdFade(gba.context, gba.targetCanvas.getContext('2d'), gba.video.drawCallback);
}
load.onclick = function() {
document.getElementById('loader').click();
}
fadeOut('ingame', 'preload');
}
function uploadSavedataPending(file) {
runCommands.push(function() { gba.loadSavedataFromFile(file) });
}
function togglePause() {
var e = document.getElementById('pause');
if (gba.paused) {
if (debug && debug.gbaCon) {
debug.gbaCon.run();
} else {
gba.runStable();
}
e.textContent = "PAUSE";
} else {
if (debug && debug.gbaCon) {
debug.gbaCon.pause();
} else {
gba.pause();
}
e.textContent = "UNPAUSE";
}
}
function screenshot() {
var canvas = gba.indirectCanvas;
window.open(canvas.toDataURL('image/png'), 'screenshot');
}
function lcdFade(context, target, callback) {
var i = 0;
var drawInterval = setInterval(function() {
i++;
var pixelData = context.getImageData(0, 0, 240, 160);
for (var y = 0; y < 160; ++y) {
for (var x = 0; x < 240; ++x) {
var xDiff = Math.abs(x - 120);
var yDiff = Math.abs(y - 80) * 0.8;
var xFactor = (120 - i - xDiff) / 120;
var yFactor = (80 - i - ((y & 1) * 10) - yDiff + Math.pow(xDiff, 1 / 2)) / 80;
pixelData.data[(x + y * 240) * 4 + 3] *= Math.pow(xFactor, 1 / 3) * Math.pow(yFactor, 1 / 2);
}
}
context.putImageData(pixelData, 0, 0);
target.clearRect(0, 0, 480, 320);
if (i > 40) {
clearInterval(drawInterval);
} else {
callback();
}
}, 50);
}
function setVolume(value) {
gba.audio.masterVolume = Math.pow(2, value) - 1;
}
function setPixelated(pixelated) {
var screen = document.getElementById('screen');
var context = screen.getContext('2d');
if (context.webkitImageSmoothingEnabled) {
context.webkitImageSmoothingEnabled = !pixelated;
} else if (context.mozImageSmoothingEnabled) {
context.mozImageSmoothingEnabled = !pixelated;
} else if (window.navigator.appName != 'Microsoft Internet Explorer') {
if (pixelated) {
screen.setAttribute('width', '240');
screen.setAttribute('height', '160');
} else {
screen.setAttribute('width', '480');
screen.setAttribute('height', '320');
}
if (window.navigator.appName == 'Opera') {
// Ugly hack! Ew!
if (pixelated) {
screen.style.marginTop = '0';
screen.style.marginBottom = '-325px';
} else {
delete screen.style;
}
}
}
}
function enableDebug() {
window.onmessage = function(message) {
if (message.origin != document.domain && (message.origin != 'file://' || document.domain)) {
console.log('Failed XSS');
return;
}
switch (message.data) {
case 'connect':
if (message.source == debug) {
debug.postMessage('connect', document.domain || '*');
}
break;
case 'connected':
break;
case 'disconnect':
if (message.source == debug) {
debug = null;
}
}
}
window.onunload = function() {
if (debug && debug.postMessage) {
debug.postMessage('disconnect', document.domain || '*');
}
}
if (!debug || !debug.postMessage) {
debug = window.open('debugger.html', 'debug');
} else {
debug.postMessage('connect', document.domain || '*');
}
}
document.addEventListener('webkitfullscreenchange', function() {
var canvas = document.getElementById('screen');
if (document.webkitIsFullScreen) {
canvas.setAttribute('height', document.body.offsetHeight);
canvas.setAttribute('width', document.body.offsetHeight / 2 * 3);
canvas.setAttribute('style', 'margin: 0');
} else {
canvas.setAttribute('height', 320);
canvas.setAttribute('width', 480);
canvas.removeAttribute('style');
}
}, false);
// New function to setup touch controls
function setupTouchControls() {
// Function to simulate key press/release
function pressKey(code) {
var e = new KeyboardEvent('keydown', {keyCode: code, bubbles: true});
window.dispatchEvent(e);
}
function releaseKey(code) {
var e = new KeyboardEvent('keyup', {keyCode: code, bubbles: true});
window.dispatchEvent(e);
}
// Assuming standard mappings: Arrows for D-Pad, Z for A, X for B, Enter for Start, Shift for Select, A for L, S for R
// D-Pad buttons
document.getElementById('up').addEventListener('touchstart', () => pressKey(38)); // Up arrow
document.getElementById('up').addEventListener('touchend', () => releaseKey(38));
document.getElementById('down').addEventListener('touchstart', () => pressKey(40)); // Down arrow
document.getElementById('down').addEventListener('touchend', () => releaseKey(40));
document.getElementById('left').addEventListener('touchstart', () => pressKey(37)); // Left arrow
document.getElementById('left').addEventListener('touchend', () => releaseKey(37));
document.getElementById('right').addEventListener('touchstart', () => pressKey(39)); // Right arrow
document.getElementById('right').addEventListener('touchend', () => releaseKey(39));
// Face buttons
document.getElementById('a').addEventListener('touchstart', () => pressKey(88)); // X for A
document.getElementById('a').addEventListener('touchend', () => releaseKey(88));
document.getElementById('b').addEventListener('touchstart', () => pressKey(90)); // Z for B
document.getElementById('b').addEventListener('touchend', () => releaseKey(90));
// Shoulders
document.getElementById('l').addEventListener('touchstart', () => pressKey(65)); // A for L
document.getElementById('l').addEventListener('touchend', () => releaseKey(65));
document.getElementById('r').addEventListener('touchstart', () => pressKey(83)); // S for R
document.getElementById('r').addEventListener('touchend', () => releaseKey(83));
// Start/Select
document.getElementById('start').addEventListener('touchstart', () => pressKey(13)); // Enter for Start
document.getElementById('start').addEventListener('touchend', () => releaseKey(13));
document.getElementById('select').addEventListener('touchstart', () => pressKey(16)); // Shift for Select
document.getElementById('select').addEventListener('touchend', () => releaseKey(16));
}
</script>
</head>
<body>
<canvas id="screen" width="480" height="320"></canvas>
<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>
<label id="pixelated">
<input type="checkbox" onchange="setPixelated(this.checked)">
<p>Pixelated</p>
</label>
<div id="sound">
<input type="checkbox" checked onchange="gba.audio.masterEnable = this.checked">
<p>Sound</p>
<input type="range" min="0" max="1" value="1" step="any" onchange="setVolume(this.value)" oninput="setVolume(this.value)">
</div>
<p id="openDebug" onclick="enableDebug()">Debugger</p>
</div>
</section>
<!-- Added Touch Controls Overlay -->
<div id="touchControls" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none; display: none; z-index: 10; flex-direction: row; justify-content: space-between; align-items: flex-end; padding: 10px; box-sizing: border-box;">
<!-- D-Pad (left side) -->
<div id="dpad" style="display: grid; grid-template-columns: repeat(3, 50px); grid-template-rows: repeat(3, 50px); gap: 5px; pointer-events: auto;">
<button id="up" style="grid-column: 2; grid-row: 1; background: rgba(0,0,0,0.5); color: white; border-radius: 10px;"></button>
<button id="left" style="grid-column: 1; grid-row: 2; background: rgba(0,0,0,0.5); color: white; border-radius: 10px;"></button>
<button id="right" style="grid-column: 3; grid-row: 2; background: rgba(0,0,0,0.5); color: white; border-radius: 10px;"></button>
<button id="down" style="grid-column: 2; grid-row: 3; background: rgba(0,0,0,0.5); color: white; border-radius: 10px;"></button>
</div>
<!-- Face Buttons (right side) -->
<div id="faceButtons" style="display: flex; flex-direction: column; align-items: flex-end; pointer-events: auto;">
<div style="display: flex; gap: 10px; margin-bottom: 10px;">
<button id="l" style="width:60px; height:30px; background: rgba(128,128,128,0.5); color: white; border-radius: 5px;">L</button>
<button id="r" style="width:60px; height:30px; background: rgba(128,128,128,0.5); color: white; border-radius: 5px;">R</button>
</div>
<div style="display: flex; gap: 10px; margin-bottom: 10px;">
<button id="select" style="width:60px; height:30px; background: rgba(0,128,0,0.5); color: white; border-radius: 5px;">Select</button>
<button id="start" style="width:60px; height:30px; background: rgba(0,128,0,0.5); color: white; border-radius: 5px;">Start</button>
</div>
<div style="display: flex; gap: 20px;">
<button id="b" style="width:70px; height:70px; border-radius:50%; background: rgba(0,0,255,0.5); color: white;">B</button>
<button id="a" style="width:70px; height:70px; border-radius:50%; background: rgba(255,0,0,0.5); color: white;">A</button>
</div>
</div>
</div>
</body>
</html>