2015-08-01 06:21:16 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* AppleIIGo
|
|
|
|
* The Java Apple II Emulator
|
2015-08-01 07:49:51 +00:00
|
|
|
* Copyright 2009 by Nick Westgate (Nick.Westgate@gmail.com)
|
|
|
|
* Copyright 2006 by Marc S. Ressl (ressl@lonetree.com)
|
|
|
|
* Released under the GNU General Public License version 2
|
|
|
|
* See http://www.gnu.org/licenses/
|
2015-08-01 07:09:49 +00:00
|
|
|
*
|
|
|
|
* Change list:
|
|
|
|
*
|
2015-08-01 07:49:51 +00:00
|
|
|
* Version 1.0.7 - changes by Nick:
|
|
|
|
* - fixed disk emulation bug (sense write protect entered write mode)
|
|
|
|
* - now honour diskWritable parameter (but writing is not implemented)
|
|
|
|
* - support meta tag for volume number in disk filename eg: Vol2_Meta_DV2.dsk
|
|
|
|
* - added isPaddleEnabled parameter
|
|
|
|
* - exposed setPaddleEnabled(boolean value), setPaddleInverted(boolean value)
|
|
|
|
* - paddle values are now 255 at startup (ie. correct if disabled/not present)
|
|
|
|
* - minor AppleSpeaker fix (SourceDataLine.class) thanks to William Halliburton
|
2015-08-01 07:42:08 +00:00
|
|
|
*
|
2015-08-01 07:49:51 +00:00
|
|
|
* Version 1.0.6 - changes by Nick:
|
2015-08-01 07:42:08 +00:00
|
|
|
* - exposed F3/F4 disk swapping method: cycleDisk(int driveNumber)
|
|
|
|
* - exposed reset() method
|
|
|
|
* - exposed setSpeed(int value) method
|
|
|
|
*
|
2015-08-01 07:38:06 +00:00
|
|
|
* Version 1.0.5 - changes by Nick:
|
|
|
|
* - added support for .NIB (nibble) disk images (also inside ZIP archives)
|
|
|
|
* - added disk speedup hacks for DOS (expect ~2x faster reads)
|
|
|
|
*
|
2015-08-01 07:29:04 +00:00
|
|
|
* Version 1.0.4 - changes by Nick:
|
|
|
|
* - added support for .PO (ProDOS order) disk images (also inside ZIP archives)
|
|
|
|
* - added Command key for Closed-Apple on Mac OS X
|
|
|
|
* - added Home and End keys for Open-Apple and Closed-Apple on full keyboards
|
|
|
|
*
|
2015-08-01 07:21:54 +00:00
|
|
|
* Version 1.0.3 - changes by Nick:
|
|
|
|
* - fixed paddle values for scaled display window
|
|
|
|
* - added "digital" joystick support via numeric keypad arrows
|
|
|
|
* - added Left-Alt and Right-Alt keys for Open-Apple and Closed-Apple
|
|
|
|
* - changed reset key from Home to Ctrl-F12 and Ctrl-Pause/Break
|
|
|
|
*
|
2015-08-01 07:09:49 +00:00
|
|
|
* Version 1.0.2 - changes by Nick:
|
|
|
|
* - improved sound sync by moving AppleSpeaker into the main thread
|
|
|
|
* - added version (F1)
|
2015-08-01 07:42:08 +00:00
|
|
|
* - added multiple disks & swapping (F3, F4)
|
2015-08-01 07:09:49 +00:00
|
|
|
* - added ZIP archive support
|
|
|
|
* - fixed HTTP disk image access bug
|
2015-08-01 06:21:16 +00:00
|
|
|
*/
|
|
|
|
|
2015-08-01 07:09:49 +00:00
|
|
|
import java.applet.Applet;
|
|
|
|
import java.awt.Graphics;
|
|
|
|
import java.awt.event.ComponentEvent;
|
|
|
|
import java.awt.event.ComponentListener;
|
|
|
|
import java.awt.event.InputEvent;
|
|
|
|
import java.awt.event.KeyEvent;
|
|
|
|
import java.awt.event.KeyListener;
|
|
|
|
import java.awt.event.MouseEvent;
|
|
|
|
import java.awt.event.MouseListener;
|
|
|
|
import java.awt.event.MouseMotionListener;
|
|
|
|
import java.io.DataInputStream;
|
|
|
|
import java.io.FileOutputStream;
|
|
|
|
import java.io.InputStream;
|
|
|
|
import java.io.OutputStream;
|
|
|
|
import java.net.MalformedURLException;
|
|
|
|
import java.net.URL;
|
|
|
|
import java.util.zip.GZIPInputStream;
|
2015-08-01 07:29:04 +00:00
|
|
|
import java.util.zip.ZipEntry;
|
2015-08-01 07:09:49 +00:00
|
|
|
import java.util.zip.ZipInputStream;
|
2015-08-01 06:21:16 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* AppleIIGo class<p>
|
|
|
|
* Connects EmAppleII, AppleCanvas
|
|
|
|
*/
|
|
|
|
public class AppleIIGo extends Applet implements KeyListener, ComponentListener,
|
|
|
|
MouseListener, MouseMotionListener {
|
2015-08-01 07:09:49 +00:00
|
|
|
|
2015-08-01 07:49:51 +00:00
|
|
|
private static final long serialVersionUID = -3302282815441501352L;
|
|
|
|
|
|
|
|
final String version = "1.0.7";
|
2015-08-01 07:09:49 +00:00
|
|
|
final String versionString = "AppleIIGo Version " + version;
|
2015-08-01 07:49:51 +00:00
|
|
|
final String metaStart = "_meta_";
|
2015-08-01 07:09:49 +00:00
|
|
|
|
2015-08-01 06:21:16 +00:00
|
|
|
// Class instances
|
|
|
|
private EmAppleII apple;
|
|
|
|
private AppleDisplay display;
|
|
|
|
private DiskII disk;
|
|
|
|
|
|
|
|
// Machine variables
|
|
|
|
private boolean isCpuPaused;
|
|
|
|
private boolean isCpuDebugEnabled;
|
|
|
|
|
|
|
|
// Keyboard variables
|
|
|
|
private boolean keyboardUppercaseOnly;
|
|
|
|
|
|
|
|
// Paddle variables
|
2015-08-01 07:49:51 +00:00
|
|
|
private boolean isPaddleEnabled;
|
2015-08-01 06:21:16 +00:00
|
|
|
private boolean isPaddleInverted;
|
|
|
|
|
2015-08-01 07:42:08 +00:00
|
|
|
// Disk variables - TODO: refactor into a class
|
2015-08-01 06:21:16 +00:00
|
|
|
private String diskDriveResource[] = new String[2];
|
|
|
|
private boolean diskWritable;
|
2015-08-01 07:42:08 +00:00
|
|
|
private String[][] diskImageNames = {{}, {}};
|
|
|
|
private int diskImageNumber[] = {0, 0};
|
2015-08-01 06:21:16 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Debug
|
|
|
|
*/
|
|
|
|
private void debug(String message) {
|
|
|
|
// System.out.println(message);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Parameters
|
|
|
|
*/
|
|
|
|
private String getAppletParameter(String parameter, String defaultValue) {
|
|
|
|
String value = getParameter(parameter);
|
|
|
|
if ((value == null) || (value.length() == 0))
|
|
|
|
return defaultValue;
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* On applet initialization
|
|
|
|
*/
|
|
|
|
public void init() {
|
|
|
|
debug("init()");
|
|
|
|
|
|
|
|
// Activate listeners
|
|
|
|
addKeyListener(this);
|
|
|
|
addMouseListener(this);
|
|
|
|
addMouseMotionListener(this);
|
|
|
|
|
|
|
|
if (getAppletParameter("displayFocusOnStart", "true").equals("true"))
|
|
|
|
addComponentListener(this);
|
|
|
|
|
|
|
|
// Initialize Apple II emulator
|
|
|
|
apple = new EmAppleII();
|
|
|
|
loadRom(getAppletParameter("cpuRom", ""));
|
|
|
|
apple.setCpuSpeed(new Integer(getAppletParameter("cpuSpeed", "1000")).intValue());
|
|
|
|
isCpuPaused = getAppletParameter("cpuPaused", "false").equals("true");
|
|
|
|
isCpuDebugEnabled = getAppletParameter("cpuDebugEnabled", "false").equals("true");
|
|
|
|
apple.setStepMode(getAppletParameter("cpuStepMode", "false").equals("true"));
|
|
|
|
|
|
|
|
// Keyboard
|
|
|
|
keyboardUppercaseOnly = getAppletParameter("keyboardUppercaseOnly", "true").equals("true");
|
|
|
|
|
2015-08-01 07:49:51 +00:00
|
|
|
// Paddles
|
|
|
|
isPaddleEnabled = getAppletParameter("paddleEnabled", "true").equals("true");
|
|
|
|
isPaddleInverted = getAppletParameter("paddleInverted", "false").equals("true");
|
|
|
|
|
2015-08-01 06:21:16 +00:00
|
|
|
// Display
|
|
|
|
display = new AppleDisplay(this, apple);
|
|
|
|
display.setScale(new Float(getAppletParameter("displayScale", "1")).floatValue());
|
|
|
|
display.setRefreshRate(new Integer(getAppletParameter("displayRefreshRate", "10")).intValue());
|
|
|
|
display.setColorMode(new Integer(getAppletParameter("displayColorMode", "0")).intValue());
|
|
|
|
display.setStatMode(getAppletParameter("displayStatMode", "false").equals("true"));
|
|
|
|
display.setGlare(getAppletParameter("displayGlare", "false").equals("true"));
|
|
|
|
|
|
|
|
// Speaker
|
2015-08-01 07:09:49 +00:00
|
|
|
apple.speaker = new AppleSpeaker(apple);
|
|
|
|
apple.speaker.setVolume(new Integer(getAppletParameter("speakerVolume", "6")).intValue());
|
2015-08-01 06:21:16 +00:00
|
|
|
|
|
|
|
// Peripherals
|
2015-08-01 07:38:06 +00:00
|
|
|
disk = new DiskII(apple);
|
2015-08-01 06:21:16 +00:00
|
|
|
apple.setPeripheral(disk, 6);
|
|
|
|
|
|
|
|
// Initialize disk drives
|
|
|
|
diskWritable = getAppletParameter("diskWritable", "false").equals("true");
|
2015-08-01 07:42:08 +00:00
|
|
|
diskImageNames[0] = getAppletParameter("diskDrive1", "").split("[|]");
|
|
|
|
diskImageNumber[0] = 0;
|
|
|
|
diskImageNames[1] = getAppletParameter("diskDrive2", "").split("[|]");
|
|
|
|
diskImageNumber[1] = 0;
|
|
|
|
mountDisk(0, diskImageNames[0][diskImageNumber[0]]);
|
|
|
|
mountDisk(1, diskImageNames[1][diskImageNumber[1]]);
|
2015-08-01 06:21:16 +00:00
|
|
|
|
|
|
|
// Start CPU
|
|
|
|
if (!isCpuPaused)
|
|
|
|
resume();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Start applet
|
|
|
|
*/
|
|
|
|
public void start() {
|
2015-08-01 07:09:49 +00:00
|
|
|
debug("AppleIIGo Version " + version);
|
2015-08-01 06:21:16 +00:00
|
|
|
debug("start()");
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Stop applet
|
|
|
|
*/
|
|
|
|
public void stop() {
|
|
|
|
debug("stop()");
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* On applet destruction
|
|
|
|
*/
|
|
|
|
public void destroy() {
|
|
|
|
debug("destroy()");
|
|
|
|
unmountDisk(0);
|
|
|
|
unmountDisk(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Public Java interface
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Javascript interface
|
|
|
|
*/
|
|
|
|
public void focus() {
|
|
|
|
debug("focus()");
|
|
|
|
requestFocus();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Pause emulator
|
|
|
|
*/
|
|
|
|
public void pause() {
|
|
|
|
debug("pause()");
|
|
|
|
isCpuPaused = true;
|
2015-08-01 07:42:08 +00:00
|
|
|
apple.setPaused(true);
|
|
|
|
display.setPaused(true);
|
|
|
|
apple.speaker.setPaused(true);
|
2015-08-01 06:21:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Resume emulator
|
|
|
|
*/
|
|
|
|
public void resume() {
|
|
|
|
debug("resume()");
|
|
|
|
isCpuPaused = false;
|
2015-08-01 07:42:08 +00:00
|
|
|
apple.speaker.setPaused(false);
|
|
|
|
display.setPaused(false);
|
|
|
|
apple.setPaused(false);
|
2015-08-01 06:21:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Restarts emulator
|
|
|
|
*/
|
|
|
|
public void restart() {
|
|
|
|
debug("restart()");
|
|
|
|
apple.restart();
|
|
|
|
}
|
2015-08-01 07:42:08 +00:00
|
|
|
|
|
|
|
public void reset() {
|
|
|
|
debug("reset()");
|
|
|
|
apple.reset();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public void setSpeed(int value) {
|
|
|
|
debug("setSpeed(" + value + ")");
|
|
|
|
try
|
|
|
|
{
|
|
|
|
pause();
|
|
|
|
this.wait(1000);
|
|
|
|
}
|
|
|
|
catch (Throwable e)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
apple.setCpuSpeed(value);
|
|
|
|
resume();
|
|
|
|
}
|
|
|
|
|
|
|
|
public void cycleDisk(int driveNumber)
|
|
|
|
{
|
|
|
|
debug("cycleDisk(" + driveNumber + ")");
|
|
|
|
if (diskImageNames[driveNumber].length > 1) {
|
|
|
|
diskImageNumber[driveNumber] = ++diskImageNumber[driveNumber] % diskImageNames[driveNumber].length;
|
|
|
|
mountDisk(driveNumber, diskImageNames[driveNumber][diskImageNumber[driveNumber]]);
|
|
|
|
}
|
|
|
|
}
|
2015-08-01 06:21:16 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Open input stream
|
|
|
|
*/
|
2015-08-01 07:09:49 +00:00
|
|
|
private DataInputStream openInputStream(String resource) {
|
2015-08-01 07:29:04 +00:00
|
|
|
return openInputStream(resource, null);
|
|
|
|
}
|
|
|
|
|
|
|
|
private DataInputStream openInputStream(String resource, StringBuffer OutFilename) {
|
2015-08-01 06:21:16 +00:00
|
|
|
InputStream is = null;
|
2015-08-01 07:29:04 +00:00
|
|
|
|
|
|
|
if (OutFilename != null)
|
2015-08-01 07:38:06 +00:00
|
|
|
{
|
2015-08-01 07:29:04 +00:00
|
|
|
OutFilename.setLength(0);
|
2015-08-01 07:38:06 +00:00
|
|
|
int slashPos = resource.lastIndexOf('/');
|
|
|
|
int backslashPos = resource.lastIndexOf('\\');
|
|
|
|
int index = Math.max(slashPos, backslashPos);
|
|
|
|
OutFilename.append(resource.substring((index > 0) ? index : 0));
|
|
|
|
}
|
2015-08-01 07:29:04 +00:00
|
|
|
|
2015-08-01 06:21:16 +00:00
|
|
|
try {
|
|
|
|
URL url = new URL(getCodeBase(), resource);
|
2015-08-01 07:09:49 +00:00
|
|
|
debug("resource: " + url.toString());
|
2015-08-01 06:21:16 +00:00
|
|
|
|
2015-08-01 07:09:49 +00:00
|
|
|
is = url.openStream();
|
2015-08-01 06:21:16 +00:00
|
|
|
if (resource.toLowerCase().endsWith(".gz"))
|
2015-08-01 07:09:49 +00:00
|
|
|
{
|
2015-08-01 06:21:16 +00:00
|
|
|
is = new GZIPInputStream(is);
|
2015-08-01 07:09:49 +00:00
|
|
|
}
|
|
|
|
else if (resource.toLowerCase().endsWith(".zip"))
|
|
|
|
{
|
|
|
|
is = new ZipInputStream(is);
|
2015-08-01 07:29:04 +00:00
|
|
|
ZipEntry entry = ((ZipInputStream)is).getNextEntry();
|
|
|
|
if (OutFilename != null)
|
|
|
|
{
|
2015-08-01 07:38:06 +00:00
|
|
|
OutFilename.setLength(0);
|
2015-08-01 07:29:04 +00:00
|
|
|
OutFilename.append(entry.getName());
|
|
|
|
}
|
|
|
|
}
|
2015-08-01 06:21:16 +00:00
|
|
|
} catch (Exception e) {
|
2015-08-01 07:09:49 +00:00
|
|
|
debug("Exeption: " + e.getLocalizedMessage());
|
2015-08-01 06:21:16 +00:00
|
|
|
}
|
|
|
|
|
2015-08-01 07:09:49 +00:00
|
|
|
if (is == null)
|
|
|
|
{
|
|
|
|
debug("failed");
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
debug("ok");
|
|
|
|
return new DataInputStream(is);
|
|
|
|
}
|
2015-08-01 06:21:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Open output stream
|
|
|
|
*/
|
|
|
|
private OutputStream openOutputStream(String resource) {
|
|
|
|
OutputStream os = null;
|
|
|
|
|
|
|
|
try {
|
|
|
|
if (!(resource.substring(0, 6).equals("http://")))
|
|
|
|
os = new FileOutputStream(resource);
|
|
|
|
} catch (Exception e) {
|
|
|
|
}
|
|
|
|
|
|
|
|
return os;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Load ROM
|
|
|
|
*/
|
|
|
|
public boolean loadRom(String resource) {
|
|
|
|
debug("loadRom(resource: " + resource + ")");
|
|
|
|
boolean success = false;
|
|
|
|
|
|
|
|
try {
|
2015-08-01 07:09:49 +00:00
|
|
|
DataInputStream is = openInputStream(resource);
|
2015-08-01 06:21:16 +00:00
|
|
|
success = apple.loadRom(is);
|
|
|
|
is.close();
|
|
|
|
} catch (Exception e) {
|
2015-08-01 07:09:49 +00:00
|
|
|
debug("Exeption: " + e.getLocalizedMessage());
|
2015-08-01 06:21:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return success;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Mount a disk
|
|
|
|
*/
|
|
|
|
public boolean mountDisk(int drive, String resource) {
|
|
|
|
debug("mountDisk(drive: " + drive + ", resource: " + resource + ")");
|
|
|
|
boolean success = false;
|
|
|
|
|
2015-08-01 07:42:08 +00:00
|
|
|
if ((drive < 0) || (drive > 1))
|
2015-08-01 06:21:16 +00:00
|
|
|
return success;
|
|
|
|
|
|
|
|
try {
|
|
|
|
unmountDisk(drive);
|
|
|
|
|
|
|
|
diskDriveResource[drive] = resource;
|
|
|
|
|
2015-08-01 07:29:04 +00:00
|
|
|
StringBuffer diskname = new StringBuffer();
|
|
|
|
DataInputStream is = openInputStream(resource, diskname);
|
2015-08-01 07:49:51 +00:00
|
|
|
|
|
|
|
int diskVolumeNumber = DiskII.DEFAULT_VOLUME;
|
2015-08-01 07:29:04 +00:00
|
|
|
|
2015-08-01 07:49:51 +00:00
|
|
|
// handle disk meta tag for disk volume (etc?)
|
|
|
|
// could break this out into a method, but then multiple tags ...?
|
|
|
|
String lowerDiskname = diskname.toString().toLowerCase();
|
|
|
|
int metaIndex = lowerDiskname.indexOf(metaStart);
|
|
|
|
if (metaIndex != -1)
|
|
|
|
{
|
|
|
|
metaIndex += metaStart.length();
|
|
|
|
int command = 0;
|
|
|
|
int operand = 0;
|
|
|
|
boolean execute = false;
|
|
|
|
while (metaIndex < lowerDiskname.length())
|
|
|
|
{
|
|
|
|
char c = lowerDiskname.charAt(metaIndex++);
|
|
|
|
switch (c)
|
|
|
|
{
|
|
|
|
case '0': case '1':case '2':case '3':case '4':
|
|
|
|
case '5': case '6':case '7':case '8':case '9':
|
|
|
|
{
|
|
|
|
operand = 10 * operand + (c - '0');
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case '.': // end meta
|
|
|
|
metaIndex = lowerDiskname.length();
|
|
|
|
execute = true;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case '_': // end word
|
|
|
|
execute = true;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
{
|
|
|
|
if (c >= 'a' && c <= 'z')
|
|
|
|
{
|
|
|
|
command = (command << 16) + c;
|
|
|
|
execute = (command & 0xFFFF0000) != 0;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (execute)
|
|
|
|
{
|
|
|
|
switch (command)
|
|
|
|
{
|
|
|
|
case ('d' << 16) + 'v':
|
|
|
|
diskVolumeNumber = operand;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
command = 0;
|
|
|
|
operand = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
success = disk.readDisk(drive, is, diskname.toString(), !diskWritable, diskVolumeNumber);
|
2015-08-01 06:21:16 +00:00
|
|
|
is.close();
|
2015-08-01 07:42:08 +00:00
|
|
|
showStatus("Drive " + (drive + 1) + ": " + resource);
|
2015-08-01 06:21:16 +00:00
|
|
|
} catch (Exception e) {
|
2015-08-01 07:09:49 +00:00
|
|
|
debug("Exeption: " + e.getLocalizedMessage());
|
2015-08-01 06:21:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return success;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Unmount a disk
|
|
|
|
*/
|
|
|
|
public void unmountDisk(int drive) {
|
|
|
|
debug("unmountDisk(drive: " + drive + ")");
|
2015-08-01 07:49:51 +00:00
|
|
|
if ((drive < 0) || (drive > 1))
|
2015-08-01 06:21:16 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
if (!diskWritable)
|
|
|
|
return;
|
|
|
|
|
|
|
|
try {
|
|
|
|
OutputStream os = openOutputStream(diskDriveResource[drive]);
|
|
|
|
disk.writeDisk(drive, os);
|
|
|
|
os.close();
|
|
|
|
} catch (Exception e) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set color mode
|
|
|
|
*/
|
|
|
|
public void setColorMode(int value) {
|
|
|
|
debug("setColorMode(value: " + value + ")");
|
|
|
|
display.setColorMode(value);
|
|
|
|
}
|
|
|
|
|
2015-08-01 07:49:51 +00:00
|
|
|
/**
|
|
|
|
* Set paddle enabled/disabled
|
|
|
|
*/
|
|
|
|
public void setPaddleEnabled(boolean value) {
|
|
|
|
debug("setPaddleEnabled(value: " + value + ")");
|
|
|
|
isPaddleEnabled = value;
|
|
|
|
if (!value)
|
|
|
|
{
|
|
|
|
apple.paddle.setPaddlePos(0, Paddle.PADDLE_HIGH);
|
|
|
|
apple.paddle.setPaddlePos(1, Paddle.PADDLE_HIGH);
|
|
|
|
apple.paddle.setButton(0, false);
|
|
|
|
apple.paddle.setButton(1, false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set paddle inverted/normal
|
|
|
|
*/
|
|
|
|
public void setPaddleInverted(boolean value) {
|
|
|
|
debug("setPaddleInverted(value: " + value + ")");
|
|
|
|
isPaddleInverted = value;
|
|
|
|
}
|
|
|
|
|
2015-08-01 06:21:16 +00:00
|
|
|
/**
|
|
|
|
* Get disk activity
|
|
|
|
*/
|
|
|
|
public boolean getDiskActivity() {
|
|
|
|
return (!isCpuPaused && disk.isMotorOn());
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* KeyListener event handling
|
|
|
|
*/
|
|
|
|
public void keyTyped(KeyEvent e) {
|
|
|
|
// Send to emulator
|
|
|
|
int key = e.getKeyChar();
|
|
|
|
if (key == 10)
|
|
|
|
apple.setKeyLatch(13);
|
|
|
|
else if (key < 128) {
|
|
|
|
if (keyboardUppercaseOnly && (key >= 97) && (key <= 122))
|
|
|
|
key -= 32;
|
|
|
|
|
|
|
|
apple.setKeyLatch(key);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public void keyPressed(KeyEvent e) {
|
|
|
|
switch(e.getKeyCode()) {
|
2015-08-01 07:29:04 +00:00
|
|
|
|
|
|
|
case KeyEvent.VK_META:
|
|
|
|
apple.paddle.setButton(1, true);
|
|
|
|
break;
|
2015-08-01 07:21:54 +00:00
|
|
|
case KeyEvent.VK_ALT:
|
|
|
|
if (e.getKeyLocation() == KeyEvent.KEY_LOCATION_LEFT)
|
|
|
|
{
|
|
|
|
apple.paddle.setButton(0, true);
|
|
|
|
}
|
|
|
|
else if (e.getKeyLocation() == KeyEvent.KEY_LOCATION_RIGHT)
|
|
|
|
{
|
|
|
|
apple.paddle.setButton(1, true);
|
|
|
|
}
|
|
|
|
break;
|
2015-08-01 06:21:16 +00:00
|
|
|
case KeyEvent.VK_BACK_SPACE:
|
|
|
|
case KeyEvent.VK_LEFT:
|
2015-08-01 07:21:54 +00:00
|
|
|
if (e.getKeyLocation() == KeyEvent.KEY_LOCATION_NUMPAD)
|
|
|
|
{
|
|
|
|
handleKeypadLeft();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
apple.setKeyLatch(8);
|
|
|
|
}
|
2015-08-01 06:21:16 +00:00
|
|
|
break;
|
|
|
|
case KeyEvent.VK_RIGHT:
|
2015-08-01 07:21:54 +00:00
|
|
|
if (e.getKeyLocation() == KeyEvent.KEY_LOCATION_NUMPAD)
|
|
|
|
{
|
|
|
|
handleKeypadRight();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
apple.setKeyLatch(21);
|
|
|
|
}
|
2015-08-01 06:21:16 +00:00
|
|
|
break;
|
|
|
|
case KeyEvent.VK_UP:
|
|
|
|
if (e.isControlDown())
|
2015-08-01 07:21:54 +00:00
|
|
|
{
|
|
|
|
apple.speaker.setVolume(apple.speaker.getVolume() + 1);
|
|
|
|
}
|
|
|
|
else if (e.getKeyLocation() == KeyEvent.KEY_LOCATION_NUMPAD)
|
|
|
|
{
|
|
|
|
handleKeypadUp();
|
|
|
|
}
|
2015-08-01 06:21:16 +00:00
|
|
|
else
|
2015-08-01 07:21:54 +00:00
|
|
|
{
|
2015-08-01 06:21:16 +00:00
|
|
|
apple.setKeyLatch(11);
|
2015-08-01 07:21:54 +00:00
|
|
|
}
|
2015-08-01 06:21:16 +00:00
|
|
|
break;
|
|
|
|
case KeyEvent.VK_DOWN:
|
|
|
|
if (e.isControlDown())
|
2015-08-01 07:21:54 +00:00
|
|
|
{
|
|
|
|
apple.speaker.setVolume(apple.speaker.getVolume() - 1);
|
|
|
|
}
|
|
|
|
else if (e.getKeyLocation() == KeyEvent.KEY_LOCATION_NUMPAD)
|
|
|
|
{
|
|
|
|
handleKeypadDown();
|
|
|
|
}
|
2015-08-01 06:21:16 +00:00
|
|
|
else
|
2015-08-01 07:21:54 +00:00
|
|
|
{
|
2015-08-01 06:21:16 +00:00
|
|
|
apple.setKeyLatch(10);
|
2015-08-01 07:21:54 +00:00
|
|
|
}
|
2015-08-01 06:21:16 +00:00
|
|
|
break;
|
|
|
|
case KeyEvent.VK_ESCAPE:
|
|
|
|
apple.setKeyLatch(27);
|
|
|
|
break;
|
|
|
|
case KeyEvent.VK_DELETE:
|
|
|
|
apple.setKeyLatch(127);
|
|
|
|
break;
|
|
|
|
case KeyEvent.VK_HOME:
|
|
|
|
if (e.isControlDown())
|
2015-08-01 07:42:08 +00:00
|
|
|
restart();
|
2015-08-01 07:29:04 +00:00
|
|
|
else
|
|
|
|
apple.paddle.setButton(0, true);
|
|
|
|
break;
|
|
|
|
case KeyEvent.VK_END:
|
|
|
|
apple.paddle.setButton(1, true);
|
2015-08-01 06:21:16 +00:00
|
|
|
break;
|
2015-08-01 07:09:49 +00:00
|
|
|
case KeyEvent.VK_F1:
|
|
|
|
showStatus("AppleIIGo Version " + version);
|
|
|
|
break;
|
|
|
|
case KeyEvent.VK_F3:
|
2015-08-01 07:42:08 +00:00
|
|
|
cycleDisk(0);
|
2015-08-01 07:09:49 +00:00
|
|
|
break;
|
|
|
|
case KeyEvent.VK_F4:
|
2015-08-01 07:42:08 +00:00
|
|
|
cycleDisk(1);
|
2015-08-01 07:09:49 +00:00
|
|
|
break;
|
2015-08-01 06:21:16 +00:00
|
|
|
case KeyEvent.VK_F5:
|
|
|
|
if (isCpuDebugEnabled)
|
|
|
|
display.setStatMode(!display.getStatMode());
|
|
|
|
break;
|
|
|
|
case KeyEvent.VK_F6:
|
|
|
|
if (isCpuDebugEnabled)
|
|
|
|
apple.setStepMode(!apple.getStepMode());
|
|
|
|
break;
|
|
|
|
case KeyEvent.VK_F7:
|
|
|
|
if (isCpuDebugEnabled) {
|
|
|
|
apple.setStepMode(apple.getStepMode());
|
|
|
|
apple.stepInstructions(1);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case KeyEvent.VK_F8:
|
|
|
|
if (isCpuDebugEnabled) {
|
|
|
|
apple.setStepMode(apple.getStepMode());
|
|
|
|
apple.stepInstructions(128);
|
|
|
|
}
|
|
|
|
break;
|
2015-08-01 07:21:54 +00:00
|
|
|
case KeyEvent.VK_CANCEL: // Ctrl-Pause/Break sends this (N/A on Mac)
|
|
|
|
case KeyEvent.VK_F12:
|
|
|
|
if (e.isControlDown())
|
2015-08-01 07:42:08 +00:00
|
|
|
reset();
|
2015-08-01 07:21:54 +00:00
|
|
|
break;
|
|
|
|
case KeyEvent.VK_KP_LEFT:
|
|
|
|
handleKeypadLeft();
|
|
|
|
break;
|
|
|
|
case KeyEvent.VK_KP_RIGHT:
|
|
|
|
handleKeypadRight();
|
|
|
|
break;
|
|
|
|
case KeyEvent.VK_KP_UP:
|
|
|
|
handleKeypadUp();
|
|
|
|
break;
|
|
|
|
case KeyEvent.VK_KP_DOWN:
|
|
|
|
handleKeypadDown();
|
|
|
|
break;
|
2015-08-01 06:21:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public void keyReleased(KeyEvent e) {
|
2015-08-01 07:21:54 +00:00
|
|
|
switch(e.getKeyCode()) {
|
2015-08-01 07:29:04 +00:00
|
|
|
case KeyEvent.VK_META:
|
|
|
|
apple.paddle.setButton(1, false);
|
|
|
|
break;
|
2015-08-01 07:21:54 +00:00
|
|
|
case KeyEvent.VK_ALT:
|
|
|
|
if (e.getKeyLocation() == KeyEvent.KEY_LOCATION_LEFT)
|
|
|
|
{
|
|
|
|
apple.paddle.setButton(0, false);
|
|
|
|
}
|
|
|
|
else if (e.getKeyLocation() == KeyEvent.KEY_LOCATION_RIGHT)
|
|
|
|
{
|
|
|
|
apple.paddle.setButton(1, false);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case KeyEvent.VK_LEFT:
|
|
|
|
case KeyEvent.VK_RIGHT:
|
|
|
|
if (e.getKeyLocation() != KeyEvent.KEY_LOCATION_NUMPAD)
|
|
|
|
break;
|
|
|
|
// else fall through
|
|
|
|
case KeyEvent.VK_KP_LEFT:
|
|
|
|
case KeyEvent.VK_KP_RIGHT:
|
2015-08-01 07:49:51 +00:00
|
|
|
handleKeypadCentreX();
|
2015-08-01 07:21:54 +00:00
|
|
|
break;
|
|
|
|
case KeyEvent.VK_UP:
|
|
|
|
case KeyEvent.VK_DOWN:
|
|
|
|
if (e.getKeyLocation() != KeyEvent.KEY_LOCATION_NUMPAD)
|
|
|
|
break;
|
|
|
|
// else fall through
|
|
|
|
case KeyEvent.VK_KP_UP:
|
|
|
|
case KeyEvent.VK_KP_DOWN:
|
2015-08-01 07:49:51 +00:00
|
|
|
handleKeypadCentreY();
|
2015-08-01 07:21:54 +00:00
|
|
|
break;
|
2015-08-01 07:29:04 +00:00
|
|
|
case KeyEvent.VK_HOME:
|
|
|
|
if (!e.isControlDown())
|
|
|
|
{
|
|
|
|
apple.paddle.setButton(0, false);
|
|
|
|
}
|
|
|
|
case KeyEvent.VK_END:
|
|
|
|
apple.paddle.setButton(1, false);
|
2015-08-01 07:21:54 +00:00
|
|
|
}
|
2015-08-01 06:21:16 +00:00
|
|
|
}
|
2015-08-01 07:21:54 +00:00
|
|
|
|
2015-08-01 07:49:51 +00:00
|
|
|
private void handleKeypadCentreX() {
|
|
|
|
if (isPaddleEnabled)
|
|
|
|
{
|
|
|
|
if (isPaddleInverted) {
|
|
|
|
apple.paddle.setPaddlePos(1, 127);
|
|
|
|
} else {
|
|
|
|
apple.paddle.setPaddlePos(0, 127);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void handleKeypadCentreY() {
|
|
|
|
if (isPaddleEnabled)
|
|
|
|
{
|
|
|
|
if (isPaddleInverted) {
|
|
|
|
apple.paddle.setPaddlePos(0, 127);
|
|
|
|
} else {
|
|
|
|
apple.paddle.setPaddlePos(1, 127);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-08-01 07:21:54 +00:00
|
|
|
private void handleKeypadLeft() {
|
2015-08-01 07:49:51 +00:00
|
|
|
if (isPaddleEnabled)
|
|
|
|
{
|
2015-08-01 07:21:54 +00:00
|
|
|
if (isPaddleInverted) {
|
|
|
|
apple.paddle.setPaddlePos(1, 255);
|
|
|
|
} else {
|
|
|
|
apple.paddle.setPaddlePos(0, 0);
|
|
|
|
}
|
2015-08-01 07:49:51 +00:00
|
|
|
}
|
2015-08-01 07:21:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private void handleKeypadRight() {
|
2015-08-01 07:49:51 +00:00
|
|
|
if (isPaddleEnabled)
|
|
|
|
{
|
2015-08-01 07:21:54 +00:00
|
|
|
if (isPaddleInverted) {
|
|
|
|
apple.paddle.setPaddlePos(1, 0);
|
|
|
|
} else {
|
|
|
|
apple.paddle.setPaddlePos(0, 255);
|
|
|
|
}
|
2015-08-01 07:49:51 +00:00
|
|
|
}
|
2015-08-01 07:21:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private void handleKeypadUp() {
|
2015-08-01 07:49:51 +00:00
|
|
|
if (isPaddleEnabled)
|
|
|
|
{
|
2015-08-01 07:21:54 +00:00
|
|
|
if (isPaddleInverted) {
|
|
|
|
apple.paddle.setPaddlePos(0, 255);
|
|
|
|
} else {
|
|
|
|
apple.paddle.setPaddlePos(1, 0);
|
|
|
|
}
|
2015-08-01 07:49:51 +00:00
|
|
|
}
|
2015-08-01 07:21:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private void handleKeypadDown() {
|
2015-08-01 07:49:51 +00:00
|
|
|
if (isPaddleEnabled)
|
|
|
|
{
|
2015-08-01 07:21:54 +00:00
|
|
|
if (isPaddleInverted) {
|
|
|
|
apple.paddle.setPaddlePos(0, 0);
|
|
|
|
} else {
|
|
|
|
apple.paddle.setPaddlePos(1, 255);
|
|
|
|
}
|
2015-08-01 07:49:51 +00:00
|
|
|
}
|
2015-08-01 07:21:54 +00:00
|
|
|
}
|
|
|
|
|
2015-08-01 06:21:16 +00:00
|
|
|
/**
|
|
|
|
* ComponentListener event handling
|
|
|
|
*/
|
|
|
|
public void componentHidden(ComponentEvent e) {
|
|
|
|
}
|
|
|
|
|
|
|
|
public void componentMoved(ComponentEvent e) {
|
|
|
|
}
|
|
|
|
|
|
|
|
public void componentResized(ComponentEvent e) {
|
|
|
|
}
|
|
|
|
|
|
|
|
public void componentShown(ComponentEvent e) {
|
|
|
|
debug("componentShown()");
|
|
|
|
|
|
|
|
removeComponentListener(this);
|
|
|
|
requestFocus();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* MouseListener, MouseMotionListener event handling
|
|
|
|
*/
|
|
|
|
public void mouseClicked(MouseEvent e) {
|
|
|
|
}
|
|
|
|
|
|
|
|
public void mouseEntered(MouseEvent e) {
|
|
|
|
try {
|
|
|
|
getAppletContext().showDocument(new URL("javascript:flipMouseOver();"));
|
|
|
|
} catch (MalformedURLException ex) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public void mouseExited(MouseEvent e) {
|
|
|
|
try {
|
|
|
|
getAppletContext().showDocument(new URL("javascript:flipMouseOut();"));
|
|
|
|
} catch (MalformedURLException ex) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public void mousePressed(MouseEvent e) {
|
|
|
|
int modifiers = e.getModifiers();
|
2015-08-01 07:49:51 +00:00
|
|
|
if (isPaddleEnabled)
|
|
|
|
{
|
|
|
|
if ((modifiers & InputEvent.BUTTON1_MASK) != 0)
|
|
|
|
apple.paddle.setButton(0, true);
|
|
|
|
if ((modifiers & InputEvent.BUTTON3_MASK) != 0)
|
|
|
|
apple.paddle.setButton(1, true);
|
|
|
|
}
|
2015-08-01 06:21:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public void mouseReleased(MouseEvent e) {
|
|
|
|
int modifiers = e.getModifiers();
|
2015-08-01 07:49:51 +00:00
|
|
|
if (isPaddleEnabled)
|
|
|
|
{
|
|
|
|
if ((modifiers & InputEvent.BUTTON1_MASK) != 0)
|
|
|
|
apple.paddle.setButton(0, false);
|
|
|
|
if ((modifiers & InputEvent.BUTTON3_MASK) != 0)
|
|
|
|
apple.paddle.setButton(1, false);
|
|
|
|
}
|
2015-08-01 06:21:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public void mouseDragged(MouseEvent e) {
|
|
|
|
mouseMoved(e);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void mouseMoved(MouseEvent e) {
|
2015-08-01 07:21:54 +00:00
|
|
|
float scale = display.getScale();
|
2015-08-01 07:49:51 +00:00
|
|
|
if (isPaddleEnabled)
|
|
|
|
{
|
|
|
|
if (isPaddleInverted) {
|
|
|
|
apple.paddle.setPaddlePos(0, (int) (255 - e.getY() * 256 / (192 * scale)));
|
|
|
|
apple.paddle.setPaddlePos(1, (int) (255 - e.getX() * 256 / (280 * scale)));
|
|
|
|
} else {
|
|
|
|
apple.paddle.setPaddlePos(0, (int) (e.getX() * 256 / (280 * scale)));
|
|
|
|
apple.paddle.setPaddlePos(1, (int) (e.getY() * 256 / (192 * scale)));
|
|
|
|
}
|
2015-08-01 06:21:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Applet paint function
|
|
|
|
*/
|
|
|
|
public void paint(Graphics g) {
|
|
|
|
display.paint(g);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Applet update function
|
|
|
|
*/
|
|
|
|
public void update(Graphics g) {
|
|
|
|
display.paint(g);
|
|
|
|
}
|
|
|
|
}
|