38 Commits

Author SHA1 Message Date
Aaron Culliney
20278ca91e Migration to 1.1.3+ should remove disks that were excised 2015-12-24 22:17:29 -08:00
Aaron Culliney
b996083a42 tweaks for Spanish localizations 2015-12-24 21:12:24 -08:00
Aaron Culliney
3e777477e2 Wish profuse apologies to native speakers, first cut at Spanish translation 2015-12-22 21:54:18 -08:00
Aaron Culliney
4d9eda4862 Work around another UI race exposed by NVIDIA Shield Portable 2015-12-22 21:53:14 -08:00
Aaron Culliney
4deedb2215 Move main menu dialog code into Apple2MainMenu 2015-12-20 16:45:59 -08:00
Aaron Culliney
bf3ef3ae18 GZIP the supplied disk images to help cut down on app space 2015-12-20 15:18:09 -08:00
Aaron Culliney
9fd288c0b9 Remove aggressive assert that fired on Cyanogen device (even with a valid CPU pause/resume lifecycle) ... 2015-12-20 15:04:20 -08:00
Aaron Culliney
abe1346051 Remove unused method 2015-12-20 15:04:06 -08:00
Aaron Culliney
145b6a6cef Refactor JNI plumbing for consistency 2015-12-20 12:54:27 -08:00
Aaron Culliney
22b1bc9ad8 Move key handling back to the Activity, otherwise we don't seem to receive onKeyUp() for the Android back button 2015-12-20 12:11:12 -08:00
Aaron Culliney
2f7f7bd359 Preliminary support for mapping an Android physical gamepad/joystick to emulated Apple //e joystick
- No support for custom joystick/gamepad configurations (yet)
2015-12-19 23:59:02 -08:00
Aaron Culliney
7dd0f0b3cf Avoid another UI race exposed by NVIDIA Shield Portable
- Use AtomicBoolean to avoid spurious extra taps/clicks/presses
2015-12-19 23:24:45 -08:00
Aaron Culliney
3ff877d80c Refactor : move event handling into custom view 2015-12-19 23:13:52 -08:00
Aaron Culliney
13de08f8cb map L1 and R1 keys to joy buttons 2015-12-19 23:13:44 -08:00
Aaron Culliney
1d248c5e22 Whitespace and style changes 2015-12-19 23:13:33 -08:00
Aaron Culliney
e5e2f98835 Avoid nasty UI race manifesting on NVIDIA Shield Portable
- For some reason this device has really slow Java UI, so it exposed a case where spammy touch resulted in two
      save/restore popups and a subsequent assert on the native side if you saved while the emulation was resumed.
2015-12-19 23:12:05 -08:00
Aaron Culliney
1e573c34ad Meager support for Android joystick/gamepad keys 2015-12-19 13:14:46 -08:00
Aaron Culliney
e165da72fc Explicitly not supporting older joystick devices 2015-12-19 13:14:10 -08:00
Aaron Culliney
1c50d12963 Source InputManager from AOSP 2015-12-19 13:08:48 -08:00
Aaron Culliney
d69b416c58 Lightly refactor emulator joystick API in preparation for more comprehensive refactor 2015-12-19 13:01:28 -08:00
Aaron Culliney
a1fbc63f98 Semi-inscrutible changes insisted upon by Android Studio 2015-12-19 12:59:40 -08:00
Aaron Culliney
c7c209907b Allow for keyboard to completely own/cover screen
- Includes updated alternate/custom keyboards
2015-12-19 12:56:24 -08:00
Aaron Culliney
5bd7ff2fe1 Simplify switching to "useralt" touch keyboard 2015-12-16 22:15:19 -08:00
Aaron Culliney
72fb577166 Update misc Android assets 2015-12-16 22:14:29 -08:00
Aaron Culliney
69b096ec14 Avoid showing redundant 0 nibble 2015-12-16 21:33:25 -08:00
Aaron Culliney
f872e0c05c fix i386 variant of op_SBC_dec (now re-passes tests on x86 Android) 2015-12-16 21:12:45 -08:00
Aaron Culliney
5211722d63 Switch to using DSK to speed up tests on Android 2015-12-16 21:11:52 -08:00
Aaron Culliney
785577e252 Fix some compiler warnings in testdisk.c 2015-12-16 21:11:35 -08:00
Aaron Culliney
3a20c96296 Check more paths in attempt to satisfy test suite disk insertion
- This is mainly to accommodate disk locations on Android
2015-12-16 21:01:50 -08:00
Aaron Culliney
2c8284d41f Start running tests on Android after first resume
- This allows for a more consistent test environment (test disks copied out of APK and available, etc) and also
      mimics main app behavior
2015-12-16 20:59:20 -08:00
Aaron Culliney
9e5274ee18 Flip-flop test to correctly account for e5f08849 2015-12-16 20:56:20 -08:00
Aaron Culliney
26e452c3a3 Avoid bufover in testsuite -- sprintf() already writes terminating null byte! 2015-12-16 20:53:16 -08:00
Aaron Culliney
870a24ced6 Fix test compilation on Android 2015-12-15 22:24:43 -08:00
Aaron Culliney
2dbd77e344 Excise uthash.h from testcpu suite
- Works around issue where Android NDK GCC 4.8/4.9 would take an inordinate amount of time when compiling testcpu with -O2
2015-12-14 23:56:48 -08:00
Aaron Culliney
699746a743 Alleviate compiler warnings in testvm/testdisplay 2015-12-14 23:55:08 -08:00
Aaron Culliney
74e97ccc97 Alleviate compiler warnings in testcpu 2015-12-14 22:11:29 -08:00
Aaron Culliney
1f0021667b Fix display test failures
- New framebuffer SHAs result of recent improvements to DHIRES colors
2015-12-14 18:59:44 -08:00
Aaron Culliney
836044c80b Bump Android version to 1.1.3 2015-12-13 22:48:29 -08:00
36 changed files with 2243 additions and 1292 deletions

View File

@@ -11,7 +11,6 @@
<entry name="!?*.flex" />
<entry name="!?*.kt" />
<entry name="!?*.clj" />
<entry name="!?*.aj" />
</wildcardResourcePatterns>
<annotationProcessing>
<profile default="true" name="Default" enabled="false">

49
Android/.idea/misc.xml generated
View File

@@ -27,6 +27,25 @@
</value>
</option>
</component>
<component name="ProjectInspectionProfilesVisibleTreeState">
<entry key="Project Default">
<profile-state>
<expanded-state>
<State>
<id />
</State>
<State>
<id>Spelling</id>
</State>
</expanded-state>
<selected-state>
<State>
<id>Spelling</id>
</State>
</selected-state>
</profile-state>
</entry>
</component>
<component name="ProjectLevelVcsManager" settingsEditedManually="false">
<OptionsSetting value="true" id="Add" />
<OptionsSetting value="true" id="Remove" />
@@ -37,10 +56,38 @@
<ConfirmationsSetting value="0" id="Add" />
<ConfirmationsSetting value="0" id="Remove" />
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" default="true" assert-keyword="true" jdk-15="true" project-jdk-name="1.7" project-jdk-type="JavaSDK">
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" assert-keyword="true" jdk-15="true" project-jdk-name="1.7" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">
<option name="id" value="Android" />
</component>
<component name="masterDetails">
<states>
<state key="Copyright.UI">
<settings>
<last-edited>deadc0de.org</last-edited>
<splitter-proportions>
<option name="proportions">
<list>
<option value="0.2" />
</list>
</option>
</splitter-proportions>
</settings>
</state>
<state key="ProjectJDKs.UI">
<settings>
<last-edited>Android API 21 Platform</last-edited>
<splitter-proportions>
<option name="proportions">
<list>
<option value="0.2" />
</list>
</option>
</splitter-proportions>
</settings>
</state>
</states>
</component>
</project>

View File

@@ -27,8 +27,8 @@ android {
applicationId "org.deadc0de.apple2ix.basic"
minSdkVersion 10
targetSdkVersion 23
versionCode 12
versionName "1.1.2"
versionCode 13
versionName "1.1.3"
ndk {
moduleName "apple2ix"
}

View File

@@ -0,0 +1,140 @@
/*
* Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.inputmanagercompat;
import android.content.Context;
import android.os.Build;
import android.os.Handler;
import android.view.InputDevice;
import android.view.MotionEvent;
public interface InputManagerCompat {
/**
* Gets information about the input device with the specified id.
*
* @param id The device id
* @return The input device or null if not found
*/
public InputDevice getInputDevice(int id);
/**
* Gets the ids of all input devices in the system.
*
* @return The input device ids.
*/
public int[] getInputDeviceIds();
/**
* Registers an input device listener to receive notifications about when
* input devices are added, removed or changed.
*
* @param listener The listener to register.
* @param handler The handler on which the listener should be invoked, or
* null if the listener should be invoked on the calling thread's
* looper.
*/
public void registerInputDeviceListener(InputManagerCompat.InputDeviceListener listener,
Handler handler);
/**
* Unregisters an input device listener.
*
* @param listener The listener to unregister.
*/
public void unregisterInputDeviceListener(InputManagerCompat.InputDeviceListener listener);
/*
* The following three calls are to simulate V16 behavior on pre-Jellybean
* devices. If you don't call them, your callback will never be called
* pre-API 16.
*/
/**
* Pass the motion events to the InputManagerCompat. This is used to
* optimize for polling for controllers. If you do not pass these events in,
* polling will cause regular object creation.
*
* @param event the motion event from the app
*/
public void onGenericMotionEvent(MotionEvent event);
/**
* Tell the V9 input manager that it should stop polling for disconnected
* devices. You can call this during onPause in your activity, although you
* might want to call it whenever your game is not active (or whenever you
* don't care about being notified of new input devices)
*/
public void onPause();
/**
* Tell the V9 input manager that it should start polling for disconnected
* devices. You can call this during onResume in your activity, although you
* might want to call it less often (only when the gameplay is actually
* active)
*/
public void onResume();
public interface InputDeviceListener {
/**
* Called whenever the input manager detects that a device has been
* added. This will only be called in the V9 version when a motion event
* is detected.
*
* @param deviceId The id of the input device that was added.
*/
void onInputDeviceAdded(int deviceId);
/**
* Called whenever the properties of an input device have changed since
* they were last queried. This will not be called for the V9 version of
* the API.
*
* @param deviceId The id of the input device that changed.
*/
void onInputDeviceChanged(int deviceId);
/**
* Called whenever the input manager detects that a device has been
* removed. For the V9 version, this can take some time depending on the
* poll rate.
*
* @param deviceId The id of the input device that was removed.
*/
void onInputDeviceRemoved(int deviceId);
}
/**
* Use this to construct a compatible InputManager.
*/
public static class Factory {
/**
* Constructs and returns a compatible InputManger
*
* @param context the Context that will be used to get the system
* service from
* @return a compatible implementation of InputManager
*/
public static InputManagerCompat getInputManager(Context context) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
return new InputManagerV16(context);
} else {
return null;
}
}
}
}

View File

