diff --git a/Android/app/src/main/java/org/deadc0de/apple2ix/Apple2AbstractMenu.java b/Android/app/src/main/java/org/deadc0de/apple2ix/Apple2AbstractMenu.java index 59f8e7f2..c1c265d8 100644 --- a/Android/app/src/main/java/org/deadc0de/apple2ix/Apple2AbstractMenu.java +++ b/Android/app/src/main/java/org/deadc0de/apple2ix/Apple2AbstractMenu.java @@ -120,6 +120,7 @@ public abstract class Apple2AbstractMenu implements Apple2MenuView { public interface IPreferenceLoadSave { public int intValue(); + public void saveInt(int value); } @@ -166,6 +167,10 @@ public abstract class Apple2AbstractMenu implements Apple2MenuView { } protected static void _alertDialogHandleSelection(final Apple2Activity activity, final int titleId, final String[] choices, final IPreferenceLoadSave iLoadSave) { + _alertDialogHandleSelection(activity, activity.getResources().getString(titleId), choices, iLoadSave); + } + + protected static void _alertDialogHandleSelection(final Apple2Activity activity, final String titleId, final String[] choices, final IPreferenceLoadSave iLoadSave) { AlertDialog.Builder builder = new AlertDialog.Builder(activity).setIcon(R.drawable.ic_launcher).setCancelable(true).setTitle(titleId); builder.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { @Override diff --git a/Android/app/src/main/java/org/deadc0de/apple2ix/Apple2DisksMenu.java b/Android/app/src/main/java/org/deadc0de/apple2ix/Apple2DisksMenu.java index 7c1fef4e..b2991220 100644 --- a/Android/app/src/main/java/org/deadc0de/apple2ix/Apple2DisksMenu.java +++ b/Android/app/src/main/java/org/deadc0de/apple2ix/Apple2DisksMenu.java @@ -53,7 +53,6 @@ public class Apple2DisksMenu implements Apple2MenuView { private final ArrayList mPathStack = new ArrayList<>(); private static File sExternalFilesDir = null; - private static boolean sExternalStorageAvailable = false; private static boolean sInitializedPath = false; public Apple2DisksMenu(Apple2Activity activity) { @@ -70,22 +69,26 @@ public class Apple2DisksMenu implements Apple2MenuView { } }); - if (!sExternalStorageAvailable) { + getExternalStorageDirectory(); + } + + public static File getExternalStorageDirectory() { + if (sExternalFilesDir == null) { String storageState = Environment.getExternalStorageState(); File externalDir = new File(Environment.getExternalStorageDirectory().getPath() + File.separator + "apple2ix"); // /sdcard/apple2ix sExternalFilesDir = null; - sExternalStorageAvailable = storageState.equals(Environment.MEDIA_MOUNTED); - if (sExternalStorageAvailable) { + boolean externalStorageAvailable = storageState.equals(Environment.MEDIA_MOUNTED); + if (externalStorageAvailable) { sExternalFilesDir = externalDir; boolean made = sExternalFilesDir.mkdirs(); if (!made) { Log.d(TAG, "WARNING: could not make directory : " + sExternalFilesDir); } } else { - sExternalStorageAvailable = storageState.equals(Environment.MEDIA_MOUNTED_READ_ONLY) && externalDir.exists(); sExternalFilesDir = externalDir; } } + return sExternalFilesDir; } // HACK NOTE 2015/02/22 : Apparently native code cannot easily access stuff in the APK ... so copy various resources @@ -114,14 +117,25 @@ public class Apple2DisksMenu implements Apple2MenuView { Log.d(TAG, "First time copying stuff-n-things out of APK for ease-of-NDK access..."); + getExternalStorageDirectory(); + try { String[] shaders = activity.getAssets().list("shaders"); for (String shader : shaders) { - Apple2DisksMenu.copyFile(activity, "shaders", shader); + Apple2DisksMenu.copyFile(activity, "shaders", shader, sDataDir + File.separator + "shaders"); } + + String[] keyboards = activity.getAssets().list("keyboards"); + for (String kbd : keyboards) { + Apple2DisksMenu.copyFile(activity, "keyboards", kbd, sDataDir + File.separator + "keyboards"); + if (sExternalFilesDir != null) { + Apple2DisksMenu.copyFile(activity, "keyboards", kbd, sExternalFilesDir.getPath()); + } + } + String[] disks = activity.getAssets().list("disks"); for (String disk : disks) { - Apple2DisksMenu.copyFile(activity, "disks", disk); + Apple2DisksMenu.copyFile(activity, "disks", disk, sDataDir + File.separator + "disks"); } } catch (IOException e) { Log.e(TAG, "problem copying resources : " + e); @@ -225,9 +239,8 @@ public class Apple2DisksMenu implements Apple2MenuView { return pathBuffer.toString(); } - private static void copyFile(Apple2Activity activity, String subdir, String assetName) + private static void copyFile(Apple2Activity activity, String subdir, String assetName, String outputPath) throws IOException { - String outputPath = sDataDir + File.separator + subdir; Log.d(TAG, "Copying " + subdir + File.separator + assetName + " to " + outputPath + File.separator + assetName + " ..."); boolean made = new File(outputPath).mkdirs(); if (!made) { @@ -325,13 +338,14 @@ public class Apple2DisksMenu implements Apple2MenuView { Arrays.sort(files); - final boolean includeExternalStoragePath = (sExternalStorageAvailable && isRootPath); + getExternalStorageDirectory(); + final boolean includeExternalStoragePath = (sExternalFilesDir != null && isRootPath); final int offset = includeExternalStoragePath ? 1 : 0; final String[] fileNames = new String[files.length + offset]; final boolean[] isDirectory = new boolean[files.length + offset]; if (includeExternalStoragePath) { - fileNames[0] = sExternalFilesDir.toString(); + fileNames[0] = sExternalFilesDir.getPath(); isDirectory[0] = true; } diff --git a/Android/app/src/main/java/org/deadc0de/apple2ix/Apple2KeyboardSettingsMenu.java b/Android/app/src/main/java/org/deadc0de/apple2ix/Apple2KeyboardSettingsMenu.java index e34f0beb..e32d43ab 100644 --- a/Android/app/src/main/java/org/deadc0de/apple2ix/Apple2KeyboardSettingsMenu.java +++ b/Android/app/src/main/java/org/deadc0de/apple2ix/Apple2KeyboardSettingsMenu.java @@ -16,6 +16,10 @@ import android.widget.CheckBox; import android.widget.CompoundButton; import android.widget.TextView; +import java.io.File; +import java.io.FilenameFilter; +import java.util.Arrays; + public class Apple2KeyboardSettingsMenu extends Apple2AbstractMenu { private final static String TAG = "Apple2KeyboardSettingsMenu"; @@ -23,11 +27,11 @@ public class Apple2KeyboardSettingsMenu extends Apple2AbstractMenu { // These settings must match native side public final static int MOUSETEXT_BEGIN = 0x80; public final static int MOUSETEXT_CLOSEDAPPLE = MOUSETEXT_BEGIN/*+0x00*/; - public final static int MOUSETEXT_OPENAPPLE = MOUSETEXT_BEGIN+0x01; - public final static int MOUSETEXT_LEFT = MOUSETEXT_BEGIN+0x08; - public final static int MOUSETEXT_UP = MOUSETEXT_BEGIN+0x0b; - public final static int MOUSETEXT_DOWN = MOUSETEXT_BEGIN+0x0a; - public final static int MOUSETEXT_RIGHT = MOUSETEXT_BEGIN+0x15; + public final static int MOUSETEXT_OPENAPPLE = MOUSETEXT_BEGIN + 0x01; + public final static int MOUSETEXT_LEFT = MOUSETEXT_BEGIN + 0x08; + public final static int MOUSETEXT_UP = MOUSETEXT_BEGIN + 0x0b; + public final static int MOUSETEXT_DOWN = MOUSETEXT_BEGIN + 0x0a; + public final static int MOUSETEXT_RIGHT = MOUSETEXT_BEGIN + 0x15; public final static int ICONTEXT_BEGIN = 0xA0; public final static int ICONTEXT_VISUAL_SPACE = ICONTEXT_BEGIN + 0x11; @@ -194,11 +198,45 @@ public class Apple2KeyboardSettingsMenu extends Apple2AbstractMenu { @Override public void handleSelection(final Apple2Activity activity, final Apple2AbstractMenu settingsMenu, boolean isChecked) { - String[] titles = new String[Apple2Preferences.KeyboardAltPreset.size + 1]; - titles[0] = activity.getResources().getString(R.string.keyboard_preset_custom); - System.arraycopy(Apple2Preferences.KeyboardAltPreset.titles(activity), 0, titles, 1, Apple2Preferences.KeyboardAltPreset.size); - _alertDialogHandleSelection(activity, R.string.keyboard_choose_alt_title, titles, new IPreferenceLoadSave() { + File keyboardDir = Apple2DisksMenu.getExternalStorageDirectory(); + if (keyboardDir == null) { + keyboardDir = new File(Apple2DisksMenu.getDataDir(activity) + File.separator + "keyboards"); + } + + final File[] files = keyboardDir.listFiles(new FilenameFilter() { + public boolean accept(File dir, String name) { + File file = new File(dir, name); + if (file.isDirectory()) { + return false; + } + + // check file extensions ... sigh ... no String.endsWithIgnoreCase() ? + + final String extension = ".kbd.json"; + final int nameLen = name.length(); + final int extLen = extension.length(); + if (nameLen <= extLen) { + return false; + } + + String suffix = name.substring(nameLen - extLen, nameLen); + return (suffix.equalsIgnoreCase(extension)); + } + }); + + Arrays.sort(files); + + String[] titles = new String[files.length]; + int idx = 0; + for (File file : files) { + titles[idx] = file.getName(); + ++idx; + } + + final String keyboardDirName = keyboardDir.getPath(); + + _alertDialogHandleSelection(activity, keyboardDirName, titles, new IPreferenceLoadSave() { @Override public int intValue() { return Apple2Preferences.KEYBOARD_ALT.intValue(activity); @@ -207,12 +245,8 @@ public class Apple2KeyboardSettingsMenu extends Apple2AbstractMenu { @Override public void saveInt(int value) { Apple2Preferences.KEYBOARD_ALT.saveInt(activity, value); - if (value == 0) { - Apple2KeyboardSettingsMenu keyboardSettingsMenu = (Apple2KeyboardSettingsMenu) settingsMenu; - ////TODO FIXME ... keyboardSettingsMenu.chooseAltKeyboard(activity); - } else { - Apple2Preferences.KeyboardAltPreset.values()[value - 1].apply(activity); - } + String path = files[value].getPath(); + Apple2Preferences.KEYBOARD_ALT_PATH.saveString(activity, path); } }); } diff --git a/Android/app/src/main/java/org/deadc0de/apple2ix/Apple2Preferences.java b/Android/app/src/main/java/org/deadc0de/apple2ix/Apple2Preferences.java index 62f2f9d2..6380d262 100644 --- a/Android/app/src/main/java/org/deadc0de/apple2ix/Apple2Preferences.java +++ b/Android/app/src/main/java/org/deadc0de/apple2ix/Apple2Preferences.java @@ -520,7 +520,18 @@ public enum Apple2Preferences { @Override public int intValue(Apple2Activity activity) { - return activity.getPreferences(Context.MODE_PRIVATE).getInt(toString(), 1); + return activity.getPreferences(Context.MODE_PRIVATE).getInt(toString(), 0); + } + }, + KEYBOARD_ALT_PATH { + @Override + public void load(Apple2Activity activity) { + nativeLoadTouchKeyboardJSON(stringValue(activity)); + } + + @Override + public String stringValue(Apple2Activity activity) { + return activity.getPreferences(Context.MODE_PRIVATE).getString(toString(), ""); } }, KEYBOARD_VISIBILITY_ACTIVE { @@ -774,46 +785,6 @@ public enum Apple2Preferences { } } - public enum KeyboardAltPreset { - DEFAULT { - @Override - public String getTitle(Apple2Activity activity) { - return activity.getResources().getString(R.string.keyboard_preset_default); - } - - @Override - public void apply(Apple2Activity activity) { - // TODO FIXME ... - } - }, - U4 { - @Override - public String getTitle(Apple2Activity activity) { - return activity.getResources().getString(R.string.keyboard_preset_u4); - } - - @Override - public void apply(Apple2Activity activity) { - // TODO FIXME ... - } - }; - - public abstract String getTitle(Apple2Activity activity); - - public abstract void apply(Apple2Activity activity); - - public static final int size = KeyboardAltPreset.values().length; - - public static String[] titles(Apple2Activity activity) { - String[] titles = new String[size]; - int i = 0; - for (KeyboardAltPreset preset : values()) { - titles[i++] = preset.getTitle(activity); - } - return titles; - } - } - public final static int DECENT_AMOUNT_OF_CHOICES = 20; public final static int AUDIO_LATENCY_NUM_CHOICES = DECENT_AMOUNT_OF_CHOICES; public final static int ALPHA_SLIDER_NUM_CHOICES = DECENT_AMOUNT_OF_CHOICES; @@ -1055,4 +1026,6 @@ public enum Apple2Preferences { private static native void nativeSetTouchDeviceKeyRepeatThreshold(float threshold); + private static native void nativeLoadTouchKeyboardJSON(String path); + } diff --git a/Android/app/src/main/res/values/strings.xml b/Android/app/src/main/res/values/strings.xml index db372374..c192484e 100644 --- a/Android/app/src/main/res/values/strings.xml +++ b/Android/app/src/main/res/values/strings.xml @@ -73,14 +73,11 @@ Keyboard Choose alt keyboard… Choose alternative customized layout - Alt keyboard layout Configure keyboard… Transparency, lowercase, custom keys Enable lowercase Enable lowercase keys - Load custom… Default - U4 optimized Visibility when active Keyboard visibility when active Visibility when inactive diff --git a/Android/assets/keyboards/00default.kbd.json b/Android/assets/keyboards/00default.kbd.json new file mode 100644 index 00000000..73828dbc --- /dev/null +++ b/Android/assets/keyboards/00default.kbd.json @@ -0,0 +1,26 @@ +[ + "Default Alternate Touch Keyboard", + + { + "_comment" : "hex code for special glyphs", + "_AA" : "b5", + "_CTRL": "b3", + "_XX" : "9b", + "_ESC" : "bc", + "_OA" : "81", + "_CA" : "80", + "_UP" : "8b", + "_LT" : "88", + "_RT" : "95", + "_DN" : "8a" + }, + + ["reserved for future use"], + ["reserved for future use"], + ["_AA", "", "_CTRL", "", "_ESC", "", "_OA", "", "_CA", ""], + [ "", "", "", "", "", "", "", "", "", ""], + [ "", "", "", "", "", "_UP", "", "", "", ""], + [ "", "", "", "", "_LT", "_XX", "_RT", "", "", ""], + [ "", "", "", "", "", "_DN", "", "", "", ""], + [ "", "", "", "", "", "", "", "", "", ""] +] diff --git a/Android/assets/keyboards/u4.kbd.json b/Android/assets/keyboards/u4.kbd.json new file mode 100644 index 00000000..c6e98cbb --- /dev/null +++ b/Android/assets/keyboards/u4.kbd.json @@ -0,0 +1,23 @@ +[ + "Alt keyboard optimized for Ultima(tm) 4", + + { + "_comment" : "hex code for special glyphs", + "_AA" : "b5", + "_XX" : "9b", + "_ESC" : "bc", + "_UP" : "8b", + "_LT" : "88", + "_RT" : "95", + "_DN" : "8a" + }, + + ["reserved for future use"], + ["reserved for future use"], + ["_AA", "", "", "", "", "", "", "", "", "_ESC"], + [ "", "", "", "", "", "", "1", "2", "3", "4"], + [ "", "", "", "", "", "", "5", "6", "7", "8"], + [ "S", "", "", "", "", "", "", "T", "_UP", "G"], + [ "A", "", "", "", "", "", "", "_LT", "_XX", "_RT"], + [ "Z", "", "", "", "", "", "", "C", "_DN", "O"] +] diff --git a/Android/jni/jniprefs.c b/Android/jni/jniprefs.c index f625c6b0..21b4955c 100644 --- a/Android/jni/jniprefs.c +++ b/Android/jni/jniprefs.c @@ -286,3 +286,10 @@ void Java_org_deadc0de_apple2ix_Apple2Preferences_nativeSetCPUSpeed(JNIEnv *env, } } +void Java_org_deadc0de_apple2ix_Apple2Preferences_nativeLoadTouchKeyboardJSON(JNIEnv *env, jclass cls, jstring j_jsonPath) { + const char *jsonPath = (*env)->GetStringUTFChars(env, j_jsonPath, 0); + LOG("jsonPath: %s", jsonPath); + keydriver_loadAltKbd(jsonPath); + (*env)->ReleaseStringUTFChars(env, j_jsonPath, jsonPath); +} + diff --git a/Android/jni/sources.mk b/Android/jni/sources.mk index f3273931..06bead5b 100644 --- a/Android/jni/sources.mk +++ b/Android/jni/sources.mk @@ -35,7 +35,8 @@ APPLE2_META_SRC = \ APPLE2_MAIN_SRC = \ $(APPLE2_SRC_PATH)/font.c $(APPLE2_SRC_PATH)/rom.c $(APPLE2_SRC_PATH)/misc.c $(APPLE2_SRC_PATH)/display.c $(APPLE2_SRC_PATH)/vm.c \ $(APPLE2_SRC_PATH)/timing.c $(APPLE2_SRC_PATH)/zlib-helpers.c $(APPLE2_SRC_PATH)/joystick.c $(APPLE2_SRC_PATH)/keys.c \ - $(APPLE2_SRC_PATH)/interface.c $(APPLE2_SRC_PATH)/disk.c $(APPLE2_SRC_PATH)/cpu-supp.c jnihooks.c + $(APPLE2_SRC_PATH)/interface.c $(APPLE2_SRC_PATH)/disk.c $(APPLE2_SRC_PATH)/cpu-supp.c jnihooks.c \ + $(APPLE2_SRC_PATH)/json_parse.c $(APPLE2_SRC_PATH)/../externals/jsmn/jsmn.c APPLE2_OPTIM_CFLAGS := -g -O2 APPLE2_BASE_CFLAGS := -DAPPLE2IX=1 -DINTERFACE_TOUCH=1 -DMOBILE_DEVICE=1 -DVIDEO_OPENGL=1 -DDEBUGGER=1 -DAUDIO_ENABLED=1 -std=gnu11 $(APPLE2_OPTIM_CFLAGS) -I$(APPLE2_SRC_PATH)