mirror of
https://github.com/whscullin/apple2js.git
synced 2024-01-12 14:14:38 +00:00
Merge pull request #1 from whscullin/whscullin/cleanup-refactor
Cleanup and refactoring.
This commit is contained in:
commit
9bd56466b4
14
.editorconfig
Normal file
14
.editorconfig
Normal file
@ -0,0 +1,14 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
indent_style = space
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.js]
|
||||
indent_size = 4
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = true
|
25
.eslintrc.json
Normal file
25
.eslintrc.json
Normal file
@ -0,0 +1,25 @@
|
||||
{
|
||||
"rules": {
|
||||
"indent": [
|
||||
2,
|
||||
4
|
||||
],
|
||||
"quotes": [
|
||||
2,
|
||||
"single"
|
||||
],
|
||||
"linebreak-style": [
|
||||
2,
|
||||
"unix"
|
||||
],
|
||||
"semi": [
|
||||
2,
|
||||
"always"
|
||||
]
|
||||
},
|
||||
"env": {
|
||||
"browser": true,
|
||||
"jquery": true
|
||||
},
|
||||
"extends": "eslint:recommended"
|
||||
}
|
22
about.html
22
about.html
@ -1,6 +1,6 @@
|
||||
<!DOCTYPE html>
|
||||
<!-- -*- mode: HTML; indent-tabs-mode: nil -*- -->
|
||||
<!-- Copyright 2010 Will Scullin -->
|
||||
<!-- Copyright 2010-2016 Will Scullin -->
|
||||
<html>
|
||||
<head>
|
||||
<base href="/apple" />
|
||||
@ -10,17 +10,17 @@
|
||||
<link rel="stylesheet" type="text/css" href="css/apple2.css" />
|
||||
<title>About Apple ][js/Apple //jse</title>
|
||||
<script type="text/javascript">
|
||||
|
||||
|
||||
var _gaq = _gaq || [];
|
||||
_gaq.push(['_setAccount', 'UA-19205057-1']);
|
||||
_gaq.push(['_trackPageview']);
|
||||
|
||||
|
||||
(function() {
|
||||
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
|
||||
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
|
||||
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
|
||||
})();
|
||||
|
||||
|
||||
</script>
|
||||
<meta property="og:title" content="About Apple ][js" />
|
||||
<meta property="og:type" content="website" />
|
||||
@ -35,7 +35,7 @@
|
||||
</div>
|
||||
<div style="max-width: 800px; margin: auto">
|
||||
<h2>What is this?</h2>
|
||||
<span class="motter"><a href="../apple2/">Apple ][js</a></span> and
|
||||
<span class="motter"><a href="../apple2/">Apple ][js</a></span> and
|
||||
<span class="motter"><a href="../apple//e">Apple //jse</a></span>
|
||||
are Apple ][ and Apple //e emulators written entirely in JavaScript
|
||||
and HTML5.
|
||||
@ -45,10 +45,10 @@
|
||||
I now simulate having a 1 Megabyte RAMFactor card in slot 2.
|
||||
<li><h3>Thunderclock Emulation (//jse)</h3>
|
||||
There is cursory emulation of the Thunderclock card, enough
|
||||
to keep ProDOS applications from asking you to enter the date
|
||||
to keep ProDOS applications from asking you to enter the date
|
||||
all the time. ProDOS attempts to guess the year from the month,
|
||||
the day and the day of the week, something that needs to be
|
||||
patched every 6 years. This means newer versions think it's 1996,
|
||||
patched every 6 years. This means newer versions think it's 1996,
|
||||
older versions are stuck in the 80s.
|
||||
<li><h3>Firefox Nightly Joystick Support</h3>
|
||||
Joystick support has yet to officially land, but the latest
|
||||
@ -95,7 +95,7 @@
|
||||
score.
|
||||
</li>
|
||||
<li><h3>Competition</h3>
|
||||
Now in addition to
|
||||
Now in addition to
|
||||
<a href="http://www.megidish.net/apple2js/">Gil Megidish's</a>
|
||||
Apple2JS, there's a couple of new kids on the block, including
|
||||
<a href="http://porkrind.org/a2/">David Caldwell's</a> Apple II+
|
||||
@ -157,7 +157,7 @@
|
||||
<a href="http://jqueryui.com">jQuery UI</a>
|
||||
</li>
|
||||
<li>
|
||||
Base64 Utilities via
|
||||
Base64 Utilities via
|
||||
<a href="http://kevin.vanzonneveld.net/">KvZ</a>
|
||||
</li>
|
||||
<li>
|
||||
@ -173,7 +173,7 @@
|
||||
<i>Beneath Apple DOS</i>
|
||||
</a>
|
||||
by Don Worth and Pieter Lechner
|
||||
</li>
|
||||
</li>
|
||||
<li>
|
||||
<i>Inside the Apple //e</i> by Gary B. Little
|
||||
</li>
|
||||
@ -224,7 +224,7 @@
|
||||
realized there was, in fact, another apple2js in the world.
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</li>
|
||||
<h2>Contact</h2>
|
||||
<ul>
|
||||
<li>
|
||||
|
769
apple2js.html
769
apple2js.html
@ -1,6 +1,6 @@
|
||||
<!DOCTYPE html><!-- -*- mode: HTML; indent-tabs-mode: nil -*- -->
|
||||
<!--
|
||||
Copyright 2010-2013 Will Scullin <scullin@scullinsteel.com>
|
||||
Copyright 2010-2016 Will Scullin <scullin@scullinsteel.com>
|
||||
|
||||
Permission to use, copy, modify, distribute, and sell this software and its
|
||||
documentation for any purpose is hereby granted without fee, provided that
|
||||
@ -50,6 +50,7 @@
|
||||
<script type="text/javascript" src="js/langcard.js"></script>
|
||||
<script type="text/javascript" src="js/fpbasic.js"></script>
|
||||
<script type="text/javascript" src="js/apple2char.js"></script>
|
||||
<script type="text/javascript" src="js/applesoft/decompiler.js"></script>
|
||||
<script type="text/javascript" src="js/canvas2.js"></script>
|
||||
<script type="text/javascript" src="js/apple2io.js"></script>
|
||||
<script type="text/javascript" src="js/parallel.js"></script>
|
||||
@ -66,772 +67,8 @@
|
||||
<!-- Disk Index -->
|
||||
<script type="text/javascript" src="json/disks/index.js"></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
<script type="text/javascript" src="js/main2.js"></script>
|
||||
|
||||
var kHz = 1023;
|
||||
|
||||
var focused = false;
|
||||
var startTime = Date.now();
|
||||
var lastCycles = 0;
|
||||
var frames = 0, lastFrames = 0;
|
||||
var paused = false;
|
||||
var sound = true;
|
||||
|
||||
var hashtag;
|
||||
|
||||
var disk_categories = {'Local Saves': []};
|
||||
var disk_sets = {}
|
||||
var disk_cur_name = [];
|
||||
var disk_cur_cat = [];
|
||||
|
||||
function DriveLights()
|
||||
{
|
||||
return {
|
||||
driveLight: function(drive, on) {
|
||||
$("#disk" + drive).css("background-image",
|
||||
on ? "url(css/red-on-16.png)" :
|
||||
"url(css/red-off-16.png)");
|
||||
},
|
||||
dirty: function(drive, dirty) {
|
||||
},
|
||||
label: function(drive, label) {
|
||||
$("#disklabel" + drive).text(label);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var DISK_TYPES = ['dsk','do','po','raw','nib','2mg'];
|
||||
var TAPE_TYPES = ['wav','aiff','aif','mp3'];
|
||||
|
||||
var _saveDrive = 1;
|
||||
var _loadDrive = 1;
|
||||
|
||||
function openLoad(drive, event)
|
||||
{
|
||||
_loadDrive = drive;
|
||||
if (disk_cur_cat[drive]) {
|
||||
$("#category_select").val(disk_cur_cat[drive]).change();
|
||||
}
|
||||
$("#load").dialog("open");
|
||||
}
|
||||
|
||||
function openSave(drive, event)
|
||||
{
|
||||
_saveDrive = drive;
|
||||
$("#save_name").val($("#disklabel" + drive).text());
|
||||
$("#save").dialog("open");
|
||||
}
|
||||
|
||||
var loading = false;
|
||||
|
||||
function loadAjax(url) {
|
||||
loading = true;
|
||||
$("#loading").dialog("open");
|
||||
|
||||
$.ajax({ url: url,
|
||||
cache: false,
|
||||
dataType: "jsonp",
|
||||
jsonp: false,
|
||||
global: false
|
||||
});
|
||||
}
|
||||
|
||||
function doLoad() {
|
||||
var urls = $("#disk_select").val(), url;
|
||||
if (urls && urls.length) {
|
||||
if (typeof(urls) == "string") {
|
||||
url = urls;
|
||||
} else {
|
||||
url = urls[0];
|
||||
}
|
||||
}
|
||||
|
||||
var files = $("#local_file").prop("files");
|
||||
if (files.length == 1) {
|
||||
doLoadLocal();
|
||||
} else if (url) {
|
||||
var filename;
|
||||
$("#load").dialog("close");
|
||||
if (url.substr(0,6) == "local:") {
|
||||
filename = url.substr(6);
|
||||
if (filename == "__manage") {
|
||||
openManage();
|
||||
} else {
|
||||
loadLocalStorage(_loadDrive, filename);
|
||||
}
|
||||
} else {
|
||||
var r1 = /json\/disks\/(.*).json$/.exec(url);
|
||||
if (r1 && _loadDrive == 1) {
|
||||
filename = r1[1];
|
||||
document.location.hash = filename;
|
||||
}
|
||||
loadAjax(url);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function doSave() {
|
||||
var name = $("#save_name").val();
|
||||
saveLocalStorage(_saveDrive, name);
|
||||
$("#save").dialog("close");
|
||||
}
|
||||
|
||||
function doDelete(name) {
|
||||
if (confirm("Delete " + name + "?")) {
|
||||
deleteLocalStorage(name);
|
||||
}
|
||||
}
|
||||
|
||||
function doLoadLocal() {
|
||||
var files = $("#local_file").prop("files")
|
||||
if (files.length == 1) {
|
||||
var file = files[0];
|
||||
var parts = file.name.split(".");
|
||||
var ext = parts[parts.length - 1].toLowerCase();
|
||||
if ($.inArray(ext, DISK_TYPES) >= 0) {
|
||||
doLoadLocalDisk(file);
|
||||
} else if ($.inArray(ext, TAPE_TYPES) >= 0) {
|
||||
doLoadLocalTape(file);
|
||||
} else {
|
||||
alert('Unknown file type: ' + ext);
|
||||
$("#load").dialog("close");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function doLoadLocalDisk(file) {
|
||||
var fileReader = new FileReader();
|
||||
fileReader.onload = function(event) {
|
||||
var parts = file.name.split(".");
|
||||
var name = parts[0], ext = parts[parts.length - 1].toLowerCase();
|
||||
if (disk2.setBinary(_saveDrive, name, ext, this.result)) {
|
||||
$("#disklabel" + _saveDrive).text(name);
|
||||
$("#load").dialog("close");
|
||||
initGamepad();
|
||||
}
|
||||
}
|
||||
fileReader.readAsArrayBuffer(file);
|
||||
}
|
||||
|
||||
function doLoadLocalTape(file) {
|
||||
// Audio Buffer Source
|
||||
if (typeof webkitAudioContext != "undefined") {
|
||||
var context = new webkitAudioContext();
|
||||
} else {
|
||||
alert("Not supported by your browser");
|
||||
$("#load").dialog("close");
|
||||
return;
|
||||
}
|
||||
|
||||
var fileReader = new FileReader();
|
||||
fileReader.onload = function(ev) {
|
||||
context.decodeAudioData(ev.target.result, function(buffer) {
|
||||
var buf = [];
|
||||
var data = buffer.getChannelData(0), datum = data[0];
|
||||
var old = (datum > 0.0), current;
|
||||
var last = 0, delta, ival;
|
||||
debug('Sample Count: ' + data.length);
|
||||
debug('Sample rate: ' + buffer.sampleRate);
|
||||
for (var idx = 1; idx < data.length; idx++) {
|
||||
datum = data[idx];
|
||||
if ((datum > 0.1) || (datum < -0.1)) {
|
||||
current = (datum > 0.0);
|
||||
if (current != old) {
|
||||
delta = idx - last;
|
||||
if (delta > 2000000) {
|
||||
delta = 2000000;
|
||||
}
|
||||
ival = delta / buffer.sampleRate * 1000;
|
||||
if (ival >= 0.550 && ival < 0.750) {
|
||||
ival = 0.650; // Header
|
||||
} else if (ival >= 0.175 && ival < 0.225) {
|
||||
ival = 0.200; // sync 1
|
||||
} else if (ival >= 0.225 && ival < 0.275) {
|
||||
ival = 0.250; // 0 / sync 2
|
||||
} else if (ival >= 0.450 && ival < 0.550) {
|
||||
ival = 0.500; // 1
|
||||
} else {
|
||||
// debug(idx + ' ' + buf.length + ' ' + ival);
|
||||
}
|
||||
buf.push(parseInt(ival * kHz));
|
||||
old = current;
|
||||
last = idx;
|
||||
}
|
||||
}
|
||||
}
|
||||
io.setTape(buf);
|
||||
$("#load").dialog("close");
|
||||
});
|
||||
};
|
||||
fileReader.readAsArrayBuffer(file);
|
||||
}
|
||||
|
||||
function openManage() {
|
||||
$("#manage").dialog("open");
|
||||
}
|
||||
|
||||
function loadHTTP(url) {
|
||||
loading = true;
|
||||
$("#loading").dialog("open");
|
||||
|
||||
var req = new XMLHttpRequest();
|
||||
req.open("GET", url, true);
|
||||
req.responseType = "arraybuffer";
|
||||
|
||||
req.onload = function(event) {
|
||||
var parts = url.split(/[\/\.]/);
|
||||
var name = decodeURIComponent(parts[parts.length - 2]);
|
||||
var ext = parts[parts.length - 1].toLowerCase();
|
||||
if (disk2.setBinary(_saveDrive, name, ext, req.response)) {
|
||||
$("#disklabel" + _saveDrive).text(name);
|
||||
$("#loading").dialog("close");
|
||||
loading = false;
|
||||
}
|
||||
}
|
||||
req.send(null);
|
||||
}
|
||||
|
||||
var prefs = new Prefs();
|
||||
var runTimer = null;
|
||||
var cpu = new CPU6502();
|
||||
|
||||
var ram1 = new RAM(0x00, 0x03),
|
||||
ram2 = new RAM(0x0C, 0x1F),
|
||||
ram3 = new RAM(0x60, 0xBF);
|
||||
|
||||
var hgr = new HiresPage(1);
|
||||
var hgr2 = new HiresPage(2);
|
||||
var gr = new LoresPage(1);
|
||||
var gr2 = new LoresPage(2);
|
||||
|
||||
var rom = new Apple2ROM();
|
||||
var vm = new VideoModes(gr, hgr, gr2, hgr2);
|
||||
var mmu = {
|
||||
auxRom: function(slot, rom) {
|
||||
cpu.addPageHandler(rom);
|
||||
}
|
||||
};
|
||||
|
||||
var drivelights = new DriveLights();
|
||||
var io = new Apple2IO(cpu, vm);
|
||||
var keyboard = new KeyBoard(io);
|
||||
var parallel = new Parallel(io, new Printer(), 1);
|
||||
var disk2 = new DiskII(io, drivelights, 6);
|
||||
var slinky = new RAMFactor(mmu, io, 2, 1024 * 1024);
|
||||
var clock = new Thunderclock(mmu, io, 7);
|
||||
var lc = new LanguageCard(io, rom);
|
||||
|
||||
cpu.addPageHandler(ram1);
|
||||
cpu.addPageHandler(gr);
|
||||
cpu.addPageHandler(gr2);
|
||||
cpu.addPageHandler(ram2);
|
||||
cpu.addPageHandler(hgr);
|
||||
cpu.addPageHandler(hgr2);
|
||||
cpu.addPageHandler(ram3);
|
||||
|
||||
cpu.addPageHandler(lc);
|
||||
cpu.addPageHandler(io);
|
||||
cpu.addPageHandler(parallel);
|
||||
cpu.addPageHandler(slinky);
|
||||
cpu.addPageHandler(disk2);
|
||||
cpu.addPageHandler(clock);
|
||||
|
||||
var showFPS = false;
|
||||
|
||||
function updateKHz() {
|
||||
var now = Date.now();
|
||||
var ms = now - startTime;
|
||||
var cycles = cpu.cycles();
|
||||
var delta;
|
||||
|
||||
if (showFPS) {
|
||||
delta = frames - lastFrames;
|
||||
var fps = parseInt(delta/(ms/1000), 10);
|
||||
$("#khz").html( fps + "fps");
|
||||
} else {
|
||||
delta = cycles - lastCycles;
|
||||
khz = parseInt(delta/ms);
|
||||
$("#khz").html( khz + "KHz");
|
||||
}
|
||||
|
||||
startTime = now;
|
||||
lastCycles = cycles;
|
||||
lastFrames = frames;
|
||||
}
|
||||
|
||||
/* Audio Handling */
|
||||
initAudio(io);
|
||||
|
||||
function updateSound()
|
||||
{
|
||||
enableSound($("#enable_sound").attr("checked"));
|
||||
}
|
||||
|
||||
function dumpDisk(drive) {
|
||||
var wind = window.open("", "_blank");
|
||||
wind.document.title = $("#disklabel" + drive).text();
|
||||
wind.document.write("<pre>");
|
||||
wind.document.write(disk2.getJSON(drive, true));
|
||||
wind.document.write("</pre>");
|
||||
wind.document.close();
|
||||
}
|
||||
|
||||
function step()
|
||||
{
|
||||
if (runTimer) {
|
||||
clearInterval(runTimer);
|
||||
}
|
||||
runTimer = null;
|
||||
|
||||
cpu.step(function() {
|
||||
debug(cpu.dumpRegisters());
|
||||
debug(cpu.dumpPC());
|
||||
});
|
||||
}
|
||||
|
||||
var running = false;
|
||||
var accelerated = false;
|
||||
|
||||
function updateSpeed()
|
||||
{
|
||||
accelerated = $("#accelerator_toggle").prop("checked");
|
||||
kHz = accelerated ? 4092 : 1023;
|
||||
io.updateHz(kHz * 1000);
|
||||
if (runTimer) {
|
||||
run();
|
||||
}
|
||||
}
|
||||
|
||||
var _requestAnimationFrame =
|
||||
window.requestAnimationFrame ||
|
||||
window.mozRequestAnimationFrame ||
|
||||
window.webkitRequestAnimationFrame ||
|
||||
window.msRequestAnimationFrame;
|
||||
|
||||
function run(pc) {
|
||||
if (runTimer) {
|
||||
clearInterval(runTimer);
|
||||
}
|
||||
|
||||
if (pc) {
|
||||
cpu.setPC(pc);
|
||||
}
|
||||
|
||||
var ival = 30;
|
||||
var now, last = Date.now();
|
||||
var runFn = function() {
|
||||
now = Date.now();
|
||||
frames++;
|
||||
|
||||
var step = (now - last) * kHz, stepMax = kHz * ival;
|
||||
last = now;
|
||||
if (step > stepMax) {
|
||||
step = stepMax;
|
||||
}
|
||||
|
||||
if (document.location.hash != hashtag) {
|
||||
hashtag = document.location.hash;
|
||||
filename = hup()
|
||||
if (filename) {
|
||||
if (filename.indexOf("://") > 0) {
|
||||
loadHTTP(disk);
|
||||
} else {
|
||||
loadAjax("json/disks/" + filename + ".json");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!loading) {
|
||||
running = true;
|
||||
cpu.stepCycles(step);
|
||||
running = false;
|
||||
vm.blit();
|
||||
io.sampleTick();
|
||||
}
|
||||
|
||||
processGamepad(io);
|
||||
|
||||
if (!paused && _requestAnimationFrame) {
|
||||
_requestAnimationFrame(runFn);
|
||||
}
|
||||
};
|
||||
if (_requestAnimationFrame) {
|
||||
_requestAnimationFrame(runFn);
|
||||
} else {
|
||||
runTimer = setInterval(runFn, ival);
|
||||
}
|
||||
}
|
||||
|
||||
function stop() {
|
||||
if (runTimer) {
|
||||
clearInterval(runTimer);
|
||||
}
|
||||
runTimer = null;
|
||||
}
|
||||
|
||||
function reset()
|
||||
{
|
||||
cpu.reset();
|
||||
}
|
||||
|
||||
function loadBinary(bin) {
|
||||
stop();
|
||||
for (var idx = 0; idx < bin.length; idx++) {
|
||||
var pos = bin.start + idx;
|
||||
cpu.write(pos >> 8, pos & 0xff, bin.data[idx]);
|
||||
}
|
||||
run(bin.start);
|
||||
}
|
||||
|
||||
function selectCategory(event) {
|
||||
$("#disk_select").empty();
|
||||
var cat = disk_categories[$("#category_select").val()];
|
||||
if (cat) {
|
||||
for (var idx = 0; idx < cat.length; idx++) {
|
||||
var file = cat[idx], name = file.name;
|
||||
if (file.disk) {
|
||||
name += " - " + file.disk;
|
||||
}
|
||||
var option = $("<option />").val(file.filename).text(name)
|
||||
.appendTo("#disk_select");
|
||||
if (disk_cur_name[_loadDrive] == name) {
|
||||
option.attr("selected", "selected");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function selectDisk(event) {
|
||||
// Maybe display some info.
|
||||
}
|
||||
|
||||
function clickDisk(event) {
|
||||
doLoad();
|
||||
}
|
||||
|
||||
function loadDisk(data) {
|
||||
var name = data.name;
|
||||
var category = data.category;
|
||||
|
||||
if (data.disk) {
|
||||
name += " - " + data.disk;
|
||||
}
|
||||
|
||||
disk_cur_cat[_loadDrive] = category;
|
||||
disk_cur_name[_loadDrive] = name;
|
||||
|
||||
$("#disklabel" + _loadDrive).text(name);
|
||||
disk2.setDisk(_loadDrive, data);
|
||||
initGamepad(data.gamepad);
|
||||
}
|
||||
|
||||
function loadJSON(data) {
|
||||
if (data.type == "binary") {
|
||||
loadBinary(data);
|
||||
} else if ($.inArray(data.type, DISK_TYPES) >= 0) {
|
||||
loadDisk(data);
|
||||
}
|
||||
initGamepad(data.gamepad);
|
||||
$("#loading").dialog("close");
|
||||
loading = false;
|
||||
}
|
||||
|
||||
/*
|
||||
* LocalStorage Disk Storage
|
||||
*/
|
||||
|
||||
function updateLocalStorage() {
|
||||
var diskIndex = JSON.parse(window.localStorage.diskIndex || "{}");
|
||||
var names = [], name, cat;
|
||||
|
||||
for (name in diskIndex) {
|
||||
if (diskIndex.hasOwnProperty(name)) {
|
||||
names.push(name);
|
||||
}
|
||||
}
|
||||
|
||||
cat = disk_categories['Local Saves'] = [];
|
||||
$("#manage").empty();
|
||||
|
||||
names.forEach(function(name) {
|
||||
cat.push({'category': 'Local Saves',
|
||||
'name': name,
|
||||
'filename': 'local:' + name});
|
||||
$("#manage").append("<span class='local_save'>" +
|
||||
name +
|
||||
" <a href='#' onclick='doDelete(\"" +
|
||||
name +
|
||||
"\")'>Delete</a><br /></span>");
|
||||
});
|
||||
cat.push({'category': 'Local Saves',
|
||||
'name': 'Manage Saves...',
|
||||
'filename': 'local:__manage'});
|
||||
}
|
||||
|
||||
function saveLocalStorage(drive, name) {
|
||||
var diskIndex = JSON.parse(window.localStorage.diskIndex || "{}");
|
||||
|
||||
var json = disk2.getJSON(drive);
|
||||
diskIndex[name] = json;
|
||||
|
||||
window.localStorage.diskIndex = JSON.stringify(diskIndex);
|
||||
|
||||
window.alert("Saved");
|
||||
|
||||
drivelights.label(drive, name);
|
||||
drivelights.dirty(drive, false);
|
||||
updateLocalStorage();
|
||||
}
|
||||
|
||||
function deleteLocalStorage(name) {
|
||||
var diskIndex = JSON.parse(window.localStorage.diskIndex || "{}");
|
||||
if (diskIndex[name]) {
|
||||
delete diskIndex[name];
|
||||
window.alert("Deleted");
|
||||
}
|
||||
window.localStorage.diskIndex = JSON.stringify(diskIndex);
|
||||
updateLocalStorage();
|
||||
}
|
||||
|
||||
function loadLocalStorage(drive, name) {
|
||||
var diskIndex = JSON.parse(window.localStorage.diskIndex || "{}");
|
||||
if (diskIndex[name]) {
|
||||
disk2.setJSON(drive, diskIndex[name]);
|
||||
drivelights.label(drive, name);
|
||||
drivelights.dirty(drive, false);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Keyboard/Gamepad routines
|
||||
*/
|
||||
|
||||
var _key;
|
||||
function _keydown(evt) {
|
||||
if (evt.keyCode === 112) { // F1 - Reset
|
||||
cpu.reset();
|
||||
} else if (evt.keyCode === 113) { // F2 - Full Screen
|
||||
var elem = document.getElementById("screen");
|
||||
if (document.webkitCancelFullScreen) {
|
||||
if (document.webkitIsFullScreen) {
|
||||
document.webkitCancelFullScreen();
|
||||
} else {
|
||||
if (Element.ALLOW_KEYBOARD_INPUT) {
|
||||
elem.webkitRequestFullScreen(Element.ALLOW_KEYBOARD_INPUT);
|
||||
} else {
|
||||
elem.webkitRequestFullScreen();
|
||||
}
|
||||
}
|
||||
} else if (document.mozCancelFullScreen) {
|
||||
if (document.mozIsFullScreen) {
|
||||
document.mozCancelFullScreen();
|
||||
} else {
|
||||
elem.mozRequestFullScreen();
|
||||
}
|
||||
}
|
||||
} else if (evt.keyCode == 16) { // Shift
|
||||
keyboard.shiftKey(true);
|
||||
io.buttonDown(2);
|
||||
} else if (evt.keyCode == 17) { // Control
|
||||
keyboard.controlKey(true);
|
||||
} else if (!focused && (!evt.metaKey || evt.ctrlKey)) {
|
||||
evt.preventDefault();
|
||||
|
||||
var key = keyboard.mapKeyEvent(evt);
|
||||
if (key != 0xff) {
|
||||
io.keyDown(key);
|
||||
_key = key;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function _keyup(evt) {
|
||||
_key = 0xff;
|
||||
|
||||
if (evt.keyCode == 16) { // Shift
|
||||
keyboard.shiftKey(false);
|
||||
io.buttonUp(2);
|
||||
} else if (evt.keyCode == 17) { // Control
|
||||
keyboard.controlKey(false);
|
||||
} else {
|
||||
if (!focused) {
|
||||
io.keyUp();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function updateScreen() {
|
||||
var green = $("#green_screen").prop("checked");
|
||||
scanlines = $("#show_scanlines").prop("checked");
|
||||
|
||||
vm.green(green);
|
||||
}
|
||||
|
||||
var flipX = false;
|
||||
var flipY = false;
|
||||
var swapXY = false;
|
||||
|
||||
function updateJoystick() {
|
||||
flipX = $("#flip_x").prop("checked");
|
||||
flipY = $("#flip_y").prop("checked");
|
||||
swapXY = $("#swap_x_y").prop("checked");
|
||||
}
|
||||
|
||||
function _mousemove(evt) {
|
||||
if (gamepad) {
|
||||
return;
|
||||
}
|
||||
var s = $("#screen");
|
||||
var offset = s.offset();
|
||||
var x = (evt.pageX - offset.left) / s.width(),
|
||||
y = (evt.pageY - offset.top) / s.height(),
|
||||
z = x;
|
||||
|
||||
if (swapXY) {
|
||||
x = y;
|
||||
y = z;
|
||||
}
|
||||
|
||||
io.paddle(0, flipX ? 1 - x : x);
|
||||
io.paddle(1, flipY ? 1 - y : y);
|
||||
}
|
||||
|
||||
var paused = false;
|
||||
function pauseRun(b) {
|
||||
if (paused) {
|
||||
run();
|
||||
b.value = "Pause";
|
||||
} else {
|
||||
stop();
|
||||
b.value = "Run";
|
||||
}
|
||||
paused = !paused;
|
||||
}
|
||||
|
||||
$(function() {
|
||||
hashtag = document.location.hash;
|
||||
|
||||
$("button,input[type=button],a.button").button().focus(function() {
|
||||
// Crazy hack required by Chrome
|
||||
var self = this;
|
||||
window.setTimeout(function() {
|
||||
self.blur();
|
||||
}, 1)
|
||||
});
|
||||
|
||||
var canvas = document.getElementById("screen");
|
||||
var context = canvas.getContext('2d');
|
||||
|
||||
vm.setContext(context);
|
||||
|
||||
/*
|
||||
* Input Handling
|
||||
*/
|
||||
|
||||
$(window).keydown(_keydown);
|
||||
$(window).keyup(_keyup);
|
||||
|
||||
$("canvas").mousedown(function(evt) {
|
||||
if (!gamepad) {
|
||||
io.buttonDown(evt.which == 1 ? 0 : 1);
|
||||
}
|
||||
evt.preventDefault();
|
||||
})
|
||||
.mouseup(function(evt) {
|
||||
if (!gamepad) {
|
||||
io.buttonUp(evt.which == 1 ? 0 : 1);
|
||||
}
|
||||
})
|
||||
.bind("contextmenu", function(e) { e.preventDefault(); });
|
||||
|
||||
$('body').mousemove(_mousemove);
|
||||
|
||||
$("input,textarea").focus(function() { focused = true; });
|
||||
$("input,textarea").blur(function() { focused = false; });
|
||||
|
||||
keyboard.create($("#keyboard"));
|
||||
|
||||
if (prefs.havePrefs()) {
|
||||
$("input[type=checkbox]").each(function() {
|
||||
var val = prefs.readPref(this.id);
|
||||
if (val != null)
|
||||
this.checked = JSON.parse(val);
|
||||
});
|
||||
$("input[type=checkbox]").change(function() {
|
||||
prefs.writePref(this.id, JSON.stringify(this.checked));
|
||||
});
|
||||
}
|
||||
|
||||
reset();
|
||||
run();
|
||||
setInterval(updateKHz, 1000);
|
||||
updateSound();
|
||||
updateScreen();
|
||||
updateSpeed();
|
||||
|
||||
var cancel = function() { $(this).dialog("close"); };
|
||||
$("#loading").dialog({ autoOpen: false, modal: true });
|
||||
$("#options").dialog({ autoOpen: false,
|
||||
modal: true,
|
||||
width: 320,
|
||||
height: 400,
|
||||
buttons: {"Close": cancel }});
|
||||
$("#load").dialog({ autoOpen: false,
|
||||
modal: true,
|
||||
width: 540,
|
||||
buttons: {"Cancel": cancel, "Load": doLoad }});
|
||||
$("#save").dialog({ autoOpen: false,
|
||||
modal: true,
|
||||
width: 320,
|
||||
buttons: {"Cancel": cancel, "Save": doSave }});
|
||||
$("#manage").dialog({ autoOpen: false,
|
||||
modal: true,
|
||||
width: 320,
|
||||
buttons: {"Close": cancel }});
|
||||
|
||||
if (window.localStorage !== undefined) {
|
||||
$("button.disksave").show();
|
||||
}
|
||||
|
||||
var oldcat = "";
|
||||
for (var idx = 0; idx < disk_index.length; idx++) {
|
||||
var file = disk_index[idx];
|
||||
var cat = file.category;
|
||||
var name = file.name, disk = file.disk;
|
||||
if (cat != oldcat) {
|
||||
$("<option />").val(cat).text(cat).appendTo("#category_select");
|
||||
disk_categories[cat] = [];
|
||||
oldcat = cat;
|
||||
}
|
||||
disk_categories[cat].push(file);
|
||||
if (disk) {
|
||||
if (!disk_sets[name]) {
|
||||
disk_sets[name] = []
|
||||
}
|
||||
disk_sets[name].push(file);
|
||||
}
|
||||
}
|
||||
$("<option/>").text("Local Saves").appendTo("#category_select");
|
||||
|
||||
updateLocalStorage();
|
||||
initGamepad();
|
||||
|
||||
// Check for disks in hashtag
|
||||
|
||||
var filename = gup("disk") || hup();
|
||||
if (filename) {
|
||||
if (filename.indexOf("://") > 0) {
|
||||
loadHTTP(filename);
|
||||
} else {
|
||||
loadAjax("json/disks/" + filename + ".json");
|
||||
}
|
||||
}
|
||||
|
||||
if (navigator.userAgent.match(/(iPod|iPhone|iPad)/)) {
|
||||
$("select").removeAttr("multiple").css("height", "auto");
|
||||
}
|
||||
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div style="margin: auto; width: 604px">
|
||||
|
772
apple2jse.html
772
apple2jse.html
@ -1,6 +1,6 @@
|
||||
<!DOCTYPE html><!-- -*- mode: HTML; indent-tabs-mode: nil -*- -->
|
||||
<!--
|
||||
Copyright 2010-2013 Will Scullin <scullin@scullinsteel.com>
|
||||
Copyright 2010-2016 Will Scullin <scullin@scullinsteel.com>
|
||||
|
||||
Permission to use, copy, modify, distribute, and sell this software and its
|
||||
documentation for any purpose is hereby granted without fee, provided that
|
||||
@ -51,6 +51,7 @@
|
||||
<script type="text/javascript" src="js/apple2e.js"></script>
|
||||
<script type="text/javascript" src="js/apple2e-enhanced.js"></script>
|
||||
<script type="text/javascript" src="js/apple2echar.js"></script>
|
||||
<script type="text/javascript" src="js/applesoft/decompiler.js"></script>
|
||||
<script type="text/javascript" src="js/canvas2e.js"></script>
|
||||
<script type="text/javascript" src="js/slot3.js"></script>
|
||||
<script type="text/javascript" src="js/apple2io.js"></script>
|
||||
@ -68,774 +69,7 @@
|
||||
<!-- Disk Index -->
|
||||
<script type="text/javascript" src="json/disks/index.js"></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
var enhanced = true;
|
||||
var focused = false;
|
||||
var startTime = Date.now();
|
||||
var lastCycles = 0;
|
||||
var frames = 0, lastFrames = 0;
|
||||
var paused = false;
|
||||
var sound = true;
|
||||
|
||||
var hashtag;
|
||||
|
||||
var disk_categories = {'Local Saves': []};
|
||||
var disk_sets = {}
|
||||
var disk_cur_name = [];
|
||||
var disk_cur_cat = [];
|
||||
|
||||
function DriveLights()
|
||||
{
|
||||
return {
|
||||
driveLight: function(drive, on) {
|
||||
$("#disk" + drive).css("background-image",
|
||||
on ? "url(css/red-on-16.png)" :
|
||||
"url(css/red-off-16.png)");
|
||||
},
|
||||
dirty: function(drive, dirty) {
|
||||
},
|
||||
label: function(drive, label) {
|
||||
$("#disklabel" + drive).text(label);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var DISK_TYPES = ['dsk','do','po','raw','nib','2mg'];
|
||||
var TAPE_TYPES = ['wav','aiff','aif','mp3'];
|
||||
|
||||
var _saveDrive = 1;
|
||||
var _loadDrive = 1;
|
||||
|
||||
function openLoad(drive, event)
|
||||
{
|
||||
_loadDrive = drive;
|
||||
if (disk_cur_cat[drive]) {
|
||||
$("#category_select").val(disk_cur_cat[drive]).change();
|
||||
}
|
||||
$("#load").dialog("open");
|
||||
}
|
||||
|
||||
function openSave(drive, event)
|
||||
{
|
||||
_saveDrive = drive;
|
||||
$("#save_name").val($("#disklabel" + drive).text());
|
||||
$("#save").dialog("open");
|
||||
}
|
||||
|
||||
var loading = false;
|
||||
|
||||
function loadAjax(url) {
|
||||
loading = true;
|
||||
$("#loading").dialog("open");
|
||||
|
||||
$.ajax({ url: url,
|
||||
cache: false,
|
||||
dataType: "jsonp",
|
||||
jsonp: false,
|
||||
global: false
|
||||
});
|
||||
}
|
||||
|
||||
function doLoad() {
|
||||
var urls = $("#disk_select").val(), url;
|
||||
if (urls && urls.length) {
|
||||
if (typeof(urls) == "string") {
|
||||
url = urls;
|
||||
} else {
|
||||
url = urls[0];
|
||||
}
|
||||
}
|
||||
|
||||
var files = $("#local_file").prop("files");
|
||||
if (files.length == 1) {
|
||||
doLoadLocal();
|
||||
} else if (url) {
|
||||
var filename;
|
||||
$("#load").dialog("close");
|
||||
if (url.substr(0,6) == "local:") {
|
||||
filename = url.substr(6);
|
||||
if (filename == "__manage") {
|
||||
openManage();
|
||||
} else {
|
||||
loadLocalStorage(_loadDrive, filename);
|
||||
}
|
||||
} else {
|
||||
var r1 = /json\/disks\/(.*).json$/.exec(url);
|
||||
if (r1 && _loadDrive == 1) {
|
||||
filename = r1[1];
|
||||
document.location.hash = filename;
|
||||
}
|
||||
loadAjax(url);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function doSave() {
|
||||
var name = $("#save_name").val();
|
||||
saveLocalStorage(_saveDrive, name);
|
||||
$("#save").dialog("close");
|
||||
}
|
||||
|
||||
function doDelete(name) {
|
||||
if (confirm("Delete " + name + "?")) {
|
||||
deleteLocalStorage(name);
|
||||
}
|
||||
}
|
||||
|
||||
function doLoadLocal() {
|
||||
var files = $("#local_file").prop("files")
|
||||
if (files.length == 1) {
|
||||
var file = files[0];
|
||||
var parts = file.name.split(".");
|
||||
var ext = parts[parts.length - 1].toLowerCase();
|
||||
if ($.inArray(ext, DISK_TYPES) >= 0) {
|
||||
doLoadLocalDisk(file);
|
||||
} else if ($.inArray(ext, TAPE_TYPES) >= 0) {
|
||||
doLoadLocalTape(file);
|
||||
} else {
|
||||
alert('Unknown file type: ' + ext);
|
||||
$("#load").dialog("close");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function doLoadLocalDisk(file) {
|
||||
var fileReader = new FileReader();
|
||||
fileReader.onload = function(event) {
|
||||
var parts = file.name.split(".");
|
||||
var name = parts[0], ext = parts[parts.length - 1].toLowerCase();
|
||||
if (disk2.setBinary(_saveDrive, name, ext, this.result)) {
|
||||
$("#disklabel" + _saveDrive).text(name);
|
||||
$("#load").dialog("close");
|
||||
initGamepad();
|
||||
}
|
||||
}
|
||||
fileReader.readAsArrayBuffer(file);
|
||||
}
|
||||
|
||||
function doLoadLocalTape(file) {
|
||||
// Audio Buffer Source
|
||||
if (typeof webkitAudioContext != "undefined") {
|
||||
var context = new webkitAudioContext();
|
||||
} else {
|
||||
alert("Not supported by your browser");
|
||||
$("#load").dialog("close");
|
||||
return;
|
||||
}
|
||||
|
||||
var fileReader = new FileReader();
|
||||
fileReader.onload = function(ev) {
|
||||
context.decodeAudioData(ev.target.result, function(buffer) {
|
||||
var buf = [];
|
||||
var data = buffer.getChannelData(0), datum = data[0];
|
||||
var old = (datum > 0.0), current;
|
||||
var last = 0, delta, ival;
|
||||
debug('Sample Count: ' + data.length);
|
||||
debug('Sample rate: ' + buffer.sampleRate);
|
||||
for (var idx = 1; idx < data.length; idx++) {
|
||||
datum = data[idx];
|
||||
if ((datum > 0.1) || (datum < -0.1)) {
|
||||
current = (datum > 0.0);
|
||||
if (current != old) {
|
||||
delta = idx - last;
|
||||
if (delta > 2000000) {
|
||||
delta = 2000000;
|
||||
}
|
||||
ival = delta / buffer.sampleRate * 1000;
|
||||
if (ival >= 0.550 && ival < 0.750) {
|
||||
ival = 0.650; // Header
|
||||
} else if (ival >= 0.175 && ival < 0.225) {
|
||||
ival = 0.200; // sync 1
|
||||
} else if (ival >= 0.225 && ival < 0.275) {
|
||||
ival = 0.250; // 0 / sync 2
|
||||
} else if (ival >= 0.450 && ival < 0.550) {
|
||||
ival = 0.500; // 1
|
||||
} else {
|
||||
// debug(idx + ' ' + buf.length + ' ' + ival);
|
||||
}
|
||||
buf.push(parseInt(ival * kHz));
|
||||
old = current;
|
||||
last = idx;
|
||||
}
|
||||
}
|
||||
}
|
||||
io.setTape(buf);
|
||||
$("#load").dialog("close");
|
||||
});
|
||||
};
|
||||
fileReader.readAsArrayBuffer(file);
|
||||
}
|
||||
|
||||
function openManage() {
|
||||
$("#manage").dialog("open");
|
||||
}
|
||||
|
||||
function loadHTTP(url) {
|
||||
loading = true;
|
||||
$("#loading").dialog("open");
|
||||
|
||||
var req = new XMLHttpRequest();
|
||||
req.open("GET", url, true);
|
||||
req.responseType = "arraybuffer";
|
||||
|
||||
req.onload = function(event) {
|
||||
var parts = url.split(/[\/\.]/);
|
||||
var name = decodeURIComponent(parts[parts.length - 2]);
|
||||
var ext = parts[parts.length - 1].toLowerCase();
|
||||
if (disk2.setBinary(_saveDrive, name, ext, req.response)) {
|
||||
$("#disklabel" + _saveDrive).text(name);
|
||||
$("#loading").dialog("close");
|
||||
loading = false;
|
||||
}
|
||||
}
|
||||
req.send(null);
|
||||
}
|
||||
|
||||
var prefs = new Prefs();
|
||||
var runTimer = null;
|
||||
var cpu = new CPU6502({"65C02": enhanced});
|
||||
|
||||
var hgr = new HiresPage(1);
|
||||
var hgr2 = new HiresPage(2);
|
||||
var gr = new LoresPage(1);
|
||||
var gr2 = new LoresPage(2);
|
||||
|
||||
var rom;
|
||||
if (enhanced) {
|
||||
rom = new Apple2eEnhancedROM();
|
||||
} else {
|
||||
rom = new Apple2eROM();
|
||||
}
|
||||
var vm = new VideoModes(gr, hgr, gr2, hgr2);
|
||||
|
||||
var drivelights = new DriveLights();
|
||||
var io = new Apple2IO(cpu, vm);
|
||||
var keyboard = new KeyBoard(io);
|
||||
|
||||
var mmu = new MMU(cpu, gr, gr2, hgr, hgr2, io, rom);
|
||||
|
||||
var parallel = new Parallel(io, new Printer(), 1);
|
||||
var disk2 = new DiskII(io, drivelights, 6);
|
||||
var slot3 = new Slot3(mmu, rom);
|
||||
var slinky = new RAMFactor(mmu, io, 2, 1024 * 1024);
|
||||
var clock = new Thunderclock(mmu, io, 7);
|
||||
|
||||
mmu.addSlot(1, parallel);
|
||||
mmu.addSlot(2, slinky);
|
||||
mmu.addSlot(3, slot3);
|
||||
mmu.addSlot(6, disk2);
|
||||
mmu.addSlot(7, clock);
|
||||
|
||||
cpu.addPageHandler(mmu);
|
||||
|
||||
var showFPS = false;
|
||||
|
||||
function updateKHz() {
|
||||
var now = Date.now();
|
||||
var ms = now - startTime;
|
||||
var cycles = cpu.cycles();
|
||||
var delta;
|
||||
|
||||
if (showFPS) {
|
||||
delta = frames - lastFrames;
|
||||
var fps = parseInt(delta/(ms/1000), 10);
|
||||
$("#khz").html( fps + "fps");
|
||||
} else {
|
||||
delta = cycles - lastCycles;
|
||||
khz = parseInt(delta/ms);
|
||||
$("#khz").html( khz + "KHz");
|
||||
}
|
||||
|
||||
startTime = now;
|
||||
lastCycles = cycles;
|
||||
lastFrames = frames;
|
||||
}
|
||||
|
||||
/* Audio Handling */
|
||||
initAudio(io);
|
||||
|
||||
function updateSound()
|
||||
{
|
||||
enableSound($("#enable_sound").attr("checked"));
|
||||
}
|
||||
|
||||
function dumpDisk(drive) {
|
||||
var wind = window.open("", "_blank");
|
||||
wind.document.title = $("#disklabel" + drive).text();
|
||||
wind.document.write("<pre>");
|
||||
wind.document.write(disk2.getJSON(drive, true));
|
||||
wind.document.write("</pre>");
|
||||
wind.document.close();
|
||||
}
|
||||
|
||||
function step()
|
||||
{
|
||||
if (runTimer) {
|
||||
clearInterval(runTimer);
|
||||
}
|
||||
runTimer = null;
|
||||
|
||||
cpu.step(function() {
|
||||
debug(cpu.dumpRegisters());
|
||||
debug(cpu.dumpPC());
|
||||
});
|
||||
}
|
||||
|
||||
var running = false;
|
||||
var accelerated = false;
|
||||
|
||||
function updateSpeed()
|
||||
{
|
||||
accelerated = $("#accelerator_toggle").prop("checked");
|
||||
kHz = accelerated ? 4092 : 1023;
|
||||
io.updateHz(kHz * 1000);
|
||||
if (runTimer) {
|
||||
run();
|
||||
}
|
||||
}
|
||||
|
||||
var _requestAnimationFrame =
|
||||
window.requestAnimationFrame ||
|
||||
window.mozRequestAnimationFrame ||
|
||||
window.webkitRequestAnimationFrame ||
|
||||
window.msRequestAnimationFrame;
|
||||
|
||||
function run(pc) {
|
||||
if (runTimer) {
|
||||
clearInterval(runTimer);
|
||||
}
|
||||
|
||||
if (pc) {
|
||||
cpu.setPC(pc);
|
||||
}
|
||||
|
||||
var ival = 30;
|
||||
var now, last = Date.now();
|
||||
var runFn = function() {
|
||||
now = Date.now();
|
||||
frames++;
|
||||
|
||||
var step = (now - last) * kHz, stepMax = kHz * ival;
|
||||
last = now;
|
||||
if (step > stepMax) {
|
||||
step = stepMax;
|
||||
}
|
||||
|
||||
if (document.location.hash != hashtag) {
|
||||
hashtag = document.location.hash;
|
||||
filename = hup()
|
||||
if (filename) {
|
||||
if (filename.indexOf("://") > 0) {
|
||||
loadHTTP(disk);
|
||||
} else {
|
||||
loadAjax("json/disks/" + filename + ".json");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!loading) {
|
||||
mmu.resetVB();
|
||||
running = true;
|
||||
cpu.stepCycles(step);
|
||||
running = false;
|
||||
vm.blit();
|
||||
io.sampleTick();
|
||||
}
|
||||
|
||||
processGamepad(io);
|
||||
|
||||
if (!paused && _requestAnimationFrame) {
|
||||
_requestAnimationFrame(runFn);
|
||||
}
|
||||
};
|
||||
if (_requestAnimationFrame) {
|
||||
_requestAnimationFrame(runFn);
|
||||
} else {
|
||||
runTimer = setInterval(runFn, ival);
|
||||
}
|
||||
}
|
||||
|
||||
function stop() {
|
||||
if (runTimer) {
|
||||
clearInterval(runTimer);
|
||||
}
|
||||
runTimer = null;
|
||||
}
|
||||
|
||||
function reset()
|
||||
{
|
||||
cpu.reset();
|
||||
}
|
||||
|
||||
function loadBinary(bin) {
|
||||
stop();
|
||||
for (var idx = 0; idx < bin.length; idx++) {
|
||||
var pos = bin.start + idx;
|
||||
cpu.write(pos >> 8, pos & 0xff, bin.data[idx]);
|
||||
}
|
||||
run(bin.start);
|
||||
}
|
||||
|
||||
function selectCategory(event) {
|
||||
$("#disk_select").empty();
|
||||
var cat = disk_categories[$("#category_select").val()];
|
||||
if (cat) {
|
||||
for (var idx = 0; idx < cat.length; idx++) {
|
||||
var file = cat[idx], name = file.name;
|
||||
if (file.disk) {
|
||||
name += " - " + file.disk;
|
||||
}
|
||||
var option = $("<option />").val(file.filename).text(name)
|
||||
.appendTo("#disk_select");
|
||||
if (disk_cur_name[_loadDrive] == name) {
|
||||
option.attr("selected", "selected");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function selectDisk(event) {
|
||||
// Maybe display some info.
|
||||
}
|
||||
|
||||
function clickDisk(event) {
|
||||
doLoad();
|
||||
}
|
||||
|
||||
function loadDisk(data) {
|
||||
var name = data.name;
|
||||
var category = data.category;
|
||||
|
||||
if (data.disk) {
|
||||
name += " - " + data.disk;
|
||||
}
|
||||
|
||||
disk_cur_cat[_loadDrive] = category;
|
||||
disk_cur_name[_loadDrive] = name;
|
||||
|
||||
$("#disklabel" + _loadDrive).text(name);
|
||||
disk2.setDisk(_loadDrive, data);
|
||||
initGamepad(data.gamepad);
|
||||
}
|
||||
|
||||
function loadJSON(data) {
|
||||
if (data.type == "binary") {
|
||||
loadBinary(data);
|
||||
} else if ($.inArray(data.type, DISK_TYPES) >= 0) {
|
||||
loadDisk(data);
|
||||
}
|
||||
initGamepad(data.gamepad);
|
||||
$("#loading").dialog("close");
|
||||
loading = false;
|
||||
}
|
||||
|
||||
/*
|
||||
* LocalStorage Disk Storage
|
||||
*/
|
||||
|
||||
function updateLocalStorage() {
|
||||
var diskIndex = JSON.parse(window.localStorage.diskIndex || "{}");
|
||||
var names = [], name, cat;
|
||||
|
||||
for (name in diskIndex) {
|
||||
if (diskIndex.hasOwnProperty(name)) {
|
||||
names.push(name);
|
||||
}
|
||||
}
|
||||
|
||||
cat = disk_categories['Local Saves'] = [];
|
||||
$("#manage").empty();
|
||||
|
||||
names.forEach(function(name) {
|
||||
cat.push({'category': 'Local Saves',
|
||||
'name': name,
|
||||
'filename': 'local:' + name});
|
||||
$("#manage").append("<span class='local_save'>" +
|
||||
name +
|
||||
" <a href='#' onclick='doDelete(\"" +
|
||||
name +
|
||||
"\")'>Delete</a><br /></span>");
|
||||
});
|
||||
cat.push({'category': 'Local Saves',
|
||||
'name': 'Manage Saves...',
|
||||
'filename': 'local:__manage'});
|
||||
}
|
||||
|
||||
function saveLocalStorage(drive, name) {
|
||||
var diskIndex = JSON.parse(window.localStorage.diskIndex || "{}");
|
||||
|
||||
var json = disk2.getJSON(drive);
|
||||
diskIndex[name] = json;
|
||||
|
||||
window.localStorage.diskIndex = JSON.stringify(diskIndex);
|
||||
|
||||
window.alert("Saved");
|
||||
|
||||
drivelights.label(drive, name);
|
||||
drivelights.dirty(drive, false);
|
||||
updateLocalStorage();
|
||||
}
|
||||
|
||||
function deleteLocalStorage(name) {
|
||||
var diskIndex = JSON.parse(window.localStorage.diskIndex || "{}");
|
||||
if (diskIndex[name]) {
|
||||
delete diskIndex[name];
|
||||
window.alert("Deleted");
|
||||
}
|
||||
window.localStorage.diskIndex = JSON.stringify(diskIndex);
|
||||
updateLocalStorage();
|
||||
}
|
||||
|
||||
function loadLocalStorage(drive, name) {
|
||||
var diskIndex = JSON.parse(window.localStorage.diskIndex || "{}");
|
||||
if (diskIndex[name]) {
|
||||
disk2.setJSON(drive, diskIndex[name]);
|
||||
drivelights.label(drive, name);
|
||||
drivelights.dirty(drive, false);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Keyboard/Gamepad routines
|
||||
*/
|
||||
|
||||
var _key;
|
||||
function _keydown(evt) {
|
||||
if (evt.keyCode === 112) { // F1 - Reset
|
||||
cpu.reset();
|
||||
} else if (evt.keyCode === 113) { // F2 - Full Screen
|
||||
var elem = document.getElementById("screen");
|
||||
if (document.webkitCancelFullScreen) {
|
||||
if (document.webkitIsFullScreen) {
|
||||
document.webkitCancelFullScreen();
|
||||
} else {
|
||||
if (Element.ALLOW_KEYBOARD_INPUT) {
|
||||
elem.webkitRequestFullScreen(Element.ALLOW_KEYBOARD_INPUT);
|
||||
} else {
|
||||
elem.webkitRequestFullScreen();
|
||||
}
|
||||
}
|
||||
} else if (document.mozCancelFullScreen) {
|
||||
if (document.mozIsFullScreen) {
|
||||
document.mozCancelFullScreen();
|
||||
} else {
|
||||
elem.mozRequestFullScreen();
|
||||
}
|
||||
}
|
||||
} else if (evt.keyCode == 16) { // Shift
|
||||
keyboard.shiftKey(true);
|
||||
io.buttonDown(2);
|
||||
} else if (evt.keyCode == 17) { // Control
|
||||
keyboard.controlKey(true);
|
||||
} else if (evt.keyCode == 91 || evt.keyCode == 93) { // Command
|
||||
keyboard.commandKey(true);
|
||||
} else if (evt.keyCode == 18) { // Alt
|
||||
keyboard.optionKey(true);
|
||||
} else if (!focused) {
|
||||
evt.preventDefault();
|
||||
|
||||
var key = keyboard.mapKeyEvent(evt);
|
||||
if (key != 0xff) {
|
||||
io.keyDown(key);
|
||||
_key = key;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function _keyup(evt) {
|
||||
_key = 0xff;
|
||||
|
||||
if (evt.keyCode == 16) { // Shift
|
||||
keyboard.shiftKey(false);
|
||||
io.buttonUp(2);
|
||||
} else if (evt.keyCode == 17) { // Control
|
||||
keyboard.controlKey(false);
|
||||
} else if (evt.keyCode == 91 || evt.keyCode == 93) { // Command
|
||||
keyboard.commandKey(false);
|
||||
} else if (evt.keyCode == 18) { // Alt
|
||||
keyboard.optionKey(false);
|
||||
} else {
|
||||
if (!focused) {
|
||||
io.keyUp();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function updateScreen() {
|
||||
var green = $("#green_screen").prop("checked");
|
||||
scanlines = $("#show_scanlines").prop("checked");
|
||||
|
||||
vm.green(green);
|
||||
}
|
||||
|
||||
var flipX = false;
|
||||
var flipY = false;
|
||||
var swapXY = false;
|
||||
|
||||
function updateJoystick() {
|
||||
flipX = $("#flip_x").prop("checked");
|
||||
flipY = $("#flip_y").prop("checked");
|
||||
swapXY = $("#swap_x_y").prop("checked");
|
||||
}
|
||||
|
||||
function _mousemove(evt) {
|
||||
if (gamepad) {
|
||||
return;
|
||||
}
|
||||
var s = $("#screen");
|
||||
var offset = s.offset();
|
||||
var x = (evt.pageX - offset.left) / s.width(),
|
||||
y = (evt.pageY - offset.top) / s.height(),
|
||||
z = x;
|
||||
|
||||
if (swapXY) {
|
||||
x = y;
|
||||
y = z;
|
||||
}
|
||||
|
||||
io.paddle(0, flipX ? 1 - x : x);
|
||||
io.paddle(1, flipY ? 1 - y : y);
|
||||
}
|
||||
|
||||
var paused = false;
|
||||
function pauseRun(b) {
|
||||
if (paused) {
|
||||
run();
|
||||
b.value = "Pause";
|
||||
} else {
|
||||
stop();
|
||||
b.value = "Run";
|
||||
}
|
||||
paused = !paused;
|
||||
}
|
||||
|
||||
$(function() {
|
||||
hashtag = document.location.hash;
|
||||
|
||||
$("button,input[type=button],a.button").button().focus(function() {
|
||||
// Crazy hack required by Chrome
|
||||
var self = this;
|
||||
window.setTimeout(function() {
|
||||
self.blur();
|
||||
}, 1)
|
||||
});
|
||||
|
||||
var canvas = document.getElementById("screen");
|
||||
var context = canvas.getContext('2d');
|
||||
|
||||
vm.setContext(context);
|
||||
|
||||
/*
|
||||
* Input Handling
|
||||
*/
|
||||
|
||||
$(window).keydown(_keydown);
|
||||
$(window).keyup(_keyup);
|
||||
|
||||
$("canvas").mousedown(function(evt) {
|
||||
if (!gamepad) {
|
||||
io.buttonDown(evt.which == 1 ? 0 : 1);
|
||||
}
|
||||
evt.preventDefault();
|
||||
})
|
||||
.mouseup(function(evt) {
|
||||
if (!gamepad) {
|
||||
io.buttonUp(evt.which == 1 ? 0 : 1);
|
||||
}
|
||||
})
|
||||
.mousemove(_mousemove)
|
||||
.bind("contextmenu", function(e) { e.preventDefault(); });
|
||||
|
||||
$("input,textarea").focus(function() { focused = true; })
|
||||
.blur(function() { focused = false; });
|
||||
|
||||
$("body > div").hover(function() { focused = false; },
|
||||
function() { focused = true; });
|
||||
|
||||
|
||||
keyboard.create($("#keyboard"));
|
||||
|
||||
if (prefs.havePrefs()) {
|
||||
$("input[type=checkbox]").each(function() {
|
||||
var val = prefs.readPref(this.id);
|
||||
if (val != null)
|
||||
this.checked = JSON.parse(val);
|
||||
});
|
||||
$("input[type=checkbox]").change(function() {
|
||||
prefs.writePref(this.id, JSON.stringify(this.checked));
|
||||
});
|
||||
}
|
||||
|
||||
reset();
|
||||
run();
|
||||
setInterval(updateKHz, 1000);
|
||||
updateSound();
|
||||
updateScreen();
|
||||
updateSpeed();
|
||||
|
||||
var cancel = function() { $(this).dialog("close"); };
|
||||
$("#loading").dialog({ autoOpen: false, modal: true });
|
||||
$("#options").dialog({ autoOpen: false,
|
||||
modal: true,
|
||||
width: 320,
|
||||
height: 400,
|
||||
buttons: {"Close": cancel }});
|
||||
$("#load").dialog({ autoOpen: false,
|
||||
modal: true,
|
||||
width: 540,
|
||||
buttons: {"Cancel": cancel, "Load": doLoad }});
|
||||
$("#save").dialog({ autoOpen: false,
|
||||
modal: true,
|
||||
width: 320,
|
||||
buttons: {"Cancel": cancel, "Save": doSave }});
|
||||
$("#manage").dialog({ autoOpen: false,
|
||||
modal: true,
|
||||
width: 320,
|
||||
buttons: {"Close": cancel }});
|
||||
|
||||
if (window.localStorage !== undefined) {
|
||||
$("button.disksave").show();
|
||||
}
|
||||
|
||||
var oldcat = "";
|
||||
for (var idx = 0; idx < disk_index.length; idx++) {
|
||||
var file = disk_index[idx];
|
||||
var cat = file.category;
|
||||
var name = file.name, disk = file.disk;
|
||||
if (cat != oldcat) {
|
||||
$("<option />").val(cat).text(cat).appendTo("#category_select");
|
||||
disk_categories[cat] = [];
|
||||
oldcat = cat;
|
||||
}
|
||||
disk_categories[cat].push(file);
|
||||
if (disk) {
|
||||
if (!disk_sets[name]) {
|
||||
disk_sets[name] = []
|
||||
}
|
||||
disk_sets[name].push(file);
|
||||
}
|
||||
}
|
||||
$("<option/>").text("Local Saves").appendTo("#category_select");
|
||||
|
||||
updateLocalStorage();
|
||||
|
||||
// Check for disks in hashtag
|
||||
|
||||
var filename = gup("disk") || hup();
|
||||
if (filename) {
|
||||
if (filename.indexOf("://") > 0) {
|
||||
loadHTTP(filename);
|
||||
} else {
|
||||
loadAjax("json/disks/" + filename + ".json");
|
||||
}
|
||||
}
|
||||
|
||||
if (navigator.userAgent.match(/(iPod|iPhone|iPad)/)) {
|
||||
$("select").removeAttr("multiple").css("height", "auto");
|
||||
}
|
||||
|
||||
});
|
||||
</script>
|
||||
<script type="text/javascript" src="js/main2e.js"></script>
|
||||
</head>
|
||||
<body class="apple2e">
|
||||
<div style="margin: auto; width: 604px">
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright 2010-2013 Will Scullin */
|
||||
/* Copyright 2010-2016 Will Scullin */
|
||||
|
||||
.disklabel {
|
||||
color: #000;
|
||||
|
523
js/apple2char.js
523
js/apple2char.js
@ -1,265 +1,260 @@
|
||||
/* -*- mode: JavaScript; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/*exported apple2_charset */
|
||||
|
||||
/*global bytify */
|
||||
/*exported charset */
|
||||
|
||||
var charset = [
|
||||
0x00,0x1c,0x22,0x2a,0x2e,0x2c,0x20,0x1e,
|
||||
0x00,0x08,0x14,0x22,0x22,0x3e,0x22,0x22,
|
||||
0x00,0x3c,0x22,0x22,0x3c,0x22,0x22,0x3c,
|
||||
0x00,0x1c,0x22,0x20,0x20,0x20,0x22,0x1c,
|
||||
0x00,0x3c,0x22,0x22,0x22,0x22,0x22,0x3c,
|
||||
0x00,0x3e,0x20,0x20,0x3c,0x20,0x20,0x3e,
|
||||
0x00,0x3e,0x20,0x20,0x3c,0x20,0x20,0x20,
|
||||
0x00,0x1e,0x20,0x20,0x20,0x26,0x22,0x1e,
|
||||
0x00,0x22,0x22,0x22,0x3e,0x22,0x22,0x22,
|
||||
0x00,0x1c,0x08,0x08,0x08,0x08,0x08,0x1c,
|
||||
0x00,0x02,0x02,0x02,0x02,0x02,0x22,0x1c,
|
||||
0x00,0x22,0x24,0x28,0x30,0x28,0x24,0x22,
|
||||
0x00,0x20,0x20,0x20,0x20,0x20,0x20,0x3e,
|
||||
0x00,0x22,0x36,0x2a,0x2a,0x22,0x22,0x22,
|
||||
0x00,0x22,0x22,0x32,0x2a,0x26,0x22,0x22,
|
||||
0x00,0x1c,0x22,0x22,0x22,0x22,0x22,0x1c,
|
||||
0x00,0x3c,0x22,0x22,0x3c,0x20,0x20,0x20,
|
||||
0x00,0x1c,0x22,0x22,0x22,0x2a,0x24,0x1a,
|
||||
0x00,0x3c,0x22,0x22,0x3c,0x28,0x24,0x22,
|
||||
0x00,0x1c,0x22,0x20,0x1c,0x02,0x22,0x1c,
|
||||
0x00,0x3e,0x08,0x08,0x08,0x08,0x08,0x08,
|
||||
0x00,0x22,0x22,0x22,0x22,0x22,0x22,0x1c,
|
||||
0x00,0x22,0x22,0x22,0x22,0x22,0x14,0x08,
|
||||
0x00,0x22,0x22,0x22,0x2a,0x2a,0x36,0x22,
|
||||
0x00,0x22,0x22,0x14,0x08,0x14,0x22,0x22,
|
||||
0x00,0x22,0x22,0x14,0x08,0x08,0x08,0x08,
|
||||
0x00,0x3e,0x02,0x04,0x08,0x10,0x20,0x3e,
|
||||
0x00,0x3e,0x30,0x30,0x30,0x30,0x30,0x3e,
|
||||
0x00,0x00,0x20,0x10,0x08,0x04,0x02,0x00,
|
||||
0x00,0x3e,0x06,0x06,0x06,0x06,0x06,0x3e,
|
||||
0x00,0x00,0x00,0x08,0x14,0x22,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3e,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x08,0x08,0x08,0x08,0x08,0x00,0x08,
|
||||
0x00,0x14,0x14,0x14,0x00,0x00,0x00,0x00,
|
||||
0x00,0x14,0x14,0x3e,0x14,0x3e,0x14,0x14,
|
||||
0x00,0x08,0x1e,0x28,0x1c,0x0a,0x3c,0x08,
|
||||
0x00,0x30,0x32,0x04,0x08,0x10,0x26,0x06,
|
||||
0x00,0x10,0x28,0x28,0x10,0x2a,0x24,0x1a,
|
||||
0x00,0x08,0x08,0x08,0x00,0x00,0x00,0x00,
|
||||
0x00,0x08,0x10,0x20,0x20,0x20,0x10,0x08,
|
||||
0x00,0x08,0x04,0x02,0x02,0x02,0x04,0x08,
|
||||
0x00,0x08,0x2a,0x1c,0x08,0x1c,0x2a,0x08,
|
||||
0x00,0x00,0x08,0x08,0x3e,0x08,0x08,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x08,0x08,0x10,
|
||||
0x00,0x00,0x00,0x00,0x3e,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,
|
||||
0x00,0x00,0x02,0x04,0x08,0x10,0x20,0x00,
|
||||
0x00,0x1c,0x22,0x26,0x2a,0x32,0x22,0x1c,
|
||||
0x00,0x08,0x18,0x08,0x08,0x08,0x08,0x1c,
|
||||
0x00,0x1c,0x22,0x02,0x0c,0x10,0x20,0x3e,
|
||||
0x00,0x3e,0x02,0x04,0x0c,0x02,0x22,0x1c,
|
||||
0x00,0x04,0x0c,0x14,0x24,0x3e,0x04,0x04,
|
||||
0x00,0x3e,0x20,0x3c,0x02,0x02,0x22,0x1c,
|
||||
0x00,0x0e,0x10,0x20,0x3c,0x22,0x22,0x1c,
|
||||
0x00,0x3e,0x02,0x04,0x08,0x10,0x10,0x10,
|
||||
0x00,0x1c,0x22,0x22,0x1c,0x22,0x22,0x1c,
|
||||
0x00,0x1c,0x22,0x22,0x1e,0x02,0x04,0x38,
|
||||
0x00,0x00,0x00,0x08,0x00,0x08,0x00,0x00,
|
||||
0x00,0x00,0x00,0x08,0x00,0x08,0x08,0x10,
|
||||
0x00,0x04,0x08,0x10,0x20,0x10,0x08,0x04,
|
||||
0x00,0x00,0x00,0x3e,0x00,0x3e,0x00,0x00,
|
||||
0x00,0x10,0x08,0x04,0x02,0x04,0x08,0x10,
|
||||
0x00,0x1c,0x22,0x04,0x08,0x08,0x00,0x08,
|
||||
0x80,0x9c,0xa2,0xaa,0xae,0xac,0xa0,0x9e,
|
||||
0x80,0x88,0x94,0xa2,0xa2,0xbe,0xa2,0xa2,
|
||||
0x80,0xbc,0xa2,0xa2,0xbc,0xa2,0xa2,0xbc,
|
||||
0x80,0x9c,0xa2,0xa0,0xa0,0xa0,0xa2,0x9c,
|
||||
0x80,0xbc,0xa2,0xa2,0xa2,0xa2,0xa2,0xbc,
|
||||
0x80,0xbe,0xa0,0xa0,0xbc,0xa0,0xa0,0xbe,
|
||||
0x80,0xbe,0xa0,0xa0,0xbc,0xa0,0xa0,0xa0,
|
||||
0x80,0x9e,0xa0,0xa0,0xa0,0xa6,0xa2,0x9e,
|
||||
0x80,0xa2,0xa2,0xa2,0xbe,0xa2,0xa2,0xa2,
|
||||
0x80,0x9c,0x88,0x88,0x88,0x88,0x88,0x9c,
|
||||
0x80,0x82,0x82,0x82,0x82,0x82,0xa2,0x9c,
|
||||
0x80,0xa2,0xa4,0xa8,0xb0,0xa8,0xa4,0xa2,
|
||||
0x80,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xbe,
|
||||
0x80,0xa2,0xb6,0xaa,0xaa,0xa2,0xa2,0xa2,
|
||||
0x80,0xa2,0xa2,0xb2,0xaa,0xa6,0xa2,0xa2,
|
||||
0x80,0x9c,0xa2,0xa2,0xa2,0xa2,0xa2,0x9c,
|
||||
0x80,0xbc,0xa2,0xa2,0xbc,0xa0,0xa0,0xa0,
|
||||
0x80,0x9c,0xa2,0xa2,0xa2,0xaa,0xa4,0x9a,
|
||||
0x80,0xbc,0xa2,0xa2,0xbc,0xa8,0xa4,0xa2,
|
||||
0x80,0x9c,0xa2,0xa0,0x9c,0x82,0xa2,0x9c,
|
||||
0x80,0xbe,0x88,0x88,0x88,0x88,0x88,0x88,
|
||||
0x80,0xa2,0xa2,0xa2,0xa2,0xa2,0xa2,0x9c,
|
||||
0x80,0xa2,0xa2,0xa2,0xa2,0xa2,0x94,0x88,
|
||||
0x80,0xa2,0xa2,0xa2,0xaa,0xaa,0xb6,0xa2,
|
||||
0x80,0xa2,0xa2,0x94,0x88,0x94,0xa2,0xa2,
|
||||
0x80,0xa2,0xa2,0x94,0x88,0x88,0x88,0x88,
|
||||
0x80,0xbe,0x82,0x84,0x88,0x90,0xa0,0xbe,
|
||||
0x80,0xbe,0xb0,0xb0,0xb0,0xb0,0xb0,0xbe,
|
||||
0x80,0x80,0xa0,0x90,0x88,0x84,0x82,0x80,
|
||||
0x80,0xbe,0x86,0x86,0x86,0x86,0x86,0xbe,
|
||||
0x80,0x80,0x80,0x88,0x94,0xa2,0x80,0x80,
|
||||
0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xbe,
|
||||
0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
|
||||
0x80,0x88,0x88,0x88,0x88,0x88,0x80,0x88,
|
||||
0x80,0x94,0x94,0x94,0x80,0x80,0x80,0x80,
|
||||
0x80,0x94,0x94,0xbe,0x94,0xbe,0x94,0x94,
|
||||
0x80,0x88,0x9e,0xa8,0x9c,0x8a,0xbc,0x88,
|
||||
0x80,0xb0,0xb2,0x84,0x88,0x90,0xa6,0x86,
|
||||
0x80,0x90,0xa8,0xa8,0x90,0xaa,0xa4,0x9a,
|
||||
0x80,0x88,0x88,0x88,0x80,0x80,0x80,0x80,
|
||||
0x80,0x88,0x90,0xa0,0xa0,0xa0,0x90,0x88,
|
||||
0x80,0x88,0x84,0x82,0x82,0x82,0x84,0x88,
|
||||
0x80,0x88,0xaa,0x9c,0x88,0x9c,0xaa,0x88,
|
||||
0x80,0x80,0x88,0x88,0xbe,0x88,0x88,0x80,
|
||||
0x80,0x80,0x80,0x80,0x80,0x88,0x88,0x90,
|
||||
0x80,0x80,0x80,0x80,0xbe,0x80,0x80,0x80,
|
||||
0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x88,
|
||||
0x80,0x80,0x82,0x84,0x88,0x90,0xa0,0x80,
|
||||
0x80,0x9c,0xa2,0xa6,0xaa,0xb2,0xa2,0x9c,
|
||||
0x80,0x88,0x98,0x88,0x88,0x88,0x88,0x9c,
|
||||
0x80,0x9c,0xa2,0x82,0x8c,0x90,0xa0,0xbe,
|
||||
0x80,0xbe,0x82,0x84,0x8c,0x82,0xa2,0x9c,
|
||||
0x80,0x84,0x8c,0x94,0xa4,0xbe,0x84,0x84,
|
||||
0x80,0xbe,0xa0,0xbc,0x82,0x82,0xa2,0x9c,
|
||||
0x80,0x8e,0x90,0xa0,0xbc,0xa2,0xa2,0x9c,
|
||||
0x80,0xbe,0x82,0x84,0x88,0x90,0x90,0x90,
|
||||
0x80,0x9c,0xa2,0xa2,0x9c,0xa2,0xa2,0x9c,
|
||||
0x80,0x9c,0xa2,0xa2,0x9e,0x82,0x84,0xb8,
|
||||
0x80,0x80,0x80,0x88,0x80,0x88,0x80,0x80,
|
||||
0x80,0x80,0x80,0x88,0x80,0x88,0x88,0x90,
|
||||
0x80,0x84,0x88,0x90,0xa0,0x90,0x88,0x84,
|
||||
0x80,0x80,0x80,0xbe,0x80,0xbe,0x80,0x80,
|
||||
0x80,0x90,0x88,0x84,0x82,0x84,0x88,0x90,
|
||||
0x80,0x9c,0xa2,0x84,0x88,0x88,0x80,0x88,
|
||||
0x00,0x1c,0x22,0x2a,0x2e,0x2c,0x20,0x1e,
|
||||
0x00,0x08,0x14,0x22,0x22,0x3e,0x22,0x22,
|
||||
0x00,0x3c,0x22,0x22,0x3c,0x22,0x22,0x3c,
|
||||
0x00,0x1c,0x22,0x20,0x20,0x20,0x22,0x1c,
|
||||
0x00,0x3c,0x22,0x22,0x22,0x22,0x22,0x3c,
|
||||
0x00,0x3e,0x20,0x20,0x3c,0x20,0x20,0x3e,
|
||||
0x00,0x3e,0x20,0x20,0x3c,0x20,0x20,0x20,
|
||||
0x00,0x1e,0x20,0x20,0x20,0x26,0x22,0x1e,
|
||||
0x00,0x22,0x22,0x22,0x3e,0x22,0x22,0x22,
|
||||
0x00,0x1c,0x08,0x08,0x08,0x08,0x08,0x1c,
|
||||
0x00,0x02,0x02,0x02,0x02,0x02,0x22,0x1c,
|
||||
0x00,0x22,0x24,0x28,0x30,0x28,0x24,0x22,
|
||||
0x00,0x20,0x20,0x20,0x20,0x20,0x20,0x3e,
|
||||
0x00,0x22,0x36,0x2a,0x2a,0x22,0x22,0x22,
|
||||
0x00,0x22,0x22,0x32,0x2a,0x26,0x22,0x22,
|
||||
0x00,0x1c,0x22,0x22,0x22,0x22,0x22,0x1c,
|
||||
0x00,0x3c,0x22,0x22,0x3c,0x20,0x20,0x20,
|
||||
0x00,0x1c,0x22,0x22,0x22,0x2a,0x24,0x1a,
|
||||
0x00,0x3c,0x22,0x22,0x3c,0x28,0x24,0x22,
|
||||
0x00,0x1c,0x22,0x20,0x1c,0x02,0x22,0x1c,
|
||||
0x00,0x3e,0x08,0x08,0x08,0x08,0x08,0x08,
|
||||
0x00,0x22,0x22,0x22,0x22,0x22,0x22,0x1c,
|
||||
0x00,0x22,0x22,0x22,0x22,0x22,0x14,0x08,
|
||||
0x00,0x22,0x22,0x22,0x2a,0x2a,0x36,0x22,
|
||||
0x00,0x22,0x22,0x14,0x08,0x14,0x22,0x22,
|
||||
0x00,0x22,0x22,0x14,0x08,0x08,0x08,0x08,
|
||||
0x00,0x3e,0x02,0x04,0x08,0x10,0x20,0x3e,
|
||||
0x00,0x3e,0x30,0x30,0x30,0x30,0x30,0x3e,
|
||||
0x00,0x00,0x20,0x10,0x08,0x04,0x02,0x00,
|
||||
0x00,0x3e,0x06,0x06,0x06,0x06,0x06,0x3e,
|
||||
0x00,0x00,0x00,0x08,0x14,0x22,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3e,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x08,0x08,0x08,0x08,0x08,0x00,0x08,
|
||||
0x00,0x14,0x14,0x14,0x00,0x00,0x00,0x00,
|
||||
0x00,0x14,0x14,0x3e,0x14,0x3e,0x14,0x14,
|
||||
0x00,0x08,0x1e,0x28,0x1c,0x0a,0x3c,0x08,
|
||||
0x00,0x30,0x32,0x04,0x08,0x10,0x26,0x06,
|
||||
0x00,0x10,0x28,0x28,0x10,0x2a,0x24,0x1a,
|
||||
0x00,0x08,0x08,0x08,0x00,0x00,0x00,0x00,
|
||||
0x00,0x08,0x10,0x20,0x20,0x20,0x10,0x08,
|
||||
0x00,0x08,0x04,0x02,0x02,0x02,0x04,0x08,
|
||||
0x00,0x08,0x2a,0x1c,0x08,0x1c,0x2a,0x08,
|
||||
0x00,0x00,0x08,0x08,0x3e,0x08,0x08,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x08,0x08,0x10,
|
||||
0x00,0x00,0x00,0x00,0x3e,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,
|
||||
0x00,0x00,0x02,0x04,0x08,0x10,0x20,0x00,
|
||||
0x00,0x1c,0x22,0x26,0x2a,0x32,0x22,0x1c,
|
||||
0x00,0x08,0x18,0x08,0x08,0x08,0x08,0x1c,
|
||||
0x00,0x1c,0x22,0x02,0x0c,0x10,0x20,0x3e,
|
||||
0x00,0x3e,0x02,0x04,0x0c,0x02,0x22,0x1c,
|
||||
0x00,0x04,0x0c,0x14,0x24,0x3e,0x04,0x04,
|
||||
0x00,0x3e,0x20,0x3c,0x02,0x02,0x22,0x1c,
|
||||
0x00,0x0e,0x10,0x20,0x3c,0x22,0x22,0x1c,
|
||||
0x00,0x3e,0x02,0x04,0x08,0x10,0x10,0x10,
|
||||
0x00,0x1c,0x22,0x22,0x1c,0x22,0x22,0x1c,
|
||||
0x00,0x1c,0x22,0x22,0x1e,0x02,0x04,0x38,
|
||||
0x00,0x00,0x00,0x08,0x00,0x08,0x00,0x00,
|
||||
0x00,0x00,0x00,0x08,0x00,0x08,0x08,0x10,
|
||||
0x00,0x04,0x08,0x10,0x20,0x10,0x08,0x04,
|
||||
0x00,0x00,0x00,0x3e,0x00,0x3e,0x00,0x00,
|
||||
0x00,0x10,0x08,0x04,0x02,0x04,0x08,0x10,
|
||||
0x00,0x1c,0x22,0x04,0x08,0x08,0x00,0x08,
|
||||
0x80,0x9c,0xa2,0xaa,0xae,0xac,0xa0,0x9e,
|
||||
0x80,0x88,0x94,0xa2,0xa2,0xbe,0xa2,0xa2,
|
||||
0x80,0xbc,0xa2,0xa2,0xbc,0xa2,0xa2,0xbc,
|
||||
0x80,0x9c,0xa2,0xa0,0xa0,0xa0,0xa2,0x9c,
|
||||
0x80,0xbc,0xa2,0xa2,0xa2,0xa2,0xa2,0xbc,
|
||||
0x80,0xbe,0xa0,0xa0,0xbc,0xa0,0xa0,0xbe,
|
||||
0x80,0xbe,0xa0,0xa0,0xbc,0xa0,0xa0,0xa0,
|
||||
0x80,0x9e,0xa0,0xa0,0xa0,0xa6,0xa2,0x9e,
|
||||
0x80,0xa2,0xa2,0xa2,0xbe,0xa2,0xa2,0xa2,
|
||||
0x80,0x9c,0x88,0x88,0x88,0x88,0x88,0x9c,
|
||||
0x80,0x82,0x82,0x82,0x82,0x82,0xa2,0x9c,
|
||||
0x80,0xa2,0xa4,0xa8,0xb0,0xa8,0xa4,0xa2,
|
||||
0x80,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xbe,
|
||||
0x80,0xa2,0xb6,0xaa,0xaa,0xa2,0xa2,0xa2,
|
||||
0x80,0xa2,0xa2,0xb2,0xaa,0xa6,0xa2,0xa2,
|
||||
0x80,0x9c,0xa2,0xa2,0xa2,0xa2,0xa2,0x9c,
|
||||
0x80,0xbc,0xa2,0xa2,0xbc,0xa0,0xa0,0xa0,
|
||||
0x80,0x9c,0xa2,0xa2,0xa2,0xaa,0xa4,0x9a,
|
||||
0x80,0xbc,0xa2,0xa2,0xbc,0xa8,0xa4,0xa2,
|
||||
0x80,0x9c,0xa2,0xa0,0x9c,0x82,0xa2,0x9c,
|
||||
0x80,0xbe,0x88,0x88,0x88,0x88,0x88,0x88,
|
||||
0x80,0xa2,0xa2,0xa2,0xa2,0xa2,0xa2,0x9c,
|
||||
0x80,0xa2,0xa2,0xa2,0xa2,0xa2,0x94,0x88,
|
||||
0x80,0xa2,0xa2,0xa2,0xaa,0xaa,0xb6,0xa2,
|
||||
0x80,0xa2,0xa2,0x94,0x88,0x94,0xa2,0xa2,
|
||||
0x80,0xa2,0xa2,0x94,0x88,0x88,0x88,0x88,
|
||||
0x80,0xbe,0x82,0x84,0x88,0x90,0xa0,0xbe,
|
||||
0x80,0xbe,0xb0,0xb0,0xb0,0xb0,0xb0,0xbe,
|
||||
0x80,0x80,0xa0,0x90,0x88,0x84,0x82,0x80,
|
||||
0x80,0xbe,0x86,0x86,0x86,0x86,0x86,0xbe,
|
||||
0x80,0x80,0x80,0x88,0x94,0xa2,0x80,0x80,
|
||||
0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xbe,
|
||||
0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
|
||||
0x80,0x88,0x88,0x88,0x88,0x88,0x80,0x88,
|
||||
0x80,0x94,0x94,0x94,0x80,0x80,0x80,0x80,
|
||||
0x80,0x94,0x94,0xbe,0x94,0xbe,0x94,0x94,
|
||||
0x80,0x88,0x9e,0xa8,0x9c,0x8a,0xbc,0x88,
|
||||
0x80,0xb0,0xb2,0x84,0x88,0x90,0xa6,0x86,
|
||||
0x80,0x90,0xa8,0xa8,0x90,0xaa,0xa4,0x9a,
|
||||
0x80,0x88,0x88,0x88,0x80,0x80,0x80,0x80,
|
||||
0x80,0x88,0x90,0xa0,0xa0,0xa0,0x90,0x88,
|
||||
0x80,0x88,0x84,0x82,0x82,0x82,0x84,0x88,
|
||||
0x80,0x88,0xaa,0x9c,0x88,0x9c,0xaa,0x88,
|
||||
0x80,0x80,0x88,0x88,0xbe,0x88,0x88,0x80,
|
||||
0x80,0x80,0x80,0x80,0x80,0x88,0x88,0x90,
|
||||
0x80,0x80,0x80,0x80,0xbe,0x80,0x80,0x80,
|
||||
0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x88,
|
||||
0x80,0x80,0x82,0x84,0x88,0x90,0xa0,0x80,
|
||||
0x80,0x9c,0xa2,0xa6,0xaa,0xb2,0xa2,0x9c,
|
||||
0x80,0x88,0x98,0x88,0x88,0x88,0x88,0x9c,
|
||||
0x80,0x9c,0xa2,0x82,0x8c,0x90,0xa0,0xbe,
|
||||
0x80,0xbe,0x82,0x84,0x8c,0x82,0xa2,0x9c,
|
||||
0x80,0x84,0x8c,0x94,0xa4,0xbe,0x84,0x84,
|
||||
0x80,0xbe,0xa0,0xbc,0x82,0x82,0xa2,0x9c,
|
||||
0x80,0x8e,0x90,0xa0,0xbc,0xa2,0xa2,0x9c,
|
||||
0x80,0xbe,0x82,0x84,0x88,0x90,0x90,0x90,
|
||||
0x80,0x9c,0xa2,0xa2,0x9c,0xa2,0xa2,0x9c,
|
||||
0x80,0x9c,0xa2,0xa2,0x9e,0x82,0x84,0xb8,
|
||||
0x80,0x80,0x80,0x88,0x80,0x88,0x80,0x80,
|
||||
0x80,0x80,0x80,0x88,0x80,0x88,0x88,0x90,
|
||||
0x80,0x84,0x88,0x90,0xa0,0x90,0x88,0x84,
|
||||
0x80,0x80,0x80,0xbe,0x80,0xbe,0x80,0x80,
|
||||
0x80,0x90,0x88,0x84,0x82,0x84,0x88,0x90,
|
||||
0x80,0x9c,0xa2,0x84,0x88,0x88,0x80,0x88
|
||||
];
|
||||
|
||||
charset = bytify(charset);
|
||||
var apple2_charset = [
|
||||
0x00,0x1c,0x22,0x2a,0x2e,0x2c,0x20,0x1e,
|
||||
0x00,0x08,0x14,0x22,0x22,0x3e,0x22,0x22,
|
||||
0x00,0x3c,0x22,0x22,0x3c,0x22,0x22,0x3c,
|
||||
0x00,0x1c,0x22,0x20,0x20,0x20,0x22,0x1c,
|
||||
0x00,0x3c,0x22,0x22,0x22,0x22,0x22,0x3c,
|
||||
0x00,0x3e,0x20,0x20,0x3c,0x20,0x20,0x3e,
|
||||
0x00,0x3e,0x20,0x20,0x3c,0x20,0x20,0x20,
|
||||
0x00,0x1e,0x20,0x20,0x20,0x26,0x22,0x1e,
|
||||
0x00,0x22,0x22,0x22,0x3e,0x22,0x22,0x22,
|
||||
0x00,0x1c,0x08,0x08,0x08,0x08,0x08,0x1c,
|
||||
0x00,0x02,0x02,0x02,0x02,0x02,0x22,0x1c,
|
||||
0x00,0x22,0x24,0x28,0x30,0x28,0x24,0x22,
|
||||
0x00,0x20,0x20,0x20,0x20,0x20,0x20,0x3e,
|
||||
0x00,0x22,0x36,0x2a,0x2a,0x22,0x22,0x22,
|
||||
0x00,0x22,0x22,0x32,0x2a,0x26,0x22,0x22,
|
||||
0x00,0x1c,0x22,0x22,0x22,0x22,0x22,0x1c,
|
||||
0x00,0x3c,0x22,0x22,0x3c,0x20,0x20,0x20,
|
||||
0x00,0x1c,0x22,0x22,0x22,0x2a,0x24,0x1a,
|
||||
0x00,0x3c,0x22,0x22,0x3c,0x28,0x24,0x22,
|
||||
0x00,0x1c,0x22,0x20,0x1c,0x02,0x22,0x1c,
|
||||
0x00,0x3e,0x08,0x08,0x08,0x08,0x08,0x08,
|
||||
0x00,0x22,0x22,0x22,0x22,0x22,0x22,0x1c,
|
||||
0x00,0x22,0x22,0x22,0x22,0x22,0x14,0x08,
|
||||
0x00,0x22,0x22,0x22,0x2a,0x2a,0x36,0x22,
|
||||
0x00,0x22,0x22,0x14,0x08,0x14,0x22,0x22,
|
||||
0x00,0x22,0x22,0x14,0x08,0x08,0x08,0x08,
|
||||
0x00,0x3e,0x02,0x04,0x08,0x10,0x20,0x3e,
|
||||
0x00,0x3e,0x30,0x30,0x30,0x30,0x30,0x3e,
|
||||
0x00,0x00,0x20,0x10,0x08,0x04,0x02,0x00,
|
||||
0x00,0x3e,0x06,0x06,0x06,0x06,0x06,0x3e,
|
||||
0x00,0x00,0x00,0x08,0x14,0x22,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3e,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x08,0x08,0x08,0x08,0x08,0x00,0x08,
|
||||
0x00,0x14,0x14,0x14,0x00,0x00,0x00,0x00,
|
||||
0x00,0x14,0x14,0x3e,0x14,0x3e,0x14,0x14,
|
||||
0x00,0x08,0x1e,0x28,0x1c,0x0a,0x3c,0x08,
|
||||
0x00,0x30,0x32,0x04,0x08,0x10,0x26,0x06,
|
||||
0x00,0x10,0x28,0x28,0x10,0x2a,0x24,0x1a,
|
||||
0x00,0x08,0x08,0x08,0x00,0x00,0x00,0x00,
|
||||
0x00,0x08,0x10,0x20,0x20,0x20,0x10,0x08,
|
||||
0x00,0x08,0x04,0x02,0x02,0x02,0x04,0x08,
|
||||
0x00,0x08,0x2a,0x1c,0x08,0x1c,0x2a,0x08,
|
||||
0x00,0x00,0x08,0x08,0x3e,0x08,0x08,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x08,0x08,0x10,
|
||||
0x00,0x00,0x00,0x00,0x3e,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,
|
||||
0x00,0x00,0x02,0x04,0x08,0x10,0x20,0x00,
|
||||
0x00,0x1c,0x22,0x26,0x2a,0x32,0x22,0x1c,
|
||||
0x00,0x08,0x18,0x08,0x08,0x08,0x08,0x1c,
|
||||
0x00,0x1c,0x22,0x02,0x0c,0x10,0x20,0x3e,
|
||||
0x00,0x3e,0x02,0x04,0x0c,0x02,0x22,0x1c,
|
||||
0x00,0x04,0x0c,0x14,0x24,0x3e,0x04,0x04,
|
||||
0x00,0x3e,0x20,0x3c,0x02,0x02,0x22,0x1c,
|
||||
0x00,0x0e,0x10,0x20,0x3c,0x22,0x22,0x1c,
|
||||
0x00,0x3e,0x02,0x04,0x08,0x10,0x10,0x10,
|
||||
0x00,0x1c,0x22,0x22,0x1c,0x22,0x22,0x1c,
|
||||
0x00,0x1c,0x22,0x22,0x1e,0x02,0x04,0x38,
|
||||
0x00,0x00,0x00,0x08,0x00,0x08,0x00,0x00,
|
||||
0x00,0x00,0x00,0x08,0x00,0x08,0x08,0x10,
|
||||
0x00,0x04,0x08,0x10,0x20,0x10,0x08,0x04,
|
||||
0x00,0x00,0x00,0x3e,0x00,0x3e,0x00,0x00,
|
||||
0x00,0x10,0x08,0x04,0x02,0x04,0x08,0x10,
|
||||
0x00,0x1c,0x22,0x04,0x08,0x08,0x00,0x08,
|
||||
0x80,0x9c,0xa2,0xaa,0xae,0xac,0xa0,0x9e,
|
||||
0x80,0x88,0x94,0xa2,0xa2,0xbe,0xa2,0xa2,
|
||||
0x80,0xbc,0xa2,0xa2,0xbc,0xa2,0xa2,0xbc,
|
||||
0x80,0x9c,0xa2,0xa0,0xa0,0xa0,0xa2,0x9c,
|
||||
0x80,0xbc,0xa2,0xa2,0xa2,0xa2,0xa2,0xbc,
|
||||
0x80,0xbe,0xa0,0xa0,0xbc,0xa0,0xa0,0xbe,
|
||||
0x80,0xbe,0xa0,0xa0,0xbc,0xa0,0xa0,0xa0,
|
||||
0x80,0x9e,0xa0,0xa0,0xa0,0xa6,0xa2,0x9e,
|
||||
0x80,0xa2,0xa2,0xa2,0xbe,0xa2,0xa2,0xa2,
|
||||
0x80,0x9c,0x88,0x88,0x88,0x88,0x88,0x9c,
|
||||
0x80,0x82,0x82,0x82,0x82,0x82,0xa2,0x9c,
|
||||
0x80,0xa2,0xa4,0xa8,0xb0,0xa8,0xa4,0xa2,
|
||||
0x80,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xbe,
|
||||
0x80,0xa2,0xb6,0xaa,0xaa,0xa2,0xa2,0xa2,
|
||||
0x80,0xa2,0xa2,0xb2,0xaa,0xa6,0xa2,0xa2,
|
||||
0x80,0x9c,0xa2,0xa2,0xa2,0xa2,0xa2,0x9c,
|
||||
0x80,0xbc,0xa2,0xa2,0xbc,0xa0,0xa0,0xa0,
|
||||
0x80,0x9c,0xa2,0xa2,0xa2,0xaa,0xa4,0x9a,
|
||||
0x80,0xbc,0xa2,0xa2,0xbc,0xa8,0xa4,0xa2,
|
||||
0x80,0x9c,0xa2,0xa0,0x9c,0x82,0xa2,0x9c,
|
||||
0x80,0xbe,0x88,0x88,0x88,0x88,0x88,0x88,
|
||||
0x80,0xa2,0xa2,0xa2,0xa2,0xa2,0xa2,0x9c,
|
||||
0x80,0xa2,0xa2,0xa2,0xa2,0xa2,0x94,0x88,
|
||||
0x80,0xa2,0xa2,0xa2,0xaa,0xaa,0xb6,0xa2,
|
||||
0x80,0xa2,0xa2,0x94,0x88,0x94,0xa2,0xa2,
|
||||
0x80,0xa2,0xa2,0x94,0x88,0x88,0x88,0x88,
|
||||
0x80,0xbe,0x82,0x84,0x88,0x90,0xa0,0xbe,
|
||||
0x80,0xbe,0xb0,0xb0,0xb0,0xb0,0xb0,0xbe,
|
||||
0x80,0x80,0xa0,0x90,0x88,0x84,0x82,0x80,
|
||||
0x80,0xbe,0x86,0x86,0x86,0x86,0x86,0xbe,
|
||||
0x80,0x80,0x80,0x88,0x94,0xa2,0x80,0x80,
|
||||
0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xbe,
|
||||
0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
|
||||
0x80,0x88,0x88,0x88,0x88,0x88,0x80,0x88,
|
||||
0x80,0x94,0x94,0x94,0x80,0x80,0x80,0x80,
|
||||
0x80,0x94,0x94,0xbe,0x94,0xbe,0x94,0x94,
|
||||
0x80,0x88,0x9e,0xa8,0x9c,0x8a,0xbc,0x88,
|
||||
0x80,0xb0,0xb2,0x84,0x88,0x90,0xa6,0x86,
|
||||
0x80,0x90,0xa8,0xa8,0x90,0xaa,0xa4,0x9a,
|
||||
0x80,0x88,0x88,0x88,0x80,0x80,0x80,0x80,
|
||||
0x80,0x88,0x90,0xa0,0xa0,0xa0,0x90,0x88,
|
||||
0x80,0x88,0x84,0x82,0x82,0x82,0x84,0x88,
|
||||
0x80,0x88,0xaa,0x9c,0x88,0x9c,0xaa,0x88,
|
||||
0x80,0x80,0x88,0x88,0xbe,0x88,0x88,0x80,
|
||||
0x80,0x80,0x80,0x80,0x80,0x88,0x88,0x90,
|
||||
0x80,0x80,0x80,0x80,0xbe,0x80,0x80,0x80,
|
||||
0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x88,
|
||||
0x80,0x80,0x82,0x84,0x88,0x90,0xa0,0x80,
|
||||
0x80,0x9c,0xa2,0xa6,0xaa,0xb2,0xa2,0x9c,
|
||||
0x80,0x88,0x98,0x88,0x88,0x88,0x88,0x9c,
|
||||
0x80,0x9c,0xa2,0x82,0x8c,0x90,0xa0,0xbe,
|
||||
0x80,0xbe,0x82,0x84,0x8c,0x82,0xa2,0x9c,
|
||||
0x80,0x84,0x8c,0x94,0xa4,0xbe,0x84,0x84,
|
||||
0x80,0xbe,0xa0,0xbc,0x82,0x82,0xa2,0x9c,
|
||||
0x80,0x8e,0x90,0xa0,0xbc,0xa2,0xa2,0x9c,
|
||||
0x80,0xbe,0x82,0x84,0x88,0x90,0x90,0x90,
|
||||
0x80,0x9c,0xa2,0xa2,0x9c,0xa2,0xa2,0x9c,
|
||||
0x80,0x9c,0xa2,0xa2,0x9e,0x82,0x84,0xb8,
|
||||
0x80,0x80,0x80,0x88,0x80,0x88,0x80,0x80,
|
||||
0x80,0x80,0x80,0x88,0x80,0x88,0x88,0x90,
|
||||
0x80,0x84,0x88,0x90,0xa0,0x90,0x88,0x84,
|
||||
0x80,0x80,0x80,0xbe,0x80,0xbe,0x80,0x80,
|
||||
0x80,0x90,0x88,0x84,0x82,0x84,0x88,0x90,
|
||||
0x80,0x9c,0xa2,0x84,0x88,0x88,0x80,0x88,
|
||||
0x00,0x1c,0x22,0x2a,0x2e,0x2c,0x20,0x1e,
|
||||
0x00,0x08,0x14,0x22,0x22,0x3e,0x22,0x22,
|
||||
0x00,0x3c,0x22,0x22,0x3c,0x22,0x22,0x3c,
|
||||
0x00,0x1c,0x22,0x20,0x20,0x20,0x22,0x1c,
|
||||
0x00,0x3c,0x22,0x22,0x22,0x22,0x22,0x3c,
|
||||
0x00,0x3e,0x20,0x20,0x3c,0x20,0x20,0x3e,
|
||||
0x00,0x3e,0x20,0x20,0x3c,0x20,0x20,0x20,
|
||||
0x00,0x1e,0x20,0x20,0x20,0x26,0x22,0x1e,
|
||||
0x00,0x22,0x22,0x22,0x3e,0x22,0x22,0x22,
|
||||
0x00,0x1c,0x08,0x08,0x08,0x08,0x08,0x1c,
|
||||
0x00,0x02,0x02,0x02,0x02,0x02,0x22,0x1c,
|
||||
0x00,0x22,0x24,0x28,0x30,0x28,0x24,0x22,
|
||||
0x00,0x20,0x20,0x20,0x20,0x20,0x20,0x3e,
|
||||
0x00,0x22,0x36,0x2a,0x2a,0x22,0x22,0x22,
|
||||
0x00,0x22,0x22,0x32,0x2a,0x26,0x22,0x22,
|
||||
0x00,0x1c,0x22,0x22,0x22,0x22,0x22,0x1c,
|
||||
0x00,0x3c,0x22,0x22,0x3c,0x20,0x20,0x20,
|
||||
0x00,0x1c,0x22,0x22,0x22,0x2a,0x24,0x1a,
|
||||
0x00,0x3c,0x22,0x22,0x3c,0x28,0x24,0x22,
|
||||
0x00,0x1c,0x22,0x20,0x1c,0x02,0x22,0x1c,
|
||||
0x00,0x3e,0x08,0x08,0x08,0x08,0x08,0x08,
|
||||
0x00,0x22,0x22,0x22,0x22,0x22,0x22,0x1c,
|
||||
0x00,0x22,0x22,0x22,0x22,0x22,0x14,0x08,
|
||||
0x00,0x22,0x22,0x22,0x2a,0x2a,0x36,0x22,
|
||||
0x00,0x22,0x22,0x14,0x08,0x14,0x22,0x22,
|
||||
0x00,0x22,0x22,0x14,0x08,0x08,0x08,0x08,
|
||||
0x00,0x3e,0x02,0x04,0x08,0x10,0x20,0x3e,
|
||||
0x00,0x3e,0x30,0x30,0x30,0x30,0x30,0x3e,
|
||||
0x00,0x00,0x20,0x10,0x08,0x04,0x02,0x00,
|
||||
0x00,0x3e,0x06,0x06,0x06,0x06,0x06,0x3e,
|
||||
0x00,0x00,0x00,0x08,0x14,0x22,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3e,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x08,0x08,0x08,0x08,0x08,0x00,0x08,
|
||||
0x00,0x14,0x14,0x14,0x00,0x00,0x00,0x00,
|
||||
0x00,0x14,0x14,0x3e,0x14,0x3e,0x14,0x14,
|
||||
0x00,0x08,0x1e,0x28,0x1c,0x0a,0x3c,0x08,
|
||||
0x00,0x30,0x32,0x04,0x08,0x10,0x26,0x06,
|
||||
0x00,0x10,0x28,0x28,0x10,0x2a,0x24,0x1a,
|
||||
0x00,0x08,0x08,0x08,0x00,0x00,0x00,0x00,
|
||||
0x00,0x08,0x10,0x20,0x20,0x20,0x10,0x08,
|
||||
0x00,0x08,0x04,0x02,0x02,0x02,0x04,0x08,
|
||||
0x00,0x08,0x2a,0x1c,0x08,0x1c,0x2a,0x08,
|
||||
0x00,0x00,0x08,0x08,0x3e,0x08,0x08,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x08,0x08,0x10,
|
||||
0x00,0x00,0x00,0x00,0x3e,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,
|
||||
0x00,0x00,0x02,0x04,0x08,0x10,0x20,0x00,
|
||||
0x00,0x1c,0x22,0x26,0x2a,0x32,0x22,0x1c,
|
||||
0x00,0x08,0x18,0x08,0x08,0x08,0x08,0x1c,
|
||||
0x00,0x1c,0x22,0x02,0x0c,0x10,0x20,0x3e,
|
||||
0x00,0x3e,0x02,0x04,0x0c,0x02,0x22,0x1c,
|
||||
0x00,0x04,0x0c,0x14,0x24,0x3e,0x04,0x04,
|
||||
0x00,0x3e,0x20,0x3c,0x02,0x02,0x22,0x1c,
|
||||
0x00,0x0e,0x10,0x20,0x3c,0x22,0x22,0x1c,
|
||||
0x00,0x3e,0x02,0x04,0x08,0x10,0x10,0x10,
|
||||
0x00,0x1c,0x22,0x22,0x1c,0x22,0x22,0x1c,
|
||||
0x00,0x1c,0x22,0x22,0x1e,0x02,0x04,0x38,
|
||||
0x00,0x00,0x00,0x08,0x00,0x08,0x00,0x00,
|
||||
0x00,0x00,0x00,0x08,0x00,0x08,0x08,0x10,
|
||||
0x00,0x04,0x08,0x10,0x20,0x10,0x08,0x04,
|
||||
0x00,0x00,0x00,0x3e,0x00,0x3e,0x00,0x00,
|
||||
0x00,0x10,0x08,0x04,0x02,0x04,0x08,0x10,
|
||||
0x00,0x1c,0x22,0x04,0x08,0x08,0x00,0x08,
|
||||
0x80,0x9c,0xa2,0xaa,0xae,0xac,0xa0,0x9e,
|
||||
0x80,0x88,0x94,0xa2,0xa2,0xbe,0xa2,0xa2,
|
||||
0x80,0xbc,0xa2,0xa2,0xbc,0xa2,0xa2,0xbc,
|
||||
0x80,0x9c,0xa2,0xa0,0xa0,0xa0,0xa2,0x9c,
|
||||
0x80,0xbc,0xa2,0xa2,0xa2,0xa2,0xa2,0xbc,
|
||||
0x80,0xbe,0xa0,0xa0,0xbc,0xa0,0xa0,0xbe,
|
||||
0x80,0xbe,0xa0,0xa0,0xbc,0xa0,0xa0,0xa0,
|
||||
0x80,0x9e,0xa0,0xa0,0xa0,0xa6,0xa2,0x9e,
|
||||
0x80,0xa2,0xa2,0xa2,0xbe,0xa2,0xa2,0xa2,
|
||||
0x80,0x9c,0x88,0x88,0x88,0x88,0x88,0x9c,
|
||||
0x80,0x82,0x82,0x82,0x82,0x82,0xa2,0x9c,
|
||||
0x80,0xa2,0xa4,0xa8,0xb0,0xa8,0xa4,0xa2,
|
||||
0x80,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xbe,
|
||||
0x80,0xa2,0xb6,0xaa,0xaa,0xa2,0xa2,0xa2,
|
||||
0x80,0xa2,0xa2,0xb2,0xaa,0xa6,0xa2,0xa2,
|
||||
0x80,0x9c,0xa2,0xa2,0xa2,0xa2,0xa2,0x9c,
|
||||
0x80,0xbc,0xa2,0xa2,0xbc,0xa0,0xa0,0xa0,
|
||||
0x80,0x9c,0xa2,0xa2,0xa2,0xaa,0xa4,0x9a,
|
||||
0x80,0xbc,0xa2,0xa2,0xbc,0xa8,0xa4,0xa2,
|
||||
0x80,0x9c,0xa2,0xa0,0x9c,0x82,0xa2,0x9c,
|
||||
0x80,0xbe,0x88,0x88,0x88,0x88,0x88,0x88,
|
||||
0x80,0xa2,0xa2,0xa2,0xa2,0xa2,0xa2,0x9c,
|
||||
0x80,0xa2,0xa2,0xa2,0xa2,0xa2,0x94,0x88,
|
||||
0x80,0xa2,0xa2,0xa2,0xaa,0xaa,0xb6,0xa2,
|
||||
0x80,0xa2,0xa2,0x94,0x88,0x94,0xa2,0xa2,
|
||||
0x80,0xa2,0xa2,0x94,0x88,0x88,0x88,0x88,
|
||||
0x80,0xbe,0x82,0x84,0x88,0x90,0xa0,0xbe,
|
||||
0x80,0xbe,0xb0,0xb0,0xb0,0xb0,0xb0,0xbe,
|
||||
0x80,0x80,0xa0,0x90,0x88,0x84,0x82,0x80,
|
||||
0x80,0xbe,0x86,0x86,0x86,0x86,0x86,0xbe,
|
||||
0x80,0x80,0x80,0x88,0x94,0xa2,0x80,0x80,
|
||||
0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xbe,
|
||||
0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
|
||||
0x80,0x88,0x88,0x88,0x88,0x88,0x80,0x88,
|
||||
0x80,0x94,0x94,0x94,0x80,0x80,0x80,0x80,
|
||||
0x80,0x94,0x94,0xbe,0x94,0xbe,0x94,0x94,
|
||||
0x80,0x88,0x9e,0xa8,0x9c,0x8a,0xbc,0x88,
|
||||
0x80,0xb0,0xb2,0x84,0x88,0x90,0xa6,0x86,
|
||||
0x80,0x90,0xa8,0xa8,0x90,0xaa,0xa4,0x9a,
|
||||
0x80,0x88,0x88,0x88,0x80,0x80,0x80,0x80,
|
||||
0x80,0x88,0x90,0xa0,0xa0,0xa0,0x90,0x88,
|
||||
0x80,0x88,0x84,0x82,0x82,0x82,0x84,0x88,
|
||||
0x80,0x88,0xaa,0x9c,0x88,0x9c,0xaa,0x88,
|
||||
0x80,0x80,0x88,0x88,0xbe,0x88,0x88,0x80,
|
||||
0x80,0x80,0x80,0x80,0x80,0x88,0x88,0x90,
|
||||
0x80,0x80,0x80,0x80,0xbe,0x80,0x80,0x80,
|
||||
0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x88,
|
||||
0x80,0x80,0x82,0x84,0x88,0x90,0xa0,0x80,
|
||||
0x80,0x9c,0xa2,0xa6,0xaa,0xb2,0xa2,0x9c,
|
||||
0x80,0x88,0x98,0x88,0x88,0x88,0x88,0x9c,
|
||||
0x80,0x9c,0xa2,0x82,0x8c,0x90,0xa0,0xbe,
|
||||
0x80,0xbe,0x82,0x84,0x8c,0x82,0xa2,0x9c,
|
||||
0x80,0x84,0x8c,0x94,0xa4,0xbe,0x84,0x84,
|
||||
0x80,0xbe,0xa0,0xbc,0x82,0x82,0xa2,0x9c,
|
||||
0x80,0x8e,0x90,0xa0,0xbc,0xa2,0xa2,0x9c,
|
||||
0x80,0xbe,0x82,0x84,0x88,0x90,0x90,0x90,
|
||||
0x80,0x9c,0xa2,0xa2,0x9c,0xa2,0xa2,0x9c,
|
||||
0x80,0x9c,0xa2,0xa2,0x9e,0x82,0x84,0xb8,
|
||||
0x80,0x80,0x80,0x88,0x80,0x88,0x80,0x80,
|
||||
0x80,0x80,0x80,0x88,0x80,0x88,0x88,0x90,
|
||||
0x80,0x84,0x88,0x90,0xa0,0x90,0x88,0x84,
|
||||
0x80,0x80,0x80,0xbe,0x80,0xbe,0x80,0x80,
|
||||
0x80,0x90,0x88,0x84,0x82,0x84,0x88,0x90,
|
||||
0x80,0x9c,0xa2,0x84,0x88,0x88,0x80,0x88
|
||||
];
|
||||
|
@ -1,6 +1,3 @@
|
||||
/* -*- mode: JavaScript; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
|
||||
/*global bytify:false */
|
||||
/*exported Apple2eEnhancedROM */
|
||||
|
||||
function Apple2eEnhancedROM()
|
||||
@ -2056,8 +2053,6 @@ function Apple2eEnhancedROM()
|
||||
0xf5,0x03,0xfb,0x03,0x62,0xfa,0xfa,0xc3
|
||||
];
|
||||
|
||||
rom = bytify(rom);
|
||||
|
||||
return {
|
||||
start: function apple2e_start() {
|
||||
return 0xc1;
|
||||
|
@ -1,5 +1,3 @@
|
||||
/* -*- mode: JavaScript; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/*global bytify:false */
|
||||
/*exported Apple2eROM*/
|
||||
|
||||
function Apple2eROM()
|
||||
@ -2057,8 +2055,6 @@ function Apple2eROM()
|
||||
0xf5,0x03,0xfb,0x03,0x62,0xfa,0x40,0xfa
|
||||
];
|
||||
|
||||
rom = bytify(rom);
|
||||
|
||||
return {
|
||||
start: function apple2e_start() {
|
||||
return 0xc1;
|
||||
|
1035
js/apple2echar.js
1035
js/apple2echar.js
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,4 @@
|
||||
/* -*- mode: JavaScript; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* Copyright 2010-2014 Will Scullin <scullin@scullinsteel.com>
|
||||
/* Copyright 2010-2016 Will Scullin <scullin@scullinsteel.com>
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software and its
|
||||
* documentation for any purpose is hereby granted without fee, provided that
|
||||
@ -15,7 +14,7 @@
|
||||
|
||||
function Apple2IO(cpu, callbacks)
|
||||
{
|
||||
"use strict";
|
||||
'use strict';
|
||||
|
||||
var _hz = 1023000;
|
||||
var _rate = 44000;
|
||||
@ -36,7 +35,7 @@ function Apple2IO(cpu, callbacks)
|
||||
var _low = -0.5;
|
||||
|
||||
var _audioListener = null;
|
||||
|
||||
|
||||
var _trigger = 0;
|
||||
|
||||
var _tape = [];
|
||||
@ -45,7 +44,7 @@ function Apple2IO(cpu, callbacks)
|
||||
var _tapeFlip = false;
|
||||
|
||||
var LOC = {
|
||||
KEYBOARD: 0x00, // keyboard data (latched) (Read),
|
||||
KEYBOARD: 0x00, // keyboard data (latched) (Read),
|
||||
CLR80VID: 0x0C, // clear 80 column mode
|
||||
SET80VID: 0x0D, // set 80 column mode
|
||||
CLRALTCH: 0x0E, // clear mousetext
|
||||
@ -89,7 +88,7 @@ function Apple2IO(cpu, callbacks)
|
||||
SETIOUDIS:0x7E, // Enable double hires
|
||||
CLRIOUDIS:0x7F // Disable double hires
|
||||
};
|
||||
|
||||
|
||||
function _debug() {
|
||||
// debug.apply(arguments);
|
||||
}
|
||||
@ -116,43 +115,43 @@ function Apple2IO(cpu, callbacks)
|
||||
var delta = now - _trigger;
|
||||
switch (off) {
|
||||
case LOC.CLR80VID:
|
||||
// _debug("80 Column Mode off");
|
||||
// _debug('80 Column Mode off');
|
||||
if ('_80col' in callbacks) callbacks._80col(false);
|
||||
break;
|
||||
case LOC.SET80VID:
|
||||
// _debug("80 Column Mode on");
|
||||
// _debug('80 Column Mode on');
|
||||
if ('_80col' in callbacks) callbacks._80col(true);
|
||||
break;
|
||||
case LOC.CLRALTCH:
|
||||
// _debug("Alt Char off");
|
||||
// _debug('Alt Char off');
|
||||
if ('altchar' in callbacks) callbacks.altchar(false);
|
||||
break;
|
||||
case LOC.SETALTCH:
|
||||
// _debug("Alt Char on");
|
||||
// _debug('Alt Char on');
|
||||
if ('altchar' in callbacks) callbacks.altchar(true);
|
||||
break;
|
||||
case LOC.CLRTEXT:
|
||||
_debug("Graphics Mode");
|
||||
_debug('Graphics Mode');
|
||||
callbacks.text(false);
|
||||
break;
|
||||
case LOC.SETTEXT:
|
||||
_debug("Text Mode");
|
||||
_debug('Text Mode');
|
||||
callbacks.text(true);
|
||||
break;
|
||||
case LOC.CLRMIXED:
|
||||
_debug("Mixed Mode off");
|
||||
_debug('Mixed Mode off');
|
||||
callbacks.mixed(false);
|
||||
break;
|
||||
case LOC.SETMIXED:
|
||||
_debug("Mixed Mode on");
|
||||
_debug('Mixed Mode on');
|
||||
callbacks.mixed(true);
|
||||
break;
|
||||
case LOC.CLRHIRES:
|
||||
_debug("LoRes Mode");
|
||||
_debug('LoRes Mode');
|
||||
callbacks.hires(false);
|
||||
break;
|
||||
case LOC.SETHIRES:
|
||||
_debug("HiRes Mode");
|
||||
_debug('HiRes Mode');
|
||||
callbacks.hires(true);
|
||||
break;
|
||||
case LOC.PAGE1:
|
||||
@ -162,27 +161,27 @@ function Apple2IO(cpu, callbacks)
|
||||
callbacks.page(2);
|
||||
break;
|
||||
case LOC.RDTEXT:
|
||||
if ('isText' in callbacks)
|
||||
if ('isText' in callbacks)
|
||||
result = callbacks.isText() ? 0x80 : 0x0;
|
||||
break;
|
||||
case LOC.RDMIXED:
|
||||
if ('isMixed' in callbacks)
|
||||
if ('isMixed' in callbacks)
|
||||
result = callbacks.isMixed() ? 0x80 : 0x0;
|
||||
break;
|
||||
case LOC.RDPAGE2:
|
||||
if ('isPage2' in callbacks)
|
||||
if ('isPage2' in callbacks)
|
||||
result = callbacks.isPage2() ? 0x80 : 0x0;
|
||||
break;
|
||||
case LOC.RDHIRES:
|
||||
if ('isHires' in callbacks)
|
||||
if ('isHires' in callbacks)
|
||||
result = callbacks.isHires() ? 0x80 : 0x0;
|
||||
break;
|
||||
case LOC.RD80VID:
|
||||
if ('is80Col' in callbacks)
|
||||
if ('is80Col' in callbacks)
|
||||
result = callbacks.is80Col() ? 0x80 : 0x0;
|
||||
break;
|
||||
case LOC.RDALTCH:
|
||||
if ('isAltChar' in callbacks)
|
||||
if ('isAltChar' in callbacks)
|
||||
result = callbacks.isAltChar() ? 0x80 : 0x0;
|
||||
break;
|
||||
case LOC.SETAN0:
|
||||
@ -262,7 +261,7 @@ function Apple2IO(cpu, callbacks)
|
||||
_trigger = cpu.cycles();
|
||||
break;
|
||||
case LOC.TAPEIN:
|
||||
var flipped = false;
|
||||
// var flipped = false;
|
||||
if (_tapeOffset == -1) {
|
||||
_tapeOffset = 0;
|
||||
_tapeNext = now;
|
||||
@ -270,22 +269,22 @@ function Apple2IO(cpu, callbacks)
|
||||
if (_tapeOffset < _tape.length) {
|
||||
while (now >= _tapeNext) {
|
||||
if ((_tapeOffset % 1000) === 0) {
|
||||
debug("Read " + (_tapeOffset / 1000));
|
||||
debug('Read ' + (_tapeOffset / 1000));
|
||||
}
|
||||
_tapeFlip = !_tapeFlip;
|
||||
flipped = true;
|
||||
// flipped = true;
|
||||
_tapeNext += _tape[_tapeOffset++];
|
||||
}
|
||||
result = _tapeFlip ? 0x80 : 0x00;
|
||||
}
|
||||
/*
|
||||
if (flipped) {
|
||||
debug("now=" + now + " next=" + _tapeNext + " (" + (_tapeNext - now) + ")");
|
||||
debug('now=' + now + ' next=' + _tapeNext + ' (' + (_tapeNext - now) + ')');
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
var progress =
|
||||
var progress =
|
||||
Math.round(_tapeOffset / _tapeBuffer.length * 100) / 100;
|
||||
|
||||
if (_progress != progress) {
|
||||
@ -294,9 +293,9 @@ function Apple2IO(cpu, callbacks)
|
||||
}
|
||||
*/
|
||||
}
|
||||
return result;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
return {
|
||||
registerSwitches: function apple2io_registerSwitches(a, locs) {
|
||||
each(locs, function(key) {
|
||||
@ -314,12 +313,12 @@ function Apple2IO(cpu, callbacks)
|
||||
end: function apple2io_end() {
|
||||
return 0xc0;
|
||||
},
|
||||
read: function apple2io_read(page, off) {
|
||||
read: function apple2io_read(page, off) {
|
||||
var result = 0;
|
||||
if (_locs[off]) {
|
||||
result = _locs[off].ioSwitch(off);
|
||||
} else {
|
||||
debug("I/O read: C0" + toHex(off));
|
||||
debug('I/O read: C0' + toHex(off));
|
||||
}
|
||||
return result;
|
||||
},
|
||||
@ -327,7 +326,7 @@ function Apple2IO(cpu, callbacks)
|
||||
if (_locs[off]) {
|
||||
_locs[off].ioSwitch(off, val);
|
||||
} else {
|
||||
debug("I/O write: C0" + toHex(off));
|
||||
debug('I/O write: C0' + toHex(off));
|
||||
}
|
||||
},
|
||||
getState: function apple2io_getState() { return {}; },
|
||||
@ -339,7 +338,7 @@ function Apple2IO(cpu, callbacks)
|
||||
_keyDown = true;
|
||||
_key = ascii | 0x80;
|
||||
},
|
||||
keyUp: function apple2io_keyUp() {
|
||||
keyUp: function apple2io_keyUp() {
|
||||
_keyDown = false;
|
||||
_key = 0;
|
||||
},
|
||||
@ -353,10 +352,10 @@ function Apple2IO(cpu, callbacks)
|
||||
paddle: function apple2io_paddle(p, v) {
|
||||
_paddle[p] = v;
|
||||
},
|
||||
|
||||
|
||||
updateHz: function apple2io_updateHz(hz) {
|
||||
_hz = hz;
|
||||
|
||||
|
||||
_cycles_per_sample = _hz / _rate;
|
||||
},
|
||||
setKeyBuffer: function apple2io_setKeyBuffer(buffer) {
|
||||
@ -373,15 +372,15 @@ function Apple2IO(cpu, callbacks)
|
||||
_tapeOffset = -1;
|
||||
},
|
||||
|
||||
sampleRate: function sampleRate(rate) {
|
||||
sampleRate: function sampleRate(rate) {
|
||||
_rate = rate;
|
||||
_cycles_per_sample = _hz / _rate;
|
||||
},
|
||||
|
||||
|
||||
sampleTick: function sampleTick() {
|
||||
_tick();
|
||||
},
|
||||
|
||||
|
||||
addSampleListener: function addSampleListener(cb) {
|
||||
_audioListener = cb;
|
||||
}
|
||||
|
173
js/applesoft/decompiler.js
Normal file
173
js/applesoft/decompiler.js
Normal file
@ -0,0 +1,173 @@
|
||||
function ApplesoftDump(mem)
|
||||
{
|
||||
var _mem = mem;
|
||||
|
||||
var LETTERS =
|
||||
" " +
|
||||
" !\"#$%&'()*+,-./0123456789:;<=>?" +
|
||||
"@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_" +
|
||||
"`abcdefghijklmnopqrstuvwxyz{|}~ ";
|
||||
var TOKENS = {
|
||||
0x80: "END",
|
||||
0x81: "FOR",
|
||||
0x82: "NEXT",
|
||||
0x83: "DATA",
|
||||
0x84: "INPUT",
|
||||
0x85: "DEL",
|
||||
0x86: "DIM",
|
||||
0x87: "READ",
|
||||
0x88: "GR",
|
||||
0x89: "TEXT",
|
||||
0x8a: "PR#",
|
||||
0x8b: "IN#",
|
||||
0x8c: "CALL",
|
||||
0x8d: "PLOT",
|
||||
0x8e: "HLIN",
|
||||
0x8f: "VLIN",
|
||||
0x90: "HGR2",
|
||||
0x91: "HGR",
|
||||
0x92: "HCOLOR=",
|
||||
0x93: "HPLOT",
|
||||
0x94: "DRAW",
|
||||
0x95: "XDRAW",
|
||||
0x96: "HTAB",
|
||||
0x97: "HOME",
|
||||
0x98: "ROT=",
|
||||
0x99: "SCALE=",
|
||||
0x9a: "SHLOAD",
|
||||
0x9b: "TRACE",
|
||||
0x9c: "NOTRACE",
|
||||
0x9d: "NORMAL",
|
||||
0x9e: "INVERSE",
|
||||
0x9f: "FLASH",
|
||||
0xa0: "COLOR=",
|
||||
0xa1: "POP=",
|
||||
0xa2: "VTAB",
|
||||
0xa3: "HIMEM:",
|
||||
0xa4: "LOMEM:",
|
||||
0xa5: "ONERR",
|
||||
0xa6: "RESUME",
|
||||
0xa7: "RECALL",
|
||||
0xa8: "STORE",
|
||||
0xa9: "SPEED=",
|
||||
0xaa: "LET",
|
||||
0xab: "GOTO",
|
||||
0xac: "RUN",
|
||||
0xad: "IF",
|
||||
0xae: "RESTORE",
|
||||
0xaf: "&",
|
||||
0xb0: "GOSUB",
|
||||
0xb1: "RETURN",
|
||||
0xb2: "REM",
|
||||
0xb3: "STOP",
|
||||
0xb4: "ON",
|
||||
0xb5: "WAIT",
|
||||
0xb6: "LOAD",
|
||||
0xb7: "SAVE",
|
||||
0xb8: "DEF",
|
||||
0xb9: "POKE",
|
||||
0xba: "PRINT",
|
||||
0xbb: "CONT",
|
||||
0xbc: "LIST",
|
||||
0xbd: "CLEAR",
|
||||
0xbe: "GET",
|
||||
0xbf: "NEW",
|
||||
0xc0: "TAB(",
|
||||
0xc1: "TO",
|
||||
0xc2: "FN",
|
||||
0xc3: "SPC(",
|
||||
0xc4: "THEN",
|
||||
0xc5: "AT",
|
||||
0xc6: "NOT",
|
||||
0xc7: "STEP",
|
||||
0xc8: "+",
|
||||
0xc9: "-",
|
||||
0xca: "*",
|
||||
0xcb: "/",
|
||||
0xcc: "^",
|
||||
0xcd: "AND",
|
||||
0xce: "OR",
|
||||
0xcf: ">",
|
||||
0xd0: "=",
|
||||
0xd1: "<",
|
||||
0xd2: "SGN",
|
||||
0xd3: "INT",
|
||||
0xd4: "ABS",
|
||||
0xd5: "USR",
|
||||
0xd6: "FRE",
|
||||
0xd7: "SCRN(",
|
||||
0xd8: "PDL",
|
||||
0xd9: "POS",
|
||||
0xda: "SQR",
|
||||
0xdb: "RND",
|
||||
0xdc: "LOG",
|
||||
0xdd: "EXP",
|
||||
0xde: "COS",
|
||||
0xdf: "SIN",
|
||||
0xe0: "TAN",
|
||||
0xe1: "ATN",
|
||||
0xe2: "PEEK",
|
||||
0xe3: "LEN",
|
||||
0xe4: "STR$",
|
||||
0xe5: "VAL",
|
||||
0xe6: "ASC",
|
||||
0xe7: "CHR$",
|
||||
0xe8: "LEFT$",
|
||||
0xe9: "RIGHT$",
|
||||
0xea: "MID$"
|
||||
};
|
||||
|
||||
function readByte(addr) {
|
||||
var page = addr >> 8,
|
||||
off = addr & 0xff;
|
||||
|
||||
return _mem.read(page, off);
|
||||
}
|
||||
|
||||
function readWord(addr) {
|
||||
var lsb, msb;
|
||||
|
||||
lsb = readByte(addr, debug);
|
||||
msb = readByte(addr + 1, debug);
|
||||
|
||||
return (msb << 8) | lsb;
|
||||
}
|
||||
|
||||
return {
|
||||
toString: function () {
|
||||
var str = "";
|
||||
var start = readWord(0x67); // Start
|
||||
var end = readWord(0xaf); // End of program
|
||||
var addr = start;
|
||||
do {
|
||||
var line = "";
|
||||
var next = readWord(addr);
|
||||
addr += 2;
|
||||
var lineno = readWord(addr);
|
||||
addr += 2;
|
||||
|
||||
line += lineno;
|
||||
line += " ";
|
||||
var val = false;
|
||||
do {
|
||||
if (addr < start || addr > end)
|
||||
return str;
|
||||
|
||||
var val = readByte(addr++);
|
||||
if (val > 0x80) {
|
||||
line += " ";
|
||||
line += TOKENS[val];
|
||||
line += " ";
|
||||
}
|
||||
else
|
||||
line += LETTERS[val];
|
||||
} while (val);
|
||||
line += "\n";
|
||||
str += line;
|
||||
addr = next;
|
||||
} while (addr && addr >= start && addr < end);
|
||||
|
||||
return str;
|
||||
}
|
||||
};
|
||||
}
|
28
js/base64.js
28
js/base64.js
@ -2,7 +2,7 @@
|
||||
|
||||
function base64_encode (data) {
|
||||
// Twacked by Will Scullin to handle arrays of "bytes"
|
||||
|
||||
|
||||
// http://kevin.vanzonneveld.net
|
||||
// + original by: Tyler Akins (http://rumkin.com)
|
||||
// + improved by: Bayron Guevara
|
||||
@ -19,9 +19,9 @@ function base64_encode (data) {
|
||||
//if (typeof this.window['atob'] == 'function') {
|
||||
// return atob(data);
|
||||
//}
|
||||
|
||||
var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
|
||||
var o1, o2, o3, h1, h2, h3, h4, bits, i = 0, ac = 0, enc="", tmp_arr = [];
|
||||
|
||||
var b64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
|
||||
var o1, o2, o3, h1, h2, h3, h4, bits, i = 0, ac = 0, enc='', tmp_arr = [];
|
||||
|
||||
if (!data) {
|
||||
return data;
|
||||
@ -42,15 +42,15 @@ function base64_encode (data) {
|
||||
// use hexets to index into b64, and append result to encoded string
|
||||
tmp_arr[ac++] = b64.charAt(h1) + b64.charAt(h2) + b64.charAt(h3) + b64.charAt(h4);
|
||||
} while (i < data.length);
|
||||
|
||||
|
||||
enc = tmp_arr.join('');
|
||||
|
||||
|
||||
switch (data.length % 3) {
|
||||
case 1:
|
||||
enc = enc.slice(0, -2) + '==';
|
||||
case 1:
|
||||
enc = enc.slice(0, -2) + '==';
|
||||
break;
|
||||
case 2:
|
||||
enc = enc.slice(0, -1) + '=';
|
||||
case 2:
|
||||
enc = enc.slice(0, -1) + '=';
|
||||
break;
|
||||
}
|
||||
|
||||
@ -59,7 +59,7 @@ function base64_encode (data) {
|
||||
|
||||
function base64_decode(data) {
|
||||
// Twacked by Will Scullin to handle arrays of "bytes"
|
||||
|
||||
|
||||
// http://kevin.vanzonneveld.net
|
||||
// + original by: Tyler Akins (http://rumkin.com)
|
||||
// + improved by: Thunder.m
|
||||
@ -80,7 +80,7 @@ function base64_decode(data) {
|
||||
// return btoa(data);
|
||||
//}
|
||||
|
||||
var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
|
||||
var b64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
|
||||
var o1, o2, o3, h1, h2, h3, h4, bits, i = 0, ac = 0, tmp_arr = [];
|
||||
|
||||
if (!data) {
|
||||
@ -99,10 +99,10 @@ function base64_decode(data) {
|
||||
o2 = bits>>8 & 0xff;
|
||||
o3 = bits & 0xff;
|
||||
|
||||
tmp_arr[ac++] = o1;
|
||||
tmp_arr[ac++] = o1;
|
||||
if (h3 != 64) {
|
||||
tmp_arr[ac++] = o2;
|
||||
}
|
||||
}
|
||||
if (h4 != 64) {
|
||||
tmp_arr[ac++] = o3;
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
/* -*- mode: JavaScript; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* Copyright 2010-2014 Will Scullin <scullin@scullinsteel.com>
|
||||
/* Copyright 2010-2016 Will Scullin <scullin@scullinsteel.com>
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software and its
|
||||
* documentation for any purpose is hereby granted without fee, provided that
|
||||
@ -10,16 +9,14 @@
|
||||
* implied warranty.
|
||||
*/
|
||||
|
||||
/*jshint browser:true */
|
||||
/*globals allocMemPages: false,
|
||||
charset: false,
|
||||
base64_encode: false, base64_decode: false */
|
||||
/*exported LoresPage, HiresPage, VideoModes*/
|
||||
|
||||
/*
|
||||
* Text Page 1 Drawing
|
||||
*/
|
||||
|
||||
/*globals allocMemPages: false,
|
||||
base64_encode: false, base64_decode: false */
|
||||
/*exported LoresPage, HiresPage, VideoModes*/
|
||||
|
||||
var textMode = true;
|
||||
var mixedMode = true;
|
||||
var hiresMode = false;
|
||||
@ -34,8 +31,10 @@ var scanlines = false;
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
function LoresPage(page)
|
||||
function LoresPage(page, charset)
|
||||
{
|
||||
'use strict';
|
||||
|
||||
// $00-$3F inverse
|
||||
// $40-$7F flashing
|
||||
// $80-$FF normal
|
||||
@ -108,16 +107,16 @@ function LoresPage(page)
|
||||
data[off + 560 * 4 + 2] = c2 >> 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
_init();
|
||||
|
||||
return {
|
||||
start: function() {
|
||||
start: function() {
|
||||
var self = this;
|
||||
window.setInterval(function() {
|
||||
self.blink();
|
||||
}, 267);
|
||||
return (0x04 * _page);
|
||||
return (0x04 * _page);
|
||||
},
|
||||
end: function() { return (0x04 * _page) + 0x03; },
|
||||
read: function(page, off) {
|
||||
@ -136,10 +135,10 @@ function LoresPage(page)
|
||||
var col = (base % 0x80) % 0x28,
|
||||
adj = off - col;
|
||||
|
||||
// 000001cd eabab000 -> 000abcde
|
||||
// 000001cd eabab000 -> 000abcde
|
||||
var ab = (adj & 0x18),
|
||||
cd = (page & 0x03) << 1,
|
||||
e = adj >> 7;
|
||||
e = adj >> 7;
|
||||
|
||||
var row = ab | cd | e, color, idx, jdx, b;
|
||||
|
||||
@ -159,7 +158,7 @@ function LoresPage(page)
|
||||
back = _greenMode ? _green : _white;
|
||||
}
|
||||
for (jdx = 0; jdx < 8; jdx++) {
|
||||
b = charset[(val & 0x3f) * 8 + jdx];
|
||||
b = charset[val * 8 + jdx];
|
||||
b <<= 1;
|
||||
for (idx = 0; idx < 7; idx++) {
|
||||
color = (b & 0x80) ? fore : back;
|
||||
@ -177,7 +176,7 @@ function LoresPage(page)
|
||||
b = (jdx < 4) ? (val & 0x0f) : (val >> 4);
|
||||
b |= (b << 4);
|
||||
b |= (b << 8);
|
||||
if (col & 0x1) {
|
||||
if ((col & 0x1) !== 0) {
|
||||
b <<= 2;
|
||||
}
|
||||
for (idx = 0; idx < 14; idx++) {
|
||||
@ -187,7 +186,7 @@ function LoresPage(page)
|
||||
off += 4;
|
||||
}
|
||||
off += 546 * 4 + 560 * 4;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (jdx = 0; jdx < 8; jdx++) {
|
||||
b = (jdx < 4) ? (val & 0x0f) : (val >> 4);
|
||||
@ -212,7 +211,7 @@ function LoresPage(page)
|
||||
},
|
||||
blink: function() {
|
||||
var addr = 0x400 * _page;
|
||||
_refreshing = true;
|
||||
_refreshing = true;
|
||||
_blink = !_blink;
|
||||
for (var idx = 0; idx < 0x400; idx++, addr++) {
|
||||
var b = _buffer[idx];
|
||||
@ -247,14 +246,14 @@ function LoresPage(page)
|
||||
}
|
||||
|
||||
function HiresPage(page)
|
||||
{
|
||||
{
|
||||
var _page = page;
|
||||
|
||||
var orangeCol = [0xff, 0x65, 0x00];
|
||||
var greenCol = [0x00, 0xff, 0x00];
|
||||
var blueCol = [0x09, 0x2a, 0xff];
|
||||
var violetCol = [0xc9, 0x39, 0xc7];
|
||||
var whiteCol = [0xff, 0xff, 0xff];
|
||||
var whiteCol = [0xff, 0xff, 0xff];
|
||||
var blackCol = [0x00, 0x00, 0x00];
|
||||
|
||||
var _buffer = [];
|
||||
@ -269,7 +268,7 @@ function HiresPage(page)
|
||||
for (var idx = 0; idx < 0x2000; idx++)
|
||||
_buffer[idx] = 0; // Math.floor(Math.random()*256);
|
||||
}
|
||||
|
||||
|
||||
function _drawPixel(data, off, color) {
|
||||
var c0 = color[0], c1 = color[1], c2 = color[2];
|
||||
|
||||
@ -286,7 +285,7 @@ function HiresPage(page)
|
||||
data[off + 560 * 4 + 2] = data[off + 560 * 4 + 6] = c2 >> 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
_init();
|
||||
|
||||
return {
|
||||
@ -306,17 +305,17 @@ function HiresPage(page)
|
||||
if (_buffer[base] === val && !_refreshing)
|
||||
return;
|
||||
_buffer[base] = val;
|
||||
|
||||
|
||||
var hbs = val & 0x80;
|
||||
val &= 0x7f;
|
||||
|
||||
var col = (base % 0x80) % 0x28,
|
||||
adj = off - col;
|
||||
|
||||
// 000001cd eabab000 -> 000abcde
|
||||
// 000001cd eabab000 -> 000abcde
|
||||
var ab = (adj & 0x18),
|
||||
cd = (page & 0x03) << 1,
|
||||
e = adj >> 7;
|
||||
e = adj >> 7;
|
||||
|
||||
var rowa = ab | cd | e,
|
||||
rowb = base >> 10;
|
||||
@ -324,18 +323,18 @@ function HiresPage(page)
|
||||
if ((rowa < 24) && (col < 40)) {
|
||||
if (textMode || !hiresMode || (mixedMode && rowa > 19))
|
||||
return;
|
||||
|
||||
|
||||
var data = pages[_page].data,
|
||||
dy = rowa * 8 + rowb,
|
||||
dx = col * 14 - 2,
|
||||
b0 = col > 0 ? _buffer[base - 1] : 0,
|
||||
b2 = col < 39 ? _buffer[base + 1] : 0;
|
||||
dy = rowa * 8 + rowb,
|
||||
dx = col * 14 - 2,
|
||||
b0 = col > 0 ? _buffer[base - 1] : 0,
|
||||
b2 = col < 39 ? _buffer[base + 1] : 0;
|
||||
val |= (b2 & 0x3) << 7;
|
||||
var v0 = b0 & 0x20, v1 = b0 & 0x40, v2 = val & 0x1,
|
||||
odd = !(col & 0x1),
|
||||
color,
|
||||
oddCol = (hbs ? orangeCol : greenCol),
|
||||
evenCol = (hbs ? blueCol : violetCol);
|
||||
odd = (col & 0x1) === 0,
|
||||
color,
|
||||
oddCol = (hbs ? orangeCol : greenCol),
|
||||
evenCol = (hbs ? blueCol : violetCol);
|
||||
|
||||
off = dx * 4 + dy * 560 * 4 * 2;
|
||||
for (var idx = 0; idx < 9; idx++, off += 8) {
|
||||
@ -434,7 +433,7 @@ function VideoModes(gr,hgr,gr2,hgr2) {
|
||||
_refresh();
|
||||
}
|
||||
},
|
||||
mixed: function(on) {
|
||||
mixed: function(on) {
|
||||
var old = mixedMode;
|
||||
mixedMode = on;
|
||||
if (old != on) {
|
||||
@ -490,4 +489,3 @@ function VideoModes(gr,hgr,gr2,hgr2) {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
220
js/canvas2e.js
220
js/canvas2e.js
@ -1,5 +1,4 @@
|
||||
/* -*- mode: JavaScript; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* Copyright 2010-2013 Will Scullin <scullin@scullinsteel.com>
|
||||
/* Copyright 2010-2016 Will Scullin <scullin@scullinsteel.com>
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software and its
|
||||
* documentation for any purpose is hereby granted without fee, provided that
|
||||
@ -10,8 +9,9 @@
|
||||
* implied warranty.
|
||||
*/
|
||||
|
||||
/*jshint browser:true */
|
||||
/*globals allocMemPages: false, charset: false, base64_encode: false, base64_decode: false, enhanced: false */
|
||||
/*globals allocMemPages: false, debug: false,
|
||||
base64_encode: false, base64_decode: false,
|
||||
enhanced: false */
|
||||
/*exported LoresPage, HiresPage, VideoModes */
|
||||
|
||||
|
||||
@ -22,6 +22,12 @@ var pageMode = 1;
|
||||
var _80colMode = false;
|
||||
var altCharMode = false;
|
||||
var doubleHiresMode = false;
|
||||
var monoDHRMode = false;
|
||||
var colorDHRMode = false;
|
||||
var mixedDHRMode = false;
|
||||
var highColorHGRMode = false;
|
||||
var highColorTextMode = false;
|
||||
|
||||
var pages = [];
|
||||
var context = null;
|
||||
var scanlines = false;
|
||||
@ -32,9 +38,9 @@ var scanlines = false;
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
function LoresPage(page)
|
||||
function LoresPage(page, charset)
|
||||
{
|
||||
"use strict";
|
||||
'use strict';
|
||||
|
||||
// $00-$3F inverse
|
||||
// $40-$7F flashing
|
||||
@ -72,7 +78,7 @@ function LoresPage(page)
|
||||
function _init() {
|
||||
_buffer[0] = allocMemPages(0x4);
|
||||
_buffer[1] = allocMemPages(0x4);
|
||||
|
||||
|
||||
for (var idx = 0; idx < 0x400; idx++) {
|
||||
_buffer[0][idx] = 0; // idx & 0x2 ? 0xff : 0x00;
|
||||
_buffer[1][idx] = 0; // idx & 0x2 ? 0xff : 0x00;
|
||||
@ -110,7 +116,7 @@ function LoresPage(page)
|
||||
data[off + 560 * 4 + 2] = c2 >> 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
_init();
|
||||
|
||||
return {
|
||||
@ -176,16 +182,13 @@ function LoresPage(page)
|
||||
return;
|
||||
_buffer[bank][base] = val;
|
||||
|
||||
if (bank !== 0 && !_80colMode)
|
||||
return;
|
||||
|
||||
var col = (base % 0x80) % 0x28,
|
||||
adj = off - col;
|
||||
|
||||
// 000001cd eabab000 -> 000abcde
|
||||
// 000001cd eabab000 -> 000abcde
|
||||
var ab = (adj & 0x18),
|
||||
cd = (page & 0x03) << 1,
|
||||
e = adj >> 7;
|
||||
e = adj >> 7;
|
||||
var idx, jdx;
|
||||
var row = ab | cd | e;
|
||||
var b;
|
||||
@ -197,19 +200,20 @@ function LoresPage(page)
|
||||
|
||||
var color;
|
||||
if (textMode || (mixedMode && row > 19)) {
|
||||
var flash = ((val & 0xc0) == 0x40) &&
|
||||
_blink && !_80colMode && !altCharMode;
|
||||
var flash = ((val & 0xc0) == 0x40) &&
|
||||
_blink && !_80colMode && !altCharMode;
|
||||
fore = flash ? _black : (_greenMode ? _green : _white);
|
||||
back = flash ? (_greenMode ? _green : _white) : _black;
|
||||
|
||||
if (!enhanced) {
|
||||
val = (val >= 0x40 && val < 0x60) ? val - 0x40 : val;
|
||||
} else if (!altCharMode) {
|
||||
val = (val >= 0x40 && val < 0x80) ? val - 0x40 : val;
|
||||
}
|
||||
|
||||
if (_80colMode) {
|
||||
if (!enhanced) {
|
||||
val = (val >= 0x40 && val < 0x60) ? val - 0x40 : val;
|
||||
} else if (!altCharMode) {
|
||||
val = (val >= 0x40 && val < 0x80) ? val - 0x40 : val;
|
||||
}
|
||||
|
||||
off = (col * 14 + (bank ? 0 : 1) * 7 + row * 560 * 8 * 2) * 4;
|
||||
|
||||
for (jdx = 0; jdx < 8; jdx++) {
|
||||
b = charset[val * 8 + jdx];
|
||||
for (idx = 0; idx < 7; idx++) {
|
||||
@ -221,8 +225,21 @@ function LoresPage(page)
|
||||
off += 553 * 4 + 560 * 4;
|
||||
}
|
||||
} else {
|
||||
val = _buffer[0][base];
|
||||
|
||||
if (!enhanced) {
|
||||
val = (val >= 0x40 && val < 0x60) ? val - 0x40 : val;
|
||||
} else if (!altCharMode) {
|
||||
val = (val >= 0x40 && val < 0x80) ? val - 0x40 : val;
|
||||
}
|
||||
|
||||
off = (col * 14 + row * 560 * 8 * 2) * 4;
|
||||
|
||||
if (highColorTextMode) {
|
||||
fore = _colors[_buffer[0][base] >> 4];
|
||||
back = _colors[_buffer[0][base] & 0x0f];
|
||||
}
|
||||
|
||||
for (jdx = 0; jdx < 8; jdx++) {
|
||||
b = charset[val * 8 + jdx];
|
||||
for (idx = 0; idx < 7; idx++) {
|
||||
@ -253,13 +270,13 @@ function LoresPage(page)
|
||||
off += 4;
|
||||
}
|
||||
off += 553 * 4 + 560 * 4;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (bank & 0x1) {
|
||||
val = ((val & 0x77) << 1) | ((val & 0x88) >> 3);
|
||||
}
|
||||
for (jdx = 0; jdx < 8; jdx++) {
|
||||
color = _colors[(jdx < 4) ?
|
||||
color = _colors[(jdx < 4) ?
|
||||
(val & 0x0f) : (val >> 4)];
|
||||
for (idx = 0; idx < 7; idx++) {
|
||||
_drawHalfPixel(data, off, color);
|
||||
@ -288,12 +305,12 @@ function LoresPage(page)
|
||||
off += 4;
|
||||
}
|
||||
off += 546 * 4 + 560 * 4;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (jdx = 0; jdx < 8; jdx++) {
|
||||
color = _colors[(jdx < 4) ?
|
||||
color = _colors[(jdx < 4) ?
|
||||
(val & 0x0f) : (val >> 4)];
|
||||
for (idx = 0; idx < 7; idx++) {
|
||||
for (idx = 0; idx < 7; idx++) {
|
||||
_drawPixel(data, off, color);
|
||||
off += 8;
|
||||
}
|
||||
@ -305,11 +322,9 @@ function LoresPage(page)
|
||||
}
|
||||
},
|
||||
refresh: function() {
|
||||
var page, off, addr = 0x400 * _page;
|
||||
var addr = 0x400 * _page;
|
||||
_refreshing = true;
|
||||
for (var idx = 0; idx < 0x400; idx++, addr++) {
|
||||
page = addr >> 8;
|
||||
off = addr & 0xff;
|
||||
this._write(addr >> 8, addr & 0xff, _buffer[0][idx], 0);
|
||||
if (_80colMode)
|
||||
this._write(addr >> 8, addr & 0xff, _buffer[1][idx], 1);
|
||||
@ -318,7 +333,7 @@ function LoresPage(page)
|
||||
},
|
||||
blink: function() {
|
||||
var addr = 0x400 * _page;
|
||||
_refreshing = true;
|
||||
_refreshing = true;
|
||||
_blink = !_blink;
|
||||
for (var idx = 0; idx < 0x400; idx++, addr++) {
|
||||
var b = _buffer[0][idx];
|
||||
@ -361,8 +376,8 @@ function LoresPage(page)
|
||||
***************************************************************************/
|
||||
|
||||
function HiresPage(page)
|
||||
{
|
||||
"use strict";
|
||||
{
|
||||
'use strict';
|
||||
|
||||
var _page = page;
|
||||
|
||||
@ -410,14 +425,14 @@ function HiresPage(page)
|
||||
var greenCol = [0x00, 0xff, 0x00];
|
||||
var blueCol = [0x09, 0x2a, 0xff];
|
||||
var violetCol = [0xc9, 0x39, 0xc7];
|
||||
var whiteCol = [0xff, 0xff, 0xff];
|
||||
var whiteCol = [0xff, 0xff, 0xff];
|
||||
var blackCol = [0x00, 0x00, 0x00];
|
||||
|
||||
var _buffer = [];
|
||||
var _refreshing = false;
|
||||
|
||||
var _green = [0x00, 0xff, 0x80];
|
||||
var _greenMode = false;
|
||||
var _green = [0x00, 0xff, 0x80];
|
||||
|
||||
function _init() {
|
||||
_buffer[0] = allocMemPages(0x20);
|
||||
@ -430,6 +445,7 @@ function HiresPage(page)
|
||||
|
||||
function _drawPixel(data, off, color) {
|
||||
var c0 = color[0], c1 = color[1], c2 = color[2];
|
||||
|
||||
data[off + 0] = data[off + 4] = c0;
|
||||
data[off + 1] = data[off + 5] = c1;
|
||||
data[off + 2] = data[off + 6] = c2;
|
||||
@ -459,7 +475,7 @@ function HiresPage(page)
|
||||
data[off + 560 * 4 + 2] = c2 >> 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
_init();
|
||||
|
||||
return {
|
||||
@ -510,13 +526,10 @@ function HiresPage(page)
|
||||
return [c[0] * 0.75, c[1] * 0.75, c[2] * 0.75];
|
||||
}
|
||||
var addr = (page << 8) | off, base = addr - 0x2000 * _page,
|
||||
idx, jdx;
|
||||
idx, jdx;
|
||||
if (_buffer[bank][base] == val && !_refreshing)
|
||||
return;
|
||||
_buffer[bank][base] = val;
|
||||
|
||||
if (bank !== 0 && !doubleHiresMode)
|
||||
return;
|
||||
|
||||
var hbs = val & 0x80;
|
||||
val &= 0x7f;
|
||||
@ -524,10 +537,10 @@ function HiresPage(page)
|
||||
var col = (base % 0x80) % 0x28,
|
||||
adj = off - col;
|
||||
|
||||
// 000001cd eabab000 -> 000abcde
|
||||
// 000001cd eabab000 -> 000abcde
|
||||
var ab = (adj & 0x18),
|
||||
cd = (page & 0x03) << 1,
|
||||
e = adj >> 7;
|
||||
e = adj >> 7;
|
||||
|
||||
var rowa = ab | cd | e,
|
||||
rowb = base >> 10;
|
||||
@ -536,9 +549,9 @@ function HiresPage(page)
|
||||
if ((rowa < 24) && (col < 40)) {
|
||||
if (textMode || !hiresMode || (mixedMode && rowa > 19))
|
||||
return;
|
||||
|
||||
|
||||
dy = rowa * 16 + rowb * 2;
|
||||
var bz, b0, b1, b2, b3, b4, c;
|
||||
var bz, b0, b1, b2, b3, b4, c, hb;
|
||||
if (doubleHiresMode) {
|
||||
// Every 4 bytes is 7 pixels
|
||||
// 2 bytes per bank
|
||||
@ -557,26 +570,57 @@ function HiresPage(page)
|
||||
((b2 & 0x3c) >> 2), // 4
|
||||
((b2 & 0x40) >> 6) | ((b3 & 0x07) << 1), // 5
|
||||
((b3 & 0x78) >> 3), // 6
|
||||
0], // 7
|
||||
hb = [0,
|
||||
b0 & 0x80, // 0
|
||||
b0 & 0x80, // 1
|
||||
b1 & 0x80, // 2
|
||||
b2 & 0x80, // 3
|
||||
b2 & 0x80, // 4
|
||||
b3 & 0x80, // 5
|
||||
b3 & 0x80, // 6
|
||||
0]; // 7
|
||||
if (col > 0) {
|
||||
c[0] = (bz & 0x78) >> 3;
|
||||
hb[0] = bz & 0x80;
|
||||
}
|
||||
if (col < 39) {
|
||||
c[8] = b4 & 0x0f;
|
||||
hb[8] = b4 & 0x80;
|
||||
}
|
||||
dx = mcol * 14;
|
||||
off = dx * 4 + dy * 280 * 4 * 2;
|
||||
|
||||
var monoColor = null;
|
||||
if (_greenMode) {
|
||||
monoColor = _green;
|
||||
} else if (monoDHRMode) {
|
||||
monoColor = whiteCol;
|
||||
}
|
||||
|
||||
for (idx = 1; idx < 8; idx++) {
|
||||
hbs = hb[idx];
|
||||
var dcolor = dcolors[r4[c[idx]]];
|
||||
var bits = c[idx-1] | (c[idx] << 4) | (c[idx+1] << 8);
|
||||
for (jdx = 0; jdx < 4; jdx++, off += 4) {
|
||||
if (_greenMode) {
|
||||
if (monoColor) {
|
||||
if (bits & 0x10) {
|
||||
_drawHalfPixel(data, off, _green);
|
||||
_drawHalfPixel(data, off, monoColor);
|
||||
} else {
|
||||
_drawHalfPixel(data, off, blackCol);
|
||||
}
|
||||
} else if (mixedDHRMode) {
|
||||
if (hbs) {
|
||||
_drawHalfPixel(data, off, dcolor);
|
||||
} else {
|
||||
if (bits & 0x10) {
|
||||
_drawHalfPixel(data, off, whiteCol);
|
||||
} else {
|
||||
_drawHalfPixel(data, off, blackCol);
|
||||
}
|
||||
}
|
||||
} else if (colorDHRMode) {
|
||||
_drawHalfPixel(data, off, dcolor);
|
||||
} else if (((bits & 0x3c) == 0x3c) ||
|
||||
((bits & 0xf0) == 0xf0) ||
|
||||
((bits & 0x1e) == 0x1e) ||
|
||||
@ -590,7 +634,7 @@ function HiresPage(page)
|
||||
_drawHalfPixel(data, off, dcolor);
|
||||
} else if ((bits & 0x28) == 0x28) {
|
||||
_drawHalfPixel(data, off, dcolor);
|
||||
} else {
|
||||
} else {
|
||||
_drawHalfPixel(data, off, blackCol);
|
||||
}
|
||||
bits >>= 1;
|
||||
@ -607,22 +651,25 @@ function HiresPage(page)
|
||||
_refreshing = false;
|
||||
}
|
||||
} else {
|
||||
val = _buffer[0][base] & 0x7f;
|
||||
dx = col * 14 - 2;
|
||||
b0 = col > 0 ? _buffer[bank][base - 1] : 0;
|
||||
b2 = col < 39 ? _buffer[bank][base + 1] : 0;
|
||||
b0 = col > 0 ? _buffer[0][base - 1] : 0;
|
||||
b2 = col < 39 ? _buffer[0][base + 1] : 0;
|
||||
val |= (b2 & 0x3) << 7;
|
||||
var v0 = b0 & 0x20, v1 = b0 & 0x40, v2 = val & 0x1,
|
||||
odd = !(col & 0x1),
|
||||
color,
|
||||
oddCol = (hbs ? orangeCol : greenCol),
|
||||
evenCol = (hbs ? blueCol : violetCol);
|
||||
|
||||
odd = !(col & 0x1),
|
||||
color,
|
||||
oddCol = (hbs ? orangeCol : greenCol),
|
||||
evenCol = (hbs ? blueCol : violetCol);
|
||||
|
||||
off = dx * 4 + dy * 280 * 4 * 2;
|
||||
for (idx = 0; idx < 9; idx++, off += 8) {
|
||||
val >>= 1;
|
||||
if (v1) {
|
||||
if (_greenMode) {
|
||||
color = _green;
|
||||
} else if (highColorHGRMode) {
|
||||
color = dcolors[_buffer[1][base] >> 4];
|
||||
} else if (v0 || v2) {
|
||||
color = whiteCol;
|
||||
} else {
|
||||
@ -631,6 +678,8 @@ function HiresPage(page)
|
||||
} else {
|
||||
if (_greenMode) {
|
||||
color = blackCol;
|
||||
} else if (highColorHGRMode) {
|
||||
color = dcolors[_buffer[1][base] & 0x0f];
|
||||
} else if (odd && v2 && v0) {
|
||||
color = v0 ? dim(evenCol) : evenCol;
|
||||
} else if (!odd && v0 && v2) {
|
||||
@ -644,7 +693,7 @@ function HiresPage(page)
|
||||
_drawPixel(data, off, color);
|
||||
}
|
||||
dx += 2;
|
||||
|
||||
|
||||
v0 = v1;
|
||||
v1 = v2;
|
||||
v2 = val & 0x01;
|
||||
@ -694,6 +743,7 @@ function HiresPage(page)
|
||||
function VideoModes(gr,hgr,gr2,hgr2) {
|
||||
var _grs = [gr, gr2];
|
||||
var _hgrs = [hgr, hgr2];
|
||||
var _seq = '';
|
||||
|
||||
function _refresh() {
|
||||
gr.refresh();
|
||||
@ -711,15 +761,28 @@ function VideoModes(gr,hgr,gr2,hgr2) {
|
||||
mixedMode = false;
|
||||
hiresMode = true;
|
||||
pageMode = 1;
|
||||
|
||||
_80colMode = false;
|
||||
altCharMode = false;
|
||||
|
||||
doubleHiresMode = false;
|
||||
monoDHRMode = false;
|
||||
colorDHRMode = false;
|
||||
mixedDHRMode = false;
|
||||
highColorHGRMode = false;
|
||||
highColorTextMode = false;
|
||||
|
||||
_refresh();
|
||||
},
|
||||
text: function(on) {
|
||||
var old = textMode;
|
||||
textMode = on;
|
||||
|
||||
highColorTextMode = false;
|
||||
|
||||
_seq = on ? 'T+' : 'T-';
|
||||
// debug('_seq=', _seq);
|
||||
|
||||
if (old != on) {
|
||||
_refresh();
|
||||
}
|
||||
@ -727,6 +790,11 @@ function VideoModes(gr,hgr,gr2,hgr2) {
|
||||
_80col: function(on) {
|
||||
var old = _80colMode;
|
||||
_80colMode = on;
|
||||
|
||||
_seq += on ? '8+' : '8-';
|
||||
_seq = _seq.substr(0, 16);
|
||||
// debug('_seq=', _seq);
|
||||
|
||||
if (old != on) {
|
||||
_refresh();
|
||||
}
|
||||
@ -741,6 +809,11 @@ function VideoModes(gr,hgr,gr2,hgr2) {
|
||||
hires: function(on) {
|
||||
var old = hiresMode;
|
||||
hiresMode = on;
|
||||
highColorHGRMode = false;
|
||||
|
||||
_seq = (on ? 'H+' : 'H-');
|
||||
// debug('_seq=', _seq);
|
||||
|
||||
if (old != on) {
|
||||
_refresh();
|
||||
}
|
||||
@ -748,6 +821,41 @@ function VideoModes(gr,hgr,gr2,hgr2) {
|
||||
doublehires: function(on) {
|
||||
var old = doubleHiresMode;
|
||||
doubleHiresMode = on;
|
||||
|
||||
_seq += on ? 'D+' : 'D-';
|
||||
_seq = _seq.substr(0, 16);
|
||||
// debug('_seq=', _seq);
|
||||
|
||||
if (on) {
|
||||
if (_seq == 'T+D+') {
|
||||
debug('High color text mode');
|
||||
highColorTextMode = true;
|
||||
doubleHiresMode = false;
|
||||
} else if (_seq == 'H+8-D+') {
|
||||
debug('High color hgr');
|
||||
highColorHGRMode = true;
|
||||
doubleHiresMode = false;
|
||||
} else if (_seq == 'H+8+D+D-D+D-D+') {
|
||||
debug('DoubleHires color');
|
||||
colorDHRMode = true;
|
||||
monoDHRMode = false;
|
||||
mixedDHRMode = false;
|
||||
_seq = '';
|
||||
} else if (_seq == 'H+8-D+D-D+D-8+D+') {
|
||||
debug('DoubleHires mono');
|
||||
colorDHRMode = false;
|
||||
monoDHRMode = true;
|
||||
mixedDHRMode = false;
|
||||
_seq = '';
|
||||
} else if (_seq == 'H+8-D+D-8+D+D-D+') {
|
||||
debug('DoubleHires mixed');
|
||||
colorDHRMode = false;
|
||||
monoDHRMode = false;
|
||||
mixedDHRMode = true;
|
||||
_seq = '';
|
||||
}
|
||||
}
|
||||
|
||||
if (old != on) {
|
||||
if (on) {
|
||||
this.page(1);
|
||||
@ -755,7 +863,7 @@ function VideoModes(gr,hgr,gr2,hgr2) {
|
||||
_refresh();
|
||||
}
|
||||
},
|
||||
mixed: function(on) {
|
||||
mixed: function(on) {
|
||||
var old = mixedMode;
|
||||
mixedMode = on;
|
||||
if (old != on) {
|
||||
@ -835,5 +943,3 @@ function VideoModes(gr,hgr,gr2,hgr2) {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,11 +1,11 @@
|
||||
/*!
|
||||
* Copyright 2010-2013 Will Scullin <scullin@scullinsteel.com>
|
||||
* Copyright 2010-2016 Will Scullin <scullin@scullinsteel.com>
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software and its
|
||||
* documentation for any purpose is hereby granted without fee, provided that
|
||||
* the above copyright notice appear in all copies and that both that
|
||||
* copyright notice and this permission notice appear in supporting
|
||||
* documentation. No representations are made about the suitability of this
|
||||
* software for any purpose. It is provided "as is" without express or
|
||||
* software for any purpose. It is provided "as is" without express or
|
||||
* implied warranty.
|
||||
*/
|
||||
|
581
js/cpu6502.js
581
js/cpu6502.js
File diff suppressed because it is too large
Load Diff
159
js/disk2.js
159
js/disk2.js
@ -1,5 +1,4 @@
|
||||
/* -*- mode: JavaScript; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* Copyright 2010-2013 Will Scullin <scullin@scullinsteel.com>
|
||||
/* Copyright 2010-2016 Will Scullin <scullin@scullinsteel.com>
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software and its
|
||||
* documentation for any purpose is hereby granted without fee, provided that
|
||||
@ -10,18 +9,20 @@
|
||||
* implied warranty.
|
||||
*/
|
||||
|
||||
/*jshint browser: true */
|
||||
/*globals extend: false, bytify: false, base64_encode: false, base64_decode: false, each: false */
|
||||
/*exported DiskII */
|
||||
/*globals bytify, each: false, extend: false
|
||||
base64_encode, base64_decode
|
||||
Uint8Array
|
||||
*/
|
||||
|
||||
function DiskII(io, callbacks, slot)
|
||||
{
|
||||
"use strict";
|
||||
'use strict';
|
||||
|
||||
slot = slot || 6;
|
||||
var _drives = [
|
||||
{ // Drive 1
|
||||
format: "dsk",
|
||||
format: 'dsk',
|
||||
volume: 254,
|
||||
tracks: [],
|
||||
track: 0,
|
||||
@ -31,7 +32,7 @@ function DiskII(io, callbacks, slot)
|
||||
dirty: false
|
||||
},
|
||||
{ // Drive 2
|
||||
format: "dsk",
|
||||
format: 'dsk',
|
||||
volume: 254,
|
||||
tracks: [],
|
||||
track: 0,
|
||||
@ -68,12 +69,12 @@ function DiskII(io, callbacks, slot)
|
||||
DRIVEREADMODE: 0x8E, // Q7L
|
||||
DRIVEWRITEMODE: 0x8F // Q7H
|
||||
};
|
||||
|
||||
|
||||
// var DO = [0x0,0x7,0xE,0x6,0xD,0x5,0xC,0x4,
|
||||
// 0xB,0x3,0xA,0x2,0x9,0x1,0x8,0xF];
|
||||
var _DO = [0x0,0xD,0xB,0x9,0x7,0x5,0x3,0x1,
|
||||
0xE,0xC,0xA,0x8,0x6,0x4,0x2,0xF];
|
||||
|
||||
|
||||
// var PO = [0x0,0x8,0x1,0x9,0x2,0xa,0x3,0xb,
|
||||
// 0x4,0xc,0x5,0xd,0x6,0xe,0x7,0xf];
|
||||
var _PO = [0x0,0x2,0x4,0x6,0x8,0xa,0xc,0xe,
|
||||
@ -116,9 +117,9 @@ function DiskII(io, callbacks, slot)
|
||||
}
|
||||
|
||||
/**
|
||||
* From Beneath Apple DOS
|
||||
* From Beneath Apple DOS
|
||||
*/
|
||||
|
||||
|
||||
function _fourXfour(val) {
|
||||
var xx = val & 0xaa;
|
||||
var yy = val & 0x55;
|
||||
@ -170,7 +171,7 @@ function DiskII(io, callbacks, slot)
|
||||
/*
|
||||
* Gap 2 (5 bytes)
|
||||
*/
|
||||
|
||||
|
||||
for (idx = 0; idx < 0x05; idx++) {
|
||||
buf.push(0xff);
|
||||
}
|
||||
@ -180,33 +181,33 @@ function DiskII(io, callbacks, slot)
|
||||
*/
|
||||
|
||||
extend(buf, [0xd5, 0xaa, 0xad]); // Data Prolog D5 AA AD
|
||||
|
||||
|
||||
var nibbles = [];
|
||||
var ptr2 = 0;
|
||||
var ptr6 = 0x56;
|
||||
var idx2, idx6;
|
||||
|
||||
|
||||
for (idx = 0; idx < 0x156; idx++) {
|
||||
nibbles[idx] = 0;
|
||||
}
|
||||
|
||||
|
||||
idx2 = 0x55;
|
||||
for (idx6 = 0x101; idx6 >= 0; idx6--) {
|
||||
var val6 = data[idx6 % 0x100];
|
||||
var val2 = nibbles[ptr2 + idx2];
|
||||
|
||||
|
||||
val2 = (val2 << 1) | (val6 & 1);
|
||||
val6 >>= 1;
|
||||
val2 = (val2 << 1) | (val6 & 1);
|
||||
val6 >>= 1;
|
||||
|
||||
|
||||
nibbles[ptr6 + idx6] = val6;
|
||||
nibbles[ptr2 + idx2] = val2;
|
||||
|
||||
if (--idx2 < 0)
|
||||
|
||||
if (--idx2 < 0)
|
||||
idx2 = 0x55;
|
||||
}
|
||||
|
||||
|
||||
var last = 0;
|
||||
for (idx = 0; idx < 0x156; idx++) {
|
||||
var val = nibbles[idx];
|
||||
@ -214,13 +215,13 @@ function DiskII(io, callbacks, slot)
|
||||
last = val;
|
||||
}
|
||||
buf.push(_trans[last]);
|
||||
|
||||
|
||||
extend(buf, [0xde, 0xaa, 0xeb]); // Epilog DE AA EB
|
||||
|
||||
|
||||
/*
|
||||
* Gap 3
|
||||
*/
|
||||
|
||||
|
||||
buf.push(0xff);
|
||||
|
||||
return buf;
|
||||
@ -229,11 +230,11 @@ function DiskII(io, callbacks, slot)
|
||||
function _json_encode(drive, pretty) {
|
||||
var cur = _drives[drive - 1];
|
||||
var data = [];
|
||||
var format = "dsk";
|
||||
var format = 'dsk';
|
||||
for (var t = 0; t < cur.tracks.length; t++) {
|
||||
data[t] = [];
|
||||
if (cur.format === "nib") {
|
||||
format = "nib";
|
||||
if (cur.format === 'nib') {
|
||||
format = 'nib';
|
||||
data[t] = base64_encode(cur.tracks[t]);
|
||||
} else {
|
||||
for (var s = 0; s < 0x10; s++) {
|
||||
@ -241,12 +242,12 @@ function DiskII(io, callbacks, slot)
|
||||
}
|
||||
}
|
||||
}
|
||||
return JSON.stringify({"type": format,
|
||||
"encoding": "base64",
|
||||
"volume": cur.volume,
|
||||
"data": data},
|
||||
null,
|
||||
pretty ? " " : null);
|
||||
return JSON.stringify({'type': format,
|
||||
'encoding': 'base64',
|
||||
'volume': cur.volume,
|
||||
'data': data},
|
||||
null,
|
||||
pretty ? ' ' : null);
|
||||
}
|
||||
|
||||
function _json_decode(drive, data) {
|
||||
@ -261,14 +262,14 @@ function DiskII(io, callbacks, slot)
|
||||
var d = base64_decode(json.data[t][_s]);
|
||||
extend(track, _explodeSector(v, t, _DO[_s], d));
|
||||
}
|
||||
tracks[t] = bytify(track);
|
||||
tracks[t] = bytify(track);
|
||||
}
|
||||
_cur.volume = v;
|
||||
_cur.format = json.type;
|
||||
_cur.tracks = tracks;
|
||||
}
|
||||
|
||||
function _readNext() {
|
||||
function _readNext() {
|
||||
var result = 0;
|
||||
if (_skip || _writeMode) {
|
||||
var t = _cur.tracks[_cur.track >> 1];
|
||||
@ -283,8 +284,8 @@ function DiskII(io, callbacks, slot)
|
||||
|
||||
++_cur.head;
|
||||
}
|
||||
}
|
||||
_skip = (++_skip % 4);
|
||||
}
|
||||
_skip = (++_skip % 4);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -383,9 +384,9 @@ function DiskII(io, callbacks, slot)
|
||||
[-1, 0, 1, 2],
|
||||
[-2,-1, 0, 1],
|
||||
[ 1,-2,-1, 0]];
|
||||
|
||||
|
||||
function setPhase(phase, on) {
|
||||
_debug("phase " + phase + (on ? " on" : " off"));
|
||||
_debug('phase ' + phase + (on ? ' on' : ' off'));
|
||||
if (on) {
|
||||
_cur.track += _phase_delta[_cur.phase][phase];
|
||||
_cur.phase = phase;
|
||||
@ -395,10 +396,10 @@ function DiskII(io, callbacks, slot)
|
||||
if (_cur.track < 0x0)
|
||||
_cur.track = 0x0;
|
||||
|
||||
/* _debug("Drive " + _drive +
|
||||
", track " + toHex(_cur.track >> 1) +
|
||||
" (" + toHex(_cur.track) + ")" +
|
||||
" [" + (_cur.track % 4) + "/" + phase + "]"); */
|
||||
/* _debug('Drive ' + _drive +
|
||||
', track ' + toHex(_cur.track >> 1) +
|
||||
' (' + toHex(_cur.track) + ')' +
|
||||
' [' + (_cur.track % 4) + '/' + phase + ']'); */
|
||||
}
|
||||
}
|
||||
|
||||
@ -429,20 +430,20 @@ function DiskII(io, callbacks, slot)
|
||||
case LOC.PHASE3ON:
|
||||
setPhase(3, true);
|
||||
break;
|
||||
|
||||
|
||||
case LOC.DRIVEOFF:
|
||||
_debug("Drive Off");
|
||||
_debug('Drive Off');
|
||||
_on = false;
|
||||
if (callbacks.driveLight) { callbacks.driveLight(_drive, false); }
|
||||
break;
|
||||
case LOC.DRIVEON:
|
||||
_debug("Drive On");
|
||||
_debug('Drive On');
|
||||
_on = true;
|
||||
if (callbacks.driveLight) { callbacks.driveLight(_drive, true); }
|
||||
break;
|
||||
|
||||
|
||||
case LOC.DRIVE1:
|
||||
_debug("Disk 1");
|
||||
_debug('Disk 1');
|
||||
_drive = 1;
|
||||
_cur = _drives[_drive - 1];
|
||||
if (_on && callbacks.driveLight) {
|
||||
@ -451,7 +452,7 @@ function DiskII(io, callbacks, slot)
|
||||
}
|
||||
break;
|
||||
case LOC.DRIVE2:
|
||||
_debug("Disk 2");
|
||||
_debug('Disk 2');
|
||||
_drive = 2;
|
||||
_cur = _drives[_drive - 1];
|
||||
if (_on && callbacks.driveLight) {
|
||||
@ -459,25 +460,25 @@ function DiskII(io, callbacks, slot)
|
||||
callbacks.driveLight(2, true);
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case LOC.DRIVEREAD:
|
||||
result = _readNext();
|
||||
// _debug("read: " + toHex(result));
|
||||
// _debug('read: ' + toHex(result));
|
||||
break;
|
||||
|
||||
|
||||
case LOC.DRIVEWRITE:
|
||||
// _debug("write: " + toHex(val));
|
||||
// _debug('write: ' + toHex(val));
|
||||
if (val !== undefined) {
|
||||
_writeNext(val);
|
||||
}
|
||||
break;
|
||||
case LOC.DRIVEREADMODE:
|
||||
_debug("Read Mode");
|
||||
_debug('Read Mode');
|
||||
_writeMode = false;
|
||||
result = (_readNext() & 0x7f) | (_cur.readOnly ? 0x80 : 0x00);
|
||||
break;
|
||||
case LOC.DRIVEWRITEMODE:
|
||||
_debug("Write Mode");
|
||||
_debug('Write Mode');
|
||||
_writeMode = true;
|
||||
break;
|
||||
default:
|
||||
@ -650,10 +651,10 @@ function DiskII(io, callbacks, slot)
|
||||
var fmt = disk.type, readOnly = disk.readOnly;
|
||||
|
||||
var data, t, s;
|
||||
if (disk.encoding == "base64") {
|
||||
if (disk.encoding == 'base64') {
|
||||
data = [];
|
||||
for (t = 0; t < disk.data.length; t++) {
|
||||
if (fmt == "nib") {
|
||||
if (fmt == 'nib') {
|
||||
data[t] = base64_decode(disk.data[t]);
|
||||
} else {
|
||||
data[t] = [];
|
||||
@ -667,7 +668,7 @@ function DiskII(io, callbacks, slot)
|
||||
}
|
||||
var cur = _drives[drive - 1];
|
||||
|
||||
// var v = (fmt === "dsk" ? data[0x11][0x00][0x06] : 0xfe);
|
||||
// var v = (fmt === 'dsk' ? data[0x11][0x00][0x06] : 0xfe);
|
||||
// if (v == 0x00) {
|
||||
var v = disk.volume || 0xfe;
|
||||
// }
|
||||
@ -679,19 +680,19 @@ function DiskII(io, callbacks, slot)
|
||||
|
||||
for (t = 0; t < data.length; t++) {
|
||||
var track = [];
|
||||
if (fmt === "nib") {
|
||||
if (fmt === 'nib') {
|
||||
track = data[t];
|
||||
} else {
|
||||
for (s = 0; s < data[t].length; s++) {
|
||||
var _s = 15 - s;
|
||||
if (fmt === "po") { // ProDOS Order
|
||||
if (fmt === 'po') { // ProDOS Order
|
||||
extend(track,
|
||||
_explodeSector(v, t, _PO[s], data[t][s]));
|
||||
} else if (fmt === "dsk") { // DOS Order
|
||||
} else if (fmt === 'dsk') { // DOS Order
|
||||
extend(track,
|
||||
_explodeSector(v, t, _DO[_s], data[t][_s]));
|
||||
} else { // flat
|
||||
extend(track,
|
||||
extend(track,
|
||||
_explodeSector(v, t, s, data[t][s]));
|
||||
}
|
||||
}
|
||||
@ -712,32 +713,32 @@ function DiskII(io, callbacks, slot)
|
||||
var _cur = _drives[drive - 1];
|
||||
var tracks = [];
|
||||
var v = 254;
|
||||
if (fmt === "do") {
|
||||
fmt = "dsk";
|
||||
if (fmt === 'do') {
|
||||
fmt = 'dsk';
|
||||
}
|
||||
_cur.readOnly = false;
|
||||
if (fmt === "2mg") {
|
||||
if (fmt === '2mg') {
|
||||
// Standard header size is 64 bytes. Make assumptions.
|
||||
var prefix = new Uint8Array(data.slice(0, 64));
|
||||
data = data.slice(64);
|
||||
|
||||
|
||||
// Check image format.
|
||||
// Sure, it's really 64 bits. But only 2 are actually used.
|
||||
switch (prefix[0xc]) {
|
||||
case 0:
|
||||
fmt = "dsk";
|
||||
fmt = 'dsk';
|
||||
break;
|
||||
case 1:
|
||||
fmt = "po";
|
||||
fmt = 'po';
|
||||
break;
|
||||
case 2:
|
||||
fmt = "nib";
|
||||
fmt = 'nib';
|
||||
break;
|
||||
default: // Something hinky, assume "dsk"
|
||||
fmt = "dsk";
|
||||
default: // Something hinky, assume 'dsk'
|
||||
fmt = 'dsk';
|
||||
break;
|
||||
}
|
||||
var flags =
|
||||
var flags =
|
||||
prefix[0x10] | (prefix[0x11] << 8) |
|
||||
(prefix[0x12] << 16) | (prefix[0x13] << 24);
|
||||
_cur.readOnly = (flags & 0x80000000) ? true : false;
|
||||
@ -749,20 +750,20 @@ function DiskII(io, callbacks, slot)
|
||||
}
|
||||
for (var t = 0; t < 35; t++) {
|
||||
var track, off, d;
|
||||
if (fmt === "nib") {
|
||||
if (fmt === 'nib') {
|
||||
off = t * 0x1a00;
|
||||
track = new Uint8Array(data.slice(off, off + 0x1a00));
|
||||
} else {
|
||||
track = [];
|
||||
for (var s = 0; s < 16; s++) {
|
||||
var _s = 15 - s;
|
||||
if (fmt == "po") { // ProDOS Order
|
||||
off = (16 * t + s) * 256;
|
||||
if (fmt == 'po') { // ProDOS Order
|
||||
off = (16 * t + s) * 256;
|
||||
d = new Uint8Array(data.slice(off, off + 256));
|
||||
extend(track,
|
||||
_explodeSector(v, t, _PO[s], d));
|
||||
} else if (fmt == "dsk") { // DOS Order
|
||||
off = (16 * t + _s) * 256;
|
||||
} else if (fmt == 'dsk') { // DOS Order
|
||||
off = (16 * t + _s) * 256;
|
||||
d = new Uint8Array(data.slice(off, off + 256));
|
||||
extend(track,
|
||||
_explodeSector(v, t, _DO[_s], d));
|
||||
@ -786,9 +787,9 @@ function DiskII(io, callbacks, slot)
|
||||
var len = (16 * cur.tracks.length * 256);
|
||||
var data = new Uint8Array(len);
|
||||
var idx = 0;
|
||||
|
||||
|
||||
for (var t = 0; t < cur.tracks.length; t++) {
|
||||
if (cur.format === "nib") {
|
||||
if (cur.format === 'nib') {
|
||||
data[idx++] = cur.tracks[t];
|
||||
} else {
|
||||
for (var s = 0; s < 0x10; s++) {
|
||||
@ -808,7 +809,7 @@ function DiskII(io, callbacks, slot)
|
||||
var data = [];
|
||||
for (var t = 0; t < cur.tracks.length; t++) {
|
||||
data[t] = [];
|
||||
if (cur.format === "nib") {
|
||||
if (cur.format === 'nib') {
|
||||
data += base64_encode(cur.tracks[t]);
|
||||
} else {
|
||||
for (var s = 0; s < 0x10; s++) {
|
||||
|
@ -1,5 +1,3 @@
|
||||
/* -*- mode: JavaScript; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/*global bytify:false */
|
||||
/*exported Apple2ROM */
|
||||
function Apple2ROM()
|
||||
{
|
||||
@ -1542,8 +1540,6 @@ function Apple2ROM()
|
||||
0xf5,0x03,0xfb,0x03,0x62,0xfa,0x59,0xff
|
||||
];
|
||||
|
||||
rom = bytify(rom);
|
||||
|
||||
return {
|
||||
start: function() {
|
||||
return 0xd0;
|
||||
|
@ -1,10 +1,10 @@
|
||||
/* -*- mode: JavaScript; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/*exported IntBASIC */
|
||||
|
||||
function IntBASIC()
|
||||
{
|
||||
var rom = [
|
||||
0xa9,0x20,0x8d,0x26,0x03,0xad,0x57,0xc0,
|
||||
0xad,0x53,0xc0,0xad,0x50,0xc0,0xa9,0x00,
|
||||
var rom = [
|
||||
0xa9,0x20,0x8d,0x26,0x03,0xad,0x57,0xc0,
|
||||
0xad,0x53,0xc0,0xad,0x50,0xc0,0xa9,0x00,
|
||||
0x85,0x1c,0xad,0x26,0x03,0x85,0x1b,0xa0,
|
||||
0x00,0x84,0x1a,0xa5,0x1c,0x91,0x1a,0x20,
|
||||
0xa2,0xd0,0xc8,0xd0,0xf6,0xe6,0x1b,0xa5,
|
||||
@ -1551,8 +1551,7 @@ function IntBASIC()
|
||||
read: function(page, off) {
|
||||
return rom[((page - 0xD0) << 8) + off];
|
||||
},
|
||||
write: function(page, off, val) {
|
||||
write: function() {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,4 @@
|
||||
/* -*- mode: JavaScript; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* Copyright 2010-2013 Will Scullin <scullin@scullinsteel.com>
|
||||
/* Copyright 2010-2016 Will Scullin <scullin@scullinsteel.com>
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software and its
|
||||
* documentation for any purpose is hereby granted without fee, provided that
|
||||
@ -10,10 +9,12 @@
|
||||
* implied warranty.
|
||||
*/
|
||||
|
||||
/*globals RAM */
|
||||
/*exported LanguageCard */
|
||||
/*globals RAM: false */
|
||||
|
||||
function LanguageCard(io, rom) {
|
||||
'use strict';
|
||||
|
||||
var _io = io;
|
||||
var _rom = rom;
|
||||
var _bank1 = null;
|
||||
@ -88,28 +89,28 @@ function LanguageCard(io, rom) {
|
||||
_readbsr = true;
|
||||
_writebsr = false;
|
||||
_bsr2 = true;
|
||||
_debug("Bank 2 Read");
|
||||
_debug('Bank 2 Read');
|
||||
break;
|
||||
case LOC.WRITEBSR2:
|
||||
case LOC._WRITEBSR2:
|
||||
_readbsr = false;
|
||||
_writebsr = ((_last & 0xF3) == (off & 0xF3));
|
||||
_bsr2 = true;
|
||||
_debug("Bank 2 Write");
|
||||
_debug('Bank 2 Write');
|
||||
break;
|
||||
case LOC.OFFBSR2:
|
||||
case LOC._OFFBSR2:
|
||||
_readbsr = false;
|
||||
_writebsr = false;
|
||||
_bsr2 = true;
|
||||
_debug("Bank 2 Off");
|
||||
_debug('Bank 2 Off');
|
||||
break;
|
||||
case LOC.READWRBSR2:
|
||||
case LOC._READWRBSR2:
|
||||
case LOC._READWRBSR2:
|
||||
_readbsr = true;
|
||||
_writebsr = ((_last & 0xF3) == (off & 0xF3));
|
||||
_bsr2 = true;
|
||||
_debug("Bank 2 Read/Write");
|
||||
_debug('Bank 2 Read/Write');
|
||||
break;
|
||||
|
||||
case LOC.READBSR1:
|
||||
@ -117,37 +118,37 @@ function LanguageCard(io, rom) {
|
||||
_readbsr = true;
|
||||
_writebsr = false;
|
||||
_bsr2 = false;
|
||||
_debug("Bank 1 Read");
|
||||
_debug('Bank 1 Read');
|
||||
break;
|
||||
case LOC.WRITEBSR1:
|
||||
case LOC._WRITEBSR1:
|
||||
_readbsr = false;
|
||||
_writebsr = ((_last & 0xF3) == (off & 0xF3));
|
||||
_bsr2 = false;
|
||||
_debug("Bank 1 Write");
|
||||
_debug('Bank 1 Write');
|
||||
break;
|
||||
case LOC.OFFBSR1:
|
||||
case LOC._OFFBSR1:
|
||||
_readbsr = false;
|
||||
_writebsr = false;
|
||||
_bsr2 = false;
|
||||
_debug("Bank 1 Off");
|
||||
_debug('Bank 1 Off');
|
||||
break;
|
||||
case LOC.READWRBSR1:
|
||||
case LOC._READWRBSR1:
|
||||
_readbsr = true;
|
||||
_writebsr = ((_last & 0xF3) == (off & 0xF3));
|
||||
_bsr2 = false;
|
||||
_debug("Bank 1 Read/Write");
|
||||
_debug('Bank 1 Read/Write');
|
||||
break;
|
||||
|
||||
|
||||
case LOC.BSRBANK2:
|
||||
result = _bsr2 ? 0x80 : 0x00;
|
||||
_debug("Bank 2 Read " + _bsr2);
|
||||
result = _bsr2 ? 0x80 : 0x00;
|
||||
_debug('Bank 2 Read ' + _bsr2);
|
||||
break;
|
||||
case LOC.BSRREADRAM:
|
||||
result = _readbsr ? 0x80 : 0x00;
|
||||
_debug("Bank SW RAM Read " + _readbsr);
|
||||
_debug('Bank SW RAM Read ' + _readbsr);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
876
js/main2.js
Normal file
876
js/main2.js
Normal file
@ -0,0 +1,876 @@
|
||||
/* globals debug: false, gup: false, hup: false
|
||||
CPU6502: false,
|
||||
RAM: false,
|
||||
Apple2ROM: false
|
||||
apple2_charset: false,
|
||||
Apple2IO: false
|
||||
LoresPage: false, HiresPage: false, VideoModes: false
|
||||
KeyBoard: false,
|
||||
Parallel: false,
|
||||
DiskII: false,
|
||||
RAMFactor: false,
|
||||
Printer: false,
|
||||
LanguageCard: false,
|
||||
Thunderclock: false,
|
||||
Prefs: false,
|
||||
disk_index: false,
|
||||
initAudio: false, enableSound: false,
|
||||
initGamepad: false, processGamepad: false, gamepad: false,
|
||||
ApplesoftDump: false
|
||||
*/
|
||||
/* exported openLoad, openSave, doDelete,
|
||||
selectCategory, selectDisk, clickDisk, loadJSON,
|
||||
updateJoystick,
|
||||
pauseRun, step
|
||||
dumpProgram, PageDebug
|
||||
*/
|
||||
|
||||
var kHz = 1023;
|
||||
|
||||
var focused = false;
|
||||
var startTime = Date.now();
|
||||
var lastCycles = 0;
|
||||
var renderedFrames = 0, lastFrames = 0;
|
||||
var paused = false;
|
||||
|
||||
var hashtag;
|
||||
|
||||
var disk_categories = {'Local Saves': []};
|
||||
var disk_sets = {};
|
||||
var disk_cur_name = [];
|
||||
var disk_cur_cat = [];
|
||||
|
||||
function DriveLights()
|
||||
{
|
||||
return {
|
||||
driveLight: function(drive, on) {
|
||||
$('#disk' + drive).css('background-image',
|
||||
on ? 'url(css/red-on-16.png)' :
|
||||
'url(css/red-off-16.png)');
|
||||
},
|
||||
dirty: function(drive, dirty) {
|
||||
$('#disksave' + drive).button('option', 'disabled', !dirty);
|
||||
},
|
||||
label: function(drive, label) {
|
||||
if (label) {
|
||||
$('#disklabel' + drive).text(label);
|
||||
}
|
||||
return $('#disklabel' + drive).text();
|
||||
},
|
||||
getState: function() {
|
||||
return {
|
||||
disks: [
|
||||
this.label(1),
|
||||
this.label(2)
|
||||
]
|
||||
};
|
||||
},
|
||||
setState: function(state) {
|
||||
if (state && state.disks) {
|
||||
this.label(1, state.disks[0].label);
|
||||
this.label(2, state.disks[1].label);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
var DISK_TYPES = ['dsk','do','po','raw','nib','2mg'];
|
||||
var TAPE_TYPES = ['wav','aiff','aif','mp3'];
|
||||
|
||||
var _saveDrive = 1;
|
||||
var _loadDrive = 1;
|
||||
|
||||
function openLoad(drive, event)
|
||||
{
|
||||
_loadDrive = drive;
|
||||
if (event.metaKey) {
|
||||
openLoadHTTP(drive);
|
||||
} else {
|
||||
if (disk_cur_cat[drive]) {
|
||||
$('#category_select').val(disk_cur_cat[drive]).change();
|
||||
}
|
||||
$('#load').dialog('open');
|
||||
}
|
||||
}
|
||||
|
||||
function openSave(drive, event)
|
||||
{
|
||||
_saveDrive = drive;
|
||||
if (event.metaKey) {
|
||||
dumpDisk(drive);
|
||||
} else if (event.altKey) {
|
||||
openSaveLocal(drive);
|
||||
} else {
|
||||
$('#save_name').val(drivelights.label(drive));
|
||||
$('#save').dialog('open');
|
||||
}
|
||||
}
|
||||
|
||||
var loading = false;
|
||||
|
||||
function loadAjax(url) {
|
||||
loading = true;
|
||||
$('#loading').dialog('open');
|
||||
|
||||
$.ajax({ url: url,
|
||||
cache: false,
|
||||
dataType: 'jsonp',
|
||||
jsonp: false,
|
||||
global: false
|
||||
});
|
||||
}
|
||||
|
||||
function doLoad() {
|
||||
var urls = $('#disk_select').val(), url;
|
||||
if (urls && urls.length) {
|
||||
if (typeof(urls) == 'string') {
|
||||
url = urls;
|
||||
} else {
|
||||
url = urls[0];
|
||||
}
|
||||
}
|
||||
|
||||
var files = $('#local_file').prop('files');
|
||||
if (files.length == 1) {
|
||||
doLoadLocal();
|
||||
} else if (url) {
|
||||
var filename;
|
||||
$('#load').dialog('close');
|
||||
if (url.substr(0,6) == 'local:') {
|
||||
filename = url.substr(6);
|
||||
if (filename == '__manage') {
|
||||
openManage();
|
||||
} else {
|
||||
loadLocalStorage(_loadDrive, filename);
|
||||
}
|
||||
} else {
|
||||
var r1 = /json\/disks\/(.*).json$/.exec(url);
|
||||
if (r1 && _loadDrive == 1) {
|
||||
filename = r1[1];
|
||||
document.location.hash = filename;
|
||||
}
|
||||
loadAjax(url);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function doSave() {
|
||||
var name = $('#save_name').val();
|
||||
saveLocalStorage(_saveDrive, name);
|
||||
$('#save').dialog('close');
|
||||
}
|
||||
|
||||
function doDelete(name) {
|
||||
if (window.confirm('Delete ' + name + '?')) {
|
||||
deleteLocalStorage(name);
|
||||
}
|
||||
}
|
||||
|
||||
function doLoadLocal() {
|
||||
var files = $('#local_file').prop('files');
|
||||
if (files.length == 1) {
|
||||
var file = files[0];
|
||||
var parts = file.name.split('.');
|
||||
var ext = parts[parts.length - 1].toLowerCase();
|
||||
if ($.inArray(ext, DISK_TYPES) >= 0) {
|
||||
doLoadLocalDisk(file);
|
||||
} else if ($.inArray(ext, TAPE_TYPES) >= 0) {
|
||||
doLoadLocalTape(file);
|
||||
} else {
|
||||
window.alert('Unknown file type: ' + ext);
|
||||
$('#load').dialog('close');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function doLoadLocalDisk(file) {
|
||||
var fileReader = new FileReader();
|
||||
fileReader.onload = function() {
|
||||
var parts = file.name.split('.');
|
||||
var name = parts[0], ext = parts[parts.length - 1].toLowerCase();
|
||||
if (disk2.setBinary(_saveDrive, name, ext, this.result)) {
|
||||
drivelights.label(_saveDrive, name);
|
||||
$('#load').dialog('close');
|
||||
initGamepad();
|
||||
}
|
||||
};
|
||||
fileReader.readAsArrayBuffer(file);
|
||||
}
|
||||
|
||||
function doLoadLocalTape(file) {
|
||||
// Audio Buffer Source
|
||||
var context;
|
||||
if (typeof window.AudioContext != 'undefined') {
|
||||
context = new window.AudioContext();
|
||||
} else {
|
||||
window.alert('Not supported by your browser');
|
||||
$('#load').dialog('close');
|
||||
return;
|
||||
}
|
||||
|
||||
var fileReader = new FileReader();
|
||||
fileReader.onload = function(ev) {
|
||||
context.decodeAudioData(ev.target.result, function(buffer) {
|
||||
var buf = [];
|
||||
var data = buffer.getChannelData(0), datum = data[0];
|
||||
var old = (datum > 0.0), current;
|
||||
var last = 0, delta, ival;
|
||||
debug('Sample Count: ' + data.length);
|
||||
debug('Sample rate: ' + buffer.sampleRate);
|
||||
for (var idx = 1; idx < data.length; idx++) {
|
||||
datum = data[idx];
|
||||
if ((datum > 0.1) || (datum < -0.1)) {
|
||||
current = (datum > 0.0);
|
||||
if (current != old) {
|
||||
delta = idx - last;
|
||||
if (delta > 2000000) {
|
||||
delta = 2000000;
|
||||
}
|
||||
ival = delta / buffer.sampleRate * 1000;
|
||||
if (ival >= 0.550 && ival < 0.750) {
|
||||
ival = 0.650; // Header
|
||||
} else if (ival >= 0.175 && ival < 0.225) {
|
||||
ival = 0.200; // sync 1
|
||||
} else if (ival >= 0.225 && ival < 0.275) {
|
||||
ival = 0.250; // 0 / sync 2
|
||||
} else if (ival >= 0.450 && ival < 0.550) {
|
||||
ival = 0.500; // 1
|
||||
} else {
|
||||
// debug(idx + ' ' + buf.length + ' ' + ival);
|
||||
}
|
||||
buf.push(parseInt(ival * kHz));
|
||||
old = current;
|
||||
last = idx;
|
||||
}
|
||||
}
|
||||
}
|
||||
io.setTape(buf);
|
||||
$('#load').dialog('close');
|
||||
});
|
||||
};
|
||||
fileReader.readAsArrayBuffer(file);
|
||||
}
|
||||
|
||||
function doLoadHTTP(_url) {
|
||||
var url = _url || $('#http_url').val();
|
||||
if (url) {
|
||||
var req = new XMLHttpRequest();
|
||||
req.open('GET', url, true);
|
||||
req.responseType = 'arraybuffer';
|
||||
|
||||
req.onload = function() {
|
||||
var parts = url.split(/[\/\.]/);
|
||||
var name = decodeURIComponent(parts[parts.length - 2]);
|
||||
var ext = parts[parts.length - 1].toLowerCase();
|
||||
if (disk2.setBinary(_saveDrive, name, ext, req.response)) {
|
||||
drivelights.label(_saveDrive, name);
|
||||
$('#http_load').dialog('close');
|
||||
initGamepad();
|
||||
}
|
||||
};
|
||||
req.send(null);
|
||||
}
|
||||
}
|
||||
|
||||
function openLoadHTTP(drive) {
|
||||
_saveDrive = drive;
|
||||
$('#http_load').dialog('open');
|
||||
}
|
||||
|
||||
function openSaveLocal(drive) {
|
||||
_saveDrive = drive;
|
||||
var mimetype = 'application/octet-stream';
|
||||
var data = disk2.getBinary(drive);
|
||||
var a = $('#local_save_link');
|
||||
|
||||
var blob = new Blob([data], { 'type': mimetype });
|
||||
a.attr('href', window.URL.createObjectURL(blob));
|
||||
a.attr('download', drivelights.label(drive) + '.dsk');
|
||||
|
||||
$('#local_save').dialog('open');
|
||||
}
|
||||
|
||||
function openManage() {
|
||||
$('#manage').dialog('open');
|
||||
}
|
||||
|
||||
var prefs = new Prefs();
|
||||
var runTimer = null;
|
||||
var cpu = new CPU6502();
|
||||
|
||||
var ram1 = new RAM(0x00, 0x03),
|
||||
ram2 = new RAM(0x0C, 0x1F),
|
||||
ram3 = new RAM(0x60, 0xBF);
|
||||
|
||||
var hgr = new HiresPage(1);
|
||||
var hgr2 = new HiresPage(2);
|
||||
var gr = new LoresPage(1, apple2_charset);
|
||||
var gr2 = new LoresPage(2, apple2_charset);
|
||||
|
||||
var rom = new Apple2ROM();
|
||||
var dumper = new ApplesoftDump(ram2);
|
||||
var vm = new VideoModes(gr, hgr, gr2, hgr2);
|
||||
var mmu = {
|
||||
auxRom: function(slot, rom) {
|
||||
cpu.addPageHandler(rom);
|
||||
}
|
||||
};
|
||||
|
||||
var drivelights = new DriveLights();
|
||||
var io = new Apple2IO(cpu, vm);
|
||||
var keyboard = new KeyBoard(io);
|
||||
var parallel = new Parallel(io, new Printer(), 1);
|
||||
var disk2 = new DiskII(io, drivelights, 6);
|
||||
var slinky = new RAMFactor(mmu, io, 2, 1024 * 1024);
|
||||
var clock = new Thunderclock(mmu, io, 7);
|
||||
var lc = new LanguageCard(io, rom);
|
||||
|
||||
cpu.addPageHandler(ram1);
|
||||
cpu.addPageHandler(gr);
|
||||
cpu.addPageHandler(gr2);
|
||||
cpu.addPageHandler(ram2);
|
||||
cpu.addPageHandler(hgr);
|
||||
cpu.addPageHandler(hgr2);
|
||||
cpu.addPageHandler(ram3);
|
||||
|
||||
cpu.addPageHandler(lc);
|
||||
cpu.addPageHandler(io);
|
||||
cpu.addPageHandler(parallel);
|
||||
cpu.addPageHandler(slinky);
|
||||
cpu.addPageHandler(disk2);
|
||||
cpu.addPageHandler(clock);
|
||||
|
||||
var showFPS = false;
|
||||
|
||||
function updateKHz() {
|
||||
var now = Date.now();
|
||||
var ms = now - startTime;
|
||||
var cycles = cpu.cycles();
|
||||
var delta;
|
||||
|
||||
if (showFPS) {
|
||||
delta = renderedFrames - lastFrames;
|
||||
var fps = parseInt(delta/(ms/1000), 10);
|
||||
$('#khz').text( fps + 'fps');
|
||||
} else {
|
||||
delta = cycles - lastCycles;
|
||||
var khz = parseInt(delta/ms);
|
||||
$('#khz').text( khz + 'KHz');
|
||||
}
|
||||
|
||||
startTime = now;
|
||||
lastCycles = cycles;
|
||||
lastFrames = renderedFrames;
|
||||
}
|
||||
|
||||
/* Audio Handling */
|
||||
initAudio(io);
|
||||
|
||||
function updateSound() {
|
||||
enableSound($('#enable_sound').attr('checked'));
|
||||
}
|
||||
|
||||
function dumpDisk(drive) {
|
||||
var wind = window.open('', '_blank');
|
||||
wind.document.title = drivelights.label(drive);
|
||||
wind.document.write('<pre>');
|
||||
wind.document.write(disk2.getJSON(drive, true));
|
||||
wind.document.write('</pre>');
|
||||
wind.document.close();
|
||||
}
|
||||
|
||||
function dumpProgram() {
|
||||
var wind = window.open('', '_blank');
|
||||
wind.document.title = 'Program Listing';
|
||||
wind.document.write('<pre>');
|
||||
wind.document.write(dumper.toString());
|
||||
wind.document.write('</pre>');
|
||||
wind.document.close();
|
||||
}
|
||||
|
||||
function step()
|
||||
{
|
||||
if (runTimer) {
|
||||
clearInterval(runTimer);
|
||||
}
|
||||
runTimer = null;
|
||||
|
||||
cpu.step(function() {
|
||||
debug(cpu.dumpRegisters());
|
||||
debug(cpu.dumpPC());
|
||||
});
|
||||
}
|
||||
|
||||
var accelerated = false;
|
||||
|
||||
function updateSpeed()
|
||||
{
|
||||
accelerated = $('#accelerator_toggle').prop('checked');
|
||||
kHz = accelerated ? 4092 : 1023;
|
||||
io.updateHz(kHz * 1000);
|
||||
if (runTimer) {
|
||||
run();
|
||||
}
|
||||
}
|
||||
|
||||
var _requestAnimationFrame =
|
||||
window.requestAnimationFrame ||
|
||||
window.mozRequestAnimationFrame ||
|
||||
window.webkitRequestAnimationFrame ||
|
||||
window.msRequestAnimationFrame;
|
||||
|
||||
function run(pc) {
|
||||
if (runTimer) {
|
||||
clearInterval(runTimer);
|
||||
}
|
||||
|
||||
if (pc) {
|
||||
cpu.setPC(pc);
|
||||
}
|
||||
|
||||
var ival = 30;
|
||||
var now, last = Date.now();
|
||||
var runFn = function() {
|
||||
now = Date.now();
|
||||
renderedFrames++;
|
||||
|
||||
var step = (now - last) * kHz, stepMax = kHz * ival;
|
||||
last = now;
|
||||
if (step > stepMax) {
|
||||
step = stepMax;
|
||||
}
|
||||
|
||||
if (document.location.hash != hashtag) {
|
||||
hashtag = document.location.hash;
|
||||
var hash = hup();
|
||||
if (hash) {
|
||||
processHash(hash);
|
||||
}
|
||||
}
|
||||
|
||||
if (!loading) {
|
||||
cpu.stepCycles(step);
|
||||
vm.blit();
|
||||
io.sampleTick();
|
||||
}
|
||||
|
||||
processGamepad(io);
|
||||
|
||||
if (!paused && _requestAnimationFrame) {
|
||||
_requestAnimationFrame(runFn);
|
||||
}
|
||||
};
|
||||
if (_requestAnimationFrame) {
|
||||
_requestAnimationFrame(runFn);
|
||||
} else {
|
||||
runTimer = setInterval(runFn, ival);
|
||||
}
|
||||
}
|
||||
|
||||
function stop() {
|
||||
if (runTimer) {
|
||||
clearInterval(runTimer);
|
||||
}
|
||||
runTimer = null;
|
||||
}
|
||||
|
||||
function reset()
|
||||
{
|
||||
cpu.reset();
|
||||
}
|
||||
|
||||
function loadBinary(bin) {
|
||||
stop();
|
||||
for (var idx = 0; idx < bin.length; idx++) {
|
||||
var pos = bin.start + idx;
|
||||
cpu.write(pos >> 8, pos & 0xff, bin.data[idx]);
|
||||
}
|
||||
run(bin.start);
|
||||
}
|
||||
|
||||
function selectCategory() {
|
||||
$('#disk_select').empty();
|
||||
var cat = disk_categories[$('#category_select').val()];
|
||||
if (cat) {
|
||||
for (var idx = 0; idx < cat.length; idx++) {
|
||||
var file = cat[idx], name = file.name;
|
||||
if (file.disk) {
|
||||
name += ' - ' + file.disk;
|
||||
}
|
||||
var option = $('<option />').val(file.filename).text(name)
|
||||
.appendTo('#disk_select');
|
||||
if (disk_cur_name[_loadDrive] == name) {
|
||||
option.attr('selected', 'selected');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function selectDisk() {
|
||||
$('#local_file').val('');
|
||||
}
|
||||
|
||||
function clickDisk() {
|
||||
doLoad();
|
||||
}
|
||||
|
||||
function loadDisk(disk) {
|
||||
var name = disk.name;
|
||||
var category = disk.category;
|
||||
|
||||
if (disk.disk) {
|
||||
name += ' - ' + disk.disk;
|
||||
}
|
||||
|
||||
disk_cur_cat[_loadDrive] = category;
|
||||
disk_cur_name[_loadDrive] = name;
|
||||
|
||||
drivelights.label(_loadDrive, name);
|
||||
disk2.setDisk(_loadDrive, disk);
|
||||
initGamepad(disk.gamepad);
|
||||
}
|
||||
|
||||
function loadJSON(data) {
|
||||
if (data.type == 'binary') {
|
||||
loadBinary(data);
|
||||
} else if ($.inArray(data.type, DISK_TYPES) >= 0) {
|
||||
loadDisk(data);
|
||||
}
|
||||
initGamepad(data.gamepad);
|
||||
$('#loading').dialog('close');
|
||||
loading = false;
|
||||
}
|
||||
|
||||
/*
|
||||
* LocalStorage Disk Storage
|
||||
*/
|
||||
|
||||
function updateLocalStorage() {
|
||||
var diskIndex = JSON.parse(window.localStorage.diskIndex || '{}');
|
||||
var names = [], name, cat;
|
||||
|
||||
for (name in diskIndex) {
|
||||
if (diskIndex.hasOwnProperty(name)) {
|
||||
names.push(name);
|
||||
}
|
||||
}
|
||||
|
||||
cat = disk_categories['Local Saves'] = [];
|
||||
$('#manage').empty();
|
||||
|
||||
names.forEach(function(name) {
|
||||
cat.push({'category': 'Local Saves',
|
||||
'name': name,
|
||||
'filename': 'local:' + name});
|
||||
$('#manage').append('<span class="local_save">' +
|
||||
name +
|
||||
' <a href="#" onclick="doDelete(\'' +
|
||||
name +
|
||||
'\')">Delete</a><br /></span>');
|
||||
});
|
||||
cat.push({'category': 'Local Saves',
|
||||
'name': 'Manage Saves...',
|
||||
'filename': 'local:__manage'});
|
||||
}
|
||||
|
||||
function saveLocalStorage(drive, name) {
|
||||
var diskIndex = JSON.parse(window.localStorage.diskIndex || '{}');
|
||||
|
||||
var json = disk2.getJSON(drive);
|
||||
diskIndex[name] = json;
|
||||
|
||||
window.localStorage.diskIndex = JSON.stringify(diskIndex);
|
||||
|
||||
window.alert('Saved');
|
||||
|
||||
drivelights.label(drive, name);
|
||||
drivelights.dirty(drive, false);
|
||||
updateLocalStorage();
|
||||
}
|
||||
|
||||
function deleteLocalStorage(name) {
|
||||
var diskIndex = JSON.parse(window.localStorage.diskIndex || '{}');
|
||||
if (diskIndex[name]) {
|
||||
delete diskIndex[name];
|
||||
window.alert('Deleted');
|
||||
}
|
||||
window.localStorage.diskIndex = JSON.stringify(diskIndex);
|
||||
updateLocalStorage();
|
||||
}
|
||||
|
||||
function loadLocalStorage(drive, name) {
|
||||
var diskIndex = JSON.parse(window.localStorage.diskIndex || '{}');
|
||||
if (diskIndex[name]) {
|
||||
disk2.setJSON(drive, diskIndex[name]);
|
||||
drivelights.label(drive, name);
|
||||
drivelights.dirty(drive, false);
|
||||
}
|
||||
}
|
||||
|
||||
function processHash(hash) {
|
||||
if (hash.indexOf('://') > 0) {
|
||||
var parts = hash.split('.');
|
||||
var ext = parts[parts.length - 1].toLowerCase();
|
||||
if (ext == 'json') {
|
||||
loadAjax(hash);
|
||||
} else {
|
||||
doLoadHTTP(hash);
|
||||
}
|
||||
} else {
|
||||
loadAjax('json/disks/' + hash + '.json');
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Keyboard/Gamepad routines
|
||||
*/
|
||||
|
||||
function _keydown(evt) {
|
||||
if (evt.keyCode === 112) { // F1 - Reset
|
||||
cpu.reset();
|
||||
} else if (evt.keyCode === 113) { // F2 - Full Screen
|
||||
var elem = document.getElementById('screen');
|
||||
if (document.webkitCancelFullScreen) {
|
||||
if (document.webkitIsFullScreen) {
|
||||
document.webkitCancelFullScreen();
|
||||
} else {
|
||||
if (Element.ALLOW_KEYBOARD_INPUT) {
|
||||
elem.webkitRequestFullScreen(Element.ALLOW_KEYBOARD_INPUT);
|
||||
} else {
|
||||
elem.webkitRequestFullScreen();
|
||||
}
|
||||
}
|
||||
} else if (document.mozCancelFullScreen) {
|
||||
if (document.mozIsFullScreen) {
|
||||
document.mozCancelFullScreen();
|
||||
} else {
|
||||
elem.mozRequestFullScreen();
|
||||
}
|
||||
}
|
||||
} else if (evt.keyCode == 16) { // Shift
|
||||
keyboard.shiftKey(true);
|
||||
io.buttonDown(2);
|
||||
} else if (evt.keyCode == 17) { // Control
|
||||
keyboard.controlKey(true);
|
||||
} else if (!focused && (!evt.metaKey || evt.ctrlKey)) {
|
||||
evt.preventDefault();
|
||||
|
||||
var key = keyboard.mapKeyEvent(evt);
|
||||
if (key != 0xff) {
|
||||
io.keyDown(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function _keyup(evt) {
|
||||
if (evt.keyCode == 16) { // Shift
|
||||
keyboard.shiftKey(false);
|
||||
io.buttonUp(2);
|
||||
} else if (evt.keyCode == 17) { // Control
|
||||
keyboard.controlKey(false);
|
||||
} else {
|
||||
if (!focused) {
|
||||
io.keyUp();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function updateScreen() {
|
||||
var green = $('#green_screen').prop('checked');
|
||||
|
||||
vm.green(green);
|
||||
}
|
||||
|
||||
var disableMouseJoystick = false;
|
||||
var flipX = false;
|
||||
var flipY = false;
|
||||
var swapXY = false;
|
||||
|
||||
function updateJoystick() {
|
||||
disableMouseJoystick = $('#disable_mouse').prop('checked');
|
||||
flipX = $('#flip_x').prop('checked');
|
||||
flipY = $('#flip_y').prop('checked');
|
||||
swapXY = $('#swap_x_y').prop('checked');
|
||||
|
||||
if (disableMouseJoystick) {
|
||||
io.paddle(0, 0.5);
|
||||
io.paddle(1, 0.5);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
function _mousemove(evt) {
|
||||
if (gamepad || disableMouseJoystick) {
|
||||
return;
|
||||
}
|
||||
|
||||
var s = $('#screen');
|
||||
var offset = s.offset();
|
||||
var x = (evt.pageX - offset.left) / s.width(),
|
||||
y = (evt.pageY - offset.top) / s.height(),
|
||||
z = x;
|
||||
|
||||
if (swapXY) {
|
||||
x = y;
|
||||
y = z;
|
||||
}
|
||||
|
||||
io.paddle(0, flipX ? 1 - x : x);
|
||||
io.paddle(1, flipY ? 1 - y : y);
|
||||
}
|
||||
|
||||
function pauseRun(b) {
|
||||
if (paused) {
|
||||
run();
|
||||
b.value = 'Pause';
|
||||
} else {
|
||||
stop();
|
||||
b.value = 'Run';
|
||||
}
|
||||
paused = !paused;
|
||||
}
|
||||
|
||||
$(function() {
|
||||
hashtag = document.location.hash;
|
||||
|
||||
$('button,input[type=button],a.button').button().focus(function() {
|
||||
// Crazy hack required by Chrome
|
||||
var self = this;
|
||||
window.setTimeout(function() {
|
||||
self.blur();
|
||||
}, 1);
|
||||
});
|
||||
|
||||
var canvas = document.getElementById('screen');
|
||||
var context = canvas.getContext('2d');
|
||||
|
||||
vm.setContext(context);
|
||||
|
||||
/*
|
||||
* Input Handling
|
||||
*/
|
||||
|
||||
$(window).keydown(_keydown);
|
||||
$(window).keyup(_keyup);
|
||||
|
||||
$('canvas').mousedown(function(evt) {
|
||||
if (!gamepad) {
|
||||
io.buttonDown(evt.which == 1 ? 0 : 1);
|
||||
}
|
||||
evt.preventDefault();
|
||||
})
|
||||
.mouseup(function(evt) {
|
||||
if (!gamepad) {
|
||||
io.buttonUp(evt.which == 1 ? 0 : 1);
|
||||
}
|
||||
})
|
||||
.bind('contextmenu', function(evt) { evt.preventDefault(); });
|
||||
|
||||
$('body').mousemove(_mousemove);
|
||||
|
||||
$('input,textarea').focus(function() { focused = true; })
|
||||
.blur(function() { focused = false; });
|
||||
|
||||
keyboard.create($('#keyboard'));
|
||||
|
||||
if (prefs.havePrefs()) {
|
||||
$('input[type=checkbox]').each(function() {
|
||||
var val = prefs.readPref(this.id);
|
||||
if (val)
|
||||
this.checked = JSON.parse(val);
|
||||
}).change(function() {
|
||||
prefs.writePref(this.id, JSON.stringify(this.checked));
|
||||
});
|
||||
}
|
||||
|
||||
reset();
|
||||
run();
|
||||
setInterval(updateKHz, 1000);
|
||||
updateSound();
|
||||
updateScreen();
|
||||
updateSpeed();
|
||||
|
||||
var cancel = function() { $(this).dialog('close'); };
|
||||
$('#loading').dialog({ autoOpen: false, modal: true });
|
||||
$('#options').dialog({ autoOpen: false,
|
||||
modal: true,
|
||||
width: 320,
|
||||
height: 400,
|
||||
buttons: {'Close': cancel }});
|
||||
$('#load').dialog({ autoOpen: false,
|
||||
modal: true,
|
||||
width: 540,
|
||||
buttons: {'Cancel': cancel, 'Load': doLoad }});
|
||||
$('#save').dialog({ autoOpen: false,
|
||||
modal: true,
|
||||
width: 320,
|
||||
buttons: {'Cancel': cancel, 'Save': doSave }});
|
||||
$('#manage').dialog({ autoOpen: false,
|
||||
modal: true,
|
||||
width: 320,
|
||||
buttons: {'Close': cancel }});
|
||||
$('#local_save').dialog({ autoOpen: false,
|
||||
modal: true,
|
||||
width: 530,
|
||||
buttons: {'OK': cancel }});
|
||||
$('#http_load').dialog({ autoOpen: false,
|
||||
modal: true,
|
||||
width: 530,
|
||||
buttons: {'Cancel': cancel, 'OK': doLoadHTTP }});
|
||||
|
||||
if (window.localStorage !== undefined) {
|
||||
$('.disksave').show();
|
||||
}
|
||||
|
||||
var oldcat = '';
|
||||
for (var idx = 0; idx < disk_index.length; idx++) {
|
||||
var file = disk_index[idx];
|
||||
var cat = file.category;
|
||||
var name = file.name, disk = file.disk;
|
||||
if (file.e) {
|
||||
continue;
|
||||
}
|
||||
if (cat != oldcat) {
|
||||
$('<option />').val(cat).text(cat).appendTo('#category_select');
|
||||
disk_categories[cat] = [];
|
||||
oldcat = cat;
|
||||
}
|
||||
disk_categories[cat].push(file);
|
||||
if (disk) {
|
||||
if (!disk_sets[name]) {
|
||||
disk_sets[name] = [];
|
||||
}
|
||||
disk_sets[name].push(file);
|
||||
}
|
||||
}
|
||||
$('<option/>').text('Local Saves').appendTo('#category_select');
|
||||
|
||||
updateLocalStorage();
|
||||
initGamepad();
|
||||
|
||||
// Check for disks in hashtag
|
||||
|
||||
var hash = gup('disk') || hup();
|
||||
if (hash) {
|
||||
processHash(hash);
|
||||
}
|
||||
|
||||
if (navigator.userAgent.match(/(iPod|iPhone|iPad)/)) {
|
||||
$('select').removeAttr('multiple').css('height', 'auto');
|
||||
}
|
||||
|
||||
if (navigator.standalone) {
|
||||
$('body').addClass('standalone');
|
||||
}
|
||||
|
||||
$('.key-REPT').click(function() {
|
||||
$('#keyboard').hide();
|
||||
$('#textarea').show();
|
||||
$('#text_input').focus();
|
||||
});
|
||||
$('#text_input').keydown(function() {
|
||||
focused = $('#buffering').prop('checked');
|
||||
}).keyup(function() {
|
||||
focused = $('#buffering').prop('checked');
|
||||
});
|
||||
});
|
877
js/main2e.js
Normal file
877
js/main2e.js
Normal file
@ -0,0 +1,877 @@
|
||||
/* globals debug: false, gup: false, hup: false,
|
||||
CPU6502: false,
|
||||
Apple2eROM: false, Apple2eEnhancedROM: false,
|
||||
apple2e_charset: false,
|
||||
Apple2IO: false
|
||||
LoresPage: false, HiresPage: false, VideoModes: false
|
||||
KeyBoard: false,
|
||||
Parallel: false,
|
||||
DiskII: false,
|
||||
RAMFactor: false,
|
||||
Printer: false,
|
||||
MMU: false,
|
||||
Slot3: false,
|
||||
Thunderclock: false,
|
||||
Prefs: false,
|
||||
disk_index: false,
|
||||
initAudio: false, enableSound: false,
|
||||
initGamepad: false, processGamepad: false, gamepad: false,
|
||||
ApplesoftDump: false
|
||||
*/
|
||||
/* exported openLoad, openSave, doDelete,
|
||||
selectCategory, selectDisk, clickDisk, loadJSON,
|
||||
updateJoystick,
|
||||
pauseRun, step,
|
||||
restoreState, saveState,
|
||||
dumpProgram, PageDebug
|
||||
*/
|
||||
|
||||
var kHz = 1023;
|
||||
|
||||
var focused = false;
|
||||
var startTime = Date.now();
|
||||
var lastCycles = 0;
|
||||
var renderedFrames = 0, lastFrames = 0;
|
||||
var paused = false;
|
||||
|
||||
var hashtag;
|
||||
|
||||
var disk_categories = {'Local Saves': []};
|
||||
var disk_sets = {};
|
||||
var disk_cur_name = [];
|
||||
var disk_cur_cat = [];
|
||||
|
||||
function DriveLights()
|
||||
{
|
||||
return {
|
||||
driveLight: function(drive, on) {
|
||||
$('#disk' + drive).css('background-image',
|
||||
on ? 'url(css/red-on-16.png)' :
|
||||
'url(css/red-off-16.png)');
|
||||
},
|
||||
dirty: function(drive, dirty) {
|
||||
$('#disksave' + drive).button('option', 'disabled', !dirty);
|
||||
},
|
||||
label: function(drive, label) {
|
||||
if (label) {
|
||||
$('#disklabel' + drive).text(label);
|
||||
}
|
||||
return $('#disklabel' + drive).text();
|
||||
},
|
||||
getState: function() {
|
||||
return {
|
||||
disks: [
|
||||
this.label(1),
|
||||
this.label(2)
|
||||
]
|
||||
};
|
||||
},
|
||||
setState: function(state) {
|
||||
if (state && state.disks) {
|
||||
this.label(1, state.disks[0].label);
|
||||
this.label(2, state.disks[1].label);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
var DISK_TYPES = ['dsk','do','po','raw','nib','2mg'];
|
||||
var TAPE_TYPES = ['wav','aiff','aif','mp3'];
|
||||
|
||||
var _saveDrive = 1;
|
||||
var _loadDrive = 1;
|
||||
|
||||
function openLoad(drive, event)
|
||||
{
|
||||
_loadDrive = drive;
|
||||
if (event.metaKey) {
|
||||
openLoadHTTP(drive);
|
||||
} else {
|
||||
if (disk_cur_cat[drive]) {
|
||||
$('#category_select').val(disk_cur_cat[drive]).change();
|
||||
}
|
||||
$('#load').dialog('open');
|
||||
}
|
||||
}
|
||||
|
||||
function openSave(drive, event)
|
||||
{
|
||||
_saveDrive = drive;
|
||||
if (event.metaKey) {
|
||||
dumpDisk(drive);
|
||||
} else if (event.altKey) {
|
||||
openSaveLocal(drive);
|
||||
} else {
|
||||
$('#save_name').val(drivelights.label(drive));
|
||||
$('#save').dialog('open');
|
||||
}
|
||||
}
|
||||
|
||||
var loading = false;
|
||||
|
||||
function loadAjax(url) {
|
||||
loading = true;
|
||||
$('#loading').dialog('open');
|
||||
|
||||
$.ajax({ url: url,
|
||||
cache: false,
|
||||
dataType: 'jsonp',
|
||||
jsonp: false,
|
||||
global: false
|
||||
});
|
||||
}
|
||||
|
||||
function doLoad() {
|
||||
var urls = $('#disk_select').val(), url;
|
||||
if (urls && urls.length) {
|
||||
if (typeof(urls) == 'string') {
|
||||
url = urls;
|
||||
} else {
|
||||
url = urls[0];
|
||||
}
|
||||
}
|
||||
|
||||
var files = $('#local_file').prop('files');
|
||||
if (files.length == 1) {
|
||||
doLoadLocal();
|
||||
} else if (url) {
|
||||
var filename;
|
||||
$('#load').dialog('close');
|
||||
if (url.substr(0,6) == 'local:') {
|
||||
filename = url.substr(6);
|
||||
if (filename == '__manage') {
|
||||
openManage();
|
||||
} else {
|
||||
loadLocalStorage(_loadDrive, filename);
|
||||
}
|
||||
} else {
|
||||
var r1 = /json\/disks\/(.*).json$/.exec(url);
|
||||
if (r1 && _loadDrive == 1) {
|
||||
filename = r1[1];
|
||||
document.location.hash = filename;
|
||||
}
|
||||
loadAjax(url);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function doSave() {
|
||||
var name = $('#save_name').val();
|
||||
saveLocalStorage(_saveDrive, name);
|
||||
$('#save').dialog('close');
|
||||
}
|
||||
|
||||
function doDelete(name) {
|
||||
if (window.confirm('Delete ' + name + '?')) {
|
||||
deleteLocalStorage(name);
|
||||
}
|
||||
}
|
||||
|
||||
function doLoadLocal() {
|
||||
var files = $('#local_file').prop('files');
|
||||
if (files.length == 1) {
|
||||
var file = files[0];
|
||||
var parts = file.name.split('.');
|
||||
var ext = parts[parts.length - 1].toLowerCase();
|
||||
if ($.inArray(ext, DISK_TYPES) >= 0) {
|
||||
doLoadLocalDisk(file);
|
||||
} else if ($.inArray(ext, TAPE_TYPES) >= 0) {
|
||||
doLoadLocalTape(file);
|
||||
} else {
|
||||
window.alert('Unknown file type: ' + ext);
|
||||
$('#load').dialog('close');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function doLoadLocalDisk(file) {
|
||||
var fileReader = new FileReader();
|
||||
fileReader.onload = function() {
|
||||
var parts = file.name.split('.');
|
||||
var name = parts[0], ext = parts[parts.length - 1].toLowerCase();
|
||||
if (disk2.setBinary(_saveDrive, name, ext, this.result)) {
|
||||
drivelights.label(_saveDrive, name);
|
||||
$('#load').dialog('close');
|
||||
initGamepad();
|
||||
}
|
||||
};
|
||||
fileReader.readAsArrayBuffer(file);
|
||||
}
|
||||
|
||||
function doLoadLocalTape(file) {
|
||||
// Audio Buffer Source
|
||||
var context;
|
||||
if (typeof window.AudioContext != 'undefined') {
|
||||
context = new window.AudioContext();
|
||||
} else {
|
||||
window.alert('Not supported by your browser');
|
||||
$('#load').dialog('close');
|
||||
return;
|
||||
}
|
||||
|
||||
var fileReader = new FileReader();
|
||||
fileReader.onload = function(ev) {
|
||||
context.decodeAudioData(ev.target.result, function(buffer) {
|
||||
var buf = [];
|
||||
var data = buffer.getChannelData(0), datum = data[0];
|
||||
var old = (datum > 0.0), current;
|
||||
var last = 0, delta, ival;
|
||||
debug('Sample Count: ' + data.length);
|
||||
debug('Sample rate: ' + buffer.sampleRate);
|
||||
for (var idx = 1; idx < data.length; idx++) {
|
||||
datum = data[idx];
|
||||
if ((datum > 0.1) || (datum < -0.1)) {
|
||||
current = (datum > 0.0);
|
||||
if (current != old) {
|
||||
delta = idx - last;
|
||||
if (delta > 2000000) {
|
||||
delta = 2000000;
|
||||
}
|
||||
ival = delta / buffer.sampleRate * 1000;
|
||||
if (ival >= 0.550 && ival < 0.750) {
|
||||
ival = 0.650; // Header
|
||||
} else if (ival >= 0.175 && ival < 0.225) {
|
||||
ival = 0.200; // sync 1
|
||||
} else if (ival >= 0.225 && ival < 0.275) {
|
||||
ival = 0.250; // 0 / sync 2
|
||||
} else if (ival >= 0.450 && ival < 0.550) {
|
||||
ival = 0.500; // 1
|
||||
} else {
|
||||
// debug(idx + ' ' + buf.length + ' ' + ival);
|
||||
}
|
||||
buf.push(parseInt(ival * kHz));
|
||||
old = current;
|
||||
last = idx;
|
||||
}
|
||||
}
|
||||
}
|
||||
io.setTape(buf);
|
||||
$('#load').dialog('close');
|
||||
});
|
||||
};
|
||||
fileReader.readAsArrayBuffer(file);
|
||||
}
|
||||
|
||||
function doLoadHTTP(_url) {
|
||||
var url = _url || $('#http_url').val();
|
||||
if (url) {
|
||||
var req = new XMLHttpRequest();
|
||||
req.open('GET', url, true);
|
||||
req.responseType = 'arraybuffer';
|
||||
|
||||
req.onload = function() {
|
||||
var parts = url.split(/[\/\.]/);
|
||||
var name = decodeURIComponent(parts[parts.length - 2]);
|
||||
var ext = parts[parts.length - 1].toLowerCase();
|
||||
if (disk2.setBinary(_saveDrive, name, ext, req.response)) {
|
||||
drivelights.label(_saveDrive, name);
|
||||
$('#http_load').dialog('close');
|
||||
initGamepad();
|
||||
}
|
||||
};
|
||||
req.send(null);
|
||||
}
|
||||
}
|
||||
|
||||
function openLoadHTTP(drive) {
|
||||
_saveDrive = drive;
|
||||
$('#http_load').dialog('open');
|
||||
}
|
||||
|
||||
function openSaveLocal(drive) {
|
||||
_saveDrive = drive;
|
||||
var mimetype = 'application/octet-stream';
|
||||
var data = disk2.getBinary(drive);
|
||||
var a = $('#local_save_link');
|
||||
|
||||
var blob = new Blob([data], { 'type': mimetype });
|
||||
a.attr('href', window.URL.createObjectURL(blob));
|
||||
a.attr('download', drivelights.label(drive) + '.dsk');
|
||||
|
||||
$('#local_save').dialog('open');
|
||||
}
|
||||
|
||||
function openManage() {
|
||||
$('#manage').dialog('open');
|
||||
}
|
||||
|
||||
var prefs = new Prefs();
|
||||
var enhanced = true;
|
||||
var runTimer = null;
|
||||
var cpu = new CPU6502({'65C02': enhanced});
|
||||
|
||||
var hgr = new HiresPage(1);
|
||||
var hgr2 = new HiresPage(2);
|
||||
var gr = new LoresPage(1, apple2e_charset);
|
||||
var gr2 = new LoresPage(2, apple2e_charset);
|
||||
|
||||
var rom;
|
||||
if (enhanced) {
|
||||
rom = new Apple2eEnhancedROM();
|
||||
} else {
|
||||
rom = new Apple2eROM();
|
||||
}
|
||||
var vm = new VideoModes(gr, hgr, gr2, hgr2);
|
||||
|
||||
var drivelights = new DriveLights();
|
||||
var io = new Apple2IO(cpu, vm);
|
||||
var keyboard = new KeyBoard(io);
|
||||
|
||||
var mmu = new MMU(cpu, gr, gr2, hgr, hgr2, io, rom);
|
||||
var dumper = new ApplesoftDump(mmu);
|
||||
|
||||
var parallel = new Parallel(io, new Printer(), 1);
|
||||
var disk2 = new DiskII(io, drivelights, 6);
|
||||
var slot3 = new Slot3(mmu, rom);
|
||||
var slinky = new RAMFactor(mmu, io, 2, 1024 * 1024);
|
||||
var clock = new Thunderclock(mmu, io, 7);
|
||||
|
||||
mmu.addSlot(1, parallel);
|
||||
mmu.addSlot(2, slinky);
|
||||
mmu.addSlot(3, slot3);
|
||||
mmu.addSlot(6, disk2);
|
||||
mmu.addSlot(7, clock);
|
||||
|
||||
cpu.addPageHandler(mmu);
|
||||
|
||||
var showFPS = false;
|
||||
|
||||
function updateKHz() {
|
||||
var now = Date.now();
|
||||
var ms = now - startTime;
|
||||
var cycles = cpu.cycles();
|
||||
var delta;
|
||||
|
||||
if (showFPS) {
|
||||
delta = renderedFrames - lastFrames;
|
||||
var fps = parseInt(delta/(ms/1000), 10);
|
||||
$('#khz').text( fps + 'fps');
|
||||
} else {
|
||||
delta = cycles - lastCycles;
|
||||
var khz = parseInt(delta/ms);
|
||||
$('#khz').text( khz + 'KHz');
|
||||
}
|
||||
|
||||
startTime = now;
|
||||
lastCycles = cycles;
|
||||
lastFrames = renderedFrames;
|
||||
}
|
||||
|
||||
/* Audio Handling */
|
||||
initAudio(io);
|
||||
|
||||
function updateSound() {
|
||||
enableSound($('#enable_sound').attr('checked'));
|
||||
}
|
||||
|
||||
function dumpDisk(drive) {
|
||||
var wind = window.open('', '_blank');
|
||||
wind.document.title = drivelights.label(drive);
|
||||
wind.document.write('<pre>');
|
||||
wind.document.write(disk2.getJSON(drive, true));
|
||||
wind.document.write('</pre>');
|
||||
wind.document.close();
|
||||
}
|
||||
|
||||
function dumpProgram() {
|
||||
var wind = window.open('', '_blank');
|
||||
wind.document.title = 'Program Listing';
|
||||
wind.document.write('<pre>');
|
||||
wind.document.write(dumper.toString());
|
||||
wind.document.write('</pre>');
|
||||
wind.document.close();
|
||||
}
|
||||
|
||||
function step()
|
||||
{
|
||||
if (runTimer) {
|
||||
clearInterval(runTimer);
|
||||
}
|
||||
runTimer = null;
|
||||
|
||||
cpu.step(function() {
|
||||
debug(cpu.dumpRegisters());
|
||||
debug(cpu.dumpPC());
|
||||
});
|
||||
}
|
||||
|
||||
var accelerated = false;
|
||||
|
||||
function updateSpeed()
|
||||
{
|
||||
accelerated = $('#accelerator_toggle').prop('checked');
|
||||
kHz = accelerated ? 4092 : 1023;
|
||||
io.updateHz(kHz * 1000);
|
||||
if (runTimer) {
|
||||
run();
|
||||
}
|
||||
}
|
||||
|
||||
var _requestAnimationFrame =
|
||||
window.requestAnimationFrame ||
|
||||
window.mozRequestAnimationFrame ||
|
||||
window.webkitRequestAnimationFrame ||
|
||||
window.msRequestAnimationFrame;
|
||||
|
||||
function run(pc) {
|
||||
if (runTimer) {
|
||||
clearInterval(runTimer);
|
||||
}
|
||||
|
||||
if (pc) {
|
||||
cpu.setPC(pc);
|
||||
}
|
||||
|
||||
var ival = 30;
|
||||
var now, last = Date.now();
|
||||
var runFn = function() {
|
||||
now = Date.now();
|
||||
renderedFrames++;
|
||||
|
||||
var step = (now - last) * kHz, stepMax = kHz * ival;
|
||||
last = now;
|
||||
if (step > stepMax) {
|
||||
step = stepMax;
|
||||
}
|
||||
|
||||
if (document.location.hash != hashtag) {
|
||||
hashtag = document.location.hash;
|
||||
var hash = hup();
|
||||
if (hash) {
|
||||
processHash(hash);
|
||||
}
|
||||
}
|
||||
|
||||
if (!loading) {
|
||||
mmu.resetVB();
|
||||
cpu.stepCycles(step);
|
||||
vm.blit();
|
||||
io.sampleTick();
|
||||
}
|
||||
|
||||
processGamepad(io);
|
||||
|
||||
if (!paused && _requestAnimationFrame) {
|
||||
_requestAnimationFrame(runFn);
|
||||
}
|
||||
};
|
||||
if (_requestAnimationFrame) {
|
||||
_requestAnimationFrame(runFn);
|
||||
} else {
|
||||
runTimer = setInterval(runFn, ival);
|
||||
}
|
||||
}
|
||||
|
||||
function stop() {
|
||||
if (runTimer) {
|
||||
clearInterval(runTimer);
|
||||
}
|
||||
runTimer = null;
|
||||
}
|
||||
|
||||
function reset()
|
||||
{
|
||||
cpu.reset();
|
||||
}
|
||||
|
||||
function loadBinary(bin) {
|
||||
stop();
|
||||
for (var idx = 0; idx < bin.length; idx++) {
|
||||
var pos = bin.start + idx;
|
||||
cpu.write(pos >> 8, pos & 0xff, bin.data[idx]);
|
||||
}
|
||||
run(bin.start);
|
||||
}
|
||||
|
||||
function selectCategory() {
|
||||
$('#disk_select').empty();
|
||||
var cat = disk_categories[$('#category_select').val()];
|
||||
if (cat) {
|
||||
for (var idx = 0; idx < cat.length; idx++) {
|
||||
var file = cat[idx], name = file.name;
|
||||
if (file.disk) {
|
||||
name += ' - ' + file.disk;
|
||||
}
|
||||
var option = $('<option />').val(file.filename).text(name)
|
||||
.appendTo('#disk_select');
|
||||
if (disk_cur_name[_loadDrive] == name) {
|
||||
option.attr('selected', 'selected');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function selectDisk() {
|
||||
$('#local_file').val('');
|
||||
}
|
||||
|
||||
function clickDisk() {
|
||||
doLoad();
|
||||
}
|
||||
|
||||
function loadDisk(disk) {
|
||||
var name = disk.name;
|
||||
var category = disk.category;
|
||||
|
||||
if (disk.disk) {
|
||||
name += ' - ' + disk.disk;
|
||||
}
|
||||
|
||||
disk_cur_cat[_loadDrive] = category;
|
||||
disk_cur_name[_loadDrive] = name;
|
||||
|
||||
drivelights.label(_loadDrive, name);
|
||||
disk2.setDisk(_loadDrive, disk);
|
||||
initGamepad(disk.gamepad);
|
||||
}
|
||||
|
||||
function loadJSON(data) {
|
||||
if (data.type == 'binary') {
|
||||
loadBinary(data);
|
||||
} else if ($.inArray(data.type, DISK_TYPES) >= 0) {
|
||||
loadDisk(data);
|
||||
}
|
||||
initGamepad(data.gamepad);
|
||||
$('#loading').dialog('close');
|
||||
loading = false;
|
||||
}
|
||||
|
||||
/*
|
||||
* LocalStorage Disk Storage
|
||||
*/
|
||||
|
||||
function updateLocalStorage() {
|
||||
var diskIndex = JSON.parse(window.localStorage.diskIndex || '{}');
|
||||
var names = [], name, cat;
|
||||
|
||||
for (name in diskIndex) {
|
||||
if (diskIndex.hasOwnProperty(name)) {
|
||||
names.push(name);
|
||||
}
|
||||
}
|
||||
|
||||
cat = disk_categories['Local Saves'] = [];
|
||||
$('#manage').empty();
|
||||
|
||||
names.forEach(function(name) {
|
||||
cat.push({'category': 'Local Saves',
|
||||
'name': name,
|
||||
'filename': 'local:' + name});
|
||||
$('#manage').append('<span class="local_save">' +
|
||||
name +
|
||||
' <a href="#" onclick="doDelete(\'' +
|
||||
name +
|
||||
'\')">Delete</a><br /></span>');
|
||||
});
|
||||
cat.push({'category': 'Local Saves',
|
||||
'name': 'Manage Saves...',
|
||||
'filename': 'local:__manage'});
|
||||
}
|
||||
|
||||
function saveLocalStorage(drive, name) {
|
||||
var diskIndex = JSON.parse(window.localStorage.diskIndex || '{}');
|
||||
|
||||
var json = disk2.getJSON(drive);
|
||||
diskIndex[name] = json;
|
||||
|
||||
window.localStorage.diskIndex = JSON.stringify(diskIndex);
|
||||
|
||||
window.alert('Saved');
|
||||
|
||||
drivelights.label(drive, name);
|
||||
drivelights.dirty(drive, false);
|
||||
updateLocalStorage();
|
||||
}
|
||||
|
||||
function deleteLocalStorage(name) {
|
||||
var diskIndex = JSON.parse(window.localStorage.diskIndex || '{}');
|
||||
if (diskIndex[name]) {
|
||||
delete diskIndex[name];
|
||||
window.alert('Deleted');
|
||||
}
|
||||
window.localStorage.diskIndex = JSON.stringify(diskIndex);
|
||||
updateLocalStorage();
|
||||
}
|
||||
|
||||
function loadLocalStorage(drive, name) {
|
||||
var diskIndex = JSON.parse(window.localStorage.diskIndex || '{}');
|
||||
if (diskIndex[name]) {
|
||||
disk2.setJSON(drive, diskIndex[name]);
|
||||
drivelights.label(drive, name);
|
||||
drivelights.dirty(drive, false);
|
||||
}
|
||||
}
|
||||
|
||||
function processHash(hash) {
|
||||
if (hash.indexOf('://') > 0) {
|
||||
var parts = hash.split('.');
|
||||
var ext = parts[parts.length - 1].toLowerCase();
|
||||
if (ext == 'json') {
|
||||
loadAjax(hash);
|
||||
} else {
|
||||
doLoadHTTP(hash);
|
||||
}
|
||||
} else {
|
||||
loadAjax('json/disks/' + hash + '.json');
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Keyboard/Gamepad routines
|
||||
*/
|
||||
|
||||
var _key;
|
||||
function _keydown(evt) {
|
||||
if (!focused) {
|
||||
evt.preventDefault();
|
||||
|
||||
var key = keyboard.mapKeyEvent(evt);
|
||||
if (key != 0xff) {
|
||||
if (_key != 0xff) io.keyUp();
|
||||
io.keyDown(key, evt.shiftKey);
|
||||
_key = key;
|
||||
}
|
||||
}
|
||||
if (evt.keyCode === 112) {
|
||||
cpu.reset();
|
||||
} else if (evt.keyCode === 113) { // F2 - Full Screen
|
||||
var elem = document.getElementById('screen');
|
||||
if (document.webkitCancelFullScreen) {
|
||||
if (document.webkitIsFullScreen) {
|
||||
document.webkitCancelFullScreen();
|
||||
} else {
|
||||
if (Element.ALLOW_KEYBOARD_INPUT) {
|
||||
elem.webkitRequestFullScreen(Element.ALLOW_KEYBOARD_INPUT);
|
||||
} else {
|
||||
elem.webkitRequestFullScreen();
|
||||
}
|
||||
}
|
||||
} else if (document.mozCancelFullScreen) {
|
||||
if (document.mozIsFullScreen) {
|
||||
document.mozCancelFullScreen();
|
||||
} else {
|
||||
elem.mozRequestFullScreen();
|
||||
}
|
||||
}
|
||||
} else if (evt.keyCode === 114) {
|
||||
io.keyDown(0x1b);
|
||||
_key = 0x1b;
|
||||
} else if (evt.keyCode == 16) { // Shift
|
||||
keyboard.shiftKey(true);
|
||||
io.buttonDown(2, true);
|
||||
} else if (evt.keyCode == 17) { // Control
|
||||
keyboard.controlKey(true);
|
||||
} else if (evt.keyCode == 91 || evt.keyCode == 93) { // Command
|
||||
keyboard.commandKey(true);
|
||||
} else if (evt.keyCode == 18) { // Alt
|
||||
keyboard.optionKey(true);
|
||||
}
|
||||
}
|
||||
|
||||
function _keyup(evt) {
|
||||
_key = 0xff;
|
||||
|
||||
if (!focused)
|
||||
io.keyUp();
|
||||
|
||||
if (evt.keyCode == 16) { // Shift
|
||||
keyboard.shiftKey(false);
|
||||
io.buttonDown(2, false);
|
||||
} else if (evt.keyCode == 17) { // Control
|
||||
keyboard.controlKey(false);
|
||||
} else if (evt.keyCode == 91 || evt.keyCode == 93) { // Command
|
||||
keyboard.commandKey(false);
|
||||
} else if (evt.keyCode == 18) { // Alt
|
||||
keyboard.optionKey(false);
|
||||
}
|
||||
}
|
||||
|
||||
function updateScreen() {
|
||||
var green = $('#green_screen').prop('checked');
|
||||
|
||||
vm.green(green);
|
||||
}
|
||||
|
||||
var disableMouseJoystick = false;
|
||||
var flipX = false;
|
||||
var flipY = false;
|
||||
var swapXY = false;
|
||||
|
||||
function updateJoystick() {
|
||||
disableMouseJoystick = $('#disable_mouse').prop('checked');
|
||||
flipX = $('#flip_x').prop('checked');
|
||||
flipY = $('#flip_y').prop('checked');
|
||||
swapXY = $('#swap_x_y').prop('checked');
|
||||
|
||||
if (disableMouseJoystick) {
|
||||
io.paddle(0, 0.5);
|
||||
io.paddle(1, 0.5);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
function _mousemove(evt) {
|
||||
if (gamepad || disableMouseJoystick) {
|
||||
return;
|
||||
}
|
||||
|
||||
var s = $('#screen');
|
||||
var offset = s.offset();
|
||||
var x = (evt.pageX - offset.left) / s.width(),
|
||||
y = (evt.pageY - offset.top) / s.height(),
|
||||
z = x;
|
||||
|
||||
if (swapXY) {
|
||||
x = y;
|
||||
y = z;
|
||||
}
|
||||
|
||||
io.paddle(0, flipX ? 1 - x : x);
|
||||
io.paddle(1, flipY ? 1 - y : y);
|
||||
}
|
||||
|
||||
function pauseRun(b) {
|
||||
if (paused) {
|
||||
run();
|
||||
b.value = 'Pause';
|
||||
} else {
|
||||
stop();
|
||||
b.value = 'Run';
|
||||
}
|
||||
paused = !paused;
|
||||
}
|
||||
|
||||
$(function() {
|
||||
hashtag = document.location.hash;
|
||||
|
||||
$('button,input[type=button],a.button').button().focus(function() {
|
||||
// Crazy hack required by Chrome
|
||||
var self = this;
|
||||
window.setTimeout(function() {
|
||||
self.blur();
|
||||
}, 1);
|
||||
});
|
||||
|
||||
var canvas = document.getElementById('screen');
|
||||
var context = canvas.getContext('2d');
|
||||
|
||||
vm.setContext(context);
|
||||
|
||||
/*
|
||||
* Input Handling
|
||||
*/
|
||||
|
||||
$(window).keydown(_keydown);
|
||||
$(window).keyup(_keyup);
|
||||
|
||||
$('canvas').mousedown(function(evt) {
|
||||
if (!gamepad) {
|
||||
io.buttonDown(evt.which == 1 ? 0 : 1);
|
||||
}
|
||||
evt.preventDefault();
|
||||
})
|
||||
.mouseup(function(evt) {
|
||||
if (!gamepad) {
|
||||
io.buttonUp(evt.which == 1 ? 0 : 1);
|
||||
}
|
||||
})
|
||||
.bind('contextmenu', function(evt) { evt.preventDefault(); });
|
||||
|
||||
$('body').mousemove(_mousemove);
|
||||
|
||||
$('body > div').hover(function() { focused = false; },
|
||||
function() { focused = true; });
|
||||
|
||||
$('input,textarea').focus(function() { focused = true; })
|
||||
.blur(function() { focused = false; });
|
||||
|
||||
keyboard.create($('#keyboard'));
|
||||
|
||||
if (prefs.havePrefs()) {
|
||||
$('input[type=checkbox]').each(function() {
|
||||
var val = prefs.readPref(this.id);
|
||||
if (val)
|
||||
this.checked = JSON.parse(val);
|
||||
}).change(function() {
|
||||
prefs.writePref(this.id, JSON.stringify(this.checked));
|
||||
});
|
||||
}
|
||||
|
||||
reset();
|
||||
run();
|
||||
setInterval(updateKHz, 1000);
|
||||
updateSound();
|
||||
updateScreen();
|
||||
updateSpeed();
|
||||
|
||||
var cancel = function() { $(this).dialog('close'); };
|
||||
$('#loading').dialog({ autoOpen: false, modal: true });
|
||||
$('#options').dialog({ autoOpen: false,
|
||||
modal: true,
|
||||
width: 320,
|
||||
height: 400,
|
||||
buttons: {'Close': cancel }});
|
||||
$('#load').dialog({ autoOpen: false,
|
||||
modal: true,
|
||||
width: 540,
|
||||
buttons: {'Cancel': cancel, 'Load': doLoad }});
|
||||
$('#save').dialog({ autoOpen: false,
|
||||
modal: true,
|
||||
width: 320,
|
||||
buttons: {'Cancel': cancel, 'Save': doSave }});
|
||||
$('#manage').dialog({ autoOpen: false,
|
||||
modal: true,
|
||||
width: 320,
|
||||
buttons: {'Close': cancel }});
|
||||
$('#local_save').dialog({ autoOpen: false,
|
||||
modal: true,
|
||||
width: 530,
|
||||
buttons: {'OK': cancel }});
|
||||
$('#http_load').dialog({ autoOpen: false,
|
||||
modal: true,
|
||||
width: 530,
|
||||
buttons: {'Cancel': cancel, 'OK': doLoadHTTP }});
|
||||
|
||||
if (window.localStorage !== undefined) {
|
||||
$('.disksave').show();
|
||||
}
|
||||
|
||||
var oldcat = '';
|
||||
for (var idx = 0; idx < disk_index.length; idx++) {
|
||||
var file = disk_index[idx];
|
||||
var cat = file.category;
|
||||
var name = file.name, disk = file.disk;
|
||||
if (cat != oldcat) {
|
||||
$('<option />').val(cat).text(cat).appendTo('#category_select');
|
||||
disk_categories[cat] = [];
|
||||
oldcat = cat;
|
||||
}
|
||||
disk_categories[cat].push(file);
|
||||
if (disk) {
|
||||
if (!disk_sets[name]) {
|
||||
disk_sets[name] = [];
|
||||
}
|
||||
disk_sets[name].push(file);
|
||||
}
|
||||
}
|
||||
$('<option/>').text('Local Saves').appendTo('#category_select');
|
||||
|
||||
updateLocalStorage();
|
||||
initGamepad();
|
||||
|
||||
// Check for disks in hashtag
|
||||
|
||||
var hash = gup('disk') || hup();
|
||||
if (hash) {
|
||||
processHash(hash);
|
||||
}
|
||||
|
||||
if (navigator.userAgent.match(/(iPod|iPhone|iPad)/)) {
|
||||
$('select').removeAttr('multiple').css('height', 'auto');
|
||||
}
|
||||
|
||||
if (navigator.standalone) {
|
||||
$('body').addClass('standalone');
|
||||
}
|
||||
|
||||
});
|
47
js/mmu.js
47
js/mmu.js
@ -1,5 +1,4 @@
|
||||
/* -*- mode: JavaScript; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* Copyright 2010-2013 Will Scullin <scullin@scullinsteel.com>
|
||||
/* Copyright 2010-2016 Will Scullin <scullin@scullinsteel.com>
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software and its
|
||||
* documentation for any purpose is hereby granted without fee, provided that
|
||||
@ -10,10 +9,16 @@
|
||||
* implied warranty.
|
||||
*/
|
||||
|
||||
/*globals RAM: false, toHex: false, hiresMode: false, debug: false */
|
||||
/*exported MMU */
|
||||
/*globals debug: false, toHex: false
|
||||
hiresMode: false,
|
||||
RAM: false
|
||||
*/
|
||||
|
||||
function MMU(cpu, lores1, lores2, hires1, hires2, io, rom)
|
||||
{
|
||||
'use strict';
|
||||
|
||||
var idx;
|
||||
|
||||
var _auxRom = 0x00;
|
||||
@ -28,14 +33,14 @@ function MMU(cpu, lores1, lores2, hires1, hires2, io, rom)
|
||||
var _writebsr;
|
||||
|
||||
// Auxilliary ROM
|
||||
var _intcxrom;
|
||||
var _intcxrom;
|
||||
var _slot3rom;
|
||||
|
||||
// Auxilliary RAM
|
||||
var _auxRamRead;
|
||||
var _auxRamWrite;
|
||||
var _altzp;
|
||||
|
||||
|
||||
// Video
|
||||
var _80store = false;
|
||||
var _page2;
|
||||
@ -51,7 +56,7 @@ function MMU(cpu, lores1, lores2, hires1, hires2, io, rom)
|
||||
_auxRamWrite = false;
|
||||
_altzp = false;
|
||||
|
||||
_intcxrom = false;
|
||||
_intcxrom = false;
|
||||
_slot3rom = false;
|
||||
|
||||
_80store = false;
|
||||
@ -93,7 +98,7 @@ function MMU(cpu, lores1, lores2, hires1, hires2, io, rom)
|
||||
var memC0_C0 = [io];
|
||||
// var memC1_CF = [emptyslots, rom];
|
||||
var memD0_DF = [rom,
|
||||
new RAM(0xD0,0xDF), new RAM(0xD0,0xDF),
|
||||
new RAM(0xD0,0xDF), new RAM(0xD0,0xDF),
|
||||
new RAM(0xD0,0xDF), new RAM(0xD0,0xDF)];
|
||||
var memE0_FF = [rom, new RAM(0xE0,0xFF), new RAM(0xE0,0xFF)];
|
||||
|
||||
@ -172,7 +177,7 @@ function MMU(cpu, lores1, lores2, hires1, hires2, io, rom)
|
||||
_readPages[idx] = _pages[idx][0];
|
||||
_writePages[idx] = _pages[idx][0];
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* I/O Switch locations
|
||||
*/
|
||||
@ -235,7 +240,7 @@ function MMU(cpu, lores1, lores2, hires1, hires2, io, rom)
|
||||
_OFFBSR1: 0x8e,
|
||||
_READWRBSR1: 0x8f
|
||||
};
|
||||
|
||||
|
||||
function _updateBanks() {
|
||||
if (_auxRamRead) {
|
||||
for (idx = 0x02; idx < 0xC0; idx++) {
|
||||
@ -372,35 +377,35 @@ function MMU(cpu, lores1, lores2, hires1, hires2, io, rom)
|
||||
if (typeof val != 'undefined') {
|
||||
_80store = true;
|
||||
// _debug("80 Store On");
|
||||
} else
|
||||
} else
|
||||
result = 0;
|
||||
break;
|
||||
case LOC.RAMRDOFF:
|
||||
if (typeof val != 'undefined') {
|
||||
_auxRamRead = false;
|
||||
_debug("Aux RAM Read Off");
|
||||
} else
|
||||
} else
|
||||
result = 0;
|
||||
break;
|
||||
case LOC.RAMRDON:
|
||||
if (typeof val != 'undefined') {
|
||||
_auxRamRead = true;
|
||||
_debug("Aux RAM Read On");
|
||||
} else
|
||||
} else
|
||||
result = 0;
|
||||
break;
|
||||
case LOC.RAMWROFF:
|
||||
if (typeof val != 'undefined') {
|
||||
_auxRamWrite = false;
|
||||
_debug("Aux RAM Write Off");
|
||||
} else
|
||||
} else
|
||||
result = 0;
|
||||
break;
|
||||
case LOC.RAMWRON:
|
||||
if (typeof val != 'undefined') {
|
||||
_auxRamWrite = true;
|
||||
_debug("Aux RAM Write On");
|
||||
} else
|
||||
} else
|
||||
result = 0;
|
||||
break;
|
||||
|
||||
@ -416,7 +421,7 @@ function MMU(cpu, lores1, lores2, hires1, hires2, io, rom)
|
||||
// _debug("Int CX ROM On");
|
||||
}
|
||||
break;
|
||||
case LOC.ALTZPOFF: // 0x08
|
||||
case LOC.ALTZPOFF: // 0x08
|
||||
if (typeof val != 'undefined') {
|
||||
_altzp = false;
|
||||
_debug("Alt ZP Off");
|
||||
@ -515,7 +520,7 @@ function MMU(cpu, lores1, lores2, hires1, hires2, io, rom)
|
||||
|
||||
case LOC.BSRBANK2:
|
||||
_debug("Bank 2 Read " + !_bank1);
|
||||
result = !_bank1 ? 0x80 : 0x00;
|
||||
result = !_bank1 ? 0x80 : 0x00;
|
||||
break;
|
||||
case LOC.BSRREADRAM:
|
||||
_debug("Bank SW RAM Read " + _readbsr);
|
||||
@ -571,10 +576,10 @@ function MMU(cpu, lores1, lores2, hires1, hires2, io, rom)
|
||||
io.start();
|
||||
lores1.start();
|
||||
lores2.start();
|
||||
|
||||
|
||||
// Do us afterward because we override some of the above
|
||||
io.registerSwitches(this, LOC);
|
||||
|
||||
|
||||
return 0x00;
|
||||
},
|
||||
end: function mmu_end() {
|
||||
@ -632,7 +637,7 @@ function MMU(cpu, lores1, lores2, hires1, hires2, io, rom)
|
||||
auxRamRead: _auxRamRead,
|
||||
auxRamWrite: _auxRamWrite,
|
||||
altzp: _altzp,
|
||||
|
||||
|
||||
_80store: _80store,
|
||||
page2: _page2,
|
||||
|
||||
@ -649,14 +654,14 @@ function MMU(cpu, lores1, lores2, hires1, hires2, io, rom)
|
||||
_readbsr = state.readbsr;
|
||||
_writebsr = state.writebsr;
|
||||
_bank1 = state.bank1;
|
||||
|
||||
|
||||
_auxRom = state.auxRom;
|
||||
_intcxrom = state.intcxrom;
|
||||
_slot3rom = state.slot3rom;
|
||||
_auxRamRead = state.auxRamRead;
|
||||
_auxRamWrite = state.auxRamWrite;
|
||||
_altzp = state.altzp;
|
||||
|
||||
|
||||
_80store = state._80store;
|
||||
_page2 = state.page2;
|
||||
|
||||
|
@ -1,5 +1,4 @@
|
||||
/* -*- mode: JavaScript; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* Copyright 2010-2013 Will Scullin <scullin@scullinsteel.com>
|
||||
/* Copyright 2010-2016 Will Scullin <scullin@scullinsteel.com>
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software and its
|
||||
* documentation for any purpose is hereby granted without fee, provided that
|
||||
@ -13,6 +12,8 @@
|
||||
/*exported Parallel */
|
||||
|
||||
function Parallel(io, cbs, slot) {
|
||||
'use strict';
|
||||
|
||||
slot = slot || 1;
|
||||
|
||||
var LOC = {
|
||||
@ -75,5 +76,3 @@ function Parallel(io, cbs, slot) {
|
||||
write: function() {}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
12
js/prefs.js
12
js/prefs.js
@ -1,5 +1,4 @@
|
||||
/* -*- mode: JavaScript; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* Copyright 2010-2013 Will Scullin <scullin@scullinsteel.com>
|
||||
/* Copyright 2010-2016 Will Scullin <scullin@scullinsteel.com>
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software and its
|
||||
* documentation for any purpose is hereby granted without fee, provided that
|
||||
@ -10,23 +9,24 @@
|
||||
* implied warranty.
|
||||
*/
|
||||
|
||||
/*jshint browser: true */
|
||||
/*exported Prefs */
|
||||
|
||||
function Prefs()
|
||||
{
|
||||
'use strict';
|
||||
|
||||
return {
|
||||
havePrefs: function() {
|
||||
return typeof(localStorage) != "undefined";
|
||||
return typeof(localStorage) != 'undefined';
|
||||
},
|
||||
readPref: function(name) {
|
||||
if (localStorage)
|
||||
return localStorage.getItem(name);
|
||||
return localStorage.getItem(name);
|
||||
return null;
|
||||
},
|
||||
writePref: function(name, value) {
|
||||
if (localStorage)
|
||||
localStorage.setItem(name, value);
|
||||
localStorage.setItem(name, value);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
/* -*- mode: JavaScript; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* Copyright 2010-2013 Will Scullin <scullin@scullinsteel.com>
|
||||
/* Copyright 2010-2016 Will Scullin <scullin@scullinsteel.com>
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software and its
|
||||
* documentation for any purpose is hereby granted without fee, provided that
|
||||
@ -10,10 +9,14 @@
|
||||
* implied warranty.
|
||||
*/
|
||||
|
||||
/*globals allocMemPages, base64_encode, base64_decode */
|
||||
/*exported RAM */
|
||||
/*globals allocMemPages: false
|
||||
base64_encode: false, base64_decode: false
|
||||
*/
|
||||
|
||||
function RAM(sp, ep) {
|
||||
'use strict';
|
||||
|
||||
var mem;
|
||||
var start_page = sp;
|
||||
var end_page = ep;
|
||||
|
@ -1,5 +1,4 @@
|
||||
/* -*- mode: JavaScript; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* Copyright 2010-2013 Will Scullin <scullin@scullinsteel.com>
|
||||
/* Copyright 2010-2016 Will Scullin <scullin@scullinsteel.com>
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software and its
|
||||
* documentation for any purpose is hereby granted without fee, provided that
|
||||
@ -10,10 +9,13 @@
|
||||
* implied warranty.
|
||||
*/
|
||||
|
||||
/*globals allocMem:false, bytify, base64_encode, base64_decode, each: false */
|
||||
/*exported RAMFactor*/
|
||||
|
||||
/*globals allocMem: false, bytify: false, each: false,
|
||||
base64_encode: false, base64_decode: false
|
||||
*/
|
||||
function RAMFactor(mmu, io, slot, size) {
|
||||
'use strict';
|
||||
|
||||
var rom = [
|
||||
0x43,0x4f,0x50,0x59,0x52,0x49,0x47,0x48,
|
||||
0x54,0x20,0x28,0x43,0x29,0x20,0x31,0x39,
|
||||
@ -1079,14 +1081,14 @@ function RAMFactor(mmu, io, slot, size) {
|
||||
}
|
||||
|
||||
function _setmid(val) {
|
||||
if ((_rammid & 0x80) && !(val & 0x80)) {
|
||||
if (((_rammid & 0x80) !== 0) && ((val & 0x80) === 0)) {
|
||||
_sethi(_ramhi + 1);
|
||||
}
|
||||
_rammid = (val & 0xff);
|
||||
}
|
||||
|
||||
function _setlo(val) {
|
||||
if ((_ramlo & 0x80) && !(val & 0x80)) {
|
||||
if (((_ramlo & 0x80) !== 0) && ((val & 0x80) === 0)) {
|
||||
_setmid(_rammid + 1);
|
||||
}
|
||||
_ramlo = (val & 0xff);
|
||||
|
@ -1,5 +1,4 @@
|
||||
/* -*- mode: JavaScript; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* Copyright 2010-2013 Will Scullin <scullin@scullinsteel.com>
|
||||
/* Copyright 2010-2016 Will Scullin <scullin@scullinsteel.com>
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software and its
|
||||
* documentation for any purpose is hereby granted without fee, provided that
|
||||
@ -14,6 +13,8 @@
|
||||
|
||||
function Slot3(mmu, rom)
|
||||
{
|
||||
'use strict';
|
||||
|
||||
var auxRomFn = {
|
||||
start: function auxRom_start() {
|
||||
return 0xc8;
|
||||
|
1474
js/symbols.js
1474
js/symbols.js
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,4 @@
|
||||
/* -*- mode: JavaScript; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* Copyright 2010-2013 Will Scullin <scullin@scullinsteel.com>
|
||||
/* Copyright 2010-2016 Will Scullin <scullin@scullinsteel.com>
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software and its
|
||||
* documentation for any purpose is hereby granted without fee, provided that
|
||||
@ -11,17 +10,19 @@
|
||||
*/
|
||||
|
||||
/*exported Thunderclock */
|
||||
/*global each */
|
||||
/*global each: false */
|
||||
|
||||
function Thunderclock(mmu, io, slot)
|
||||
{
|
||||
'use strict';
|
||||
|
||||
var rom = [
|
||||
0x08,0x78,0x28,0x2c,0x58,0xff,0x70,0x05, // 00
|
||||
0x38,0xb0,0x01,0x18,0xb8,0x08,0x78,0x48,
|
||||
0x8a,0x48,0x98,0x48,0xad,0xff,0xcf,0x20, // 10
|
||||
0x1a,0xc8,0x68,0x68,0xba,0x8d,0xf8,0x07,
|
||||
0x0a,0x0a,0x0a,0x0a,0x8d,0x78,0x07,0x68, // 20
|
||||
0x68,0x68,0xa8,0x68,0x9a,0x09,0x04,0x48,
|
||||
0x68,0x68,0xa8,0x68,0x9a,0x09,0x04,0x48,
|
||||
0x28,0x98,0xac,0x78,0x07,0xae,0xf8,0x07, // 30
|
||||
0x29,0x7f,0x48,0x50,0x0e,0xb8,0xa5,0x36,
|
||||
0xd0,0x04,0xe4,0x37,0xf0,0x0a,0xa9,0x08, // 40
|
||||
@ -340,7 +341,7 @@ function Thunderclock(mmu, io, slot)
|
||||
switch (off) {
|
||||
case LOC.CONTROL:
|
||||
if (val !== undefined) {
|
||||
if (val & FLAGS.STROBE) {
|
||||
if ((val & FLAGS.STROBE) !== 0) {
|
||||
if ((_command & 0x78) == 0x18) {
|
||||
_calcbits();
|
||||
}
|
||||
@ -390,4 +391,3 @@ function Thunderclock(mmu, io, slot)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,4 @@
|
||||
/* -*- mode: JavaScript; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* Copyright 2010-2014 Will Scullin <scullin@scullinsteel.com>
|
||||
/* Copyright 2010-2016 Will Scullin <scullin@scullinsteel.com>
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software and its
|
||||
* documentation for any purpose is hereby granted without fee, provided that
|
||||
@ -10,7 +9,6 @@
|
||||
* implied warranty.
|
||||
*/
|
||||
|
||||
/*jshint jquery: true, browser: true */
|
||||
/*globals debug: false */
|
||||
/*exported enableSound, initAudio */
|
||||
|
||||
@ -18,46 +16,46 @@
|
||||
* Audio Handling
|
||||
*/
|
||||
|
||||
var sound = true;
|
||||
var _samples = [];
|
||||
var sound = true;
|
||||
var _samples = [];
|
||||
|
||||
var audioContext;
|
||||
var audioNode;
|
||||
var AC = window.webkitAudioContext || window.AudioContext;
|
||||
var audioContext;
|
||||
var audioNode;
|
||||
var AC = window.AudioContext;
|
||||
|
||||
if (typeof AC !== 'undefined') {
|
||||
audioContext = new AC();
|
||||
audioNode = audioContext.createScriptProcessor(4096, 1, 1);
|
||||
if (typeof AC !== 'undefined') {
|
||||
audioContext = new AC();
|
||||
audioNode = audioContext.createScriptProcessor(4096, 1, 1);
|
||||
|
||||
audioNode.onaudioprocess = function(event) {
|
||||
var data = event.outputBuffer.getChannelData(0);
|
||||
var sample = _samples.shift();
|
||||
var idx = 0;
|
||||
audioNode.onaudioprocess = function(event) {
|
||||
var data = event.outputBuffer.getChannelData(0);
|
||||
var sample = _samples.shift();
|
||||
var idx = 0;
|
||||
|
||||
var len = data.length;
|
||||
if (sample) {
|
||||
len = Math.min(sample.length, len);
|
||||
for (; idx < len; idx++) {
|
||||
data[idx] = sample[idx];
|
||||
}
|
||||
}
|
||||
|
||||
for (; idx < data.length; idx++) {
|
||||
data[idx] = 0.0;
|
||||
}
|
||||
};
|
||||
var len = data.length;
|
||||
if (sample) {
|
||||
len = Math.min(sample.length, len);
|
||||
for (; idx < len; idx++) {
|
||||
data[idx] = sample[idx];
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
// Create and specify parameters for the low-pass filter.
|
||||
var filter = audioContext.createBiquadFilter();
|
||||
filter.type = 'lowpass';
|
||||
filter.frequency.value = 11000;
|
||||
filter.connect(audioContext.destination);
|
||||
audioNode.connect(filter);
|
||||
*/
|
||||
for (; idx < data.length; idx++) {
|
||||
data[idx] = 0.0;
|
||||
}
|
||||
};
|
||||
|
||||
audioNode.connect(audioContext.destination);
|
||||
}
|
||||
/*
|
||||
// Create and specify parameters for the low-pass filter.
|
||||
var filter = audioContext.createBiquadFilter();
|
||||
filter.type = 'lowpass';
|
||||
filter.frequency.value = 11000;
|
||||
filter.connect(audioContext.destination);
|
||||
audioNode.connect(filter);
|
||||
*/
|
||||
|
||||
audioNode.connect(audioContext.destination);
|
||||
}
|
||||
|
||||
function initAudio(io) {
|
||||
if (audioContext) {
|
||||
|
@ -1,11 +1,11 @@
|
||||
/*!
|
||||
* Copyright 2010-2013 Will Scullin <scullin@scullinsteel.com>
|
||||
* Copyright 2010-2016 Will Scullin <scullin@scullinsteel.com>
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software and its
|
||||
* documentation for any purpose is hereby granted without fee, provided that
|
||||
* the above copyright notice appear in all copies and that both that
|
||||
* copyright notice and this permission notice appear in supporting
|
||||
* documentation. No representations are made about the suitability of this
|
||||
* software for any purpose. It is provided "as is" without express or
|
||||
* software for any purpose. It is provided "as is" without express or
|
||||
* implied warranty.
|
||||
*/
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* -*- mode: JavaScript; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* Copyright 2010-2014 Will Scullin <scullin@scullinsteel.com>
|
||||
|
||||
/* Copyright 2010-2016 Will Scullin <scullin@scullinsteel.com>
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software and its
|
||||
* documentation for any purpose is hereby granted without fee, provided that
|
||||
@ -14,7 +14,7 @@
|
||||
/*globals flipX: false, flipY: false */
|
||||
/*exported processGamepad, initGamepad, gamepad */
|
||||
|
||||
var gamepadSupportAvailable = !!navigator.webkitGetGamepads;
|
||||
var getGamepads = navigator.getGamepads || navigator.webkitGetGamepads;
|
||||
var gamepad;
|
||||
var gamepadMap = [];
|
||||
var gamepadState = [];
|
||||
@ -54,17 +54,17 @@ var DEFAULT_GAMEPAD = {
|
||||
'START': '\033'
|
||||
};
|
||||
|
||||
window.addEventListener("gamepadconnected", function(e) {
|
||||
window.addEventListener('gamepadconnected', function(e) {
|
||||
gamepad = e.gamepad;
|
||||
});
|
||||
|
||||
function processGamepad(io) {
|
||||
if (gamepadSupportAvailable) {
|
||||
gamepad = navigator.webkitGetGamepads()[0];
|
||||
if (getGamepads) {
|
||||
gamepad = getGamepads.call(navigator)[0];
|
||||
}
|
||||
if (gamepad) {
|
||||
var x = (gamepad.axes[0] * 1.414 + 1) / 2.0;
|
||||
var y = (gamepad.axes[1] * 1.414 + 1) / 2.0;
|
||||
var x = (gamepad.axes[0] * 1.414 + 1) / 2.0;
|
||||
var y = (gamepad.axes[1] * 1.414 + 1) / 2.0;
|
||||
io.paddle(0, flipX ? 1.0 - x : x);
|
||||
io.paddle(1, flipY ? 1.0 - y : y);
|
||||
var val;
|
||||
@ -74,12 +74,12 @@ function processGamepad(io) {
|
||||
var old = gamepadState[idx];
|
||||
var button = gamepad.buttons[idx];
|
||||
var pressed;
|
||||
if (typeof(button) == "object") {
|
||||
if (typeof(button) == 'object') {
|
||||
pressed = button.pressed;
|
||||
} else {
|
||||
pressed = (button == 1.0);
|
||||
}
|
||||
|
||||
|
||||
if (pressed && !old) {
|
||||
if (val <= 0) {
|
||||
io.buttonDown(-val);
|
||||
@ -117,5 +117,3 @@ function initGamepad(data) {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,5 +1,4 @@
|
||||
/* -*- mode: JavaScript; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* Copyright 2010-2013 Will Scullin <scullin@scullinsteel.com>
|
||||
/* Copyright 2010-2016 Will Scullin <scullin@scullinsteel.com>
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software and its
|
||||
* documentation for any purpose is hereby granted without fee, provided that
|
||||
@ -10,7 +9,6 @@
|
||||
* implied warranty.
|
||||
*/
|
||||
|
||||
/*jshint jquery: true, browser: true */
|
||||
/*globals debug: false, toHex: false, reset: false */
|
||||
/*exported KeyBoard */
|
||||
|
||||
@ -18,46 +16,46 @@ function KeyBoard(io) {
|
||||
// keycode: [plain, cntl, shift]
|
||||
var keymap = {
|
||||
// Most of these won't happen
|
||||
0x00: [0x00, 0x00, 0x00], //
|
||||
0x01: [0x01, 0x01, 0x01], //
|
||||
0x02: [0x02, 0x02, 0x02], //
|
||||
0x03: [0x03, 0x03, 0x03], //
|
||||
0x04: [0x04, 0x04, 0x04], //
|
||||
0x05: [0x05, 0x05, 0x05], //
|
||||
0x06: [0x06, 0x06, 0x06], //
|
||||
0x07: [0x07, 0x07, 0x07], //
|
||||
0x00: [0x00, 0x00, 0x00], //
|
||||
0x01: [0x01, 0x01, 0x01], //
|
||||
0x02: [0x02, 0x02, 0x02], //
|
||||
0x03: [0x03, 0x03, 0x03], //
|
||||
0x04: [0x04, 0x04, 0x04], //
|
||||
0x05: [0x05, 0x05, 0x05], //
|
||||
0x06: [0x06, 0x06, 0x06], //
|
||||
0x07: [0x07, 0x07, 0x07], //
|
||||
0x08: [0x08, 0x08, 0x08], // BS
|
||||
0x09: [0x09, 0x09, 0x09], // TAB
|
||||
0x0A: [0x0A, 0x0A, 0x0A], //
|
||||
0x0B: [0x0B, 0x0B, 0x0B], //
|
||||
0x0C: [0x0C, 0x0C, 0x0C], //
|
||||
0x0A: [0x0A, 0x0A, 0x0A], //
|
||||
0x0B: [0x0B, 0x0B, 0x0B], //
|
||||
0x0C: [0x0C, 0x0C, 0x0C], //
|
||||
0x0D: [0x0D, 0x0D, 0x0D], // CR
|
||||
0x0E: [0x0E, 0x0E, 0x0E], //
|
||||
0x0F: [0x0F, 0x0F, 0x0F], //
|
||||
|
||||
0x0E: [0x0E, 0x0E, 0x0E], //
|
||||
0x0F: [0x0F, 0x0F, 0x0F], //
|
||||
|
||||
0x10: [0xff, 0xff, 0xff], // SHIFT
|
||||
0x11: [0xff, 0xff, 0xff], // CTRL
|
||||
0x12: [0xff, 0xff, 0xff], // OPTION
|
||||
0x13: [0x13, 0x13, 0x13], //
|
||||
0x14: [0x14, 0x14, 0x14], //
|
||||
0x15: [0x15, 0x15, 0x15], //
|
||||
0x16: [0x16, 0x16, 0x16], //
|
||||
0x17: [0x17, 0x17, 0x18], //
|
||||
0x18: [0x18, 0x18, 0x18], //
|
||||
0x19: [0x19, 0x19, 0x19], //
|
||||
0x1A: [0x1A, 0x1A, 0x1A], //
|
||||
0x13: [0x13, 0x13, 0x13], //
|
||||
0x14: [0x14, 0x14, 0x14], //
|
||||
0x15: [0x15, 0x15, 0x15], //
|
||||
0x16: [0x16, 0x16, 0x16], //
|
||||
0x17: [0x17, 0x17, 0x18], //
|
||||
0x18: [0x18, 0x18, 0x18], //
|
||||
0x19: [0x19, 0x19, 0x19], //
|
||||
0x1A: [0x1A, 0x1A, 0x1A], //
|
||||
0x1B: [0x1B, 0x1B, 0x1B], // ESC
|
||||
0x1C: [0x1C, 0x1C, 0x1C], //
|
||||
0x1D: [0x1D, 0x1D, 0x1D], //
|
||||
0x1E: [0x1E, 0x1E, 0x1E], //
|
||||
0x1F: [0x1F, 0x1F, 0x1F], //
|
||||
|
||||
0x1C: [0x1C, 0x1C, 0x1C], //
|
||||
0x1D: [0x1D, 0x1D, 0x1D], //
|
||||
0x1E: [0x1E, 0x1E, 0x1E], //
|
||||
0x1F: [0x1F, 0x1F, 0x1F], //
|
||||
|
||||
// Most of these besides space won't happen
|
||||
0x20: [0x20, 0x20, 0x20], //
|
||||
0x21: [0x21, 0x21, 0x21], //
|
||||
0x22: [0x22, 0x22, 0x22], //
|
||||
0x23: [0x23, 0x23, 0x23], //
|
||||
0x24: [0x24, 0x24, 0x24], //
|
||||
0x20: [0x20, 0x20, 0x20], //
|
||||
0x21: [0x21, 0x21, 0x21], //
|
||||
0x22: [0x22, 0x22, 0x22], //
|
||||
0x23: [0x23, 0x23, 0x23], //
|
||||
0x24: [0x24, 0x24, 0x24], //
|
||||
0x25: [0x08, 0x08, 0x08], // <- left
|
||||
0x26: [0x0B, 0x0B, 0x0B], // ^ up
|
||||
0x27: [0x15, 0x15, 0x15], // -> right
|
||||
@ -69,7 +67,7 @@ function KeyBoard(io) {
|
||||
0x2D: [0x2D, 0x2D, 0x5F], // - - _
|
||||
0x2E: [0x2E, 0x2E, 0x3E], // . - >
|
||||
0x2F: [0x2F, 0x2F, 0x3F], // / - ?
|
||||
|
||||
|
||||
0x30: [0x30, 0x30, 0x29], // 0 - )
|
||||
0x31: [0x31, 0x31, 0x21], // 1 - !
|
||||
0x32: [0x32, 0x00, 0x40], // 2 - @
|
||||
@ -86,7 +84,7 @@ function KeyBoard(io) {
|
||||
0x3D: [0x3D, 0x3D, 0x2B], // = - +
|
||||
0x3E: [0x3E, 0x3E, 0x3E], // >
|
||||
0x3F: [0x3F, 0x3F, 0x3F], // ?
|
||||
|
||||
|
||||
// Alpha and control
|
||||
0x40: [0x40, 0x00, 0x40], // @
|
||||
0x41: [0x41, 0x01, 0x41], // A
|
||||
@ -99,12 +97,12 @@ function KeyBoard(io) {
|
||||
0x48: [0x48, 0x08, 0x48], // H
|
||||
0x49: [0x49, 0x09, 0x49], // I - TAB
|
||||
0x4A: [0x4A, 0x0A, 0x4A], // J - NL
|
||||
0x4B: [0x4B, 0x0B, 0x4B], // K - VT
|
||||
0x4B: [0x4B, 0x0B, 0x4B], // K - VT
|
||||
0x4C: [0x4C, 0x0C, 0x4C], // L
|
||||
0x4D: [0x4D, 0x0D, 0x4D], // M - CR
|
||||
0x4E: [0x4E, 0x0E, 0x4E], // N
|
||||
0x4F: [0x4F, 0x0F, 0x4F], // O
|
||||
|
||||
|
||||
0x50: [0x50, 0x10, 0x50], // P
|
||||
0x51: [0x51, 0x11, 0x51], // Q
|
||||
0x52: [0x52, 0x12, 0x52], // R
|
||||
@ -121,7 +119,7 @@ function KeyBoard(io) {
|
||||
// 0x5D: [0x5D, 0x1D, 0x5D], // ]
|
||||
0x5E: [0x5E, 0x1E, 0x5E], // ^
|
||||
0x5F: [0x5F, 0x1F, 0x5F], // _
|
||||
|
||||
|
||||
// Stray keys
|
||||
0xBA: [0x3B, 0x3B, 0x3A], // ; - :
|
||||
0xBB: [0x3D, 0x3D, 0x2B], // = - +
|
||||
@ -132,35 +130,35 @@ function KeyBoard(io) {
|
||||
0xDB: [0x5B, 0x5B, 0x5B], // [
|
||||
0xDC: [0x5C, 0x5C, 0x5C], // \
|
||||
0xDD: [0x5D, 0x5D, 0x5D], // ]
|
||||
0xDE: [0x27, 0x27, 0x22], // ' - "
|
||||
|
||||
0xDE: [0x27, 0x27, 0x22], // ' - '
|
||||
|
||||
0xFF: [0xFF, 0xFF, 0xFF] // No comma line
|
||||
};
|
||||
|
||||
var keys =
|
||||
|
||||
var keys =
|
||||
[[['1','2','3','4','5','6','7','8','9','0',':','-','RESET'],
|
||||
['ESC','Q','W','E','R','T','Y','U','I','O','P','REPT','RETURN'],
|
||||
['CTRL','A','S','D','F','G','H','J','K','L',';','←','→'],
|
||||
['SHIFT','Z','X','C','V','B','N','M',',','.','/','SHIFT'],
|
||||
['POWER', ' ']],
|
||||
[['!','"','#','$','%','&',"'",'(',')','0','*','=','RESET'],
|
||||
[['!','"','#','$','%','&','\'','(',')','0','*','=','RESET'],
|
||||
['ESC','Q','W','E','R','T','Y','U','I','O','@','REPT','RETURN'],
|
||||
['CTRL','A','S','D','F','BELL','H','J','K','L','+','←','→'],
|
||||
['SHIFT','Z','X','C','V','B','^',']','<','>','?','SHIFT'],
|
||||
['POWER', ' ']]];
|
||||
|
||||
|
||||
var shifted = false;
|
||||
var controlled = false;
|
||||
|
||||
|
||||
return {
|
||||
mapKeyEvent: function keyboard_mapKeyEvent(evt) {
|
||||
var code = evt.keyCode;
|
||||
|
||||
|
||||
if (code in keymap) {
|
||||
return keymap[code][evt.shiftKey ? 2 : (evt.ctrlKey ? 1 : 0)];
|
||||
}
|
||||
|
||||
debug("Unhandled key = " + toHex(code));
|
||||
|
||||
debug('Unhandled key = ' + toHex(code));
|
||||
return 0xFF;
|
||||
},
|
||||
|
||||
@ -168,125 +166,125 @@ function KeyBoard(io) {
|
||||
shifted = down;
|
||||
if (down) {
|
||||
io.buttonDown(2);
|
||||
$("#keyboard .key-SHIFT").addClass("active");
|
||||
$('#keyboard .key-SHIFT').addClass('active');
|
||||
} else {
|
||||
io.buttonUp(2);
|
||||
$("#keyboard .key-SHIFT").removeClass("active");
|
||||
$('#keyboard .key-SHIFT').removeClass('active');
|
||||
}
|
||||
},
|
||||
|
||||
controlKey: function keyboard_controlKey(down) {
|
||||
controlled = down;
|
||||
if (down) {
|
||||
$("#keyboard .key-CTRL").addClass("active");
|
||||
$('#keyboard .key-CTRL').addClass('active');
|
||||
} else {
|
||||
$("#keyboard .key-CTRL").removeClass("active");
|
||||
$('#keyboard .key-CTRL').removeClass('active');
|
||||
}
|
||||
},
|
||||
|
||||
create: function keyboard_create(kb) {
|
||||
var x, y, row, key, key1, key2, label, label1, label2;
|
||||
|
||||
|
||||
kb.disableSelection();
|
||||
|
||||
function buildLabel(k) {
|
||||
var span = $("<span>" + k + "</span>");
|
||||
var span = $('<span>' + k + '</span>');
|
||||
if (k.length > 1 && k.substr(0,1) != '&')
|
||||
span.addClass("small");
|
||||
span.addClass('small');
|
||||
return span;
|
||||
}
|
||||
|
||||
function _mouseup(ev) {
|
||||
$(ev.currentTarget).removeClass("pressed");
|
||||
$(ev.currentTarget).removeClass('pressed');
|
||||
}
|
||||
|
||||
function _mousedown(ev) {
|
||||
$(ev.currentTarget).addClass("pressed");
|
||||
var key = $(ev.currentTarget).data(shifted ? "key2" : "key1");
|
||||
$(ev.currentTarget).addClass('pressed');
|
||||
var key = $(ev.currentTarget).data(shifted ? 'key2' : 'key1');
|
||||
switch (key) {
|
||||
case "BELL":
|
||||
key = "G";
|
||||
case 'BELL':
|
||||
key = 'G';
|
||||
break;
|
||||
case "RETURN":
|
||||
key = "\r";
|
||||
case 'RETURN':
|
||||
key = '\r';
|
||||
break;
|
||||
case "←":
|
||||
key = "\010";
|
||||
case '←':
|
||||
key = '\010';
|
||||
break;
|
||||
case "→":
|
||||
key = "\025";
|
||||
case '→':
|
||||
key = '\025';
|
||||
break;
|
||||
case " ":
|
||||
key = " ";
|
||||
case ' ':
|
||||
key = ' ';
|
||||
break;
|
||||
case "ESC":
|
||||
key = "\033";
|
||||
case 'ESC':
|
||||
key = '\033';
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (key.length > 1) {
|
||||
switch (key) {
|
||||
case "SHIFT":
|
||||
case 'SHIFT':
|
||||
shifted = !shifted;
|
||||
$("#keyboard .key-SHIFT").toggleClass("active");
|
||||
$('#keyboard .key-SHIFT').toggleClass('active');
|
||||
break;
|
||||
case "CTRL":
|
||||
case 'CTRL':
|
||||
controlled = !controlled;
|
||||
$("#keyboard .key-CTRL").toggleClass("active");
|
||||
$('#keyboard .key-CTRL').toggleClass('active');
|
||||
break;
|
||||
case "RESET":
|
||||
case 'RESET':
|
||||
reset();
|
||||
break;
|
||||
case "POWER":
|
||||
if (window.confirm("Power Cycle?"))
|
||||
case 'POWER':
|
||||
if (window.confirm('Power Cycle?'))
|
||||
window.location.reload();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (controlled && key >= "@" && key <= "_") {
|
||||
if (controlled && key >= '@' && key <= '_') {
|
||||
io.keyDown(key.charCodeAt(0) - 0x40);
|
||||
} else {
|
||||
io.keyDown(key.charCodeAt(0));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (y = 0; y < 5; y++) {
|
||||
row = $("<div class='row row" + y + "'/>");
|
||||
row = $('<div class="row row' + y + '"/>');
|
||||
kb.append(row);
|
||||
for (x = 0; x < keys[0][y].length; x++) {
|
||||
key1 = keys[0][y][x];
|
||||
key2 = keys[1][y][x];
|
||||
|
||||
label = $("<div />");
|
||||
label = $('<div />');
|
||||
label1 = buildLabel(key1);
|
||||
label2 = buildLabel(key2);
|
||||
|
||||
key = $("<div class='key'>");
|
||||
key.addClass("key-" + key1.replace(/[&;]/g,""));
|
||||
key = $('<div class="key">');
|
||||
key.addClass('key-' + key1.replace(/[&;]/g,''));
|
||||
|
||||
if (key1.length > 1)
|
||||
key.addClass("vcenter");
|
||||
key.addClass('vcenter');
|
||||
|
||||
if (key1 != key2) {
|
||||
key.addClass("key-" + key2.replace(/[&;]/g,""));
|
||||
key.addClass('key-' + key2.replace(/[&;]/g,''));
|
||||
label.append(label2);
|
||||
label.append("<br/>");
|
||||
label.append('<br/>');
|
||||
}
|
||||
label.append(label1);
|
||||
key.append(label);
|
||||
key.data({"key1": key1, "key2": key2});
|
||||
key.data({'key1': key1, 'key2': key2});
|
||||
|
||||
if (window.ontouchstart === undefined) {
|
||||
key.bind("mousedown", _mousedown);
|
||||
key.bind("mouseup mouseout", _mouseup);
|
||||
key.bind('mousedown', _mousedown);
|
||||
key.bind('mouseup mouseout', _mouseup);
|
||||
} else {
|
||||
key.bind("touchstart", _mousedown);
|
||||
key.bind("touchend touchleave", _mouseup);
|
||||
key.bind('touchstart', _mousedown);
|
||||
key.bind('touchend touchleave', _mouseup);
|
||||
}
|
||||
row.append(key);
|
||||
}
|
||||
@ -294,4 +292,3 @@ function KeyBoard(io) {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* -*- mode: JavaScript; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* Copyright 2010-2013 Will Scullin <scullin@scullinsteel.com>
|
||||
|
||||
/* Copyright 2010-2016 Will Scullin <scullin@scullinsteel.com>
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software and its
|
||||
* documentation for any purpose is hereby granted without fee, provided that
|
||||
@ -18,46 +18,46 @@ function KeyBoard(io) {
|
||||
// keycode: [plain, cntl, shift]
|
||||
var keymap = {
|
||||
// Most of these won't happen
|
||||
0x00: [0x00, 0x00, 0x00], //
|
||||
0x01: [0x01, 0x01, 0x01], //
|
||||
0x02: [0x02, 0x02, 0x02], //
|
||||
0x03: [0x03, 0x03, 0x03], //
|
||||
0x04: [0x04, 0x04, 0x04], //
|
||||
0x05: [0x05, 0x05, 0x05], //
|
||||
0x06: [0x06, 0x06, 0x06], //
|
||||
0x07: [0x07, 0x07, 0x07], //
|
||||
0x00: [0x00, 0x00, 0x00], //
|
||||
0x01: [0x01, 0x01, 0x01], //
|
||||
0x02: [0x02, 0x02, 0x02], //
|
||||
0x03: [0x03, 0x03, 0x03], //
|
||||
0x04: [0x04, 0x04, 0x04], //
|
||||
0x05: [0x05, 0x05, 0x05], //
|
||||
0x06: [0x06, 0x06, 0x06], //
|
||||
0x07: [0x07, 0x07, 0x07], //
|
||||
0x08: [0x7F, 0x7F, 0x7F], // BS/DELETE
|
||||
0x09: [0x09, 0x09, 0x09], // TAB
|
||||
0x0A: [0x0A, 0x0A, 0x0A], //
|
||||
0x0B: [0x0B, 0x0B, 0x0B], //
|
||||
0x0C: [0x0C, 0x0C, 0x0C], //
|
||||
0x0A: [0x0A, 0x0A, 0x0A], //
|
||||
0x0B: [0x0B, 0x0B, 0x0B], //
|
||||
0x0C: [0x0C, 0x0C, 0x0C], //
|
||||
0x0D: [0x0D, 0x0D, 0x0D], // CR
|
||||
0x0E: [0x0E, 0x0E, 0x0E], //
|
||||
0x0F: [0x0F, 0x0F, 0x0F], //
|
||||
|
||||
0x0E: [0x0E, 0x0E, 0x0E], //
|
||||
0x0F: [0x0F, 0x0F, 0x0F], //
|
||||
|
||||
0x10: [0xff, 0xff, 0xff], // SHIFT
|
||||
0x11: [0xff, 0xff, 0xff], // CTRL
|
||||
0x12: [0xff, 0xff, 0xff], // ALT/OPTION
|
||||
0x13: [0x13, 0x13, 0x13], //
|
||||
0x14: [0x14, 0x14, 0x14], //
|
||||
0x15: [0x15, 0x15, 0x15], //
|
||||
0x16: [0x16, 0x16, 0x16], //
|
||||
0x17: [0x17, 0x17, 0x18], //
|
||||
0x18: [0x18, 0x18, 0x18], //
|
||||
0x19: [0x19, 0x19, 0x19], //
|
||||
0x1A: [0x1A, 0x1A, 0x1A], //
|
||||
0x13: [0x13, 0x13, 0x13], //
|
||||
0x14: [0x14, 0x14, 0x14], //
|
||||
0x15: [0x15, 0x15, 0x15], //
|
||||
0x16: [0x16, 0x16, 0x16], //
|
||||
0x17: [0x17, 0x17, 0x18], //
|
||||
0x18: [0x18, 0x18, 0x18], //
|
||||
0x19: [0x19, 0x19, 0x19], //
|
||||
0x1A: [0x1A, 0x1A, 0x1A], //
|
||||
0x1B: [0x1B, 0x1B, 0x1B], // ESC
|
||||
0x1C: [0x1C, 0x1C, 0x1C], //
|
||||
0x1D: [0x1D, 0x1D, 0x1D], //
|
||||
0x1E: [0x1E, 0x1E, 0x1E], //
|
||||
0x1F: [0x1F, 0x1F, 0x1F], //
|
||||
|
||||
0x1C: [0x1C, 0x1C, 0x1C], //
|
||||
0x1D: [0x1D, 0x1D, 0x1D], //
|
||||
0x1E: [0x1E, 0x1E, 0x1E], //
|
||||
0x1F: [0x1F, 0x1F, 0x1F], //
|
||||
|
||||
// Most of these besides space won't happen
|
||||
0x20: [0x20, 0x20, 0x20], //
|
||||
0x21: [0x21, 0x21, 0x21], //
|
||||
0x22: [0x22, 0x22, 0x22], //
|
||||
0x23: [0x23, 0x23, 0x23], //
|
||||
0x24: [0x24, 0x24, 0x24], //
|
||||
0x20: [0x20, 0x20, 0x20], //
|
||||
0x21: [0x21, 0x21, 0x21], //
|
||||
0x22: [0x22, 0x22, 0x22], //
|
||||
0x23: [0x23, 0x23, 0x23], //
|
||||
0x24: [0x24, 0x24, 0x24], //
|
||||
0x25: [0x08, 0x08, 0x08], // <- left
|
||||
0x26: [0x0B, 0x0B, 0x0B], // ^ up
|
||||
0x27: [0x15, 0x15, 0x15], // -> right
|
||||
@ -69,7 +69,7 @@ function KeyBoard(io) {
|
||||
0x2D: [0x2D, 0x2D, 0x5F], // - - _
|
||||
0x2E: [0x2E, 0x2E, 0x3E], // . - >
|
||||
0x2F: [0x2F, 0x2F, 0x3F], // / - ?
|
||||
|
||||
|
||||
0x30: [0x30, 0x30, 0x29], // 0 - )
|
||||
0x31: [0x31, 0x31, 0x21], // 1 - !
|
||||
0x32: [0x32, 0x00, 0x40], // 2 - @
|
||||
@ -86,7 +86,7 @@ function KeyBoard(io) {
|
||||
0x3D: [0x3D, 0x3D, 0x2B], // = - +
|
||||
0x3E: [0x3E, 0x3E, 0x3E], // >
|
||||
0x3F: [0x3F, 0x3F, 0x3F], // ?
|
||||
|
||||
|
||||
// Alpha and control
|
||||
0x40: [0x40, 0x00, 0x40], // @
|
||||
0x41: [0x61, 0x01, 0x41], // A
|
||||
@ -99,12 +99,12 @@ function KeyBoard(io) {
|
||||
0x48: [0x68, 0x08, 0x48], // H
|
||||
0x49: [0x69, 0x09, 0x49], // I - TAB
|
||||
0x4A: [0x6A, 0x0A, 0x4A], // J - NL
|
||||
0x4B: [0x6B, 0x0B, 0x4B], // K - VT
|
||||
0x4B: [0x6B, 0x0B, 0x4B], // K - VT
|
||||
0x4C: [0x6C, 0x0C, 0x4C], // L
|
||||
0x4D: [0x6D, 0x0D, 0x4D], // M - CR
|
||||
0x4E: [0x6E, 0x0E, 0x4E], // N
|
||||
0x4F: [0x6F, 0x0F, 0x4F], // O
|
||||
|
||||
|
||||
0x50: [0x70, 0x10, 0x50], // P
|
||||
0x51: [0x71, 0x11, 0x51], // Q
|
||||
0x52: [0x72, 0x12, 0x52], // R
|
||||
@ -119,7 +119,7 @@ function KeyBoard(io) {
|
||||
0x5B: [0xFF, 0xFF, 0xFF], // Left window
|
||||
0x5C: [0xFF, 0xFF, 0xFF], // Right window
|
||||
0x5D: [0xFF, 0xFF, 0xFF], // Select
|
||||
0x5E: [0x5E, 0x1E, 0x5E], //
|
||||
0x5E: [0x5E, 0x1E, 0x5E], //
|
||||
0x5F: [0x5F, 0x1F, 0x5F], // _
|
||||
|
||||
// Numeric pad
|
||||
@ -139,7 +139,7 @@ function KeyBoard(io) {
|
||||
0x6D: [0x2D, 0x2D, 0x2D], // -
|
||||
0x6E: [0x2E, 0x2E, 0x2E], // .
|
||||
0x6F: [0x2F, 0x2F, 0x39], // /
|
||||
|
||||
|
||||
// Stray keys
|
||||
0xBA: [0x3B, 0x3B, 0x3A], // ; - :
|
||||
0xBB: [0x3D, 0x3D, 0x2B], // = - +
|
||||
@ -151,23 +151,23 @@ function KeyBoard(io) {
|
||||
0xDB: [0x5B, 0x5B, 0x7B], // [
|
||||
0xDC: [0x5C, 0x5C, 0x7C], // \
|
||||
0xDD: [0x5D, 0x5D, 0x7D], // ]
|
||||
0xDE: [0x27, 0x22, 0x22], // ' - "
|
||||
|
||||
0xDE: [0x27, 0x22, 0x22], // ' - '
|
||||
|
||||
0xFF: [0xFF, 0xFF, 0xFF] // No comma line
|
||||
};
|
||||
|
||||
var keys =
|
||||
var keys =
|
||||
[[['ESC','1','2','3','4','5','6','7','8','9','0','-','=','DELETE'],
|
||||
['TAB','Q','W','E','R','T','Y','U','I','O','P','[',']','\\'],
|
||||
['CTRL','A','S','D','F','G','H','J','K','L',';','\'','RETURN'],
|
||||
['CTRL','A','S','D','F','G','H','J','K','L',';','"','RETURN'],
|
||||
['SHIFT','Z','X','C','V','B','N','M',',','.','/','SHIFT'],
|
||||
['LOCK','`','POW','OPEN_APPLE',' ','CLOSED_APPLE','←','→','↓','↑']],
|
||||
[['ESC','!','@','#','$','%','^','&',"*",'(',')','_','+','DELETE'],
|
||||
[['ESC','!','@','#','$','%','^','&','*','(',')','_','+','DELETE'],
|
||||
['TAB','Q','W','E','R','T','Y','U','I','O','P','{','}','|'],
|
||||
['CTRL','A','S','D','F','G','H','J','K','L',':','"','RETURN'],
|
||||
['CTRL','A','S','D','F','G','H','J','K','L',':','\'','RETURN'],
|
||||
['SHIFT','Z','X','C','V','B','N','M','<','>','?','SHIFT'],
|
||||
['CAPS','~','POW','OPEN_APPLE',' ','CLOSED_APPLE','←','→','↓','↑']]];
|
||||
|
||||
|
||||
var shifted = false;
|
||||
var controlled = false;
|
||||
var capslocked = true;
|
||||
@ -177,15 +177,15 @@ function KeyBoard(io) {
|
||||
return {
|
||||
mapKeyEvent: function keyboard_mapKeyEvent(evt) {
|
||||
var code = evt.keyCode, key = 0xff;
|
||||
|
||||
|
||||
if (code in keymap) {
|
||||
key = keymap[code][evt.shiftKey ? 2 : (evt.ctrlKey ? 1 : 0)];
|
||||
if (capslocked && key >= 0x61 && key <= 0x7A)
|
||||
key -= 0x20;
|
||||
} else {
|
||||
debug("Unhandled key = " + toHex(code));
|
||||
debug('Unhandled key = ' + toHex(code));
|
||||
}
|
||||
|
||||
|
||||
return key;
|
||||
},
|
||||
|
||||
@ -193,19 +193,19 @@ function KeyBoard(io) {
|
||||
shifted = down;
|
||||
if (down) {
|
||||
io.buttonDown(2);
|
||||
$("#keyboard .key-SHIFT").addClass("active");
|
||||
$('#keyboard .key-SHIFT').addClass('active');
|
||||
} else {
|
||||
io.buttonUp(2);
|
||||
$("#keyboard .key-SHIFT").removeClass("active");
|
||||
$('#keyboard .key-SHIFT').removeClass('active');
|
||||
}
|
||||
},
|
||||
|
||||
controlKey: function keyboard_controlKey(down) {
|
||||
controlled = down;
|
||||
if (down) {
|
||||
$("#keyboard .key-CTRL").addClass("active");
|
||||
$('#keyboard .key-CTRL').addClass('active');
|
||||
} else {
|
||||
$("#keyboard .key-CTRL").removeClass("active");
|
||||
$('#keyboard .key-CTRL').removeClass('active');
|
||||
}
|
||||
},
|
||||
|
||||
@ -213,10 +213,10 @@ function KeyBoard(io) {
|
||||
commanded = down;
|
||||
if (down) {
|
||||
io.buttonDown(0);
|
||||
$("#keyboard .key-OPEN_APPLE").addClass("active");
|
||||
$('#keyboard .key-OPEN_APPLE').addClass('active');
|
||||
} else {
|
||||
io.buttonUp(0);
|
||||
$("#keyboard .key-OPEN_APPLE").removeClass("active");
|
||||
$('#keyboard .key-OPEN_APPLE').removeClass('active');
|
||||
}
|
||||
},
|
||||
|
||||
@ -224,106 +224,106 @@ function KeyBoard(io) {
|
||||
optioned = down;
|
||||
if (down) {
|
||||
io.buttonDown(1);
|
||||
$("#keyboard .key-CLOSED_APPLE").addClass("active");
|
||||
$('#keyboard .key-CLOSED_APPLE').addClass('active');
|
||||
} else {
|
||||
io.buttonUp(1);
|
||||
$("#keyboard .key-CLOSED_APPLE").removeClass("active");
|
||||
$('#keyboard .key-CLOSED_APPLE').removeClass('active');
|
||||
}
|
||||
},
|
||||
|
||||
capslockKey: function keyboard_caplockKey(down) {
|
||||
capslocked = down;
|
||||
if (down) {
|
||||
$("#keyboard .key-LOCK").addClass("active");
|
||||
$('#keyboard .key-LOCK').addClass('active');
|
||||
} else {
|
||||
$("#keyboard .key-LOCK").removeClass("active");
|
||||
$('#keyboard .key-LOCK').removeClass('active');
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
create: function keyboard_create(kb) {
|
||||
var x, y, row, key, key1, key2, label, label1, label2, self = this;
|
||||
|
||||
|
||||
kb.disableSelection();
|
||||
|
||||
function buildLabel(k) {
|
||||
var span = $("<span>" + k + "</span>");
|
||||
var span = $('<span>' + k + '</span>');
|
||||
if (k.length > 1 && k.substr(0,1) != '&')
|
||||
span.addClass("small");
|
||||
span.addClass('small');
|
||||
return span;
|
||||
}
|
||||
|
||||
function _mouseup(ev) {
|
||||
$(ev.currentTarget).removeClass("pressed");
|
||||
$(ev.currentTarget).removeClass('pressed');
|
||||
}
|
||||
|
||||
function _mousedown(ev) {
|
||||
$(this).addClass("pressed");
|
||||
var key = $(ev.currentTarget).data(shifted ? "key2" : "key1");
|
||||
$(this).addClass('pressed');
|
||||
var key = $(ev.currentTarget).data(shifted ? 'key2' : 'key1');
|
||||
switch (key) {
|
||||
case "BELL":
|
||||
key = "G";
|
||||
case 'BELL':
|
||||
key = 'G';
|
||||
break;
|
||||
case "RETURN":
|
||||
key = "\r";
|
||||
case 'RETURN':
|
||||
key = '\r';
|
||||
break;
|
||||
case "TAB":
|
||||
key = "\t";
|
||||
case 'TAB':
|
||||
key = '\t';
|
||||
break;
|
||||
case "DELETE":
|
||||
key = "\0177";
|
||||
case 'DELETE':
|
||||
key = '\0177';
|
||||
break;
|
||||
case "←":
|
||||
key = "\010";
|
||||
case '←':
|
||||
key = '\010';
|
||||
break;
|
||||
case "→":
|
||||
key = "\025";
|
||||
case '→':
|
||||
key = '\025';
|
||||
break;
|
||||
case "↓":
|
||||
key = "\012";
|
||||
case '↓':
|
||||
key = '\012';
|
||||
break;
|
||||
case "↑":
|
||||
key = "\013";
|
||||
case '↑':
|
||||
key = '\013';
|
||||
break;
|
||||
case " ":
|
||||
key = " ";
|
||||
case ' ':
|
||||
key = ' ';
|
||||
break;
|
||||
case "ESC":
|
||||
key = "\033";
|
||||
case 'ESC':
|
||||
key = '\033';
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (key.length > 1) {
|
||||
switch (key) {
|
||||
case "SHIFT":
|
||||
case 'SHIFT':
|
||||
self.shiftKey(!shifted);
|
||||
break;
|
||||
case "CTRL":
|
||||
case 'CTRL':
|
||||
self.controlKey(!controlled);
|
||||
break;
|
||||
case "CAPS":
|
||||
case "LOCK":
|
||||
case 'CAPS':
|
||||
case 'LOCK':
|
||||
self.capslockKey(!capslocked);
|
||||
break;
|
||||
case "POW":
|
||||
if (window.confirm("Power Cycle?"))
|
||||
case 'POW':
|
||||
if (window.confirm('Power Cycle?'))
|
||||
window.location.reload();
|
||||
break;
|
||||
case "OPEN_APPLE":
|
||||
case 'OPEN_APPLE':
|
||||
self.commandKey(!commanded);
|
||||
break;
|
||||
case "CLOSED_APPLE":
|
||||
case 'CLOSED_APPLE':
|
||||
self.optionKey(!optioned);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (controlled && key >= "@" && key <= "_") {
|
||||
if (controlled && key >= '@' && key <= '_') {
|
||||
io.keyDown(key.charCodeAt(0) - 0x40);
|
||||
} else if (!shifted && !capslocked &&
|
||||
} else if (!shifted && !capslocked &&
|
||||
key >= 'A' && key <= 'Z') {
|
||||
io.keyDown(key.charCodeAt(0) + 0x20);
|
||||
} else {
|
||||
@ -333,43 +333,43 @@ function KeyBoard(io) {
|
||||
}
|
||||
|
||||
for (y = 0; y < 5; y++) {
|
||||
row = $("<div class='row row" + y + "e'/>");
|
||||
row = $('<div class="row row' + y + 'e"/>');
|
||||
kb.append(row);
|
||||
for (x = 0; x < keys[0][y].length; x++) {
|
||||
key1 = keys[0][y][x];
|
||||
key2 = keys[1][y][x];
|
||||
|
||||
label = $("<div />");
|
||||
label = $('<div />');
|
||||
label1 = buildLabel(key1);
|
||||
label2 = buildLabel(key2);
|
||||
|
||||
key = $("<div class='key'>");
|
||||
key.addClass("key-" + key1.replace(/[&#;]/g,""));
|
||||
key = $('<div class="key">');
|
||||
key.addClass('key-' + key1.replace(/[&#;]/g,''));
|
||||
|
||||
if (key1.length > 1) {
|
||||
if (key1 == "LOCK")
|
||||
key.addClass("vcenter2");
|
||||
if (key1 == 'LOCK')
|
||||
key.addClass('vcenter2');
|
||||
else
|
||||
key.addClass("vcenter");
|
||||
key.addClass('vcenter');
|
||||
}
|
||||
if (key1 != key2) {
|
||||
key.addClass("key-" + key2.replace(/[&;]/g,""));
|
||||
key.addClass('key-' + key2.replace(/[&;]/g,''));
|
||||
label.append(label2);
|
||||
label.append("<br/>");
|
||||
label.append('<br/>');
|
||||
}
|
||||
if (key1 == "LOCK")
|
||||
key.addClass("active");
|
||||
if (key1 == 'LOCK')
|
||||
key.addClass('active');
|
||||
|
||||
label.append(label1);
|
||||
key.append(label);
|
||||
key.data({"key1": key1, "key2": key2});
|
||||
key.data({'key1': key1, 'key2': key2});
|
||||
|
||||
if (window.ontouchstart === undefined) {
|
||||
key.bind("mousedown", _mousedown);
|
||||
key.bind("mouseup mouseout", _mouseup);
|
||||
key.bind('mousedown', _mousedown);
|
||||
key.bind('mouseup mouseout', _mouseup);
|
||||
} else {
|
||||
key.bind("touchstart", _mousedown);
|
||||
key.bind("touchend touchleave", _mouseup);
|
||||
key.bind('touchstart', _mousedown);
|
||||
key.bind('touchend touchleave', _mouseup);
|
||||
}
|
||||
|
||||
row.append(key);
|
||||
@ -380,4 +380,3 @@ function KeyBoard(io) {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,3 @@
|
||||
/*jshint browser:true */
|
||||
/*exported Printer */
|
||||
|
||||
function Printer() {
|
||||
@ -6,21 +5,20 @@ function Printer() {
|
||||
return {
|
||||
putChar: function(val) {
|
||||
if (!_printer || _printer.closed) {
|
||||
_printer = window.open("", "_blank","toolbar=0,location=0");
|
||||
_printer.document.title = "Printer";
|
||||
_printer.document.write("<div style='font: 12px courier'>");
|
||||
_printer.document.write("<span>");
|
||||
_printer = window.open('', '_blank','toolbar=0,location=0');
|
||||
_printer.document.title = 'Printer';
|
||||
_printer.document.write('<div style="font: 12px courier">');
|
||||
_printer.document.write('<span>');
|
||||
window.focus();
|
||||
}
|
||||
var c = String.fromCharCode(val & 0x7f);
|
||||
if (c == '\r') {
|
||||
_printer.document.write("<br /></span>");
|
||||
_printer.document.write('<br /></span>');
|
||||
} else if (c == ' ') {
|
||||
_printer.document.write(" ");
|
||||
_printer.document.write(' ');
|
||||
} else {
|
||||
_printer.document.write(c);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
59
js/util.js
59
js/util.js
@ -1,5 +1,4 @@
|
||||
/* -*- mode: JavaScript; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* Copyright 2010-2013 Will Scullin <scullin@scullinsteel.com>
|
||||
/* Copyright 2010-2016 Will Scullin <scullin@scullinsteel.com>
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software and its
|
||||
* documentation for any purpose is hereby granted without fee, provided that
|
||||
@ -10,8 +9,10 @@
|
||||
* implied warranty.
|
||||
*/
|
||||
|
||||
/*jshint rhino:true, browser: true, devel: true */
|
||||
/*exported allocMem, allocMemPages, bytify, debug, toHex, toBinary, extend, gup, hup, each */
|
||||
/*eslint no-console: 0*/
|
||||
/*exported allocMemPages, bytify, debug, each extend, gup, hup, toBinary, toHex
|
||||
*/
|
||||
/*global Uint8Array: false */
|
||||
|
||||
if (!Date.now) {
|
||||
Date.now = function now() {
|
||||
@ -19,8 +20,8 @@ if (!Date.now) {
|
||||
};
|
||||
}
|
||||
|
||||
var hex_digits = "0123456789ABCDEF";
|
||||
var bin_digits = "01";
|
||||
var hex_digits = '0123456789ABCDEF';
|
||||
var bin_digits = '01';
|
||||
|
||||
function allocMem(size) {
|
||||
var result;
|
||||
@ -46,16 +47,14 @@ function bytify(ary) {
|
||||
|
||||
function extend(ary1, ary2) {
|
||||
ary2.forEach(function(val) {
|
||||
ary1.push(val);
|
||||
ary1.push(val);
|
||||
});
|
||||
return ary1;
|
||||
}
|
||||
|
||||
function debug(msg) {
|
||||
if (typeof(console) != 'undefined' && 'log' in console) {
|
||||
console.log(msg);
|
||||
} else if (typeof(environment) == 'object') { // rhino shell
|
||||
print(msg);
|
||||
function debug() {
|
||||
if (typeof console != 'undefined' && 'log' in console) {
|
||||
console.log.apply(console, arguments);
|
||||
}
|
||||
}
|
||||
|
||||
@ -63,7 +62,7 @@ function toHex(v, n) {
|
||||
if (!n) {
|
||||
n = v < 256 ? 2 : 4;
|
||||
}
|
||||
var result = "";
|
||||
var result = '';
|
||||
for (var idx = 0; idx < n; idx++) {
|
||||
result = hex_digits[v & 0x0f] + result;
|
||||
v >>= 4;
|
||||
@ -72,7 +71,7 @@ function toHex(v, n) {
|
||||
}
|
||||
|
||||
function toBinary(v) {
|
||||
var result = "";
|
||||
var result = '';
|
||||
for (var idx = 0; idx < 8; idx++) {
|
||||
result = bin_digits[v & 0x01] + result;
|
||||
v >>= 1;
|
||||
@ -83,25 +82,25 @@ function toBinary(v) {
|
||||
// From http://www.netlobo.com/url_query_string_javascript.html
|
||||
function gup( name )
|
||||
{
|
||||
name = name.replace(/[\[]/,"\\[").replace(/[\]]/,"\\]");
|
||||
var regexS = "[\\?&]"+name+"=([^&#]*)";
|
||||
var regex = new RegExp( regexS );
|
||||
var results = regex.exec( window.location.href );
|
||||
if( !results )
|
||||
return "";
|
||||
else
|
||||
return results[1];
|
||||
}
|
||||
|
||||
function hup() {
|
||||
var regex = new RegExp("#(.*)");
|
||||
var results = regex.exec(window.location.hash);
|
||||
if ( !results )
|
||||
return "";
|
||||
name = name.replace(/[\[]/,'\\[').replace(/[\]]/,'\\]');
|
||||
var regexS = '[\\?&]'+name+'=([^&#]*)';
|
||||
var regex = new RegExp( regexS );
|
||||
var results = regex.exec( window.location.href );
|
||||
if( !results )
|
||||
return '';
|
||||
else
|
||||
return results[1];
|
||||
}
|
||||
|
||||
|
||||
function hup() {
|
||||
var regex = new RegExp('#(.*)');
|
||||
var results = regex.exec(window.location.hash);
|
||||
if ( !results )
|
||||
return '';
|
||||
else
|
||||
return results[1];
|
||||
}
|
||||
|
||||
function keys(obj) {
|
||||
var result = [];
|
||||
for (var key in obj) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
#!/usr/bin/perl -w
|
||||
# Copyright 2010-2013 Will Scullin <scullin@scullinsteel.com>
|
||||
# Copyright 2010-2016 Will Scullin <scullin@scullinsteel.com>
|
||||
#
|
||||
# Permission to use, copy, modify, distribute, and sell this software and its
|
||||
# documentation for any purpose is hereby granted without fee, provided that
|
||||
|
@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env perl -w
|
||||
# Copyright 2010-2013 Will Scullin <scullin@scullinsteel.com>
|
||||
# Copyright 2010-2016 Will Scullin <scullin@scullinsteel.com>
|
||||
#
|
||||
# Permission to use, copy, modify, distribute, and sell this software and its
|
||||
# documentation for any purpose is hereby granted without fee, provided that
|
||||
|
Loading…
Reference in New Issue
Block a user