@@ -0,0 +1,107 @@
/*
* Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.inputmanagercompat;
import android.annotation.TargetApi;
import android.content.Context;
import android.hardware.input.InputManager;
import android.os.Build;
import android.os.Handler;
import android.view.InputDevice;
import android.view.MotionEvent;
import java.util.HashMap;
import java.util.Map;
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
public class InputManagerV16 implements InputManagerCompat {
private final InputManager mInputManager;
private final Map<InputManagerCompat.InputDeviceListener, V16InputDeviceListener> mListeners;
public InputManagerV16(Context context) {
mInputManager = (InputManager) context.getSystemService(Context.INPUT_SERVICE);
mListeners = new HashMap<InputManagerCompat.InputDeviceListener, V16InputDeviceListener>();
}
@Override
public InputDevice getInputDevice(int id) {
return mInputManager.getInputDevice(id);
}
@Override
public int[] getInputDeviceIds() {
return mInputManager.getInputDeviceIds();
}
static class V16InputDeviceListener implements InputManager.InputDeviceListener {
final InputManagerCompat.InputDeviceListener mIDL;
public V16InputDeviceListener(InputDeviceListener idl) {
mIDL = idl;
}
@Override
public void onInputDeviceAdded(int deviceId) {
mIDL.onInputDeviceAdded(deviceId);
}
@Override
public void onInputDeviceChanged(int deviceId) {
mIDL.onInputDeviceChanged(deviceId);
}
@Override
public void onInputDeviceRemoved(int deviceId) {
mIDL.onInputDeviceRemoved(deviceId);
}
}
@Override
public void registerInputDeviceListener(InputDeviceListener listener, Handler handler) {
V16InputDeviceListener v16Listener = new V16InputDeviceListener(listener);
mInputManager.registerInputDeviceListener(v16Listener, handler);
mListeners.put(listener, v16Listener);
}
@Override
public void unregisterInputDeviceListener(InputDeviceListener listener) {
V16InputDeviceListener curListener = mListeners.remove(listener);
if (null != curListener)
{
mInputManager.unregisterInputDeviceListener(curListener);
}
}
@Override
public void onGenericMotionEvent(MotionEvent event) {
// unused in V16
}
@Override
public void onPause() {
// unused in V16
}
@Override
public void onResume() {
// unused in V16
}
}

View File

@@ -14,17 +14,14 @@ package org.deadc0de.apple2ix;
import android.Manifest;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.media.AudioManager;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.StrictMode;
import android.util.Log;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
@@ -38,14 +35,10 @@ import java.util.concurrent.atomic.AtomicBoolean;
import org.deadc0de.apple2ix.basic.BuildConfig;
import org.deadc0de.apple2ix.basic.R;
import org.json.JSONException;
import org.json.JSONObject;
public class Apple2Activity extends Activity {
private final static String TAG = "Apple2Activity";
private final static int MAX_FINGERS = 32;// HACK ...
private final static String SAVE_FILE = "emulator.state";
private static volatile boolean DEBUG_STRICT = false;
private Apple2View mView = null;
@@ -60,9 +53,6 @@ public class Apple2Activity extends Activity {
private AtomicBoolean mPausing = new AtomicBoolean(false);
private float[] mXCoords = new float[MAX_FINGERS];
private float[] mYCoords = new float[MAX_FINGERS];
// non-null if we failed to load/link the native code ... likely we are running on some bizarre 'droid variant
private static Throwable sNativeBarfedThrowable = null;
private static boolean sNativeBarfed = false;
@@ -76,50 +66,33 @@ public class Apple2Activity extends Activity {
}
}
public final static long NATIVE_TOUCH_HANDLED = (1 << 0);
public final static long NATIVE_TOUCH_REQUEST_SHOW_MENU = (1 << 1);
public final static long NATIVE_TOUCH_KEY_TAP = (1 << 4);
public final static long NATIVE_TOUCH_KBD = (1 << 5);
public final static long NATIVE_TOUCH_JOY = (1 << 6);
public final static long NATIVE_TOUCH_MENU = (1 << 7);
public final static long NATIVE_TOUCH_JOY_KPAD = (1 << 8);
public final static long NATIVE_TOUCH_INPUT_DEVICE_CHANGED = (1 << 16);
public final static long NATIVE_TOUCH_CPU_SPEED_DEC = (1 << 17);
public final static long NATIVE_TOUCH_CPU_SPEED_INC = (1 << 18);
public final static long NATIVE_TOUCH_ASCII_SCANCODE_SHIFT = 32;
public final static long NATIVE_TOUCH_ASCII_SCANCODE_MASK = 0xFFFFL;
public final static long NATIVE_TOUCH_ASCII_MASK = 0xFF00L;
public final static long NATIVE_TOUCH_SCANCODE_MASK = 0x00FFL;
public final static int REQUEST_PERMISSION_RWSTORE = 42;
private native void nativeOnCreate(String dataDir, int sampleRate, int monoBufferSize, int stereoBufferSize);
private static native void nativeOnCreate(String dataDir, int sampleRate, int monoBufferSize, int stereoBufferSize);
private native void nativeOnKeyDown(int keyCode, int metaState);
private static native void nativeOnKeyDown(int keyCode, int metaState);
private native void nativeOnKeyUp(int keyCode, int metaState);
private static native void nativeOnKeyUp(int keyCode, int metaState);
private native void nativeSaveState(String path);
private static native void nativeSaveState(String path);
private native String nativeLoadState(String path);
private static native String nativeLoadState(String path);
public native void nativeEmulationResume();
private static native void nativeEmulationResume();
public native void nativeEmulationPause();
private static native void nativeEmulationPause();
public native void nativeOnQuit();
private static native void nativeOnQuit();
public native long nativeOnTouch(int action, int pointerCount, int pointerIndex, float[] xCoords, float[] yCoords);
private static native void nativeReboot();
public native void nativeReboot();
private static native void nativeChooseDisk(String path, boolean driveA, boolean readOnly);
public native void nativeChooseDisk(String path, boolean driveA, boolean readOnly);
public native void nativeEjectDisk(boolean driveA);
private static native void nativeEjectDisk(boolean driveA);
public final static boolean isNativeBarfed() {
return sNativeBarfed;
}
@Override
public void onCreate(Bundle savedInstanceState) {
@@ -164,7 +137,7 @@ public class Apple2Activity extends Activity {
if (firstTime) {
// allow for primitive migrations as needed
Apple2Preferences.EMULATOR_VERSION.saveInt(this, BuildConfig.VERSION_CODE);
Log.v(TAG, "Triggering migration to Apple2ix version : "+BuildConfig.VERSION_NAME);
Log.v(TAG, "Triggering migration to Apple2ix version : " + BuildConfig.VERSION_NAME);
}
showSplashScreen(!firstTime);
@@ -295,21 +268,23 @@ public class Apple2Activity extends Activity {
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (sNativeBarfed) {
return true;
if (Apple2Activity.isNativeBarfed()) {
return super.onKeyDown(keyCode, event);
}
if ((keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) || (keyCode == KeyEvent.KEYCODE_VOLUME_MUTE) || (keyCode == KeyEvent.KEYCODE_VOLUME_UP)) {
return false;
return super.onKeyDown(keyCode, event);
}
nativeOnKeyDown(keyCode, event.getMetaState());
return true;
}
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
if (sNativeBarfed) {
return true;
if (Apple2Activity.isNativeBarfed()) {
return super.onKeyUp(keyCode, event);
}
if (keyCode == KeyEvent.KEYCODE_BACK) {
Apple2MenuView apple2MenuView = peekApple2View();
if (apple2MenuView == null) {
@@ -322,106 +297,11 @@ public class Apple2Activity extends Activity {
showMainMenu();
return true;
} else if ((keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) || (keyCode == KeyEvent.KEYCODE_VOLUME_MUTE) || (keyCode == KeyEvent.KEYCODE_VOLUME_UP)) {
return false;
} else {
nativeOnKeyUp(keyCode, event.getMetaState());
return true;
return super.onKeyUp(keyCode, event);
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
do {
if (sNativeBarfed) {
break;
}
if (mMainMenu == null) {
break;
}
Apple2MenuView apple2MenuView = peekApple2View();
if ((apple2MenuView != null) && (!apple2MenuView.isCalibrating())) {
break;
}
//printSamples(event);
int action = event.getActionMasked();
int pointerIndex = event.getActionIndex();
int pointerCount = event.getPointerCount();
for (int i = 0; i < pointerCount/* && i < MAX_FINGERS */; i++) {
mXCoords[i] = event.getX(i);
mYCoords[i] = event.getY(i);
}
long nativeFlags = nativeOnTouch(action, pointerCount, pointerIndex, mXCoords, mYCoords);
if ((nativeFlags & NATIVE_TOUCH_HANDLED) == 0) {
break;
}
if ((nativeFlags & NATIVE_TOUCH_REQUEST_SHOW_MENU) != 0) {
mMainMenu.show();
}
if ((nativeFlags & NATIVE_TOUCH_KEY_TAP) != 0) {
if (Apple2Preferences.KEYBOARD_CLICK_ENABLED.booleanValue(this)) {
AudioManager am = (AudioManager) getSystemService(AUDIO_SERVICE);
if (am != null) {
am.playSoundEffect(AudioManager.FX_KEY_CLICK);
}
}
if ((apple2MenuView != null) && apple2MenuView.isCalibrating()) {
long asciiScancodeLong = nativeFlags & (NATIVE_TOUCH_ASCII_SCANCODE_MASK << NATIVE_TOUCH_ASCII_SCANCODE_SHIFT);
int asciiInt = (int) (asciiScancodeLong >> (NATIVE_TOUCH_ASCII_SCANCODE_SHIFT + 8));
int scancode = (int) ((asciiScancodeLong >> NATIVE_TOUCH_ASCII_SCANCODE_SHIFT) & 0xFFL);
char ascii = (char) asciiInt;
apple2MenuView.onKeyTapCalibrationEvent(ascii, scancode);
}
}
if ((nativeFlags & NATIVE_TOUCH_MENU) == 0) {
break;
}
// handle menu-specific actions
if ((nativeFlags & NATIVE_TOUCH_INPUT_DEVICE_CHANGED) != 0) {
Apple2Preferences.TouchDeviceVariant nextVariant;
if ((nativeFlags & NATIVE_TOUCH_KBD) != 0) {
nextVariant = Apple2Preferences.TouchDeviceVariant.KEYBOARD;
} else if ((nativeFlags & NATIVE_TOUCH_JOY) != 0) {
nextVariant = Apple2Preferences.TouchDeviceVariant.JOYSTICK;
} else if ((nativeFlags & NATIVE_TOUCH_JOY_KPAD) != 0) {
nextVariant = Apple2Preferences.TouchDeviceVariant.JOYSTICK_KEYPAD;
} else {
int touchDevice = Apple2Preferences.nativeGetCurrentTouchDevice();
nextVariant = Apple2Preferences.TouchDeviceVariant.next(touchDevice);
}
Apple2Preferences.CURRENT_TOUCH_DEVICE.saveTouchDevice(this, nextVariant);
} else if ((nativeFlags & NATIVE_TOUCH_CPU_SPEED_DEC) != 0) {
int percentSpeed = Apple2Preferences.nativeGetCPUSpeed();
if (percentSpeed > 400) { // HACK: max value from native side
percentSpeed = 375;
} else if (percentSpeed > 100) {
percentSpeed -= 25;
} else {
percentSpeed -= 5;
}
Apple2Preferences.CPU_SPEED_PERCENT.saveInt(this, percentSpeed);
} else if ((nativeFlags & NATIVE_TOUCH_CPU_SPEED_INC) != 0) {
int percentSpeed = Apple2Preferences.nativeGetCPUSpeed();
if (percentSpeed >= 100) {
percentSpeed += 25;
} else {
percentSpeed += 5;
}
Apple2Preferences.CPU_SPEED_PERCENT.saveInt(this, percentSpeed);
}
} while (false);
return super.onTouchEvent(event);
nativeOnKeyUp(keyCode, event.getMetaState());
return true;
}
public void showMainMenu() {
@@ -533,23 +413,13 @@ public class Apple2Activity extends Activity {
}
public synchronized void pushApple2View(Apple2MenuView apple2MenuView) {
//
mMenuStack.add(apple2MenuView);
View menuView = apple2MenuView.getView();
nativeEmulationPause();
addContentView(menuView, new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT));
}
public synchronized Apple2MenuView popApple2View() {
int lastIndex = mMenuStack.size() - 1;
if (lastIndex < 0) {
return null;
}
Apple2MenuView apple2MenuView = mMenuStack.remove(lastIndex);
_disposeApple2View(apple2MenuView);
return apple2MenuView;
}
public synchronized Apple2MenuView peekApple2View() {
int lastIndex = mMenuStack.size() - 1;
if (lastIndex < 0) {
@@ -626,29 +496,40 @@ public class Apple2Activity extends Activity {
}
}
public void maybeResumeCPU() {
public boolean isEmulationPaused() {
boolean mainMenuShowing = (mMainMenu != null && mMainMenu.isShowing());
boolean menusShowing = (mMenuStack.size() > 0);
return mainMenuShowing || menusShowing;
}
public void maybeResumeEmulation() {
if (mMenuStack.size() == 0 && !mPausing.get()) {
nativeEmulationResume();
}
}
public void maybeRebootQuit() {
public void pauseEmulation() {
nativeEmulationPause();
}
AlertDialog rebootQuitDialog = new AlertDialog.Builder(this).setIcon(R.drawable.ic_launcher).setCancelable(true).setTitle(R.string.quit_reboot).setMessage(R.string.quit_reboot_choice).setPositiveButton(R.string.reboot, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
nativeReboot();
Apple2Activity.this.mMainMenu.dismiss();
}
}).setNeutralButton(R.string.quit, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
quitEmulator();
}
}).setNegativeButton(R.string.cancel, null).create();
public void rebootEmulation() {
nativeReboot();
}
registerAndShowDialog(rebootQuitDialog);
public void saveState(String stateFile) {
nativeSaveState(stateFile);
}
public String loadState(String stateFile) {
return Apple2Activity.nativeLoadState(stateFile);
}
public void chooseDisk(String path, boolean driveA, boolean readOnly) {
nativeChooseDisk(path, driveA, readOnly);
}
public void ejectDisk(boolean driveA) {
nativeEjectDisk(driveA);
}
public void quitEmulator() {
@@ -666,41 +547,4 @@ public class Apple2Activity extends Activity {
}
}.run();
}
public void maybeSaveRestore() {
nativeEmulationPause();
final String quickSavePath = Apple2DisksMenu.getDataDir(this) + File.separator + SAVE_FILE;
AlertDialog saveRestoreDialog = new AlertDialog.Builder(this).setIcon(R.drawable.ic_launcher).setCancelable(true).setTitle(R.string.saverestore).setMessage(R.string.saverestore_choice).setPositiveButton(R.string.save, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Apple2Activity.this.nativeSaveState(quickSavePath);
Apple2Activity.this.mMainMenu.dismiss();
}
}).setNeutralButton(R.string.restore, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
// loading state can change the disk inserted ... reflect that in
String jsonData = Apple2Activity.this.nativeLoadState(quickSavePath);
try {
JSONObject map = new JSONObject(jsonData);
String diskPath1 = map.getString("disk1");
boolean readOnly1 = map.getBoolean("readOnly1");
Apple2Preferences.CURRENT_DISK_A.setPath(Apple2Activity.this, diskPath1);
Apple2Preferences.CURRENT_DISK_A_RO.saveBoolean(Apple2Activity.this, readOnly1);
String diskPath2 = map.getString("disk2");
boolean readOnly2 = map.getBoolean("readOnly2");
Apple2Preferences.CURRENT_DISK_B.setPath(Apple2Activity.this, diskPath2);
Apple2Preferences.CURRENT_DISK_B_RO.saveBoolean(Apple2Activity.this, readOnly2);
} catch (JSONException je) {
Log.v(TAG, "OOPS : "+je);
}
Apple2Activity.this.mMainMenu.dismiss();
}
}).setNegativeButton(R.string.cancel, null).create();
registerAndShowDialog(saveRestoreDialog);
}
}

View File

@@ -42,8 +42,10 @@ import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InterruptedIOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.zip.GZIPOutputStream;
import org.deadc0de.apple2ix.basic.R;
@@ -140,7 +142,7 @@ public class Apple2DisksMenu implements Apple2MenuView {
if (sExternalFilesDir == null) {
return;
}
final ProgressBar bar = (ProgressBar) activity.findViewById(R.id.crash_progressBar);
activity.runOnUiThread(new Runnable() {
@Override
@@ -155,7 +157,7 @@ public class Apple2DisksMenu implements Apple2MenuView {
});
Log.v(TAG, "Overwriting system files in /sdcard/apple2ix/ (external storage) ...");
recursivelyCopyAPKAssets(activity, /*from APK directory:*/"keyboards", /*to location:*/sExternalFilesDir.getAbsolutePath());
recursivelyCopyAPKAssets(activity, /*from APK directory:*/"keyboards", /*to location:*/sExternalFilesDir.getAbsolutePath(), false);
activity.runOnUiThread(new Runnable() {
@Override
@@ -186,12 +188,19 @@ public class Apple2DisksMenu implements Apple2MenuView {
getDataDir(activity);
// FIXME TODO : Heavy-handed migration to 1.1.3 ...
recursivelyDelete(new File(new File(sDataDir, "disks").getAbsolutePath(), "blanks"));
recursivelyDelete(new File(new File(sDataDir, "disks").getAbsolutePath(), "demo"));
recursivelyDelete(new File(new File(sDataDir, "disks").getAbsolutePath(), "eamon"));
recursivelyDelete(new File(new File(sDataDir, "disks").getAbsolutePath(), "logo"));
recursivelyDelete(new File(new File(sDataDir, "disks").getAbsolutePath(), "miscgame"));
Log.d(TAG, "First time copying stuff-n-things out of APK for ease-of-NDK access...");
getExternalStorageDirectory(activity);
recursivelyCopyAPKAssets(activity, /*from APK directory:*/"disks", /*to location:*/new File(sDataDir, "disks").getAbsolutePath());
recursivelyCopyAPKAssets(activity, /*from APK directory:*/"keyboards", /*to location:*/new File(sDataDir, "keyboards").getAbsolutePath());
recursivelyCopyAPKAssets(activity, /*from APK directory:*/"shaders", /*to location:*/new File(sDataDir, "shaders").getAbsolutePath());
recursivelyCopyAPKAssets(activity, /*from APK directory:*/"disks", /*to location:*/new File(sDataDir, "disks").getAbsolutePath(), true);
recursivelyCopyAPKAssets(activity, /*from APK directory:*/"keyboards", /*to location:*/new File(sDataDir, "keyboards").getAbsolutePath(), false);
recursivelyCopyAPKAssets(activity, /*from APK directory:*/"shaders", /*to location:*/new File(sDataDir, "shaders").getAbsolutePath(), false);
activity.runOnUiThread(new Runnable() {
@Override
@@ -207,7 +216,7 @@ public class Apple2DisksMenu implements Apple2MenuView {
}
public static void exposeSymbols(Apple2Activity activity) {
recursivelyCopyAPKAssets(activity, /*from APK directory:*/"symbols", /*to location:*/new File(sDataDir, "symbols").getAbsolutePath());
recursivelyCopyAPKAssets(activity, /*from APK directory:*/"symbols", /*to location:*/new File(sDataDir, "symbols").getAbsolutePath(), false);
}
public static void unexposeSymbols(Apple2Activity activity) {
@@ -351,6 +360,7 @@ public class Apple2DisksMenu implements Apple2MenuView {
return pathBuffer.toString();
}
// TODO FIXME : WARNING : this is super dangerous if there are symlinks !!!
private static void recursivelyDelete(File file) {
if (file.isDirectory()) {
for (File f : file.listFiles()) {
@@ -362,7 +372,7 @@ public class Apple2DisksMenu implements Apple2MenuView {
}
}
private static void recursivelyCopyAPKAssets(Apple2Activity activity, String srcFileOrDir, String dstFileOrDir) {
private static void recursivelyCopyAPKAssets(Apple2Activity activity, String srcFileOrDir, String dstFileOrDir, boolean shouldGzip) {
AssetManager assetManager = activity.getAssets();
final int maxAttempts = 5;
@@ -402,19 +412,23 @@ public class Apple2DisksMenu implements Apple2MenuView {
}
for (String filename : files) {
// iterate on files and subdirectories
recursivelyCopyAPKAssets(activity, srcFileOrDir + File.separator + filename, dstFileOrDir + File.separator + filename);
recursivelyCopyAPKAssets(activity, srcFileOrDir + File.separator + filename, dstFileOrDir + File.separator + filename, shouldGzip);
}
return;
}
// presumably this is a file, not a subdirectory
InputStream is = null;
FileOutputStream os = null;
OutputStream os = null;
attempts = 0;
do {
try {
is = assetManager.open(srcFileOrDir);
os = new FileOutputStream(dstFileOrDir);
if (shouldGzip) {
os = new GZIPOutputStream(new FileOutputStream(dstFileOrDir + ".gz"));
} else {
os = new FileOutputStream(dstFileOrDir);
}
copyFile(is, os);
break;
} catch (InterruptedIOException e) {
@@ -446,7 +460,7 @@ public class Apple2DisksMenu implements Apple2MenuView {
} while (attempts < maxAttempts);
}
private static void copyFile(InputStream is, FileOutputStream os) throws IOException {
private static void copyFile(InputStream is, OutputStream os) throws IOException {
final int BUF_SZ = 4096;
byte[] buf = new byte[BUF_SZ];
while (true) {
@@ -562,7 +576,7 @@ public class Apple2DisksMenu implements Apple2MenuView {
ejectButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mActivity.nativeEjectDisk(/*driveA:*/true);
mActivity.ejectDisk(/*driveA:*/true);
Apple2Preferences.CURRENT_DISK_A.saveString(mActivity, "");
dynamicSetup();
}
@@ -574,7 +588,7 @@ public class Apple2DisksMenu implements Apple2MenuView {
ejectButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mActivity.nativeEjectDisk(/*driveA:*/false);
mActivity.ejectDisk(/*driveA:*/false);
Apple2Preferences.CURRENT_DISK_B.saveString(mActivity, "");
dynamicSetup();
}
@@ -616,17 +630,16 @@ public class Apple2DisksMenu implements Apple2MenuView {
final String imageName = str;
if (imageName.equals(Apple2Preferences.CURRENT_DISK_A.stringValue(mActivity))) {
mActivity.nativeEjectDisk(/*driveA:*/true);
mActivity.ejectDisk(/*driveA:*/true);
Apple2Preferences.CURRENT_DISK_A.saveString(mActivity, "");
dynamicSetup();
return;
}
if (imageName.equals(Apple2Preferences.CURRENT_DISK_B.stringValue(mActivity))) {
mActivity.nativeEjectDisk(/*driveA:*/false);
mActivity.ejectDisk(/*driveA:*/false);
Apple2Preferences.CURRENT_DISK_B.saveString(mActivity, "");
dynamicSetup();
return;
}
String title = mActivity.getResources().getString(R.string.header_disks);

View File

@@ -65,18 +65,18 @@ public class Apple2KeypadChooser implements Apple2MenuView {
mCurrentChoicePrompt.setText(getNextChoiceString() + asciiStr);
switch (mChooserState) {
case CHOOSE_TAP:
mActivity.nativeOnTouch(MotionEvent.ACTION_DOWN, 1, 0, new float[]{400.f}, new float[]{400.f});
mActivity.nativeOnTouch(MotionEvent.ACTION_UP, 1, 0, new float[]{400.f}, new float[]{400.f});
Apple2View.nativeOnTouch(MotionEvent.ACTION_DOWN, 1, 0, new float[]{400.f}, new float[]{400.f});
Apple2View.nativeOnTouch(MotionEvent.ACTION_UP, 1, 0, new float[]{400.f}, new float[]{400.f});
break;
case CHOOSE_SWIPEDOWN:
mActivity.nativeOnTouch(MotionEvent.ACTION_DOWN, 1, 0, new float[]{400.f}, new float[]{400.f});
mActivity.nativeOnTouch(MotionEvent.ACTION_MOVE, 1, 0, new float[]{400.f}, new float[]{600.f});
mActivity.nativeOnTouch(MotionEvent.ACTION_UP, 1, 0, new float[]{400.f}, new float[]{600.f});
Apple2View.nativeOnTouch(MotionEvent.ACTION_DOWN, 1, 0, new float[]{400.f}, new float[]{400.f});
Apple2View.nativeOnTouch(MotionEvent.ACTION_MOVE, 1, 0, new float[]{400.f}, new float[]{600.f});
Apple2View.nativeOnTouch(MotionEvent.ACTION_UP, 1, 0, new float[]{400.f}, new float[]{600.f});
break;
case CHOOSE_SWIPEUP:
mActivity.nativeOnTouch(MotionEvent.ACTION_DOWN, 1, 0, new float[]{400.f}, new float[]{400.f});
mActivity.nativeOnTouch(MotionEvent.ACTION_MOVE, 1, 0, new float[]{400.f}, new float[]{200.f});
mActivity.nativeOnTouch(MotionEvent.ACTION_UP, 1, 0, new float[]{400.f}, new float[]{200.f});
Apple2View.nativeOnTouch(MotionEvent.ACTION_DOWN, 1, 0, new float[]{400.f}, new float[]{400.f});
Apple2View.nativeOnTouch(MotionEvent.ACTION_MOVE, 1, 0, new float[]{400.f}, new float[]{200.f});
Apple2View.nativeOnTouch(MotionEvent.ACTION_UP, 1, 0, new float[]{400.f}, new float[]{200.f});
break;
default:
break;

View File

@@ -11,7 +11,9 @@
package org.deadc0de.apple2ix;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.graphics.drawable.BitmapDrawable;
import android.os.Build;
import android.util.Log;
@@ -27,16 +29,24 @@ import android.widget.PopupWindow;
import android.widget.TextView;
import org.deadc0de.apple2ix.basic.R;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.File;
import java.util.concurrent.atomic.AtomicBoolean;
public class Apple2MainMenu {
private final static int MENU_INSET = 20;
private final static String SAVE_FILE = "emulator.state";
private final static String TAG = "Apple2MainMenu";
private Apple2Activity mActivity = null;
private Apple2View mParentView = null;
private PopupWindow mMainMenuPopup = null;
private AtomicBoolean mShowingRebootQuit = new AtomicBoolean(false);
private AtomicBoolean mShowingSaveRestore = new AtomicBoolean(false);
public Apple2MainMenu(Apple2Activity activity, Apple2View parent) {
mActivity = activity;
mParentView = parent;
@@ -45,52 +55,82 @@ public class Apple2MainMenu {
enum SETTINGS {
SHOW_SETTINGS {
@Override public String getTitle(Context ctx) {
@Override
public String getTitle(Context ctx) {
return ctx.getResources().getString(R.string.menu_settings);
}
@Override public String getSummary(Context ctx) {
@Override
public String getSummary(Context ctx) {
return ctx.getResources().getString(R.string.menu_settings_summary);
}
@Override public void handleSelection(Apple2MainMenu mainMenu) {
@Override
public void handleSelection(Apple2MainMenu mainMenu) {
mainMenu.showSettings();
}
},
LOAD_DISK {
@Override public String getTitle(Context ctx) {
@Override
public String getTitle(Context ctx) {
return ctx.getResources().getString(R.string.menu_disks);
}
@Override public String getSummary(Context ctx) {
@Override
public String getSummary(Context ctx) {
return ctx.getResources().getString(R.string.menu_disks_summary);
}
@Override public void handleSelection(Apple2MainMenu mainMenu) {
@Override
public void handleSelection(Apple2MainMenu mainMenu) {
mainMenu.showDisksMenu();
}
},
SAVE_RESTORE {
@Override public String getTitle(Context ctx) {
@Override
public String getTitle(Context ctx) {
return ctx.getResources().getString(R.string.saverestore);
}
@Override public String getSummary(Context ctx) {
@Override
public String getSummary(Context ctx) {
return ctx.getResources().getString(R.string.saverestore_summary);
}
@Override public void handleSelection(Apple2MainMenu mainMenu) {
mainMenu.mActivity.maybeSaveRestore();
@Override
public void handleSelection(Apple2MainMenu mainMenu) {
if (!mainMenu.mShowingSaveRestore.compareAndSet(false, true)) {
Log.v(TAG, "OMG, avoiding nasty UI race around save/restore");
return;
}
mainMenu.maybeSaveRestore();
}
},
REBOOT_QUIT_EMULATOR {
@Override public String getTitle(Context ctx) {
@Override
public String getTitle(Context ctx) {
return ctx.getResources().getString(R.string.quit_reboot);
}
@Override public String getSummary(Context ctx) {
@Override
public String getSummary(Context ctx) {
return "";
}
@Override public void handleSelection(Apple2MainMenu mainMenu) {
mainMenu.mActivity.maybeRebootQuit();
@Override
public void handleSelection(Apple2MainMenu mainMenu) {
if (!mainMenu.mShowingRebootQuit.compareAndSet(false, true)) {
Log.v(TAG, "OMG, avoiding nasty UI race around quit/reboot");
return;
}
mainMenu.maybeRebootQuit();
}
};
public abstract String getTitle(Context ctx);
public abstract String getSummary(Context ctx);
public abstract void handleSelection(Apple2MainMenu mainMenu);
public static String[] titles(Context ctx) {
@@ -105,11 +145,11 @@ public class Apple2MainMenu {
private void setup() {
LayoutInflater inflater = (LayoutInflater)mActivity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View listLayout=inflater.inflate(R.layout.activity_main_menu, null, false);
ListView mainMenuView = (ListView)listLayout.findViewById(R.id.main_popup_menu);
LayoutInflater inflater = (LayoutInflater) mActivity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View listLayout = inflater.inflate(R.layout.activity_main_menu, null, false);
ListView mainMenuView = (ListView) listLayout.findViewById(R.id.main_popup_menu);
mainMenuView.setEnabled(true);
LinearLayout mainPopupContainer = (LinearLayout)listLayout.findViewById(R.id.main_popup_container);
LinearLayout mainPopupContainer = (LinearLayout) listLayout.findViewById(R.id.main_popup_container);
final String[] values = SETTINGS.titles(mActivity);
@@ -118,10 +158,11 @@ public class Apple2MainMenu {
public boolean areAllItemsEnabled() {
return true;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = super.getView(position, convertView, parent);
TextView tv = (TextView)view.findViewById(android.R.id.text2);
TextView tv = (TextView) view.findViewById(android.R.id.text2);
SETTINGS setting = SETTINGS.values()[position];
tv.setText(setting.getSummary(mActivity));
return view;
@@ -131,7 +172,7 @@ public class Apple2MainMenu {
mainMenuView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Log.d(TAG, "position:"+position+" tapped...");
Log.d(TAG, "position:" + position + " tapped...");
SETTINGS setting = SETTINGS.values()[position];
setting.handleSelection(Apple2MainMenu.this);
}
@@ -153,7 +194,7 @@ public class Apple2MainMenu {
maxWidth = width;
}
}
mMainMenuPopup = new PopupWindow(mainPopupContainer, maxWidth+TOTAL_MARGINS, totalHeight, true);
mMainMenuPopup = new PopupWindow(mainPopupContainer, maxWidth + TOTAL_MARGINS, totalHeight, true);
}
// This kludgery allows touching the outside or back-buttoning to dismiss
@@ -162,8 +203,8 @@ public class Apple2MainMenu {
mMainMenuPopup.setOnDismissListener(new PopupWindow.OnDismissListener() {
@Override
public void onDismiss() {
Apple2MainMenu.this.mActivity.maybeResumeCPU();
}
Apple2MainMenu.this.mActivity.maybeResumeEmulation();
}
});
}
@@ -184,7 +225,10 @@ public class Apple2MainMenu {
return;
}
mActivity.nativeEmulationPause();
mShowingRebootQuit.set(false);
mShowingSaveRestore.set(false);
mActivity.pauseEmulation();
mMainMenuPopup.showAtLocation(mParentView, Gravity.CENTER, 0, 0);
}
@@ -199,4 +243,82 @@ public class Apple2MainMenu {
public boolean isShowing() {
return mMainMenuPopup.isShowing();
}
public void maybeRebootQuit() {
mActivity.pauseEmulation();
final AtomicBoolean selectionAlreadyHandled = new AtomicBoolean(false);
AlertDialog rebootQuitDialog = new AlertDialog.Builder(mActivity).setIcon(R.drawable.ic_launcher).setCancelable(true).setTitle(R.string.quit_reboot).setMessage(R.string.quit_reboot_choice).setPositiveButton(R.string.reboot, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (!selectionAlreadyHandled.compareAndSet(false, true)) {
Log.v(TAG, "OMG, avoiding nasty UI race in reboot/quit onClick()");
return;
}
mActivity.rebootEmulation();
Apple2MainMenu.this.dismiss();
}
}).setNeutralButton(R.string.quit, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (!selectionAlreadyHandled.compareAndSet(false, true)) {
Log.v(TAG, "OMG, avoiding nasty UI race in reboot/quit onClick()");
return;
}
mActivity.quitEmulator();
}
}).setNegativeButton(R.string.cancel, null).create();
mActivity.registerAndShowDialog(rebootQuitDialog);
}
public void maybeSaveRestore() {
mActivity.pauseEmulation();
final String quickSavePath = Apple2DisksMenu.getDataDir(mActivity) + File.separator + SAVE_FILE;
final AtomicBoolean selectionAlreadyHandled = new AtomicBoolean(false);
AlertDialog saveRestoreDialog = new AlertDialog.Builder(mActivity).setIcon(R.drawable.ic_launcher).setCancelable(true).setTitle(R.string.saverestore).setMessage(R.string.saverestore_choice).setPositiveButton(R.string.save, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (!selectionAlreadyHandled.compareAndSet(false, true)) {
Log.v(TAG, "OMG, avoiding nasty UI race in save/restore onClick()");
return;
}
mActivity.saveState(quickSavePath);
Apple2MainMenu.this.dismiss();
}
}).setNeutralButton(R.string.restore, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (!selectionAlreadyHandled.compareAndSet(false, true)) {
Log.v(TAG, "OMG, avoiding nasty UI race in save/restore onClick()");
return;
}
String jsonData = mActivity.loadState(quickSavePath);
try {
JSONObject map = new JSONObject(jsonData);
String diskPath1 = map.getString("disk1");
boolean readOnly1 = map.getBoolean("readOnly1");
Apple2Preferences.CURRENT_DISK_A.setPath(mActivity, diskPath1);
Apple2Preferences.CURRENT_DISK_A_RO.saveBoolean(mActivity, readOnly1);
String diskPath2 = map.getString("disk2");
boolean readOnly2 = map.getBoolean("readOnly2");
Apple2Preferences.CURRENT_DISK_B.setPath(mActivity, diskPath2);
Apple2Preferences.CURRENT_DISK_B_RO.saveBoolean(mActivity, readOnly2);
} catch (JSONException je) {
Log.v(TAG, "OOPS : " + je);
}
Apple2MainMenu.this.dismiss();
}
}).setNegativeButton(R.string.cancel, null).create();
mActivity.registerAndShowDialog(saveRestoreDialog);
}
}

View File

@@ -1034,7 +1034,7 @@ public enum Apple2Preferences {
file = new File(fullPath);
}
if (file.exists()) {
activity.nativeChooseDisk(fullPath, isDriveA, isReadOnly);
activity.chooseDisk(fullPath, isDriveA, isReadOnly);
} else {
Log.d(TAG, "Cannot insert: " + fullPath);
}

View File

@@ -15,43 +15,57 @@
package org.deadc0de.apple2ix;
import android.content.Context;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.media.AudioManager;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import android.os.Build;
import android.util.Log;
import android.view.InputDevice;
import android.view.MotionEvent;
import android.view.ViewTreeObserver;
import com.example.inputmanagercompat.InputManagerCompat;
import javax.microedition.khronos.egl.EGL10;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.egl.EGLContext;
import javax.microedition.khronos.egl.EGLDisplay;
import javax.microedition.khronos.opengles.GL10;
/**
* A simple GLSurfaceView sub-class that demonstrate how to perform
* OpenGL ES 2.0 rendering into a GL Surface. Note the following important
* details:
*
* - The class must use a custom context factory to enable 2.0 rendering.
* See ContextFactory class definition below.
*
* - The class must use a custom EGLConfigChooser to be able to select
* an EGLConfig that supports 2.0. This is done by providing a config
* specification to eglChooseConfig() that has the attribute
* EGL10.ELG_RENDERABLE_TYPE containing the EGL_OPENGL_ES2_BIT flag
* set. See ConfigChooser class definition below.
*
* - The class must select the surface's format, then choose an EGLConfig
* that matches it exactly (with regards to red/green/blue/alpha channels
* bit depths). Failure to do so would result in an EGL_BAD_MATCH error.
*/
class Apple2View extends GLSurfaceView {
class Apple2View extends GLSurfaceView implements InputManagerCompat.InputDeviceListener {
private final static String TAG = "Apple2View";
private final static boolean DEBUG = false;
private final static int MAX_FINGERS = 32;// HACK ...
public final static long NATIVE_TOUCH_HANDLED = (1 << 0);
public final static long NATIVE_TOUCH_REQUEST_SHOW_MENU = (1 << 1);
public final static long NATIVE_TOUCH_KEY_TAP = (1 << 4);
public final static long NATIVE_TOUCH_KBD = (1 << 5);
public final static long NATIVE_TOUCH_JOY = (1 << 6);
public final static long NATIVE_TOUCH_MENU = (1 << 7);
public final static long NATIVE_TOUCH_JOY_KPAD = (1 << 8);
public final static long NATIVE_TOUCH_INPUT_DEVICE_CHANGED = (1 << 16);
public final static long NATIVE_TOUCH_CPU_SPEED_DEC = (1 << 17);
public final static long NATIVE_TOUCH_CPU_SPEED_INC = (1 << 18);
public final static long NATIVE_TOUCH_ASCII_SCANCODE_SHIFT = 32;
public final static long NATIVE_TOUCH_ASCII_SCANCODE_MASK = 0xFFFFL;
public final static long NATIVE_TOUCH_ASCII_MASK = 0xFF00L;
public final static long NATIVE_TOUCH_SCANCODE_MASK = 0x00FFL;
private Apple2Activity mActivity;
private Runnable mGraphicsInitializedRunnable;
private final InputManagerCompat mInputManager;
private float[] mXCoords = new float[MAX_FINGERS];
private float[] mYCoords = new float[MAX_FINGERS];
private Apple2Activity mActivity = null;
private Runnable mGraphicsInitializedRunnable = null;
private static native void nativeGraphicsInitialized(int width, int height);
@@ -59,11 +73,24 @@ class Apple2View extends GLSurfaceView {
private static native void nativeRender();
private static native void nativeOnJoystickMove(int x, int y);
public static native long nativeOnTouch(int action, int pointerCount, int pointerIndex, float[] xCoords, float[] yCoords);
public Apple2View(Apple2Activity activity, Runnable graphicsInitializedRunnable) {
super(activity.getApplication());
mActivity = activity;
mGraphicsInitializedRunnable = graphicsInitializedRunnable;
setFocusable(true);
setFocusableInTouchMode(true);
mInputManager = InputManagerCompat.Factory.getInputManager(this.getContext());
if (mInputManager != null) {
mInputManager.registerInputDeviceListener(this, null);
}
/* By default, GLSurfaceView() creates a RGB_565 opaque surface.
* If we want a translucent one, we should change the surface's
* format here, using PixelFormat.TRANSLUCENT for GL Surfaces
@@ -114,7 +141,7 @@ class Apple2View extends GLSurfaceView {
public EGLContext createContext(EGL10 egl, EGLDisplay display, EGLConfig eglConfig) {
Log.w(TAG, "creating OpenGL ES 2.0 context");
checkEglError("Before eglCreateContext", egl);
int[] attrib_list = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE };
int[] attrib_list = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE};
EGLContext context = egl.eglCreateContext(display, eglConfig, EGL10.EGL_NO_CONTEXT, attrib_list);
checkEglError("After eglCreateContext", egl);
return context;
@@ -149,12 +176,12 @@ class Apple2View extends GLSurfaceView {
*/
private static int EGL_OPENGL_ES2_BIT = 4;
private static int[] s_configAttribs2 = {
EGL10.EGL_RED_SIZE, 4,
EGL10.EGL_GREEN_SIZE, 4,
EGL10.EGL_BLUE_SIZE, 4,
EGL10.EGL_ALPHA_SIZE, 4,
EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
EGL10.EGL_NONE
EGL10.EGL_RED_SIZE, 4,
EGL10.EGL_GREEN_SIZE, 4,
EGL10.EGL_BLUE_SIZE, 4,
EGL10.EGL_ALPHA_SIZE, 4,
EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
EGL10.EGL_NONE
};
public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) {
@@ -174,7 +201,7 @@ class Apple2View extends GLSurfaceView {
egl.eglChooseConfig(display, s_configAttribs2, configs, numConfigs, num_config);
if (DEBUG) {
printConfigs(egl, display, configs);
printConfigs(egl, display, configs);
}
// Now return the "best" one
@@ -303,11 +330,11 @@ class Apple2View extends GLSurfaceView {
for (int i = 0; i < attributes.length; i++) {
int attribute = attributes[i];
String name = names[i];
if ( egl.eglGetConfigAttrib(display, config, attribute, value)) {
if (egl.eglGetConfigAttrib(display, config, attribute, value)) {
Log.w(TAG, String.format(" %s: %d\n", name, value[0]));
} else {
// Log.w(TAG, String.format(" %s: failed\n", name));
while (egl.eglGetError() != EGL10.EGL_SUCCESS);
while (egl.eglGetError() != EGL10.EGL_SUCCESS) ;
}
}
}
@@ -351,7 +378,7 @@ class Apple2View extends GLSurfaceView {
Apple2View.this.mGraphicsInitializedRunnable = null;
}
Apple2View.this.mActivity.maybeResumeCPU();
Apple2View.this.mActivity.maybeResumeEmulation();
}
@Override
@@ -359,4 +386,193 @@ class Apple2View extends GLSurfaceView {
// Do nothing.
}
}
// --------------------------------------------------------------------------
// Event handling, touch, keyboard, gamepad
@Override
public void onInputDeviceAdded(int deviceId) {
}
@Override
public void onInputDeviceChanged(int deviceId) {
}
@Override
public void onInputDeviceRemoved(int deviceId) {
}
@Override
public boolean onGenericMotionEvent(MotionEvent event) {
if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) {
return super.onGenericMotionEvent(event);
}
if (mActivity.isEmulationPaused()) {
return super.onGenericMotionEvent(event);
}
// Check that the event came from a joystick or gamepad since a generic
// motion event could be almost anything.
int eventSource = event.getSource();
if ((event.getAction() == MotionEvent.ACTION_MOVE) && (((eventSource & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD) || ((eventSource & InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK))) {
int id = event.getDeviceId();
if (id != -1) {
InputDevice device = event.getDevice();
float x = getCenteredAxis(event, device, MotionEvent.AXIS_X);
if (x == 0) {
x = getCenteredAxis(event, device, MotionEvent.AXIS_HAT_X);
}
if (x == 0) {
x = getCenteredAxis(event, device, MotionEvent.AXIS_Z);
}
float y = getCenteredAxis(event, device, MotionEvent.AXIS_Y);
if (y == 0) {
y = getCenteredAxis(event, device, MotionEvent.AXIS_HAT_Y);
}
if (y == 0) {
y = getCenteredAxis(event, device, MotionEvent.AXIS_RZ);
}
int normal_x = (int) ((x + 1.f) * 128.f);
if (normal_x < 0) {
normal_x = 0;
}
if (normal_x > 255) {
normal_x = 255;
}
int normal_y = (int) ((y + 1.f) * 128.f);
if (normal_y < 0) {
normal_y = 0;
}
if (normal_y > 255) {
normal_y = 255;
}
nativeOnJoystickMove(normal_x, normal_y);
return true;
}
}
return super.onGenericMotionEvent(event);
}
private static float getCenteredAxis(MotionEvent event, InputDevice device, int axis) {
if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) {
return 0;
}
final InputDevice.MotionRange range = device.getMotionRange(axis, event.getSource());
if (range != null) {
final float flat = range.getFlat();
final float value = event.getAxisValue(axis);
// Ignore axis values that are within the 'flat' region of the joystick axis center.
// A joystick at rest does not always report an absolute position of (0,0).
if (Math.abs(value) > flat) {
return value;
}
}
return 0;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
do {
if (Apple2Activity.isNativeBarfed()) {
break;
}
if (mActivity.getMainMenu() == null) {
break;
}
Apple2MenuView apple2MenuView = mActivity.peekApple2View();
if ((apple2MenuView != null) && (!apple2MenuView.isCalibrating())) {
break;
}
//printSamples(event);
int action = event.getActionMasked();
int pointerIndex = event.getActionIndex();
int pointerCount = event.getPointerCount();
for (int i = 0; i < pointerCount/* && i < MAX_FINGERS */; i++) {
mXCoords[i] = event.getX(i);
mYCoords[i] = event.getY(i);
}
long nativeFlags = nativeOnTouch(action, pointerCount, pointerIndex, mXCoords, mYCoords);
if ((nativeFlags & NATIVE_TOUCH_HANDLED) == 0) {
break;
}
if ((nativeFlags & NATIVE_TOUCH_REQUEST_SHOW_MENU) != 0) {
mActivity.getMainMenu().show();
}
if ((nativeFlags & NATIVE_TOUCH_KEY_TAP) != 0) {
if (Apple2Preferences.KEYBOARD_CLICK_ENABLED.booleanValue(mActivity)) {
AudioManager am = (AudioManager) mActivity.getSystemService(Context.AUDIO_SERVICE);
if (am != null) {
am.playSoundEffect(AudioManager.FX_KEY_CLICK);
}
}
if ((apple2MenuView != null) && apple2MenuView.isCalibrating()) {
long asciiScancodeLong = nativeFlags & (NATIVE_TOUCH_ASCII_SCANCODE_MASK << NATIVE_TOUCH_ASCII_SCANCODE_SHIFT);
int asciiInt = (int) (asciiScancodeLong >> (NATIVE_TOUCH_ASCII_SCANCODE_SHIFT + 8));
int scancode = (int) ((asciiScancodeLong >> NATIVE_TOUCH_ASCII_SCANCODE_SHIFT) & 0xFFL);
char ascii = (char) asciiInt;
apple2MenuView.onKeyTapCalibrationEvent(ascii, scancode);
}
}
if ((nativeFlags & NATIVE_TOUCH_MENU) == 0) {
break;
}
// handle menu-specific actions
if ((nativeFlags & NATIVE_TOUCH_INPUT_DEVICE_CHANGED) != 0) {
Apple2Preferences.TouchDeviceVariant nextVariant;
if ((nativeFlags & NATIVE_TOUCH_KBD) != 0) {
nextVariant = Apple2Preferences.TouchDeviceVariant.KEYBOARD;
} else if ((nativeFlags & NATIVE_TOUCH_JOY) != 0) {
nextVariant = Apple2Preferences.TouchDeviceVariant.JOYSTICK;
} else if ((nativeFlags & NATIVE_TOUCH_JOY_KPAD) != 0) {
nextVariant = Apple2Preferences.TouchDeviceVariant.JOYSTICK_KEYPAD;
} else {
int touchDevice = Apple2Preferences.nativeGetCurrentTouchDevice();
nextVariant = Apple2Preferences.TouchDeviceVariant.next(touchDevice);
}
Apple2Preferences.CURRENT_TOUCH_DEVICE.saveTouchDevice(mActivity, nextVariant);
} else if ((nativeFlags & NATIVE_TOUCH_CPU_SPEED_DEC) != 0) {
int percentSpeed = Apple2Preferences.nativeGetCPUSpeed();
if (percentSpeed > 400) { // HACK: max value from native side
percentSpeed = 375;
} else if (percentSpeed > 100) {
percentSpeed -= 25;
} else {
percentSpeed -= 5;
}
Apple2Preferences.CPU_SPEED_PERCENT.saveInt(mActivity, percentSpeed);
} else if ((nativeFlags & NATIVE_TOUCH_CPU_SPEED_INC) != 0) {
int percentSpeed = Apple2Preferences.nativeGetCPUSpeed();
if (percentSpeed >= 100) {
percentSpeed += 25;
} else {
percentSpeed += 5;
}
Apple2Preferences.CPU_SPEED_PERCENT.saveInt(mActivity, percentSpeed);
}
} while (false);
return true;
}
}

View File

@@ -0,0 +1,162 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="black">#000000</color>
<color name="white">#ffffff</color>
<!-- developer-only options -->
<string name="crasher_summary">Test crash generation</string>
<string name="crasher_title">Crash emulator</string>
<string name="crash_null">NULL-deref</string>
<string name="crash_java_npe">Java NPE</string>
<string name="crash_stackcall_overflow">stack call overflow</string>
<string name="crash_stackbuf_overflow">stack buffer overflow</string>
<!-- main options -->
<string name="about_apple2ix">Acerca de Apple2ix…</string>
<string name="about_apple2ix_summary">Acerca de este software</string>
<string name="app_name">Apple2ix</string>
<string name="audio_configure">Configurar audio…</string>
<string name="audio_configure_summary">Ajustar el volumen del altavoz, "Mockingboard", etc</string>
<string name="audio_latency">La latencia de audio</string>
<string name="audio_latency_summary">La latencia de audio en segundos</string>
<string name="cancel">Cancelar</string>
<string name="color_bw">Blanco/negro</string>
<string name="color_color">Color</string>
<string name="color_interpolated">Color interpolado</string>
<string name="crasher">Fallos del software</string>
<string name="crasher_check_title">Fallos del software</string>
<string name="crasher_check_summary">Verificar la presencia de fallos del software</string>
<string name="crasher_send">¿Enviar informe de error?</string>
<string name="crasher_send_message">Lo sentimos, ha habido un problema. ¿Desea enviar informe de error para el programador de software?</string>
<string name="diskA">Disquetera 1</string>
<string name="diskB">Disquetera 2</string>
<string name="disk_eject">Eyectar</string>
<string name="disk_insert_toast">Disco insertado en la disquetera de sólo lectura</string>
<string name="disk_insert_could_not_read">Lo sentimos, no se puede leer la imagen de disquete!</string>
<string name="disk_read_only">Sólo leer</string>
<string name="disk_read_write">Leer y escribir</string>
<string name="disk_show_operation">Mostrar las operaciones de "Disk ]["</string>
<string name="disk_show_operation_summary">Shows when disk drives are reading or writing</string>
<string name="emulation_continue">Continuar…</string>
<string name="emulation_settings">Configuración…</string>
<string name="emulation_disks">Insertar imagen de disquete…</string>
<string name="header_disks">Insertar imagen de disquete:</string>
<string name="input_current">Unidad de entrada actual</string>
<string name="input_current_summary">Elija unidad de entrada</string>
<string name="joystick">"Joystick"</string>
<string name="joystick_axis_sensitivity_summary">Afinar la sensibilidad del eje del joystick (desacelerar o acelerar)</string>
<string name="joystick_button_button1">Botón 1</string>
<string name="joystick_button_button2">Botón 2</string>
<string name="joystick_button_button_both">Los dos</string>
<string name="joystick_button_button_none">Ninguno</string>
<string name="joystick_button_tap_button">Toque para disparar</string>
<string name="joystick_button_tap_button_summary">Botón para disparar sobre toque abajo</string>
<string name="joystick_button_tapdelay_summary">Toque retardo del joystick en segundos</string>
<string name="joystick_button_swipe_up_button">Pase hacia arriba</string>
<string name="joystick_button_swipe_up_button_summary">Botón para disparar sobre pase el dedo hacia arriba</string>
<string name="joystick_button_swipe_down_button">Pase hacia abajo</string>
<string name="joystick_button_swipe_down_button_summary">Botón para disparar sobre pase el dedo hacia abajo</string>
<string name="joystick_button_threshold_summary">Umbral del joystick en puntos</string>
<string name="joystick_calibrate">Calibrar…</string>
<string name="joystick_calibrate_summary">Calibrar el joystick</string>
<string name="joystick_configure">Configurar el joystick…</string>
<string name="joystick_configure_summary">Eje táctil, los botónes, etc</string>
<string name="joystick_axisleft">Eje del joystick a la izquierda</string>
<string name="joystick_axisleft_summary">Eje del joystick a la izquierda (los botónes de la derecha)</string>
<string name="joystick_visible">Visibilidad del joystick</string>
<string name="joystick_visible_summary">Mostrar controles cuando se utiliza</string>
<string name="key_closed_apple">[Botón 2]</string>
<string name="key_ctrl">[Ctrl]</string>
<string name="key_down">&#8595;</string>
<string name="key_esc">[ESC]</string>
<string name="key_left">&#8592;</string>
<string name="key_none">[Ninguno]</string>
<string name="key_open_apple">[Botón 1]</string>
<string name="key_ret">[Retorno]</string>
<string name="key_right">&#8594;</string>
<string name="key_space">[Espaciadora]</string>
<string name="key_up">&#8593;</string>
<string name="keyboard">Teclado</string>
<string name="keyboard_choose_alt">Elija teclado alternativo…</string>
<string name="keyboard_choose_alt_summary">Elija el diseño de teclado alternativo</string>
<string name="keyboard_click_enabled">Habilitar la tecla de sonido de clic</string>
<string name="keyboard_click_enabled_summary">Haga clic en sonido de clave permite si está disponible</string>
<string name="keyboard_configure">Configurar el teclado…</string>
<string name="keyboard_configure_summary">Transparencia, minúsculas, teclado personalizado</string>
<string name="keyboard_lowercase_enabled">Habilitar minúsculas</string>
<string name="keyboard_lowercase_enabled_summary">Utilice las teclas minúsculas</string>
<string name="keyboard_visibility_active">Visibilidad cuando está activo</string>
<string name="keyboard_visibility_active_summary">Visibilidad del teclado cuando está activo</string>
<string name="keyboard_visibility_inactive">Visibilidad cuando está inactivo</string>
<string name="keyboard_visibility_inactive_summary">Visibilidad del teclado cuando está inactivo</string>
<string name="keypad">Joystick como teclado numérico</string>
<string name="keypad_calibrate">@string/joystick_calibrate</string>
<string name="keypad_calibrate_summary">@string/joystick_calibrate</string>
<string name="keypad_choose">Teclas del teclado numérico…</string>
<string name="keypad_choose_summary">Elegir las teclas del joystick del teclado numérico</string>
<string name="keypad_choose_title">Ejes y botones</string>
<string name="keypad_choose_current">Elija [XXX] tecla del teclado: </string>
<string name="keypad_configure">Configurar el joystick del teclado numérico…</string>
<string name="keypad_configure_summary">@string/joystick_configure_summary</string>
<string name="keypad_key_axis_c">Centro</string>
<string name="keypad_key_axis_dn">Abajo</string>
<string name="keypad_key_axis_dl">Abajo y a la izquierda</string>
<string name="keypad_key_axis_dr">Abajo y a la derecha</string>
<string name="keypad_key_axis_l">Izquierda</string>
<string name="keypad_key_axis_r">Derecha</string>
<string name="keypad_key_axis_ul">Arriba y a la izquierda</string>
<string name="keypad_key_axis_up">Arriba</string>
<string name="keypad_key_axis_ur">Arriba y a la derecha</string>
<string name="keypad_key_button_tap">Toque</string>
<string name="keypad_key_button_swipeup">Desliza el dedo hacia arriba</string>
<string name="keypad_key_button_swipedown"> Desliza el dedo hacia abajo</string>
<string name="keypad_preset_crazy_seafox">Seafox keys ;-)…</string>
<string name="keypad_preset_custom">Elija personalizado…</string>
<string name="keypad_preset_arrows_space">&#8593;,&#8592;,&#8594;,&#8595;, pulse espaciadora</string>
<string name="keypad_preset_az_left_right_space">A,Z,&#8592;,&#8594;, pulse espaciadora</string>
<string name="keypad_preset_ijkm_space">I,J,K,M, pulse espaciadora</string>
<string name="keypad_preset_left_right_space">&#8592;,&#8594;, pulse espaciadora</string>
<string name="keypad_preset_wadx_space">W,A,D,X, pulse espaciadora</string>
<string name="keypad_repeat_summary">Umbral de repetición de teclas en segundos</string>
<string name="menu_disks">Insertar imagen de disco…</string>
<string name="menu_disks_summary">Insertar imagen de "Disk ]["</string>
<string name="menu_settings">Configuración del emulador…</string>
<string name="menu_settings_summary">Configuración general, joystick, teclado</string>
<string name="mockingboard_disabled_title">Mockingboard desactivado</string>
<string name="mockingboard_disabled_mesg">Mockingboard no pudo ser habilitado</string>
<string name="mockingboard_enable">Activar Mockingboard</string>
<string name="mockingboard_enable_summary">Revisión C en la ranura 4/5 puede requerir reinicio</string>
<string name="mockingboard_volume">Volumen de Mockingboard</string>
<string name="mockingboard_volume_summary">Adjustar el volumen del Mockingboard</string>
<string name="no">No</string>
<string name="ok"></string>
<string name="preferences_reset_title">Restablecer preferencias</string>
<string name="preferences_reset_summary">Restablecer preferencias y salir</string>
<string name="preferences_reset_really">¿Restablecer realmente y salir?</string>
<string name="preferences_reset_warning">Usted perderá su configuración</string>
<string name="quit">Salir</string>
<string name="quit_reboot">Reiniciar o salir el emulador…</string>
<string name="quit_reboot_choice">¿Reiniciar o salir?</string>
<string name="reboot">Reiniciar</string>
<string name="restore">Restauración rápida</string>
<string name="save">Guardar rápido</string>
<string name="saverestore">Guardar y restaurar…</string>
<string name="saverestore_choice">¿Guardar el estado actual o anterior de restauración?</string>
<string name="saverestore_summary">Guardar y restaurar rápida</string>
<string name="skip">Saltar&#8594;</string>
<string name="speaker_volume">El volumen del altavoz</string>
<string name="speaker_volume_summary">Ajustar el volumen del altavoz</string>
<string name="settings">Configuración Apple2ix</string>
<string name="settings_advanced">Configuración avanzada</string>
<string name="settings_advanced_summary">Advertencia: estos valores puede degradar el rendimiento</string>
<string name="settings_advanced_joystick">Configuración de teclado y joystick avanzados</string>
<string name="settings_advanced_joystick_summary">Configuración avanzada y optimización del rendimiento</string>
<string name="touch_menu_enable">Activar menús táctiles</string>
<string name="touch_menu_enable_summary">Los botones del menú en la parte superior de la pantalla</string>
<string name="touch_menu_visibility">Visibilidad del menú</string>
<string name="touch_menu_visibility_summary">Visibilidad del menú cuando está inactivo</string>
<string name="video_configure">Configurar el video…</string>
<string name="video_configure_summary">Ajustes de color</string>
</resources>

View File

@@ -5,7 +5,6 @@
"_comment" : "hex code for special glyphs",
"_AA" : "b5",
"_CTRL": "b3",
"_XX" : "9b",
"_ESC" : "bc",
"_OA" : "81",
"_CA" : "80",
@@ -20,7 +19,7 @@
["_AA", "", "_CTRL", "", "_ESC", "", "_OA", "", "_CA", ""],
[ "", "", "", "", "", "", "", "", "", ""],
[ "", "", "", "", "", "_UP", "", "", "", ""],
[ "", "", "", "", "_LT", "_XX", "_RT", "", "", ""],
[ "", "", "", "", "_LT", "_AA", "_RT", "", "", ""],
[ "", "", "", "", "", "_DN", "", "", "", ""],
[ "", "", "", "", "", "", "", "", "", ""]
]

View File

@@ -9,11 +9,11 @@
"_SP" : "b1"
},
[ "reserved for future use" ],
[ "reserved for future use" ],
[ "", "", "", "", "", "", "", "", "", "" ],
[ "_AA", "", "", "", "", "", "", "", "", "" ],
[ "", "", "", "", "", "", "", "", "", "" ],
[ "", "", "", "", "", "", "", "", "", "" ],
[ "", "", "", "", "", "", "", "", "", "" ],
[ "Q", "", "", "", "", "", "", "", "A", "" ],
[ "", "", "", "", "", "", "", "_LT", "", "_RT" ],
[ "_SP", "", "", "", "", "", "", "", "Z", "" ]

View File

@@ -8,9 +8,9 @@
"_SP" : "b1"
},
["reserved for future use"],
["reserved for future use"],
["_AA", "", "", "", "", "", "", "", "", "D"],
[ "Q", "", "", "", "", "", "", "", "", "" ],
[ "", "", "", "", "", "", "", "", "", "V"],
[ "_AA", "", "", "", "", "", "", "", "", "D"],
[ "_ESC", "", "", "", "", "", "", "", "", "G"],
[ "Y", "", "", "", "", "", "", "", "", "" ],
[ "N", "", "", "", "", "", "", "I", "O", "P"],

View File

@@ -12,12 +12,12 @@
"_SP" : "b1"
},
["reserved for future use"],
["reserved for future use"],
[ "Q", "", "", "", "", "", "", "", "K", "X"],
[ "P", "", "", "", "", "", "", "", "D", "B"],
["_AA", "", "", "", "", "", "1", "2", "3", "4"],
[ "N", "", "", "", "", "", "5", "6", "7", "8"],
[ "Y", "", "", "", "", "", "Z", "G", "", "_ESC"],
[ "S", "", "", "", "", "", "C", "", "_UP", "" ],
[ "", "", "", "", "", "", "", "_LT", "", "_RT"],
[ "A", "", "T", "O", "", "", "_SP", "", "_DN", ""]
[ "", "", "", "", "", "", "", "_LT", "", "_RT"],
[ "A", "", "T", "O", "J", "E", "_SP", "", "_DN", ""]
]

View File

View File

@@ -40,6 +40,19 @@ void android_keycode_to_emulator(int keyCode, int metaState, bool pressed) {
break;
}
switch (keyCode) {
case KEYCODE_BUTTON_A:
case KEYCODE_BUTTON_X:
case KEYCODE_BUTTON_L1:
joydriver_setButton0Pressed(pressed);
return;
case KEYCODE_BUTTON_B:
case KEYCODE_BUTTON_Y:
case KEYCODE_BUTTON_R1:
joydriver_setButton1Pressed(pressed);
return;
}
switch (keyCode) {
case KEYCODE_0:
key = _is_shifted(metaState) ? ')' : keyCode + ASCII_0_OFFSET;

View File

@@ -98,6 +98,8 @@
#define KEYCODE_BUTTON_L2 0x68
#define KEYCODE_BUTTON_R1 0x67
#define KEYCODE_BUTTON_R2 0x69
#define KEYCODE_BUTTON_X 0x63
#define KEYCODE_BUTTON_Y 0x64
#define META_ALT_LEFT_ON 0x00000010
#define META_ALT_RIGHT_ON 0x00000020

View File

@@ -47,6 +47,7 @@ typedef enum lifecycle_seq_t {
static lifecycle_seq_t appState = APP_RUNNING;
#if TESTING
static bool running_tests = false;
static void _run_tests(void) {
char *local_argv[] = {
"-f",
@@ -142,7 +143,7 @@ static void discover_cpu_family(void) {
// ----------------------------------------------------------------------------
// JNI functions
void Java_org_deadc0de_apple2ix_Apple2Activity_nativeOnCreate(JNIEnv *env, jobject obj, jstring j_dataDir, jint sampleRate, jint monoBufferSize, jint stereoBufferSize) {
void Java_org_deadc0de_apple2ix_Apple2Activity_nativeOnCreate(JNIEnv *env, jclass cls, jstring j_dataDir, jint sampleRate, jint monoBufferSize, jint stereoBufferSize) {
const char *dataDir = (*env)->GetStringUTFChars(env, j_dataDir, 0);
// Android lifecycle can call onCreate() multiple times...
@@ -170,11 +171,9 @@ void Java_org_deadc0de_apple2ix_Apple2Activity_nativeOnCreate(JNIEnv *env, jobje
android_monoBufferSubmitSizeSamples = (unsigned long)monoBufferSize;
android_stereoBufferSubmitSizeSamples = (unsigned long)stereoBufferSize;
#if TESTING
assert(cpu_thread_id == 0 && "CPU thread must not be initialized yet...");
_run_tests();
// CPU thread is started from testsuite (if needed)
#else
joydriver_setClampBeyondRadius(true);
#if !TESTING
cpu_pause();
emulator_start();
#endif
@@ -187,26 +186,31 @@ void Java_org_deadc0de_apple2ix_Apple2View_nativeGraphicsChanged(JNIEnv *env, jc
}
void Java_org_deadc0de_apple2ix_Apple2View_nativeGraphicsInitialized(JNIEnv *env, jclass cls, jint width, jint height) {
// WANRING : this needs to happen on the GL thread only
// WARNING : this needs to happen on the GL thread only
LOG("width:%d height:%d", width, height);
video_shutdown();
video_backend->reshape(width, height);
video_backend->init((void *)0);
}
void Java_org_deadc0de_apple2ix_Apple2Activity_nativeEmulationResume(JNIEnv *env, jobject obj) {
void Java_org_deadc0de_apple2ix_Apple2Activity_nativeEmulationResume(JNIEnv *env, jclass cls) {
#if TESTING
// test driver thread is managing CPU
if (!running_tests) {
running_tests = true;
assert(cpu_thread_id == 0 && "CPU thread must not be initialized yet...");
_run_tests();
}
#else
if (!cpu_isPaused()) {
return;
}
LOG("...");
#if TESTING
// test driver thread is managing CPU
#else
cpu_resume();
#endif
}
void Java_org_deadc0de_apple2ix_Apple2Activity_nativeEmulationPause(JNIEnv *env, jobject obj) {
void Java_org_deadc0de_apple2ix_Apple2Activity_nativeEmulationPause(JNIEnv *env, jclass cls) {
if (appState != APP_RUNNING) {
return;
}
@@ -257,12 +261,12 @@ void Java_org_deadc0de_apple2ix_Apple2View_nativeRender(JNIEnv *env, jclass cls)
video_backend->render();
}
void Java_org_deadc0de_apple2ix_Apple2Activity_nativeReboot(JNIEnv *env, jobject obj) {
void Java_org_deadc0de_apple2ix_Apple2Activity_nativeReboot(JNIEnv *env, jclass cls) {
LOG("...");
cpu65_reboot();
}
void Java_org_deadc0de_apple2ix_Apple2Activity_nativeOnQuit(JNIEnv *env, jobject obj) {
void Java_org_deadc0de_apple2ix_Apple2Activity_nativeOnQuit(JNIEnv *env, jclass cls) {
#if TESTING
// test driver thread is managing CPU
#else
@@ -277,21 +281,25 @@ void Java_org_deadc0de_apple2ix_Apple2Activity_nativeOnQuit(JNIEnv *env, jobject
#endif
}
void Java_org_deadc0de_apple2ix_Apple2Activity_nativeOnKeyDown(JNIEnv *env, jobject obj, jint keyCode, jint metaState) {
void Java_org_deadc0de_apple2ix_Apple2Activity_nativeOnKeyDown(JNIEnv *env, jclass cls, jint keyCode, jint metaState) {
if (UNLIKELY(appState != APP_RUNNING)) {
return;
}
android_keycode_to_emulator(keyCode, metaState, true);
}
void Java_org_deadc0de_apple2ix_Apple2Activity_nativeOnKeyUp(JNIEnv *env, jobject obj, jint keyCode, jint metaState) {
void Java_org_deadc0de_apple2ix_Apple2Activity_nativeOnKeyUp(JNIEnv *env, jclass cls, jint keyCode, jint metaState) {
if (UNLIKELY(appState != APP_RUNNING)) {
return;
}
android_keycode_to_emulator(keyCode, metaState, false);
}
jlong Java_org_deadc0de_apple2ix_Apple2Activity_nativeOnTouch(JNIEnv *env, jobject obj, jint action, jint pointerCount, jint pointerIndex, jfloatArray xCoords, jfloatArray yCoords) {
void Java_org_deadc0de_apple2ix_Apple2View_nativeOnJoystickMove(JNIEnv *env, jclass cls, jint x, jint y) {
joydriver_setAxisValue((uint8_t)x, (uint8_t)y);
}
jlong Java_org_deadc0de_apple2ix_Apple2View_nativeOnTouch(JNIEnv *env, jclass cls, jint action, jint pointerCount, jint pointerIndex, jfloatArray xCoords, jfloatArray yCoords) {
//LOG(": %d/%d/%d :", action, pointerCount, pointerIndex);
SCOPE_TRACE_TOUCH("nativeOnTouch");
@@ -316,7 +324,7 @@ jlong Java_org_deadc0de_apple2ix_Apple2Activity_nativeOnTouch(JNIEnv *env, jobje
return flags;
}
void Java_org_deadc0de_apple2ix_Apple2Activity_nativeChooseDisk(JNIEnv *env, jobject obj, jstring jPath, jboolean driveA, jboolean readOnly) {
void Java_org_deadc0de_apple2ix_Apple2Activity_nativeChooseDisk(JNIEnv *env, jclass cls, jstring jPath, jboolean driveA, jboolean readOnly) {
const char *path = (*env)->GetStringUTFChars(env, jPath, NULL);
int drive = driveA ? 0 : 1;
int ro = readOnly ? 1 : 0;
@@ -341,15 +349,15 @@ void Java_org_deadc0de_apple2ix_Apple2Activity_nativeChooseDisk(JNIEnv *env, job
(*env)->ReleaseStringUTFChars(env, jPath, path);
}
void Java_org_deadc0de_apple2ix_Apple2Activity_nativeEjectDisk(JNIEnv *env, jobject obj, jboolean driveA) {
void Java_org_deadc0de_apple2ix_Apple2Activity_nativeEjectDisk(JNIEnv *env, jclass cls, jboolean driveA) {
LOG("...");
disk6_eject(!driveA);
}
void Java_org_deadc0de_apple2ix_Apple2Activity_nativeSaveState(JNIEnv *env, jobject obj, jstring jPath) {
void Java_org_deadc0de_apple2ix_Apple2Activity_nativeSaveState(JNIEnv *env, jclass cls, jstring jPath) {
const char *path = (*env)->GetStringUTFChars(env, jPath, NULL);
assert(cpu_isPaused() && "considered dangerous to save state CPU thread is running");
assert(cpu_isPaused() && "considered dangerous to save state when CPU thread is running");
LOG(": (%s)", path);
if (!emulator_saveState(path)) {
@@ -359,10 +367,10 @@ void Java_org_deadc0de_apple2ix_Apple2Activity_nativeSaveState(JNIEnv *env, jobj
(*env)->ReleaseStringUTFChars(env, jPath, path);
}
jstring Java_org_deadc0de_apple2ix_Apple2Activity_nativeLoadState(JNIEnv *env, jobject obj, jstring jPath) {
jstring Java_org_deadc0de_apple2ix_Apple2Activity_nativeLoadState(JNIEnv *env, jclass cls, jstring jPath) {
const char *path = (*env)->GetStringUTFChars(env, jPath, NULL);
assert(cpu_isPaused() && "considered dangerous to save state CPU thread is running");
assert(cpu_isPaused() && "considered dangerous to save state when CPU thread is running");
LOG(": (%s)", path);
if (!emulator_loadState(path)) {

View File

@@ -18,6 +18,7 @@ LOCAL_LDLIBS := $(APPLE2_BASE_LDLIBS)
# Add assembly files first ... mostly for the benefit of the ARM assembler ...
ifeq ($(TARGET_ARCH_ABI),x86)
LOCAL_SRC_FILES += $(APPLE2_X86_SRC)
LOCAL_CFLAGS += -DNO_UNDERSCORES=1
else
LOCAL_SRC_FILES += $(APPLE2_ARM_SRC)
endif

View File

@@ -18,6 +18,7 @@ LOCAL_LDLIBS := $(APPLE2_BASE_LDLIBS)
# Add assembly files first ... mostly for the benefit of the ARM assembler ...
ifeq ($(TARGET_ARCH_ABI),x86)
LOCAL_SRC_FILES += $(APPLE2_X86_SRC)
LOCAL_CFLAGS += -DNO_UNDERSCORES=1
else
LOCAL_SRC_FILES += $(APPLE2_ARM_SRC)
endif

View File

@@ -18,6 +18,7 @@ LOCAL_LDLIBS := $(APPLE2_BASE_LDLIBS)
# Add assembly files first ... mostly for the benefit of the ARM assembler ...
ifeq ($(TARGET_ARCH_ABI),x86)
LOCAL_SRC_FILES += $(APPLE2_X86_SRC)
LOCAL_CFLAGS += -DNO_UNDERSCORES=1
else
LOCAL_SRC_FILES += $(APPLE2_ARM_SRC)
endif

View File

@@ -18,6 +18,7 @@ LOCAL_LDLIBS := $(APPLE2_BASE_LDLIBS)
# Add assembly files first ... mostly for the benefit of the ARM assembler ...
ifeq ($(TARGET_ARCH_ABI),x86)
LOCAL_SRC_FILES += $(APPLE2_X86_SRC)
LOCAL_CFLAGS += -DNO_UNDERSCORES=1
else
LOCAL_SRC_FILES += $(APPLE2_ARM_SRC)
endif

View File

@@ -127,26 +127,6 @@ void gldriver_joystick_reset(void) {
#pragma mark NSObject(DDHidJoystickDelegate)
#define DDHID_JOYSTICK_NORMALIZER ((float)JOY_RANGE/(DDHID_JOYSTICK_VALUE_MAX*2))
#define QUARTER_JOY (HALF_JOY_RANGE>>1)
static inline void clampBeyondRadius(void) {
CGFloat half_x = joy_x - HALF_JOY_RANGE;
CGFloat half_y = joy_y - HALF_JOY_RANGE;
CGFloat r = sqrtf(half_x*half_x + half_y*half_y);
bool shouldClip = (r > HALF_JOY_RANGE);
if (joy_clip_to_radius && shouldClip) {
if (joy_x < HALF_JOY_RANGE) {
joy_x = (joy_x < QUARTER_JOY) ? 0.f : joy_x;
} else {
joy_x = (joy_x < HALF_JOY_RANGE+QUARTER_JOY) ? joy_x : JOY_RANGE-1;
}
if (joy_y < HALF_JOY_RANGE) {
joy_y = (joy_y < QUARTER_JOY) ? 0.f : joy_y;
} else {
joy_y = (joy_y < HALF_JOY_RANGE+QUARTER_JOY) ? joy_y : JOY_RANGE-1;
}
}
}
- (void)ddhidJoystick:(DDHidJoystick *)joystick stick:(unsigned int)stick xChanged:(int)value
{
@@ -156,12 +136,8 @@ static inline void clampBeyondRadius(void) {
}
#endif
joy_x = (uint16_t)((value+DDHID_JOYSTICK_VALUE_MAX) * DDHID_JOYSTICK_NORMALIZER);
if (joy_x > 0xFF) {
joy_x = 0xFF;
}
clampBeyondRadius();
uint8_t x = (uint8_t)((value+DDHID_JOYSTICK_VALUE_MAX) * DDHID_JOYSTICK_NORMALIZER);
joydriver_setAxisValue(x, joydriver_getAxisY());
}
- (void)ddhidJoystick:(DDHidJoystick *)joystick stick:(unsigned int)stick yChanged:(int)value
@@ -172,12 +148,8 @@ static inline void clampBeyondRadius(void) {
}
#endif
joy_y = (uint16_t)((value+DDHID_JOYSTICK_VALUE_MAX) * DDHID_JOYSTICK_NORMALIZER);
if (joy_y > 0xFF) {
joy_y = 0xFF;
}
clampBeyondRadius();
uint8_t y = (uint8_t)((value+DDHID_JOYSTICK_VALUE_MAX) * DDHID_JOYSTICK_NORMALIZER);
joydriver_setAxisValue(joydriver_getAxisX(), y);
}
- (void)ddhidJoystick:(DDHidJoystick *)joystick stick:(unsigned int)stick otherAxis:(unsigned)otherAxis valueChanged:(int)value

View File

@@ -741,20 +741,17 @@ static long opensles_systemResume(AudioContext_s *audio_context) {
break;
}
#if !TESTING
assert(state != SL_PLAYSTATE_PLAYING && "mismatch between systemPause/systemResume");
#endif
if (state != SL_PLAYSTATE_PLAYING) {
ERRLOG("WARNING: possible audio lifecycle mismatch ... continuing anyway");
}
if (state == SL_PLAYSTATE_PAUSED) {
// Balanced resume OK here
SLresult result = (*(ctx->bqPlayerPlay))->SetPlayState(ctx->bqPlayerPlay, SL_PLAYSTATE_PLAYING);
#if !TESTING
} else {
} else if (state == SL_PLAYSTATE_STOPPED) {
// Do not resume for stopped state, let this get forced from CPU/speaker thread otherwise we starve. (The
// stopped state happens if user dynamically changed buffer parameters in menu settings which triggered an
// OpenSLES destroy/re-initialization ... e.g. audio_setLatency() was invoked)
assert(state == SL_PLAYSTATE_STOPPED);
#endif
}
} while (0);

View File

@@ -253,6 +253,55 @@ void c_joystick_reset(void)
#endif
}
// clamps modern gamepad controller axis values to the "corners" of a traditional joystick as used on the Apple //e
static inline void clampBeyondRadius(uint8_t *x, uint8_t *y) {
float half_x = (*x) - HALF_JOY_RANGE;
float half_y = (*y) - HALF_JOY_RANGE;
float r = sqrtf(half_x*half_x + half_y*half_y);
bool shouldClip = (r > HALF_JOY_RANGE);
if (joy_clip_to_radius && shouldClip) {
if ((*x) < HALF_JOY_RANGE) {
(*x) = ((*x) < QUARTER_JOY_RANGE) ? 0.f : (*x);
} else {
(*x) = ((*x) < HALF_JOY_RANGE+QUARTER_JOY_RANGE) ? (*x) : 0xFF;
}
if ((*y) < HALF_JOY_RANGE) {
(*y) = ((*y) < QUARTER_JOY_RANGE) ? 0.f : (*y);
} else {
(*y) = ((*y) < HALF_JOY_RANGE+QUARTER_JOY_RANGE) ? (*y) : JOY_RANGE-1;
}
}
}
void joydriver_setClampBeyondRadius(bool clamp) {
joy_clip_to_radius = clamp;
}
void joydriver_setAxisValue(uint8_t x, uint8_t y) {
clampBeyondRadius(&x, &y);
joy_x = x;
joy_y = y;
}
uint8_t joydriver_getAxisX(void) {
return joy_x;
}
// return Y axis value
uint8_t joydriver_getAxisY(void) {
return joy_y;
}
// set button 0 pressed
void joydriver_setButton0Pressed(bool pressed) {
joy_button0 = (pressed) ? 0x80 : 0x0;
}
// set button 1 pressed
void joydriver_setButton1Pressed(bool pressed) {
joy_button1 = (pressed) ? 0x80 : 0x0;
}
#if INTERFACE_TOUCH
bool (*joydriver_isTouchJoystickAvailable)(void) = NULL;
void (*joydriver_setTouchJoystickEnabled)(bool enabled) = NULL;

View File

@@ -13,7 +13,8 @@
#define _JOYSTICK_H_
#define JOY_RANGE 0x100
#define HALF_JOY_RANGE 0x80
#define HALF_JOY_RANGE (JOY_RANGE>>1)
#define QUARTER_JOY_RANGE (HALF_JOY_RANGE>>1)
extern uint16_t joy_x;
extern uint16_t joy_y;
@@ -32,6 +33,24 @@ void c_joystick_reset(void);
void c_calibrate_joystick(void);
#endif
// enable/disable gamepad clamping to joystick corners
void joydriver_setClampBeyondRadius(bool clamp);
// set joystick axis values
void joydriver_setAxisValue(uint8_t x, uint8_t y);
// return X axis value
uint8_t joydriver_getAxisX(void);
// return Y axis value
uint8_t joydriver_getAxisY(void);
// set button 0 pressed
void joydriver_setButton0Pressed(bool pressed);
// set button 1 pressed
void joydriver_setButton1Pressed(bool pressed);
#if INTERFACE_TOUCH
typedef enum touchjoy_variant_t {

View File

@@ -128,9 +128,10 @@ void test_common_init() {
}
int test_setup_boot_disk(const char *fileName, int readonly) {
char *disk = NULL;
int err = 0;
#ifdef __APPLE__
char **path = NULL;
#if defined(__APPLE__)
CFBundleRef mainBundle = CFBundleGetMainBundle();
CFStringRef fileString = CFStringCreateWithCString(/*allocator*/NULL, fileName, CFStringGetSystemEncoding());
CFURLRef fileURL = CFBundleCopyResourceURL(mainBundle, fileString, NULL, NULL);
@@ -144,15 +145,48 @@ int test_setup_boot_disk(const char *fileName, int readonly) {
FREE(disk);
}
CFRELEASE(filePath);
char *paths[] = {
disk,
NULL,
};
#else
asprintf(&disk, "%s/disks/%s", data_dir, fileName);
char *paths[] = {
NULL,
NULL,
NULL,
NULL,
};
asprintf(&paths[0], "%s/disks/%s", data_dir, fileName);
asprintf(&paths[1], "%s/disks/demo/%s", data_dir, fileName);
asprintf(&paths[2], "%s/disks/blanks/%s", data_dir, fileName);
#endif
if (disk6_insert(0, disk, readonly)) {
path = &paths[0];
while (*path) {
char *disk = *path;
++path;
err = disk6_insert(0, disk, readonly) != NULL;
if (!err) {
break;
}
int len = strlen(disk);
disk[len-3] = '\0'; // try again without '.gz' extension
err = (disk6_insert(0, disk, readonly) != NULL);
err = disk6_insert(0, disk, readonly) != NULL;
if (!err) {
break;
}
}
FREE(disk);
path = &paths[0];
while (*path) {
char *disk = *path;
++path;
FREE(disk);
}
return err;
}
@@ -161,6 +195,5 @@ void sha1_to_str(const uint8_t * const md, char *buf) {
for (int j=0; j<SHA_DIGEST_LENGTH; j++, i+=2) {
sprintf(buf+i, "%02X", md[j]);
}
sprintf(buf+i, "%c", '\0');
}

File diff suppressed because it is too large Load Diff

View File

@@ -237,7 +237,7 @@ TEST test_read_null_bytes() {
c_debugger_go();
ASSERT(apple_ii_64k[0][WATCHPOINT_ADDR] == TEST_FINISHED);
ASSERT(apple_ii_64k[0][TESTOUT_ADDR] == 0x00);
ASSERT(apple_ii_64k[0][TESTOUT_ADDR] == 0xFF);
PASS();
}
@@ -1436,12 +1436,16 @@ GREATEST_MAIN_DEFS();
static char **test_argv = NULL;
static int test_argc = 0;
static void *test_thread(void *dummyptr) {
static int _test_thread(void) {
int argc = test_argc;
char **argv = test_argv;
GREATEST_MAIN_BEGIN();
RUN_SUITE(test_suite_disk);
GREATEST_MAIN_END();
}
static void *test_thread(void *dummyptr) {
_test_thread();
return NULL;
}

View File

@@ -32,7 +32,7 @@ static void testdisplay_teardown(void *arg) {
// Various Display Tests ...
TEST test_boot_disk() {
test_setup_boot_disk("testdisplay1.nib.gz", 1);
test_setup_boot_disk("testdisplay1.dsk.gz", 1);
BOOT_TO_DOS();
@@ -306,13 +306,13 @@ TEST test_80col_hires() {
c_debugger_go();
ASSERT(apple_ii_64k[0][WATCHPOINT_ADDR] == TEST_FINISHED);
ASSERT_SHA("10F63A7B11EBF5019AE6D1F64AA7BACEA903426D");
ASSERT_SHA("126363F103F3A24BB2EB2AEC5B4972F46F7CA24B");
apple_ii_64k[0][WATCHPOINT_ADDR] = 0x00;
c_debugger_go();
ASSERT(apple_ii_64k[0][WATCHPOINT_ADDR] == TEST_FINISHED);
ASSERT_SHA("CC81BD3FE7055126D3FA13231CBD86E7C49590AA");
ASSERT_SHA("91F63831B6D1145446F0DBACE8EBD284B5690D81");
PASS();
}
@@ -443,12 +443,16 @@ GREATEST_MAIN_DEFS();
static char **test_argv = NULL;
static int test_argc = 0;
static void *test_thread(void *dummyptr) {
static int _test_thread(void) {
int argc = test_argc;
char **argv = test_argv;
GREATEST_MAIN_BEGIN();
RUN_SUITE(test_suite_display);
GREATEST_MAIN_END();
}
static void *test_thread(void *dummyptr) {
_test_thread();
return NULL;
}

View File

@@ -33,7 +33,7 @@ static void testvm_teardown(void *arg) {
// VM TESTS ...
TEST test_boot_disk() {
test_setup_boot_disk("testvm1.nib.gz", 1);
test_setup_boot_disk("testvm1.dsk.gz", 1);
BOOT_TO_DOS();
@@ -1071,8 +1071,6 @@ TEST test_HIRES_off(bool flag_ramrd, bool flag_ramwrt) {
uint32_t switch_save = softswitches;
uint8_t *save_base_textrd = base_textrd;
uint8_t *save_base_textwrt = base_textwrt;
uint8_t *save_base_hgrrd = base_hgrrd;
uint8_t *save_base_hgrwrt = base_hgrwrt;
int save_current_page = video__current_page;
apple_ii_64k[0][WATCHPOINT_ADDR] = 0x00;
@@ -1288,8 +1286,6 @@ TEST test_lc_c082() {
uint8_t *save_base_textwrt = base_textwrt;
uint8_t *save_base_hgrrd = base_hgrrd;
uint8_t *save_base_hgrwrt = base_hgrwrt;
uint8_t *save_base_d000_wrt = base_d000_wrt;
uint8_t *save_base_e000_wrt = base_e000_wrt;
int save_current_page = video__current_page;
ASM_INIT();
@@ -1541,8 +1537,6 @@ TEST test_lc_c08a() {
uint8_t *save_base_textwrt = base_textwrt;
uint8_t *save_base_hgrrd = base_hgrrd;
uint8_t *save_base_hgrwrt = base_hgrwrt;
uint8_t *save_base_d000_wrt = base_d000_wrt;
uint8_t *save_base_e000_wrt = base_e000_wrt;
int save_current_page = video__current_page;
ASM_INIT();
@@ -1755,11 +1749,8 @@ TEST test_80store_on(bool flag_hires, bool flag_page2) {
ASSERT(flag_page2 ? (softswitches & SS_PAGE2) : !(softswitches & SS_PAGE2) );
uint32_t switch_save = softswitches;
uint8_t *save_base_textrd = base_textrd;
uint8_t *save_base_textwrt = base_textwrt;
uint8_t *save_base_hgrrd = base_hgrrd;
uint8_t *save_base_hgrwrt = base_hgrwrt;
int save_current_page = video__current_page;
apple_ii_64k[0][WATCHPOINT_ADDR] = 0x00;
c_debugger_go();
@@ -1856,11 +1847,6 @@ TEST test_80store_off(bool flag_ramrd, bool flag_ramwrt, bool flag_page2) {
ASSERT(flag_page2 ? (softswitches & SS_PAGE2) : !(softswitches & SS_PAGE2) );
uint32_t switch_save = softswitches;
uint8_t *save_base_textrd = base_textrd;
uint8_t *save_base_textwrt = base_textwrt;
uint8_t *save_base_hgrrd = base_hgrrd;
uint8_t *save_base_hgrwrt = base_hgrwrt;
int save_current_page = video__current_page;
apple_ii_64k[0][WATCHPOINT_ADDR] = 0x00;
apple_ii_64k[1][WATCHPOINT_ADDR] = 0x00;
@@ -1984,7 +1970,6 @@ TEST test_ramrd_main(bool flag_80store, bool flag_hires) {
ASSERT(flag_hires ? (softswitches & SS_HIRES) : !(softswitches & SS_HIRES) );
uint32_t switch_save = softswitches;
uint8_t *save_base_ramrd = base_ramrd;
uint8_t *save_base_ramwrt = base_ramwrt;
uint8_t *save_base_textrd = base_textrd;
uint8_t *save_base_textwrt = base_textwrt;
@@ -2066,7 +2051,6 @@ TEST test_ramrd_aux(bool flag_80store, bool flag_hires) {
ASSERT(flag_hires ? (softswitches & SS_HIRES) : !(softswitches & SS_HIRES) );
uint32_t switch_save = softswitches;
uint8_t *save_base_ramrd = base_ramrd;
uint8_t *save_base_ramwrt = base_ramwrt;
uint8_t *save_base_textrd = base_textrd;
uint8_t *save_base_textwrt = base_textwrt;
@@ -2184,7 +2168,6 @@ TEST test_ramwrt_main(bool flag_80store, bool flag_hires) {
uint32_t switch_save = softswitches;
uint8_t *save_base_ramrd = base_ramrd;
uint8_t *save_base_ramwrt = base_ramwrt;
uint8_t *save_base_textrd = base_textrd;
uint8_t *save_base_textwrt = base_textwrt;
uint8_t *save_base_hgrrd = base_hgrrd;
@@ -2265,7 +2248,6 @@ TEST test_ramwrt_aux(bool flag_80store, bool flag_hires) {
uint32_t switch_save = softswitches;
uint8_t *save_base_ramrd = base_ramrd;
uint8_t *save_base_ramwrt = base_ramwrt;
uint8_t *save_base_textrd = base_textrd;
uint8_t *save_base_textwrt = base_textwrt;
uint8_t *save_base_hgrrd = base_hgrrd;
@@ -2602,10 +2584,6 @@ TEST test_80col_off() {
ASSERT((softswitches & SS_80COL));
uint32_t switch_save = softswitches;
uint8_t *save_base_d000_rd = base_d000_rd;
uint8_t *save_base_d000_wrt = base_d000_wrt;
uint8_t *save_base_e000_rd = base_e000_rd;
uint8_t *save_base_e000_wrt = base_e000_wrt;
int save_current_page = video__current_page;
apple_ii_64k[0][WATCHPOINT_ADDR] = 0x00;
@@ -2713,10 +2691,6 @@ TEST test_altchar_off() {
ASSERT((softswitches & SS_ALTCHAR));
uint32_t switch_save = softswitches;
uint8_t *save_base_d000_rd = base_d000_rd;
uint8_t *save_base_d000_wrt = base_d000_wrt;
uint8_t *save_base_e000_rd = base_e000_rd;
uint8_t *save_base_e000_wrt = base_e000_wrt;
int save_current_page = video__current_page;
apple_ii_64k[0][WATCHPOINT_ADDR] = 0x00;
@@ -2824,10 +2798,6 @@ TEST test_ioudis_off() {
ASSERT((softswitches & SS_IOUDIS));
uint32_t switch_save = softswitches;
uint8_t *save_base_d000_rd = base_d000_rd;
uint8_t *save_base_d000_wrt = base_d000_wrt;
uint8_t *save_base_e000_rd = base_e000_rd;
uint8_t *save_base_e000_wrt = base_e000_wrt;
int save_current_page = video__current_page;
apple_ii_64k[0][WATCHPOINT_ADDR] = 0x00;
@@ -2943,10 +2913,6 @@ TEST test_dhires_off(bool flag_ioudis/* FIXME TODO : possibly testing a existing
ASSERT((softswitches & SS_DHIRES));
uint32_t switch_save = softswitches;
uint8_t *save_base_d000_rd = base_d000_rd;
uint8_t *save_base_d000_wrt = base_d000_wrt;
uint8_t *save_base_e000_rd = base_e000_rd;
uint8_t *save_base_e000_wrt = base_e000_wrt;
int save_current_page = video__current_page;
apple_ii_64k[0][WATCHPOINT_ADDR] = 0x00;
@@ -3023,7 +2989,6 @@ TEST test_c3rom_internal() {
ASSERT(!(softswitches & SS_C3ROM));
uint32_t switch_save = softswitches;
uint8_t *save_base_c3rom = base_c3rom;
apple_ii_64k[0][WATCHPOINT_ADDR] = 0x00;
c_debugger_go();
@@ -3145,10 +3110,6 @@ TEST test_cxrom_internal() {
ASSERT(!(softswitches & SS_CXROM));
uint32_t switch_save = softswitches;
uint8_t *save_base_cxrom = base_cxrom;
uint8_t *save_base_c3rom = base_c3rom;
uint8_t *save_base_c4rom = base_c4rom;
uint8_t *save_base_c5rom = base_c5rom;
apple_ii_64k[0][WATCHPOINT_ADDR] = 0x00;
c_debugger_go();
@@ -3195,7 +3156,6 @@ TEST test_cxrom_peripheral(bool flag_c3rom) {
ASSERT((softswitches & SS_CXROM));
uint32_t switch_save = softswitches;
uint8_t *save_base_cxrom = base_cxrom;
uint8_t *save_base_c3rom = base_c3rom;
apple_ii_64k[0][WATCHPOINT_ADDR] = 0x00;
@@ -3462,12 +3422,16 @@ GREATEST_MAIN_DEFS();
static char **test_argv = NULL;
static int test_argc = 0;
static void *test_thread(void *dummyptr) {
static int _test_thread(void) {
int argc = test_argc;
char **argv = test_argv;
GREATEST_MAIN_BEGIN();
RUN_SUITE(test_suite_vm);
GREATEST_MAIN_END();
}
static void *test_thread(void *dummyptr) {
_test_thread();
return NULL;
}

View File

@@ -316,12 +316,12 @@ static void _animation_showDiskChosen(int drive) {
static void _animation_showTrackSector(int drive, int track, int sect) {
#define DISK_TRACK_SECTOR_ROWS 3
#define DISK_TRACK_SECTOR_COLS 9
#define DISK_TRACK_SECTOR_COLS 8
static char diskTrackSectorTemplate[DISK_TRACK_SECTOR_ROWS][DISK_TRACK_SECTOR_COLS+1] = {
" ",
"D / TT/SS",
" ",
" ",
"D / TT/S",
" ",
};
char *template = diskTrackSectorTemplate[0];
@@ -343,7 +343,7 @@ static void _animation_showTrackSector(int drive, int track, int sect) {
assert(false && "should not happen");
break;
}
snprintf(&diskTrackSectorTemplate[1][0], DISK_TRACK_SECTOR_COLS+1, "%d %c %02X/%02X", drive+1, c, track, sect);
snprintf(&diskTrackSectorTemplate[1][0], DISK_TRACK_SECTOR_COLS+1, "%d %c %02X/%01X", drive+1, c, track, sect);
_animation_showMessage(template, DISK_TRACK_SECTOR_COLS, DISK_TRACK_SECTOR_ROWS);
}

View File

@@ -29,17 +29,19 @@
#define MODEL_DEPTH -1/32.f
#define KBD_TEMPLATE_COLS 10
#define KBD_TEMPLATE_ROWS 6
#define KBD_TEMPLATE_ROWS 8
#define DEFAULT_CTRL_COL 2
#define _ROWOFF 2 // main keyboard row offset
#define CTRLROW 2 // first non-empty default row
#define MAINROW 4 // main keyboard row offset
#define SWITCHCOL 0
#define KBD_FB_WIDTH (KBD_TEMPLATE_COLS * FONT80_WIDTH_PIXELS)
#define KBD_FB_HEIGHT (KBD_TEMPLATE_ROWS * FONT_HEIGHT_PIXELS)
#define KBD_OBJ_W 2.0
#define KBD_OBJ_H 1.5
#define KBD_OBJ_H 2.0
HUD_CLASS(GLModelHUDKeyboard,
// ...
@@ -55,6 +57,8 @@ static float minAlpha = 0.f;
static float maxAlpha = 1.f;
static uint8_t kbdTemplateUCase[KBD_TEMPLATE_ROWS][KBD_TEMPLATE_COLS+1] = {
" ",
" ",
"@ @ @ @ @ ",
"1234567890",
"QWERTYUIOP",
@@ -64,6 +68,8 @@ static uint8_t kbdTemplateUCase[KBD_TEMPLATE_ROWS][KBD_TEMPLATE_COLS+1] = {
};
static uint8_t kbdTemplateLCase[KBD_TEMPLATE_ROWS][KBD_TEMPLATE_COLS+1] = {
" ",
" ",
"@ @ @ @ @ ",
"1234567890",
"qwertyuiop",
@@ -73,6 +79,8 @@ static uint8_t kbdTemplateLCase[KBD_TEMPLATE_ROWS][KBD_TEMPLATE_COLS+1] = {
};
static uint8_t kbdTemplateAlt[KBD_TEMPLATE_ROWS][KBD_TEMPLATE_COLS+1] = {
" ",
" ",
"@ @ @ @ @ ",
"1234567890",
"@#%&*/-+()",
@@ -82,6 +90,8 @@ static uint8_t kbdTemplateAlt[KBD_TEMPLATE_ROWS][KBD_TEMPLATE_COLS+1] = {
};
static uint8_t kbdTemplateUserAlt[KBD_TEMPLATE_ROWS][KBD_TEMPLATE_COLS+1] = {
" ",
" ",
"@ @ @ @ @ ",
" ",
" @ ",
@@ -214,16 +224,6 @@ static inline void _switch_keyboard(GLModel *parent, uint8_t *template) {
}
}
static inline void _show_useralt_kbd(void) {
GLModelHUDKeyboard *hudKeyboard = (GLModelHUDKeyboard *)kbd.model->custom;
uint8_t c = hudKeyboard->tpl[_ROWOFF*(KBD_TEMPLATE_COLS+1)];
if (c == ICONTEXT_NONACTIONABLE) {
_switch_keyboard(kbd.model, kbdTemplateUCase[0]);
} else {
_switch_keyboard(kbd.model, kbdTemplateUserAlt[0]);
}
}
#warning FIXME TODO ... this can become a common helper function ...
static inline float _get_keyboard_visibility(void) {
struct timespec now = { 0 };
@@ -314,9 +314,9 @@ static inline int64_t _tap_key_at_point(float x, float y) {
case ICONTEXT_SHOWALT1:
key = 0;
if (allowLowercase && !isCalibrating) {
kbdTemplateAlt[0][0] = ICONTEXT_LOWERCASE;
kbdTemplateAlt[CTRLROW][SWITCHCOL] = ICONTEXT_LOWERCASE;
} else {
kbdTemplateAlt[0][0] = ICONTEXT_UPPERCASE;
kbdTemplateAlt[CTRLROW][SWITCHCOL] = ICONTEXT_UPPERCASE;
}
_switch_keyboard(kbd.model, kbdTemplateAlt[0]);
break;
@@ -375,7 +375,8 @@ static inline int64_t _tap_key_at_point(float x, float y) {
case ICONTEXT_MENU_SPROUT:
key = 0;
_show_useralt_kbd();
kbd.ctrlPressed = false;
_switch_keyboard(kbd.model, kbdTemplateUserAlt[0]);
break;
case ICONTEXT_GOTO:
@@ -737,26 +738,26 @@ static void gltouchkbd_loadAltKbd(const char *kbdPath) {
break;
}
// next is reserved0 array
if (parsedData.jsonTokens[idx].type != JSMN_ARRAY) {
ERRLOG("Expecting a reserved array at JSON token position 3");
break;
}
++idx;
idx += parsedData.jsonTokens[idx-1].size;
// next is reserved1 array
if (parsedData.jsonTokens[idx].type != JSMN_ARRAY) {
ERRLOG("Expecting a reserved array at JSON token position 4");
break;
}
++idx;
idx += parsedData.jsonTokens[idx-1].size;
// next are the character rows
int row = 0;
while (idx < tokCount) {
if ( !((parsedData.jsonTokens[idx].type == JSMN_ARRAY) && (parsedData.jsonTokens[idx].size == KBD_TEMPLATE_COLS) && (parsedData.jsonTokens[idx].parent == 0)) ) {
if (row < 2) {
if ( !((parsedData.jsonTokens[idx].type == JSMN_ARRAY) && (parsedData.jsonTokens[idx].parent == 0)) ) {
ERRLOG("Expecting a reserved array at keyboard row %d", row+1);
break;
}
if (parsedData.jsonTokens[idx].size != KBD_TEMPLATE_COLS) {
// backwards compatibility when we only had the lower 6 rows for keyboard data ...
LOG("You can now edit %d columns of row %d in your custom keyboard", KBD_TEMPLATE_COLS, row+1);
for (int col=0; col<KBD_TEMPLATE_COLS; col++) {
kbdTemplateUserAlt[row][col] = ICONTEXT_NONACTIONABLE;
}
++row;
++idx;
idx += parsedData.jsonTokens[idx-1].size;
continue;
}
} else if ( !((parsedData.jsonTokens[idx].type == JSMN_ARRAY) && (parsedData.jsonTokens[idx].size == KBD_TEMPLATE_COLS) && (parsedData.jsonTokens[idx].parent == 0)) ) {
ERRLOG("Expecting an array of ten items at keyboard row %d", row+1);
break;
}
@@ -815,6 +816,10 @@ static void gltouchkbd_loadAltKbd(const char *kbdPath) {
}
++row;
if (row >= KBD_TEMPLATE_ROWS) {
break;
}
}
if (row != KBD_TEMPLATE_ROWS) {
@@ -847,7 +852,7 @@ static void _animation_hideTouchKeyboard(void) {
static void _initialize_keyboard_templates(void) {
for (unsigned int i=0; i<(_ROWOFF-1); i++) {
for (unsigned int i=0; i<(MAINROW-1); i++) {
for (unsigned int j=0; j<KBD_TEMPLATE_COLS; j++) {
kbdTemplateUCase[i][j] = ICONTEXT_NONACTIONABLE;
kbdTemplateLCase[i][j] = ICONTEXT_NONACTIONABLE;
@@ -862,86 +867,86 @@ static void _initialize_keyboard_templates(void) {
}
}
kbdTemplateLCase[0][0] = ICONTEXT_UPPERCASE;
kbdTemplateUCase[0][0] = ICONTEXT_SHOWALT1;
kbdTemplateAlt [0][0] = ICONTEXT_UPPERCASE;
kbdTemplateUserAlt[0][0] = ICONTEXT_UPPERCASE;
kbdTemplateLCase[CTRLROW+0][0] = ICONTEXT_UPPERCASE;
kbdTemplateUCase[CTRLROW+0][0] = ICONTEXT_SHOWALT1;
kbdTemplateAlt [CTRLROW+0][0] = ICONTEXT_UPPERCASE;
kbdTemplateUserAlt[CTRLROW+0][0] = ICONTEXT_UPPERCASE;
kbdTemplateUCase[0][2] = ICONTEXT_CTRL;
kbdTemplateLCase[0][2] = ICONTEXT_CTRL;
kbdTemplateAlt [0][2] = ICONTEXT_CTRL;
kbdTemplateUserAlt[0][2] = ICONTEXT_CTRL;
kbdTemplateUCase[CTRLROW+0][2] = ICONTEXT_CTRL;
kbdTemplateLCase[CTRLROW+0][2] = ICONTEXT_CTRL;
kbdTemplateAlt [CTRLROW+0][2] = ICONTEXT_CTRL;
kbdTemplateUserAlt[CTRLROW+0][2] = ICONTEXT_CTRL;
kbdTemplateUCase[0][4] = ICONTEXT_ESC;
kbdTemplateLCase[0][4] = ICONTEXT_ESC;
kbdTemplateAlt [0][4] = ICONTEXT_ESC;
kbdTemplateUserAlt[0][4] = ICONTEXT_ESC;
kbdTemplateUCase[CTRLROW+0][4] = ICONTEXT_ESC;
kbdTemplateLCase[CTRLROW+0][4] = ICONTEXT_ESC;
kbdTemplateAlt [CTRLROW+0][4] = ICONTEXT_ESC;
kbdTemplateUserAlt[CTRLROW+0][4] = ICONTEXT_ESC;
kbdTemplateUCase[0][6] = MOUSETEXT_OPENAPPLE;
kbdTemplateLCase[0][6] = MOUSETEXT_OPENAPPLE;
kbdTemplateAlt [0][6] = MOUSETEXT_OPENAPPLE;
kbdTemplateUserAlt[0][6] = MOUSETEXT_OPENAPPLE;
kbdTemplateUCase[CTRLROW+0][6] = MOUSETEXT_OPENAPPLE;
kbdTemplateLCase[CTRLROW+0][6] = MOUSETEXT_OPENAPPLE;
kbdTemplateAlt [CTRLROW+0][6] = MOUSETEXT_OPENAPPLE;
kbdTemplateUserAlt[CTRLROW+0][6] = MOUSETEXT_OPENAPPLE;
kbdTemplateUCase[0][8] = MOUSETEXT_CLOSEDAPPLE;
kbdTemplateLCase[0][8] = MOUSETEXT_CLOSEDAPPLE;
kbdTemplateAlt [0][8] = MOUSETEXT_CLOSEDAPPLE;
kbdTemplateUserAlt[0][8] = MOUSETEXT_CLOSEDAPPLE;
kbdTemplateUCase[CTRLROW+0][8] = MOUSETEXT_CLOSEDAPPLE;
kbdTemplateLCase[CTRLROW+0][8] = MOUSETEXT_CLOSEDAPPLE;
kbdTemplateAlt [CTRLROW+0][8] = MOUSETEXT_CLOSEDAPPLE;
kbdTemplateUserAlt[CTRLROW+0][8] = MOUSETEXT_CLOSEDAPPLE;
kbdTemplateUserAlt[2][5] = MOUSETEXT_UP;
kbdTemplateUserAlt[3][4] = MOUSETEXT_LEFT;
kbdTemplateUserAlt[3][6] = MOUSETEXT_RIGHT;
kbdTemplateUserAlt[4][5] = MOUSETEXT_DOWN;
kbdTemplateUserAlt[CTRLROW+2][5] = MOUSETEXT_UP;
kbdTemplateUserAlt[CTRLROW+3][4] = MOUSETEXT_LEFT;
kbdTemplateUserAlt[CTRLROW+3][6] = MOUSETEXT_RIGHT;
kbdTemplateUserAlt[CTRLROW+4][5] = MOUSETEXT_DOWN;
kbdTemplateUCase[3][5] = ICONTEXT_MENU_SPROUT;
kbdTemplateLCase[3][5] = ICONTEXT_MENU_SPROUT;
kbdTemplateAlt [3][5] = ICONTEXT_MENU_SPROUT;
kbdTemplateUserAlt[3][5] = ICONTEXT_MENU_SPROUT;
kbdTemplateUCase[CTRLROW+3][5] = ICONTEXT_MENU_SPROUT;
kbdTemplateLCase[CTRLROW+3][5] = ICONTEXT_MENU_SPROUT;
kbdTemplateAlt [CTRLROW+3][5] = ICONTEXT_MENU_SPROUT;
kbdTemplateUserAlt[CTRLROW+3][5] = ICONTEXT_UPPERCASE;
kbdTemplateUCase[_ROWOFF+2][0] = ICONTEXT_NONACTIONABLE;
kbdTemplateLCase[_ROWOFF+2][0] = ICONTEXT_NONACTIONABLE;
kbdTemplateUCase[MAINROW+2][0] = ICONTEXT_NONACTIONABLE;
kbdTemplateLCase[MAINROW+2][0] = ICONTEXT_NONACTIONABLE;
kbdTemplateUCase[_ROWOFF+2][8] = ICONTEXT_NONACTIONABLE;
kbdTemplateLCase[_ROWOFF+2][8] = ICONTEXT_NONACTIONABLE;
kbdTemplateAlt [_ROWOFF+2][8] = ICONTEXT_NONACTIONABLE;
kbdTemplateUCase[MAINROW+2][8] = ICONTEXT_NONACTIONABLE;
kbdTemplateLCase[MAINROW+2][8] = ICONTEXT_NONACTIONABLE;
kbdTemplateAlt [MAINROW+2][8] = ICONTEXT_NONACTIONABLE;
kbdTemplateUCase[_ROWOFF+2][9] = ICONTEXT_BACKSPACE;
kbdTemplateLCase[_ROWOFF+2][9] = ICONTEXT_BACKSPACE;
kbdTemplateAlt [_ROWOFF+2][9] = ICONTEXT_BACKSPACE;
kbdTemplateUCase[MAINROW+2][9] = ICONTEXT_BACKSPACE;
kbdTemplateLCase[MAINROW+2][9] = ICONTEXT_BACKSPACE;
kbdTemplateAlt [MAINROW+2][9] = ICONTEXT_BACKSPACE;
// last row specials
kbdTemplateLCase[_ROWOFF+3][0] = ICONTEXT_NONACTIONABLE;
kbdTemplateUCase[_ROWOFF+3][0] = ICONTEXT_NONACTIONABLE;
kbdTemplateLCase[MAINROW+3][0] = ICONTEXT_NONACTIONABLE;
kbdTemplateUCase[MAINROW+3][0] = ICONTEXT_NONACTIONABLE;
kbdTemplateUCase[_ROWOFF+3][1] = ICONTEXT_NONACTIONABLE;
kbdTemplateLCase[_ROWOFF+3][1] = ICONTEXT_NONACTIONABLE;
kbdTemplateUCase[MAINROW+3][1] = ICONTEXT_NONACTIONABLE;
kbdTemplateLCase[MAINROW+3][1] = ICONTEXT_NONACTIONABLE;
kbdTemplateUCase[_ROWOFF+3][2] = ICONTEXT_NONACTIONABLE;
kbdTemplateLCase[_ROWOFF+3][2] = ICONTEXT_NONACTIONABLE;
kbdTemplateUCase[MAINROW+3][2] = ICONTEXT_NONACTIONABLE;
kbdTemplateLCase[MAINROW+3][2] = ICONTEXT_NONACTIONABLE;
kbdTemplateUCase[_ROWOFF+3][0] = ICONTEXT_GOTO;
kbdTemplateLCase[_ROWOFF+3][0] = ICONTEXT_GOTO;
kbdTemplateUCase[MAINROW+3][0] = ICONTEXT_GOTO;
kbdTemplateLCase[MAINROW+3][0] = ICONTEXT_GOTO;
kbdTemplateUCase[_ROWOFF+3][3] = ICONTEXT_LEFTSPACE;
kbdTemplateLCase[_ROWOFF+3][3] = ICONTEXT_LEFTSPACE;
kbdTemplateAlt [_ROWOFF+3][3] = ICONTEXT_LEFTSPACE;
kbdTemplateUCase[_ROWOFF+3][4] = ICONTEXT_MIDSPACE;
kbdTemplateLCase[_ROWOFF+3][4] = ICONTEXT_MIDSPACE;
kbdTemplateAlt [_ROWOFF+3][4] = ICONTEXT_MIDSPACE;
kbdTemplateUCase[_ROWOFF+3][5] = ICONTEXT_RIGHTSPACE;
kbdTemplateLCase[_ROWOFF+3][5] = ICONTEXT_RIGHTSPACE;
kbdTemplateAlt [_ROWOFF+3][5] = ICONTEXT_RIGHTSPACE;
kbdTemplateUCase[MAINROW+3][3] = ICONTEXT_LEFTSPACE;
kbdTemplateLCase[MAINROW+3][3] = ICONTEXT_LEFTSPACE;
kbdTemplateAlt [MAINROW+3][3] = ICONTEXT_LEFTSPACE;
kbdTemplateUCase[MAINROW+3][4] = ICONTEXT_MIDSPACE;
kbdTemplateLCase[MAINROW+3][4] = ICONTEXT_MIDSPACE;
kbdTemplateAlt [MAINROW+3][4] = ICONTEXT_MIDSPACE;
kbdTemplateUCase[MAINROW+3][5] = ICONTEXT_RIGHTSPACE;
kbdTemplateLCase[MAINROW+3][5] = ICONTEXT_RIGHTSPACE;
kbdTemplateAlt [MAINROW+3][5] = ICONTEXT_RIGHTSPACE;
kbdTemplateUCase[_ROWOFF+3][7] = ICONTEXT_NONACTIONABLE;
kbdTemplateLCase[_ROWOFF+3][7] = ICONTEXT_NONACTIONABLE;
kbdTemplateUCase[MAINROW+3][7] = ICONTEXT_NONACTIONABLE;
kbdTemplateLCase[MAINROW+3][7] = ICONTEXT_NONACTIONABLE;
kbdTemplateUCase[_ROWOFF+3][8] = ICONTEXT_RETURN_L;
kbdTemplateLCase[_ROWOFF+3][8] = ICONTEXT_RETURN_L;
kbdTemplateAlt [_ROWOFF+3][8] = ICONTEXT_RETURN_L;
kbdTemplateUCase[MAINROW+3][8] = ICONTEXT_RETURN_L;
kbdTemplateLCase[MAINROW+3][8] = ICONTEXT_RETURN_L;
kbdTemplateAlt [MAINROW+3][8] = ICONTEXT_RETURN_L;
kbdTemplateUCase[_ROWOFF+3][9] = ICONTEXT_RETURN_R;
kbdTemplateLCase[_ROWOFF+3][9] = ICONTEXT_RETURN_R;
kbdTemplateAlt [_ROWOFF+3][9] = ICONTEXT_RETURN_R;
kbdTemplateUCase[MAINROW+3][9] = ICONTEXT_RETURN_R;
kbdTemplateLCase[MAINROW+3][9] = ICONTEXT_RETURN_R;
kbdTemplateAlt [MAINROW+3][9] = ICONTEXT_RETURN_R;
}
__attribute__((constructor(CTOR_PRIORITY_LATE)))
@@ -967,7 +972,7 @@ static void _init_gltouchkbd(void) {
kbd.selectedRow = -1;
kbd.ctrlCol = DEFAULT_CTRL_COL;
kbd.ctrlRow = 0;
kbd.ctrlRow = CTRLROW;
glnode_registerNode(RENDER_LOW, (GLNode){
.setup = &gltouchkbd_setup,

View File

@@ -1713,7 +1713,8 @@ ENTRY(op_SBC_dec)
incb SYM(cpu65_opcycles) // +1 cycle
GetFromEA_B
DebugBCDCheck
btc $C_Flag_Bit, AF_Reg_X
bt $C_Flag_Bit, AF_Reg_X
cmc
xchgb A_Reg, %al
#if !defined(__LP64__)
sbbb A_Reg, %al
@@ -1722,7 +1723,6 @@ ENTRY(op_SBC_dec)
cmc
FlagNVZC
#else
cmc
sbbb A_Reg, %al
// DAS algorithm : http://www.ray.masmcode.com/BCDdas.html
// CF_old = CF