mirror of
https://github.com/mauiaaron/apple2.git
synced 2024-06-01 13:41:28 +00:00
Compare commits
224 Commits
android-1.
...
android_de
Author | SHA1 | Date | |
---|---|---|---|
|
2739a6b084 | ||
|
ead2ac32f5 | ||
|
76f98557b7 | ||
|
294c6ca790 | ||
|
21fff2cc15 | ||
|
2bda54d342 | ||
|
a5a4a50983 | ||
|
d63ba9538d | ||
|
2728d44f8c | ||
|
ad0a8400ef | ||
|
4616a41326 | ||
|
a470329143 | ||
|
ab482fc3dc | ||
|
2ef5abba2c | ||
|
68e6fb768f | ||
|
296bd12029 | ||
|
f5899e74d6 | ||
|
310825e2cc | ||
|
46b74f65fa | ||
|
397b43b3e7 | ||
|
5aa691815b | ||
|
c0fd258c40 | ||
|
acade0076b | ||
|
cff22f6b34 | ||
|
bf4f76a142 | ||
|
f654fb0825 | ||
|
9a1d305975 | ||
|
e224912f8b | ||
|
1e986d73ef | ||
|
dfc09e87bb | ||
|
57d1e95cce | ||
|
d6e21fd967 | ||
|
37df4796c9 | ||
|
76c9daeb4c | ||
|
e70051d6a4 | ||
|
7ac274261a | ||
|
cf01bb7985 | ||
|
8f2ab2f072 | ||
|
00984b7ab9 | ||
|
1491d3f88d | ||
|
2615351d46 | ||
|
f608de450e | ||
|
c59b18d176 | ||
|
1c022c9587 | ||
|
43d99ec9f4 | ||
|
4e27c1a322 | ||
|
82813b3ac8 | ||
|
ad95368a8c | ||
|
135ccb6b2d | ||
|
7591715357 | ||
|
317f83a44b | ||
|
3bad383cbe | ||
|
96e75f50ff | ||
|
17147ce662 | ||
|
348eeb1f09 | ||
|
e8e3110d18 | ||
|
412fb06011 | ||
|
fe714af37c | ||
|
45cc3332fb | ||
|
7eacfb4564 | ||
|
e643b1c855 | ||
|
4515e5d7b7 | ||
|
713d9a99e2 | ||
|
fcfd32b843 | ||
|
c98777c6ae | ||
|
2878c5adde | ||
|
788c6cb172 | ||
|
a25d68a1d2 | ||
|
44e7bda8ac | ||
|
5efd1099bc | ||
|
3579423890 | ||
|
20852bf737 | ||
|
1a32756bd4 | ||
|
5a8aa065a9 | ||
|
ef3944a4dd | ||
|
9e8a5e2134 | ||
|
1c61071a11 | ||
|
3ca0d9b618 | ||
|
9b110224a0 | ||
|
faf7d707ed | ||
|
5bd8e25739 | ||
|
75be89d1ab | ||
|
f038ef0346 | ||
|
d90e12b5dc | ||
|
c22ad4c1e9 | ||
|
1bf328795a | ||
|
aa74763d28 | ||
|
36c83c62e3 | ||
|
27a848f61b | ||
|
253a99ead2 | ||
|
b08c5d9289 | ||
|
5230afa788 | ||
|
1d2f521e0b | ||
|
db4a71ca6f | ||
|
27c45834d2 | ||
|
1e2449cfdf | ||
|
3317a23563 | ||
|
346d7128d8 | ||
|
0478afe60e | ||
|
d8e6f54c6b | ||
|
e31a50a7fd | ||
|
e9ad630996 | ||
|
d3432fb3d8 | ||
|
3a35404fa3 | ||
|
ab0c796249 | ||
|
1d089af199 | ||
|
6a519b7b5f | ||
|
8a347630b3 | ||
|
d890cddfa1 | ||
|
6f03b89283 | ||
|
fdc5bd33f0 | ||
|
aef25292b7 | ||
|
8b19ba762f | ||
|
184884635b | ||
|
92369c3fdb | ||
|
0625084602 | ||
|
05633d4b0e | ||
|
55418504f4 | ||
|
8e3c07ed57 | ||
|
05d3d884b9 | ||
|
fb44420713 | ||
|
0ddd9ffd91 | ||
|
80f741f225 | ||
|
aabc29e924 | ||
|
32d5d2ee1c | ||
|
f235dd6d7c | ||
|
ae5a2c4d61 | ||
|
dfbc97d7a5 | ||
|
2928556be8 | ||
|
fa2f8569f8 | ||
|
a0f2819a4e | ||
|
ed37c18ec5 | ||
|
18d831b04c | ||
|
227098ec52 | ||
|
8757cb2a06 | ||
|
2a7e375f26 | ||
|
d443f01af3 | ||
|
50d440df1b | ||
|
9f1ef968ac | ||
|
6ee8699079 | ||
|
0f3ba15e87 | ||
|
5b3d0799a3 | ||
|
530aaa4f77 | ||
|
3183dd20b7 | ||
|
55ca51262b | ||
|
b403ee7b6e | ||
|
58488ab8e9 | ||
|
0f38791940 | ||
|
dc49060eda | ||
|
409c4f39ad | ||
|
b216d5f9f8 | ||
|
75edac3ace | ||
|
43ab5c8233 | ||
|
14bb75a941 | ||
|
596f767b9a | ||
|
8f4e878919 | ||
|
a8e14381c1 | ||
|
7ac8f4303c | ||
|
db8fb67944 | ||
|
850b8f3b02 | ||
|
e3c0c2550f | ||
|
aa41c89e68 | ||
|
6ed0100291 | ||
|
3318d159b5 | ||
|
234caa8c9c | ||
|
eb13718c5e | ||
|
51d2efba03 | ||
|
1de71d1ff4 | ||
|
3c04e12db0 | ||
|
cedf7b9d0e | ||
|
154b9a7ef8 | ||
|
dd42645c4c | ||
|
e898a85f50 | ||
|
807b441ab1 | ||
|
4aa75a59c8 | ||
|
c1076aa9cf | ||
|
8f155b5190 | ||
|
e4e0c941d3 | ||
|
6e7af373d7 | ||
|
167263ab3a | ||
|
b1161ba746 | ||
|
6b901dff07 | ||
|
8b554083b4 | ||
|
cd6eb65fc5 | ||
|
4bc61b6216 | ||
|
20b085d9f7 | ||
|
a0c26386e8 | ||
|
1ff7bfe4bf | ||
|
7a99b72f20 | ||
|
021604471b | ||
|
dc5e7eee25 | ||
|
c3ea8c5aea | ||
|
53459c9e78 | ||
|
570147712c | ||
|
a9755215bf | ||
|
981cff845b | ||
|
b5b79faf1d | ||
|
dd02333eae | ||
|
a055ae8b8d | ||
|
25e4fd0eba | ||
|
58d2392eac | ||
|
ae76537a19 | ||
|
8e6701bcbb | ||
|
2517b45720 | ||
|
d35d87af9f | ||
|
2d5c47d534 | ||
|
85dc4e5132 | ||
|
861cb3320c | ||
|
d226db8021 | ||
|
f8b4602fca | ||
|
0801c9f010 | ||
|
72c5c550fe | ||
|
11cf51753b | ||
|
98aecedd65 | ||
|
bcbf5ac234 | ||
|
1716dd35be | ||
|
153f1434db | ||
|
51a5f5fcf7 | ||
|
3b1c72e872 | ||
|
3c1dcd4a69 | ||
|
97a98f0c86 | ||
|
bdbe544c3b | ||
|
13bf93e5ca | ||
|
2836d903d9 |
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -79,6 +79,7 @@ Android/local.properties
|
|||
Android/.idea/workspace.xml
|
||||
Android/.idea/libraries
|
||||
Android/.idea/dictionaries
|
||||
Android/.idea/caches
|
||||
Android/build
|
||||
Android/jni/obj
|
||||
Android/obj
|
||||
|
|
14
ASM
14
ASM
|
@ -1,14 +0,0 @@
|
|||
Begin3
|
||||
Title: Apple //ix
|
||||
Author: alexb@csd.uu.se (Alexander Jean-Claude Bottema)
|
||||
sl14@cornell.edu (Stephen Lee)
|
||||
michael@talamasca.ocis.net (Michael Deutschmann)
|
||||
ASC _at_ BITR0T (Aaron Culliney)
|
||||
Version: 0.8
|
||||
Entered-date: 2014-02-27
|
||||
Description: Apple //e emulator for POSIX systems
|
||||
Keywords: emulator, linux, posix
|
||||
Uploader: ASC _at_ BITR0T (Aaron Culliney)
|
||||
Primary-site: https://github.com/mauiaaron/apple2
|
||||
Platform: Linux i386
|
||||
End
|
116
Android/.idea/codeStyles/Project.xml
Normal file
116
Android/.idea/codeStyles/Project.xml
Normal file
|
@ -0,0 +1,116 @@
|
|||
<component name="ProjectCodeStyleConfiguration">
|
||||
<code_scheme name="Project" version="173">
|
||||
<codeStyleSettings language="XML">
|
||||
<indentOptions>
|
||||
<option name="CONTINUATION_INDENT_SIZE" value="4" />
|
||||
</indentOptions>
|
||||
<arrangement>
|
||||
<rules>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>xmlns:android</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>xmlns:.*</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
<order>BY_NAME</order>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*:id</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*:name</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>name</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>style</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
<order>BY_NAME</order>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
<order>ANDROID_ATTRIBUTE_ORDER</order>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>.*</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
<order>BY_NAME</order>
|
||||
</rule>
|
||||
</section>
|
||||
</rules>
|
||||
</arrangement>
|
||||
</codeStyleSettings>
|
||||
</code_scheme>
|
||||
</component>
|
|
@ -1,22 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CompilerConfiguration">
|
||||
<resourceExtensions />
|
||||
<wildcardResourcePatterns>
|
||||
<entry name="!?*.java" />
|
||||
<entry name="!?*.form" />
|
||||
<entry name="!?*.class" />
|
||||
<entry name="!?*.groovy" />
|
||||
<entry name="!?*.scala" />
|
||||
<entry name="!?*.flex" />
|
||||
<entry name="!?*.kt" />
|
||||
<entry name="!?*.clj" />
|
||||
<entry name="!?*.aj" />
|
||||
</wildcardResourcePatterns>
|
||||
<annotationProcessing>
|
||||
<profile default="true" name="Default" enabled="false">
|
||||
<processorPath useClasspath="true" />
|
||||
</profile>
|
||||
</annotationProcessing>
|
||||
</component>
|
||||
</project>
|
|
@ -1,3 +0,0 @@
|
|||
<component name="CopyrightManager">
|
||||
<settings default="" />
|
||||
</component>
|
|
@ -1,6 +1,4 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Encoding">
|
||||
<file url="PROJECT" charset="UTF-8" />
|
||||
</component>
|
||||
<component name="Encoding" addBOMForNewFiles="with NO BOM" />
|
||||
</project>
|
|
@ -3,9 +3,11 @@
|
|||
<component name="GradleSettings">
|
||||
<option name="linkedExternalProjectsSettings">
|
||||
<GradleProjectSettings>
|
||||
<option name="distributionType" value="LOCAL" />
|
||||
<compositeConfiguration>
|
||||
<compositeBuild compositeDefinitionSource="SCRIPT" />
|
||||
</compositeConfiguration>
|
||||
<option name="distributionType" value="DEFAULT_WRAPPED" />
|
||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||
<option name="gradleHome" value="$APPLICATION_HOME_DIR$/gradle/gradle-2.14.1" />
|
||||
<option name="modules">
|
||||
<set>
|
||||
<option value="$PROJECT_DIR$" />
|
||||
|
|
|
@ -1,43 +1,41 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="EntryPointsManager">
|
||||
<entry_points version="2.0" />
|
||||
</component>
|
||||
<component name="NullableNotNullManager">
|
||||
<option name="myDefaultNullable" value="android.support.annotation.Nullable" />
|
||||
<option name="myDefaultNotNull" value="android.support.annotation.NonNull" />
|
||||
<option name="myNullables">
|
||||
<value>
|
||||
<list size="4">
|
||||
<list size="10">
|
||||
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.Nullable" />
|
||||
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nullable" />
|
||||
<item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.Nullable" />
|
||||
<item index="3" class="java.lang.String" itemvalue="android.support.annotation.Nullable" />
|
||||
<item index="2" class="java.lang.String" itemvalue="javax.annotation.CheckForNull" />
|
||||
<item index="3" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.Nullable" />
|
||||
<item index="4" class="java.lang.String" itemvalue="android.support.annotation.Nullable" />
|
||||
<item index="5" class="java.lang.String" itemvalue="androidx.annotation.Nullable" />
|
||||
<item index="6" class="java.lang.String" itemvalue="androidx.annotation.RecentlyNullable" />
|
||||
<item index="7" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.qual.Nullable" />
|
||||
<item index="8" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NullableDecl" />
|
||||
<item index="9" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NullableType" />
|
||||
</list>
|
||||
</value>
|
||||
</option>
|
||||
<option name="myNotNulls">
|
||||
<value>
|
||||
<list size="4">
|
||||
<list size="9">
|
||||
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.NotNull" />
|
||||
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nonnull" />
|
||||
<item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.NonNull" />
|
||||
<item index="3" class="java.lang.String" itemvalue="android.support.annotation.NonNull" />
|
||||
<item index="4" class="java.lang.String" itemvalue="androidx.annotation.NonNull" />
|
||||
<item index="5" class="java.lang.String" itemvalue="androidx.annotation.RecentlyNonNull" />
|
||||
<item index="6" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.qual.NonNull" />
|
||||
<item index="7" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NonNullDecl" />
|
||||
<item index="8" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NonNullType" />
|
||||
</list>
|
||||
</value>
|
||||
</option>
|
||||
</component>
|
||||
<component name="ProjectLevelVcsManager" settingsEditedManually="false">
|
||||
<OptionsSetting value="true" id="Add" />
|
||||
<OptionsSetting value="true" id="Remove" />
|
||||
<OptionsSetting value="true" id="Checkout" />
|
||||
<OptionsSetting value="true" id="Update" />
|
||||
<OptionsSetting value="true" id="Status" />
|
||||
<OptionsSetting value="true" id="Edit" />
|
||||
<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.8" project-jdk-type="JavaSDK">
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" project-jdk-name="JDK" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
||||
</component>
|
||||
<component name="ProjectType">
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module external.linked.project.id="Android" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$" external.system.id="GRADLE" external.system.module.group="" external.system.module.version="unspecified" type="JAVA_MODULE" version="4">
|
||||
<module external.linked.project.id="Android" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$" external.system.id="GRADLE" type="JAVA_MODULE" version="4">
|
||||
<component name="FacetManager">
|
||||
<facet type="java-gradle" name="Java-Gradle">
|
||||
<configuration>
|
||||
|
@ -13,7 +13,7 @@
|
|||
<content url="file://$MODULE_DIR$">
|
||||
<excludeFolder url="file://$MODULE_DIR$/.gradle" />
|
||||
</content>
|
||||
<orderEntry type="jdk" jdkName="1.8" jdkType="JavaSDK" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
|
@ -1 +0,0 @@
|
|||
app/build/intermediates/manifests/full/debug/AndroidManifest.xml
|
|
@ -1,9 +1,11 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module external.linked.project.id=":app" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$/.." external.system.id="GRADLE" external.system.module.group="Android" external.system.module.version="unspecified" type="JAVA_MODULE" version="4">
|
||||
<module external.linked.project.id=":app" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$/.." external.system.id="GRADLE" type="JAVA_MODULE" version="4">
|
||||
<component name="FacetManager">
|
||||
<facet type="android-gradle" name="Android-Gradle">
|
||||
<configuration>
|
||||
<option name="GRADLE_PROJECT_PATH" value=":app" />
|
||||
<option name="LAST_SUCCESSFUL_SYNC_AGP_VERSION" value="3.5.2" />
|
||||
<option name="LAST_KNOWN_AGP_VERSION" value="3.5.2" />
|
||||
</configuration>
|
||||
</facet>
|
||||
<facet type="android" name="Android">
|
||||
|
@ -17,30 +19,30 @@
|
|||
<option name="ALLOW_USER_CONFIGURATION" value="false" />
|
||||
<option name="MANIFEST_FILE_RELATIVE_PATH" value="/src/main/AndroidManifest.xml" />
|
||||
<option name="RES_FOLDER_RELATIVE_PATH" value="/src/main/res" />
|
||||
<option name="RES_FOLDERS_RELATIVE_PATH" value="file://$MODULE_DIR$/src/main/res" />
|
||||
<option name="RES_FOLDERS_RELATIVE_PATH" value="file://$MODULE_DIR$/src/main/res;file://$MODULE_DIR$/build/generated/res/resValues/debug" />
|
||||
<option name="TEST_RES_FOLDERS_RELATIVE_PATH" value="" />
|
||||
<option name="ASSETS_FOLDER_RELATIVE_PATH" value="/src/main/assets" />
|
||||
</configuration>
|
||||
</facet>
|
||||
</component>
|
||||
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_7" inherit-compiler-output="false">
|
||||
<output url="file://$MODULE_DIR$/build/intermediates/classes/debug" />
|
||||
<output-test url="file://$MODULE_DIR$/build/intermediates/classes/test/debug" />
|
||||
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_7">
|
||||
<output url="file://$MODULE_DIR$/build/intermediates/javac/debug/classes" />
|
||||
<output-test url="file://$MODULE_DIR$/build/intermediates/javac/debugUnitTest/classes" />
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/r/debug" isTestSource="false" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/debug" isTestSource="false" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/ap_generated_sources/debug/out" isTestSource="false" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/aidl_source_output_dir/debug/compileDebugAidl/out" isTestSource="false" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/debug" isTestSource="false" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/debug" isTestSource="false" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/apt/debug" isTestSource="false" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/debug" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/resValues/debug" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/r/androidTest/debug" isTestSource="true" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/androidTest/debug" isTestSource="true" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/renderscript_source_output_dir/debug/compileDebugRenderscript/out" isTestSource="false" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/debug" type="java-resource" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/resValues/debug" type="java-resource" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/ap_generated_sources/debugAndroidTest/out" isTestSource="true" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/aidl_source_output_dir/debugAndroidTest/compileDebugAndroidTestAidl/out" isTestSource="true" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/androidTest/debug" isTestSource="true" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/androidTest/debug" isTestSource="true" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/apt/androidTest/debug" isTestSource="true" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/androidTest/debug" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/resValues/androidTest/debug" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/renderscript_source_output_dir/debugAndroidTest/compileDebugAndroidTestRenderscript/out" isTestSource="true" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/androidTest/debug" type="java-test-resource" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/resValues/androidTest/debug" type="java-test-resource" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/ap_generated_sources/debugUnitTest/out" isTestSource="true" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/res" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/resources" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/assets" type="java-resource" />
|
||||
|
@ -48,6 +50,13 @@
|
|||
<sourceFolder url="file://$MODULE_DIR$/src/debug/java" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/rs" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/shaders" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/res" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/resources" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/assets" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/aidl" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/java" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/rs" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/shaders" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/res" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/resources" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/assets" type="java-test-resource" />
|
||||
|
@ -62,13 +71,6 @@
|
|||
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/rs" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/shaders" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/res" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/resources" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/assets" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/aidl" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/rs" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/shaders" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/res" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/resources" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/assets" type="java-test-resource" />
|
||||
|
@ -76,33 +78,40 @@
|
|||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/java" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/rs" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/shaders" isTestSource="true" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/assets" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/blame" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/classes" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental-safeguard" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/jniLibs" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/manifests" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/pre-dexed" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/res" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/rs" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/shaders" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/symbols" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/transforms" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/outputs" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/tmp" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/res" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/resources" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/assets" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/aidl" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/rs" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/shaders" isTestSource="true" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build" />
|
||||
</content>
|
||||
<orderEntry type="jdk" jdkName="Android API 24 Platform" jdkType="Android SDK" />
|
||||
<orderEntry type="jdk" jdkName="Android API 29 Platform" jdkType="Android SDK" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" exported="" name="support-media-compat-24.2.0" level="project" />
|
||||
<orderEntry type="library" exported="" name="support-compat-24.2.0" level="project" />
|
||||
<orderEntry type="library" exported="" name="support-v4-24.2.0" level="project" />
|
||||
<orderEntry type="library" exported="" name="support-core-ui-24.2.0" level="project" />
|
||||
<orderEntry type="library" exported="" name="support-core-utils-24.2.0" level="project" />
|
||||
<orderEntry type="library" exported="" name="appcompat-v7-24.2.0" level="project" />
|
||||
<orderEntry type="library" exported="" name="support-fragment-24.2.0" level="project" />
|
||||
<orderEntry type="library" exported="" name="support-annotations-24.2.0" level="project" />
|
||||
<orderEntry type="library" exported="" name="support-vector-drawable-24.2.0" level="project" />
|
||||
<orderEntry type="library" exported="" name="animated-vector-drawable-24.2.0" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.collection:collection:1.1.0@jar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.lifecycle:lifecycle-common:2.1.0@jar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.arch.core:core-common:2.1.0@jar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.annotation:annotation:1.1.0@jar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.appcompat:appcompat:1.1.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.fragment:fragment:1.1.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.appcompat:appcompat-resources:1.1.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.drawerlayout:drawerlayout:1.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.viewpager:viewpager:1.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.loader:loader:1.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.activity:activity:1.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.vectordrawable:vectordrawable-animated:1.1.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.vectordrawable:vectordrawable:1.1.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.customview:customview:1.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.core:core:1.1.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.cursoradapter:cursoradapter:1.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.versionedparcelable:versionedparcelable:1.1.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.lifecycle:lifecycle-viewmodel:2.1.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.lifecycle:lifecycle-runtime:2.1.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.savedstate:savedstate:1.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.lifecycle:lifecycle-livedata:2.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.lifecycle:lifecycle-livedata-core:2.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.interpolator:interpolator:1.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.arch.core:core-runtime:2.0.0@aar" level="project" />
|
||||
</component>
|
||||
</module>
|
|
@ -1,8 +1,7 @@
|
|||
apply plugin: 'com.android.application'
|
||||
|
||||
android {
|
||||
compileSdkVersion 24
|
||||
buildToolsVersion '25.0.0'
|
||||
compileSdkVersion 29
|
||||
signingConfigs {
|
||||
release {
|
||||
storeFile file("release2.keystore")
|
||||
|
@ -22,16 +21,33 @@ android {
|
|||
jniDebuggable true
|
||||
}
|
||||
}
|
||||
splits {
|
||||
|
||||
// Configures multiple APKs based on ABI
|
||||
abi {
|
||||
// Enables building multiple APKs per ABI
|
||||
enable true
|
||||
|
||||
// Resets the list of ABIs that Gradle should create APKs for to none
|
||||
reset()
|
||||
|
||||
// Include just these ...
|
||||
include "armeabi-v7a", "arm64-v8a", "x86", "x86_64"
|
||||
|
||||
// Specifies that we do not want to also generate a universal APK that includes all ABIs
|
||||
//universalApk false
|
||||
}
|
||||
}
|
||||
lintOptions {
|
||||
checkReleaseBuilds false
|
||||
}
|
||||
|
||||
defaultConfig {
|
||||
applicationId "org.deadc0de.apple2ix.basic"
|
||||
minSdkVersion 10
|
||||
targetSdkVersion 24
|
||||
versionCode 20
|
||||
versionName "1.2.0"
|
||||
minSdkVersion 14
|
||||
targetSdkVersion 29
|
||||
versionCode 26
|
||||
versionName "2.1.0-RC3"
|
||||
ndk {
|
||||
moduleName "apple2ix"
|
||||
}
|
||||
|
@ -39,6 +55,6 @@ android {
|
|||
}
|
||||
|
||||
dependencies {
|
||||
compile fileTree(dir: 'libs', include: ['*.jar'])
|
||||
compile 'com.android.support:appcompat-v7:24.2.0'
|
||||
api fileTree(dir: 'libs', include: ['*.jar'])
|
||||
api 'androidx.appcompat:appcompat:1.1.0'
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
package="org.deadc0de.apple2ix.basic" >
|
||||
|
||||
<uses-feature android:glEsVersion="0x00020000" />
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
||||
|
||||
<supports-screens
|
||||
|
@ -12,6 +13,7 @@
|
|||
android:smallScreens="false" />
|
||||
|
||||
<application
|
||||
android:requestLegacyExternalStorage="true"
|
||||
android:allowBackup="true"
|
||||
android:fullBackupContent="@xml/a2backupscheme"
|
||||
android:icon="@drawable/ic_launcher"
|
||||
|
@ -21,9 +23,9 @@
|
|||
android:name="org.deadc0de.apple2ix.Apple2Activity"
|
||||
android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|screenLayout|fontScale|uiMode|orientation"
|
||||
android:screenOrientation="sensorLandscape"
|
||||
android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
|
||||
android:theme="@style/Theme.AppCompat.NoActionBar.FullScreen"
|
||||
android:launchMode="singleTask"
|
||||
android:windowSoftInputMode="adjustResize" >
|
||||
android:windowSoftInputMode="stateHidden|adjustNothing" >
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
|
@ -37,11 +39,18 @@
|
|||
|
||||
</activity>
|
||||
|
||||
<activity android:name="org.deadc0de.apple2ix.Apple2DiskChooserActivity" />
|
||||
<activity android:name="org.deadc0de.apple2ix.Apple2DiskChooserActivity"
|
||||
android:theme="@style/Theme.AppCompat"
|
||||
/>
|
||||
|
||||
<activity android:name="org.deadc0de.apple2ix.Apple2EmailerActivity"
|
||||
android:theme="@style/Theme.AppCompat"
|
||||
android:screenOrientation="portrait"
|
||||
/>
|
||||
|
||||
<provider
|
||||
android:authorities="${applicationId}.provider"
|
||||
android:name="android.support.v4.content.FileProvider"
|
||||
android:name="androidx.core.content.FileProvider"
|
||||
android:exported="false"
|
||||
android:grantUriPermissions="true">
|
||||
<meta-data
|
||||
|
|
|
@ -10,11 +10,11 @@ package android.widget;
|
|||
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import androidx.appcompat.widget.AppCompatSeekBar;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.MotionEvent;
|
||||
|
||||
public class VerticalSeekBar extends SeekBar {
|
||||
public class VerticalSeekBar extends AppCompatSeekBar {
|
||||
|
||||
public VerticalSeekBar(Context context) {
|
||||
super(context);
|
||||
|
|
|
@ -11,10 +11,12 @@
|
|||
|
||||
package org.deadc0de.apple2ix;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.appcompat.widget.AppCompatCheckBox;
|
||||
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
@ -219,7 +221,7 @@ public abstract class Apple2AbstractMenu implements Apple2MenuView {
|
|||
}
|
||||
|
||||
protected static CheckBox _addCheckbox(Apple2Activity activity, IMenuEnum setting, View convertView, boolean isChecked) {
|
||||
CheckBox checkBox = new CheckBox(activity);
|
||||
AppCompatCheckBox checkBox = new AppCompatCheckBox(activity);
|
||||
checkBox.setChecked(isChecked);
|
||||
LinearLayout layout = (LinearLayout) convertView.findViewById(R.id.a2preference_widget_frame);
|
||||
layout.addView(checkBox);
|
||||
|
|
|
@ -12,12 +12,15 @@
|
|||
package org.deadc0de.apple2ix;
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.res.AssetManager;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.StrictMode;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import android.util.Log;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.View;
|
||||
|
@ -25,14 +28,21 @@ import android.view.ViewGroup;
|
|||
import android.widget.FrameLayout;
|
||||
import android.widget.Toast;
|
||||
|
||||
import org.deadc0de.apple2ix.basic.BuildConfig;
|
||||
import org.deadc0de.apple2ix.basic.R;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.InterruptedIOException;
|
||||
import java.io.Reader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import org.deadc0de.apple2ix.basic.BuildConfig;
|
||||
import org.deadc0de.apple2ix.basic.R;
|
||||
|
||||
public class Apple2Activity extends Activity implements Apple2DiskChooserActivity.Callback {
|
||||
public class Apple2Activity extends AppCompatActivity implements Apple2DiskChooserActivity.Callback, Apple2EmailerActivity.Callback
|
||||
{
|
||||
|
||||
private final static String TAG = "Apple2Activity";
|
||||
|
||||
|
@ -88,6 +98,8 @@ public class Apple2Activity extends Activity implements Apple2DiskChooserActivit
|
|||
|
||||
private static native void nativeReboot(int resetState);
|
||||
|
||||
private static native void nativeLogMessage(String jsonStr);
|
||||
|
||||
public final static boolean isNativeBarfed() {
|
||||
return sNativeBarfed;
|
||||
}
|
||||
|
@ -110,7 +122,7 @@ public class Apple2Activity extends Activity implements Apple2DiskChooserActivit
|
|||
}
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
Log.e(TAG, "onCreate()");
|
||||
logMessage(LogType.ERROR, TAG, "onCreate()");
|
||||
|
||||
// placeholder view on initial launch
|
||||
if (mView == null) {
|
||||
|
@ -119,14 +131,14 @@ public class Apple2Activity extends Activity implements Apple2DiskChooserActivit
|
|||
|
||||
Apple2CrashHandler.getInstance().initializeAndSetCustomExceptionHandler(this);
|
||||
if (sNativeBarfed) {
|
||||
Log.e(TAG, "NATIVE BARFED...", sNativeBarfedThrowable);
|
||||
logMessage(LogType.ERROR, TAG, "NATIVE BARFED : " + sNativeBarfedThrowable.getMessage());
|
||||
return;
|
||||
}
|
||||
|
||||
int sampleRate = DevicePropertyCalculator.getRecommendedSampleRate(this);
|
||||
int monoBufferSize = DevicePropertyCalculator.getRecommendedBufferSize(this, /*isStereo:*/false);
|
||||
int stereoBufferSize = DevicePropertyCalculator.getRecommendedBufferSize(this, /*isStereo:*/true);
|
||||
Log.d(TAG, "Device sampleRate:" + sampleRate + " mono bufferSize:" + monoBufferSize + " stereo bufferSize:" + stereoBufferSize);
|
||||
logMessage(LogType.DEBUG, TAG, "Device sampleRate:" + sampleRate + " mono bufferSize:" + monoBufferSize + " stereo bufferSize:" + stereoBufferSize);
|
||||
|
||||
String dataDir = Apple2Utils.getDataDir(this);
|
||||
nativeOnCreate(dataDir, sampleRate, monoBufferSize, stereoBufferSize);
|
||||
|
@ -145,23 +157,20 @@ public class Apple2Activity extends Activity implements Apple2DiskChooserActivit
|
|||
|
||||
// Is there a way to persist the user orientation setting such that we launch in the previously set orientation and avoid getting multiple onCreate() onResume()?! ... Android lifecycle edge cases are so damn kludgishly annoying ...
|
||||
mSwitchingToPortrait.set(switchingToPortrait);
|
||||
if (!switchingToPortrait) {
|
||||
Apple2CrashHandler.getInstance().checkForCrashes(this);
|
||||
}
|
||||
|
||||
Apple2CrashHandler.getInstance().checkForCrashes(this);
|
||||
|
||||
boolean extperm = true;
|
||||
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
// On Marshmallow+ specifically ask for permission to read/write storage
|
||||
String readPermission = Manifest.permission.READ_EXTERNAL_STORAGE;
|
||||
String writePermission = Manifest.permission.WRITE_EXTERNAL_STORAGE;
|
||||
int hasReadPermission = checkSelfPermission(readPermission);
|
||||
int hasWritePermission = checkSelfPermission(writePermission);
|
||||
int hasReadPermission = checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE);
|
||||
int hasWritePermission = checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE);
|
||||
ArrayList<String> permissions = new ArrayList<String>();
|
||||
if (hasReadPermission != PackageManager.PERMISSION_GRANTED) {
|
||||
permissions.add(readPermission);
|
||||
permissions.add(Manifest.permission.READ_EXTERNAL_STORAGE);
|
||||
}
|
||||
if (hasWritePermission != PackageManager.PERMISSION_GRANTED) {
|
||||
permissions.add(writePermission);
|
||||
permissions.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
|
||||
}
|
||||
if (!permissions.isEmpty()) {
|
||||
extperm = false;
|
||||
|
@ -179,9 +188,20 @@ public class Apple2Activity extends Activity implements Apple2DiskChooserActivit
|
|||
Apple2Utils.exposeAPKAssets(Apple2Activity.this);
|
||||
if (externalStoragePermission) {
|
||||
Apple2Utils.exposeAPKAssetsToExternal(Apple2Activity.this);
|
||||
logMessage(LogType.DEBUG, TAG, "Finished first time copying #1...");
|
||||
|
||||
if (!(boolean)Apple2Preferences.getJSONPref(Apple2Preferences.PREF_DOMAIN_INTERFACE, Apple2Preferences.PREF_RELEASE_NOTES, false)) {
|
||||
Runnable myRunnable = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
showReleaseNotes();
|
||||
}
|
||||
};
|
||||
new Handler(Apple2Activity.this.getMainLooper()).post(myRunnable);
|
||||
}
|
||||
}
|
||||
|
||||
mSplashScreen.setDismissable(true);
|
||||
Log.d(TAG, "Finished first time copying...");
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
@ -190,6 +210,11 @@ public class Apple2Activity extends Activity implements Apple2DiskChooserActivit
|
|||
mDisksMenu = new Apple2DisksMenu(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEmailerFinished() {
|
||||
Apple2CrashHandler.getInstance().cleanCrashData(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisksChosen(DiskArgs args) {
|
||||
final String name = args.name;
|
||||
|
@ -215,10 +240,15 @@ public class Apple2Activity extends Activity implements Apple2DiskChooserActivit
|
|||
// perform migration(s) and assets exposure now
|
||||
Apple2Utils.migrateToExternalStorage(Apple2Activity.this);
|
||||
Apple2Utils.exposeAPKAssetsToExternal(Apple2Activity.this);
|
||||
logMessage(LogType.DEBUG, TAG, "Finished first time copying #2...");
|
||||
} // else ... we keep nagging on app startup ...
|
||||
} else {
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||
}
|
||||
|
||||
if (!(boolean)Apple2Preferences.getJSONPref(Apple2Preferences.PREF_DOMAIN_INTERFACE, Apple2Preferences.PREF_RELEASE_NOTES, false)) {
|
||||
showReleaseNotes();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -231,11 +261,8 @@ public class Apple2Activity extends Activity implements Apple2DiskChooserActivit
|
|||
break;
|
||||
}
|
||||
|
||||
Log.d(TAG, "onResume()");
|
||||
logMessage(LogType.DEBUG, TAG, "onResume()");
|
||||
showSplashScreen(/*dismissable:*/true);
|
||||
if (!mSwitchingToPortrait.get()) {
|
||||
Apple2CrashHandler.getInstance().checkForCrashes(this); // NOTE : needs to be called again to clean-up
|
||||
}
|
||||
|
||||
if (mDisksMenu == null) {
|
||||
break;
|
||||
|
@ -298,10 +325,10 @@ public class Apple2Activity extends Activity implements Apple2DiskChooserActivit
|
|||
if (isEmulationPaused()) {
|
||||
Apple2Preferences.save(this);
|
||||
} else {
|
||||
Log.d(TAG, "Letting native save preferences...");
|
||||
logMessage(LogType.DEBUG, TAG, "Letting native save preferences...");
|
||||
}
|
||||
|
||||
Log.d(TAG, "onPause()");
|
||||
logMessage(LogType.INFO, TAG, "onPause() ...");
|
||||
if (mView != null) {
|
||||
mView.onPause();
|
||||
}
|
||||
|
@ -363,6 +390,59 @@ public class Apple2Activity extends Activity implements Apple2DiskChooserActivit
|
|||
}
|
||||
}
|
||||
|
||||
public void showReleaseNotes() {
|
||||
|
||||
Apple2Preferences.setJSONPref(Apple2Preferences.PREF_DOMAIN_INTERFACE, Apple2Preferences.PREF_RELEASE_NOTES, true);
|
||||
Apple2Preferences.save(this);
|
||||
|
||||
String releaseNotes = "";
|
||||
final int maxAttempts = 5;
|
||||
int attempts = 0;
|
||||
do {
|
||||
InputStream is = null;
|
||||
try {
|
||||
AssetManager assetManager = getAssets();
|
||||
is = assetManager.open("release_notes.txt");
|
||||
|
||||
final int bufferSize = 4096;
|
||||
final char[] buffer = new char[bufferSize];
|
||||
final StringBuilder out = new StringBuilder();
|
||||
Reader in = new InputStreamReader(is, "UTF-8");
|
||||
while (true) {
|
||||
int siz = in.read(buffer, 0, buffer.length);
|
||||
if (siz < 0) {
|
||||
break;
|
||||
}
|
||||
out.append(buffer, 0, siz);
|
||||
}
|
||||
releaseNotes = out.toString();
|
||||
break;
|
||||
} catch (InterruptedIOException e) {
|
||||
/* EINTR, EAGAIN */
|
||||
} catch (IOException e) {
|
||||
logMessage(LogType.ERROR, TAG, "OOPS could not load release_notes.txt : " + e.getMessage());
|
||||
} finally {
|
||||
if (is != null) {
|
||||
try {
|
||||
is.close();
|
||||
} catch (IOException e) {
|
||||
// NOOP
|
||||
}
|
||||
}
|
||||
}
|
||||
++attempts;
|
||||
} while (attempts < maxAttempts);
|
||||
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(Apple2Activity.this).setIcon(R.drawable.ic_launcher).setCancelable(false).setTitle(R.string.release_notes).setMessage(releaseNotes).setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
dialog.dismiss();
|
||||
}
|
||||
});
|
||||
AlertDialog dialog = builder.create();
|
||||
registerAndShowDialog(dialog);
|
||||
}
|
||||
|
||||
public Apple2MainMenu getMainMenu() {
|
||||
return mMainMenu;
|
||||
}
|
||||
|
@ -531,6 +611,7 @@ public class Apple2Activity extends Activity implements Apple2DiskChooserActivit
|
|||
}
|
||||
|
||||
public void quitEmulator() {
|
||||
logMessage(LogType.INFO, TAG, "Quitting...");
|
||||
nativeOnQuit();
|
||||
finish();
|
||||
new Runnable() {
|
||||
|
@ -545,4 +626,30 @@ public class Apple2Activity extends Activity implements Apple2DiskChooserActivit
|
|||
}
|
||||
}.run();
|
||||
}
|
||||
|
||||
public enum LogType {
|
||||
// Constants match
|
||||
VERBOSE(2),
|
||||
DEBUG(3),
|
||||
INFO(4),
|
||||
WARN(5),
|
||||
ERROR(6);
|
||||
private int type;
|
||||
|
||||
LogType(int type) {
|
||||
this.type = type;
|
||||
}
|
||||
}
|
||||
|
||||
public static void logMessage(LogType type, String tag, String mesg) {
|
||||
JSONObject map = new JSONObject();
|
||||
try {
|
||||
map.put("type", type.type);
|
||||
map.put("tag", tag);
|
||||
map.put("mesg", mesg);
|
||||
nativeLogMessage(map.toString());
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "OOPS: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,22 +11,18 @@
|
|||
|
||||
package org.deadc0de.apple2ix;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Environment;
|
||||
import android.util.Log;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import android.view.View;
|
||||
import android.widget.ProgressBar;
|
||||
|
||||
import org.deadc0de.apple2ix.basic.BuildConfig;
|
||||
import org.deadc0de.apple2ix.basic.R;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
|
@ -34,10 +30,13 @@ import java.io.FileWriter;
|
|||
import java.io.FilenameFilter;
|
||||
import java.io.IOException;
|
||||
import java.io.InterruptedIOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
public class Apple2CrashHandler {
|
||||
|
||||
public final static String ALL_CRASH_FILE = "apple2ix_data.zip";
|
||||
|
||||
public final static String javaCrashFileName = "jcrash.txt";
|
||||
|
||||
public static Apple2CrashHandler getInstance() {
|
||||
|
@ -205,222 +204,127 @@ public class Apple2CrashHandler {
|
|||
}
|
||||
|
||||
public void checkForCrashes(final Apple2Activity activity) {
|
||||
|
||||
File oldCrashFile = _getCrashLogFile(activity);
|
||||
if (oldCrashFile.exists()) {
|
||||
oldCrashFile.delete();
|
||||
}
|
||||
|
||||
if (!areCrashesPresent(activity)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Apple2Preferences.load(activity);
|
||||
if (!(boolean) Apple2Preferences.getJSONPref(Apple2SettingsMenu.SETTINGS.CRASH)) {
|
||||
cleanCrashData(activity);
|
||||
return;
|
||||
}
|
||||
|
||||
boolean previouslyRanCrashCheck = mAlreadyRanCrashCheck.getAndSet(true);
|
||||
|
||||
boolean previouslySentReport = mAlreadySentReport.get();
|
||||
if (previouslySentReport) {
|
||||
|
||||
// here we assume that the crash data was previously sent via email ... if not then we lost it =P
|
||||
|
||||
Log.d(TAG, "Cleaning up crash data ...");
|
||||
int idx = 0;
|
||||
File[] nativeCrashes = _nativeCrashFiles(activity);
|
||||
for (File crash : nativeCrashes) {
|
||||
|
||||
if (!crash.delete()) {
|
||||
Log.d(TAG, "Could not unlink crash : " + crash);
|
||||
}
|
||||
|
||||
File processed = new File(_dumpPath2ProcessedPath(crash.getAbsolutePath()));
|
||||
if (!processed.delete()) {
|
||||
Log.d(TAG, "Could not unlink processed : " + processed);
|
||||
}
|
||||
}
|
||||
|
||||
File javaCrashFile = _javaCrashFile(activity);
|
||||
if (!javaCrashFile.delete()) {
|
||||
Log.d(TAG, "Could not unlink java crash : " + javaCrashFile);
|
||||
}
|
||||
|
||||
// remove previous log file
|
||||
File allCrashFile = _getCrashFile(activity);
|
||||
Apple2Utils.writeFile(new StringBuilder(), allCrashFile);
|
||||
allCrashFile.delete();
|
||||
return;
|
||||
}
|
||||
|
||||
if (previouslyRanCrashCheck) {
|
||||
// don't keep asking on return from backgrounding
|
||||
return;
|
||||
}
|
||||
|
||||
final AlertDialog crashDialog = new AlertDialog.Builder(activity).setIcon(R.drawable.ic_launcher).setCancelable(true).setTitle(R.string.crasher_send).setMessage(R.string.crasher_send_message).setNegativeButton(R.string.no, null).setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
|
||||
final AlertDialog crashDialog = new AlertDialog.Builder(activity).setIcon(R.drawable.ic_launcher).setCancelable(true).setTitle(R.string.crasher_send).setMessage(R.string.crasher_send_message).setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
dialog.dismiss();
|
||||
emailCrashesAndLogs(activity);
|
||||
}
|
||||
}).create();
|
||||
activity.registerAndShowDialog(crashDialog);
|
||||
}
|
||||
|
||||
public void emailCrashesAndLogs(final Apple2Activity activity) {
|
||||
final Apple2SplashScreen splashScreen = activity.getSplashScreen();
|
||||
if (splashScreen != null) {
|
||||
splashScreen.setDismissable(false);
|
||||
}
|
||||
final ProgressBar bar = (ProgressBar) activity.findViewById(R.id.crash_progressBar);
|
||||
try {
|
||||
bar.setVisibility(View.VISIBLE);
|
||||
} catch (NullPointerException npe) {
|
||||
/* email logs doesn't show the splash screen */
|
||||
}
|
||||
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_BACKGROUND);
|
||||
|
||||
final int sampleRate = DevicePropertyCalculator.getRecommendedSampleRate(activity);
|
||||
final int monoBufferSize = DevicePropertyCalculator.getRecommendedBufferSize(activity, /*isStereo:*/false);
|
||||
final int stereoBufferSize = DevicePropertyCalculator.getRecommendedBufferSize(activity, /*isStereo:*/true);
|
||||
|
||||
StringBuilder summary = new StringBuilder();
|
||||
|
||||
// prepend information about this device
|
||||
summary.append("BRAND: ").append(Build.BRAND).append("\n");
|
||||
summary.append("MODEL: ").append(Build.MODEL).append("\n");
|
||||
summary.append("MANUFACTURER: ").append(Build.MANUFACTURER).append("\n");
|
||||
summary.append("DEVICE: ").append(Build.DEVICE).append("\n");
|
||||
summary.append("SDK: ").append(Build.VERSION.SDK_INT).append("\n");
|
||||
summary.append("SAMPLE RATE: ").append(sampleRate).append("\n");
|
||||
summary.append("MONO BUFSIZE: ").append(monoBufferSize).append("\n");
|
||||
summary.append("STEREO BUFSIZE: ").append(stereoBufferSize).append("\n");
|
||||
summary.append("GPU VENDOR: ").append(Apple2Preferences.getJSONPref(SETTINGS.GL_VENDOR)).append("\n");
|
||||
summary.append("GPU RENDERER: ").append(Apple2Preferences.getJSONPref(SETTINGS.GL_RENDERER)).append("\n");
|
||||
summary.append("GPU VERSION: ").append(Apple2Preferences.getJSONPref(SETTINGS.GL_VERSION)).append("\n");
|
||||
|
||||
final Apple2SplashScreen splashScreen = activity.getSplashScreen();
|
||||
if (splashScreen != null) {
|
||||
splashScreen.setDismissable(false);
|
||||
}
|
||||
final ProgressBar bar = (ProgressBar) activity.findViewById(R.id.crash_progressBar);
|
||||
try {
|
||||
bar.setVisibility(View.VISIBLE);
|
||||
} catch (NullPointerException npe) {
|
||||
/* could happen on early lifecycle crashes */
|
||||
PackageInfo pInfo = activity.getPackageManager().getPackageInfo(activity.getPackageName(), 0);
|
||||
summary.append("APP VERSION: ").append(pInfo.versionName).append("\n");
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
// ...
|
||||
}
|
||||
|
||||
new Thread(new Runnable() {
|
||||
File[] nativeCrashes = _nativeCrashFiles(activity);
|
||||
if (nativeCrashes == null) {
|
||||
nativeCrashes = new File[0];
|
||||
}
|
||||
|
||||
final int len = nativeCrashes.length + 1/* maybe Java crash */ + 1/* exposeSymbols */;
|
||||
|
||||
activity.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (bar != null) {
|
||||
bar.setMax(len);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_BACKGROUND);
|
||||
if (nativeCrashes.length > 0) {
|
||||
Apple2Utils.exposeSymbols(activity);
|
||||
}
|
||||
|
||||
final int sampleRate = DevicePropertyCalculator.getRecommendedSampleRate(activity);
|
||||
final int monoBufferSize = DevicePropertyCalculator.getRecommendedBufferSize(activity, /*isStereo:*/false);
|
||||
final int stereoBufferSize = DevicePropertyCalculator.getRecommendedBufferSize(activity, /*isStereo:*/true);
|
||||
activity.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (bar != null) {
|
||||
bar.setProgress(1);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
StringBuilder summary = new StringBuilder();
|
||||
StringBuilder allCrashData = new StringBuilder();
|
||||
// iteratively process native crashes
|
||||
ArrayList<File> allCrashFiles = new ArrayList<File>();
|
||||
if (nativeCrashes.length > 0) {
|
||||
for (File crash : nativeCrashes) {
|
||||
|
||||
// prepend information about this device
|
||||
summary.append("BRAND: ").append(Build.BRAND).append("\n");
|
||||
summary.append("MODEL: ").append(Build.MODEL).append("\n");
|
||||
summary.append("MANUFACTURER: ").append(Build.MANUFACTURER).append("\n");
|
||||
summary.append("DEVICE: ").append(Build.DEVICE).append("\n");
|
||||
summary.append("SDK: ").append(Build.VERSION.SDK_INT).append("\n");
|
||||
summary.append("SAMPLE RATE: ").append(sampleRate).append("\n");
|
||||
summary.append("MONO BUFSIZE: ").append(monoBufferSize).append("\n");
|
||||
summary.append("STEREO BUFSIZE: ").append(stereoBufferSize).append("\n");
|
||||
summary.append("GPU VENDOR: ").append(Apple2Preferences.getJSONPref(SETTINGS.GL_VENDOR)).append("\n");
|
||||
summary.append("GPU RENDERER: ").append(Apple2Preferences.getJSONPref(SETTINGS.GL_RENDERER)).append("\n");
|
||||
summary.append("GPU VERSION: ").append(Apple2Preferences.getJSONPref(SETTINGS.GL_VERSION)).append("\n");
|
||||
String crashPath = crash.getAbsolutePath();
|
||||
Apple2Activity.logMessage(Apple2Activity.LogType.DEBUG, TAG, "Processing crash : " + crashPath);
|
||||
|
||||
String processedPath = _dumpPath2ProcessedPath(crashPath);
|
||||
try {
|
||||
PackageInfo pInfo = activity.getPackageManager().getPackageInfo(activity.getPackageName(), 0);
|
||||
summary.append("APP VERSION: ").append(pInfo.versionName).append("\n");
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
// ...
|
||||
nativeProcessCrash(crashPath, processedPath); // Run Breakpad minidump_stackwalk
|
||||
} catch (UnsatisfiedLinkError ule) {
|
||||
/* could happen on early lifecycle crashes */
|
||||
}
|
||||
|
||||
allCrashData.append(summary);
|
||||
|
||||
File[] nativeCrashes = _nativeCrashFiles(activity);
|
||||
if (nativeCrashes == null) {
|
||||
nativeCrashes = new File[0];
|
||||
}
|
||||
|
||||
final int len = nativeCrashes.length + 1/* maybe Java crash */ + 1/* exposeSymbols */;
|
||||
|
||||
activity.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (bar != null) {
|
||||
bar.setMax(len);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (len > 0) {
|
||||
Apple2Utils.exposeSymbols(activity);
|
||||
}
|
||||
|
||||
activity.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (bar != null) {
|
||||
bar.setProgress(1);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
boolean summarizedHeader = false;
|
||||
|
||||
// iteratively process native crashes
|
||||
for (File crash : nativeCrashes) {
|
||||
|
||||
String crashPath = crash.getAbsolutePath();
|
||||
Log.d(TAG, "Processing crash : " + crashPath);
|
||||
|
||||
String processedPath = _dumpPath2ProcessedPath(crashPath);
|
||||
try {
|
||||
nativeProcessCrash(crashPath, processedPath); // Run Breakpad minidump_stackwalk
|
||||
} catch (UnsatisfiedLinkError ule) {
|
||||
/* could happen on early lifecycle crashes */
|
||||
}
|
||||
|
||||
StringBuilder crashData = new StringBuilder();
|
||||
if (!Apple2Utils.readEntireFile(new File(processedPath), crashData)) {
|
||||
Log.e(TAG, "Error processing crash : " + crashPath);
|
||||
}
|
||||
allCrashData.append(">>>>>>> NATIVE CRASH [").append(crashPath).append("]\n");
|
||||
allCrashData.append(crashData);
|
||||
summary.append("NATIVE CRASH:\n");
|
||||
|
||||
// append succinct information about crashing thread
|
||||
String[] lines = crashData.toString().split("[\\n\\r][\\n\\r]*");
|
||||
for (int i = 0, j = 0; i < lines.length; i++) {
|
||||
|
||||
// 2 lines of minidump summary
|
||||
if (i < 2) {
|
||||
if (!summarizedHeader) {
|
||||
summary.append(lines[i]);
|
||||
summary.append("\n");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// 1 line of crashing thread and reason
|
||||
if (i == 2) {
|
||||
summarizedHeader = true;
|
||||
summary.append(lines[i]);
|
||||
summary.append("\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
// whole lotta modules
|
||||
if (lines[i].startsWith("Module")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// one apparently empty line
|
||||
if (lines[i].matches("^[ \\t]*$")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// append crashing thread backtrace
|
||||
|
||||
summary.append(lines[i]);
|
||||
summary.append("\n");
|
||||
final int maxSummaryBacktrace = 8;
|
||||
if (j++ >= maxSummaryBacktrace) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
activity.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (bar != null) {
|
||||
bar.setProgress(bar.getProgress() + 1);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
StringBuilder javaCrashData = new StringBuilder();
|
||||
File javaCrashFile = _javaCrashFile(activity);
|
||||
if (javaCrashFile.exists()) {
|
||||
Log.d(TAG, "Reading java crashes file");
|
||||
if (!Apple2Utils.readEntireFile(javaCrashFile, javaCrashData)) {
|
||||
Log.e(TAG, "Error processing java crash : " + javaCrashFileName);
|
||||
}
|
||||
}
|
||||
|
||||
allCrashData.append(">>>>>>> JAVA CRASH DATA\n");
|
||||
allCrashData.append(javaCrashData);
|
||||
|
||||
summary.append("JAVA CRASH:\n");
|
||||
summary.append(javaCrashData);
|
||||
allCrashFiles.add(new File(processedPath));
|
||||
|
||||
activity.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
|
@ -430,43 +334,85 @@ public class Apple2CrashHandler {
|
|||
}
|
||||
}
|
||||
});
|
||||
|
||||
StringBuilder jsonData = new StringBuilder();
|
||||
if (Apple2Utils.readEntireFile(new File(homeDir, Apple2Preferences.PREFS_FILE), jsonData)) {
|
||||
JSONObject obj = null;
|
||||
try {
|
||||
obj = new JSONObject(jsonData.toString());
|
||||
} catch (JSONException e) {
|
||||
Log.e(TAG, "Error reading preferences : " + e);
|
||||
}
|
||||
if (obj != null) {
|
||||
summary.append("PREFS:\n");
|
||||
summary.append(obj.toString());
|
||||
allCrashData.append(">>>>>>> PREFS\n");
|
||||
allCrashData.append(obj.toString());
|
||||
}
|
||||
}
|
||||
|
||||
Apple2Utils.unexposeSymbols(activity);
|
||||
activity.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
bar.setVisibility(View.INVISIBLE);
|
||||
splashScreen.setDismissable(true);
|
||||
} catch (NullPointerException npe) {
|
||||
/* could happen on early lifecycle crashes */
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// send report with all the data
|
||||
_sendEmailToDeveloperWithCrashData(activity, summary, allCrashData);
|
||||
}
|
||||
}).start();
|
||||
summary.append("" + nativeCrashes.length + " Native dumps\n");
|
||||
}
|
||||
|
||||
File javaCrashFile = _javaCrashFile(activity);
|
||||
if (javaCrashFile.exists()) {
|
||||
summary.append("Java crash log\n");
|
||||
allCrashFiles.add(javaCrashFile);
|
||||
}
|
||||
|
||||
activity.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (bar != null) {
|
||||
bar.setProgress(bar.getProgress() + 1);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
allCrashFiles.add(new File(homeDir, Apple2Preferences.PREFS_FILE));
|
||||
|
||||
if (nativeCrashes.length > 0) {
|
||||
Apple2Utils.unexposeSymbols(activity);
|
||||
}
|
||||
|
||||
activity.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
bar.setVisibility(View.INVISIBLE);
|
||||
splashScreen.setDismissable(true);
|
||||
} catch (NullPointerException npe) {
|
||||
/* email logs doesn't show the splash screen */
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Add all the log files ...
|
||||
{
|
||||
File[] nativeLogs = _nativeLogs(activity);
|
||||
for (File logFile : nativeLogs) {
|
||||
allCrashFiles.add(logFile);
|
||||
}
|
||||
}
|
||||
|
||||
File[] allCrashesAry = new File[allCrashFiles.size()];
|
||||
File nativeCrashesZip = Apple2Utils.zipFiles(allCrashFiles.toArray(allCrashesAry), _getCrashLogFile(activity));
|
||||
// send report with all the data
|
||||
_sendEmailToDeveloperWithCrashData(activity, summary, nativeCrashesZip);
|
||||
}
|
||||
}).create();
|
||||
activity.registerAndShowDialog(crashDialog);
|
||||
}).start();
|
||||
}
|
||||
|
||||
public void cleanCrashData(Apple2Activity activity) {
|
||||
|
||||
Apple2Activity.logMessage(Apple2Activity.LogType.DEBUG, TAG, "Cleaning up crash data ...");
|
||||
File[] nativeCrashes = _nativeCrashFiles(activity);
|
||||
for (File crash : nativeCrashes) {
|
||||
|
||||
if (!crash.delete()) {
|
||||
Apple2Activity.logMessage(Apple2Activity.LogType.DEBUG, TAG, "Could not unlink crash : " + crash);
|
||||
}
|
||||
|
||||
File processed = new File(_dumpPath2ProcessedPath(crash.getAbsolutePath()));
|
||||
if (!processed.delete()) {
|
||||
Apple2Activity.logMessage(Apple2Activity.LogType.DEBUG, TAG, "Could not unlink processed : " + processed);
|
||||
}
|
||||
}
|
||||
|
||||
File javaCrashFile = _javaCrashFile(activity);
|
||||
if (!javaCrashFile.delete()) {
|
||||
Apple2Activity.logMessage(Apple2Activity.LogType.DEBUG, TAG, "Could not unlink java crash : " + javaCrashFile);
|
||||
}
|
||||
|
||||
/* HACK NOTE -- don't delete the crash log file here ... possibly the email sender program still needs the link!
|
||||
File allCrashFile = _getCrashLogFile(activity);
|
||||
Apple2Utils.writeFile(new StringBuilder(), allCrashFile);
|
||||
allCrashFile.delete();
|
||||
*/
|
||||
}
|
||||
|
||||
public void performCrash(int crashType) {
|
||||
|
@ -511,7 +457,7 @@ public class Apple2CrashHandler {
|
|||
} catch (InterruptedIOException ie) {
|
||||
/* EINTR, EAGAIN ... */
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Exception attempting to write data : " + e);
|
||||
Apple2Activity.logMessage(Apple2Activity.LogType.ERROR, TAG, "Exception attempting to write data : " + e);
|
||||
}
|
||||
|
||||
try {
|
||||
|
@ -527,6 +473,21 @@ public class Apple2CrashHandler {
|
|||
return new File(homeDir, javaCrashFileName);
|
||||
}
|
||||
|
||||
private File[] _nativeLogs(Apple2Activity activity) {
|
||||
FilenameFilter logFilter = new FilenameFilter() {
|
||||
public boolean accept(File dir, String name) {
|
||||
File file = new File(dir, name);
|
||||
if (file.isDirectory()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return name.startsWith("apple2ix_log");
|
||||
}
|
||||
};
|
||||
|
||||
return new File(homeDir).listFiles(logFilter);
|
||||
}
|
||||
|
||||
private File[] _nativeCrashFiles(Apple2Activity activity) {
|
||||
FilenameFilter dmpFilter = new FilenameFilter() {
|
||||
public boolean accept(File dir, String name) {
|
||||
|
@ -556,59 +517,57 @@ public class Apple2CrashHandler {
|
|||
return crashPath.substring(0, crashPath.length() - 4) + ".txt";
|
||||
}
|
||||
|
||||
private File _getCrashFile(Apple2Activity activity) {
|
||||
File allCrashFile;
|
||||
private File _getCrashLogFile(Apple2Activity activity) {
|
||||
File file;
|
||||
String storageState = Environment.getExternalStorageState();
|
||||
if (storageState.equals(Environment.MEDIA_MOUNTED)) {
|
||||
allCrashFile = new File(Environment.getExternalStorageDirectory(), "apple2ix_crash.txt");
|
||||
file = new File(Environment.getExternalStorageDirectory(), ALL_CRASH_FILE);
|
||||
} else {
|
||||
allCrashFile = new File(Apple2Utils.getDataDir(activity), "apple2ix_crash.txt");
|
||||
file = new File(Apple2Utils.getDataDir(activity), ALL_CRASH_FILE);
|
||||
}
|
||||
Log.d(TAG, "Writing all crashes to temp file : " + allCrashFile.getAbsolutePath());
|
||||
return allCrashFile;
|
||||
return file;
|
||||
}
|
||||
|
||||
private void _sendEmailToDeveloperWithCrashData(Apple2Activity activity, StringBuilder summary, StringBuilder allCrashData) {
|
||||
mAlreadySentReport.set(true);
|
||||
private void _sendEmailToDeveloperWithCrashData(Apple2Activity activity, StringBuilder summary, File nativeCrashesZip) {
|
||||
final boolean alreadyChoosing = Apple2EmailerActivity.sEmailerIsEmailing.getAndSet(true);
|
||||
if (alreadyChoosing) {
|
||||
return;
|
||||
}
|
||||
|
||||
// <sigh> ... the disaster that is early Android ... there does not appear to be a reliable way to start an
|
||||
// email Intent to send both text and an attachment, but we make a valiant (if futile) effort to do so here.
|
||||
// And the reason to send an attachment is that you trigger an android.os.TransactionTooLargeException with too
|
||||
// much text data in the EXTRA_TEXT ... </sigh>
|
||||
|
||||
Intent emailIntent = new Intent(Intent.ACTION_SENDTO, Uri.fromParts("mailto", "apple2ix_crash@deadcode.org"/*non-zero variant is correct endpoint at the moment*/, null));
|
||||
emailIntent.putExtra(Intent.EXTRA_SUBJECT, "Crasher");
|
||||
Intent emailIntent = new Intent(activity, Apple2EmailerActivity.class);
|
||||
emailIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK/* | Intent.FLAG_ACTIVITY_CLEAR_TOP */);
|
||||
|
||||
final int maxCharsEmail = 4096;
|
||||
int len = summary.length();
|
||||
len = len < maxCharsEmail ? len : maxCharsEmail;
|
||||
String summaryData = summary.substring(0, len);
|
||||
emailIntent.putExtra(Intent.EXTRA_TEXT, "The app crashed, please help!\n\n" + summaryData);
|
||||
emailIntent.putExtra(Intent.EXTRA_TEXT, "A2IX app logs and crash data\n\n" + summaryData);
|
||||
|
||||
File allCrashFile = _getCrashFile(activity);
|
||||
Apple2Utils.writeFile(allCrashData, allCrashFile);
|
||||
if (!allCrashFile.setReadable(true, /*ownerOnly:*/false)) {
|
||||
Log.d(TAG, "Oops, could not set file data readable!");
|
||||
if (!nativeCrashesZip.setReadable(true, /*ownerOnly:*/false)) {
|
||||
Apple2Activity.logMessage(Apple2Activity.LogType.DEBUG, TAG, "Oops, could not set crash file data readable!");
|
||||
}
|
||||
|
||||
emailIntent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(allCrashFile));
|
||||
emailIntent.putExtra(Apple2EmailerActivity.EXTRA_STREAM_PATH, nativeCrashesZip.getAbsolutePath());
|
||||
|
||||
Log.d(TAG, "STARTING CHOOSER FOR EMAIL ...");
|
||||
activity.startActivity(Intent.createChooser(emailIntent, "Send email"));
|
||||
Log.d(TAG, "AFTER START ACTIVITY ...");
|
||||
Apple2Activity.logMessage(Apple2Activity.LogType.DEBUG, TAG, "STARTING EMAILER ACTIVITY ...");
|
||||
Apple2EmailerActivity.sEmailerCallback = activity;
|
||||
|
||||
activity.startActivityForResult(emailIntent, Apple2EmailerActivity.SEND_REQUEST_CODE);
|
||||
}
|
||||
|
||||
|
||||
private final static String TAG = "Apple2CrashHandler";
|
||||
private final static Apple2CrashHandler sCrashHandler = new Apple2CrashHandler();
|
||||
|
||||
private String homeDir;
|
||||
private Thread.UncaughtExceptionHandler mDefaultExceptionHandler;
|
||||
private AtomicBoolean mAlreadyRanCrashCheck = new AtomicBoolean(false);
|
||||
private AtomicBoolean mAlreadySentReport = new AtomicBoolean(false);
|
||||
|
||||
private static native void nativePerformCrash(int crashType); // testing
|
||||
|
||||
private static native void nativeProcessCrash(String crashFilePath, String crashProcessedPath);
|
||||
|
||||
}
|
||||
|
|
|
@ -11,21 +11,23 @@
|
|||
|
||||
package org.deadc0de.apple2ix;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.provider.DocumentsContract;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.util.Log;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import android.provider.OpenableColumns;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
public class Apple2DiskChooserActivity extends Activity {
|
||||
public class Apple2DiskChooserActivity extends AppCompatActivity {
|
||||
|
||||
public static final AtomicBoolean sDiskChooserIsChoosing = new AtomicBoolean(false);
|
||||
public static Callback sDisksCallback;
|
||||
|
@ -52,15 +54,44 @@ public class Apple2DiskChooserActivity extends Activity {
|
|||
resolver.takePersistableUriPermission(uri, (Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION));
|
||||
pfd = resolver.openFileDescriptor(uri, "rw");
|
||||
} catch (Throwable t) {
|
||||
Log.e(TAG, "OOPS, could not get appropriate access to URI ( " + uri + " ) : " + t);
|
||||
Apple2Activity.logMessage(Apple2Activity.LogType.ERROR, TAG, "OOPS, could not get appropriate access to URI ( " + uri + " ) : " + t);
|
||||
}
|
||||
|
||||
return pfd;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static String getFileNameFromUri(Context ctx, Uri uri) {
|
||||
|
||||
String fileName = null;
|
||||
|
||||
try {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
|
||||
throw new RuntimeException("SDK Version not allowed access");
|
||||
}
|
||||
|
||||
if (!DocumentsContract.isDocumentUri(ctx, uri)) {
|
||||
throw new RuntimeException("Not a Document URI for " + uri);
|
||||
}
|
||||
|
||||
ContentResolver resolver = ctx.getContentResolver();
|
||||
|
||||
Cursor returnCursor = resolver.query(uri, null, null, null, null);
|
||||
int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
|
||||
returnCursor.moveToFirst();
|
||||
fileName = returnCursor.getString(nameIndex);
|
||||
|
||||
} catch (Throwable t) {
|
||||
Apple2Activity.logMessage(Apple2Activity.LogType.ERROR, TAG, "OOPS, could not get filename from URI ( " + uri + " ) : " + t);
|
||||
}
|
||||
|
||||
return fileName;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSaveInstanceState(Bundle outState) {
|
||||
outState.putBoolean("ran", true);
|
||||
super.onSaveInstanceState(outState);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -85,13 +116,14 @@ public class Apple2DiskChooserActivity extends Activity {
|
|||
}
|
||||
|
||||
boolean ran = b.getBoolean("ran");
|
||||
/* -- Android onCreate() can be called multiple times, for example, on an orientation change ... this codepath was aborting the disk selection process when an orientation event occurred...
|
||||
if (ran) {
|
||||
Log.e(TAG, "OOPS, already ran...");
|
||||
Apple2Activity.logMessage(Apple2Activity.LogType.ERROR, TAG, "OOPS, already ran...");
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
*/
|
||||
|
||||
////Intent pickIntent = new Intent(Intent.ACTION_GET_CONTENT);
|
||||
Intent pickIntent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
|
||||
|
||||
try {
|
||||
|
@ -107,7 +139,7 @@ public class Apple2DiskChooserActivity extends Activity {
|
|||
startActivityForResult(pickIntent, EDIT_REQUEST_CODE);
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
Log.e(TAG, "OOPS : " + t);
|
||||
Apple2Activity.logMessage(Apple2Activity.LogType.ERROR, TAG, "OOPS : " + t);
|
||||
setResult(RESULT_CANCELED);
|
||||
finish();
|
||||
}
|
||||
|
@ -142,6 +174,7 @@ public class Apple2DiskChooserActivity extends Activity {
|
|||
|
||||
if (chosenUri != null) {
|
||||
chosenPfd = openFileDescriptorFromUri(this, chosenUri);
|
||||
chosenFileName = getFileNameFromUri(this, chosenUri);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -157,8 +190,10 @@ public class Apple2DiskChooserActivity extends Activity {
|
|||
@Override
|
||||
public void finish() {
|
||||
sDiskChooserIsChoosing.set(false);
|
||||
String name = chosenUri == null ? "" : chosenUri.toString();
|
||||
sDisksCallback.onDisksChosen(new DiskArgs(name, chosenUri, chosenPfd));
|
||||
String name = chosenFileName == null ? (chosenUri == null ? "" : chosenUri.toString()) : chosenFileName;
|
||||
if (sDisksCallback != null) {
|
||||
sDisksCallback.onDisksChosen(new DiskArgs(name, chosenUri, chosenPfd));
|
||||
}
|
||||
super.finish();
|
||||
}
|
||||
|
||||
|
@ -166,6 +201,8 @@ public class Apple2DiskChooserActivity extends Activity {
|
|||
|
||||
private ParcelFileDescriptor chosenPfd;
|
||||
|
||||
private String chosenFileName;
|
||||
|
||||
private static final String TAG = "A2DiskChooserActivity";
|
||||
|
||||
private static final int EDIT_REQUEST_CODE = 44;
|
||||
|
|
|
@ -11,13 +11,13 @@
|
|||
|
||||
package org.deadc0de.apple2ix;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
|
@ -34,8 +34,10 @@ import android.widget.RadioButton;
|
|||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import org.deadc0de.apple2ix.basic.R;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FilenameFilter;
|
||||
|
@ -43,9 +45,6 @@ import java.io.IOException;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.deadc0de.apple2ix.basic.R;
|
||||
import org.json.JSONObject;
|
||||
|
||||
public class Apple2DisksMenu implements Apple2MenuView {
|
||||
|
||||
private final static String TAG = "Apple2DisksMenu";
|
||||
|
@ -94,7 +93,7 @@ public class Apple2DisksMenu implements Apple2MenuView {
|
|||
|
||||
@Override
|
||||
public Object getPrefDefault() {
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
},
|
||||
CURRENT_DISK_PATH_A {
|
||||
|
@ -116,7 +115,7 @@ public class Apple2DisksMenu implements Apple2MenuView {
|
|||
|
||||
@Override
|
||||
public Object getPrefDefault() {
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
},
|
||||
CURRENT_DISK_PATH_B {
|
||||
|
@ -138,7 +137,7 @@ public class Apple2DisksMenu implements Apple2MenuView {
|
|||
|
||||
@Override
|
||||
public Object getPrefDefault() {
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
},
|
||||
USE_NEWSCHOOL_DISK_SELECTION {
|
||||
|
@ -370,7 +369,7 @@ public class Apple2DisksMenu implements Apple2MenuView {
|
|||
try {
|
||||
diskArgs.pfd.close();
|
||||
} catch (IOException ioe) {
|
||||
Log.e(TAG, "Error attempting to close PFD : " + ioe);
|
||||
Apple2Activity.logMessage(Apple2Activity.LogType.ERROR, TAG, "Error attempting to close PFD : " + ioe);
|
||||
}
|
||||
}
|
||||
diskArgs.pfd = null;
|
||||
|
@ -382,7 +381,7 @@ public class Apple2DisksMenu implements Apple2MenuView {
|
|||
}
|
||||
|
||||
} catch (Throwable t) {
|
||||
Log.d(TAG, "OOPS: " + t);
|
||||
Apple2Activity.logMessage(Apple2Activity.LogType.DEBUG, TAG, "OOPS: " + t);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -429,12 +428,6 @@ public class Apple2DisksMenu implements Apple2MenuView {
|
|||
final RadioButton readWrite = (RadioButton) diskConfirmationView.findViewById(R.id.radioButton_readWrite);
|
||||
readWrite.setChecked(!roChecked);
|
||||
|
||||
builder.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
dialog.dismiss();
|
||||
}
|
||||
});
|
||||
builder.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
|
@ -571,6 +564,10 @@ public class Apple2DisksMenu implements Apple2MenuView {
|
|||
break;
|
||||
}
|
||||
|
||||
if (diskPath.startsWith(Apple2DisksMenu.EXTERNAL_CHOOSER_SENTINEL)) {
|
||||
diskPath = diskPath.substring(Apple2DisksMenu.EXTERNAL_CHOOSER_SENTINEL.length());
|
||||
}
|
||||
|
||||
Uri uri = Uri.parse(diskPath);
|
||||
if (uri == null) {
|
||||
break;
|
||||
|
@ -582,7 +579,7 @@ public class Apple2DisksMenu implements Apple2MenuView {
|
|||
break;
|
||||
}
|
||||
|
||||
imageName = diskPath.substring(idx + 1);
|
||||
imageName = Apple2DiskChooserActivity.getFileNameFromUri(mActivity, uri);
|
||||
} while (false);
|
||||
|
||||
LinearLayout layout = (LinearLayout) mDisksView.findViewById((i == 0) ? R.id.a2_newschool_driveA_layout : R.id.a2_newschool_driveB_layout);
|
||||
|
@ -742,7 +739,7 @@ public class Apple2DisksMenu implements Apple2MenuView {
|
|||
@Override
|
||||
public void onItemClick(AdapterView<?> parent, View view, final int position, long id) {
|
||||
if (isDirectory[position]) {
|
||||
Log.d(TAG, "Descending to path : " + filePaths[position]);
|
||||
Apple2Activity.logMessage(Apple2Activity.LogType.DEBUG, TAG, "Descending to path : " + filePaths[position]);
|
||||
if (parentIsRootPath && !new File(filePaths[position]).isAbsolute()) {
|
||||
pushPathStack(parentDisksDir + File.separator + filePaths[position]);
|
||||
} else {
|
||||
|
|
|
@ -0,0 +1,143 @@
|
|||
/*
|
||||
* Apple // emulator for *nix
|
||||
*
|
||||
* This software package is subject to the GNU General Public License
|
||||
* version 3 or later (your choice) as published by the Free Software
|
||||
* Foundation.
|
||||
*
|
||||
* Copyright 2019 Aaron Culliney
|
||||
*
|
||||
*/
|
||||
|
||||
package org.deadc0de.apple2ix;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.media.MediaScannerConnection;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
public class Apple2EmailerActivity extends AppCompatActivity {
|
||||
|
||||
public static final String EXTRA_STREAM_PATH = Intent.EXTRA_STREAM + "-PATH";
|
||||
|
||||
public static final int SEND_REQUEST_CODE = 46;
|
||||
|
||||
public static final AtomicBoolean sEmailerIsEmailing = new AtomicBoolean(false);
|
||||
public static Callback sEmailerCallback;
|
||||
|
||||
public interface Callback {
|
||||
void onEmailerFinished();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRestoreInstanceState(Bundle inState) {
|
||||
super.onRestoreInstanceState(inState);
|
||||
mExtraText = inState.getString(Intent.EXTRA_TEXT);
|
||||
mExtraStreamPath = inState.getString(EXTRA_STREAM_PATH);
|
||||
mExtraStream = inState.getParcelable(Intent.EXTRA_STREAM);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSaveInstanceState(Bundle outState) {
|
||||
outState.putBoolean("ran", true);
|
||||
outState.putString(Intent.EXTRA_TEXT, mExtraText);
|
||||
outState.putString(EXTRA_STREAM_PATH, mExtraStreamPath);
|
||||
outState.putParcelable(Intent.EXTRA_STREAM, mExtraStream);
|
||||
super.onSaveInstanceState(outState);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedState) {
|
||||
super.onCreate(savedState);
|
||||
|
||||
Bundle b;
|
||||
{
|
||||
Intent intent = getIntent();
|
||||
Bundle extras = null;
|
||||
if (intent != null) {
|
||||
extras = intent.getExtras();
|
||||
}
|
||||
|
||||
if (savedState != null) {
|
||||
b = savedState;
|
||||
} else if (extras != null) {
|
||||
b = extras;
|
||||
} else {
|
||||
b = new Bundle();
|
||||
}
|
||||
}
|
||||
|
||||
final boolean ran = b.getBoolean("ran");
|
||||
mExtraText = b.getString(Intent.EXTRA_TEXT);
|
||||
mExtraStreamPath = b.getString(EXTRA_STREAM_PATH);
|
||||
|
||||
MediaScannerConnection.scanFile(this,
|
||||
/*paths:*/new String[] { mExtraStreamPath },
|
||||
/*mimeTypes:*/new String[] { "application/zip" },
|
||||
new MediaScannerConnection.OnScanCompletedListener() {
|
||||
public void onScanCompleted(String path, Uri uri) {
|
||||
|
||||
mExtraStream = uri;
|
||||
Intent emailIntent = new Intent(Intent.ACTION_SEND);
|
||||
|
||||
try {
|
||||
emailIntent.putExtra(Intent.EXTRA_EMAIL, new String[] { "apple2ix_crash@deadcode.org" });
|
||||
emailIntent.putExtra(Intent.EXTRA_SUBJECT, "A2IX Report To apple2ix_crash@deadcode.org");
|
||||
emailIntent.putExtra(Intent.EXTRA_TEXT, mExtraText);
|
||||
emailIntent.putExtra(Intent.EXTRA_STREAM, mExtraStream);
|
||||
emailIntent.setType("message/rfc822");
|
||||
|
||||
if (!ran) {
|
||||
Apple2Activity.logMessage(Apple2Activity.LogType.DEBUG, TAG, "STARTING EMAIL ACTIVITY ...");
|
||||
startActivityForResult(emailIntent, SEND_REQUEST_CODE);
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
Apple2Activity.logMessage(Apple2Activity.LogType.ERROR, TAG, "OOPS : " + t);
|
||||
setResult(RESULT_CANCELED);
|
||||
finish();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
|
||||
if (resultCode != RESULT_CANCELED) {
|
||||
// Do something?
|
||||
}
|
||||
|
||||
if (mExtraStream != null) {
|
||||
int deleted = getContentResolver().delete(mExtraStream, null, null);
|
||||
}
|
||||
|
||||
sEmailerCallback.onEmailerFinished();
|
||||
|
||||
setResult(RESULT_OK);
|
||||
finish();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finish() {
|
||||
sEmailerIsEmailing.set(false);
|
||||
super.finish();
|
||||
}
|
||||
|
||||
private String mExtraText;
|
||||
|
||||
private String mExtraStreamPath;
|
||||
|
||||
private Uri mExtraStream;
|
||||
|
||||
private static final String TAG = "A2EmailerActivity";
|
||||
}
|
|
@ -12,9 +12,11 @@
|
|||
package org.deadc0de.apple2ix;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.SeekBar;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.deadc0de.apple2ix.basic.R;
|
||||
|
||||
|
@ -22,18 +24,47 @@ import java.util.ArrayList;
|
|||
|
||||
public class Apple2JoystickCalibration implements Apple2MenuView {
|
||||
|
||||
private final static String TAG = "Apple2JoystickCalibration";
|
||||
private final static String TAG = "apple2ix-js-calibrate";
|
||||
|
||||
public final static int JOYSTICK_DIVIDER_NUM_CHOICES = Apple2Preferences.DECENT_AMOUNT_OF_CHOICES;
|
||||
public final static String PREF_SCREEN_DIVISION = "screenDivider";
|
||||
|
||||
private static native long nativePollJoystick();
|
||||
|
||||
private Apple2Activity mActivity = null;
|
||||
private View mSettingsView = null;
|
||||
private ArrayList<Apple2MenuView> mViewStack = null;
|
||||
private boolean mTouchMenuEnabled = false;
|
||||
private int mSavedTouchDevice = Apple2SettingsMenu.TouchDeviceVariant.NONE.ordinal();
|
||||
private Thread joystickPollerThread = null;
|
||||
|
||||
public Apple2JoystickCalibration(Apple2Activity activity, ArrayList<Apple2MenuView> viewStack, Apple2SettingsMenu.TouchDeviceVariant variant) {
|
||||
public static void startCalibration(Apple2Activity activity, Apple2SettingsMenu.TouchDeviceVariant variant) {
|
||||
|
||||
ArrayList<Apple2MenuView> viewStack = new ArrayList<Apple2MenuView>();
|
||||
{
|
||||
int idx = 0;
|
||||
while (true) {
|
||||
Apple2MenuView apple2MenuView = activity.peekApple2View(idx);
|
||||
if (apple2MenuView == null) {
|
||||
break;
|
||||
}
|
||||
viewStack.add(apple2MenuView);
|
||||
++idx;
|
||||
}
|
||||
}
|
||||
|
||||
Apple2JoystickCalibration calibration = new Apple2JoystickCalibration(activity, viewStack, variant);
|
||||
|
||||
// show this new view...
|
||||
calibration.show();
|
||||
|
||||
// ...with nothing else underneath 'cept the emulator OpenGL layer
|
||||
for (Apple2MenuView apple2MenuView : viewStack) {
|
||||
activity.popApple2View(apple2MenuView);
|
||||
}
|
||||
}
|
||||
|
||||
private Apple2JoystickCalibration(Apple2Activity activity, ArrayList<Apple2MenuView> viewStack, Apple2SettingsMenu.TouchDeviceVariant variant) {
|
||||
mActivity = activity;
|
||||
mViewStack = viewStack;
|
||||
if (!(variant == Apple2SettingsMenu.TouchDeviceVariant.JOYSTICK || variant == Apple2SettingsMenu.TouchDeviceVariant.JOYSTICK_KEYPAD)) {
|
||||
|
@ -43,7 +74,7 @@ public class Apple2JoystickCalibration implements Apple2MenuView {
|
|||
setup(variant);
|
||||
}
|
||||
|
||||
private void setup(Apple2SettingsMenu.TouchDeviceVariant variant) {
|
||||
private void setup(final Apple2SettingsMenu.TouchDeviceVariant variant) {
|
||||
LayoutInflater inflater = (LayoutInflater) mActivity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
mSettingsView = inflater.inflate(R.layout.activity_calibrate_joystick, null, false);
|
||||
|
||||
|
@ -72,6 +103,48 @@ public class Apple2JoystickCalibration implements Apple2MenuView {
|
|||
float val = Apple2Preferences.getFloatJSONPref(Apple2Preferences.PREF_DOMAIN_JOYSTICK, PREF_SCREEN_DIVISION, (JOYSTICK_DIVIDER_NUM_CHOICES >> 1) / (float) JOYSTICK_DIVIDER_NUM_CHOICES);
|
||||
sb.setProgress((int) (val * JOYSTICK_DIVIDER_NUM_CHOICES));
|
||||
|
||||
final TextView axisCoords = (TextView) mSettingsView.findViewById(R.id.axisCoords);
|
||||
|
||||
joystickPollerThread = new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
Apple2Activity.logMessage(Apple2Activity.LogType.INFO, TAG, "Starting joystick poll thread...");
|
||||
try {
|
||||
while (true) {
|
||||
long cxy = nativePollJoystick();
|
||||
|
||||
String t = "";
|
||||
if (variant == Apple2SettingsMenu.TouchDeviceVariant.JOYSTICK) {
|
||||
final int x = ((int) (cxy & 0xFF00) >> 8) - 128;
|
||||
final int y = ((int) (cxy & 0x00FF) >> 0) - 128;
|
||||
t = "X: " + x + " Y: " + y;
|
||||
} else {
|
||||
char ascii = (char) ((cxy & 0xFF000000) >> 24);
|
||||
int scancode = (char) ((cxy & 0x00FF0000) >> 16);
|
||||
|
||||
if (ascii == Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION || scancode == 0) {
|
||||
// ...
|
||||
} else {
|
||||
t = "Key: " + Apple2KeypadChooser.asciiRepresentation(mActivity, ascii);
|
||||
}
|
||||
}
|
||||
|
||||
final String axisText = t;
|
||||
mActivity.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
axisCoords.setText(axisText);
|
||||
}
|
||||
});
|
||||
Thread.sleep(100);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Apple2Activity.logMessage(Apple2Activity.LogType.INFO, TAG, "Stopping joystick poll thread...");
|
||||
}
|
||||
}
|
||||
};
|
||||
joystickPollerThread.start();
|
||||
|
||||
mTouchMenuEnabled = (boolean) Apple2Preferences.getJSONPref(Apple2KeyboardSettingsMenu.SETTINGS.TOUCH_MENU_ENABLED);
|
||||
Apple2Preferences.setJSONPref(Apple2KeyboardSettingsMenu.SETTINGS.TOUCH_MENU_ENABLED, false);
|
||||
mSavedTouchDevice = (int) Apple2Preferences.getJSONPref(Apple2SettingsMenu.SETTINGS.CURRENT_INPUT);
|
||||
|
@ -96,6 +169,7 @@ public class Apple2JoystickCalibration implements Apple2MenuView {
|
|||
}
|
||||
|
||||
public void dismiss() {
|
||||
joystickPollerThread.interrupt();
|
||||
for (Apple2MenuView apple2MenuView : mViewStack) {
|
||||
if (apple2MenuView != this) {
|
||||
mActivity.pushApple2View(apple2MenuView);
|
||||
|
|
|
@ -36,12 +36,18 @@ public class Apple2JoystickSettingsMenu extends Apple2AbstractMenu {
|
|||
public final static int JOYSTICK_AXIS_SENSITIVITY_INC_NUMCHOICES = (int) ((JOYSTICK_AXIS_SENSITIVITY_MAX - JOYSTICK_AXIS_SENSITIVITY_DEFAULT) / JOYSTICK_AXIS_SENSITIVITY_INC_STEP); // 12
|
||||
public final static int JOYSTICK_AXIS_SENSITIVITY_NUM_CHOICES = JOYSTICK_AXIS_SENSITIVITY_DEC_NUMCHOICES + JOYSTICK_AXIS_SENSITIVITY_INC_NUMCHOICES; // 15 + 12
|
||||
|
||||
public final static int TAPDELAY_NUM_CHOICES = Apple2Preferences.DECENT_AMOUNT_OF_CHOICES;
|
||||
public final static float TAPDELAY_SCALE = 0.5f;
|
||||
public final static int TAPDELAY_NUM_CHOICES = (30 + 1); // 0-30 (30Frames == ~0.5sec)
|
||||
|
||||
private Apple2SettingsMenu.TouchDeviceVariant mVariant;
|
||||
|
||||
public Apple2JoystickSettingsMenu(Apple2Activity activity) {
|
||||
public Apple2JoystickSettingsMenu(Apple2Activity activity, Apple2SettingsMenu.TouchDeviceVariant variant) {
|
||||
super(activity);
|
||||
|
||||
if (!(variant == Apple2SettingsMenu.TouchDeviceVariant.JOYSTICK || variant == Apple2SettingsMenu.TouchDeviceVariant.JOYSTICK_KEYPAD)) {
|
||||
throw new RuntimeException("You're doing it wrong");
|
||||
}
|
||||
|
||||
mVariant = variant;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -80,6 +86,33 @@ public class Apple2JoystickSettingsMenu extends Apple2AbstractMenu {
|
|||
}
|
||||
|
||||
protected enum SETTINGS implements Apple2AbstractMenu.IMenuEnum {
|
||||
JOYSTICK_CALIBRATE {
|
||||
@Override
|
||||
public final String getTitle(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.joystick_calibrate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String getSummary(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.joystick_calibrate_summary);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrefKey() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPrefDefault() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleSelection(Apple2Activity activity, Apple2AbstractMenu settingsMenu, boolean isChecked) {
|
||||
Apple2JoystickSettingsMenu thisMenu = (Apple2JoystickSettingsMenu)settingsMenu;
|
||||
Apple2JoystickCalibration.startCalibration(activity, thisMenu.mVariant);
|
||||
}
|
||||
},
|
||||
JOYSTICK_TAP_BUTTON {
|
||||
@Override
|
||||
public final String getTitle(Apple2Activity activity) {
|
||||
|
@ -227,44 +260,105 @@ public class Apple2JoystickSettingsMenu extends Apple2AbstractMenu {
|
|||
});
|
||||
}
|
||||
},
|
||||
JOYSTICK_CALIBRATE {
|
||||
JOYSTICK_SWIPELEFT_BUTTON {
|
||||
@Override
|
||||
public final String getTitle(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.joystick_calibrate);
|
||||
return activity.getResources().getString(R.string.joystick_button_swipe_left_button);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String getSummary(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.joystick_calibrate_summary);
|
||||
return activity.getResources().getString(R.string.joystick_button_swipe_left_button_summary);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleSelection(Apple2Activity activity, Apple2AbstractMenu settingsMenu, boolean isChecked) {
|
||||
ArrayList<Apple2MenuView> viewStack = new ArrayList<Apple2MenuView>();
|
||||
{
|
||||
int idx = 0;
|
||||
while (true) {
|
||||
Apple2MenuView apple2MenuView = activity.peekApple2View(idx);
|
||||
if (apple2MenuView == null) {
|
||||
break;
|
||||
}
|
||||
viewStack.add(apple2MenuView);
|
||||
++idx;
|
||||
public String getPrefKey() {
|
||||
return "jsSwipeWestChar";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPrefDefault() {
|
||||
return TouchJoystickButtons.NONE.ordinal();
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(final Apple2Activity activity, View convertView) {
|
||||
convertView = _basicView(activity, this, convertView);
|
||||
_addPopupIcon(activity, this, convertView);
|
||||
return convertView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleSelection(final Apple2Activity activity, final Apple2AbstractMenu settingsMenu, boolean isChecked) {
|
||||
final IMenuEnum self = this;
|
||||
_alertDialogHandleSelection(activity, R.string.joystick_button_swipe_left_button, new String[]{
|
||||
activity.getResources().getString(R.string.joystick_button_button_none),
|
||||
activity.getResources().getString(R.string.joystick_button_button1),
|
||||
activity.getResources().getString(R.string.joystick_button_button2),
|
||||
activity.getResources().getString(R.string.joystick_button_button_both),
|
||||
}, new IPreferenceLoadSave() {
|
||||
@Override
|
||||
public int intValue() {
|
||||
return (int) Apple2Preferences.getJSONPref(self);
|
||||
}
|
||||
}
|
||||
|
||||
Apple2JoystickCalibration calibration = new Apple2JoystickCalibration(activity, viewStack, Apple2SettingsMenu.TouchDeviceVariant.JOYSTICK);
|
||||
|
||||
// show this new view...
|
||||
calibration.show();
|
||||
|
||||
// ...with nothing else underneath 'cept the emulator OpenGL layer
|
||||
for (Apple2MenuView apple2MenuView : viewStack) {
|
||||
activity.popApple2View(apple2MenuView);
|
||||
}
|
||||
@Override
|
||||
public void saveInt(int value) {
|
||||
Apple2Preferences.setJSONPref(self, TouchJoystickButtons.values()[value].ordinal());
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
JOYSTICK_TAPDELAY {
|
||||
JOYSTICK_SWIPERIGHT_BUTTON {
|
||||
@Override
|
||||
public final String getTitle(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.joystick_button_swipe_right_button);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String getSummary(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.joystick_button_swipe_right_button_summary);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrefKey() {
|
||||
return "jsSwipeEastChar";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPrefDefault() {
|
||||
return TouchJoystickButtons.NONE.ordinal();
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(final Apple2Activity activity, View convertView) {
|
||||
convertView = _basicView(activity, this, convertView);
|
||||
_addPopupIcon(activity, this, convertView);
|
||||
return convertView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleSelection(final Apple2Activity activity, final Apple2AbstractMenu settingsMenu, boolean isChecked) {
|
||||
final IMenuEnum self = this;
|
||||
_alertDialogHandleSelection(activity, R.string.joystick_button_swipe_right_button, new String[]{
|
||||
activity.getResources().getString(R.string.joystick_button_button_none),
|
||||
activity.getResources().getString(R.string.joystick_button_button1),
|
||||
activity.getResources().getString(R.string.joystick_button_button2),
|
||||
activity.getResources().getString(R.string.joystick_button_button_both),
|
||||
}, new IPreferenceLoadSave() {
|
||||
@Override
|
||||
public int intValue() {
|
||||
return (int) Apple2Preferences.getJSONPref(self);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveInt(int value) {
|
||||
Apple2Preferences.setJSONPref(self, TouchJoystickButtons.values()[value].ordinal());
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
JOYSTICK_AXIS_SENSITIVITY {
|
||||
@Override
|
||||
public final String getTitle(Apple2Activity activity) {
|
||||
return "";
|
||||
|
@ -272,36 +366,55 @@ public class Apple2JoystickSettingsMenu extends Apple2AbstractMenu {
|
|||
|
||||
@Override
|
||||
public final String getSummary(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.joystick_button_tapdelay_summary);
|
||||
return activity.getResources().getString(R.string.joystick_axis_sensitivity_summary);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrefKey() {
|
||||
return "jsTapDelaySecs";
|
||||
return "axisSensitivity";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPrefDefault() {
|
||||
return ((float) 8 / TAPDELAY_NUM_CHOICES * TAPDELAY_SCALE); // -> 0.2f
|
||||
return 1.f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(final Apple2Activity activity, View convertView) {
|
||||
final IMenuEnum self = this;
|
||||
return _sliderView(activity, this, TAPDELAY_NUM_CHOICES, new IPreferenceSlider() {
|
||||
return _sliderView(activity, this, JOYSTICK_AXIS_SENSITIVITY_NUM_CHOICES, new IPreferenceSlider() {
|
||||
@Override
|
||||
public void saveInt(int progress) {
|
||||
Apple2Preferences.setJSONPref(self, ((float) progress / TAPDELAY_NUM_CHOICES * TAPDELAY_SCALE));
|
||||
final int pivot = JOYSTICK_AXIS_SENSITIVITY_DEC_NUMCHOICES;
|
||||
float sensitivity = 1.f;
|
||||
if (progress < pivot) {
|
||||
int decAmount = (pivot - progress);
|
||||
sensitivity -= (JOYSTICK_AXIS_SENSITIVITY_DEC_STEP * decAmount);
|
||||
} else if (progress > pivot) {
|
||||
int incAmount = (progress - pivot);
|
||||
sensitivity += (JOYSTICK_AXIS_SENSITIVITY_INC_STEP * incAmount);
|
||||
}
|
||||
Apple2Preferences.setJSONPref(self, sensitivity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int intValue() {
|
||||
return (int) (Apple2Preferences.getFloatJSONPref(self) / TAPDELAY_SCALE * TAPDELAY_NUM_CHOICES);
|
||||
float sensitivity = Apple2Preferences.getFloatJSONPref(self);
|
||||
int pivot = JOYSTICK_AXIS_SENSITIVITY_DEC_NUMCHOICES;
|
||||
if (sensitivity < 1.f) {
|
||||
pivot = Math.round((sensitivity - JOYSTICK_AXIS_SENSITIVITY_MIN) / JOYSTICK_AXIS_SENSITIVITY_DEC_STEP);
|
||||
} else if (sensitivity > 1.f) {
|
||||
sensitivity -= 1.f;
|
||||
pivot += Math.round(sensitivity / JOYSTICK_AXIS_SENSITIVITY_INC_STEP);
|
||||
}
|
||||
return pivot;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showValue(int progress, final TextView seekBarValue) {
|
||||
seekBarValue.setText("" + (((float) progress / TAPDELAY_NUM_CHOICES) * TAPDELAY_SCALE));
|
||||
saveInt(progress);
|
||||
int percent = (int) (Apple2Preferences.getFloatJSONPref(self) * 100.f);
|
||||
seekBarValue.setText("" + percent + "%");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -387,7 +500,7 @@ public class Apple2JoystickSettingsMenu extends Apple2AbstractMenu {
|
|||
if (position < 0 || position >= SETTINGS.size) {
|
||||
throw new ArrayIndexOutOfBoundsException();
|
||||
}
|
||||
return position == SETTINGS.JOYSTICK_AXIS_ON_LEFT.ordinal();
|
||||
return position <= SETTINGS.JOYSTICK_AXIS_ON_LEFT.ordinal();
|
||||
}
|
||||
|
||||
protected enum SETTINGS implements Apple2AbstractMenu.IMenuEnum {
|
||||
|
@ -461,7 +574,7 @@ public class Apple2JoystickSettingsMenu extends Apple2AbstractMenu {
|
|||
return convertView;
|
||||
}
|
||||
},
|
||||
JOYSTICK_AXIS_SENSITIVITY {
|
||||
JOYSTICK_TAPDELAY {
|
||||
@Override
|
||||
public final String getTitle(Apple2Activity activity) {
|
||||
return "";
|
||||
|
@ -469,55 +582,40 @@ public class Apple2JoystickSettingsMenu extends Apple2AbstractMenu {
|
|||
|
||||
@Override
|
||||
public final String getSummary(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.joystick_axis_sensitivity_summary);
|
||||
return activity.getResources().getString(R.string.joystick_button_tapdelay_summary);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrefKey() {
|
||||
return "axisSensitivity";
|
||||
return "jsTapDelayFrames";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPrefDefault() {
|
||||
return 1.f;
|
||||
return 12; // 12 * 16.688millis == ~0.2secs
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(final Apple2Activity activity, View convertView) {
|
||||
final IMenuEnum self = this;
|
||||
return _sliderView(activity, this, JOYSTICK_AXIS_SENSITIVITY_NUM_CHOICES, new IPreferenceSlider() {
|
||||
return _sliderView(activity, this, TAPDELAY_NUM_CHOICES, new IPreferenceSlider() {
|
||||
@Override
|
||||
public void saveInt(int progress) {
|
||||
final int pivot = JOYSTICK_AXIS_SENSITIVITY_DEC_NUMCHOICES;
|
||||
float sensitivity = 1.f;
|
||||
if (progress < pivot) {
|
||||
int decAmount = (pivot - progress);
|
||||
sensitivity -= (JOYSTICK_AXIS_SENSITIVITY_DEC_STEP * decAmount);
|
||||
} else if (progress > pivot) {
|
||||
int incAmount = (progress - pivot);
|
||||
sensitivity += (JOYSTICK_AXIS_SENSITIVITY_INC_STEP * incAmount);
|
||||
}
|
||||
Apple2Preferences.setJSONPref(self, sensitivity);
|
||||
Apple2Preferences.setJSONPref(self, progress);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int intValue() {
|
||||
float sensitivity = Apple2Preferences.getFloatJSONPref(self);
|
||||
int pivot = JOYSTICK_AXIS_SENSITIVITY_DEC_NUMCHOICES;
|
||||
if (sensitivity < 1.f) {
|
||||
pivot = Math.round((sensitivity - JOYSTICK_AXIS_SENSITIVITY_MIN) / JOYSTICK_AXIS_SENSITIVITY_DEC_STEP);
|
||||
} else if (sensitivity > 1.f) {
|
||||
sensitivity -= 1.f;
|
||||
pivot += Math.round(sensitivity / JOYSTICK_AXIS_SENSITIVITY_INC_STEP);
|
||||
}
|
||||
return pivot;
|
||||
return Apple2Preferences.getIntJSONPref(self);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showValue(int progress, final TextView seekBarValue) {
|
||||
saveInt(progress);
|
||||
int percent = (int) (Apple2Preferences.getFloatJSONPref(self) * 100.f);
|
||||
seekBarValue.setText("" + percent + "%");
|
||||
String millis = String.format(java.util.Locale.ROOT, "%.3f", progress * 16.688f);
|
||||
String framesStr = activity.getResources().getString(R.string.string_frames);
|
||||
String millisStr = activity.getResources().getString(R.string.string_millis);
|
||||
String textSummary = "" + progress + " " + framesStr + " (" + millis + " " + millisStr + ")";
|
||||
seekBarValue.setText(textSummary);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -549,9 +647,6 @@ public class Apple2JoystickSettingsMenu extends Apple2AbstractMenu {
|
|||
return _sliderView(activity, this, JOYSTICK_BUTTON_THRESHOLD_NUM_CHOICES, new IPreferenceSlider() {
|
||||
@Override
|
||||
public void saveInt(int progress) {
|
||||
if (progress == 0) {
|
||||
progress = 1;
|
||||
}
|
||||
progress *= getJoystickButtonSwitchThresholdScale(activity);
|
||||
Apple2Preferences.setJSONPref(self, progress);
|
||||
}
|
||||
|
|
|
@ -29,6 +29,15 @@ public class Apple2KeyboardSettingsMenu extends Apple2AbstractMenu {
|
|||
private final static String TAG = "KeyboardSettingsMenu";
|
||||
|
||||
// These settings must match native side
|
||||
public final static int kLT = 8;
|
||||
public final static int kTAB = 9;
|
||||
public final static int kDN = 10;
|
||||
public final static int kUP = 11;
|
||||
public final static int kRET = 13;
|
||||
public final static int kRT = 21;
|
||||
public final static int kESC = 27;
|
||||
public final static int kDEL = 127;
|
||||
|
||||
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;
|
||||
|
@ -46,7 +55,9 @@ public class Apple2KeyboardSettingsMenu extends Apple2AbstractMenu {
|
|||
public final static int ICONTEXT_NONACTION = ICONTEXT_KBD_BEGIN + 0x0C;
|
||||
|
||||
public final static int SCANCODE_A = 30;
|
||||
public final static int SCANCODE_C = 46;
|
||||
public final static int SCANCODE_D = 32;
|
||||
public final static int SCANCODE_E = 18;
|
||||
public final static int SCANCODE_F = 33;
|
||||
public final static int SCANCODE_H = 35;
|
||||
public final static int SCANCODE_I = 23;
|
||||
|
@ -56,17 +67,23 @@ public class Apple2KeyboardSettingsMenu extends Apple2AbstractMenu {
|
|||
public final static int SCANCODE_M = 50;
|
||||
public final static int SCANCODE_N = 49;
|
||||
public final static int SCANCODE_O = 24;
|
||||
public final static int SCANCODE_P = 25;
|
||||
public final static int SCANCODE_Q = 16;
|
||||
public final static int SCANCODE_S = 31;
|
||||
public final static int SCANCODE_U = 22;
|
||||
public final static int SCANCODE_W = 17;
|
||||
public final static int SCANCODE_X = 45;
|
||||
public final static int SCANCODE_Y = 21;
|
||||
public final static int SCANCODE_Z = 44;
|
||||
public final static int SCANCODE_SPACE = 57;
|
||||
public final static int SCANCODE_SEMICOLON = 39;
|
||||
public final static int SCANCODE_UP = 103;
|
||||
public final static int SCANCODE_LEFT = 105;
|
||||
public final static int SCANCODE_RIGHT = 106;
|
||||
public final static int SCANCODE_DOWN = 108;
|
||||
public final static int SCANCODE_COMMA = 51;
|
||||
public final static int SCANCODE_PERIOD = 52;
|
||||
public final static int SCANCODE_SLASH = 53;
|
||||
|
||||
public Apple2KeyboardSettingsMenu(Apple2Activity activity) {
|
||||
super(activity);
|
||||
|
@ -136,6 +153,102 @@ public class Apple2KeyboardSettingsMenu extends Apple2AbstractMenu {
|
|||
return convertView;
|
||||
}
|
||||
},
|
||||
KEYBOARD_CHOOSE_ALT {
|
||||
@Override
|
||||
public final String getTitle(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.keyboard_choose_alt);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String getSummary(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.keyboard_choose_alt_summary);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrefKey() {
|
||||
return "altPathIndex";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPrefDefault() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final View getView(final Apple2Activity activity, View convertView) {
|
||||
convertView = _basicView(activity, this, convertView);
|
||||
_addPopupIcon(activity, this, convertView);
|
||||
return convertView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleSelection(final Apple2Activity activity, final Apple2AbstractMenu settingsMenu, boolean isChecked) {
|
||||
|
||||
File extKeyboardDir = Apple2Utils.getExternalStorageDirectory(activity);
|
||||
|
||||
FilenameFilter kbdJsonFilter = 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));
|
||||
}
|
||||
};
|
||||
|
||||
File[] files = null;
|
||||
if (extKeyboardDir != null) {
|
||||
files = extKeyboardDir.listFiles(kbdJsonFilter);
|
||||
}
|
||||
if (files == null) {
|
||||
// read keyboard data from /data/data/...
|
||||
File keyboardDir = new File(Apple2Utils.getDataDir(activity) + File.separator + "keyboards");
|
||||
files = keyboardDir.listFiles(kbdJsonFilter);
|
||||
if (files == null) {
|
||||
Apple2Activity.logMessage(Apple2Activity.LogType.ERROR, TAG, "OOPS, could not read keyboard data directory");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Arrays.sort(files);
|
||||
|
||||
final File[] allFiles = files;
|
||||
String[] titles = new String[allFiles.length];
|
||||
int idx = 0;
|
||||
for (File file : allFiles) {
|
||||
titles[idx] = file.getName();
|
||||
++idx;
|
||||
}
|
||||
|
||||
final String keyboardDirName = extKeyboardDir == null ? "Keyboards" : extKeyboardDir.getPath();
|
||||
|
||||
final IMenuEnum self = this;
|
||||
_alertDialogHandleSelection(activity, keyboardDirName, titles, new IPreferenceLoadSave() {
|
||||
@Override
|
||||
public int intValue() {
|
||||
return (int) Apple2Preferences.getJSONPref(self);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveInt(int value) {
|
||||
Apple2Preferences.setJSONPref(self, value);
|
||||
String path = allFiles[value].getPath();
|
||||
Apple2Preferences.setJSONPref(Apple2Preferences.PREF_DOMAIN_KEYBOARD, "altPath", path);
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
KEYBOARD_VISIBILITY_INACTIVE {
|
||||
@Override
|
||||
public final String getTitle(Apple2Activity activity) {
|
||||
|
@ -255,6 +368,41 @@ public class Apple2KeyboardSettingsMenu extends Apple2AbstractMenu {
|
|||
return convertView;
|
||||
}
|
||||
},
|
||||
KEYBOARD_ENABLE_DUO_TOUCH {
|
||||
@Override
|
||||
public final String getTitle(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.keyboard_duotouch_enabled);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String getSummary(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.keyboard_duotouch_enabled_summary);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrefKey() {
|
||||
return "duoTouchEnabled";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPrefDefault() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(final Apple2Activity activity, View convertView) {
|
||||
convertView = _basicView(activity, this, convertView);
|
||||
CheckBox cb = _addCheckbox(activity, this, convertView, (boolean) Apple2Preferences.getJSONPref(this));
|
||||
final IMenuEnum self = this;
|
||||
cb.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
||||
Apple2Preferences.setJSONPref(self, isChecked);
|
||||
}
|
||||
});
|
||||
return convertView;
|
||||
}
|
||||
},
|
||||
KEYBOARD_ENABLE_LOWERCASE {
|
||||
@Override
|
||||
public final String getTitle(Apple2Activity activity) {
|
||||
|
@ -290,102 +438,6 @@ public class Apple2KeyboardSettingsMenu extends Apple2AbstractMenu {
|
|||
return convertView;
|
||||
}
|
||||
},
|
||||
KEYBOARD_CHOOSE_ALT {
|
||||
@Override
|
||||
public final String getTitle(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.keyboard_choose_alt);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String getSummary(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.keyboard_choose_alt_summary);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrefKey() {
|
||||
return "altPathIndex";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPrefDefault() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final View getView(final Apple2Activity activity, View convertView) {
|
||||
convertView = _basicView(activity, this, convertView);
|
||||
_addPopupIcon(activity, this, convertView);
|
||||
return convertView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleSelection(final Apple2Activity activity, final Apple2AbstractMenu settingsMenu, boolean isChecked) {
|
||||
|
||||
File extKeyboardDir = Apple2Utils.getExternalStorageDirectory(activity);
|
||||
|
||||
FilenameFilter kbdJsonFilter = 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));
|
||||
}
|
||||
};
|
||||
|
||||
File[] files = null;
|
||||
if (extKeyboardDir != null) {
|
||||
files = extKeyboardDir.listFiles(kbdJsonFilter);
|
||||
}
|
||||
if (files == null) {
|
||||
// read keyboard data from /data/data/...
|
||||
File keyboardDir = new File(Apple2Utils.getDataDir(activity) + File.separator + "keyboards");
|
||||
files = keyboardDir.listFiles(kbdJsonFilter);
|
||||
if (files == null) {
|
||||
Log.e(TAG, "OOPS, could not read keyboard data directory");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Arrays.sort(files);
|
||||
|
||||
final File[] allFiles = files;
|
||||
String[] titles = new String[allFiles.length];
|
||||
int idx = 0;
|
||||
for (File file : allFiles) {
|
||||
titles[idx] = file.getName();
|
||||
++idx;
|
||||
}
|
||||
|
||||
final String keyboardDirName = extKeyboardDir == null ? "Keyboards" : extKeyboardDir.getPath();
|
||||
|
||||
final IMenuEnum self = this;
|
||||
_alertDialogHandleSelection(activity, keyboardDirName, titles, new IPreferenceLoadSave() {
|
||||
@Override
|
||||
public int intValue() {
|
||||
return (int) Apple2Preferences.getJSONPref(self);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveInt(int value) {
|
||||
Apple2Preferences.setJSONPref(self, value);
|
||||
String path = allFiles[value].getPath();
|
||||
Apple2Preferences.setJSONPref(Apple2Preferences.PREF_DOMAIN_KEYBOARD, "altPath", path);
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
KEYBOARD_GLYPH_SCALE {
|
||||
@Override
|
||||
public final String getTitle(Apple2Activity activity) {
|
||||
|
|
|
@ -15,7 +15,6 @@ import android.content.Context;
|
|||
import android.os.Handler;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.TextView;
|
||||
|
@ -25,6 +24,7 @@ import java.util.ArrayList;
|
|||
import org.deadc0de.apple2ix.basic.R;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
public class Apple2KeypadChooser implements Apple2MenuView {
|
||||
|
||||
|
@ -35,7 +35,7 @@ public class Apple2KeypadChooser implements Apple2MenuView {
|
|||
private ArrayList<Apple2MenuView> mViewStack = null;
|
||||
private TextView mCurrentChoicePrompt = null;
|
||||
|
||||
private STATE_MACHINE mChooserState = STATE_MACHINE.CHOOSE_NORTHWEST;
|
||||
private STATE_MACHINE mChooserState = STATE_MACHINE.CHOOSE_AXIS_NORTHWEST;
|
||||
|
||||
private boolean mTouchMenuEnabled = false;
|
||||
private int mSavedTouchDevice = Apple2SettingsMenu.TouchDeviceVariant.NONE.ordinal();
|
||||
|
@ -50,6 +50,36 @@ public class Apple2KeypadChooser implements Apple2MenuView {
|
|||
return true;
|
||||
}
|
||||
|
||||
public static boolean isShiftedKey(char ascii) {
|
||||
switch (ascii) {
|
||||
case '~':
|
||||
case '!':
|
||||
case '@':
|
||||
case '#':
|
||||
case '$':
|
||||
case '%':
|
||||
case '^':
|
||||
case '&':
|
||||
case '*':
|
||||
case '(':
|
||||
case ')':
|
||||
case '_':
|
||||
case '+':
|
||||
case '{':
|
||||
case '}':
|
||||
case '|':
|
||||
case ':':
|
||||
case '"':
|
||||
case '<':
|
||||
case '>':
|
||||
case '?':
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void onKeyTapCalibrationEvent(char ascii, int scancode) {
|
||||
if (ascii == Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION) {
|
||||
scancode = -1;
|
||||
|
@ -58,34 +88,17 @@ public class Apple2KeypadChooser implements Apple2MenuView {
|
|||
return;
|
||||
}
|
||||
|
||||
String asciiStr = asciiRepresentation(ascii);
|
||||
Log.d(TAG, "ascii:'" + asciiStr + "' scancode:" + scancode);
|
||||
String asciiStr = asciiRepresentation(mActivity, ascii);
|
||||
Apple2Activity.logMessage(Apple2Activity.LogType.DEBUG, TAG, "ascii:'" + asciiStr + "' scancode:" + scancode);
|
||||
if (ascii == ' ') {
|
||||
ascii = Apple2KeyboardSettingsMenu.ICONTEXT_VISUAL_SPACE;
|
||||
}
|
||||
mChooserState.setKey(mActivity, ascii, scancode);
|
||||
Apple2KeypadSettingsMenu.KeyTuple tuple = new Apple2KeypadSettingsMenu.KeyTuple((long) ascii, (long) scancode, isShiftedKey(ascii));
|
||||
mChooserState.setKey(mActivity, tuple);
|
||||
Apple2Preferences.setJSONPref(Apple2SettingsMenu.SETTINGS.CURRENT_INPUT, Apple2SettingsMenu.TouchDeviceVariant.JOYSTICK_KEYPAD.ordinal());
|
||||
Apple2Preferences.sync(mActivity, Apple2Preferences.PREF_DOMAIN_TOUCHSCREEN);
|
||||
|
||||
mCurrentChoicePrompt.setText(getNextChoiceString() + asciiStr);
|
||||
switch (mChooserState) {
|
||||
case CHOOSE_TAP:
|
||||
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:
|
||||
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:
|
||||
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;
|
||||
}
|
||||
|
||||
calibrationContinue();
|
||||
}
|
||||
|
@ -184,31 +197,41 @@ public class Apple2KeypadChooser implements Apple2MenuView {
|
|||
Apple2Preferences.sync(mActivity, Apple2Preferences.PREF_DOMAIN_TOUCHSCREEN);
|
||||
}
|
||||
|
||||
private String asciiRepresentation(char ascii) {
|
||||
public static String asciiRepresentation(Apple2Activity activity, char ascii) {
|
||||
switch (ascii) {
|
||||
case Apple2KeyboardSettingsMenu.MOUSETEXT_OPENAPPLE:
|
||||
return mActivity.getResources().getString(R.string.key_open_apple);
|
||||
return activity.getResources().getString(R.string.key_open_apple);
|
||||
case Apple2KeyboardSettingsMenu.MOUSETEXT_CLOSEDAPPLE:
|
||||
return mActivity.getResources().getString(R.string.key_closed_apple);
|
||||
return activity.getResources().getString(R.string.key_closed_apple);
|
||||
case Apple2KeyboardSettingsMenu.kUP:
|
||||
case Apple2KeyboardSettingsMenu.MOUSETEXT_UP:
|
||||
return mActivity.getResources().getString(R.string.key_up);
|
||||
return activity.getResources().getString(R.string.key_up);
|
||||
case Apple2KeyboardSettingsMenu.kLT:
|
||||
case Apple2KeyboardSettingsMenu.MOUSETEXT_LEFT:
|
||||
return mActivity.getResources().getString(R.string.key_left);
|
||||
return activity.getResources().getString(R.string.key_left);
|
||||
case Apple2KeyboardSettingsMenu.kRT:
|
||||
case Apple2KeyboardSettingsMenu.MOUSETEXT_RIGHT:
|
||||
return mActivity.getResources().getString(R.string.key_right);
|
||||
return activity.getResources().getString(R.string.key_right);
|
||||
case Apple2KeyboardSettingsMenu.kDN:
|
||||
case Apple2KeyboardSettingsMenu.MOUSETEXT_DOWN:
|
||||
return mActivity.getResources().getString(R.string.key_down);
|
||||
return activity.getResources().getString(R.string.key_down);
|
||||
case Apple2KeyboardSettingsMenu.ICONTEXT_CTRL:
|
||||
return mActivity.getResources().getString(R.string.key_ctrl);
|
||||
return activity.getResources().getString(R.string.key_ctrl);
|
||||
case Apple2KeyboardSettingsMenu.kESC:
|
||||
case Apple2KeyboardSettingsMenu.ICONTEXT_ESC:
|
||||
return mActivity.getResources().getString(R.string.key_esc);
|
||||
return activity.getResources().getString(R.string.key_esc);
|
||||
case Apple2KeyboardSettingsMenu.kRET:
|
||||
case Apple2KeyboardSettingsMenu.ICONTEXT_RETURN:
|
||||
return mActivity.getResources().getString(R.string.key_ret);
|
||||
return activity.getResources().getString(R.string.key_ret);
|
||||
case Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION:
|
||||
return mActivity.getResources().getString(R.string.key_none);
|
||||
return activity.getResources().getString(R.string.key_none);
|
||||
case ' ':
|
||||
case Apple2KeyboardSettingsMenu.ICONTEXT_VISUAL_SPACE:
|
||||
return mActivity.getResources().getString(R.string.key_space);
|
||||
return activity.getResources().getString(R.string.key_space);
|
||||
case Apple2KeyboardSettingsMenu.kDEL:
|
||||
return activity.getResources().getString(R.string.key_del);
|
||||
case Apple2KeyboardSettingsMenu.kTAB:
|
||||
return activity.getResources().getString(R.string.key_tab);
|
||||
default:
|
||||
return "" + ascii;
|
||||
}
|
||||
|
@ -220,98 +243,130 @@ public class Apple2KeypadChooser implements Apple2MenuView {
|
|||
}
|
||||
|
||||
private enum STATE_MACHINE {
|
||||
CHOOSE_NORTHWEST {
|
||||
CHOOSE_AXIS_NORTHWEST {
|
||||
@Override
|
||||
public String getKeyName(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.keypad_key_axis_ul);
|
||||
}
|
||||
},
|
||||
CHOOSE_NORTH {
|
||||
CHOOSE_AXIS_NORTH {
|
||||
@Override
|
||||
public String getKeyName(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.keypad_key_axis_up);
|
||||
}
|
||||
},
|
||||
CHOOSE_NORTHEAST {
|
||||
CHOOSE_AXIS_NORTHEAST {
|
||||
@Override
|
||||
public String getKeyName(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.keypad_key_axis_ur);
|
||||
}
|
||||
},
|
||||
CHOOSE_WEST {
|
||||
CHOOSE_AXIS_WEST {
|
||||
@Override
|
||||
public String getKeyName(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.keypad_key_axis_l);
|
||||
}
|
||||
},
|
||||
CHOOSE_CENTER {
|
||||
CHOOSE_AXIS_CENTER {
|
||||
@Override
|
||||
public String getKeyName(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.keypad_key_axis_c);
|
||||
}
|
||||
},
|
||||
CHOOSE_EAST {
|
||||
CHOOSE_AXIS_EAST {
|
||||
@Override
|
||||
public String getKeyName(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.keypad_key_axis_r);
|
||||
}
|
||||
},
|
||||
CHOOSE_SOUTHWEST {
|
||||
CHOOSE_AXIS_SOUTHWEST {
|
||||
@Override
|
||||
public String getKeyName(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.keypad_key_axis_dl);
|
||||
}
|
||||
},
|
||||
CHOOSE_SOUTH {
|
||||
CHOOSE_AXIS_SOUTH {
|
||||
@Override
|
||||
public String getKeyName(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.keypad_key_axis_dn);
|
||||
}
|
||||
},
|
||||
CHOOSE_SOUTHEAST {
|
||||
CHOOSE_AXIS_SOUTHEAST {
|
||||
@Override
|
||||
public String getKeyName(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.keypad_key_axis_dr);
|
||||
}
|
||||
},
|
||||
CHOOSE_TAP {
|
||||
CHOOSE_BUTT_NORTHWEST {
|
||||
@Override
|
||||
public String getKeyName(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.keypad_key_button_tap);
|
||||
return activity.getResources().getString(R.string.keypad_key_axis_ul);
|
||||
}
|
||||
},
|
||||
CHOOSE_SWIPEUP {
|
||||
CHOOSE_BUTT_NORTH {
|
||||
@Override
|
||||
public String getKeyName(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.keypad_key_button_swipeup);
|
||||
return activity.getResources().getString(R.string.keypad_key_axis_up);
|
||||
}
|
||||
},
|
||||
CHOOSE_SWIPEDOWN {
|
||||
CHOOSE_BUTT_NORTHEAST {
|
||||
@Override
|
||||
public String getKeyName(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.keypad_key_button_swipedown);
|
||||
return activity.getResources().getString(R.string.keypad_key_axis_ur);
|
||||
}
|
||||
},
|
||||
CHOOSE_BUTT_WEST {
|
||||
@Override
|
||||
public String getKeyName(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.keypad_key_axis_l);
|
||||
}
|
||||
},
|
||||
CHOOSE_BUTT_CENTER {
|
||||
@Override
|
||||
public String getKeyName(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.keypad_key_axis_c);
|
||||
}
|
||||
},
|
||||
CHOOSE_BUTT_EAST {
|
||||
@Override
|
||||
public String getKeyName(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.keypad_key_axis_r);
|
||||
}
|
||||
},
|
||||
CHOOSE_BUTT_SOUTHWEST {
|
||||
@Override
|
||||
public String getKeyName(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.keypad_key_axis_dl);
|
||||
}
|
||||
},
|
||||
CHOOSE_BUTT_SOUTH {
|
||||
@Override
|
||||
public String getKeyName(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.keypad_key_axis_dn);
|
||||
}
|
||||
},
|
||||
CHOOSE_BUTT_SOUTHEAST {
|
||||
@Override
|
||||
public String getKeyName(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.keypad_key_axis_dr);
|
||||
}
|
||||
};
|
||||
|
||||
public static final int size = STATE_MACHINE.values().length;
|
||||
|
||||
private static ArrayList<String> chars = null;
|
||||
private static ArrayList<String> scans = null;
|
||||
private static ArrayList<Apple2KeypadSettingsMenu.KeyTuple> axisRosette = new ArrayList<Apple2KeypadSettingsMenu.KeyTuple>();
|
||||
private static ArrayList<Apple2KeypadSettingsMenu.KeyTuple> buttRosette = new ArrayList<Apple2KeypadSettingsMenu.KeyTuple>();
|
||||
|
||||
public void setKey(Apple2Activity activity, int ascii, int scancode) {
|
||||
public void setKey(Apple2Activity activity, Apple2KeypadSettingsMenu.KeyTuple tuple) {
|
||||
int ord = ordinal();
|
||||
if (ord < CHOOSE_TAP.ordinal()) {
|
||||
chars.set(ord, "" + ascii);
|
||||
scans.set(ord, "" + scancode);
|
||||
Apple2KeypadSettingsMenu.KeypadPreset.saveRosettes(chars, scans);
|
||||
} else if (ord == CHOOSE_TAP.ordinal()) {
|
||||
Apple2KeypadSettingsMenu.KeypadPreset.saveTouchDownKey(ascii, scancode);
|
||||
} else if (ord == CHOOSE_SWIPEUP.ordinal()) {
|
||||
Apple2KeypadSettingsMenu.KeypadPreset.saveSwipeNorthKey(ascii, scancode);
|
||||
} else if (ord == CHOOSE_SWIPEDOWN.ordinal()) {
|
||||
Apple2KeypadSettingsMenu.KeypadPreset.saveSwipeSouthKey(ascii, scancode);
|
||||
int buttbegin = CHOOSE_BUTT_NORTHWEST.ordinal();
|
||||
if (ord < buttbegin) {
|
||||
axisRosette.set(ord, tuple);
|
||||
Apple2KeypadSettingsMenu.KeypadPreset.saveAxisRosette(axisRosette);
|
||||
} else {
|
||||
throw new RuntimeException();
|
||||
ord -= buttbegin;
|
||||
buttRosette.set(ord, tuple);
|
||||
Apple2KeypadSettingsMenu.KeypadPreset.saveButtRosette(buttRosette);
|
||||
}
|
||||
Apple2Preferences.sync(activity, Apple2Preferences.PREF_DOMAIN_JOYSTICK);
|
||||
}
|
||||
|
@ -319,37 +374,46 @@ public class Apple2KeypadChooser implements Apple2MenuView {
|
|||
public abstract String getKeyName(Apple2Activity activity);
|
||||
|
||||
public void start() {
|
||||
setupCharsAndScans(axisRosette, Apple2KeypadSettingsMenu.PREF_KPAD_AXIS_ROSETTE);
|
||||
|
||||
JSONArray jsonChars = (JSONArray) Apple2Preferences.getJSONPref(Apple2Preferences.PREF_DOMAIN_JOYSTICK, Apple2KeypadSettingsMenu.PREF_KPAD_ROSETTE_CHAR_ARRAY, null);
|
||||
JSONArray jsonScans = (JSONArray) Apple2Preferences.getJSONPref(Apple2Preferences.PREF_DOMAIN_JOYSTICK, Apple2KeypadSettingsMenu.PREF_KPAD_ROSETTE_SCAN_ARRAY, null);
|
||||
setupCharsAndScans(buttRosette, Apple2KeypadSettingsMenu.PREF_KPAD_BUTT_ROSETTE);
|
||||
}
|
||||
|
||||
if (jsonChars == null || jsonScans == null) {
|
||||
Log.v(TAG, "Creating new keypad joystick JSON...");
|
||||
jsonChars = new JSONArray();
|
||||
jsonScans = new JSONArray();
|
||||
for (int i = 0; i < Apple2KeypadSettingsMenu.ROSETTE_SIZE; i++) {
|
||||
jsonChars.put(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION);
|
||||
jsonScans.put(-1);
|
||||
}
|
||||
}
|
||||
private void setupCharsAndScans(final ArrayList<Apple2KeypadSettingsMenu.KeyTuple> rosette, final String pref) {
|
||||
rosette.clear();
|
||||
|
||||
int len = jsonChars.length();
|
||||
if (len != Apple2KeypadSettingsMenu.ROSETTE_SIZE) {
|
||||
throw new RuntimeException("jsonChars not expected length");
|
||||
}
|
||||
if (len != jsonScans.length()) {
|
||||
throw new RuntimeException("jsonScans not expected length");
|
||||
}
|
||||
|
||||
chars = new ArrayList<String>();
|
||||
scans = new ArrayList<String>();
|
||||
try {
|
||||
JSONArray jsonArray = (JSONArray) Apple2Preferences.getJSONPref(Apple2Preferences.PREF_DOMAIN_JOYSTICK, pref, null);
|
||||
|
||||
if (jsonArray == null) {
|
||||
jsonArray = new JSONArray();
|
||||
for (int i = 0; i < Apple2KeypadSettingsMenu.ROSETTE_SIZE; i++) {
|
||||
JSONObject map = new JSONObject();
|
||||
map.put("ch", (long) Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION);
|
||||
map.put("scan", -1L);
|
||||
map.put("isShifted", false);
|
||||
}
|
||||
}
|
||||
|
||||
int len = jsonArray.length();
|
||||
if (len != Apple2KeypadSettingsMenu.ROSETTE_SIZE) {
|
||||
throw new RuntimeException("rosette not expected length");
|
||||
}
|
||||
|
||||
for (int i = 0; i < len; i++) {
|
||||
Apple2KeypadSettingsMenu.KeypadPreset.addRosetteKey(chars, scans, jsonChars.getInt(i), jsonScans.getInt(i));
|
||||
JSONObject obj = jsonArray.getJSONObject(i);
|
||||
long ch = obj.getLong("ch");
|
||||
long scan = obj.getLong("scan");
|
||||
boolean isShifted = obj.getBoolean("isShifted");
|
||||
rosette.add(new Apple2KeypadSettingsMenu.KeyTuple(ch, scan, isShifted));
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
if (rosette.size() != Apple2KeypadSettingsMenu.ROSETTE_SIZE) {
|
||||
throw new RuntimeException("rosette chars is not correct size");
|
||||
}
|
||||
}
|
||||
|
||||
public STATE_MACHINE next() {
|
||||
|
|
|
@ -12,32 +12,35 @@
|
|||
package org.deadc0de.apple2ix;
|
||||
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.CompoundButton;
|
||||
import android.widget.Toast;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.deadc0de.apple2ix.basic.R;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
|
||||
public class Apple2KeypadSettingsMenu extends Apple2AbstractMenu {
|
||||
|
||||
private final static String TAG = "Apple2KeypadSettingsMenu";
|
||||
|
||||
public final static int KEYREPEAT_NUM_CHOICES = Apple2Preferences.DECENT_AMOUNT_OF_CHOICES;
|
||||
|
||||
public final static String PREF_KPAD_ROSETTE_CHAR_ARRAY = "kpAxisRosetteChars";
|
||||
public final static String PREF_KPAD_ROSETTE_SCAN_ARRAY = "kpAxisRosetteScancodes";
|
||||
public final static String PREF_KPAD_SWIPE_NORTH_CHAR = "kpSwipeNorthChar";
|
||||
public final static String PREF_KPAD_SWIPE_NORTH_SCAN = "kpSwipeNorthScancode";
|
||||
public final static String PREF_KPAD_SWIPE_SOUTH_CHAR = "kpSwipeSouthChar";
|
||||
public final static String PREF_KPAD_SWIPE_SOUTH_SCAN = "kpSwipeSouthScancode";
|
||||
public final static String PREF_KPAD_TOUCHDOWN_CHAR = "kpTouchDownChar";
|
||||
public final static String PREF_KPAD_TOUCHDOWN_SCAN = "kpTouchDownScancode";
|
||||
public final static String PREF_KPAD_AXIS_ROSETTE = "kpAxisRosette";
|
||||
public final static String PREF_KPAD_BUTT_ROSETTE = "kpButtRosette";
|
||||
|
||||
public final static int ROSETTE_SIZE = 9;
|
||||
|
||||
public Apple2KeypadSettingsMenu(Apple2Activity activity) {
|
||||
private Apple2SettingsMenu.TouchDeviceVariant mVariant;
|
||||
|
||||
public Apple2KeypadSettingsMenu(Apple2Activity activity, Apple2SettingsMenu.TouchDeviceVariant variant) {
|
||||
super(activity);
|
||||
|
||||
if (!(variant == Apple2SettingsMenu.TouchDeviceVariant.JOYSTICK || variant == Apple2SettingsMenu.TouchDeviceVariant.JOYSTICK_KEYPAD)) {
|
||||
throw new RuntimeException("You're doing it wrong");
|
||||
}
|
||||
|
||||
mVariant = variant;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -63,6 +66,22 @@ public class Apple2KeypadSettingsMenu extends Apple2AbstractMenu {
|
|||
return true;
|
||||
}
|
||||
|
||||
public static class KeyTuple {
|
||||
public long ch;
|
||||
public long scan;
|
||||
public boolean isShifted;
|
||||
|
||||
public KeyTuple(long ch, long scan) {
|
||||
this(ch, scan, false);
|
||||
}
|
||||
|
||||
public KeyTuple(long ch, long scan, boolean isShifted) {
|
||||
this.ch = ch;
|
||||
this.scan = scan;
|
||||
this.isShifted = isShifted;
|
||||
}
|
||||
}
|
||||
|
||||
public enum KeypadPreset {
|
||||
ARROWS_SPACE {
|
||||
@Override
|
||||
|
@ -72,22 +91,37 @@ public class Apple2KeypadSettingsMenu extends Apple2AbstractMenu {
|
|||
|
||||
@Override
|
||||
public void apply(Apple2Activity activity) {
|
||||
ArrayList<String> chars = new ArrayList<String>();
|
||||
ArrayList<String> scans = new ArrayList<String>();
|
||||
addRosetteKey(chars, scans, Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1);
|
||||
addRosetteKey(chars, scans, Apple2KeyboardSettingsMenu.MOUSETEXT_UP, Apple2KeyboardSettingsMenu.SCANCODE_UP);
|
||||
addRosetteKey(chars, scans, Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1);
|
||||
addRosetteKey(chars, scans, Apple2KeyboardSettingsMenu.MOUSETEXT_LEFT, Apple2KeyboardSettingsMenu.SCANCODE_LEFT);
|
||||
addRosetteKey(chars, scans, Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1);
|
||||
addRosetteKey(chars, scans, Apple2KeyboardSettingsMenu.MOUSETEXT_RIGHT, Apple2KeyboardSettingsMenu.SCANCODE_RIGHT);
|
||||
addRosetteKey(chars, scans, Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1);
|
||||
addRosetteKey(chars, scans, Apple2KeyboardSettingsMenu.MOUSETEXT_DOWN, Apple2KeyboardSettingsMenu.SCANCODE_DOWN);
|
||||
addRosetteKey(chars, scans, Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1);
|
||||
saveRosettes(chars, scans);
|
||||
{
|
||||
ArrayList<KeyTuple> axisRosette = new ArrayList<KeyTuple>();
|
||||
axisRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1));
|
||||
axisRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.MOUSETEXT_UP, Apple2KeyboardSettingsMenu.SCANCODE_UP));
|
||||
axisRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1));
|
||||
|
||||
saveTouchDownKey(Apple2KeyboardSettingsMenu.ICONTEXT_VISUAL_SPACE, Apple2KeyboardSettingsMenu.SCANCODE_SPACE);
|
||||
saveSwipeSouthKey(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1);
|
||||
saveSwipeNorthKey(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1);
|
||||
axisRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.MOUSETEXT_LEFT, Apple2KeyboardSettingsMenu.SCANCODE_LEFT));
|
||||
axisRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1));
|
||||
axisRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.MOUSETEXT_RIGHT, Apple2KeyboardSettingsMenu.SCANCODE_RIGHT));
|
||||
|
||||
axisRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1));
|
||||
axisRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.MOUSETEXT_DOWN, Apple2KeyboardSettingsMenu.SCANCODE_DOWN));
|
||||
axisRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1));
|
||||
saveAxisRosette(axisRosette);
|
||||
}
|
||||
|
||||
{
|
||||
ArrayList<KeyTuple> buttRosette = new ArrayList<KeyTuple>();
|
||||
buttRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, Apple2KeyboardSettingsMenu.SCANCODE_SPACE));
|
||||
buttRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, Apple2KeyboardSettingsMenu.SCANCODE_SPACE));
|
||||
buttRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, Apple2KeyboardSettingsMenu.SCANCODE_SPACE));
|
||||
|
||||
buttRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, Apple2KeyboardSettingsMenu.SCANCODE_SPACE));
|
||||
buttRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_VISUAL_SPACE, Apple2KeyboardSettingsMenu.SCANCODE_SPACE));
|
||||
buttRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, Apple2KeyboardSettingsMenu.SCANCODE_SPACE));
|
||||
|
||||
buttRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, Apple2KeyboardSettingsMenu.SCANCODE_SPACE));
|
||||
buttRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, Apple2KeyboardSettingsMenu.SCANCODE_SPACE));
|
||||
buttRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, Apple2KeyboardSettingsMenu.SCANCODE_SPACE));
|
||||
saveButtRosette(buttRosette);
|
||||
}
|
||||
}
|
||||
},
|
||||
AZ_LEFT_RIGHT_SPACE {
|
||||
|
@ -98,22 +132,38 @@ public class Apple2KeypadSettingsMenu extends Apple2AbstractMenu {
|
|||
|
||||
@Override
|
||||
public void apply(Apple2Activity activity) {
|
||||
ArrayList<String> chars = new ArrayList<String>();
|
||||
ArrayList<String> scans = new ArrayList<String>();
|
||||
addRosetteKey(chars, scans, Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1);
|
||||
addRosetteKey(chars, scans, 'A', Apple2KeyboardSettingsMenu.SCANCODE_A);
|
||||
addRosetteKey(chars, scans, Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1);
|
||||
addRosetteKey(chars, scans, Apple2KeyboardSettingsMenu.MOUSETEXT_LEFT, Apple2KeyboardSettingsMenu.SCANCODE_LEFT);
|
||||
addRosetteKey(chars, scans, Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1);
|
||||
addRosetteKey(chars, scans, Apple2KeyboardSettingsMenu.MOUSETEXT_RIGHT, Apple2KeyboardSettingsMenu.SCANCODE_RIGHT);
|
||||
addRosetteKey(chars, scans, Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1);
|
||||
addRosetteKey(chars, scans, 'Z', Apple2KeyboardSettingsMenu.SCANCODE_Z);
|
||||
addRosetteKey(chars, scans, Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1);
|
||||
saveRosettes(chars, scans);
|
||||
{
|
||||
ArrayList<KeyTuple> axisRosette = new ArrayList<KeyTuple>();
|
||||
|
||||
saveTouchDownKey(Apple2KeyboardSettingsMenu.ICONTEXT_VISUAL_SPACE, Apple2KeyboardSettingsMenu.SCANCODE_SPACE);
|
||||
saveSwipeSouthKey(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1);
|
||||
saveSwipeNorthKey(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1);
|
||||
axisRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1));
|
||||
axisRosette.add(new KeyTuple('A', Apple2KeyboardSettingsMenu.SCANCODE_A));
|
||||
axisRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1));
|
||||
|
||||
axisRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.MOUSETEXT_LEFT, Apple2KeyboardSettingsMenu.SCANCODE_LEFT));
|
||||
axisRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1));
|
||||
axisRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.MOUSETEXT_RIGHT, Apple2KeyboardSettingsMenu.SCANCODE_RIGHT));
|
||||
|
||||
axisRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1));
|
||||
axisRosette.add(new KeyTuple('Z', Apple2KeyboardSettingsMenu.SCANCODE_Z));
|
||||
axisRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1));
|
||||
saveAxisRosette(axisRosette);
|
||||
}
|
||||
|
||||
{
|
||||
ArrayList<KeyTuple> buttRosette = new ArrayList<KeyTuple>();
|
||||
buttRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, Apple2KeyboardSettingsMenu.SCANCODE_SPACE));
|
||||
buttRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, Apple2KeyboardSettingsMenu.SCANCODE_SPACE));
|
||||
buttRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, Apple2KeyboardSettingsMenu.SCANCODE_SPACE));
|
||||
|
||||
buttRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, Apple2KeyboardSettingsMenu.SCANCODE_SPACE));
|
||||
buttRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_VISUAL_SPACE, Apple2KeyboardSettingsMenu.SCANCODE_SPACE));
|
||||
buttRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, Apple2KeyboardSettingsMenu.SCANCODE_SPACE));
|
||||
|
||||
buttRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, Apple2KeyboardSettingsMenu.SCANCODE_SPACE));
|
||||
buttRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, Apple2KeyboardSettingsMenu.SCANCODE_SPACE));
|
||||
buttRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, Apple2KeyboardSettingsMenu.SCANCODE_SPACE));
|
||||
saveButtRosette(buttRosette);
|
||||
}
|
||||
}
|
||||
},
|
||||
LEFT_RIGHT_SPACE {
|
||||
|
@ -124,22 +174,78 @@ public class Apple2KeypadSettingsMenu extends Apple2AbstractMenu {
|
|||
|
||||
@Override
|
||||
public void apply(Apple2Activity activity) {
|
||||
ArrayList<String> chars = new ArrayList<String>();
|
||||
ArrayList<String> scans = new ArrayList<String>();
|
||||
addRosetteKey(chars, scans, Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1);
|
||||
addRosetteKey(chars, scans, Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1);
|
||||
addRosetteKey(chars, scans, Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1);
|
||||
addRosetteKey(chars, scans, Apple2KeyboardSettingsMenu.MOUSETEXT_LEFT, Apple2KeyboardSettingsMenu.SCANCODE_LEFT);
|
||||
addRosetteKey(chars, scans, Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1);
|
||||
addRosetteKey(chars, scans, Apple2KeyboardSettingsMenu.MOUSETEXT_RIGHT, Apple2KeyboardSettingsMenu.SCANCODE_RIGHT);
|
||||
addRosetteKey(chars, scans, Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1);
|
||||
addRosetteKey(chars, scans, Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1);
|
||||
addRosetteKey(chars, scans, Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1);
|
||||
saveRosettes(chars, scans);
|
||||
{
|
||||
ArrayList<KeyTuple> axisRosette = new ArrayList<KeyTuple>();
|
||||
axisRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, Apple2KeyboardSettingsMenu.SCANCODE_LEFT));
|
||||
axisRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1));
|
||||
axisRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, Apple2KeyboardSettingsMenu.SCANCODE_RIGHT));
|
||||
|
||||
saveTouchDownKey(Apple2KeyboardSettingsMenu.ICONTEXT_VISUAL_SPACE, Apple2KeyboardSettingsMenu.SCANCODE_SPACE);
|
||||
saveSwipeSouthKey(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1);
|
||||
saveSwipeNorthKey(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1);
|
||||
axisRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.MOUSETEXT_LEFT, Apple2KeyboardSettingsMenu.SCANCODE_LEFT));
|
||||
axisRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1));
|
||||
axisRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.MOUSETEXT_RIGHT, Apple2KeyboardSettingsMenu.SCANCODE_RIGHT));
|
||||
|
||||
axisRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, Apple2KeyboardSettingsMenu.SCANCODE_LEFT));
|
||||
axisRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1));
|
||||
axisRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, Apple2KeyboardSettingsMenu.SCANCODE_RIGHT));
|
||||
saveAxisRosette(axisRosette);
|
||||
}
|
||||
|
||||
{
|
||||
ArrayList<KeyTuple> buttRosette = new ArrayList<KeyTuple>();
|
||||
buttRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, Apple2KeyboardSettingsMenu.SCANCODE_SPACE));
|
||||
buttRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, Apple2KeyboardSettingsMenu.SCANCODE_SPACE));
|
||||
buttRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, Apple2KeyboardSettingsMenu.SCANCODE_SPACE));
|
||||
|
||||
buttRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, Apple2KeyboardSettingsMenu.SCANCODE_SPACE));
|
||||
buttRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_VISUAL_SPACE, Apple2KeyboardSettingsMenu.SCANCODE_SPACE));
|
||||
buttRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, Apple2KeyboardSettingsMenu.SCANCODE_SPACE));
|
||||
|
||||
buttRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, Apple2KeyboardSettingsMenu.SCANCODE_SPACE));
|
||||
buttRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, Apple2KeyboardSettingsMenu.SCANCODE_SPACE));
|
||||
buttRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, Apple2KeyboardSettingsMenu.SCANCODE_SPACE));
|
||||
saveButtRosette(buttRosette);
|
||||
}
|
||||
}
|
||||
},
|
||||
QAZ_LEFT_RIGHT_SPACE {
|
||||
@Override
|
||||
public String getTitle(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.keypad_preset_qaz_left_right_space);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(Apple2Activity activity) {
|
||||
{
|
||||
ArrayList<KeyTuple> axisRosette = new ArrayList<KeyTuple>();
|
||||
axisRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1));
|
||||
axisRosette.add(new KeyTuple('A', Apple2KeyboardSettingsMenu.SCANCODE_A));
|
||||
axisRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1));
|
||||
|
||||
axisRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.MOUSETEXT_LEFT, Apple2KeyboardSettingsMenu.SCANCODE_LEFT));
|
||||
axisRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1));
|
||||
axisRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.MOUSETEXT_RIGHT, Apple2KeyboardSettingsMenu.SCANCODE_RIGHT));
|
||||
|
||||
axisRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1));
|
||||
axisRosette.add(new KeyTuple('Z', Apple2KeyboardSettingsMenu.SCANCODE_Z));
|
||||
axisRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1));
|
||||
saveAxisRosette(axisRosette);
|
||||
}
|
||||
|
||||
{
|
||||
ArrayList<KeyTuple> buttRosette = new ArrayList<KeyTuple>();
|
||||
buttRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, Apple2KeyboardSettingsMenu.SCANCODE_Q));
|
||||
buttRosette.add(new KeyTuple('Q', Apple2KeyboardSettingsMenu.SCANCODE_Q));
|
||||
buttRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, Apple2KeyboardSettingsMenu.SCANCODE_Q));
|
||||
|
||||
buttRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, Apple2KeyboardSettingsMenu.SCANCODE_SPACE));
|
||||
buttRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_VISUAL_SPACE, Apple2KeyboardSettingsMenu.SCANCODE_SPACE));
|
||||
buttRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, Apple2KeyboardSettingsMenu.SCANCODE_SPACE));
|
||||
|
||||
buttRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, Apple2KeyboardSettingsMenu.SCANCODE_SPACE));
|
||||
buttRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, Apple2KeyboardSettingsMenu.SCANCODE_SPACE));
|
||||
buttRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, Apple2KeyboardSettingsMenu.SCANCODE_SPACE));
|
||||
saveButtRosette(buttRosette);
|
||||
}
|
||||
}
|
||||
},
|
||||
IJKM_SPACE {
|
||||
|
@ -150,22 +256,37 @@ public class Apple2KeypadSettingsMenu extends Apple2AbstractMenu {
|
|||
|
||||
@Override
|
||||
public void apply(Apple2Activity activity) {
|
||||
ArrayList<String> chars = new ArrayList<String>();
|
||||
ArrayList<String> scans = new ArrayList<String>();
|
||||
addRosetteKey(chars, scans, Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1);
|
||||
addRosetteKey(chars, scans, 'I', Apple2KeyboardSettingsMenu.SCANCODE_I);
|
||||
addRosetteKey(chars, scans, Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1);
|
||||
addRosetteKey(chars, scans, 'J', Apple2KeyboardSettingsMenu.SCANCODE_J);
|
||||
addRosetteKey(chars, scans, Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1);
|
||||
addRosetteKey(chars, scans, 'K', Apple2KeyboardSettingsMenu.SCANCODE_K);
|
||||
addRosetteKey(chars, scans, Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1);
|
||||
addRosetteKey(chars, scans, 'M', Apple2KeyboardSettingsMenu.SCANCODE_M);
|
||||
addRosetteKey(chars, scans, Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1);
|
||||
saveRosettes(chars, scans);
|
||||
{
|
||||
ArrayList<KeyTuple> axisRosette = new ArrayList<KeyTuple>();
|
||||
axisRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1));
|
||||
axisRosette.add(new KeyTuple('I', Apple2KeyboardSettingsMenu.SCANCODE_I));
|
||||
axisRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1));
|
||||
|
||||
saveTouchDownKey(Apple2KeyboardSettingsMenu.ICONTEXT_VISUAL_SPACE, Apple2KeyboardSettingsMenu.SCANCODE_SPACE);
|
||||
saveSwipeSouthKey(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1);
|
||||
saveSwipeNorthKey(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1);
|
||||
axisRosette.add(new KeyTuple('J', Apple2KeyboardSettingsMenu.SCANCODE_J));
|
||||
axisRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1));
|
||||
axisRosette.add(new KeyTuple('K', Apple2KeyboardSettingsMenu.SCANCODE_K));
|
||||
|
||||
axisRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1));
|
||||
axisRosette.add(new KeyTuple('M', Apple2KeyboardSettingsMenu.SCANCODE_M));
|
||||
axisRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1));
|
||||
saveAxisRosette(axisRosette);
|
||||
}
|
||||
|
||||
{
|
||||
ArrayList<KeyTuple> buttRosette = new ArrayList<KeyTuple>();
|
||||
buttRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, Apple2KeyboardSettingsMenu.SCANCODE_SPACE));
|
||||
buttRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, Apple2KeyboardSettingsMenu.SCANCODE_SPACE));
|
||||
buttRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, Apple2KeyboardSettingsMenu.SCANCODE_SPACE));
|
||||
|
||||
buttRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, Apple2KeyboardSettingsMenu.SCANCODE_SPACE));
|
||||
buttRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_VISUAL_SPACE, Apple2KeyboardSettingsMenu.SCANCODE_SPACE));
|
||||
buttRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, Apple2KeyboardSettingsMenu.SCANCODE_SPACE));
|
||||
|
||||
buttRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, Apple2KeyboardSettingsMenu.SCANCODE_SPACE));
|
||||
buttRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, Apple2KeyboardSettingsMenu.SCANCODE_SPACE));
|
||||
buttRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, Apple2KeyboardSettingsMenu.SCANCODE_SPACE));
|
||||
saveButtRosette(buttRosette);
|
||||
}
|
||||
}
|
||||
},
|
||||
WADX_SPACE {
|
||||
|
@ -176,87 +297,206 @@ public class Apple2KeypadSettingsMenu extends Apple2AbstractMenu {
|
|||
|
||||
@Override
|
||||
public void apply(Apple2Activity activity) {
|
||||
ArrayList<String> chars = new ArrayList<String>();
|
||||
ArrayList<String> scans = new ArrayList<String>();
|
||||
addRosetteKey(chars, scans, Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1);
|
||||
addRosetteKey(chars, scans, 'W', Apple2KeyboardSettingsMenu.SCANCODE_W);
|
||||
addRosetteKey(chars, scans, Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1);
|
||||
addRosetteKey(chars, scans, 'A', Apple2KeyboardSettingsMenu.SCANCODE_A);
|
||||
addRosetteKey(chars, scans, Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1);
|
||||
addRosetteKey(chars, scans, 'D', Apple2KeyboardSettingsMenu.SCANCODE_D);
|
||||
addRosetteKey(chars, scans, Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1);
|
||||
addRosetteKey(chars, scans, 'X', Apple2KeyboardSettingsMenu.SCANCODE_X);
|
||||
addRosetteKey(chars, scans, Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1);
|
||||
saveRosettes(chars, scans);
|
||||
{
|
||||
ArrayList<KeyTuple> axisRosette = new ArrayList<KeyTuple>();
|
||||
axisRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1));
|
||||
axisRosette.add(new KeyTuple('W', Apple2KeyboardSettingsMenu.SCANCODE_W));
|
||||
axisRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1));
|
||||
|
||||
saveTouchDownKey(Apple2KeyboardSettingsMenu.ICONTEXT_VISUAL_SPACE, Apple2KeyboardSettingsMenu.SCANCODE_SPACE);
|
||||
saveSwipeSouthKey(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1);
|
||||
saveSwipeNorthKey(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1);
|
||||
axisRosette.add(new KeyTuple('A', Apple2KeyboardSettingsMenu.SCANCODE_A));
|
||||
axisRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1));
|
||||
axisRosette.add(new KeyTuple('D', Apple2KeyboardSettingsMenu.SCANCODE_D));
|
||||
|
||||
axisRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1));
|
||||
axisRosette.add(new KeyTuple('X', Apple2KeyboardSettingsMenu.SCANCODE_X));
|
||||
axisRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1));
|
||||
saveAxisRosette(axisRosette);
|
||||
}
|
||||
|
||||
{
|
||||
ArrayList<KeyTuple> buttRosette = new ArrayList<KeyTuple>();
|
||||
buttRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, Apple2KeyboardSettingsMenu.SCANCODE_SPACE));
|
||||
buttRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, Apple2KeyboardSettingsMenu.SCANCODE_SPACE));
|
||||
buttRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, Apple2KeyboardSettingsMenu.SCANCODE_SPACE));
|
||||
|
||||
buttRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, Apple2KeyboardSettingsMenu.SCANCODE_SPACE));
|
||||
buttRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_VISUAL_SPACE, Apple2KeyboardSettingsMenu.SCANCODE_SPACE));
|
||||
buttRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, Apple2KeyboardSettingsMenu.SCANCODE_SPACE));
|
||||
|
||||
buttRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, Apple2KeyboardSettingsMenu.SCANCODE_SPACE));
|
||||
buttRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, Apple2KeyboardSettingsMenu.SCANCODE_SPACE));
|
||||
buttRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, Apple2KeyboardSettingsMenu.SCANCODE_SPACE));
|
||||
saveButtRosette(buttRosette);
|
||||
}
|
||||
}
|
||||
},
|
||||
CRAZY_SEAFOX_KEYS {
|
||||
LODERUNNER_KEYS {
|
||||
@Override
|
||||
public String getTitle(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.keypad_preset_crazy_seafox);
|
||||
return activity.getResources().getString(R.string.keypad_preset_loderunner);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getToast(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.keypad_preset_loderunner_toast);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(Apple2Activity activity) {
|
||||
// Heh, the entire purpose of the keypad-variant touch joystick is to make this possible ;-)
|
||||
ArrayList<String> chars = new ArrayList<String>();
|
||||
ArrayList<String> scans = new ArrayList<String>();
|
||||
addRosetteKey(chars, scans, 'Y', Apple2KeyboardSettingsMenu.SCANCODE_Y);
|
||||
addRosetteKey(chars, scans, 'U', Apple2KeyboardSettingsMenu.SCANCODE_U);
|
||||
addRosetteKey(chars, scans, 'I', Apple2KeyboardSettingsMenu.SCANCODE_I);
|
||||
addRosetteKey(chars, scans, 'H', Apple2KeyboardSettingsMenu.SCANCODE_H);
|
||||
addRosetteKey(chars, scans, 'J', Apple2KeyboardSettingsMenu.SCANCODE_J);
|
||||
addRosetteKey(chars, scans, 'K', Apple2KeyboardSettingsMenu.SCANCODE_K);
|
||||
addRosetteKey(chars, scans, 'N', Apple2KeyboardSettingsMenu.SCANCODE_N);
|
||||
addRosetteKey(chars, scans, 'M', Apple2KeyboardSettingsMenu.SCANCODE_M);
|
||||
addRosetteKey(chars, scans, ',', Apple2KeyboardSettingsMenu.SCANCODE_COMMA);
|
||||
saveRosettes(chars, scans);
|
||||
{
|
||||
ArrayList<KeyTuple> axisRosette = new ArrayList<KeyTuple>();
|
||||
axisRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1));
|
||||
axisRosette.add(new KeyTuple('I', Apple2KeyboardSettingsMenu.SCANCODE_I));
|
||||
axisRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1));
|
||||
|
||||
saveTouchDownKey('D', Apple2KeyboardSettingsMenu.SCANCODE_D);
|
||||
saveSwipeSouthKey('F', Apple2KeyboardSettingsMenu.SCANCODE_F);
|
||||
saveSwipeNorthKey(Apple2KeyboardSettingsMenu.ICONTEXT_VISUAL_SPACE, Apple2KeyboardSettingsMenu.SCANCODE_SPACE);
|
||||
axisRosette.add(new KeyTuple('J', Apple2KeyboardSettingsMenu.SCANCODE_J));
|
||||
axisRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_VISUAL_SPACE, Apple2KeyboardSettingsMenu.SCANCODE_SPACE));
|
||||
axisRosette.add(new KeyTuple('L', Apple2KeyboardSettingsMenu.SCANCODE_L));
|
||||
|
||||
axisRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1));
|
||||
axisRosette.add(new KeyTuple('K', Apple2KeyboardSettingsMenu.SCANCODE_K));
|
||||
axisRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1));
|
||||
saveAxisRosette(axisRosette);
|
||||
}
|
||||
|
||||
{
|
||||
ArrayList<KeyTuple> buttRosette = new ArrayList<KeyTuple>();
|
||||
buttRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, Apple2KeyboardSettingsMenu.SCANCODE_U));
|
||||
buttRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1));
|
||||
buttRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, Apple2KeyboardSettingsMenu.SCANCODE_O));
|
||||
|
||||
buttRosette.add(new KeyTuple('U', Apple2KeyboardSettingsMenu.SCANCODE_U));
|
||||
buttRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1));
|
||||
buttRosette.add(new KeyTuple('O', Apple2KeyboardSettingsMenu.SCANCODE_O));
|
||||
|
||||
buttRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, Apple2KeyboardSettingsMenu.SCANCODE_U));
|
||||
buttRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1));
|
||||
buttRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, Apple2KeyboardSettingsMenu.SCANCODE_O));
|
||||
saveButtRosette(buttRosette);
|
||||
}
|
||||
}
|
||||
},
|
||||
ROBOTRON_KEYS {
|
||||
@Override
|
||||
public String getTitle(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.keypad_preset_robotron);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(Apple2Activity activity) {
|
||||
{
|
||||
ArrayList<KeyTuple> axisRosette = new ArrayList<KeyTuple>();
|
||||
axisRosette.add(new KeyTuple('Q', Apple2KeyboardSettingsMenu.SCANCODE_Q));
|
||||
axisRosette.add(new KeyTuple('W', Apple2KeyboardSettingsMenu.SCANCODE_W));
|
||||
axisRosette.add(new KeyTuple('E', Apple2KeyboardSettingsMenu.SCANCODE_E));
|
||||
|
||||
axisRosette.add(new KeyTuple('A', Apple2KeyboardSettingsMenu.SCANCODE_A));
|
||||
axisRosette.add(new KeyTuple('S', Apple2KeyboardSettingsMenu.SCANCODE_S));
|
||||
axisRosette.add(new KeyTuple('D', Apple2KeyboardSettingsMenu.SCANCODE_D));
|
||||
|
||||
axisRosette.add(new KeyTuple('Z', Apple2KeyboardSettingsMenu.SCANCODE_Z));
|
||||
axisRosette.add(new KeyTuple('X', Apple2KeyboardSettingsMenu.SCANCODE_X));
|
||||
axisRosette.add(new KeyTuple('C', Apple2KeyboardSettingsMenu.SCANCODE_C));
|
||||
saveAxisRosette(axisRosette);
|
||||
}
|
||||
|
||||
{
|
||||
ArrayList<KeyTuple> buttRosette = new ArrayList<KeyTuple>();
|
||||
buttRosette.add(new KeyTuple('I', Apple2KeyboardSettingsMenu.SCANCODE_I));
|
||||
buttRosette.add(new KeyTuple('O', Apple2KeyboardSettingsMenu.SCANCODE_O));
|
||||
buttRosette.add(new KeyTuple('P', Apple2KeyboardSettingsMenu.SCANCODE_P));
|
||||
|
||||
buttRosette.add(new KeyTuple('K', Apple2KeyboardSettingsMenu.SCANCODE_K));
|
||||
buttRosette.add(new KeyTuple('L', Apple2KeyboardSettingsMenu.SCANCODE_L));
|
||||
buttRosette.add(new KeyTuple(';', Apple2KeyboardSettingsMenu.SCANCODE_SEMICOLON));
|
||||
|
||||
buttRosette.add(new KeyTuple(',', Apple2KeyboardSettingsMenu.SCANCODE_COMMA));
|
||||
buttRosette.add(new KeyTuple('.', Apple2KeyboardSettingsMenu.SCANCODE_PERIOD));
|
||||
buttRosette.add(new KeyTuple('/', Apple2KeyboardSettingsMenu.SCANCODE_SLASH));
|
||||
saveButtRosette(buttRosette);
|
||||
}
|
||||
}
|
||||
},
|
||||
SEAFOX_KEYS {
|
||||
@Override
|
||||
public String getTitle(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.keypad_preset_seafox);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(Apple2Activity activity) {
|
||||
{
|
||||
ArrayList<KeyTuple> axisRosette = new ArrayList<KeyTuple>();
|
||||
axisRosette.add(new KeyTuple('Y', Apple2KeyboardSettingsMenu.SCANCODE_Y));
|
||||
axisRosette.add(new KeyTuple('U', Apple2KeyboardSettingsMenu.SCANCODE_U));
|
||||
axisRosette.add(new KeyTuple('I', Apple2KeyboardSettingsMenu.SCANCODE_I));
|
||||
|
||||
axisRosette.add(new KeyTuple('H', Apple2KeyboardSettingsMenu.SCANCODE_H));
|
||||
axisRosette.add(new KeyTuple('J', Apple2KeyboardSettingsMenu.SCANCODE_J));
|
||||
axisRosette.add(new KeyTuple('K', Apple2KeyboardSettingsMenu.SCANCODE_K));
|
||||
|
||||
axisRosette.add(new KeyTuple('N', Apple2KeyboardSettingsMenu.SCANCODE_N));
|
||||
axisRosette.add(new KeyTuple('M', Apple2KeyboardSettingsMenu.SCANCODE_M));
|
||||
axisRosette.add(new KeyTuple(',', Apple2KeyboardSettingsMenu.SCANCODE_COMMA));
|
||||
saveAxisRosette(axisRosette);
|
||||
}
|
||||
|
||||
{
|
||||
ArrayList<KeyTuple> buttRosette = new ArrayList<KeyTuple>();
|
||||
buttRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, Apple2KeyboardSettingsMenu.SCANCODE_D));
|
||||
buttRosette.add(new KeyTuple('D', Apple2KeyboardSettingsMenu.SCANCODE_D));
|
||||
buttRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, Apple2KeyboardSettingsMenu.SCANCODE_F));
|
||||
|
||||
buttRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1));
|
||||
buttRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_VISUAL_SPACE, Apple2KeyboardSettingsMenu.SCANCODE_SPACE));
|
||||
buttRosette.add(new KeyTuple('F', Apple2KeyboardSettingsMenu.SCANCODE_F));
|
||||
|
||||
buttRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1));
|
||||
buttRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1));
|
||||
buttRosette.add(new KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1));
|
||||
saveButtRosette(buttRosette);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public static void addRosetteKey(ArrayList<String> chars, ArrayList<String> scans, int aChar, int aScan) {
|
||||
chars.add("" + aChar);
|
||||
scans.add("" + aScan);
|
||||
}
|
||||
|
||||
public static void saveRosettes(ArrayList<String> chars, ArrayList<String> scans) {
|
||||
if (chars.size() != 9) {
|
||||
throw new RuntimeException("rosette chars is not correct size");
|
||||
public static void saveAxisRosette(ArrayList<KeyTuple> axisRosette) {
|
||||
if (axisRosette.size() != 9) {
|
||||
throw new RuntimeException("axis rosette is not correct size");
|
||||
}
|
||||
if (scans.size() != 9) {
|
||||
throw new RuntimeException("rosette scans is not correct size");
|
||||
Apple2Preferences.setJSONPref(Apple2Preferences.PREF_DOMAIN_JOYSTICK, PREF_KPAD_AXIS_ROSETTE, toJSONArray(axisRosette));
|
||||
}
|
||||
|
||||
public static void saveButtRosette(ArrayList<KeyTuple> buttRosette) {
|
||||
if (buttRosette.size() != 9) {
|
||||
throw new RuntimeException("butt rosette is not correct size");
|
||||
}
|
||||
Apple2Preferences.setJSONPref(Apple2Preferences.PREF_DOMAIN_JOYSTICK, PREF_KPAD_ROSETTE_CHAR_ARRAY, new JSONArray(chars));
|
||||
Apple2Preferences.setJSONPref(Apple2Preferences.PREF_DOMAIN_JOYSTICK, PREF_KPAD_ROSETTE_SCAN_ARRAY, new JSONArray(scans));
|
||||
Apple2Preferences.setJSONPref(Apple2Preferences.PREF_DOMAIN_JOYSTICK, PREF_KPAD_BUTT_ROSETTE, toJSONArray(buttRosette));
|
||||
}
|
||||
|
||||
public static void saveTouchDownKey(int aChar, int aScan) {
|
||||
Apple2Preferences.setJSONPref(Apple2Preferences.PREF_DOMAIN_JOYSTICK, PREF_KPAD_TOUCHDOWN_CHAR, aChar);
|
||||
Apple2Preferences.setJSONPref(Apple2Preferences.PREF_DOMAIN_JOYSTICK, PREF_KPAD_TOUCHDOWN_SCAN, aScan);
|
||||
}
|
||||
|
||||
public static void saveSwipeSouthKey(int aChar, int aScan) {
|
||||
Apple2Preferences.setJSONPref(Apple2Preferences.PREF_DOMAIN_JOYSTICK, PREF_KPAD_SWIPE_SOUTH_CHAR, aChar);
|
||||
Apple2Preferences.setJSONPref(Apple2Preferences.PREF_DOMAIN_JOYSTICK, PREF_KPAD_SWIPE_SOUTH_SCAN, aScan);
|
||||
}
|
||||
|
||||
public static void saveSwipeNorthKey(int aChar, int aScan) {
|
||||
Apple2Preferences.setJSONPref(Apple2Preferences.PREF_DOMAIN_JOYSTICK, PREF_KPAD_SWIPE_NORTH_CHAR, aChar);
|
||||
Apple2Preferences.setJSONPref(Apple2Preferences.PREF_DOMAIN_JOYSTICK, PREF_KPAD_SWIPE_NORTH_SCAN, aScan);
|
||||
private static JSONArray toJSONArray(ArrayList<KeyTuple> rosette) {
|
||||
JSONArray jsonArray = new JSONArray();
|
||||
try {
|
||||
for (KeyTuple tuple : rosette) {
|
||||
JSONObject obj = new JSONObject();
|
||||
obj.put("ch", tuple.ch);
|
||||
obj.put("scan", tuple.scan);
|
||||
obj.put("isShifted", tuple.isShifted);
|
||||
jsonArray.put(obj);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return jsonArray;
|
||||
}
|
||||
|
||||
public abstract String getTitle(Apple2Activity activity);
|
||||
|
||||
public abstract void apply(Apple2Activity activity);
|
||||
|
||||
public String getToast(Apple2Activity activity) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static final int size = KeypadPreset.values().length;
|
||||
|
||||
public static String[] titles(Apple2Activity activity) {
|
||||
|
@ -270,6 +510,33 @@ public class Apple2KeypadSettingsMenu extends Apple2AbstractMenu {
|
|||
}
|
||||
|
||||
enum SETTINGS implements Apple2AbstractMenu.IMenuEnum {
|
||||
JOYSTICK_CALIBRATE {
|
||||
@Override
|
||||
public final String getTitle(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.joystick_calibrate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String getSummary(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.joystick_calibrate_summary);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrefKey() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPrefDefault() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleSelection(Apple2Activity activity, Apple2AbstractMenu settingsMenu, boolean isChecked) {
|
||||
Apple2KeypadSettingsMenu thisMenu = (Apple2KeypadSettingsMenu)settingsMenu;
|
||||
Apple2JoystickCalibration.startCalibration(activity, thisMenu.mVariant);
|
||||
}
|
||||
},
|
||||
KEYPAD_CHOOSE_KEYS {
|
||||
@Override
|
||||
public final String getTitle(Apple2Activity activity) {
|
||||
|
@ -319,52 +586,55 @@ public class Apple2KeypadSettingsMenu extends Apple2AbstractMenu {
|
|||
keypadSettingsMenu.chooseKeys(activity);
|
||||
} else {
|
||||
KeypadPreset.values()[value - 1].apply(activity);
|
||||
|
||||
String toast = KeypadPreset.values()[value - 1].getToast(activity);
|
||||
if (toast != null) {
|
||||
Toast.makeText(activity, toast, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
KEYPAD_CALIBRATE {
|
||||
FAST_AUTOREPEAT {
|
||||
@Override
|
||||
public final String getTitle(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.keypad_calibrate);
|
||||
return activity.getResources().getString(R.string.keypad_autorepeat_fast);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String getSummary(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.keypad_calibrate_summary);
|
||||
return activity.getResources().getString(R.string.keypad_autorepeat_fast_summary);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleSelection(Apple2Activity activity, Apple2AbstractMenu settingsMenu, boolean isChecked) {
|
||||
ArrayList<Apple2MenuView> viewStack = new ArrayList<Apple2MenuView>();
|
||||
{
|
||||
int idx = 0;
|
||||
while (true) {
|
||||
Apple2MenuView apple2MenuView = activity.peekApple2View(idx);
|
||||
if (apple2MenuView == null) {
|
||||
break;
|
||||
}
|
||||
viewStack.add(apple2MenuView);
|
||||
++idx;
|
||||
public String getPrefKey() {
|
||||
return "kpFastAutoRepeat";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPrefDefault() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(final Apple2Activity activity, View convertView) {
|
||||
final IMenuEnum self = this;
|
||||
convertView = _basicView(activity, this, convertView);
|
||||
CheckBox cb = _addCheckbox(activity, this, convertView, (boolean) Apple2Preferences.getJSONPref(this));
|
||||
cb.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
||||
Apple2Preferences.setJSONPref(self, isChecked);
|
||||
}
|
||||
}
|
||||
|
||||
Apple2JoystickCalibration calibration = new Apple2JoystickCalibration(activity, viewStack, Apple2SettingsMenu.TouchDeviceVariant.JOYSTICK_KEYPAD);
|
||||
|
||||
// show this new view...
|
||||
calibration.show();
|
||||
|
||||
// ...with nothing else underneath 'cept the emulator OpenGL layer
|
||||
for (Apple2MenuView apple2MenuView : viewStack) {
|
||||
activity.popApple2View(apple2MenuView);
|
||||
}
|
||||
});
|
||||
return convertView;
|
||||
}
|
||||
},
|
||||
KEYPAD_ADVANCED {
|
||||
JOYSTICK_ADVANCED {
|
||||
@Override
|
||||
public final String getTitle(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.settings_advanced);
|
||||
return activity.getResources().getString(R.string.settings_advanced_joystick);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -374,7 +644,7 @@ public class Apple2KeypadSettingsMenu extends Apple2AbstractMenu {
|
|||
|
||||
@Override
|
||||
public void handleSelection(Apple2Activity activity, Apple2AbstractMenu settingsMenu, boolean isChecked) {
|
||||
new Apple2KeypadSettingsMenu.KeypadAdvanced(activity).show();
|
||||
new Apple2JoystickSettingsMenu.JoystickAdvanced(activity).show();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -441,133 +711,4 @@ public class Apple2KeypadSettingsMenu extends Apple2AbstractMenu {
|
|||
activity.popApple2View(apple2MenuView);
|
||||
}
|
||||
}
|
||||
|
||||
public static class KeypadAdvanced extends Apple2AbstractMenu {
|
||||
|
||||
private final static String TAG = "KeypadAdvanced";
|
||||
|
||||
public KeypadAdvanced(Apple2Activity activity) {
|
||||
super(activity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String[] allTitles() {
|
||||
return SETTINGS.titles(mActivity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final IMenuEnum[] allValues() {
|
||||
return SETTINGS.values();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean areAllItemsEnabled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean isEnabled(int position) {
|
||||
if (position < 0 || position >= SETTINGS.size) {
|
||||
throw new ArrayIndexOutOfBoundsException();
|
||||
}
|
||||
return position == SETTINGS.JOYSTICK_ADVANCED.ordinal();
|
||||
}
|
||||
|
||||
protected enum SETTINGS implements Apple2AbstractMenu.IMenuEnum {
|
||||
KEYREPEAT_THRESHOLD {
|
||||
@Override
|
||||
public final String getTitle(Apple2Activity activity) {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String getSummary(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.keypad_repeat_summary);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrefKey() {
|
||||
return "keyRepeatThresholdSecs";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPrefDefault() {
|
||||
return (float) 4 / KEYREPEAT_NUM_CHOICES;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(final Apple2Activity activity, View convertView) {
|
||||
final IMenuEnum self = this;
|
||||
return _sliderView(activity, this, KEYREPEAT_NUM_CHOICES, new IPreferenceSlider() {
|
||||
@Override
|
||||
public void saveInt(int progress) {
|
||||
Apple2Preferences.setJSONPref(self, (float) progress / KEYREPEAT_NUM_CHOICES);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int intValue() {
|
||||
return (int) (Apple2Preferences.getFloatJSONPref(self) * KEYREPEAT_NUM_CHOICES);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showValue(int progress, final TextView seekBarValue) {
|
||||
seekBarValue.setText("" + ((float) progress / KEYREPEAT_NUM_CHOICES));
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
JOYSTICK_ADVANCED {
|
||||
@Override
|
||||
public final String getTitle(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.settings_advanced_joystick);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String getSummary(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.settings_advanced_joystick_summary);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleSelection(Apple2Activity activity, Apple2AbstractMenu settingsMenu, boolean isChecked) {
|
||||
new Apple2JoystickSettingsMenu.JoystickAdvanced(activity).show();
|
||||
}
|
||||
};
|
||||
|
||||
public static final int size = SETTINGS.values().length;
|
||||
|
||||
@Override
|
||||
public String getPrefDomain() {
|
||||
return Apple2Preferences.PREF_DOMAIN_JOYSTICK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrefKey() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPrefDefault() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleSelection(Apple2Activity activity, Apple2AbstractMenu settingsMenu, boolean isChecked) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(Apple2Activity activity, View convertView) {
|
||||
return _basicView(activity, this, convertView);
|
||||
}
|
||||
|
||||
public static String[] titles(Apple2Activity activity) {
|
||||
String[] titles = new String[size];
|
||||
int i = 0;
|
||||
for (SETTINGS setting : values()) {
|
||||
titles[i++] = setting.getTitle(activity);
|
||||
}
|
||||
return titles;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -11,13 +11,14 @@
|
|||
|
||||
package org.deadc0de.apple2ix;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import androidx.appcompat.app.ActionBar;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import android.util.Log;
|
||||
import android.view.Gravity;
|
||||
import android.view.LayoutInflater;
|
||||
|
@ -33,7 +34,6 @@ import android.widget.TextView;
|
|||
import android.widget.Toast;
|
||||
|
||||
import org.deadc0de.apple2ix.basic.R;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.File;
|
||||
|
@ -179,14 +179,14 @@ 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...");
|
||||
Apple2Activity.logMessage(Apple2Activity.LogType.DEBUG, TAG, "position:" + position + " tapped...");
|
||||
SETTINGS setting = SETTINGS.values()[position];
|
||||
setting.handleSelection(Apple2MainMenu.this);
|
||||
}
|
||||
});
|
||||
|
||||
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.GINGERBREAD_MR1) {
|
||||
mMainMenuPopup = new PopupWindow(mainPopupContainer, android.app.ActionBar.LayoutParams.WRAP_CONTENT, android.app.ActionBar.LayoutParams.WRAP_CONTENT, true);
|
||||
mMainMenuPopup = new PopupWindow(mainPopupContainer, ActionBar.LayoutParams.WRAP_CONTENT, ActionBar.LayoutParams.WRAP_CONTENT, true);
|
||||
} else {
|
||||
// 2015/03/11 ... there may well be a less hackish way to support Gingerbread, but eh ... diminishing returns
|
||||
final int TOTAL_MARGINS = 16;
|
||||
|
@ -267,7 +267,7 @@ public class Apple2MainMenu {
|
|||
final RadioButton noAppleSelected = (RadioButton) resetConfirmationView.findViewById(R.id.radioButton_noApple);
|
||||
noAppleSelected.setChecked(false);
|
||||
|
||||
AlertDialog.Builder builder = 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.reset, new DialogInterface.OnClickListener() {
|
||||
AlertDialog rebootQuitDialog = new AlertDialog.Builder(mActivity).setIcon(R.drawable.ic_launcher).setCancelable(true).setTitle(R.string.quit_reboot).setMessage(R.string.quit_reboot_choice).setView(resetConfirmationView).setNeutralButton(R.string.reset, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
if (!selectionAlreadyHandled.compareAndSet(false, true)) {
|
||||
|
@ -283,7 +283,7 @@ public class Apple2MainMenu {
|
|||
mActivity.rebootEmulation(resetState);
|
||||
Apple2MainMenu.this.dismiss();
|
||||
}
|
||||
}).setNeutralButton(R.string.quit, new DialogInterface.OnClickListener() {
|
||||
}).setPositiveButton(R.string.quit, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
if (!selectionAlreadyHandled.compareAndSet(false, true)) {
|
||||
|
@ -292,10 +292,7 @@ public class Apple2MainMenu {
|
|||
}
|
||||
mActivity.quitEmulator();
|
||||
}
|
||||
}).setNegativeButton(R.string.cancel, null);
|
||||
|
||||
builder.setView(resetConfirmationView);
|
||||
AlertDialog rebootQuitDialog = builder.create();
|
||||
}).create();
|
||||
|
||||
mActivity.registerAndShowDialog(rebootQuitDialog);
|
||||
}
|
||||
|
@ -340,12 +337,12 @@ public class Apple2MainMenu {
|
|||
try {
|
||||
diskArgs.pfd.close(); // at this point diskArgs.pfd !null
|
||||
} catch (IOException ioe) {
|
||||
Log.e(TAG, "Error attempting to close PFD : " + ioe);
|
||||
Apple2Activity.logMessage(Apple2Activity.LogType.ERROR, TAG, "Error attempting to close PFD : " + ioe);
|
||||
}
|
||||
diskArgs.pfd = null;
|
||||
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "OOPS: " + e);
|
||||
Apple2Activity.logMessage(Apple2Activity.LogType.ERROR, TAG, "OOPS: " + e);
|
||||
}
|
||||
|
||||
return restored;
|
||||
|
@ -389,7 +386,7 @@ public class Apple2MainMenu {
|
|||
|
||||
pfds[i] = Apple2DiskChooserActivity.openFileDescriptorFromUri(activity, uri);
|
||||
if (pfds[i] == null) {
|
||||
Log.e(TAG, "Did not find URI for drive #" + i + " specified in " + SAVE_FILE + " file : " + diskPath);
|
||||
Apple2Activity.logMessage(Apple2Activity.LogType.ERROR, TAG, "Did not find URI for drive #" + i + " specified in " + SAVE_FILE + " file : " + diskPath);
|
||||
} else {
|
||||
int fd = pfds[i].getFd();
|
||||
map.put(fdKeys[i], fd);
|
||||
|
@ -397,7 +394,7 @@ public class Apple2MainMenu {
|
|||
} else {
|
||||
boolean exists = new File(diskPath).exists();
|
||||
if (!exists) {
|
||||
Log.e(TAG, "Did not find path for drive #" + i + " specified in " + SAVE_FILE + " file : " + diskPath);
|
||||
Apple2Activity.logMessage(Apple2Activity.LogType.ERROR, TAG, "Did not find path for drive #" + i + " specified in " + SAVE_FILE + " file : " + diskPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -410,7 +407,7 @@ public class Apple2MainMenu {
|
|||
pfds[i].close();
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
Log.e(TAG, "Error attempting to close PFD #" + i + " : " + ioe);
|
||||
Apple2Activity.logMessage(Apple2Activity.LogType.ERROR, TAG, "Error attempting to close PFD #" + i + " : " + ioe);
|
||||
}
|
||||
}
|
||||
map = new JSONObject(jsonString);
|
||||
|
@ -438,7 +435,7 @@ public class Apple2MainMenu {
|
|||
|
||||
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() {
|
||||
AlertDialog saveRestoreDialog = new AlertDialog.Builder(mActivity).setIcon(R.drawable.ic_launcher).setCancelable(true).setTitle(R.string.saverestore).setMessage(R.string.saverestore_choice).setNeutralButton(R.string.save, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
if (!selectionAlreadyHandled.compareAndSet(false, true)) {
|
||||
|
@ -450,7 +447,7 @@ public class Apple2MainMenu {
|
|||
mActivity.saveState(jsonString);
|
||||
Apple2MainMenu.this.dismiss();
|
||||
}
|
||||
}).setNeutralButton(R.string.restore, new DialogInterface.OnClickListener() {
|
||||
}).setPositiveButton(R.string.restore, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
|
||||
|
@ -466,7 +463,7 @@ public class Apple2MainMenu {
|
|||
}
|
||||
Apple2MainMenu.this.dismiss();
|
||||
}
|
||||
}).setNegativeButton(R.string.cancel, null).create();
|
||||
}).create();
|
||||
|
||||
mActivity.registerAndShowDialog(saveRestoreDialog);
|
||||
}
|
||||
|
|
|
@ -48,6 +48,7 @@ public class Apple2Preferences {
|
|||
public final static String PREF_DEVICE_HEIGHT = "deviceHeight";
|
||||
public final static String PREF_DEVICE_WIDTH = "deviceWidth";
|
||||
public final static String PREF_EMULATOR_VERSION = "emulatorVersion";
|
||||
public final static String PREF_RELEASE_NOTES = "shownReleaseNotes";
|
||||
|
||||
// JSON preferences
|
||||
private static JSONObject sSettings = null;
|
||||
|
@ -102,7 +103,7 @@ public class Apple2Preferences {
|
|||
key = menu.getPrefKey();
|
||||
val = map.get(key);
|
||||
} catch (JSONException e) {
|
||||
Log.d(TAG, "Did not find value for domain:" + menu.getPrefDefault() + " key:" + key);
|
||||
Apple2Activity.logMessage(Apple2Activity.LogType.DEBUG, TAG, "Did not find value for domain:" + menu.getPrefDefault() + " key:" + key);
|
||||
}
|
||||
if (val == null && key != null) {
|
||||
val = menu.getPrefDefault();
|
||||
|
@ -122,7 +123,7 @@ public class Apple2Preferences {
|
|||
map = _prefDomain(domain);
|
||||
val = map.get(key);
|
||||
} catch (JSONException e) {
|
||||
Log.d(TAG, "Did not find value for domain:" + domain + " key:" + key);
|
||||
Apple2Activity.logMessage(Apple2Activity.LogType.DEBUG, TAG, "Did not find value for domain:" + domain + " key:" + key);
|
||||
}
|
||||
if (val == null) {
|
||||
val = defaultVal;
|
||||
|
@ -142,21 +143,43 @@ public class Apple2Preferences {
|
|||
try {
|
||||
return (float) obj;
|
||||
} catch (ClassCastException e) {
|
||||
Log.d(TAG, "could not cast object as float");
|
||||
Apple2Activity.logMessage(Apple2Activity.LogType.DEBUG, TAG, "could not cast object as float");
|
||||
}
|
||||
try {
|
||||
return (float) ((double) obj);
|
||||
} catch (ClassCastException e) {
|
||||
Log.d(TAG, "could not cast object as double");
|
||||
Apple2Activity.logMessage(Apple2Activity.LogType.DEBUG, TAG, "could not cast object as double");
|
||||
}
|
||||
try {
|
||||
return (float) ((int) obj);
|
||||
} catch (ClassCastException e) {
|
||||
Log.d(TAG, "could not cast object as int");
|
||||
Apple2Activity.logMessage(Apple2Activity.LogType.DEBUG, TAG, "could not cast object as int");
|
||||
}
|
||||
return (float) ((long) obj);
|
||||
}
|
||||
|
||||
private static int _convertToInt(Object obj) {
|
||||
if (obj == null) {
|
||||
return 0;
|
||||
}
|
||||
try {
|
||||
return (int) obj;
|
||||
} catch (ClassCastException e) {
|
||||
Apple2Activity.logMessage(Apple2Activity.LogType.DEBUG, TAG, "could not cast object as int");
|
||||
}
|
||||
try {
|
||||
return (int) ((long) obj);
|
||||
} catch (ClassCastException e) {
|
||||
Apple2Activity.logMessage(Apple2Activity.LogType.DEBUG, TAG, "could not cast object as long");
|
||||
}
|
||||
try {
|
||||
return (int) ((float) obj);
|
||||
} catch (ClassCastException e) {
|
||||
Apple2Activity.logMessage(Apple2Activity.LogType.DEBUG, TAG, "could not cast object as float");
|
||||
}
|
||||
return (int) ((double) obj);
|
||||
}
|
||||
|
||||
public static float getFloatJSONPref(Apple2AbstractMenu.IMenuEnum menu) {
|
||||
return _convertToFloat(getJSONPref(menu));
|
||||
}
|
||||
|
@ -165,6 +188,14 @@ public class Apple2Preferences {
|
|||
return _convertToFloat(getJSONPref(domain, key, defaultVal));
|
||||
}
|
||||
|
||||
public static int getIntJSONPref(Apple2AbstractMenu.IMenuEnum menu) {
|
||||
return _convertToInt(getJSONPref(menu));
|
||||
}
|
||||
|
||||
public static int getIntJSONPref(String domain, String key, Object defaultVal) {
|
||||
return _convertToInt(getJSONPref(domain, key, defaultVal));
|
||||
}
|
||||
|
||||
public static boolean migrate(Apple2Activity activity) {
|
||||
int versionCode = (int) getJSONPref(PREF_DOMAIN_INTERFACE, PREF_EMULATOR_VERSION, 0);
|
||||
final boolean firstTime = (versionCode != BuildConfig.VERSION_CODE);
|
||||
|
@ -174,286 +205,118 @@ public class Apple2Preferences {
|
|||
|
||||
Log.v(TAG, "Triggering migration to Apple2ix version : " + BuildConfig.VERSION_NAME);
|
||||
setJSONPref(PREF_DOMAIN_INTERFACE, PREF_EMULATOR_VERSION, BuildConfig.VERSION_CODE);
|
||||
setJSONPref(PREF_DOMAIN_INTERFACE, PREF_RELEASE_NOTES, false);
|
||||
|
||||
if (versionCode < 22) {
|
||||
// force upgrade to defaults here ...
|
||||
setJSONPref(Apple2VideoSettingsMenu.SETTINGS.SHOW_HALF_SCANLINES, Apple2VideoSettingsMenu.SETTINGS.SHOW_HALF_SCANLINES.getPrefDefault());
|
||||
setJSONPref(Apple2VideoSettingsMenu.SETTINGS.COLOR_MODE_CONFIGURE, Apple2VideoSettingsMenu.SETTINGS.COLOR_MODE_CONFIGURE.getPrefDefault());
|
||||
}
|
||||
|
||||
Apple2Utils.migrateToExternalStorage(activity);
|
||||
if (BuildConfig.VERSION_CODE >= 17) {
|
||||
// FIXME TODO : remove this after most/all app users are on 18+
|
||||
|
||||
boolean keypadPreset = false;
|
||||
Apple2AbstractMenu.IMenuEnum menuEnum = null;
|
||||
ArrayList<String> keypadJSONChars = new ArrayList<String>();
|
||||
ArrayList<String> keypadJSONScans = new ArrayList<String>();
|
||||
for (int i = 0; i < Apple2KeypadSettingsMenu.ROSETTE_SIZE; i++) {
|
||||
keypadJSONChars.add("" + Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION);
|
||||
keypadJSONScans.add("-1");
|
||||
}
|
||||
int keypadTapChar = Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION;
|
||||
int keypadTapScan = -1;
|
||||
int keypadSwipeDownChar = Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION;
|
||||
int keypadSwipeDownScan = -1;
|
||||
int keypadSwipeUpChar = Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION;
|
||||
int keypadSwipeUpScan = -1;
|
||||
|
||||
Map<String, ?> oldPrefs = activity.getPreferences(Activity.MODE_PRIVATE).getAll();
|
||||
for (Map.Entry<String, ?> entry : oldPrefs.entrySet()) {
|
||||
|
||||
String key = entry.getKey();
|
||||
Object val = entry.getValue();
|
||||
Log.d("OLDPREFS", key + " : " + val.toString());
|
||||
|
||||
// remove olde preference ...
|
||||
activity.getPreferences(Activity.MODE_PRIVATE).edit().remove(key).commit();
|
||||
|
||||
try {
|
||||
switch (key) {
|
||||
|
||||
case "HIRES_COLOR": // long
|
||||
menuEnum = Apple2VideoSettingsMenu.SETTINGS.COLOR_CONFIGURE;
|
||||
break;
|
||||
case "LANDSCAPE_MODE": // bool
|
||||
menuEnum = Apple2VideoSettingsMenu.SETTINGS.LANDSCAPE_MODE;
|
||||
break;
|
||||
case "PORTRAIT_KEYBOARD_POSITION_SCALE": //-> float
|
||||
menuEnum = Apple2PortraitCalibration.States.CALIBRATE_KEYBOARD_POSITION_SCALE;
|
||||
val = (int) val / (float) Apple2PortraitCalibration.PORTRAIT_CALIBRATE_NUM_CHOICES;
|
||||
break;
|
||||
case "PORTRAIT_FRAMEBUFFER_POSITION_SCALE": // -> float
|
||||
menuEnum = Apple2PortraitCalibration.States.CALIBRATE_FRAMEBUFFER_POSITION_SCALE;
|
||||
val = (int) val / (float) Apple2PortraitCalibration.PORTRAIT_CALIBRATE_NUM_CHOICES;
|
||||
break;
|
||||
case "PORTRAIT_KEYBOARD_HEIGHT_SCALE": // -> float
|
||||
menuEnum = Apple2PortraitCalibration.States.CALIBRATE_KEYBOARD_HEIGHT_SCALE;
|
||||
val = (int) val / (float) Apple2PortraitCalibration.PORTRAIT_CALIBRATE_NUM_CHOICES;
|
||||
break;
|
||||
|
||||
case "SPEAKER_VOLUME": // long
|
||||
menuEnum = Apple2AudioSettingsMenu.SETTINGS.SPEAKER_VOLUME;
|
||||
break;
|
||||
case "MOCKINGBOARD_ENABLED": // bool
|
||||
menuEnum = Apple2AudioSettingsMenu.SETTINGS.MOCKINGBOARD_ENABLED;
|
||||
break;
|
||||
case "MOCKINGBOARD_VOLUME": // long
|
||||
menuEnum = Apple2AudioSettingsMenu.SETTINGS.MOCKINGBOARD_VOLUME;
|
||||
break;
|
||||
case "AUDIO_LATENCY": // -> float
|
||||
menuEnum = Apple2AudioSettingsMenu.SETTINGS.AUDIO_LATENCY;
|
||||
val = (int) val / (float) Apple2AudioSettingsMenu.AUDIO_LATENCY_NUM_CHOICES;
|
||||
break;
|
||||
|
||||
case "TOUCH_MENU_ENABLED": // bool
|
||||
menuEnum = Apple2KeyboardSettingsMenu.SETTINGS.TOUCH_MENU_ENABLED;
|
||||
break;
|
||||
case "KEYBOARD_VISIBILITY_ACTIVE": // -> float
|
||||
menuEnum = Apple2KeyboardSettingsMenu.SETTINGS.KEYBOARD_VISIBILITY_ACTIVE;
|
||||
val = (int) val / (float) ALPHA_SLIDER_NUM_CHOICES;
|
||||
break;
|
||||
case "KEYBOARD_VISIBILITY_INACTIVE": // -> float
|
||||
menuEnum = Apple2KeyboardSettingsMenu.SETTINGS.KEYBOARD_VISIBILITY_INACTIVE;
|
||||
val = (int) val / (float) ALPHA_SLIDER_NUM_CHOICES;
|
||||
break;
|
||||
case "KEYBOARD_GLYPH_SCALE": // long
|
||||
menuEnum = Apple2KeyboardSettingsMenu.SETTINGS.KEYBOARD_GLYPH_SCALE;
|
||||
break;
|
||||
case "KEYBOARD_LOWERCASE_ENABLED": // bool
|
||||
menuEnum = Apple2KeyboardSettingsMenu.SETTINGS.KEYBOARD_ENABLE_LOWERCASE;
|
||||
break;
|
||||
case "KEYBOARD_CLICK_ENABLED": // bool
|
||||
menuEnum = Apple2KeyboardSettingsMenu.SETTINGS.KEYBOARD_ENABLE_CLICK;
|
||||
break;
|
||||
case "KEYBOARD_ALT": // long
|
||||
menuEnum = Apple2KeyboardSettingsMenu.SETTINGS.KEYBOARD_CHOOSE_ALT;
|
||||
break;
|
||||
case "KEYBOARD_ALT_PATH": // String
|
||||
setJSONPref(Apple2Preferences.PREF_DOMAIN_KEYBOARD, "altPath", val);
|
||||
continue;
|
||||
|
||||
case "JOYSTICK_SWIPEUP_BUTTON":
|
||||
menuEnum = Apple2JoystickSettingsMenu.SETTINGS.JOYSTICK_SWIPEUP_BUTTON;
|
||||
break;
|
||||
case "JOYSTICK_TAP_BUTTON":
|
||||
menuEnum = Apple2JoystickSettingsMenu.SETTINGS.JOYSTICK_TAP_BUTTON;
|
||||
break;
|
||||
case "JOYSTICK_SWIPEDOWN_BUTTON":
|
||||
menuEnum = Apple2JoystickSettingsMenu.SETTINGS.JOYSTICK_SWIPEDOWN_BUTTON;
|
||||
break;
|
||||
case "JOYSTICK_VISIBILITY": // boolean
|
||||
menuEnum = Apple2JoystickSettingsMenu.JoystickAdvanced.SETTINGS.JOYSTICK_VISIBILITY;
|
||||
break;
|
||||
case "JOYSTICK_BUTTON_THRESHOLD": // -> float
|
||||
menuEnum = Apple2JoystickSettingsMenu.JoystickAdvanced.SETTINGS.JOYSTICK_BUTTON_THRESHOLD;
|
||||
val = (int) val * Apple2JoystickSettingsMenu.getJoystickButtonSwitchThresholdScale(activity);
|
||||
break;
|
||||
case "JOYSTICK_DIVIDER": // -> float
|
||||
Apple2Preferences.setJSONPref(Apple2Preferences.PREF_DOMAIN_JOYSTICK, Apple2JoystickCalibration.PREF_SCREEN_DIVISION, (int) val / (float) Apple2JoystickCalibration.JOYSTICK_DIVIDER_NUM_CHOICES);
|
||||
continue;
|
||||
case "JOYSTICK_AXIS_ON_LEFT": // bool
|
||||
menuEnum = Apple2JoystickSettingsMenu.JoystickAdvanced.SETTINGS.JOYSTICK_AXIS_ON_LEFT;
|
||||
break;
|
||||
case "JOYSTICK_TAPDELAY": // -> float
|
||||
menuEnum = Apple2JoystickSettingsMenu.SETTINGS.JOYSTICK_TAPDELAY;
|
||||
val = ((int) val / (float) Apple2JoystickSettingsMenu.TAPDELAY_NUM_CHOICES * Apple2JoystickSettingsMenu.TAPDELAY_SCALE);
|
||||
break;
|
||||
case "JOYSTICK_AZIMUTH_VISIBILITY": // boolean
|
||||
continue; // removed
|
||||
case "JOYSTICK_AXIS_SENSITIVIY": // -> float
|
||||
menuEnum = Apple2JoystickSettingsMenu.JoystickAdvanced.SETTINGS.JOYSTICK_AXIS_SENSITIVITY;
|
||||
final int pivot = Apple2JoystickSettingsMenu.JOYSTICK_AXIS_SENSITIVITY_DEC_NUMCHOICES;
|
||||
float sensitivity = 1.f;
|
||||
if ((int) val < pivot) {
|
||||
int decAmount = (pivot - (int) val);
|
||||
sensitivity -= (Apple2JoystickSettingsMenu.JOYSTICK_AXIS_SENSITIVITY_DEC_STEP * decAmount);
|
||||
} else if ((int) val > pivot) {
|
||||
int incAmount = ((int) val - pivot);
|
||||
sensitivity += (Apple2JoystickSettingsMenu.JOYSTICK_AXIS_SENSITIVITY_INC_STEP * incAmount);
|
||||
}
|
||||
val = sensitivity;
|
||||
break;
|
||||
|
||||
case "CURRENT_DISK_PATH": // String
|
||||
menuEnum = Apple2DisksMenu.SETTINGS.CURRENT_DISK_SEARCH_PATH;
|
||||
try {
|
||||
val = new JSONArray((String) val);
|
||||
} catch (JSONException e) {
|
||||
Log.v(TAG, "JSON error parsing disk path : " + e);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case "CURRENT_DRIVE_A_BUTTON": // bool
|
||||
menuEnum = Apple2DisksMenu.SETTINGS.CURRENT_DRIVE_A;
|
||||
break;
|
||||
case "CURRENT_DISK_A": // String
|
||||
menuEnum = Apple2DisksMenu.SETTINGS.CURRENT_DISK_PATH_A;
|
||||
break;
|
||||
case "CURRENT_DISK_A_RO": // bool
|
||||
menuEnum = Apple2DisksMenu.SETTINGS.CURRENT_DISK_PATH_A_RO;
|
||||
break;
|
||||
case "CURRENT_DISK_B": // String
|
||||
menuEnum = Apple2DisksMenu.SETTINGS.CURRENT_DISK_PATH_B;
|
||||
break;
|
||||
case "CURRENT_DISK_B_RO": // bool
|
||||
menuEnum = Apple2DisksMenu.SETTINGS.CURRENT_DISK_PATH_B_RO;
|
||||
break;
|
||||
|
||||
case "CURRENT_DISK_RO_BUTTON": // bool
|
||||
menuEnum = Apple2DisksMenu.SETTINGS.CURRENT_DISK_RO_BUTTON;
|
||||
break;
|
||||
case "CURRENT_TOUCH_DEVICE": // long
|
||||
menuEnum = Apple2SettingsMenu.SETTINGS.CURRENT_INPUT;
|
||||
break;
|
||||
|
||||
case "CRASH_CHECK": // boolean
|
||||
menuEnum = Apple2SettingsMenu.SETTINGS.CRASH;
|
||||
break;
|
||||
case "SHOW_DISK_OPERATIONS": // bool
|
||||
menuEnum = Apple2SettingsMenu.SETTINGS.SHOW_DISK_OPERATIONS;
|
||||
break;
|
||||
|
||||
case "KEYPAD_KEYS": // long
|
||||
menuEnum = Apple2KeypadSettingsMenu.SETTINGS.KEYPAD_CHOOSE_KEYS;
|
||||
if ((int) val != 0) {
|
||||
Apple2KeypadSettingsMenu.KeypadPreset preset = Apple2KeypadSettingsMenu.KeypadPreset.values()[(int) val - 1];
|
||||
preset.apply(activity);
|
||||
keypadPreset = true;
|
||||
}
|
||||
break;
|
||||
case "KEYREPEAT_THRESHOLD": // -> float
|
||||
menuEnum = Apple2KeypadSettingsMenu.KeypadAdvanced.SETTINGS.KEYREPEAT_THRESHOLD;
|
||||
val = (int) val / (float) Apple2KeypadSettingsMenu.KEYREPEAT_NUM_CHOICES;
|
||||
break;
|
||||
case "KEYPAD_TAP_KEY_SCAN":
|
||||
keypadTapScan = (int) val;
|
||||
continue;
|
||||
case "KEYPAD_TAP_KEY_ASCII":
|
||||
keypadTapChar = (int) val;
|
||||
continue;
|
||||
case "KEYPAD_SWIPEDOWN_KEY_SCAN":
|
||||
keypadSwipeDownScan = (int) val;
|
||||
continue;
|
||||
case "KEYPAD_SWIPEDOWN_KEY_ASCII":
|
||||
keypadSwipeDownChar = (int) val;
|
||||
continue;
|
||||
case "KEYPAD_SWIPEUP_KEY_SCAN":
|
||||
keypadSwipeUpScan = (int) val;
|
||||
continue;
|
||||
case "KEYPAD_SWIPEUP_KEY_ASCII":
|
||||
keypadSwipeUpChar = (int) val;
|
||||
continue;
|
||||
|
||||
case "KEYPAD_NORTHWEST_KEY_SCAN":
|
||||
keypadJSONScans.set(0, val.toString());
|
||||
continue;
|
||||
case "KEYPAD_NORTHWEST_KEY_ASCII":
|
||||
keypadJSONChars.set(0, val.toString());
|
||||
continue;
|
||||
case "KEYPAD_NORTH_KEY_SCAN":
|
||||
keypadJSONScans.set(1, val.toString());
|
||||
continue;
|
||||
case "KEYPAD_NORTH_KEY_ASCII":
|
||||
keypadJSONChars.set(1, val.toString());
|
||||
continue;
|
||||
case "KEYPAD_NORTHEAST_KEY_SCAN":
|
||||
keypadJSONScans.set(2, val.toString());
|
||||
continue;
|
||||
case "KEYPAD_NORTHEAST_KEY_ASCII":
|
||||
keypadJSONChars.set(2, val.toString());
|
||||
continue;
|
||||
|
||||
case "KEYPAD_WEST_KEY_SCAN":
|
||||
keypadJSONScans.set(3, val.toString());
|
||||
continue;
|
||||
case "KEYPAD_WEST_KEY_ASCII":
|
||||
keypadJSONChars.set(3, val.toString());
|
||||
continue;
|
||||
case "KEYPAD_CENTER_KEY_SCAN":
|
||||
keypadJSONScans.set(4, val.toString());
|
||||
continue;
|
||||
case "KEYPAD_CENTER_KEY_ASCII":
|
||||
keypadJSONChars.set(4, val.toString());
|
||||
continue;
|
||||
case "KEYPAD_EAST_KEY_SCAN":
|
||||
keypadJSONScans.set(5, val.toString());
|
||||
continue;
|
||||
case "KEYPAD_EAST_KEY_ASCII":
|
||||
keypadJSONChars.set(5, val.toString());
|
||||
continue;
|
||||
|
||||
case "KEYPAD_SOUTHWEST_KEY_SCAN":
|
||||
keypadJSONScans.set(6, val.toString());
|
||||
continue;
|
||||
case "KEYPAD_SOUTHWEST_KEY_ASCII":
|
||||
keypadJSONChars.set(6, val.toString());
|
||||
continue;
|
||||
case "KEYPAD_SOUTH_KEY_SCAN":
|
||||
keypadJSONScans.set(7, val.toString());
|
||||
continue;
|
||||
case "KEYPAD_SOUTH_KEY_ASCII":
|
||||
keypadJSONChars.set(7, val.toString());
|
||||
continue;
|
||||
case "KEYPAD_SOUTHEAST_KEY_SCAN":
|
||||
keypadJSONScans.set(8, val.toString());
|
||||
continue;
|
||||
case "KEYPAD_SOUTHEAST_KEY_ASCII":
|
||||
keypadJSONChars.set(8, val.toString());
|
||||
continue;
|
||||
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
|
||||
setJSONPref(menuEnum, val);
|
||||
save(activity);
|
||||
} catch (ClassCastException cce) {
|
||||
Log.v(TAG, "" + cce);
|
||||
if (versionCode < 24) {
|
||||
// migrate tap delay from seconds to frames ...
|
||||
float secs = getFloatJSONPref(PREF_DOMAIN_JOYSTICK, "jsTapDelaySecs", 9999f);
|
||||
if (secs != 9999f) {
|
||||
// UtAIIe 3-13 : "The duration of the television scan is 262 horizontal scans. This is [16.688 milliseconds]"
|
||||
// recalculate this to a frames value between 0-30 inclusive ...
|
||||
int framesDelay = Math.round(secs / 0.016688f);
|
||||
if (framesDelay < 0) {
|
||||
framesDelay = 0;
|
||||
} else if (framesDelay > 30) {
|
||||
framesDelay = 30;
|
||||
}
|
||||
setJSONPref(Apple2JoystickSettingsMenu.JoystickAdvanced.SETTINGS.JOYSTICK_TAPDELAY, framesDelay);
|
||||
}
|
||||
|
||||
// handle keypad arrays
|
||||
if (oldPrefs.size() > 0 && !keypadPreset) {
|
||||
Apple2KeypadSettingsMenu.KeypadPreset.saveRosettes(keypadJSONChars, keypadJSONScans);
|
||||
Apple2KeypadSettingsMenu.KeypadPreset.saveTouchDownKey(keypadTapChar, keypadTapScan);
|
||||
Apple2KeypadSettingsMenu.KeypadPreset.saveSwipeNorthKey(keypadSwipeUpChar, keypadSwipeUpScan);
|
||||
Apple2KeypadSettingsMenu.KeypadPreset.saveSwipeSouthKey(keypadSwipeDownChar, keypadSwipeDownScan);
|
||||
// migrate axis rosette arrays to new format ...
|
||||
try {
|
||||
ArrayList<Apple2KeypadSettingsMenu.KeyTuple> axisRosette = new ArrayList<Apple2KeypadSettingsMenu.KeyTuple>();
|
||||
axisRosette.add(new Apple2KeypadSettingsMenu.KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1));
|
||||
axisRosette.add(new Apple2KeypadSettingsMenu.KeyTuple('I', Apple2KeyboardSettingsMenu.SCANCODE_I));
|
||||
axisRosette.add(new Apple2KeypadSettingsMenu.KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1));
|
||||
|
||||
axisRosette.add(new Apple2KeypadSettingsMenu.KeyTuple('J', Apple2KeyboardSettingsMenu.SCANCODE_J));
|
||||
axisRosette.add(new Apple2KeypadSettingsMenu.KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1));
|
||||
axisRosette.add(new Apple2KeypadSettingsMenu.KeyTuple('K', Apple2KeyboardSettingsMenu.SCANCODE_K));
|
||||
|
||||
axisRosette.add(new Apple2KeypadSettingsMenu.KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1));
|
||||
axisRosette.add(new Apple2KeypadSettingsMenu.KeyTuple('M', Apple2KeyboardSettingsMenu.SCANCODE_M));
|
||||
axisRosette.add(new Apple2KeypadSettingsMenu.KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1));
|
||||
|
||||
JSONArray jsonArray;
|
||||
|
||||
jsonArray = (JSONArray) getJSONPref(PREF_DOMAIN_JOYSTICK, "kpAxisRosetteChars", null);
|
||||
if (jsonArray == null || jsonArray.length() != Apple2KeypadSettingsMenu.ROSETTE_SIZE) {
|
||||
Apple2Activity.logMessage(Apple2Activity.LogType.ERROR, TAG, "Oops, kpAxisRosetteChars is not expected length");
|
||||
} else {
|
||||
for (int i = 0; i < Apple2KeypadSettingsMenu.ROSETTE_SIZE; i++) {
|
||||
Apple2KeypadSettingsMenu.KeyTuple tuple = axisRosette.get(i);
|
||||
tuple.ch = jsonArray.getLong(i);
|
||||
}
|
||||
}
|
||||
|
||||
jsonArray = (JSONArray) getJSONPref(PREF_DOMAIN_JOYSTICK, "kpAxisRosetteScancodes", null);
|
||||
if (jsonArray == null || jsonArray.length() != Apple2KeypadSettingsMenu.ROSETTE_SIZE) {
|
||||
Apple2Activity.logMessage(Apple2Activity.LogType.ERROR, TAG, "Oops, kpAxisRosetteScancodes is not expected length");
|
||||
} else {
|
||||
for (int i = 0; i < Apple2KeypadSettingsMenu.ROSETTE_SIZE; i++) {
|
||||
Apple2KeypadSettingsMenu.KeyTuple tuple = axisRosette.get(i);
|
||||
tuple.scan = jsonArray.getLong(i);
|
||||
}
|
||||
}
|
||||
|
||||
Apple2KeypadSettingsMenu.KeypadPreset.saveAxisRosette(axisRosette);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
// migrate individual keypad button actions to new button rosette actions ...
|
||||
{
|
||||
ArrayList<Apple2KeypadSettingsMenu.KeyTuple> buttRosette = new ArrayList<Apple2KeypadSettingsMenu.KeyTuple>();
|
||||
|
||||
int northChar = getIntJSONPref(PREF_DOMAIN_JOYSTICK, "kpSwipeNorthChar", Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION);
|
||||
int northScan = getIntJSONPref(PREF_DOMAIN_JOYSTICK, "kpSwipeNorthScancode", -1);
|
||||
|
||||
int downChar = getIntJSONPref(PREF_DOMAIN_JOYSTICK, "kpTouchDownChar", Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION);
|
||||
int downScan = getIntJSONPref(PREF_DOMAIN_JOYSTICK, "kpTouchDownScancode", -1);
|
||||
|
||||
int southChar = getIntJSONPref(PREF_DOMAIN_JOYSTICK, "kpSwipeSouthChar", Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION);
|
||||
int southScan = getIntJSONPref(PREF_DOMAIN_JOYSTICK, "kpSwipeSouthScancode", -1);
|
||||
|
||||
if (northScan < 0 && downScan < 0 && southScan < 0) {
|
||||
downChar = Apple2KeyboardSettingsMenu.ICONTEXT_VISUAL_SPACE;
|
||||
downScan = Apple2KeyboardSettingsMenu.SCANCODE_SPACE;
|
||||
}
|
||||
|
||||
buttRosette.add(new Apple2KeypadSettingsMenu.KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1));
|
||||
buttRosette.add(new Apple2KeypadSettingsMenu.KeyTuple(northChar, northScan));
|
||||
buttRosette.add(new Apple2KeypadSettingsMenu.KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1));
|
||||
|
||||
buttRosette.add(new Apple2KeypadSettingsMenu.KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1));
|
||||
buttRosette.add(new Apple2KeypadSettingsMenu.KeyTuple(downChar, downScan));
|
||||
buttRosette.add(new Apple2KeypadSettingsMenu.KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1));
|
||||
|
||||
buttRosette.add(new Apple2KeypadSettingsMenu.KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1));
|
||||
buttRosette.add(new Apple2KeypadSettingsMenu.KeyTuple(southChar, southScan));
|
||||
buttRosette.add(new Apple2KeypadSettingsMenu.KeyTuple(Apple2KeyboardSettingsMenu.ICONTEXT_NONACTION, -1));
|
||||
|
||||
Apple2KeypadSettingsMenu.KeypadPreset.saveButtRosette(buttRosette);
|
||||
}
|
||||
|
||||
JSONObject map = _prefDomain(PREF_DOMAIN_JOYSTICK);
|
||||
map.remove("jsTapDelaySecs");
|
||||
map.remove("kpAxisRosetteChars");
|
||||
map.remove("kpAxisRosetteScancodes");
|
||||
map.remove("kpButtRosetteChars");
|
||||
map.remove("kpButtRosetteScancodes");
|
||||
map.remove("kpSwipeNorthChar");
|
||||
map.remove("kpSwipeNorthScancode");
|
||||
map.remove("kpSwipeSouthChar");
|
||||
map.remove("kpSwipeSouthScancode");
|
||||
map.remove("kpTouchDownChar");
|
||||
map.remove("kpTouchDownScancode");
|
||||
}
|
||||
|
||||
save(activity);
|
||||
|
@ -470,7 +333,7 @@ public class Apple2Preferences {
|
|||
|
||||
StringBuilder jsonString = new StringBuilder();
|
||||
if (!Apple2Utils.readEntireFile(prefsFile, jsonString)) {
|
||||
Log.d(TAG, "Oops, could not read JSON file : " + prefsFile);
|
||||
Apple2Activity.logMessage(Apple2Activity.LogType.DEBUG, TAG, "Oops, could not read JSON file : " + prefsFile);
|
||||
}
|
||||
|
||||
try {
|
||||
|
@ -496,7 +359,7 @@ public class Apple2Preferences {
|
|||
try {
|
||||
jsonString = sSettings.toString(2);
|
||||
} catch (JSONException e) {
|
||||
Log.w(TAG, "Error attempting to pretty-print JSON : " + e);
|
||||
Apple2Activity.logMessage(Apple2Activity.LogType.WARN, TAG, "Error attempting to pretty-print JSON : " + e);
|
||||
ex = e;
|
||||
jsonString = sSettings.toString();
|
||||
}
|
||||
|
|
|
@ -11,15 +11,14 @@
|
|||
|
||||
package org.deadc0de.apple2ix;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.CompoundButton;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.deadc0de.apple2ix.basic.BuildConfig;
|
||||
import org.deadc0de.apple2ix.basic.R;
|
||||
|
@ -162,7 +161,7 @@ public class Apple2SettingsMenu extends Apple2AbstractMenu {
|
|||
|
||||
@Override
|
||||
public void handleSelection(final Apple2Activity activity, final Apple2AbstractMenu settingsMenu, boolean isChecked) {
|
||||
new Apple2JoystickSettingsMenu(activity).show();
|
||||
new Apple2JoystickSettingsMenu(activity, Apple2SettingsMenu.TouchDeviceVariant.JOYSTICK).show();
|
||||
}
|
||||
},
|
||||
KEYPAD_CONFIGURE {
|
||||
|
@ -178,7 +177,7 @@ public class Apple2SettingsMenu extends Apple2AbstractMenu {
|
|||
|
||||
@Override
|
||||
public void handleSelection(final Apple2Activity activity, final Apple2AbstractMenu settingsMenu, boolean isChecked) {
|
||||
new Apple2KeypadSettingsMenu(activity).show();
|
||||
new Apple2KeypadSettingsMenu(activity, Apple2SettingsMenu.TouchDeviceVariant.JOYSTICK_KEYPAD).show();
|
||||
}
|
||||
},
|
||||
KEYBOARD_CONFIGURE {
|
||||
|
@ -248,6 +247,57 @@ public class Apple2SettingsMenu extends Apple2AbstractMenu {
|
|||
return convertView;
|
||||
}
|
||||
},
|
||||
FAST_DISK_OPERATIONS {
|
||||
@Override
|
||||
public final String getTitle(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.disk_fast_operation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String getSummary(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.disk_fast_operation_summary);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrefKey() {
|
||||
return "diskFastLoading";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPrefDefault() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(final Apple2Activity activity, View convertView) {
|
||||
final IMenuEnum self = this;
|
||||
convertView = _basicView(activity, this, convertView);
|
||||
CheckBox cb = _addCheckbox(activity, this, convertView, (boolean) Apple2Preferences.getJSONPref(this));
|
||||
cb.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
||||
Apple2Preferences.setJSONPref(self, isChecked);
|
||||
}
|
||||
});
|
||||
return convertView;
|
||||
}
|
||||
},
|
||||
RELEASE_NOTES {
|
||||
@Override
|
||||
public final String getTitle(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.release_notes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String getSummary(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.release_notes_summary);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleSelection(Apple2Activity activity, final Apple2AbstractMenu settingsMenu, boolean isChecked) {
|
||||
activity.showReleaseNotes();
|
||||
}
|
||||
},
|
||||
ABOUT {
|
||||
@Override
|
||||
public final String getTitle(Apple2Activity activity) {
|
||||
|
@ -299,17 +349,33 @@ public class Apple2SettingsMenu extends Apple2AbstractMenu {
|
|||
|
||||
@Override
|
||||
public void handleSelection(final Apple2Activity activity, final Apple2AbstractMenu settingsMenu, boolean isChecked) {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(activity).setIcon(R.drawable.ic_launcher).setCancelable(true).setTitle(R.string.preferences_reset_really).setMessage(R.string.preferences_reset_warning).setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(activity).setIcon(R.drawable.ic_launcher).setCancelable(true).setTitle(R.string.preferences_reset_really).setMessage(R.string.preferences_reset_warning).setPositiveButton(R.string.reset, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
dialog.dismiss();
|
||||
Apple2Preferences.reset(activity);
|
||||
}
|
||||
}).setNegativeButton(R.string.no, null);
|
||||
});
|
||||
AlertDialog dialog = builder.create();
|
||||
activity.registerAndShowDialog(dialog);
|
||||
}
|
||||
},
|
||||
EMAIL_LOGS {
|
||||
@Override
|
||||
public final String getTitle(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.preferences_email_logs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String getSummary(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.preferences_email_logs_summary);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleSelection(final Apple2Activity activity, final Apple2AbstractMenu settingsMenu, boolean isChecked) {
|
||||
Apple2CrashHandler.getInstance().emailCrashesAndLogs(activity);
|
||||
}
|
||||
},
|
||||
CRASH {
|
||||
@Override
|
||||
public final String getTitle(Apple2Activity activity) {
|
||||
|
@ -375,7 +441,7 @@ public class Apple2SettingsMenu extends Apple2AbstractMenu {
|
|||
activity.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Log.d(TAG, "About to NPE : " + str[0].length());
|
||||
Apple2Activity.logMessage(Apple2Activity.LogType.DEBUG, TAG, "About to NPE : " + str[0].length());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -11,9 +11,9 @@
|
|||
|
||||
package org.deadc0de.apple2ix;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
|
@ -50,13 +50,13 @@ public class Apple2SplashScreen implements Apple2MenuView {
|
|||
prefsButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(mActivity).setIcon(R.drawable.ic_launcher).setCancelable(true).setTitle(R.string.preferences_reset_really).setMessage(R.string.preferences_reset_warning).setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(mActivity).setIcon(R.drawable.ic_launcher).setCancelable(true).setTitle(R.string.preferences_reset_really).setMessage(R.string.preferences_reset_warning).setPositiveButton(R.string.reset, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
dialog.dismiss();
|
||||
Apple2Preferences.reset(mActivity);
|
||||
}
|
||||
}).setNegativeButton(R.string.no, null);
|
||||
});
|
||||
AlertDialog dialog = builder.create();
|
||||
mActivity.registerAndShowDialog(dialog);
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ package org.deadc0de.apple2ix;
|
|||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.res.AssetManager;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Environment;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
|
@ -22,6 +23,8 @@ import android.widget.ProgressBar;
|
|||
import org.deadc0de.apple2ix.basic.BuildConfig;
|
||||
import org.deadc0de.apple2ix.basic.R;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
|
@ -35,6 +38,8 @@ import java.io.InputStream;
|
|||
import java.io.InterruptedIOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
public class Apple2Utils {
|
||||
|
||||
|
@ -61,7 +66,7 @@ public class Apple2Utils {
|
|||
} catch (InterruptedIOException ie) {
|
||||
/* EINTR, EAGAIN ... */
|
||||
} catch (IOException e) {
|
||||
Log.d(TAG, "Error reading file at path : " + file.toString());
|
||||
Apple2Activity.logMessage(Apple2Activity.LogType.DEBUG, TAG, "Error reading file at path : " + file.toString());
|
||||
}
|
||||
|
||||
try {
|
||||
|
@ -89,7 +94,7 @@ public class Apple2Utils {
|
|||
} catch (InterruptedIOException ie) {
|
||||
/* EINTR, EAGAIN ... */
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Exception attempting to write data : " + e);
|
||||
Apple2Activity.logMessage(Apple2Activity.LogType.ERROR, TAG, "Exception attempting to write data : " + e);
|
||||
}
|
||||
|
||||
try {
|
||||
|
@ -103,6 +108,93 @@ public class Apple2Utils {
|
|||
return attempts < maxAttempts;
|
||||
}
|
||||
|
||||
public static File zipFiles(File[] files, File zipFile) {
|
||||
|
||||
zipFile.delete();
|
||||
ZipOutputStream out = null;
|
||||
|
||||
do {
|
||||
try {
|
||||
zipFile.createNewFile();
|
||||
} catch (IOException ioe) {
|
||||
Apple2Activity.logMessage(Apple2Activity.LogType.ERROR, TAG, "Could not create zipfile " + zipFile.getAbsolutePath() + " : " + ioe.getMessage());
|
||||
break;
|
||||
}
|
||||
|
||||
final int BUF_SIZ = 4096;
|
||||
BufferedInputStream origin = null;
|
||||
|
||||
try {
|
||||
out = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(zipFile)));
|
||||
} catch (IOException ioe) {
|
||||
Apple2Activity.logMessage(Apple2Activity.LogType.ERROR, TAG, "Could not create zip outputStream : " + ioe.getMessage());
|
||||
break;
|
||||
}
|
||||
|
||||
byte data[] = new byte[BUF_SIZ];
|
||||
|
||||
for (File file : files) {
|
||||
FileInputStream fi = null;
|
||||
|
||||
try {
|
||||
fi = new FileInputStream(file);
|
||||
} catch (IOException ioe) {
|
||||
Apple2Activity.logMessage(Apple2Activity.LogType.ERROR, TAG, "Could not create file input stream : " + ioe.getMessage());
|
||||
continue;
|
||||
}
|
||||
|
||||
origin = new BufferedInputStream(fi, BUF_SIZ);
|
||||
|
||||
ZipEntry entry = new ZipEntry(file.getName());
|
||||
try {
|
||||
out.putNextEntry(entry);
|
||||
} catch (IOException ioe) {
|
||||
Apple2Activity.logMessage(Apple2Activity.LogType.ERROR, TAG, "Could not put next zip entry : " + ioe.getMessage());
|
||||
continue;
|
||||
}
|
||||
|
||||
final int maxAttempts = 5;
|
||||
int attempts = 0;
|
||||
do {
|
||||
int count;
|
||||
try {
|
||||
while ((count = origin.read(data, 0, BUF_SIZ)) != -1) {
|
||||
out.write(data, 0, count);
|
||||
}
|
||||
break;
|
||||
} catch (InterruptedIOException ie) {
|
||||
/* EINTR, EAGAIN ... */
|
||||
} catch (IOException ioe) {
|
||||
Apple2Activity.logMessage(Apple2Activity.LogType.ERROR, TAG, "Could read/write zip data : " + ioe.getMessage());
|
||||
break;
|
||||
}
|
||||
++attempts;
|
||||
} while (attempts < maxAttempts);
|
||||
|
||||
try {
|
||||
origin.close();
|
||||
} catch (IOException ioe) {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
} while (false);
|
||||
|
||||
if (out != null) {
|
||||
try {
|
||||
out.close();
|
||||
} catch (IOException ioe) {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
|
||||
if (zipFile.exists()) {
|
||||
return zipFile;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public static void migrateToExternalStorage(Apple2Activity activity) {
|
||||
|
||||
do {
|
||||
|
@ -182,7 +274,7 @@ public class Apple2Utils {
|
|||
if (!externalDir.exists()) {
|
||||
boolean made = externalDir.mkdirs();
|
||||
if (!made) {
|
||||
Log.d(TAG, "WARNING: could not make directory : " + sExternalFilesDir);
|
||||
Apple2Activity.logMessage(Apple2Activity.LogType.DEBUG, TAG, "WARNING: could not make directory : " + sExternalFilesDir);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -218,7 +310,7 @@ public class Apple2Utils {
|
|||
PackageInfo pi = pm.getPackageInfo(activity.getPackageName(), 0);
|
||||
sDataDir = pi.applicationInfo.dataDir;
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
Log.e(TAG, "" + e);
|
||||
Apple2Activity.logMessage(Apple2Activity.LogType.ERROR, TAG, "" + e);
|
||||
if (sDataDir == null) {
|
||||
sDataDir = "/data/local/tmp";
|
||||
}
|
||||
|
@ -227,7 +319,7 @@ public class Apple2Utils {
|
|||
return sDataDir;
|
||||
}
|
||||
|
||||
public static void exposeAPKAssetsToExternal(Apple2Activity activity) {
|
||||
public static void exposeAPKAssetsToExternal(final Apple2Activity activity) {
|
||||
getExternalStorageDirectory(activity);
|
||||
if (sExternalFilesDir == null) {
|
||||
return;
|
||||
|
@ -240,29 +332,34 @@ public class Apple2Utils {
|
|||
try {
|
||||
bar.setVisibility(View.VISIBLE);
|
||||
bar.setIndeterminate(true);
|
||||
|
||||
AsyncTask.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Log.v(TAG, "Overwriting system files in /sdcard/apple2ix/ (external storage) ...");
|
||||
recursivelyCopyAPKAssets(activity, /*from APK directory:*/"keyboards", /*to location:*/sExternalFilesDir.getAbsolutePath(), false);
|
||||
|
||||
activity.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
bar.setVisibility(View.INVISIBLE);
|
||||
bar.setIndeterminate(false);
|
||||
} catch (NullPointerException npe) {
|
||||
Log.v(TAG, "Avoid NPE in exposeAPKAssetsToExternal #2");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
} catch (NullPointerException npe) {
|
||||
Log.v(TAG, "Avoid NPE in exposeAPKAssetsToExternal #1");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Log.v(TAG, "Overwriting system files in /sdcard/apple2ix/ (external storage) ...");
|
||||
recursivelyCopyAPKAssets(activity, /*from APK directory:*/"keyboards", /*to location:*/sExternalFilesDir.getAbsolutePath(), false);
|
||||
|
||||
activity.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
bar.setVisibility(View.INVISIBLE);
|
||||
bar.setIndeterminate(false);
|
||||
} catch (NullPointerException npe) {
|
||||
Log.v(TAG, "Avoid NPE in exposeAPKAssetsToExternal #2");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void exposeAPKAssets(Apple2Activity activity) {
|
||||
public static void exposeAPKAssets(final Apple2Activity activity) {
|
||||
final ProgressBar bar = (ProgressBar) activity.findViewById(R.id.crash_progressBar);
|
||||
activity.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
|
@ -270,39 +367,45 @@ public class Apple2Utils {
|
|||
try {
|
||||
bar.setVisibility(View.VISIBLE);
|
||||
bar.setIndeterminate(true);
|
||||
|
||||
AsyncTask.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
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"));
|
||||
|
||||
Apple2Activity.logMessage(Apple2Activity.LogType.DEBUG, 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(), 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
|
||||
public void run() {
|
||||
try {
|
||||
bar.setVisibility(View.INVISIBLE);
|
||||
bar.setIndeterminate(false);
|
||||
} catch (NullPointerException npe) {
|
||||
Log.v(TAG, "Avoid NPE in exposeAPKAssets #1");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
} catch (NullPointerException npe) {
|
||||
Log.v(TAG, "Avoid NPE in exposeAPKAssets #1");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
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(), 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
|
||||
public void run() {
|
||||
try {
|
||||
bar.setVisibility(View.INVISIBLE);
|
||||
bar.setIndeterminate(false);
|
||||
} catch (NullPointerException npe) {
|
||||
Log.v(TAG, "Avoid NPE in exposeAPKAssets #1");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void exposeSymbols(Apple2Activity activity) {
|
||||
|
@ -316,12 +419,15 @@ public class Apple2Utils {
|
|||
// 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()) {
|
||||
recursivelyDelete(f);
|
||||
File[] files = file.listFiles();
|
||||
if (files != null) {
|
||||
for (File f : files) {
|
||||
recursivelyDelete(f);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!file.delete()) {
|
||||
Log.d(TAG, "Failed to delete file: " + file);
|
||||
Apple2Activity.logMessage(Apple2Activity.LogType.DEBUG, TAG, "Failed to delete file: " + file);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -338,7 +444,7 @@ public class Apple2Utils {
|
|||
} catch (InterruptedIOException e) {
|
||||
/* EINTR, EAGAIN ... */
|
||||
} catch (IOException e) {
|
||||
Log.d(TAG, "OOPS exception attempting to list APK files at : " + srcFileOrDir + " : " + e);
|
||||
Apple2Activity.logMessage(Apple2Activity.LogType.DEBUG, TAG, "OOPS exception attempting to list APK files at : " + srcFileOrDir + " : " + e);
|
||||
}
|
||||
|
||||
try {
|
||||
|
@ -350,7 +456,7 @@ public class Apple2Utils {
|
|||
} while (attempts < maxAttempts);
|
||||
|
||||
if (files == null) {
|
||||
Log.d(TAG, "OOPS, could not list APK assets at : " + srcFileOrDir);
|
||||
Apple2Activity.logMessage(Apple2Activity.LogType.DEBUG, TAG, "OOPS, could not list APK assets at : " + srcFileOrDir);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -359,7 +465,7 @@ public class Apple2Utils {
|
|||
File dstPath = new File(dstFileOrDir);
|
||||
if (!dstPath.mkdirs()) {
|
||||
if (!dstPath.exists()) {
|
||||
Log.d(TAG, "OOPS, could not mkdirs on " + dstPath);
|
||||
Apple2Activity.logMessage(Apple2Activity.LogType.DEBUG, TAG, "OOPS, could not mkdirs on " + dstPath);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -387,7 +493,7 @@ public class Apple2Utils {
|
|||
} catch (InterruptedIOException e) {
|
||||
/* EINTR, EAGAIN */
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Failed to copy asset file: " + srcFileOrDir, e);
|
||||
Apple2Activity.logMessage(Apple2Activity.LogType.ERROR, TAG, "Failed to copy asset file: " + srcFileOrDir + " : " + e.getMessage());
|
||||
} finally {
|
||||
if (is != null) {
|
||||
try {
|
||||
|
@ -462,7 +568,7 @@ public class Apple2Utils {
|
|||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "OOPS : {e}");
|
||||
Apple2Activity.logMessage(Apple2Activity.LogType.ERROR, TAG, "OOPS : {e}");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -478,7 +584,7 @@ public class Apple2Utils {
|
|||
} catch (InterruptedIOException e) {
|
||||
// EINTR, EAGAIN ...
|
||||
} catch (IOException e) {
|
||||
Log.d(TAG, "OOPS exception attempting to copy emulator state file : " + e);
|
||||
Apple2Activity.logMessage(Apple2Activity.LogType.DEBUG, TAG, "OOPS exception attempting to copy emulator state file : " + e);
|
||||
}
|
||||
|
||||
try {
|
||||
|
|
|
@ -56,10 +56,33 @@ public class Apple2VideoSettingsMenu extends Apple2AbstractMenu {
|
|||
return true;
|
||||
}
|
||||
|
||||
public enum HiresColor {
|
||||
BW,
|
||||
COLOR,
|
||||
INTERPOLATED
|
||||
public enum ColorMode {
|
||||
COLOR_MODE_MONO,
|
||||
COLOR_MODE_COLOR,
|
||||
COLOR_MODE_INTERP,
|
||||
COLOR_MODE_COLOR_MONITOR,
|
||||
COLOR_MODE_MONO_TV,
|
||||
COLOR_MODE_COLOR_TV,
|
||||
}
|
||||
|
||||
public enum MonoMode {
|
||||
MONO_MODE_BW,
|
||||
MONO_MODE_GREEN,
|
||||
}
|
||||
|
||||
// must match interface_colorscheme_t
|
||||
public enum DeviceColor {
|
||||
GREEN_ON_BLACK(0),
|
||||
GREEN_ON_BLUE(1), // ...
|
||||
RED_ON_BLACK(2),
|
||||
BLUE_ON_BLACK(3),
|
||||
WHITE_ON_BLACK(4);
|
||||
|
||||
private int val;
|
||||
|
||||
DeviceColor(int val) {
|
||||
this.val = val;
|
||||
}
|
||||
}
|
||||
|
||||
protected enum SETTINGS implements Apple2AbstractMenu.IMenuEnum {
|
||||
|
@ -97,7 +120,7 @@ public class Apple2VideoSettingsMenu extends Apple2AbstractMenu {
|
|||
cb.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
||||
Apple2Preferences.setJSONPref((IMenuEnum)self, isChecked);
|
||||
Apple2Preferences.setJSONPref((IMenuEnum) self, isChecked);
|
||||
applyLandscapeMode(activity);
|
||||
}
|
||||
});
|
||||
|
@ -144,7 +167,7 @@ public class Apple2VideoSettingsMenu extends Apple2AbstractMenu {
|
|||
}
|
||||
}
|
||||
},
|
||||
COLOR_CONFIGURE {
|
||||
COLOR_MODE_CONFIGURE {
|
||||
@Override
|
||||
public final String getTitle(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.color_configure);
|
||||
|
@ -167,7 +190,103 @@ public class Apple2VideoSettingsMenu extends Apple2AbstractMenu {
|
|||
|
||||
@Override
|
||||
public Object getPrefDefault() {
|
||||
return HiresColor.INTERPOLATED.ordinal();
|
||||
return ColorMode.COLOR_MODE_COLOR_TV.ordinal();
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(Apple2Activity activity, View convertView) {
|
||||
convertView = _basicView(activity, this, convertView);
|
||||
_addPopupIcon(activity, this, convertView);
|
||||
return convertView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleSelection(final Apple2Activity activity, final Apple2AbstractMenu settingsMenu, boolean isChecked) {
|
||||
final Apple2AbstractMenu.IMenuEnum self = this;
|
||||
_alertDialogHandleSelection(activity, R.string.video_configure, new String[]{
|
||||
settingsMenu.mActivity.getResources().getString(R.string.color_mono),
|
||||
settingsMenu.mActivity.getResources().getString(R.string.color_color),
|
||||
settingsMenu.mActivity.getResources().getString(R.string.color_interpolated),
|
||||
settingsMenu.mActivity.getResources().getString(R.string.color_monitor),
|
||||
settingsMenu.mActivity.getResources().getString(R.string.color_tv_mono),
|
||||
settingsMenu.mActivity.getResources().getString(R.string.color_tv),
|
||||
}, new IPreferenceLoadSave() {
|
||||
@Override
|
||||
public int intValue() {
|
||||
return (int) Apple2Preferences.getJSONPref(self);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveInt(int value) {
|
||||
Apple2Preferences.setJSONPref(self, ColorMode.values()[value].ordinal());
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
SHOW_HALF_SCANLINES {
|
||||
@Override
|
||||
public final String getTitle(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.show_half_scanlines);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String getSummary(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.show_half_scanlines_summary);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrefDomain() {
|
||||
return Apple2Preferences.PREF_DOMAIN_VIDEO;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrefKey() {
|
||||
return "showHalfScanlines";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPrefDefault() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(final Apple2Activity activity, View convertView) {
|
||||
final IMenuEnum self = this;
|
||||
convertView = _basicView(activity, this, convertView);
|
||||
CheckBox cb = _addCheckbox(activity, this, convertView, (boolean) Apple2Preferences.getJSONPref(this));
|
||||
cb.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
||||
Apple2Preferences.setJSONPref(self, isChecked);
|
||||
}
|
||||
});
|
||||
return convertView;
|
||||
}
|
||||
},
|
||||
MONO_MODE_CONFIGURE {
|
||||
@Override
|
||||
public final String getTitle(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.mono_configure);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String getSummary(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.mono_configure_summary);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrefDomain() {
|
||||
return Apple2Preferences.PREF_DOMAIN_VIDEO;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrefKey() {
|
||||
return "monoMode";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPrefDefault() {
|
||||
return MonoMode.MONO_MODE_BW.ordinal();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -182,8 +301,7 @@ public class Apple2VideoSettingsMenu extends Apple2AbstractMenu {
|
|||
final Apple2AbstractMenu.IMenuEnum self = this;
|
||||
_alertDialogHandleSelection(activity, R.string.video_configure, new String[]{
|
||||
settingsMenu.mActivity.getResources().getString(R.string.color_bw),
|
||||
settingsMenu.mActivity.getResources().getString(R.string.color_color),
|
||||
settingsMenu.mActivity.getResources().getString(R.string.color_interpolated),
|
||||
settingsMenu.mActivity.getResources().getString(R.string.color_green),
|
||||
}, new IPreferenceLoadSave() {
|
||||
@Override
|
||||
public int intValue() {
|
||||
|
@ -192,7 +310,83 @@ public class Apple2VideoSettingsMenu extends Apple2AbstractMenu {
|
|||
|
||||
@Override
|
||||
public void saveInt(int value) {
|
||||
Apple2Preferences.setJSONPref(self, HiresColor.values()[value].ordinal());
|
||||
Apple2Preferences.setJSONPref(self, MonoMode.values()[value].ordinal());
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
COLOR_DEVICE_CONFIGURE {
|
||||
@Override
|
||||
public final String getTitle(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.touch_device_color);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String getSummary(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.touch_device_color_summary);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrefDomain() {
|
||||
return Apple2Preferences.PREF_DOMAIN_INTERFACE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrefKey() {
|
||||
return "hudColorMode";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPrefDefault() {
|
||||
return DeviceColor.RED_ON_BLACK.ordinal();
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(Apple2Activity activity, View convertView) {
|
||||
convertView = _basicView(activity, this, convertView);
|
||||
_addPopupIcon(activity, this, convertView);
|
||||
return convertView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleSelection(final Apple2Activity activity, final Apple2AbstractMenu settingsMenu, boolean isChecked) {
|
||||
final Apple2AbstractMenu.IMenuEnum self = this;
|
||||
_alertDialogHandleSelection(activity, R.string.touch_device_color_configure, new String[]{
|
||||
settingsMenu.mActivity.getResources().getString(R.string.color_red_on_black),
|
||||
settingsMenu.mActivity.getResources().getString(R.string.color_green_on_black),
|
||||
settingsMenu.mActivity.getResources().getString(R.string.color_blue_on_black),
|
||||
settingsMenu.mActivity.getResources().getString(R.string.color_white_on_black),
|
||||
}, new IPreferenceLoadSave() {
|
||||
@Override
|
||||
public int intValue() {
|
||||
int colorscheme = (int) Apple2Preferences.getJSONPref(self);
|
||||
if (colorscheme == DeviceColor.GREEN_ON_BLACK.ordinal()) {
|
||||
return 1;
|
||||
} else if (colorscheme == DeviceColor.BLUE_ON_BLACK.ordinal()) {
|
||||
return 2;
|
||||
} else if (colorscheme == DeviceColor.WHITE_ON_BLACK.ordinal()) {
|
||||
return 3;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveInt(int value) {
|
||||
switch (value) {
|
||||
case 1:
|
||||
Apple2Preferences.setJSONPref(self, (int) DeviceColor.GREEN_ON_BLACK.ordinal());
|
||||
break;
|
||||
case 2:
|
||||
Apple2Preferences.setJSONPref(self, (int) DeviceColor.BLUE_ON_BLACK.ordinal());
|
||||
break;
|
||||
case 3:
|
||||
Apple2Preferences.setJSONPref(self, (int) DeviceColor.WHITE_ON_BLACK.ordinal());
|
||||
break;
|
||||
default:
|
||||
Apple2Preferences.setJSONPref(self, (int) DeviceColor.RED_ON_BLACK.ordinal());
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -230,8 +424,8 @@ public class Apple2VideoSettingsMenu extends Apple2AbstractMenu {
|
|||
return false;
|
||||
} else {
|
||||
int orientation = activity.getRequestedOrientation();
|
||||
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
|
||||
return orientation != ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
|
||||
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT);
|
||||
return orientation != ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@ import android.util.Log;
|
|||
import android.view.InputDevice;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.ViewTreeObserver;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
|
||||
import com.example.inputmanagercompat.InputManagerCompat;
|
||||
|
||||
|
@ -42,6 +43,7 @@ class Apple2View extends GLSurfaceView implements InputManagerCompat.InputDevice
|
|||
|
||||
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_REQUEST_SHOW_SYSTEM_KBD = (1 << 2);
|
||||
|
||||
public final static long NATIVE_TOUCH_KEY_TAP = (1 << 4);
|
||||
public final static long NATIVE_TOUCH_KBD = (1 << 5);
|
||||
|
@ -134,7 +136,7 @@ class Apple2View extends GLSurfaceView implements InputManagerCompat.InputDevice
|
|||
private static int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
|
||||
|
||||
public EGLContext createContext(EGL10 egl, EGLDisplay display, EGLConfig eglConfig) {
|
||||
Log.w(TAG, "creating OpenGL ES 2.0 context");
|
||||
Apple2Activity.logMessage(Apple2Activity.LogType.WARN, TAG, "creating OpenGL ES 2.0 context");
|
||||
checkEglError("Before eglCreateContext", egl);
|
||||
int[] attrib_list = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE};
|
||||
EGLContext context = egl.eglCreateContext(display, eglConfig, EGL10.EGL_NO_CONTEXT, attrib_list);
|
||||
|
@ -150,7 +152,7 @@ class Apple2View extends GLSurfaceView implements InputManagerCompat.InputDevice
|
|||
private static void checkEglError(String prompt, EGL10 egl) {
|
||||
int error;
|
||||
while ((error = egl.eglGetError()) != EGL10.EGL_SUCCESS) {
|
||||
Log.e(TAG, String.format("%s: EGL error: 0x%x", prompt, error));
|
||||
Apple2Activity.logMessage(Apple2Activity.LogType.ERROR, TAG, String.format("%s: EGL error: 0x%x", prompt, error));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -202,9 +204,9 @@ class Apple2View extends GLSurfaceView implements InputManagerCompat.InputDevice
|
|||
// Now return the "best" one
|
||||
EGLConfig best = chooseConfig(egl, display, configs);
|
||||
if (best == null) {
|
||||
Log.e(TAG, "OOPS! Did not pick an EGLConfig. What device are you using?! Android will now crash this app...");
|
||||
Apple2Activity.logMessage(Apple2Activity.LogType.ERROR, TAG, "OOPS! Did not pick an EGLConfig. What device are you using?! Android will now crash this app...");
|
||||
} else {
|
||||
Log.w(TAG, "Using EGL CONFIG : ");
|
||||
Apple2Activity.logMessage(Apple2Activity.LogType.WARN, TAG, "Using EGL CONFIG : ");
|
||||
printConfig(egl, display, best);
|
||||
}
|
||||
return best;
|
||||
|
@ -243,9 +245,9 @@ class Apple2View extends GLSurfaceView implements InputManagerCompat.InputDevice
|
|||
|
||||
private void printConfigs(EGL10 egl, EGLDisplay display, EGLConfig[] configs) {
|
||||
int numConfigs = configs.length;
|
||||
Log.w(TAG, String.format("%d configurations", numConfigs));
|
||||
Apple2Activity.logMessage(Apple2Activity.LogType.WARN, TAG, String.format("%d configurations", numConfigs));
|
||||
for (int i = 0; i < numConfigs; i++) {
|
||||
Log.w(TAG, String.format("Configuration %d:\n", i));
|
||||
Apple2Activity.logMessage(Apple2Activity.LogType.WARN, TAG, String.format("Configuration %d:\n", i));
|
||||
printConfig(egl, display, configs[i]);
|
||||
}
|
||||
}
|
||||
|
@ -326,9 +328,9 @@ class Apple2View extends GLSurfaceView implements InputManagerCompat.InputDevice
|
|||
int attribute = attributes[i];
|
||||
String name = names[i];
|
||||
if (egl.eglGetConfigAttrib(display, config, attribute, value)) {
|
||||
Log.w(TAG, String.format(" %s: %d\n", name, value[0]));
|
||||
Apple2Activity.logMessage(Apple2Activity.LogType.WARN, TAG, String.format(" %s: %d\n", name, value[0]));
|
||||
} else {
|
||||
// Log.w(TAG, String.format(" %s: failed\n", name));
|
||||
// Apple2Activity.logMessage(Apple2Activity.LogType.WARN, TAG, String.format(" %s: failed\n", name));
|
||||
while (egl.eglGetError() != EGL10.EGL_SUCCESS) ;
|
||||
}
|
||||
}
|
||||
|
@ -519,6 +521,16 @@ class Apple2View extends GLSurfaceView implements InputManagerCompat.InputDevice
|
|||
apple2MenuView.onKeyTapCalibrationEvent(ascii, scancode);
|
||||
}
|
||||
}
|
||||
|
||||
if ((nativeFlags & NATIVE_TOUCH_REQUEST_SHOW_SYSTEM_KBD) != 0) {
|
||||
clearFocus();
|
||||
requestFocus();
|
||||
InputMethodManager inputMethodManager = (InputMethodManager) mActivity.getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||
if (inputMethodManager != null) {
|
||||
inputMethodManager.showSoftInput(this, InputMethodManager.SHOW_FORCED);
|
||||
}
|
||||
}
|
||||
|
||||
} while (false);
|
||||
|
||||
return true;
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="?android:attr/listPreferredItemHeight"
|
||||
android:minHeight="?attr/listPreferredItemHeight"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingRight="?android:attr/scrollbarSize">
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:background="@color/black"
|
||||
android:baselineAligned="false"
|
||||
android:orientation="vertical">
|
||||
|
||||
|
@ -16,6 +15,8 @@
|
|||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:layout_marginStart="40dp"
|
||||
android:layout_marginLeft="40dp"
|
||||
android:text="@string/diskA" />
|
||||
|
||||
<RadioButton
|
||||
|
@ -37,6 +38,8 @@
|
|||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:layout_marginStart="40dp"
|
||||
android:layout_marginLeft="40dp"
|
||||
android:text="@string/disk_read_only" />
|
||||
|
||||
<RadioButton
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="?android:attr/listPreferredItemHeight"
|
||||
android:minHeight="?attr/listPreferredItemHeight"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingRight="?android:attr/scrollbarSize">
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="?android:attr/listPreferredItemHeight"
|
||||
android:minHeight="?attr/listPreferredItemHeight"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingRight="?android:attr/scrollbarSize">
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:background="@color/black"
|
||||
android:baselineAligned="false"
|
||||
android:orientation="vertical">
|
||||
|
||||
|
@ -16,6 +15,8 @@
|
|||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:layout_marginStart="40dp"
|
||||
android:layout_marginLeft="40dp"
|
||||
android:text="@string/reboot" />
|
||||
|
||||
<RadioButton
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginLeft="0dp"
|
||||
android:layout_marginStart="0dp"
|
||||
android:layout_marginRight="0dp"
|
||||
|
@ -20,4 +20,19 @@
|
|||
android:layout_alignParentStart="true"
|
||||
android:layout_marginLeft="0dp"
|
||||
android:layout_marginStart="0dp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/axisCoords"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@+id/seekBar"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_marginStart="@dimen/preference_margin_left"
|
||||
android:layout_marginLeft="@dimen/preference_margin_left"
|
||||
android:layout_marginTop="@dimen/preference_margin_top"
|
||||
android:background="@color/white"
|
||||
android:text="X:255 Y:255"
|
||||
android:textColor="@color/black" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_marginBottom="5dip"
|
||||
|
@ -98,7 +99,7 @@
|
|||
android:ellipsize="marquee"
|
||||
android:fadingEdge="horizontal"
|
||||
android:singleLine="true"
|
||||
android:text="@+string/file_chooser"
|
||||
android:text="@string/file_chooser"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge" />
|
||||
|
||||
<!-- spacer that works with API 10 ... -->
|
||||
|
@ -108,7 +109,7 @@
|
|||
android:layout_weight="1" />
|
||||
|
||||
<ImageView
|
||||
android:src="@android:drawable/ic_menu_save"
|
||||
app:srcCompat="@android:drawable/ic_menu_save"
|
||||
android:layout_gravity="center"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
|
@ -123,7 +124,7 @@
|
|||
android:layout_alignStart="@id/disk_selection_newschool_chooser"
|
||||
android:layout_below="@id/disk_selection_newschool_chooser"
|
||||
android:gravity="center_vertical"
|
||||
android:minHeight="?android:attr/listPreferredItemHeight"
|
||||
android:minHeight="?attr/listPreferredItemHeight"
|
||||
android:paddingLeft="0dp"
|
||||
android:paddingStart="0dp"
|
||||
android:paddingRight="?android:attr/scrollbarSize"
|
||||
|
@ -145,7 +146,7 @@
|
|||
android:ellipsize="marquee"
|
||||
android:fadingEdge="horizontal"
|
||||
android:singleLine="true"
|
||||
android:text="@+string/diskA"
|
||||
android:text="@string/diskA"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge" />
|
||||
|
||||
<TextView
|
||||
|
@ -171,7 +172,7 @@
|
|||
android:layout_alignStart="@id/a2_newschool_driveA_layout"
|
||||
android:layout_below="@id/a2_newschool_driveA_layout"
|
||||
android:gravity="center_vertical"
|
||||
android:minHeight="?android:attr/listPreferredItemHeight"
|
||||
android:minHeight="?attr/listPreferredItemHeight"
|
||||
android:paddingLeft="0dp"
|
||||
android:paddingStart="0dp"
|
||||
android:paddingRight="?android:attr/scrollbarSize"
|
||||
|
@ -192,7 +193,7 @@
|
|||
android:ellipsize="marquee"
|
||||
android:fadingEdge="horizontal"
|
||||
android:singleLine="true"
|
||||
android:text="@+string/diskB"
|
||||
android:text="@string/diskB"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge" />
|
||||
|
||||
<TextView
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/splashScreen"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
|
@ -16,14 +17,14 @@
|
|||
android:layout_height="fill_parent"
|
||||
android:adjustViewBounds="true"
|
||||
android:scaleType="centerCrop"
|
||||
android:src="@drawable/apple_iie"
|
||||
app:srcCompat="@drawable/apple_iie"
|
||||
android:id="@+id/splashView" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/imageView"
|
||||
android:src="@drawable/ic_launcher"
|
||||
app:srcCompat="@drawable/ic_launcher"
|
||||
android:layout_alignTop="@+id/startButton"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_alignParentStart="true"
|
||||
|
|
|
@ -56,7 +56,6 @@
|
|||
<string name="joystick_button_button_none">Keine</string>
|
||||
<string name="joystick_button_tap_button">Drücke den Feuerknopf</string>
|
||||
<string name="joystick_button_tap_button_summary">Ausgewählter Feuerknopf</string>
|
||||
<string name="joystick_button_tapdelay_summary">Joystickknopf-Zeitverzögerung in Sek.</string>
|
||||
<string name="joystick_button_swipe_up_button">Aufwärts wischen zum feuern</string>
|
||||
<string name="joystick_button_swipe_up_button_summary">Feuerknopf zum feuern beim aufwärts wischen</string>
|
||||
<string name="joystick_button_swipe_down_button">Abwärts wischen zum feuern</string>
|
||||
|
@ -97,8 +96,6 @@
|
|||
<string name="keyboard_visibility_inactive">Sichtbarkeit wenn deaktiviert</string>
|
||||
<string name="keyboard_visibility_inactive_summary">Sichtbarkeit des Keyboard und Touch Menüs wenn deaktiviert</string>
|
||||
<string name="keypad">Keypad Joystick</string>
|
||||
<string name="keypad_calibrate">@string/joystick_calibrate</string>
|
||||
<string name="keypad_calibrate_summary">@string/joystick_calibrate</string>
|
||||
<string name="keypad_choose">Auswahl der Keypad Tasten…</string>
|
||||
<string name="keypad_choose_summary">Auswahl der Achsen und Knopf Tasten</string>
|
||||
<string name="keypad_choose_title">Achse & Knöpfe</string>
|
||||
|
@ -117,14 +114,13 @@
|
|||
<string name="keypad_key_button_tap">antippen</string>
|
||||
<string name="keypad_key_button_swipeup">Nach oben wischen</string>
|
||||
<string name="keypad_key_button_swipedown">Nach unten wischen</string>
|
||||
<string name="keypad_preset_crazy_seafox">Seafox Tasten ;-)…</string>
|
||||
<string name="keypad_preset_seafox">Seafox Tasten…</string>
|
||||
<string name="keypad_preset_custom">Auswahl einer Anpassung…</string>
|
||||
<string name="keypad_preset_arrows_space">↑,←,→,↓, tippe auf die Leerstaste</string>
|
||||
<string name="keypad_preset_az_left_right_space">A,Z,←,→, tippe auf die Leertaste</string>
|
||||
<string name="keypad_preset_ijkm_space">I,J,K,M, tippe auf die Leertaste</string>
|
||||
<string name="keypad_preset_left_right_space">←,→, tippe auf die Leertaste</string>
|
||||
<string name="keypad_preset_wadx_space">W,A,D,X, tippe auf die Leertaste</string>
|
||||
<string name="keypad_repeat_summary">Tastenwiederholungsschwellwert in Sek.</string>
|
||||
<string name="keypad_preset_arrows_space">(↑ ← → ↓), tippe auf die Leerstaste</string>
|
||||
<string name="keypad_preset_az_left_right_space">(A Z ← →), tippe auf die Leerstaste</string>
|
||||
<string name="keypad_preset_ijkm_space">(I J K M), tippe auf die Leertaste</string>
|
||||
<string name="keypad_preset_left_right_space">(← →), tippe auf die Leertaste</string>
|
||||
<string name="keypad_preset_wadx_space">(W A D X), tippe auf die Leertaste</string>
|
||||
<string name="menu_disks">Lade Disk-Image…</string>
|
||||
<string name="menu_disks_summary">Einlegen eines Disk ][ Image</string>
|
||||
<string name="menu_settings">Emulator Einstellungen…</string>
|
||||
|
@ -132,7 +128,7 @@
|
|||
<string name="mockingboard_disabled_title">Mockingboard deaktiviert</string>
|
||||
<string name="mockingboard_disabled_mesg">Mockingboard konnte nicht aktiviert werden</string>
|
||||
<string name="mockingboard_enable">Aktiviere Mockingboard</string>
|
||||
<string name="mockingboard_enable_summary">Revision C in Slot 4/5 (evtl. wird ein Restart benötigt)</string>
|
||||
<string name="mockingboard_enable_summary">Revision C in Slot 4/5 (evtl. wird ein Restart benötigt) (may consume extra battery)</string>
|
||||
<string name="mockingboard_volume">Mockingboard Lautstärke</string>
|
||||
<string name="mockingboard_volume_summary">Einstellen der Mockingboard Lautstärke</string>
|
||||
<string name="no">Nein</string>
|
||||
|
@ -143,7 +139,7 @@
|
|||
<string name="preferences_reset_warning">Sie werden alle Ihre Einstellungen verlieren</string>
|
||||
<string name="quit">Beenden</string>
|
||||
<string name="quit_reboot">Neustart oder beenden des Emulators…</string>
|
||||
<string name="quit_reboot_choice">Neustart oder beenden?</string>
|
||||
<string name="quit_reboot_choice">Neustart oder beenden?                                    …</string>
|
||||
<string name="reboot">Neustart</string>
|
||||
<string name="restore">Schnelle Wiederherstellung</string>
|
||||
<string name="save">Schnelle Speicherung</string>
|
||||
|
@ -162,8 +158,8 @@
|
|||
<string name="touch_menu_enable_summary">Aktiviere Softmenü Knöpfe in den oberen Ecken des Bildschirms</string>
|
||||
<string name="video_configure">Video-Konfiguration…</string>
|
||||
<string name="video_configure_summary">Farbeinstellungen</string>
|
||||
<string name="color_configure">Configure color</string>
|
||||
<string name="color_configure_summary">Color mode</string>
|
||||
<string name="color_configure">Video display mode</string>
|
||||
<string name="color_configure_summary">Video display emulation mode</string>
|
||||
<string name="joystick_azimuth_visible">Show joystick/keypad heading</string>
|
||||
<string name="joystick_azimuth_visible_summary">Shows current axis direction and magnitude</string>
|
||||
<string name="mode_landscape">Landscape</string>
|
||||
|
@ -179,5 +175,47 @@
|
|||
<string name="reset_preferences">Reset settings</string>
|
||||
<string name="reset_self_test">Self Test</string>
|
||||
<string name="reset_soft">Soft</string>
|
||||
<string name="touch_device_color">Configure touch device color</string>
|
||||
<string name="touch_device_color_summary">Configure color of HUD elements</string>
|
||||
<string name="state_not_restored">Error restoring state…</string>
|
||||
<string name="storage">/storage/</string>
|
||||
<string name="touch_device_color_configure">Configure HUD color…</string>
|
||||
<string name="color_red_on_black">Red on black</string>
|
||||
<string name="color_green_on_black">Green on black</string>
|
||||
<string name="color_blue_on_black">Blue on black</string>
|
||||
<string name="color_white_on_black">White on black</string>
|
||||
<string name="color_monitor">Color Monitor</string>
|
||||
<string name="color_tv_mono">Monochrome TV</string>
|
||||
<string name="color_tv">Color TV</string>
|
||||
<string name="show_half_scanlines">Show half scanlines</string>
|
||||
<string name="mono_configure">Monocolor mode</string>
|
||||
<string name="mono_configure_summary">Configure monochrome color</string>
|
||||
<string name="color_green">Green screen</string>
|
||||
<string name="color_mono">Monochrome</string>
|
||||
<string name="disk_fast_operation">Disk fast loading (EXPERIMENTAL)</string>
|
||||
<string name="disk_fast_operation_summary">Quickly load disk images (may negatively affect device battery life)</string>
|
||||
<string name="show_half_scanlines_summary">Renders pixel vertical divisions</string>
|
||||
<string name="release_notes">Release notes</string>
|
||||
<string name="release_notes_summary">View notes for this release</string>
|
||||
<string name="keyboard_duotouch_enabled">Enable dual-touch</string>
|
||||
<string name="keyboard_duotouch_enabled_summary">Support two-thumb input</string>
|
||||
<string name="keypad_preset_qaz_left_right_space">(A Z ← →), Leertaste, Q</string>
|
||||
<string name="keypad_tapdelay_summary">Keypad touch down delay in secs</string>
|
||||
<string name="keypad_autorepeat_fast_summary">Allows immediate auto-repeat (avoids original 534-801 millis delay)</string>
|
||||
<string name="keypad_autorepeat_fast">Keypad Immediate Autorepeat</string>
|
||||
<string name="string_frames">Frames</string>
|
||||
<string name="string_millis">Millis</string>
|
||||
<string name="joystick_button_tapdelay_summary">Joystick touch down delay in video frames</string>
|
||||
<string name="keypad_preset_robotron">Robotron Tasten…</string>
|
||||
<string name="keypad_preset_loderunner">Lode Runner Tasten…</string>
|
||||
<string name="keypad_preset_loderunner_toast">Start game with Ctrl-K to activate keyboard</string>
|
||||
<string name="joystick_button_swipe_left_button">Swipe left fire</string>
|
||||
<string name="joystick_button_swipe_right_button">Swipe right fire</string>
|
||||
<string name="joystick_button_swipe_left_button_summary">Button to fire on swipe left</string>
|
||||
<string name="joystick_button_swipe_right_button_summary">Button to fire on swipe right</string>
|
||||
<string name="key_del">[DEL]</string>
|
||||
<string name="key_tab">[TAB]</string>
|
||||
<string name="preferences_email_logs">Email logs</string>
|
||||
<string name="preferences_email_logs_summary">Email logs to developer…</string>
|
||||
|
||||
</resources>
|
||||
|
|
|
@ -56,7 +56,6 @@
|
|||
<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>
|
||||
|
@ -95,8 +94,6 @@
|
|||
<string name="keyboard_visibility_inactive">Visibilidad cuando está inactivo</string>
|
||||
<string name="keyboard_visibility_inactive_summary">Visibilidad del teclado y menú 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>
|
||||
|
@ -115,14 +112,13 @@
|
|||
<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_seafox">Tecla para Seafox…</string>
|
||||
<string name="keypad_preset_custom">Elija personalizado…</string>
|
||||
<string name="keypad_preset_arrows_space">↑,←,→,↓, pulse espaciadora</string>
|
||||
<string name="keypad_preset_az_left_right_space">A,Z,←,→, pulse espaciadora</string>
|
||||
<string name="keypad_preset_ijkm_space">I,J,K,M, pulse espaciadora</string>
|
||||
<string name="keypad_preset_left_right_space">←,→, 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="keypad_preset_arrows_space">(↑ ← → ↓), pulse barra espaciadora</string>
|
||||
<string name="keypad_preset_az_left_right_space">(A Z ← →), pulse barra espaciadora</string>
|
||||
<string name="keypad_preset_ijkm_space">(I J K M), pulse barra espaciadora</string>
|
||||
<string name="keypad_preset_left_right_space">(← →), pulse barra espaciadora</string>
|
||||
<string name="keypad_preset_wadx_space">(W A D X), pulse barra espaciadora</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>
|
||||
|
@ -130,7 +126,7 @@
|
|||
<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_enable_summary">Revisión C en Slot 4/5 (puede requerir reinicio) (may consume extra battery)</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>
|
||||
|
@ -141,7 +137,7 @@
|
|||
<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="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>
|
||||
|
@ -160,8 +156,8 @@
|
|||
<string name="touch_menu_enable_summary">Los botones del menú en la parte superior de la pantalla</string>
|
||||
<string name="video_configure">Configurar el video…</string>
|
||||
<string name="video_configure_summary">Ajustes de color</string>
|
||||
<string name="color_configure">Configure color</string>
|
||||
<string name="color_configure_summary">Color mode</string>
|
||||
<string name="color_configure">Video display mode</string>
|
||||
<string name="color_configure_summary">Video display emulation mode</string>
|
||||
<string name="joystick_azimuth_visible">Show joystick/keypad heading</string>
|
||||
<string name="joystick_azimuth_visible_summary">Shows current axis direction and magnitude</string>
|
||||
<string name="mode_landscape">Landscape</string>
|
||||
|
@ -179,5 +175,47 @@
|
|||
<string name="reset_preferences">Reset settings</string>
|
||||
<string name="reset_self_test">Self Test</string>
|
||||
<string name="reset_soft">Soft</string>
|
||||
<string name="touch_device_color">Configure touch device color</string>
|
||||
<string name="touch_device_color_summary">Configure color of HUD elements</string>
|
||||
<string name="state_not_restored">Error restoring state…</string>
|
||||
<string name="storage">/storage/</string>
|
||||
<string name="touch_device_color_configure">Configure HUD color…</string>
|
||||
<string name="color_red_on_black">Red on black</string>
|
||||
<string name="color_green_on_black">Green on black</string>
|
||||
<string name="color_blue_on_black">Blue on black</string>
|
||||
<string name="color_white_on_black">White on black</string>
|
||||
<string name="color_monitor">Color Monitor</string>
|
||||
<string name="color_tv_mono">Monochrome TV</string>
|
||||
<string name="color_tv">Color TV</string>
|
||||
<string name="show_half_scanlines">Show half scanlines</string>
|
||||
<string name="mono_configure">Monocolor mode</string>
|
||||
<string name="mono_configure_summary">Configure monochrome color</string>
|
||||
<string name="color_green">Green screen</string>
|
||||
<string name="color_mono">Monochrome</string>
|
||||
<string name="disk_fast_operation">Disk fast loading (EXPERIMENTAL)</string>
|
||||
<string name="disk_fast_operation_summary">Quickly load disk images (may negatively affect device battery life)</string>
|
||||
<string name="show_half_scanlines_summary">Renders pixel vertical divisions</string>
|
||||
<string name="release_notes">Release notes</string>
|
||||
<string name="release_notes_summary">View notes for this release</string>
|
||||
<string name="keyboard_duotouch_enabled">Enable dual-touch</string>
|
||||
<string name="keyboard_duotouch_enabled_summary">Support two-thumb input</string>
|
||||
<string name="keypad_preset_qaz_left_right_space">(A Z ← →), barra espaciadora, Q</string>
|
||||
<string name="keypad_tapdelay_summary">Keypad touch down delay in secs</string>
|
||||
<string name="keypad_autorepeat_fast_summary">Allows immediate auto-repeat (avoids original 534-801 millis delay)</string>
|
||||
<string name="keypad_autorepeat_fast">Keypad Immediate Autorepeat</string>
|
||||
<string name="string_frames">Frames</string>
|
||||
<string name="string_millis">Millis</string>
|
||||
<string name="joystick_button_tapdelay_summary">Joystick touch down delay in video frames</string>
|
||||
<string name="keypad_preset_robotron">Tecla para Robotron…</string>
|
||||
<string name="keypad_preset_loderunner">Lode Runner keys…</string>
|
||||
<string name="keypad_preset_loderunner_toast">Start game with Ctrl-K to activate keyboard</string>
|
||||
<string name="joystick_button_swipe_left_button">Swipe left fire</string>
|
||||
<string name="joystick_button_swipe_right_button">Swipe right fire</string>
|
||||
<string name="joystick_button_swipe_left_button_summary">Button to fire on swipe left</string>
|
||||
<string name="joystick_button_swipe_right_button_summary">Button to fire on swipe right</string>
|
||||
<string name="key_del">[DEL]</string>
|
||||
<string name="key_tab">[TAB]</string>
|
||||
<string name="preferences_email_logs">Email logs</string>
|
||||
<string name="preferences_email_logs_summary">Email logs to developer…</string>
|
||||
|
||||
</resources>
|
||||
|
|
|
@ -56,7 +56,6 @@
|
|||
<string name="joystick_button_button_none">Rien</string>
|
||||
<string name="joystick_button_tap_button">Sélectionner l\'action</string>
|
||||
<string name="joystick_button_tap_button_summary">Bouton à activer lors d\'une pression vers le bas</string>
|
||||
<string name="joystick_button_tapdelay_summary">Délai de pression du bouton Joystick en secondes</string>
|
||||
<string name="joystick_button_swipe_up_button">Lancement du swipe up</string>
|
||||
<string name="joystick_button_swipe_up_button_summary">Bouton à lancer sur swipe up</string>
|
||||
<string name="joystick_button_swipe_down_button">Lancement du swipe down</string>
|
||||
|
@ -95,8 +94,6 @@
|
|||
<string name="keyboard_visibility_inactive">Visibilité quand inactif</string>
|
||||
<string name="keyboard_visibility_inactive_summary">Clavier et menu tactile visible quand inactif</string>
|
||||
<string name="keypad">Keypad Joystick</string>
|
||||
<string name="keypad_calibrate">@string/joystick_calibrate</string>
|
||||
<string name="keypad_calibrate_summary">@string/joystick_calibrate</string>
|
||||
<string name="keypad_choose">Sélection des touches du keypad…</string>
|
||||
<string name="keypad_choose_summary">Sélection des touches pour les axes et boutons</string>
|
||||
<string name="keypad_choose_title">Axis & boutons</string>
|
||||
|
@ -115,14 +112,13 @@
|
|||
<string name="keypad_key_button_tap">Presser</string>
|
||||
<string name="keypad_key_button_swipeup">Slider vers le haut</string>
|
||||
<string name="keypad_key_button_swipedown">Slider vers le bas</string>
|
||||
<string name="keypad_preset_crazy_seafox">Touches Seafox ;-)…</string>
|
||||
<string name="keypad_preset_seafox">Touches Seafox…</string>
|
||||
<string name="keypad_preset_custom">Choisir customisation…</string>
|
||||
<string name="keypad_preset_arrows_space">↑,←,→,↓, pressez barre d\'espace</string>
|
||||
<string name="keypad_preset_az_left_right_space">A,Z,←,→, pressez barre d\'espace</string>
|
||||
<string name="keypad_preset_ijkm_space">I,J,K,M, pressez barre d\'espace</string>
|
||||
<string name="keypad_preset_left_right_space">←,→, pressez barre d\'espace</string>
|
||||
<string name="keypad_preset_wadx_space">W,A,D,X, pressez barre d\'espace</string>
|
||||
<string name="keypad_repeat_summary">Répétition des touches en secs</string>
|
||||
<string name="keypad_preset_arrows_space">(↑ ← → ↓), pressez barre d\'espace</string>
|
||||
<string name="keypad_preset_az_left_right_space">(A Z ← →), pressez barre d\'espace</string>
|
||||
<string name="keypad_preset_ijkm_space">(I J K M), pressez barre d\'espace</string>
|
||||
<string name="keypad_preset_left_right_space">(← →), pressez barre d\'espace</string>
|
||||
<string name="keypad_preset_wadx_space">(W A D X), pressez barre d\'espace</string>
|
||||
<string name="menu_disks">Chargement de l\'image disque…</string>
|
||||
<string name="menu_disks_summary">Insérer un fichier image (disque) ][</string>
|
||||
<string name="menu_settings">Paramètres de l\'émulateur…</string>
|
||||
|
@ -130,7 +126,7 @@
|
|||
<string name="mockingboard_disabled_title">Mockingboard désactivé</string>
|
||||
<string name="mockingboard_disabled_mesg">Le Mockingboard ne peut être activé</string>
|
||||
<string name="mockingboard_enable">Activer le Mockingboard</string>
|
||||
<string name="mockingboard_enable_summary">Révision C dans Slot 4/5 (redémarrage possible)</string>
|
||||
<string name="mockingboard_enable_summary">Révision C dans Slot 4/5 (redémarrage possible) (may consume extra battery)</string>
|
||||
<string name="mockingboard_volume">Volume du Mockingboard</string>
|
||||
<string name="mockingboard_volume_summary">Placer le volume du Mockingboard</string>
|
||||
<string name="no">Non</string>
|
||||
|
@ -141,7 +137,7 @@
|
|||
<string name="preferences_reset_warning">Vous perdrez toutes vos options de configuration</string>
|
||||
<string name="quit">Quitter</string>
|
||||
<string name="quit_reboot">Rebooter ou quitter l\'émulateur…</string>
|
||||
<string name="quit_reboot_choice">Rebooter ou quitter?</string>
|
||||
<string name="quit_reboot_choice">Rebooter ou quitter?                                    …</string>
|
||||
<string name="reboot">Rebooter</string>
|
||||
<string name="restore">Restauration rapide</string>
|
||||
<string name="save">Sauvegarde rapide</string>
|
||||
|
@ -160,8 +156,8 @@
|
|||
<string name="touch_menu_enable_summary">Activation soft des bouton du menu dans les coins en haut de l\'écran</string>
|
||||
<string name="video_configure">Configuration de la vidéo…</string>
|
||||
<string name="video_configure_summary">Configuration des couleurs</string>
|
||||
<string name="color_configure">Configure color</string>
|
||||
<string name="color_configure_summary">Color mode</string>
|
||||
<string name="color_configure">Video display mode</string>
|
||||
<string name="color_configure_summary">Video display emulation mode</string>
|
||||
<string name="joystick_azimuth_visible">Show joystick/keypad heading</string>
|
||||
<string name="joystick_azimuth_visible_summary">Shows current axis direction and magnitude</string>
|
||||
<string name="mode_landscape">Landscape</string>
|
||||
|
@ -179,5 +175,47 @@
|
|||
<string name="reset_self_test">Self Test</string>
|
||||
<string name="reset_preferences">Reset settings</string>
|
||||
<string name="reset_soft">Soft</string>
|
||||
<string name="touch_device_color">Configure touch device color</string>
|
||||
<string name="touch_device_color_summary">Configure color of HUD elements</string>
|
||||
<string name="state_not_restored">Error restoring state…</string>
|
||||
<string name="storage">/storage/</string>
|
||||
<string name="touch_device_color_configure">Configure HUD color…</string>
|
||||
<string name="color_red_on_black">Red on black</string>
|
||||
<string name="color_green_on_black">Green on black</string>
|
||||
<string name="color_blue_on_black">Blue on black</string>
|
||||
<string name="color_white_on_black">White on black</string>
|
||||
<string name="color_monitor">Color Monitor</string>
|
||||
<string name="color_tv_mono">Monochrome TV</string>
|
||||
<string name="color_tv">Color TV</string>
|
||||
<string name="show_half_scanlines">Show half scanlines</string>
|
||||
<string name="mono_configure">Monocolor mode</string>
|
||||
<string name="mono_configure_summary">Configure monochrome color</string>
|
||||
<string name="color_green">Green screen</string>
|
||||
<string name="color_mono">Monochrome</string>
|
||||
<string name="disk_fast_operation">Disk fast loading (EXPERIMENTAL)</string>
|
||||
<string name="disk_fast_operation_summary">Quickly load disk images (may negatively affect device battery life)</string>
|
||||
<string name="show_half_scanlines_summary">Renders pixel vertical divisions</string>
|
||||
<string name="release_notes">Release notes</string>
|
||||
<string name="release_notes_summary">View notes for this release</string>
|
||||
<string name="keyboard_duotouch_enabled">Enable dual-touch</string>
|
||||
<string name="keyboard_duotouch_enabled_summary">Support two-thumb input</string>
|
||||
<string name="keypad_preset_qaz_left_right_space">(A Z ← →) barre d\'espace, Q</string>
|
||||
<string name="keypad_tapdelay_summary">Keypad touch down delay in secs</string>
|
||||
<string name="keypad_autorepeat_fast_summary">Allows immediate auto-repeat (avoids original 534-801 millis delay)</string>
|
||||
<string name="keypad_autorepeat_fast">Keypad Immediate Autorepeat</string>
|
||||
<string name="string_frames">Frames</string>
|
||||
<string name="string_millis">Millis</string>
|
||||
<string name="joystick_button_tapdelay_summary">Joystick touch down delay in video frames</string>
|
||||
<string name="keypad_preset_robotron">Touches Robotron…</string>
|
||||
<string name="keypad_preset_loderunner">Touches Lode Runner…</string>
|
||||
<string name="keypad_preset_loderunner_toast">Start game with Ctrl-K to activate keyboard</string>
|
||||
<string name="joystick_button_swipe_left_button">Swipe left fire</string>
|
||||
<string name="joystick_button_swipe_right_button">Swipe right fire</string>
|
||||
<string name="joystick_button_swipe_left_button_summary">Button to fire on swipe left</string>
|
||||
<string name="joystick_button_swipe_right_button_summary">Button to fire on swipe right</string>
|
||||
<string name="key_del">[DEL]</string>
|
||||
<string name="key_tab">[TAB]</string>
|
||||
<string name="preferences_email_logs">Email logs</string>
|
||||
<string name="preferences_email_logs_summary">Email logs to developer…</string>
|
||||
|
||||
</resources>
|
||||
|
|
|
@ -25,8 +25,8 @@
|
|||
<string name="audio_latency">Audio latency</string>
|
||||
<string name="audio_latency_summary">Audio latency in secs</string>
|
||||
<string name="cancel">Cancel</string>
|
||||
<string name="color_configure">Configure color</string>
|
||||
<string name="color_configure_summary">Color mode</string>
|
||||
<string name="color_configure">Video display mode</string>
|
||||
<string name="color_configure_summary">Video display emulation mode</string>
|
||||
<string name="color_bw">Black/white</string>
|
||||
<string name="color_color">Color</string>
|
||||
<string name="color_interpolated">Interpolated color</string>
|
||||
|
@ -60,7 +60,7 @@
|
|||
<string name="joystick_button_button_none">None</string>
|
||||
<string name="joystick_button_tap_button">Tap fire</string>
|
||||
<string name="joystick_button_tap_button_summary">Button to fire on tap down</string>
|
||||
<string name="joystick_button_tapdelay_summary">Joystick button tap delay in secs</string>
|
||||
<string name="joystick_button_tapdelay_summary">Joystick touch down delay in video frames</string>
|
||||
<string name="joystick_button_swipe_up_button">Swipe up fire</string>
|
||||
<string name="joystick_button_swipe_up_button_summary">Button to fire on swipe up</string>
|
||||
<string name="joystick_button_swipe_down_button">Swipe down fire</string>
|
||||
|
@ -68,7 +68,7 @@
|
|||
<string name="joystick_button_threshold_summary">Joystick/keypad button switch threshold in pts (max: ⅓ screen height)</string>
|
||||
<string name="joystick_calibrate">Calibrate…</string>
|
||||
<string name="joystick_calibrate_summary">Configure and test current settings</string>
|
||||
<string name="joystick_configure">Configure joystick…</string>
|
||||
<string name="joystick_configure">Configure touch joystick…</string>
|
||||
<string name="joystick_configure_summary">Axis touch, buttons, etc</string>
|
||||
<string name="joystick_axisleft">Joystick/keypad axis on left</string>
|
||||
<string name="joystick_axisleft_summary">Joystick/keypad axis on left (buttons on right)</string>
|
||||
|
@ -92,7 +92,7 @@
|
|||
<string name="keyboard_choose_alt_summary">Choose alternative customized layout</string>
|
||||
<string name="keyboard_click_enabled">Enable key click</string>
|
||||
<string name="keyboard_click_enabled_summary">Enables key click sound if available</string>
|
||||
<string name="keyboard_configure">Configure keyboard…</string>
|
||||
<string name="keyboard_configure">Configure touch keyboard…</string>
|
||||
<string name="keyboard_configure_summary">Transparency, lowercase, custom keys</string>
|
||||
<string name="keyboard_glyph_scale">Keyboard glyphs scaled 2x</string>
|
||||
<string name="keyboard_glyph_scale_summary">(Makes keyboard appear less pixelated on large screens)</string>
|
||||
|
@ -103,13 +103,11 @@
|
|||
<string name="keyboard_visibility_inactive">Visibility when inactive</string>
|
||||
<string name="keyboard_visibility_inactive_summary">Keyboard and touch menu visibility when inactive</string>
|
||||
<string name="keypad">Keypad Joystick</string>
|
||||
<string name="keypad_calibrate">@string/joystick_calibrate</string>
|
||||
<string name="keypad_calibrate_summary">@string/joystick_calibrate</string>
|
||||
<string name="keypad_choose">Choose keypad keys…</string>
|
||||
<string name="keypad_choose_summary">Choose axis and button keys</string>
|
||||
<string name="keypad_choose_title">Axis & buttons</string>
|
||||
<string name="keypad_choose_current">Choose XXX Key: </string>
|
||||
<string name="keypad_configure">Configure keypad joystick…</string>
|
||||
<string name="keypad_configure">Configure touch keypad joystick…</string>
|
||||
<string name="keypad_configure_summary">@string/joystick_configure_summary</string>
|
||||
<string name="keypad_key_axis_c">Center</string>
|
||||
<string name="keypad_key_axis_dn">Down</string>
|
||||
|
@ -123,14 +121,14 @@
|
|||
<string name="keypad_key_button_tap">Tap</string>
|
||||
<string name="keypad_key_button_swipeup">Swipe Up</string>
|
||||
<string name="keypad_key_button_swipedown">Swipe Down</string>
|
||||
<string name="keypad_preset_crazy_seafox">Seafox keys ;-)…</string>
|
||||
<string name="keypad_preset_seafox">Seafox keys…</string>
|
||||
<string name="keypad_preset_custom">Choose custom…</string>
|
||||
<string name="keypad_preset_arrows_space">↑,←,→,↓, tap spacebar</string>
|
||||
<string name="keypad_preset_az_left_right_space">A,Z,←,→, tap spacebar</string>
|
||||
<string name="keypad_preset_ijkm_space">I,J,K,M, tap spacebar</string>
|
||||
<string name="keypad_preset_left_right_space">←,→, tap spacebar</string>
|
||||
<string name="keypad_preset_wadx_space">W,A,D,X, tap spacebar</string>
|
||||
<string name="keypad_repeat_summary">Key repeat threshold in secs</string>
|
||||
<string name="keypad_preset_arrows_space">(↑ ← → ↓), tap spacebar</string>
|
||||
<string name="keypad_preset_az_left_right_space">(A Z ← →), tap spacebar</string>
|
||||
<string name="keypad_preset_ijkm_space">(I J K M), tap spacebar</string>
|
||||
<string name="keypad_preset_left_right_space">(← →), tap spacebar</string>
|
||||
<string name="keypad_preset_wadx_space">(W A D X), tap spacebar</string>
|
||||
<string name="keypad_tapdelay_summary">Keypad touch down delay in secs</string>
|
||||
<string name="menu_disks">Load image or state file…</string>
|
||||
<string name="menu_disks_summary">Insert Disk ][ image or state file</string>
|
||||
<string name="menu_settings">Emulator settings…</string>
|
||||
|
@ -138,7 +136,7 @@
|
|||
<string name="mockingboard_disabled_title">Mockingboard disabled</string>
|
||||
<string name="mockingboard_disabled_mesg">Mockingboard could not be enabled</string>
|
||||
<string name="mockingboard_enable">Enable Mockingboard</string>
|
||||
<string name="mockingboard_enable_summary">Revision C in Slot 4/5 (may require restart)</string>
|
||||
<string name="mockingboard_enable_summary">Revision C in Slot 4/5 (may require restart) (may consume extra battery)</string>
|
||||
<string name="mockingboard_volume">Mockingboard volume</string>
|
||||
<string name="mockingboard_volume_summary">Set the Mockingboard volume</string>
|
||||
<string name="mode_landscape">Landscape</string>
|
||||
|
@ -156,7 +154,7 @@
|
|||
<string name="preferences_reset_warning">You will lose your settings</string>
|
||||
<string name="quit">Quit</string>
|
||||
<string name="quit_reboot">Reset or quit emulator…</string>
|
||||
<string name="quit_reboot_choice">Reset/reboot or quit?</string>
|
||||
<string name="quit_reboot_choice">Reset, reboot or quit?                                    …</string>
|
||||
<string name="reboot">Reboot</string>
|
||||
<string name="reset">Reset</string>
|
||||
<string name="reset_preferences">Reset settings</string>
|
||||
|
@ -180,6 +178,44 @@
|
|||
<string name="touch_menu_enable">Enable touch menus</string>
|
||||
<string name="touch_menu_enable_summary">Enables soft menu buttons in top screen corners</string>
|
||||
<string name="video_configure">Configure video…</string>
|
||||
<string name="video_configure_summary">Color landscape/portrait, color, etc</string>
|
||||
<string name="video_configure_summary">Landscape/portrait, video modes, colors, etc</string>
|
||||
<string name="touch_device_color">Configure touch device color</string>
|
||||
<string name="touch_device_color_summary">Configure color of HUD elements</string>
|
||||
<string name="touch_device_color_configure">Configure HUD color…</string>
|
||||
<string name="color_red_on_black">Red on black</string>
|
||||
<string name="color_green_on_black">Green on black</string>
|
||||
<string name="color_blue_on_black">Blue on black</string>
|
||||
<string name="color_white_on_black">White on black</string>
|
||||
<string name="color_monitor">Color Monitor</string>
|
||||
<string name="color_tv_mono">Monochrome TV</string>
|
||||
<string name="color_tv">Color TV</string>
|
||||
<string name="show_half_scanlines">Show half scanlines</string>
|
||||
<string name="mono_configure">Monocolor mode</string>
|
||||
<string name="mono_configure_summary">Configure monochrome color</string>
|
||||
<string name="color_green">Green screen</string>
|
||||
<string name="color_mono">Monochrome</string>
|
||||
<string name="disk_fast_operation">Disk fast loading (EXPERIMENTAL)</string>
|
||||
<string name="disk_fast_operation_summary">Quickly load disk images (may negatively affect device battery life)</string>
|
||||
<string name="show_half_scanlines_summary">Renders pixel vertical divisions</string>
|
||||
<string name="release_notes">Release notes</string>
|
||||
<string name="release_notes_summary">View notes for this release</string>
|
||||
<string name="keyboard_duotouch_enabled">Enable dual-touch</string>
|
||||
<string name="keyboard_duotouch_enabled_summary">Support two-thumb input</string>
|
||||
<string name="keypad_preset_qaz_left_right_space">(A Z ← →), tap spacebar, Q up</string>
|
||||
<string name="keypad_autorepeat_fast">Keypad Immediate Autorepeat</string>
|
||||
<string name="keypad_autorepeat_fast_summary">Allows immediate auto-repeat (avoids original 534-801 millis delay)</string>
|
||||
<string name="string_frames">Frames</string>
|
||||
<string name="string_millis">Millis</string>
|
||||
<string name="keypad_preset_robotron">Robotron keys…</string>
|
||||
<string name="keypad_preset_loderunner">Lode Runner keys…</string>
|
||||
<string name="keypad_preset_loderunner_toast">Start game with Ctrl-K to activate keyboard</string>
|
||||
<string name="joystick_button_swipe_left_button">Swipe left fire</string>
|
||||
<string name="joystick_button_swipe_right_button">Swipe right fire</string>
|
||||
<string name="joystick_button_swipe_right_button_summary">Button to fire on swipe right</string>
|
||||
<string name="joystick_button_swipe_left_button_summary">Button to fire on swipe left</string>
|
||||
<string name="key_del">[DEL]</string>
|
||||
<string name="key_tab">[TAB]</string>
|
||||
<string name="preferences_email_logs">Email logs</string>
|
||||
<string name="preferences_email_logs_summary">Email logs to developer…</string>
|
||||
|
||||
</resources>
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
<resources>
|
||||
|
||||
<!-- Base application theme. -->
|
||||
<!-- <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar"> ... this freaks-out CLI builds -->
|
||||
<!-- Customize your theme here. -->
|
||||
<!-- </style> -->
|
||||
<style name="Theme.AppCompat.NoActionBar.FullScreen" parent="@style/Theme.AppCompat.NoActionBar">
|
||||
<item name="android:windowNoTitle">true</item>
|
||||
<item name="android:windowActionBar">false</item>
|
||||
<item name="android:windowFullscreen">true</item>
|
||||
<item name="android:windowContentOverlay">@null</item>
|
||||
</style>
|
||||
|
||||
</resources>
|
||||
|
|
24
Android/assets/keyboards/2400AD.kbd.json
Normal file
24
Android/assets/keyboards/2400AD.kbd.json
Normal file
|
@ -0,0 +1,24 @@
|
|||
[
|
||||
"Alt keyboard optimized for 2400AD",
|
||||
|
||||
{
|
||||
"_comment" : "hex code for special glyphs",
|
||||
"_AA" : "b5",
|
||||
"_ESC" : "bc",
|
||||
"_SP" : "b1",
|
||||
"_RET" : "8d",
|
||||
"_LT" : "88",
|
||||
"_RT" : "95",
|
||||
"_UP" : "8b",
|
||||
"_DN" : "8a"
|
||||
},
|
||||
|
||||
[ "", "1", "2", "3", "4", "5", "6", "7", "8", "" ],
|
||||
[ "_AA", "", "", "", "", "", "", "", "", "Y" ],
|
||||
[ "S", "", "", "", "", "", "", "", "", "N" ],
|
||||
[ "R", "", "", "", "", "", "", "", "", "U" ],
|
||||
[ "W" , "", "", "", "", "", "", "", "", "D" ],
|
||||
[ "", "_RET", "", "", "", "", "", "", "", "F" ],
|
||||
[ "_LT", "_SP", "_RT", "", "", "", "", "", "", "L" ],
|
||||
[ "", "_DN", "", "G", "B", "O", "C", "T", "P","A" ]
|
||||
]
|
24
Android/assets/keyboards/deathlord.kbd.json
Normal file
24
Android/assets/keyboards/deathlord.kbd.json
Normal file
|
@ -0,0 +1,24 @@
|
|||
[
|
||||
"Alt keyboard optimized for Deathlord",
|
||||
|
||||
{
|
||||
"_comment" : "hex code for special glyphs",
|
||||
"_AA" : "b5",
|
||||
"_ESC" : "bc",
|
||||
"_RET" : "8d",
|
||||
"_UP" : "8b",
|
||||
"_LT" : "88",
|
||||
"_RT" : "95",
|
||||
"_DN" : "8a",
|
||||
"_SP" : "b1"
|
||||
},
|
||||
|
||||
[ "", "", "", "1", "2", "3", "4" , "5" , "6", "" ],
|
||||
[ "Z", "", "", "", "", "&", "'", "(", ")", "$" ],
|
||||
["_AA", "", "", "", "", "", "P", "", "^", "#"],
|
||||
[ "N", "", "", "", "", "", "T", "", "U", "Y"],
|
||||
[ "?", "", "", "", "", "", "_ESC", "", "_SP", "" ],
|
||||
[ "?", "", "", "", "", "", "", "I", "", "_UP" ],
|
||||
[ "C", "", "S", "R", "G", "V", "J", "", "K", "_RET"],
|
||||
[ "A", "", "O", "E", "F", "B", "", "M", "", "_DN" ]
|
||||
]
|
22
Android/assets/keyboards/windwalker.kbd.json
Normal file
22
Android/assets/keyboards/windwalker.kbd.json
Normal file
|
@ -0,0 +1,22 @@
|
|||
[
|
||||
"Alt keyboard optimized for Windwalker",
|
||||
|
||||
{
|
||||
"_comment" : "hex code for special glyphs",
|
||||
"_AA" : "b5",
|
||||
"_ESC" : "bc",
|
||||
"_SP" : "b1",
|
||||
"_RET" : "8d",
|
||||
"_UP" : "8b",
|
||||
"_DN" : "8a"
|
||||
},
|
||||
|
||||
[ "", "", "", "", "", "", "", "", "", "" ],
|
||||
[ "", "", "", "", "", "", "", "", "", "" ],
|
||||
[ "_AA", "", "", "", "", "", "", "", "", "" ],
|
||||
[ "_ESC", "", "", "", "", "", "", "", "", "_RET" ],
|
||||
[ "_UP", "", "", "", "", "", "", "", "", "" ],
|
||||
[ "_DN", "", "", "", "", "", "", "I", "O", "P"],
|
||||
[ "Y", "", "A", "S", "", "", "", "K", "L", ";"],
|
||||
[ "N", "", "Z", "X", "", "", "", ",", ".", "/"]
|
||||
]
|
30
Android/assets/release_notes.txt
Normal file
30
Android/assets/release_notes.txt
Normal file
|
@ -0,0 +1,30 @@
|
|||
Apple2ix (A2IX) 2.1.0-RC2 for Android
|
||||
|
||||
The major change here is that I now provide full 64bit native builds for arm64-v8a and x86_64 devices. (This is a new G00G requirement for publishing on the Play Store). It frankly isn't something that I would have wanted to foist upon you, dear user! But they are forcing my hand, so ... c'est la vie!
|
||||
|
||||
Anecdotally, I have heard about certain devices that claim to be arm64-v8a, but which DO NOT run 64bit code efficiently. These devices would have been better off continuing to run the armeabi-v7a build of A2IX. But there's nothing I can do about this, since the Play Store serves the specific build it thinks best. So if you are one of the unlucky owners of such a device and A2IX seems horrendously sluggish, (and if you're an adventurous power-user), you could side-load the armeabi-v7a semi-official release from the GitHub project page ;)
|
||||
|
||||
MENU INTERFACE:
|
||||
|
||||
- Migrated menu system to newer-ish Dark Holo theme
|
||||
- Moved some preferences around a bit for clarity
|
||||
|
||||
TOUCH KEYBOARD:
|
||||
|
||||
- New preference for dual-thumb touch keyboard handling
|
||||
- More alternate keyboard presets for old-school RPGs
|
||||
- Tapping Open/Closed-Apple keys now generate joystick button events
|
||||
|
||||
TOUCH JOYSTICKS:
|
||||
|
||||
- Keypad Joystick: Improved emulation fidelity for the keyboard auto-repeat circuitry, tied to the emulated video refresh. (In plain English: improved twitch-response ;)
|
||||
- Keypad Joystick: Full left and right side rosette key configurations (18 total configurable keys)
|
||||
- Keypad Joystick: More presets for popular games (L0de Runner, R0b0tr0n 2084, ...)
|
||||
- Keypad+Joystick: Improved calibration mode showing axis/key values
|
||||
- Keypad+Joystick: Button/key switch threshold now configurable down to zero minimum (improves twitch-reponse)
|
||||
- Joystick: Can now configure button to fire on left/right swipe (instead of just tap and swipe up/down)
|
||||
|
||||
M0AR INFO:
|
||||
|
||||
- Apple2ix for Android home page : https://deadc0de.org/apple2ix/android
|
||||
- Play Store beta-build opt-in URL: https://play.google.com/apps/testing/org.deadc0de.apple2ix.basic
|
0
Android/assets/symbols/x86_64/.blank
Normal file
0
Android/assets/symbols/x86_64/.blank
Normal file
|
@ -3,9 +3,10 @@
|
|||
buildscript {
|
||||
repositories {
|
||||
jcenter()
|
||||
google()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:2.3.3'
|
||||
classpath 'com.android.tools.build:gradle:3.5.2'
|
||||
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
// in the individual module build.gradle files
|
||||
|
@ -15,5 +16,6 @@ buildscript {
|
|||
allprojects {
|
||||
repositories {
|
||||
jcenter()
|
||||
google()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,4 +17,5 @@
|
|||
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
|
||||
# org.gradle.parallel=true
|
||||
|
||||
android.useDeprecatedNdk=true
|
||||
android.enableJetifier=true
|
||||
android.useAndroidX=true
|
|
@ -1,6 +1,6 @@
|
|||
#Mon Apr 17 16:37:13 HST 2017
|
||||
#Sun Oct 27 16:51:42 PDT 2019
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
APP_ABI := armeabi armeabi-v7a x86
|
||||
APP_ABI := armeabi-v7a arm64-v8a x86 x86_64
|
||||
|
||||
# Do not change APP_PLATFORM if we care about Gingerbread (2.3.3) devices! We must compile against android-10,
|
||||
# otherwise we may encounter runtime load-library errors from symbols that should have been inlined against older
|
||||
|
|
|
@ -243,16 +243,20 @@ void android_keycode_to_emulator(int keyCode, int metaState, bool pressed) {
|
|||
}
|
||||
} while (0);
|
||||
|
||||
if (key < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
//LOG("keyCode:%08x -> key:%02x ('%c') metaState:%08x", keyCode, key, key, metaState);
|
||||
|
||||
if (isASCII && _is_ctrl(metaState)) {
|
||||
key = c_keys_ascii_to_scancode(key);
|
||||
c_keys_handle_input(key, true, false);
|
||||
key = keys_ascii2Scancode(key);
|
||||
keys_handleInput(key, /*is_pressed:*/true, /*is_ascii:*/false);
|
||||
isASCII = false;
|
||||
pressed = false;
|
||||
}
|
||||
|
||||
assert(key < 0x80);
|
||||
c_keys_handle_input(key, pressed, isASCII);
|
||||
keys_handleInput(key, pressed, isASCII);
|
||||
}
|
||||
|
||||
|
|
|
@ -125,7 +125,7 @@ if test "x$do_build" = "x1" -o "x$do_release" = "x1" ; then
|
|||
$CC $CFLAGS -o $apple2_src_path/genfont $apple2_src_path/genfont.c && \
|
||||
$apple2_src_path/genfont < $apple2_src_path/font.txt > $apple2_src_path/font.c
|
||||
|
||||
# trampoline generation
|
||||
# bridge trampoline generation
|
||||
TARGET_ARCH=x86 $apple2_src_path/genglue.sh $glue_srcs > $apple2_src_path/x86/glue.S
|
||||
TARGET_ARCH=arm $apple2_src_path/genglue.sh $glue_srcs > $apple2_src_path/arm/glue.S
|
||||
|
||||
|
@ -148,7 +148,7 @@ if test "x$do_build" = "x1" -o "x$do_release" = "x1" ; then
|
|||
# Symbolicate and move symbols file into location to be deployed on device
|
||||
|
||||
SYMFILE=libapple2ix.so.sym
|
||||
ARCHES_TO_SYMBOLICATE='armeabi armeabi-v7a x86'
|
||||
ARCHES_TO_SYMBOLICATE='armeabi-v7a arm64-v8a x86 x86_64'
|
||||
|
||||
for arch in $ARCHES_TO_SYMBOLICATE ; do
|
||||
SYMDIR=../assets/symbols/$arch/libapple2ix.so
|
||||
|
|
|
@ -132,21 +132,25 @@ void Java_org_deadc0de_apple2ix_Apple2CrashHandler_nativeProcessCrash(JNIEnv *en
|
|||
do {
|
||||
outputFILE = TEMP_FAILURE_RETRY_FOPEN(fopen(outputPath, "w"));
|
||||
if (!outputFILE) {
|
||||
ERRLOG("could not open %s", outputPath);
|
||||
LOG("could not open %s", outputPath);
|
||||
break;
|
||||
}
|
||||
|
||||
if (android_armArchV7A) {
|
||||
if (android_arm64Arch) {
|
||||
ASPRINTF(&symbolsPath, "%s/symbols/arm64-v8a", data_dir);
|
||||
} else if (android_armArchV7A || android_armArch) {
|
||||
ASPRINTF(&symbolsPath, "%s/symbols/armeabi-v7a", data_dir);
|
||||
} else if (android_x86_64) {
|
||||
ASPRINTF(&symbolsPath, "%s/symbols/x86_64", data_dir);
|
||||
} else if (android_x86) {
|
||||
ASPRINTF(&symbolsPath, "%s/symbols/x86", data_dir);
|
||||
} else /*if (android_armArch)*/ {
|
||||
ASPRINTF(&symbolsPath, "%s/symbols/armeabi", data_dir);
|
||||
} /*else { moar archs ... } */
|
||||
} else {
|
||||
LOG("unknown symbols architecture!");
|
||||
}
|
||||
|
||||
bool success = crashHandler->processCrash(crashPath, symbolsPath, outputFILE);
|
||||
if (!success) {
|
||||
RELEASE_LOG("CRASH REPORT PROCESSING FAILED ...");
|
||||
LOG("CRASH REPORT PROCESSING FAILED ...");
|
||||
}
|
||||
} while (0);
|
||||
|
||||
|
|
|
@ -123,8 +123,9 @@ static void discover_cpu_family(void) {
|
|||
|
||||
AndroidCpuFamily family = android_getCpuFamily();
|
||||
uint64_t features = android_getCpuFeatures();
|
||||
if (family == ANDROID_CPU_FAMILY_X86) {
|
||||
android_x86 = true;
|
||||
if (family == ANDROID_CPU_FAMILY_X86 || family == ANDROID_CPU_FAMILY_X86_64) {
|
||||
android_x86 = (family == ANDROID_CPU_FAMILY_X86);
|
||||
android_x86_64 = (family == ANDROID_CPU_FAMILY_X86_64);
|
||||
if (features & ANDROID_CPU_X86_FEATURE_SSSE3) {
|
||||
LOG("nANDROID_CPU_X86_FEATURE_SSSE3");
|
||||
android_x86SSSE3Enabled = true;
|
||||
|
@ -155,9 +156,7 @@ static void discover_cpu_family(void) {
|
|||
LOG("ANDROID_CPU_ARM_FEATURE_LDREX_STREX");
|
||||
}
|
||||
} else if (family == ANDROID_CPU_FAMILY_ARM64) {
|
||||
#warning FIXME TODO ...
|
||||
//android_arm64Arch = true;
|
||||
android_armArchV7A = true;
|
||||
android_arm64Arch = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -292,13 +291,13 @@ void Java_org_deadc0de_apple2ix_Apple2View_nativeRender(JNIEnv *env, jclass cls)
|
|||
void Java_org_deadc0de_apple2ix_Apple2Activity_nativeReboot(JNIEnv *env, jclass cls, jint resetState) {
|
||||
LOG("...");
|
||||
if (resetState) {
|
||||
// joystick button settings should be balanced by c_joystick_reset() triggered on CPU thread
|
||||
// joystick button settings should be balanced by joystick_reset() triggered on CPU thread
|
||||
if (resetState == 1) {
|
||||
joy_button0 = 0xff;
|
||||
joy_button1 = 0x0;
|
||||
run_args.joy_button0 = 0xff;
|
||||
run_args.joy_button1 = 0x0;
|
||||
} else {
|
||||
joy_button0 = 0x0;
|
||||
joy_button1 = 0xff;
|
||||
run_args.joy_button0 = 0x0;
|
||||
run_args.joy_button1 = 0xff;
|
||||
}
|
||||
}
|
||||
cpu65_interrupt(ResetSig);
|
||||
|
@ -337,7 +336,7 @@ void Java_org_deadc0de_apple2ix_Apple2View_nativeOnJoystickMove(JNIEnv *env, jcl
|
|||
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");
|
||||
SCOPE_TRACE_INTERFACE("nativeOnTouch");
|
||||
|
||||
if (UNLIKELY(appState != APP_RUNNING)) {
|
||||
return 0x0LL;
|
||||
|
@ -388,12 +387,12 @@ jstring Java_org_deadc0de_apple2ix_Apple2DisksMenu_nativeChooseDisk(JNIEnv *env,
|
|||
if (!json_mapParseLongValue(jsonData, "fd", &fd, 10)) {
|
||||
TEMP_FAILURE_RETRY(fd = open(path, readOnly ? O_RDONLY : O_RDWR));
|
||||
if (fd == -1) {
|
||||
LOG("OOPS could not open disk path : %s", path);
|
||||
LOG("OOPS could not open disk path : %s (%s)", path, strerror(errno));
|
||||
}
|
||||
} else {
|
||||
fd = dup(fd);
|
||||
TEMP_FAILURE_RETRY(fd = dup(fd));
|
||||
if (fd == -1) {
|
||||
ERRLOG("OOPS could not dup file descriptor!");
|
||||
LOG("OOPS could not dup file descriptor! (%s)", strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -406,10 +405,10 @@ jstring Java_org_deadc0de_apple2ix_Apple2DisksMenu_nativeChooseDisk(JNIEnv *env,
|
|||
if (err) {
|
||||
char *diskImageUnreadable = "Disk Image Unreadable";
|
||||
unsigned int cols = strlen(diskImageUnreadable);
|
||||
video_animations->animation_showMessage(diskImageUnreadable, cols, 1);
|
||||
video_getAnimationDriver()->animation_showMessage(diskImageUnreadable, cols, 1);
|
||||
inserted = false;
|
||||
} else {
|
||||
video_animations->animation_showDiskChosen(drive);
|
||||
video_getAnimationDriver()->animation_showDiskChosen(drive);
|
||||
}
|
||||
|
||||
json_mapSetBoolValue(jsonData, "inserted", inserted);
|
||||
|
@ -442,7 +441,7 @@ void Java_org_deadc0de_apple2ix_Apple2DisksMenu_nativeEjectDisk(JNIEnv *env, jcl
|
|||
disk6_eject(driveA ? 0 : 1);
|
||||
}
|
||||
|
||||
static int _openFdFromJson(OUTPARM int *fdOut, JSON_ref jsonData, const char * const fdKey, const char * const pathKey, int flags, int mode) {
|
||||
static void _openFdFromJson(OUTPARM int *fdOut, JSON_ref jsonData, const char * const fdKey, const char * const pathKey, int flags, int mode) {
|
||||
|
||||
long fd = -1;
|
||||
char *path = NULL;
|
||||
|
@ -463,12 +462,12 @@ static int _openFdFromJson(OUTPARM int *fdOut, JSON_ref jsonData, const char * c
|
|||
TEMP_FAILURE_RETRY(fd = open(path, flags, mode));
|
||||
}
|
||||
if (fd == -1) {
|
||||
LOG("OOPS could not open state file path %s", path);
|
||||
LOG("OOPS could not open state file path %s (%s)", path, strerror(errno));
|
||||
}
|
||||
} else {
|
||||
fd = dup(fd);
|
||||
TEMP_FAILURE_RETRY(fd = dup(fd));
|
||||
if (fd == -1) {
|
||||
ERRLOG("OOPS could not dup file descriptor!");
|
||||
LOG("OOPS could not dup file descriptor! (%s)", strerror(errno));
|
||||
}
|
||||
}
|
||||
} while (0);
|
||||
|
@ -604,12 +603,61 @@ void Java_org_deadc0de_apple2ix_Apple2Preferences_nativePrefsSync(JNIEnv *env, j
|
|||
domain = (*env)->GetStringUTFChars(env, jDomain, 0);
|
||||
}
|
||||
|
||||
#if !TEST_PREFS
|
||||
LOG("... domain: %s", domain);
|
||||
prefs_load();
|
||||
prefs_sync(domain);
|
||||
#endif
|
||||
|
||||
if (jDomain) {
|
||||
(*env)->ReleaseStringUTFChars(env, jDomain, domain);
|
||||
}
|
||||
}
|
||||
|
||||
jlong Java_org_deadc0de_apple2ix_Apple2JoystickCalibration_nativePollJoystick(JNIEnv *env, jclass cls) {
|
||||
jlong cxy = 0;
|
||||
|
||||
long c = keys_consumeLastKey();
|
||||
|
||||
cxy |= (c << 16);
|
||||
cxy |= ((joy_x & 0xFF) << 8);
|
||||
cxy |= ((joy_y & 0xFF) << 0);
|
||||
|
||||
// last_ascii | last_scancode | joy_x | joy_y
|
||||
return cxy;
|
||||
}
|
||||
|
||||
void Java_org_deadc0de_apple2ix_Apple2Activity_nativeLogMessage(JNIEnv *env, jclass cls, jstring jJsonString) {
|
||||
#if TESTING
|
||||
return NULL;
|
||||
#endif
|
||||
|
||||
const char *jsonString = (*env)->GetStringUTFChars(env, jJsonString, NULL);
|
||||
|
||||
JSON_ref jsonData = NULL;
|
||||
bool ret = json_createFromString(jsonString, &jsonData);
|
||||
assert(ret > 0);
|
||||
|
||||
(*env)->ReleaseStringUTFChars(env, jJsonString, jsonString); jsonString = NULL;
|
||||
|
||||
long type = LOG_TYPE_INFO;
|
||||
json_mapParseLongValue(jsonData, "type", &type, 10);
|
||||
|
||||
char *tag = NULL;
|
||||
json_mapCopyStringValue(jsonData, "tag", &tag);
|
||||
|
||||
char *mesg = NULL;
|
||||
json_mapCopyStringValue(jsonData, "mesg", &mesg);
|
||||
|
||||
log_taggedOutputString((log_type_t)type, tag, mesg);
|
||||
|
||||
if (tag) {
|
||||
FREE(tag);
|
||||
}
|
||||
if (mesg) {
|
||||
FREE(mesg);
|
||||
}
|
||||
|
||||
json_destroy(&jsonData);
|
||||
}
|
||||
|
||||
|
|
|
@ -4,43 +4,67 @@
|
|||
APPLE2_SRC_PATH := apple2ix-src
|
||||
|
||||
APPLE2_X86_SRC := \
|
||||
$(APPLE2_SRC_PATH)/x86/glue.S $(APPLE2_SRC_PATH)/x86/cpu.S
|
||||
$(APPLE2_SRC_PATH)/x86/cpu.S \
|
||||
$(APPLE2_SRC_PATH)/x86/glue.S
|
||||
|
||||
APPLE2_ARM_SRC := \
|
||||
$(APPLE2_SRC_PATH)/arm/glue.S $(APPLE2_SRC_PATH)/arm/cpu.S
|
||||
$(APPLE2_SRC_PATH)/arm/cpu.S \
|
||||
$(APPLE2_SRC_PATH)/arm/glue.S
|
||||
|
||||
APPLE2_VIDEO_SRC = \
|
||||
$(APPLE2_SRC_PATH)/video/glvideo.c \
|
||||
$(APPLE2_SRC_PATH)/video/glnode.c \
|
||||
$(APPLE2_SRC_PATH)/video/glhudmodel.c \
|
||||
$(APPLE2_SRC_PATH)/video/glalert.c \
|
||||
$(APPLE2_SRC_PATH)/video/glhudmodel.c \
|
||||
$(APPLE2_SRC_PATH)/video/glnode.c \
|
||||
$(APPLE2_SRC_PATH)/video/gltouchjoy.c \
|
||||
$(APPLE2_SRC_PATH)/video/gltouchjoy_joy.c \
|
||||
$(APPLE2_SRC_PATH)/video/gltouchjoy_kpad.c \
|
||||
$(APPLE2_SRC_PATH)/video/gltouchkbd.c \
|
||||
$(APPLE2_SRC_PATH)/video/gltouchmenu.c \
|
||||
$(APPLE2_SRC_PATH)/video/glvideo.c \
|
||||
$(APPLE2_SRC_PATH)/video/ntsc.c \
|
||||
$(APPLE2_SRC_PATH)/video/video.c \
|
||||
$(APPLE2_SRC_PATH)/video_util/matrixUtil.c \
|
||||
$(APPLE2_SRC_PATH)/video_util/modelUtil.c \
|
||||
$(APPLE2_SRC_PATH)/video_util/sourceUtil.c \
|
||||
$(APPLE2_SRC_PATH)/video_util/vectorUtil.c
|
||||
|
||||
APPLE2_AUDIO_SRC = \
|
||||
$(APPLE2_SRC_PATH)/audio/soundcore.c $(APPLE2_SRC_PATH)/audio/soundcore-opensles.c $(APPLE2_SRC_PATH)/audio/speaker.c \
|
||||
$(APPLE2_SRC_PATH)/audio/mockingboard.c $(APPLE2_SRC_PATH)/audio/AY8910.c
|
||||
$(APPLE2_SRC_PATH)/audio/AY8910.c \
|
||||
$(APPLE2_SRC_PATH)/audio/mockingboard.c \
|
||||
$(APPLE2_SRC_PATH)/audio/soundcore.c \
|
||||
$(APPLE2_SRC_PATH)/audio/soundcore-opensles.c \
|
||||
$(APPLE2_SRC_PATH)/audio/speaker.c
|
||||
|
||||
APPLE2_META_SRC = \
|
||||
$(APPLE2_SRC_PATH)/meta/debug.c $(APPLE2_SRC_PATH)/meta/debugger.c $(APPLE2_SRC_PATH)/meta/opcodes.c \
|
||||
$(APPLE2_SRC_PATH)/meta/lintrace.c $(APPLE2_SRC_PATH)/test/sha1.c $(APPLE2_SRC_PATH)/json_parse.c \
|
||||
$(APPLE2_SRC_PATH)/memmngt.c $(APPLE2_SRC_PATH)/../externals/jsmn/jsmn.c
|
||||
$(APPLE2_SRC_PATH)/meta/debug.c \
|
||||
$(APPLE2_SRC_PATH)/meta/debugger.c \
|
||||
$(APPLE2_SRC_PATH)/meta/systrace.c \
|
||||
$(APPLE2_SRC_PATH)/meta/log.c \
|
||||
$(APPLE2_SRC_PATH)/meta/memmngt.c \
|
||||
$(APPLE2_SRC_PATH)/meta/opcodes.c \
|
||||
$(APPLE2_SRC_PATH)/test/sha1.c \
|
||||
|
||||
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 $(APPLE2_SRC_PATH)/prefs.c \
|
||||
jnihooks.c androidkeys.c
|
||||
androidkeys.c \
|
||||
jnihooks.c \
|
||||
$(APPLE2_SRC_PATH)/cpu-supp.c \
|
||||
$(APPLE2_SRC_PATH)/disk.c \
|
||||
$(APPLE2_SRC_PATH)/display.c \
|
||||
$(APPLE2_SRC_PATH)/font.c \
|
||||
$(APPLE2_SRC_PATH)/interface.c \
|
||||
$(APPLE2_SRC_PATH)/joystick.c \
|
||||
$(APPLE2_SRC_PATH)/json_parse.c \
|
||||
$(APPLE2_SRC_PATH)/keys.c \
|
||||
$(APPLE2_SRC_PATH)/misc.c \
|
||||
$(APPLE2_SRC_PATH)/prefs.c \
|
||||
$(APPLE2_SRC_PATH)/rom.c \
|
||||
$(APPLE2_SRC_PATH)/timing.c \
|
||||
$(APPLE2_SRC_PATH)/vm.c \
|
||||
$(APPLE2_SRC_PATH)/zlib-helpers.c \
|
||||
$(APPLE2_SRC_PATH)/../externals/jsmn/jsmn.c
|
||||
|
||||
APPLE2_OPTIM_CFLAGS := -Os
|
||||
APPLE2_BASE_CFLAGS := -DAPPLE2IX=1 -DINTERFACE_TOUCH=1 -DMOBILE_DEVICE=1 -DVIDEO_OPENGL=1 -std=gnu11 -fPIC $(APPLE2_OPTIM_CFLAGS) -I$(APPLE2_SRC_PATH)
|
||||
APPLE2_OPTIM_CFLAGS := -O2 # match the same optimization level as BUILD_MODE=release for ndk-build
|
||||
APPLE2_BASE_CFLAGS := -Wall -DAPPLE2IX=1 -DINTERFACE_TOUCH=1 -DMOBILE_DEVICE=1 -DVIDEO_OPENGL=1 -std=gnu11 -fPIC $(APPLE2_OPTIM_CFLAGS) -I$(APPLE2_SRC_PATH)
|
||||
APPLE2_BASE_LDLIBS := -Wl,-z,text -Wl,-z,noexecstack -llog -landroid -lGLESv2 -lz -lOpenSLES -latomic
|
||||
|
||||
LOCAL_WHOLE_STATIC_LIBRARIES += cpufeatures
|
||||
|
|
|
@ -23,6 +23,12 @@ else
|
|||
LOCAL_SRC_FILES += $(APPLE2_ARM_SRC)
|
||||
endif
|
||||
|
||||
ifeq ($(BUILD_MODE),release)
|
||||
LOCAL_CFLAGS += -DNDEBUG=1
|
||||
else
|
||||
LOCAL_CFLAGS += -g
|
||||
endif
|
||||
|
||||
LOCAL_SRC_FILES += $(APPLE2_MAIN_SRC) $(APPLE2_META_SRC) $(APPLE2_VIDEO_SRC) $(APPLE2_AUDIO_SRC)
|
||||
|
||||
# Build a shared library and let Java/Dalvik drive
|
||||
|
|
|
@ -23,6 +23,12 @@ else
|
|||
LOCAL_SRC_FILES += $(APPLE2_ARM_SRC)
|
||||
endif
|
||||
|
||||
ifeq ($(BUILD_MODE),release)
|
||||
LOCAL_CFLAGS += -DNDEBUG=1
|
||||
else
|
||||
LOCAL_CFLAGS += -g
|
||||
endif
|
||||
|
||||
LOCAL_SRC_FILES += $(APPLE2_MAIN_SRC) $(APPLE2_META_SRC) $(APPLE2_VIDEO_SRC) $(APPLE2_AUDIO_SRC)
|
||||
|
||||
# Build a shared library and let Java/Dalvik drive
|
||||
|
|
|
@ -23,6 +23,12 @@ else
|
|||
LOCAL_SRC_FILES += $(APPLE2_ARM_SRC)
|
||||
endif
|
||||
|
||||
ifeq ($(BUILD_MODE),release)
|
||||
LOCAL_CFLAGS += -DNDEBUG=1
|
||||
else
|
||||
LOCAL_CFLAGS += -g
|
||||
endif
|
||||
|
||||
LOCAL_SRC_FILES += $(APPLE2_MAIN_SRC) $(APPLE2_META_SRC) $(APPLE2_VIDEO_SRC) $(APPLE2_AUDIO_SRC)
|
||||
|
||||
# Build a shared library and let Java/Dalvik drive
|
||||
|
|
|
@ -23,6 +23,12 @@ else
|
|||
LOCAL_SRC_FILES += $(APPLE2_ARM_SRC)
|
||||
endif
|
||||
|
||||
ifeq ($(BUILD_MODE),release)
|
||||
LOCAL_CFLAGS += -DNDEBUG=1
|
||||
else
|
||||
LOCAL_CFLAGS += -g
|
||||
endif
|
||||
|
||||
LOCAL_SRC_FILES += $(APPLE2_MAIN_SRC) $(APPLE2_META_SRC) $(APPLE2_VIDEO_SRC) $(APPLE2_AUDIO_SRC)
|
||||
|
||||
# Build a shared library and let Java/Dalvik drive
|
||||
|
|
|
@ -23,6 +23,12 @@ else
|
|||
LOCAL_SRC_FILES += $(APPLE2_ARM_SRC)
|
||||
endif
|
||||
|
||||
ifeq ($(BUILD_MODE),release)
|
||||
LOCAL_CFLAGS += -DNDEBUG=1
|
||||
else
|
||||
LOCAL_CFLAGS += -g
|
||||
endif
|
||||
|
||||
LOCAL_SRC_FILES += $(APPLE2_MAIN_SRC) $(APPLE2_META_SRC) $(APPLE2_VIDEO_SRC) $(APPLE2_AUDIO_SRC)
|
||||
|
||||
# Build a shared library and let Java/Dalvik drive
|
||||
|
|
|
@ -23,6 +23,12 @@ else
|
|||
LOCAL_SRC_FILES += $(APPLE2_ARM_SRC)
|
||||
endif
|
||||
|
||||
ifeq ($(BUILD_MODE),release)
|
||||
LOCAL_CFLAGS += -DNDEBUG=1
|
||||
else
|
||||
LOCAL_CFLAGS += -g
|
||||
endif
|
||||
|
||||
LOCAL_SRC_FILES += $(APPLE2_MAIN_SRC) $(APPLE2_META_SRC) $(APPLE2_VIDEO_SRC) $(APPLE2_AUDIO_SRC)
|
||||
|
||||
# Build a shared library and let Java/Dalvik drive
|
||||
|
|
|
@ -23,6 +23,12 @@ else
|
|||
LOCAL_SRC_FILES += $(APPLE2_ARM_SRC)
|
||||
endif
|
||||
|
||||
ifeq ($(BUILD_MODE),release)
|
||||
LOCAL_CFLAGS += -DNDEBUG=1
|
||||
else
|
||||
LOCAL_CFLAGS += -g
|
||||
endif
|
||||
|
||||
LOCAL_SRC_FILES += $(APPLE2_MAIN_SRC) $(APPLE2_META_SRC) $(APPLE2_VIDEO_SRC) $(APPLE2_AUDIO_SRC)
|
||||
|
||||
# Build a shared library and let Java/Dalvik drive
|
||||
|
|
516
Android/toolchain_edits/NDK_R15C/python-packages/adb/device.py
Executable file
516
Android/toolchain_edits/NDK_R15C/python-packages/adb/device.py
Executable file
|
@ -0,0 +1,516 @@
|
|||
#
|
||||
# Copyright (C) 2015 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.
|
||||
#
|
||||
import atexit
|
||||
import base64
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
|
||||
|
||||
class FindDeviceError(RuntimeError):
|
||||
pass
|
||||
|
||||
|
||||
class DeviceNotFoundError(FindDeviceError):
|
||||
def __init__(self, serial):
|
||||
self.serial = serial
|
||||
super(DeviceNotFoundError, self).__init__(
|
||||
'No device with serial {}'.format(serial))
|
||||
|
||||
|
||||
class NoUniqueDeviceError(FindDeviceError):
|
||||
def __init__(self):
|
||||
super(NoUniqueDeviceError, self).__init__('No unique device')
|
||||
|
||||
|
||||
class ShellError(RuntimeError):
|
||||
def __init__(self, cmd, stdout, stderr, exit_code):
|
||||
super(ShellError, self).__init__(
|
||||
'`{0}` exited with code {1}'.format(cmd, exit_code))
|
||||
self.cmd = cmd
|
||||
self.stdout = stdout
|
||||
self.stderr = stderr
|
||||
self.exit_code = exit_code
|
||||
|
||||
|
||||
def get_devices(adb_path='adb'):
|
||||
with open(os.devnull, 'wb') as devnull:
|
||||
subprocess.check_call([adb_path, 'start-server'], stdout=devnull,
|
||||
stderr=devnull)
|
||||
out = split_lines(subprocess.check_output([adb_path, 'devices']))
|
||||
|
||||
# The first line of `adb devices` just says "List of attached devices", so
|
||||
# skip that.
|
||||
devices = []
|
||||
for line in out[1:]:
|
||||
if not line.strip():
|
||||
continue
|
||||
if 'offline' in line:
|
||||
continue
|
||||
|
||||
serial, _ = re.split(r'\s+', line, maxsplit=1)
|
||||
devices.append(serial)
|
||||
return devices
|
||||
|
||||
|
||||
def _get_unique_device(product=None, adb_path='adb'):
|
||||
devices = get_devices(adb_path=adb_path)
|
||||
if len(devices) != 1:
|
||||
raise NoUniqueDeviceError()
|
||||
return AndroidDevice(devices[0], product, adb_path)
|
||||
|
||||
|
||||
def _get_device_by_serial(serial, product=None, adb_path='adb'):
|
||||
for device in get_devices(adb_path=adb_path):
|
||||
if device == serial:
|
||||
return AndroidDevice(serial, product, adb_path)
|
||||
raise DeviceNotFoundError(serial)
|
||||
|
||||
|
||||
def get_device(serial=None, product=None, adb_path='adb'):
|
||||
"""Get a uniquely identified AndroidDevice if one is available.
|
||||
|
||||
Raises:
|
||||
DeviceNotFoundError:
|
||||
The serial specified by `serial` or $ANDROID_SERIAL is not
|
||||
connected.
|
||||
|
||||
NoUniqueDeviceError:
|
||||
Neither `serial` nor $ANDROID_SERIAL was set, and the number of
|
||||
devices connected to the system is not 1. Having 0 connected
|
||||
devices will also result in this error.
|
||||
|
||||
Returns:
|
||||
An AndroidDevice associated with the first non-None identifier in the
|
||||
following order of preference:
|
||||
|
||||
1) The `serial` argument.
|
||||
2) The environment variable $ANDROID_SERIAL.
|
||||
3) The single device connnected to the system.
|
||||
"""
|
||||
if serial is not None:
|
||||
return _get_device_by_serial(serial, product, adb_path)
|
||||
|
||||
android_serial = os.getenv('ANDROID_SERIAL')
|
||||
if android_serial is not None:
|
||||
return _get_device_by_serial(android_serial, product, adb_path)
|
||||
|
||||
return _get_unique_device(product, adb_path=adb_path)
|
||||
|
||||
|
||||
def _get_device_by_type(flag, adb_path):
|
||||
with open(os.devnull, 'wb') as devnull:
|
||||
subprocess.check_call([adb_path, 'start-server'], stdout=devnull,
|
||||
stderr=devnull)
|
||||
try:
|
||||
serial = subprocess.check_output(
|
||||
[adb_path, flag, 'get-serialno']).strip()
|
||||
except subprocess.CalledProcessError:
|
||||
raise RuntimeError('adb unexpectedly returned nonzero')
|
||||
if serial == 'unknown':
|
||||
raise NoUniqueDeviceError()
|
||||
return _get_device_by_serial(serial, adb_path=adb_path)
|
||||
|
||||
|
||||
def get_usb_device(adb_path='adb'):
|
||||
"""Get the unique USB-connected AndroidDevice if it is available.
|
||||
|
||||
Raises:
|
||||
NoUniqueDeviceError:
|
||||
0 or multiple devices are connected via USB.
|
||||
|
||||
Returns:
|
||||
An AndroidDevice associated with the unique USB-connected device.
|
||||
"""
|
||||
return _get_device_by_type('-d', adb_path=adb_path)
|
||||
|
||||
|
||||
def get_emulator_device(adb_path='adb'):
|
||||
"""Get the unique emulator AndroidDevice if it is available.
|
||||
|
||||
Raises:
|
||||
NoUniqueDeviceError:
|
||||
0 or multiple emulators are running.
|
||||
|
||||
Returns:
|
||||
An AndroidDevice associated with the unique running emulator.
|
||||
"""
|
||||
return _get_device_by_type('-e', adb_path=adb_path)
|
||||
|
||||
|
||||
# If necessary, modifies subprocess.check_output() or subprocess.Popen() args
|
||||
# to run the subprocess via Windows PowerShell to work-around an issue in
|
||||
# Python 2's subprocess class on Windows where it doesn't support Unicode.
|
||||
def _get_subprocess_args(args):
|
||||
# Only do this slow work-around if Unicode is in the cmd line on Windows.
|
||||
# PowerShell takes 600-700ms to startup on a 2013-2014 machine, which is
|
||||
# very slow.
|
||||
if os.name != 'nt' or all(not isinstance(arg, unicode) for arg in args[0]):
|
||||
return args
|
||||
|
||||
def escape_arg(arg):
|
||||
# Escape for the parsing that the C Runtime does in Windows apps. In
|
||||
# particular, this will take care of double-quotes.
|
||||
arg = subprocess.list2cmdline([arg])
|
||||
# Escape single-quote with another single-quote because we're about
|
||||
# to...
|
||||
arg = arg.replace(u"'", u"''")
|
||||
# ...put the arg in a single-quoted string for PowerShell to parse.
|
||||
arg = u"'" + arg + u"'"
|
||||
return arg
|
||||
|
||||
# Escape command line args.
|
||||
argv = map(escape_arg, args[0])
|
||||
# Cause script errors (such as adb not found) to stop script immediately
|
||||
# with an error.
|
||||
ps_code = u'$ErrorActionPreference = "Stop"\r\n'
|
||||
# Add current directory to the PATH var, to match cmd.exe/CreateProcess()
|
||||
# behavior.
|
||||
ps_code += u'$env:Path = ".;" + $env:Path\r\n'
|
||||
# Precede by &, the PowerShell call operator, and separate args by space.
|
||||
ps_code += u'& ' + u' '.join(argv)
|
||||
# Make the PowerShell exit code the exit code of the subprocess.
|
||||
ps_code += u'\r\nExit $LastExitCode'
|
||||
# Encode as UTF-16LE (without Byte-Order-Mark) which Windows natively
|
||||
# understands.
|
||||
ps_code = ps_code.encode('utf-16le')
|
||||
|
||||
# Encode the PowerShell command as base64 and use the special
|
||||
# -EncodedCommand option that base64 decodes. Base64 is just plain ASCII,
|
||||
# so it should have no problem passing through Win32 CreateProcessA()
|
||||
# (which python erroneously calls instead of CreateProcessW()).
|
||||
return (['powershell.exe', '-NoProfile', '-NonInteractive',
|
||||
'-EncodedCommand', base64.b64encode(ps_code)],) + args[1:]
|
||||
|
||||
|
||||
# Call this instead of subprocess.check_output() to work-around issue in Python
|
||||
# 2's subprocess class on Windows where it doesn't support Unicode.
|
||||
def _subprocess_check_output(*args, **kwargs):
|
||||
try:
|
||||
return subprocess.check_output(*_get_subprocess_args(args), **kwargs)
|
||||
except subprocess.CalledProcessError as e:
|
||||
# Show real command line instead of the powershell.exe command line.
|
||||
raise subprocess.CalledProcessError(e.returncode, args[0],
|
||||
output=e.output)
|
||||
|
||||
|
||||
# Call this instead of subprocess.Popen(). Like _subprocess_check_output().
|
||||
def _subprocess_Popen(*args, **kwargs):
|
||||
return subprocess.Popen(*_get_subprocess_args(args), **kwargs)
|
||||
|
||||
|
||||
def split_lines(s):
|
||||
"""Splits lines in a way that works even on Windows and old devices.
|
||||
|
||||
Windows will see \r\n instead of \n, old devices do the same, old devices
|
||||
on Windows will see \r\r\n.
|
||||
"""
|
||||
# rstrip is used here to workaround a difference between splineslines and
|
||||
# re.split:
|
||||
# >>> 'foo\n'.splitlines()
|
||||
# ['foo']
|
||||
# >>> re.split(r'\n', 'foo\n')
|
||||
# ['foo', '']
|
||||
return re.split(r'[\r\n]+', s.rstrip())
|
||||
|
||||
|
||||
def version(adb_path=None):
|
||||
"""Get the version of adb (in terms of ADB_SERVER_VERSION)."""
|
||||
|
||||
adb_path = adb_path if adb_path is not None else ['adb']
|
||||
version_output = subprocess.check_output(adb_path + ['version'])
|
||||
pattern = r'^Android Debug Bridge version 1.0.(\d+)$'
|
||||
result = re.match(pattern, version_output.splitlines()[0])
|
||||
if not result:
|
||||
return 0
|
||||
return int(result.group(1))
|
||||
|
||||
|
||||
class AndroidDevice(object):
|
||||
# Delimiter string to indicate the start of the exit code.
|
||||
_RETURN_CODE_DELIMITER = 'x'
|
||||
|
||||
# Follow any shell command with this string to get the exit
|
||||
# status of a program since this isn't propagated by adb.
|
||||
#
|
||||
# The delimiter is needed because `printf 1; echo $?` would print
|
||||
# "10", and we wouldn't be able to distinguish the exit code.
|
||||
_RETURN_CODE_PROBE = [';', 'echo', '{0}$?'.format(_RETURN_CODE_DELIMITER)]
|
||||
|
||||
# Maximum search distance from the output end to find the delimiter.
|
||||
# adb on Windows returns \r\n even if adbd returns \n. Some old devices
|
||||
# seem to actually return \r\r\n.
|
||||
_RETURN_CODE_SEARCH_LENGTH = len(
|
||||
'{0}255\r\r\n'.format(_RETURN_CODE_DELIMITER))
|
||||
|
||||
def __init__(self, serial, product=None, adb_path='adb'):
|
||||
self.serial = serial
|
||||
self.product = product
|
||||
self.adb_cmd = [adb_path]
|
||||
|
||||
if self.serial is not None:
|
||||
self.adb_cmd.extend(['-s', serial])
|
||||
if self.product is not None:
|
||||
self.adb_cmd.extend(['-p', product])
|
||||
self._linesep = None
|
||||
self._features = None
|
||||
|
||||
@property
|
||||
def linesep(self):
|
||||
if self._linesep is None:
|
||||
self._linesep = subprocess.check_output(self.adb_cmd +
|
||||
['shell', 'echo'])
|
||||
return self._linesep
|
||||
|
||||
@property
|
||||
def features(self):
|
||||
if self._features is None:
|
||||
try:
|
||||
self._features = split_lines(self._simple_call(['features']))
|
||||
except subprocess.CalledProcessError:
|
||||
self._features = []
|
||||
return self._features
|
||||
|
||||
def has_shell_protocol(self):
|
||||
return version(self.adb_cmd) >= 35 and 'shell_v2' in self.features
|
||||
|
||||
def _make_shell_cmd(self, user_cmd):
|
||||
command = self.adb_cmd + ['shell'] + user_cmd
|
||||
if not self.has_shell_protocol():
|
||||
command += self._RETURN_CODE_PROBE
|
||||
return command
|
||||
|
||||
def _parse_shell_output(self, out):
|
||||
"""Finds the exit code string from shell output.
|
||||
|
||||
Args:
|
||||
out: Shell output string.
|
||||
|
||||
Returns:
|
||||
An (exit_code, output_string) tuple. The output string is
|
||||
cleaned of any additional stuff we appended to find the
|
||||
exit code.
|
||||
|
||||
Raises:
|
||||
RuntimeError: Could not find the exit code in |out|.
|
||||
"""
|
||||
search_text = out
|
||||
if len(search_text) > self._RETURN_CODE_SEARCH_LENGTH:
|
||||
# We don't want to search over massive amounts of data when we know
|
||||
# the part we want is right at the end.
|
||||
search_text = search_text[-self._RETURN_CODE_SEARCH_LENGTH:]
|
||||
partition = search_text.rpartition(self._RETURN_CODE_DELIMITER)
|
||||
if partition[1] == '':
|
||||
raise RuntimeError('Could not find exit status in shell output.')
|
||||
result = int(partition[2])
|
||||
# partition[0] won't contain the full text if search_text was
|
||||
# truncated, pull from the original string instead.
|
||||
out = out[:-len(partition[1]) - len(partition[2])]
|
||||
return result, out
|
||||
|
||||
def _simple_call(self, cmd):
|
||||
logging.info(' '.join(self.adb_cmd + cmd))
|
||||
return _subprocess_check_output(
|
||||
self.adb_cmd + cmd, stderr=subprocess.STDOUT)
|
||||
|
||||
def shell(self, cmd):
|
||||
"""Calls `adb shell`
|
||||
|
||||
Args:
|
||||
cmd: command to execute as a list of strings.
|
||||
|
||||
Returns:
|
||||
A (stdout, stderr) tuple. Stderr may be combined into stdout
|
||||
if the device doesn't support separate streams.
|
||||
|
||||
Raises:
|
||||
ShellError: the exit code was non-zero.
|
||||
"""
|
||||
exit_code, stdout, stderr = self.shell_nocheck(cmd)
|
||||
if exit_code != 0:
|
||||
raise ShellError(cmd, stdout, stderr, exit_code)
|
||||
return stdout, stderr
|
||||
|
||||
def shell_nocheck(self, cmd):
|
||||
"""Calls `adb shell`
|
||||
|
||||
Args:
|
||||
cmd: command to execute as a list of strings.
|
||||
|
||||
Returns:
|
||||
An (exit_code, stdout, stderr) tuple. Stderr may be combined
|
||||
into stdout if the device doesn't support separate streams.
|
||||
"""
|
||||
cmd = self._make_shell_cmd(cmd)
|
||||
logging.info(' '.join(cmd))
|
||||
p = _subprocess_Popen(
|
||||
cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
stdout, stderr = p.communicate()
|
||||
if self.has_shell_protocol():
|
||||
exit_code = p.returncode
|
||||
else:
|
||||
exit_code, stdout = self._parse_shell_output(stdout)
|
||||
return exit_code, stdout, stderr
|
||||
|
||||
def shell_popen(self, cmd, kill_atexit=True, preexec_fn=None,
|
||||
creationflags=0, **kwargs):
|
||||
"""Calls `adb shell` and returns a handle to the adb process.
|
||||
|
||||
This function provides direct access to the subprocess used to run the
|
||||
command, without special return code handling. Users that need the
|
||||
return value must retrieve it themselves.
|
||||
|
||||
Args:
|
||||
cmd: Array of command arguments to execute.
|
||||
kill_atexit: Whether to kill the process upon exiting.
|
||||
preexec_fn: Argument forwarded to subprocess.Popen.
|
||||
creationflags: Argument forwarded to subprocess.Popen.
|
||||
**kwargs: Arguments forwarded to subprocess.Popen.
|
||||
|
||||
Returns:
|
||||
subprocess.Popen handle to the adb shell instance
|
||||
"""
|
||||
|
||||
command = self.adb_cmd + ['shell'] + cmd
|
||||
|
||||
# Make sure a ctrl-c in the parent script doesn't kill gdbserver.
|
||||
if os.name == 'nt':
|
||||
creationflags |= subprocess.CREATE_NEW_PROCESS_GROUP
|
||||
else:
|
||||
if preexec_fn is None:
|
||||
preexec_fn = os.setpgrp
|
||||
elif preexec_fn is not os.setpgrp:
|
||||
fn = preexec_fn
|
||||
def _wrapper():
|
||||
fn()
|
||||
os.setpgrp()
|
||||
preexec_fn = _wrapper
|
||||
|
||||
p = _subprocess_Popen(command, creationflags=creationflags,
|
||||
preexec_fn=preexec_fn, **kwargs)
|
||||
|
||||
if kill_atexit:
|
||||
atexit.register(p.kill)
|
||||
|
||||
return p
|
||||
|
||||
def install(self, filename, replace=False):
|
||||
cmd = ['install']
|
||||
if replace:
|
||||
cmd.append('-r')
|
||||
cmd.append(filename)
|
||||
return self._simple_call(cmd)
|
||||
|
||||
def push(self, local, remote):
|
||||
return self._simple_call(['push', local, remote])
|
||||
|
||||
def pull(self, remote, local):
|
||||
return self._simple_call(['pull', remote, local])
|
||||
|
||||
def sync(self, directory=None):
|
||||
cmd = ['sync']
|
||||
if directory is not None:
|
||||
cmd.append(directory)
|
||||
return self._simple_call(cmd)
|
||||
|
||||
def tcpip(self, port):
|
||||
return self._simple_call(['tcpip', port])
|
||||
|
||||
def usb(self):
|
||||
return self._simple_call(['usb'])
|
||||
|
||||
def reboot(self):
|
||||
return self._simple_call(['reboot'])
|
||||
|
||||
def remount(self):
|
||||
return self._simple_call(['remount'])
|
||||
|
||||
def root(self):
|
||||
return self._simple_call(['root'])
|
||||
|
||||
def unroot(self):
|
||||
return self._simple_call(['unroot'])
|
||||
|
||||
def connect(self, host):
|
||||
return self._simple_call(['connect', host])
|
||||
|
||||
def disconnect(self, host):
|
||||
return self._simple_call(['disconnect', host])
|
||||
|
||||
def forward(self, local, remote):
|
||||
return self._simple_call(['forward', local, remote])
|
||||
|
||||
def forward_list(self):
|
||||
return self._simple_call(['forward', '--list'])
|
||||
|
||||
def forward_no_rebind(self, local, remote):
|
||||
return self._simple_call(['forward', '--no-rebind', local, remote])
|
||||
|
||||
def forward_remove(self, local):
|
||||
return self._simple_call(['forward', '--remove', local])
|
||||
|
||||
def forward_remove_all(self):
|
||||
return self._simple_call(['forward', '--remove-all'])
|
||||
|
||||
def reverse(self, remote, local):
|
||||
return self._simple_call(['reverse', remote, local])
|
||||
|
||||
def reverse_list(self):
|
||||
return self._simple_call(['reverse', '--list'])
|
||||
|
||||
def reverse_no_rebind(self, local, remote):
|
||||
return self._simple_call(['reverse', '--no-rebind', local, remote])
|
||||
|
||||
def reverse_remove_all(self):
|
||||
return self._simple_call(['reverse', '--remove-all'])
|
||||
|
||||
def reverse_remove(self, remote):
|
||||
return self._simple_call(['reverse', '--remove', remote])
|
||||
|
||||
def wait(self):
|
||||
return self._simple_call(['wait-for-device'])
|
||||
|
||||
def get_props(self):
|
||||
result = {}
|
||||
output, _ = self.shell(['getprop'])
|
||||
output = split_lines(output)
|
||||
pattern = re.compile(r'^\[([^]]+)\]: \[(.*)\]')
|
||||
for line in output:
|
||||
match = pattern.match(line)
|
||||
if match is None:
|
||||
# apple2ix NOTE : don't freak out here ...
|
||||
#raise RuntimeError('invalid getprop line: "{}"'.format(line))
|
||||
continue
|
||||
key = match.group(1)
|
||||
value = match.group(2)
|
||||
if key in result:
|
||||
raise RuntimeError('duplicate getprop key: "{}"'.format(key))
|
||||
result[key] = value
|
||||
return result
|
||||
|
||||
def get_prop(self, prop_name):
|
||||
output = split_lines(self.shell(['getprop', prop_name])[0])
|
||||
if len(output) != 1:
|
||||
raise RuntimeError('Too many lines in getprop output:\n' +
|
||||
'\n'.join(output))
|
||||
value = output[0]
|
||||
if not value.strip():
|
||||
return None
|
||||
return value
|
||||
|
||||
def set_prop(self, prop_name, value):
|
||||
self.shell(['setprop', prop_name, value])
|
|
@ -1,856 +0,0 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
# Copyright (C) 2010 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.
|
||||
#
|
||||
|
||||
# This wrapper script is used to launch a native debugging session
|
||||
# on a given NDK application. The application must be debuggable, i.e.
|
||||
# its android:debuggable attribute must be set to 'true' in the
|
||||
# <application> element of its manifest.
|
||||
#
|
||||
# See docs/NDK-GDB.TXT for usage description. Essentially, you just
|
||||
# need to launch ndk-gdb from your application project directory
|
||||
# after doing ndk-build && ant install && <start-application-on-device>
|
||||
#
|
||||
PROGDIR=`dirname $0`
|
||||
PROGDIR=`cd $PROGDIR && pwd -P`
|
||||
|
||||
#set -x
|
||||
|
||||
# Check if absolute NDK path contain space
|
||||
#
|
||||
case $PROGDIR in
|
||||
*\ *) echo "ERROR: NDK path cannot contain space"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
NDK_BUILDTOOLS_PATH=$PROGDIR/build/tools
|
||||
. $PROGDIR/build/tools/prebuilt-common.sh
|
||||
. $PROGDIR/build/tools/ndk-common.sh
|
||||
|
||||
force_32bit_binaries
|
||||
|
||||
# Find if a given shell program is available.
|
||||
# We need to take care of the fact that the 'which <foo>' command
|
||||
# may return either an empty string (Linux) or something like
|
||||
# "no <foo> in ..." (Darwin). Also, we need to redirect stderr
|
||||
# to /dev/null for Cygwin
|
||||
#
|
||||
# $1: program name
|
||||
# Out: program path, or empty string
|
||||
# Return: 0 on success, != 0 on error
|
||||
#
|
||||
find_program ()
|
||||
{
|
||||
local PROG RET
|
||||
PROG=$(which "$1" 2>/dev/null)
|
||||
RET=$?
|
||||
if [ $RET != 0 ]; then
|
||||
PROG=
|
||||
fi
|
||||
echo "$PROG"
|
||||
return $RET
|
||||
}
|
||||
|
||||
quote_spaces ()
|
||||
{
|
||||
echo "$@" | sed -e 's! !\ !g'
|
||||
}
|
||||
|
||||
# If ADB_CMD is not defined, try to find a program named 'adb'
|
||||
# in our path.
|
||||
ADB_CMD=${ADB_CMD:-$(find_program adb)}
|
||||
ADB_FLAGS=${ADB_FLAGS:-}
|
||||
DEVICE_SERIAL=
|
||||
|
||||
JDB_CMD=${JDB_CMD:-$(find_program jdb)}
|
||||
|
||||
AWK_CMD=${AWK_CMD:-$(find_program awk)}
|
||||
|
||||
DEBUG_PORT=5039
|
||||
JDB_PORT=65534
|
||||
|
||||
UNKNOWN_ABI=$(find_ndk_unknown_archs)
|
||||
|
||||
# Delay in seconds between launching the activity and attaching gdbserver on it.
|
||||
# This is needed because there is no way to know when the activity has really
|
||||
# started, and sometimes this takes a few seconds.
|
||||
DELAY=2
|
||||
|
||||
PARAMETERS=
|
||||
OPTION_HELP=no
|
||||
OPTION_PROJECT=
|
||||
OPTION_FORCE=no
|
||||
OPTION_ADB=
|
||||
OPTION_EXEC=
|
||||
OPTION_START=no
|
||||
OPTION_LAUNCH=
|
||||
OPTION_LAUNCH_LIST=no
|
||||
OPTION_DELAY=
|
||||
OPTION_WAIT="-D"
|
||||
OPTION_PACKAGE_NAME=
|
||||
|
||||
check_parameter ()
|
||||
{
|
||||
if [ -z "$2" ]; then
|
||||
echo "ERROR: Missing parameter after option '$1'"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
check_adb_flags ()
|
||||
{
|
||||
if [ -n "$ADB_FLAGS" ] ; then
|
||||
echo "ERROR: Only one of -e, -d or -s <serial> can be used at the same time!"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
get_build_var ()
|
||||
{
|
||||
if [ -z "$GNUMAKE" ] ; then
|
||||
GNUMAKE=make
|
||||
fi
|
||||
$GNUMAKE --no-print-dir -f $ANDROID_NDK_ROOT/build/core/build-local.mk -C $PROJECT DUMP_$1 | tail -1
|
||||
}
|
||||
|
||||
get_build_var_for_abi ()
|
||||
{
|
||||
if [ -z "$GNUMAKE" ] ; then
|
||||
GNUMAKE=make
|
||||
fi
|
||||
$GNUMAKE --no-print-dir -f $ANDROID_NDK_ROOT/build/core/build-local.mk -C $PROJECT DUMP_$1 APP_ABI=$2 | tail -1
|
||||
}
|
||||
|
||||
# Used to run an awk script on the manifest
|
||||
run_awk_manifest_script ()
|
||||
{
|
||||
$AWK_CMD -f $AWK_SCRIPTS/$1 $PROJECT/$MANIFEST
|
||||
}
|
||||
|
||||
if [ "$HOST_OS" = "cygwin" ] ; then
|
||||
# Return native path representation from cygwin one
|
||||
# $1: a cygwin-compatible path (e.g. /cygdrive/c/some/thing)
|
||||
# Return: path in host windows representation, e.g. C:/some/thing
|
||||
#
|
||||
# We use mixed mode (i.e. / as the directory separator) because
|
||||
# all the tools we use recognize it properly, and it avoids lots
|
||||
# of escaping nonsense associated with "\"
|
||||
#
|
||||
native_path ()
|
||||
{
|
||||
cygpath -m $1
|
||||
}
|
||||
else # HOST_OS != windows
|
||||
native_path ()
|
||||
{
|
||||
echo "$1"
|
||||
}
|
||||
fi # HOST_OS != windows
|
||||
|
||||
# We need to ensure the ANDROID_NDK_ROOT is absolute, otherwise calls
|
||||
# to get_build_var, get_build_var_for_abi and run_awk_manifest_script
|
||||
# might fail, e.g. when invoked with:
|
||||
#
|
||||
# cd $NDKROOT
|
||||
# ./ndk-gdb --project=/path/to/project
|
||||
#
|
||||
path_is_absolute ()
|
||||
{
|
||||
local P P2
|
||||
P=$1 # copy path
|
||||
P2=${P#/} # remove / prefix, if any
|
||||
[ "$P" != "$P2" ]
|
||||
}
|
||||
|
||||
if ! path_is_absolute "$ANDROID_NDK_ROOT"; then
|
||||
ANDROID_NDK_ROOT=$(pwd)/$ANDROID_NDK_ROOT
|
||||
fi
|
||||
|
||||
|
||||
VERBOSE=no
|
||||
while [ -n "$1" ]; do
|
||||
opt="$1"
|
||||
optarg=`expr "x$opt" : 'x[^=]*=\(.*\)'`
|
||||
case "$opt" in
|
||||
--help|-h|-\?)
|
||||
OPTION_HELP=yes
|
||||
;;
|
||||
--verbose)
|
||||
VERBOSE=yes
|
||||
;;
|
||||
-s)
|
||||
check_parameter $1 $2
|
||||
check_adb_flags
|
||||
ADB_FLAGS=" -s"
|
||||
DEVICE_SERIAL=$2
|
||||
shift
|
||||
;;
|
||||
-s*)
|
||||
check_adb_flags
|
||||
optarg=`expr -- "$opt" : '-s\(.*\)'`
|
||||
ADB_FLAGS=" -s"
|
||||
DEVICE_SERIAL=$optarg
|
||||
;;
|
||||
-p)
|
||||
check_parameter $1 $2
|
||||
OPTION_PROJECT="$2"
|
||||
shift
|
||||
;;
|
||||
-p*)
|
||||
optarg=`expr -- "$opt" : '-p\(.*\)'`
|
||||
OPTION_PROJECT="$optarg"
|
||||
;;
|
||||
--exec=*)
|
||||
OPTION_EXEC="$optarg"
|
||||
;;
|
||||
-x)
|
||||
check_parameter $1 $2
|
||||
OPTION_EXEC="$2"
|
||||
shift
|
||||
;;
|
||||
-x*)
|
||||
optarg=`expr -- "$opt" : '-x\(.*\)'`
|
||||
OPTION_EXEC="$optarg"
|
||||
;;
|
||||
-e)
|
||||
check_adb_flags
|
||||
ADB_FLAGS=" -e"
|
||||
;;
|
||||
-d)
|
||||
check_adb_flags
|
||||
ADB_FLAGS=" -d"
|
||||
;;
|
||||
--adb=*) # specify ADB command
|
||||
OPTION_ADB="$optarg"
|
||||
;;
|
||||
--awk=*)
|
||||
AWK_CMD="$optarg"
|
||||
;;
|
||||
--project=*)
|
||||
OPTION_PROJECT="$optarg"
|
||||
;;
|
||||
--port=*)
|
||||
DEBUG_PORT="$optarg"
|
||||
;;
|
||||
--force)
|
||||
OPTION_FORCE="yes"
|
||||
;;
|
||||
--launch-list)
|
||||
OPTION_LAUNCH_LIST="yes"
|
||||
;;
|
||||
--launch=*)
|
||||
OPTION_LAUNCH="$optarg"
|
||||
;;
|
||||
--start)
|
||||
OPTION_START=yes
|
||||
;;
|
||||
--delay=*)
|
||||
OPTION_DELAY="$optarg"
|
||||
;;
|
||||
--nowait)
|
||||
JDB_PORT=
|
||||
OPTION_WAIT=
|
||||
;;
|
||||
--package=*)
|
||||
OPTION_PACKAGE_NAME="$optarg"
|
||||
;;
|
||||
-*) # unknown options
|
||||
echo "ERROR: Unknown option '$opt', use --help for list of valid ones."
|
||||
exit 1
|
||||
;;
|
||||
*) # Simply record parameter
|
||||
if [ -z "$PARAMETERS" ] ; then
|
||||
PARAMETERS="$opt"
|
||||
else
|
||||
PARAMETERS="$PARAMETERS $opt"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
if [ -z "$JDB_CMD" ] && [ -n "$OPTION_WAIT" ]; then
|
||||
echo "ERROR: 'jdb' not found; you must either install the JDK, or specify --nowait"
|
||||
exit 1
|
||||
fi
|
||||
if [ -n "$JDB_PORT" ] && [ "$JDB_PORT" = "$DEBUG_PORT" ]; then
|
||||
echo "ERROR: --port specified cannot be $JDB_PORT without --nowait"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "$OPTION_HELP" = "yes" ] ; then
|
||||
echo "Usage: $PROGNAME [options]"
|
||||
echo ""
|
||||
echo "Setup a gdb debugging session for your Android NDK application."
|
||||
echo "Read $$NDK/docs/NDK-GDB.TXT for complete usage instructions."
|
||||
echo ""
|
||||
echo "Valid options:"
|
||||
echo ""
|
||||
echo " --help|-h|-? Print this help"
|
||||
echo " --verbose Enable verbose mode"
|
||||
echo " --force Kill existing debug session if it exists"
|
||||
echo " --nowait Don't have application wait for debugger to attach"
|
||||
echo " (This might cause you to miss some early JNI breakpoints)"
|
||||
echo " --start Launch application instead of attaching to existing one"
|
||||
echo " --launch=<name> Same as --start, but specify activity name (see below)"
|
||||
echo " --launch-list List all launchable activity names from manifest"
|
||||
echo " --delay=<secs> Delay in seconds between activity start and gdbserver attach."
|
||||
echo " --project=<path> Specify application project path"
|
||||
echo " -p <path> Same as --project=<path>"
|
||||
echo " --package=<name> Specify package name"
|
||||
echo " --port=<port> Use tcp:localhost:<port> to communicate with gdbserver [$DEBUG_PORT]"
|
||||
echo " --exec=<file> Execute gdb initialization commands in <file> after connection"
|
||||
echo " -x <file> Same as --exec=<file>"
|
||||
echo " --adb=<file> Use specific adb command [$ADB_CMD]"
|
||||
echo " --awk=<file> Use specific awk command [$AWK_CMD]"
|
||||
echo " -e Connect to single emulator instance"
|
||||
echo " -d Connect to single target device"
|
||||
echo " -s <serial> Connect to specific emulator or device"
|
||||
echo ""
|
||||
exit 0
|
||||
fi
|
||||
|
||||
log "Android NDK installation path: $ANDROID_NDK_ROOT"
|
||||
|
||||
if [ -n "$OPTION_EXEC" ] ; then
|
||||
if [ ! -f "$OPTION_EXEC" ]; then
|
||||
echo "ERROR: Invalid initialization file: $OPTION_EXEC"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -n "$OPTION_DELAY" ] ; then
|
||||
DELAY="$OPTION_DELAY"
|
||||
fi
|
||||
|
||||
# Check ADB tool version
|
||||
if [ -n "$OPTION_ADB" ] ; then
|
||||
ADB_CMD=$OPTION_ADB
|
||||
log "Using specific adb command: $ADB_CMD"
|
||||
else
|
||||
if [ -z "$ADB_CMD" ] ; then
|
||||
echo "ERROR: The 'adb' tool is not in your path."
|
||||
echo " You can change your PATH variable, or use"
|
||||
echo " --adb=<executable> to point to a valid one."
|
||||
exit 1
|
||||
fi
|
||||
log "Using default adb command: $ADB_CMD"
|
||||
fi
|
||||
|
||||
ADB_CMD=$(quote_spaces $ADB_CMD)
|
||||
ADB_VERSION=$("$ADB_CMD" version 2>/dev/null)
|
||||
if [ $? != 0 ] ; then
|
||||
echo "ERROR: Could not run ADB with: $ADB_CMD"
|
||||
exit 1
|
||||
fi
|
||||
log "ADB version found: $ADB_VERSION"
|
||||
|
||||
if [ "x$DEVICE_SERIAL" = "x" ]; then
|
||||
log "Using ADB flags: $ADB_FLAGS"
|
||||
else
|
||||
log "Using ADB flags: $ADB_FLAGS" \"$DEVICE_SERIAL\"
|
||||
fi
|
||||
|
||||
JDB_CMD=$(quote_spaces $JDB_CMD)
|
||||
log "Using JDB command: $JDB_CMD"
|
||||
|
||||
# Run an ADB command with the right ADB flags
|
||||
# $1+: adb command parameter
|
||||
adb_cmd ()
|
||||
{
|
||||
if [ "x$DEVICE_SERIAL" = "x" ]; then
|
||||
"$ADB_CMD" $ADB_FLAGS "$@"
|
||||
else
|
||||
# NOTE: We escape $ADB_CMD and $DEVICE_SERIAL in case they contains spaces.
|
||||
"$ADB_CMD" $ADB_FLAGS "$DEVICE_SERIAL" "$@"
|
||||
fi
|
||||
}
|
||||
|
||||
# Used internally by adb_var_shell and adb_var_shell2.
|
||||
# $1: 1 to redirect stderr to $1, 0 otherwise.
|
||||
# $2: Variable name that will contain the result
|
||||
# $3+: Command options
|
||||
_adb_var_shell ()
|
||||
{
|
||||
# We need a temporary file to store the output of our command
|
||||
local CMD_OUT RET OUTPUT VARNAME REDIRECT_STDERR
|
||||
REDIRECT_STDERR=$1
|
||||
VARNAME=$2
|
||||
shift; shift;
|
||||
CMD_OUT=`mktemp /tmp/ndk-gdb-cmdout-XXXXXX`
|
||||
# Run the command, while storing the standard output to CMD_OUT
|
||||
# and appending the exit code as the last line.
|
||||
if [ "$REDIRECT_STDERR" != 0 ]; then
|
||||
adb_cmd shell "$@" ";" echo \$? | sed -e 's![[:cntrl:]]!!g' > $CMD_OUT 2>&1
|
||||
else
|
||||
adb_cmd shell "$@" ";" echo \$? | sed -e 's![[:cntrl:]]!!g' > $CMD_OUT
|
||||
fi
|
||||
# Get last line in log, which contains the exit code from the command
|
||||
RET=`sed -e '$!d' $CMD_OUT`
|
||||
# Get output, which corresponds to everything except the last line
|
||||
OUT=`sed -e '$d' $CMD_OUT`
|
||||
rm -f $CMD_OUT
|
||||
eval $VARNAME=\"\$OUT\"
|
||||
return $RET
|
||||
}
|
||||
|
||||
# Run a command through 'adb shell' and captures its standard output
|
||||
# into a variable. The function's exit code is the same than the command's.
|
||||
#
|
||||
# This is required because there is a bug where "adb shell" always returns
|
||||
# 0 on the host, even if the command fails on the device.
|
||||
#
|
||||
# $1: Variable name (e.g. FOO)
|
||||
# On exit, $FOO is set to the command's standard output
|
||||
#
|
||||
# The return status will be 0 (success) if the command succeeded
|
||||
# or 1 (failure) otherwise.
|
||||
adb_var_shell ()
|
||||
{
|
||||
_adb_var_shell 0 "$@"
|
||||
}
|
||||
|
||||
# A variant of adb_var_shell that stores both stdout and stderr in the output
|
||||
# $1: Variable name
|
||||
adb_var_shell2 ()
|
||||
{
|
||||
_adb_var_shell 1 "$@"
|
||||
}
|
||||
|
||||
# Return the PID of a given package or program, or 0 if it doesn't run
|
||||
# $1: Package name ("com.example.hellojni") or program name ("/lib/gdbserver")
|
||||
# Out: PID number, or 0 if not running
|
||||
get_pid_of ()
|
||||
{
|
||||
adb_cmd shell ps | $AWK_CMD -f $AWK_SCRIPTS/extract-pid.awk -v PACKAGE="$1"
|
||||
}
|
||||
|
||||
# Check the awk tool
|
||||
AWK_SCRIPTS=$ANDROID_NDK_ROOT/build/awk
|
||||
AWK_TEST=`$AWK_CMD -f $AWK_SCRIPTS/check-awk.awk`
|
||||
if [ $? != 0 ] ; then
|
||||
echo "ERROR: Could not run '$AWK_CMD' command. Do you have it installed properly?"
|
||||
exit 1
|
||||
fi
|
||||
if [ "$AWK_TEST" != "Pass" ] ; then
|
||||
echo "ERROR: Your version of 'awk' is obsolete. Please use --awk=<file> to point to Nawk or Gawk!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Name of the manifest file
|
||||
MANIFEST=AndroidManifest.xml
|
||||
|
||||
# Find the root of the application project.
|
||||
if [ -n "$OPTION_PROJECT" ] ; then
|
||||
PROJECT=$OPTION_PROJECT
|
||||
log "Using specified project path: $PROJECT"
|
||||
if [ ! -d "$PROJECT" ] ; then
|
||||
echo "ERROR: Your --project option does not point to a directory!"
|
||||
exit 1
|
||||
fi
|
||||
if [ ! -f "$PROJECT/$MANIFEST" ] ; then
|
||||
echo "ERROR: Your --project does not point to an Android project path!"
|
||||
echo " It is missing a $MANIFEST file."
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
# Assume we are in the project directory
|
||||
if [ -f "$MANIFEST" ] ; then
|
||||
PROJECT=.
|
||||
else
|
||||
PROJECT=
|
||||
CURDIR=`pwd`
|
||||
while [ "$CURDIR" != "/" ] ; do
|
||||
if [ -f "$CURDIR/$MANIFEST" ] ; then
|
||||
PROJECT="$CURDIR"
|
||||
break
|
||||
fi
|
||||
CURDIR=`dirname $CURDIR`
|
||||
done
|
||||
if [ -z "$PROJECT" ] ; then
|
||||
echo "ERROR: Launch this script from an application project directory, or use --project=<path>."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
log "Using auto-detected project path: $PROJECT"
|
||||
fi
|
||||
|
||||
if [ ! -z "$OPTION_PACKAGE_NAME" ]; then
|
||||
PACKAGE_NAME="$OPTION_PACKAGE_NAME"
|
||||
log "Using package name: $PACKAGE_NAME"
|
||||
else
|
||||
# Extract the package name from the manifest
|
||||
PACKAGE_NAME=`run_awk_manifest_script extract-package-name.awk`
|
||||
if [ $? != 0 -o "$PACKAGE_NAME" = "<none>" ] ; then
|
||||
echo "ERROR: Could not extract package name from $PROJECT/$MANIFEST."
|
||||
echo " Please check that the file is well-formed!"
|
||||
exit 1
|
||||
fi
|
||||
log "Found package name: $PACKAGE_NAME"
|
||||
fi
|
||||
|
||||
# If --launch-list is used, list all launchable activities, and be done with it
|
||||
if [ "$OPTION_LAUNCH_LIST" = "yes" ] ; then
|
||||
log "Extracting list of launchable activities from manifest:"
|
||||
run_awk_manifest_script extract-launchable.awk
|
||||
exit 0
|
||||
fi
|
||||
|
||||
APP_ABIS=`get_build_var APP_ABI`
|
||||
if [ "$APP_ABIS" != "${APP_ABIS%%all*}" ] ; then
|
||||
# replace first "all" with all available ABIs
|
||||
ALL_ABIS=`get_build_var NDK_ALL_ABIS`
|
||||
APP_ABIS_FRONT="${APP_ABIS%%all*}"
|
||||
APP_ABIS_BACK="${APP_ABIS#*all}"
|
||||
APP_ABIS="${APP_ABIS_FRONT}${ALL_ABIS}${APP_ABIS_BACK}"
|
||||
fi
|
||||
# replace "armeabi-v7a-hard" with "armeabi-v7a"
|
||||
APP_ABIS=`echo $APP_ABIS | sed -e 's/armeabi-v7a-hard/armeabi-v7a/g'`
|
||||
log "ABIs targetted by application: $APP_ABIS"
|
||||
|
||||
# Check the ADB command, and that we can connect to the device/emulator
|
||||
ADB_TEST=`adb_cmd shell ls`
|
||||
if [ $? != 0 ] ; then
|
||||
echo "ERROR: Could not connect to device or emulator!"
|
||||
echo " Please check that an emulator is running or a device is connected"
|
||||
echo " through USB to this machine. You can use -e, -d and -s <serial>"
|
||||
echo " in case of multiple ones."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check that the device is running Froyo (API Level 8) or higher
|
||||
#
|
||||
adb_var_shell API_LEVEL getprop ro.build.version.sdk
|
||||
if [ $? != 0 -o -z "$API_LEVEL" ] ; then
|
||||
echo "ERROR: Could not find target device's supported API level!"
|
||||
echo "ndk-gdb will only work if your device is running Android 2.2 or higher."
|
||||
exit 1
|
||||
fi
|
||||
log "Device API Level: $API_LEVEL"
|
||||
if [ "$API_LEVEL" -lt "8" ] ; then
|
||||
echo "ERROR: ndk-gdb requires a target device running Android 2.2 (API level 8) or higher."
|
||||
echo "The target device is running API level $API_LEVEL!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Get the target device's supported ABI(s)
|
||||
# And check that they are supported by the application
|
||||
#
|
||||
COMPAT_ABI=none
|
||||
|
||||
# All modern Android images must support ro.product.cpu.abilist32
|
||||
# and ro.product.cpu.abilist64. Otherwise fall back to obsolete
|
||||
# ro.product.cpu.abi and ro.product.cpu.abi2
|
||||
adb_var_shell CPU_ABILIST64 getprop ro.product.cpu.abilist64
|
||||
adb_var_shell CPU_ABILIST32 getprop ro.product.cpu.abilist32
|
||||
CPU_ABIS="$CPU_ABILIST64,$CPU_ABILIST32"
|
||||
if [ -z "$CPU_ABILIST64" ] && [ -z "$CPU_ABILIST32" ] ; then
|
||||
adb_var_shell CPU_ABI1 getprop ro.product.cpu.abi
|
||||
adb_var_shell CPU_ABI2 getprop ro.product.cpu.abi2
|
||||
CPU_ABIS="$CPU_ABI1,$CPU_ABI2"
|
||||
fi
|
||||
|
||||
# Replace all ',' with space and add trailing space to
|
||||
# ease whole-word matching of APP_ABI
|
||||
CPU_ABILIST64=$(echo $CPU_ABILIST64 | tr ',' ' ')
|
||||
CPU_ABILIST32=$(echo $CPU_ABILIST32 | tr ',' ' ')
|
||||
CPU_ABIS=$(echo $CPU_ABIS | tr ',' ' ')
|
||||
log "Device CPU ABIs: $CPU_ABIS"
|
||||
|
||||
APP_ABIS=$APP_ABIS" "
|
||||
|
||||
adb_var_shell BCFILES run-as $PACKAGE_NAME /system/bin/sh -c "ls lib/*.bc"
|
||||
####if [ $? = 0 ]; then
|
||||
#### COMPAT_ABI="$UNKNOWN_ABI"
|
||||
####else
|
||||
# Assume that compatible ABI is 32-bit
|
||||
COMPAT_ABI_BITS=32
|
||||
# First look compatible ABI in the list of 64-bit ABIs
|
||||
if [ -n "$CPU_ABILIST64" ] ; then
|
||||
for CPU_ABI64 in $CPU_ABILIST64; do
|
||||
if [ "$APP_ABIS" != "${APP_ABIS%$CPU_ABI64 *}" ] ; then
|
||||
COMPAT_ABI=$CPU_ABI64
|
||||
COMPAT_ABI_BITS=64
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
# If we found nothing - look among 32-bit ABIs
|
||||
if [ "$COMPAT_ABI" = none ] && [ -n "$CPU_ABILIST32" ] ; then
|
||||
for CPU_ABI32 in $CPU_ABILIST32; do
|
||||
if [ "$APP_ABIS" != "${APP_ABIS%$CPU_ABI32 *}" ] ; then
|
||||
COMPAT_ABI=$CPU_ABI32
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
# Lastly, lets check ro.product.cpu.abi and ro.product.cpu.abi2
|
||||
if [ "$COMPAT_ABI" = none ] && [ -z "$CPU_ABILIST64" ] && [ -z "$CPU_ABILIST32" ]; then
|
||||
for CPU_ABI in $CPU_ABIS; do
|
||||
if [ "$APP_ABIS" != "${APP_ABIS%$CPU_ABI *}" ] ; then
|
||||
COMPAT_ABI=$CPU_ABI
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
####fi
|
||||
|
||||
if [ "$COMPAT_ABI" = none ] ; then
|
||||
COMPAT_ABI='armeabi'
|
||||
fi
|
||||
log "Compatible device ABI: $COMPAT_ABI"
|
||||
|
||||
# Get information from the build system
|
||||
GDBSETUP_INIT=`get_build_var_for_abi NDK_APP_GDBSETUP $COMPAT_ABI`
|
||||
log "Using gdb setup init: $GDBSETUP_INIT"
|
||||
|
||||
# Find the prefix for gdb-client
|
||||
if [ "$COMPAT_ABI" != "$UNKNOWN_ABI" ]; then
|
||||
TOOLCHAIN_PREFIX=`get_build_var_for_abi TOOLCHAIN_PREFIX $COMPAT_ABI`
|
||||
else
|
||||
TOOLCHAIN_ABI=$(echo $CPU_ABIS | awk '{print $NF}')
|
||||
TOOLCHAIN_PREFIX=`get_build_var_for_abi TOOLCHAIN_PREFIX $TOOLCHAIN_ABI`
|
||||
fi
|
||||
log "Using toolchain prefix: $TOOLCHAIN_PREFIX"
|
||||
|
||||
APP_OUT=`get_build_var_for_abi TARGET_OUT $COMPAT_ABI`
|
||||
log "Using app out directory: $APP_OUT"
|
||||
|
||||
# Check that the application is debuggable, or nothing will work
|
||||
####DEBUGGABLE=`run_awk_manifest_script extract-debuggable.awk`
|
||||
####RET=$?
|
||||
####log "Found debuggable flag: $DEBUGGABLE"
|
||||
####if [ "$RET" != 0 -o "$DEBUGGABLE" != "true" ] ; then
|
||||
#### # If gdb.setup exists, then we built with 'ndk-build NDK_DEBUG=1' and it's
|
||||
#### # ok to not have android:debuggable set to true in the original manifest.
|
||||
#### # However, if this is not the case, then complain!!
|
||||
#### if [ -f $PROJECT/libs/$COMPAT_ABI/gdb.setup ] ; then
|
||||
#### log "Found gdb.setup under libs/$COMPAT_ABI, assuming app was built with NDK_DEBUG=1"
|
||||
#### else
|
||||
#### echo "ERROR: Package $PACKAGE_NAME is not debuggable ! You can fix that in two ways:"
|
||||
#### echo ""
|
||||
#### echo " - Rebuilt with the NDK_DEBUG=1 option when calling 'ndk-build'."
|
||||
#### echo ""
|
||||
#### echo " - Modify your manifest to set android:debuggable attribute to \"true\","
|
||||
#### echo " then rebuild normally."
|
||||
#### echo ""
|
||||
#### echo "After one of these, re-install to the device!"
|
||||
#### exit 1
|
||||
#### fi
|
||||
####else
|
||||
# DEBUGGABLE is true in the manifest. Let's check that the user didn't change the
|
||||
# debuggable flag in the manifest without calling ndk-build afterwards.
|
||||
if [ ! -f $PROJECT/libs/$COMPAT_ABI/gdb.setup ] ; then
|
||||
echo "ERROR: Could not find gdb.setup under $PROJECT/libs/$COMPAT_ABI"
|
||||
echo " This usually means you modified your AndroidManifest.xml to set"
|
||||
echo " the android:debuggable flag to 'true' but did not rebuild the"
|
||||
echo " native binaries. Please call 'ndk-build' to do so,"
|
||||
echo " *then* re-install to the device!"
|
||||
exit 1
|
||||
fi
|
||||
####fi
|
||||
|
||||
# Find the <dataDir> of the package on the device
|
||||
adb_var_shell2 DATA_DIR run-as $PACKAGE_NAME /system/bin/sh -c pwd
|
||||
if [ $? != 0 -o -z "$DATA_DIR" ] ; then
|
||||
echo "ERROR: Could not extract package's data directory. Are you sure that"
|
||||
echo " your installed application is debuggable?"
|
||||
exit 1
|
||||
fi
|
||||
log "Found data directory: '$DATA_DIR'"
|
||||
|
||||
# Let's check that 'gdbserver' is properly installed on the device too. If 'gdbserver'
|
||||
# is not there, push 'gdbserver' found in prebuilt.
|
||||
#
|
||||
DEVICE_GDBSERVER=$DATA_DIR/lib/gdbserver
|
||||
adb_var_shell2 GDBSERVER_RESULT run-as $PACKAGE_NAME ls $DEVICE_GDBSERVER
|
||||
if [ $? != 0 ]; then
|
||||
|
||||
# Figure out what's the target-arch and find gdbserver in prebuilt.
|
||||
TARGET_ARCH=none
|
||||
|
||||
for ANDROID_ARCH in $ANDROID_NDK_ROOT/prebuilt/android-*; do
|
||||
ANDROID_ARCH=${ANDROID_ARCH#$ANDROID_NDK_ROOT/prebuilt/android-}
|
||||
if [ "$COMPAT_ABI" = "$ANDROID_ARCH" ]; then
|
||||
TARGET_ARCH=$ANDROID_ARCH
|
||||
break;
|
||||
fi
|
||||
done
|
||||
|
||||
if [ $TARGET_ARCH != "none" ]; then
|
||||
DEVICE_GDBSERVER=/data/local/tmp/gdbserver
|
||||
|
||||
adb shell mkdir -p /data/local/tmp
|
||||
adb push ${ANDROID_NDK_ROOT}/prebuilt/android-${TARGET_ARCH}/gdbserver/gdbserver \
|
||||
$DEVICE_GDBSERVER
|
||||
log "Push gdbserver in device"
|
||||
else
|
||||
echo "ERROR: Non-debuggable application installed on the target device."
|
||||
echo " Please re-install the debuggable version!"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
log "Found device gdbserver: $DEVICE_GDBSERVER"
|
||||
|
||||
# Launch the activity if needed
|
||||
if [ "$OPTION_START" = "yes" ] ; then
|
||||
# If --launch is used, ignore --start, otherwise extract the first
|
||||
# launchable activity name from the manifest and use it as if --launch=<name>
|
||||
# was used instead.
|
||||
#
|
||||
if [ -z "$OPTION_LAUNCH" ] ; then
|
||||
OPTION_LAUNCH=`run_awk_manifest_script extract-launchable.awk | sed 2q`
|
||||
if [ $? != 0 ] ; then
|
||||
echo "ERROR: Could not extract name of launchable activity from manifest!"
|
||||
echo " Try to use --launch=<name> directly instead as a work-around."
|
||||
exit 1
|
||||
fi
|
||||
log "Found first launchable activity: $OPTION_LAUNCH"
|
||||
if [ -z "$OPTION_LAUNCH" ] ; then
|
||||
echo "ERROR: It seems that your Application does not have any launchable activity!"
|
||||
echo " Please fix your manifest file and rebuild/re-install your application."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -n "$OPTION_LAUNCH" ] ; then
|
||||
log "Launching activity: $PACKAGE_NAME/$OPTION_LAUNCH"
|
||||
adb_var_shell2 DUMMY am start $OPTION_WAIT -n $PACKAGE_NAME/$OPTION_LAUNCH
|
||||
if [ $? != 0 ] ; then
|
||||
echo "ERROR: Could not launch specified activity: $OPTION_LAUNCH"
|
||||
echo " Use --launch-list to dump a list of valid values."
|
||||
exit 1
|
||||
fi
|
||||
# Sleep a bit, it sometimes take one second to start properly
|
||||
# Note that we use the 'sleep' command on the device here.
|
||||
run adb_cmd shell sleep $DELAY
|
||||
fi
|
||||
|
||||
# Find the PID of the application being run
|
||||
PID=$(get_pid_of "$PACKAGE_NAME")
|
||||
RET=$?
|
||||
log "Found running PID: $PID"
|
||||
if [ "$RET" != 0 -o "$PID" = "0" ] ; then
|
||||
echo "ERROR: Could not extract PID of application on device/emulator."
|
||||
if [ -n "$OPTION_LAUNCH" ] ; then
|
||||
echo " Weird, this probably means one of these:"
|
||||
echo ""
|
||||
echo " - The installed package does not match your current manifest."
|
||||
echo " - The application process was terminated."
|
||||
echo ""
|
||||
echo " Try using the --verbose option and look at its output for details."
|
||||
else
|
||||
echo " Are you sure the application is already started?"
|
||||
echo " Consider using --start or --launch=<name> if not."
|
||||
fi
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check that there is no other instance of gdbserver running
|
||||
GDBSERVER_PID=$(get_pid_of lib/gdbserver)
|
||||
if [ "$GDBSERVER_PID" != "0" ]; then
|
||||
if [ "$OPTION_FORCE" = "no" ] ; then
|
||||
echo "ERROR: Another debug session running, Use --force to kill it."
|
||||
exit 1
|
||||
fi
|
||||
log "Killing existing debugging session"
|
||||
run adb_cmd shell kill -9 $GDBSERVER_PID
|
||||
fi
|
||||
|
||||
# Launch gdbserver now
|
||||
DEBUG_SOCKET=debug-socket
|
||||
adb_var_shell2 DUMMY run-as $PACKAGE_NAME $DEVICE_GDBSERVER +$DEBUG_SOCKET --attach $PID &
|
||||
if [ $? != 0 ] ; then
|
||||
echo "ERROR: Could not launch gdbserver on the device?"
|
||||
exit 1
|
||||
fi
|
||||
log "Launched gdbserver succesfully."
|
||||
|
||||
# Setup network redirection
|
||||
log "Setup network redirection"
|
||||
run adb_cmd forward tcp:$DEBUG_PORT localfilesystem:$DATA_DIR/$DEBUG_SOCKET
|
||||
if [ $? != 0 ] ; then
|
||||
echo "ERROR: Could not setup network redirection to gdbserver?"
|
||||
echo " Maybe using --port=<port> to use a different TCP port might help?"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# If we are debugging 64-bit app, then we need to pull linker64,
|
||||
# app_process64 and libc.so from lib64 directory
|
||||
LINKER_NAME=linker
|
||||
LIBDIR_NAME=lib
|
||||
APP_PROCESS_NAME=app_process32
|
||||
if [ "$COMPAT_ABI_BITS" = 64 ] ; then
|
||||
LINKER_NAME=linker64
|
||||
LIBDIR_NAME=lib64
|
||||
APP_PROCESS_NAME=app_process64
|
||||
else
|
||||
# Old 32-bit devices do not have app_process32. Pull
|
||||
# app_process in this case
|
||||
adb_var_shell2 DUMMY test -e /system/bin/$APP_PROCESS_NAME
|
||||
if [ $? != 0 ] ; then
|
||||
APP_PROCESS_NAME=app_process
|
||||
fi
|
||||
fi
|
||||
|
||||
# Get the app_server binary from the device
|
||||
APP_PROCESS=$APP_OUT/app_process
|
||||
run adb_cmd pull /system/bin/$APP_PROCESS_NAME `native_path $APP_PROCESS`
|
||||
log "Pulled $APP_PROCESS_NAME from device/emulator."
|
||||
|
||||
run adb_cmd pull /system/bin/$LINKER_NAME `native_path $APP_OUT/$LINKER_NAME`
|
||||
log "Pulled $LINKER_NAME from device/emulator."
|
||||
|
||||
run adb_cmd pull /system/$LIBDIR_NAME/libc.so `native_path $APP_OUT/libc.so`
|
||||
log "Pulled /system/$LIBDIR_NAME/libc.so from device/emulator."
|
||||
|
||||
# Setup JDB connection, for --start or --launch
|
||||
if [ "$OPTION_START" = "yes" ] || [ -n "$OPTION_LAUNCH" ] ; then
|
||||
if [ -n "$JDB_PORT" ]; then
|
||||
log "Setup JDB connection"
|
||||
run adb_cmd forward tcp:$JDB_PORT jdwp:$PID
|
||||
sleep 1
|
||||
$JDB_CMD -connect com.sun.jdi.SocketAttach:hostname=localhost,port=$JDB_PORT &
|
||||
sleep 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# If we are debugging UNKNOWN_ABI, download compiled *.so from device.
|
||||
#
|
||||
if [ "$COMPAT_ABI" = "$UNKNOWN_ABI" ]; then
|
||||
for bc in $BCFILES; do
|
||||
log "Pulled $(basename $bc .bc).so from device/emulator."
|
||||
adb pull $DATA_DIR/lib/$(basename $bc .bc).so $PROJECT/obj/local/$UNKNOWN_ABI/
|
||||
done
|
||||
fi
|
||||
|
||||
# Now launch the appropriate gdb client with the right init commands
|
||||
#
|
||||
GDBCLIENT=${TOOLCHAIN_PREFIX}gdb
|
||||
GDBSETUP=$APP_OUT/gdb.setup
|
||||
cp -f $GDBSETUP_INIT $GDBSETUP
|
||||
#uncomment the following to debug the remote connection only
|
||||
#echo "set debug remote 1" >> $GDBSETUP
|
||||
echo "file `native_path $APP_PROCESS`" >> $GDBSETUP
|
||||
echo "target remote :$DEBUG_PORT" >> $GDBSETUP
|
||||
if [ -n "$OPTION_EXEC" ] ; then
|
||||
cat $OPTION_EXEC >> $GDBSETUP
|
||||
fi
|
||||
$GDBCLIENT -x `native_path $GDBSETUP`
|
||||
|
||||
set +x
|
File diff suppressed because it is too large
Load Diff
|
@ -1,9 +0,0 @@
|
|||
//
|
||||
// Prefix header
|
||||
//
|
||||
// The contents of this file are implicitly included at the beginning of every source file.
|
||||
//
|
||||
|
||||
#ifdef __OBJC__
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#endif
|
|
@ -80,9 +80,10 @@
|
|||
{
|
||||
cpu_pause();
|
||||
timing_toggleCPUSpeed();
|
||||
if (video_animations && video_animations->animation_showCPUSpeed)
|
||||
video_animation_s *anim = video_getAnimationDriver();
|
||||
if (anim && anim->animation_showCPUSpeed)
|
||||
{
|
||||
video_animations->animation_showCPUSpeed();
|
||||
anim->animation_showCPUSpeed();
|
||||
}
|
||||
cpu_resume();
|
||||
}
|
||||
|
@ -92,6 +93,7 @@
|
|||
NSAssert(pthread_main_np(), @"Pause emulation called from non-main thread");
|
||||
self.paused = !_paused;
|
||||
}
|
||||
|
||||
- (void)setPaused:(BOOL)paused
|
||||
{
|
||||
if (_paused == paused)
|
||||
|
@ -102,15 +104,17 @@
|
|||
_paused = paused;
|
||||
if (paused)
|
||||
{
|
||||
cpu_pause();
|
||||
cpu_pause();
|
||||
}
|
||||
else
|
||||
{
|
||||
cpu_resume();
|
||||
}
|
||||
if (video_animations && video_animations->animation_showPaused)
|
||||
|
||||
video_animation_s *anim = video_getAnimationDriver();
|
||||
if (anim && anim->animation_showPaused)
|
||||
{
|
||||
video_animations->animation_showPaused();
|
||||
anim->animation_showPaused();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="9531" systemVersion="15C50" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none">
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="14490.70" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none">
|
||||
<dependencies>
|
||||
<deployment version="1060" identifier="macosx"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="9531"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14490.70"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<customObject id="-2" userLabel="File's Owner" customClass="NSApplication">
|
||||
|
@ -375,7 +376,7 @@ CA
|
|||
</items>
|
||||
</menu>
|
||||
<window title="Apple2Mac" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" animationBehavior="default" id="371" userLabel="Window - Apple2Mac" customClass="EmulatorWindow">
|
||||
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES" unifiedTitleAndToolbar="YES"/>
|
||||
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
|
||||
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
|
||||
<rect key="contentRect" x="200" y="200" width="568" height="384"/>
|
||||
<rect key="screenRect" x="0.0" y="0.0" width="1920" height="1178"/>
|
||||
|
@ -424,7 +425,7 @@ CA
|
|||
<outlet property="window" destination="371" id="z3B-S9-PsV"/>
|
||||
</connections>
|
||||
</customObject>
|
||||
<window title="Insert Disks" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" oneShot="NO" releasedWhenClosed="NO" showsToolbarButton="NO" visibleAtLaunch="NO" animationBehavior="default" id="RAk-at-ZT4" userLabel="Window - Insert Disks">
|
||||
<window title="Insert Disks" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" id="RAk-at-ZT4" userLabel="Window - Insert Disks">
|
||||
<windowStyleMask key="styleMask" titled="YES" closable="YES"/>
|
||||
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
|
||||
<rect key="contentRect" x="109" y="132" width="522" height="302"/>
|
||||
|
@ -598,19 +599,13 @@ CA
|
|||
<action selector="startupDiskBChoiceChanged:" target="FHO-g2-V3A" id="tQS-5l-DDf"/>
|
||||
</connections>
|
||||
</button>
|
||||
<box verticalHuggingPriority="750" title="Box" boxType="separator" titlePosition="noTitle" id="7ZU-H6-jQn">
|
||||
<box verticalHuggingPriority="750" boxType="separator" id="7ZU-H6-jQn">
|
||||
<rect key="frame" x="12" y="59" width="498" height="5"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<color key="borderColor" white="0.0" alpha="0.41999999999999998" colorSpace="calibratedWhite"/>
|
||||
<color key="fillColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
|
||||
<font key="titleFont" metaFont="system"/>
|
||||
</box>
|
||||
<box horizontalHuggingPriority="750" title="Box" boxType="separator" titlePosition="noTitle" id="864-Ov-2tE">
|
||||
<box horizontalHuggingPriority="750" boxType="separator" id="864-Ov-2tE">
|
||||
<rect key="frame" x="259" y="70" width="5" height="217"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<color key="borderColor" white="0.0" alpha="0.41999999999999998" colorSpace="calibratedWhite"/>
|
||||
<color key="fillColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
|
||||
<font key="titleFont" metaFont="system"/>
|
||||
</box>
|
||||
<button verticalHuggingPriority="750" id="tLd-IJ-Kjl">
|
||||
<rect key="frame" x="338" y="13" width="85" height="32"/>
|
||||
|
@ -645,7 +640,7 @@ DQ
|
|||
<outlet property="startupLoadDiskB" destination="Ceo-uO-cRu" id="V0B-0f-YZu"/>
|
||||
</connections>
|
||||
</customObject>
|
||||
<window title="Apple2Mac Preferences" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" oneShot="NO" releasedWhenClosed="NO" showsToolbarButton="NO" visibleAtLaunch="NO" animationBehavior="default" id="Mzv-VG-jce" userLabel="Window - Prefs" customClass="EmulatorWindow">
|
||||
<window title="Apple2Mac Preferences" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" id="Mzv-VG-jce" userLabel="Window - Prefs" customClass="EmulatorWindow">
|
||||
<windowStyleMask key="styleMask" titled="YES" closable="YES"/>
|
||||
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
|
||||
<rect key="contentRect" x="109" y="132" width="580" height="360"/>
|
||||
|
@ -721,12 +716,9 @@ DQ
|
|||
<action selector="peggedChoiceChanged:" target="mUW-Rh-bL1" id="K2H-Vc-15h"/>
|
||||
</connections>
|
||||
</button>
|
||||
<box verticalHuggingPriority="750" title="Box" boxType="separator" titlePosition="noTitle" id="9U0-v9-wTm">
|
||||
<box verticalHuggingPriority="750" boxType="separator" id="9U0-v9-wTm">
|
||||
<rect key="frame" x="17" y="183" width="508" height="5"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<color key="borderColor" white="0.0" alpha="0.41999999999999998" colorSpace="calibratedWhite"/>
|
||||
<color key="fillColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
|
||||
<font key="titleFont" metaFont="system"/>
|
||||
</box>
|
||||
<slider verticalHuggingPriority="750" id="y10-Rm-oDB">
|
||||
<rect key="frame" x="15" y="115" width="404" height="27"/>
|
||||
|
@ -846,12 +838,9 @@ DQ
|
|||
<rect key="frame" x="10" y="33" width="534" height="298"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<box horizontalHuggingPriority="750" title="Box" boxType="separator" titlePosition="noTitle" id="Fkg-X3-0XG">
|
||||
<box horizontalHuggingPriority="750" boxType="separator" id="Fkg-X3-0XG">
|
||||
<rect key="frame" x="265" y="9" width="5" height="286"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<color key="borderColor" white="0.0" alpha="0.41999999999999998" colorSpace="calibratedWhite"/>
|
||||
<color key="fillColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
|
||||
<font key="titleFont" metaFont="system"/>
|
||||
</box>
|
||||
<customView id="OWJ-x7-P0q" customClass="EmulatorJoystickCalibrationView">
|
||||
<rect key="frame" x="276" y="39" width="256" height="256"/>
|
||||
|
|
|
@ -56,23 +56,34 @@
|
|||
{
|
||||
// This method is triggered whenever the user makes a change to the picker selection.
|
||||
// The parameter named row and component represents what was selected.
|
||||
int drive=0;
|
||||
BOOL ro=YES;
|
||||
int drive = 0;
|
||||
BOOL ro = YES;
|
||||
|
||||
if(pickerView==self.disk1Picker)
|
||||
if (pickerView == self.disk1Picker)
|
||||
{
|
||||
drive=0;
|
||||
ro=self.diskAProtection.on;
|
||||
}
|
||||
if(pickerView==self.disk2Picker)
|
||||
if (pickerView == self.disk2Picker)
|
||||
{
|
||||
drive=1;
|
||||
drive=1;
|
||||
ro=self.diskBProtection.on;
|
||||
}
|
||||
|
||||
NSLog(@"Selected Row %d %@ %c", row,(NSString*)[self._disks objectAtIndex:row],ro);
|
||||
disk6_eject(drive);
|
||||
const char *errMsg = disk6_insert(drive, [[self.path stringByAppendingPathComponent:[self._disks objectAtIndex:row]] UTF8String], ro);
|
||||
|
||||
const char *path = [[self.path stringByAppendingPathComponent:[self._disks objectAtIndex:row]] UTF8String];
|
||||
int fd = -1;
|
||||
TEMP_FAILURE_RETRY(fd = open(path, ro ? O_RDONLY : O_RDWR));
|
||||
if (fd == -1) {
|
||||
LOG("OOPS, open failed for path %s (%s)", path, strerror(errno));
|
||||
}
|
||||
const char *errMsg = disk6_insert(fd, drive, path, ro);
|
||||
(void)errMsg;
|
||||
if (fd >= 0) {
|
||||
TEMP_FAILURE_RETRY(close(fd));
|
||||
}
|
||||
}
|
||||
|
||||
- (IBAction)unwindToMainViewController:(UIStoryboardSegue*)sender
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="10117" systemVersion="15G1004" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none">
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="14490.70" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none">
|
||||
<dependencies>
|
||||
<deployment version="1060" identifier="macosx"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="10117"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14490.70"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<customObject id="-2" userLabel="File's Owner" customClass="NSApplication">
|
||||
|
@ -373,13 +374,14 @@ CA
|
|||
</menu>
|
||||
</menuItem>
|
||||
</items>
|
||||
<point key="canvasLocation" x="-608" y="-1487"/>
|
||||
</menu>
|
||||
<window title="Apple2Mac" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" animationBehavior="default" id="371" userLabel="Window - Apple2Mac" customClass="EmulatorWindow">
|
||||
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES" unifiedTitleAndToolbar="YES"/>
|
||||
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
|
||||
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
|
||||
<rect key="contentRect" x="200" y="200" width="568" height="384"/>
|
||||
<rect key="screenRect" x="0.0" y="0.0" width="1920" height="1178"/>
|
||||
<view key="contentView" id="372" customClass="EmulatorGLView">
|
||||
<view key="contentView" id="372">
|
||||
<rect key="frame" x="0.0" y="0.0" width="568" height="384"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</view>
|
||||
|
@ -428,7 +430,7 @@ CA
|
|||
<toolbarItem reference="85b-WO-tks"/>
|
||||
</defaultToolbarItems>
|
||||
</toolbar>
|
||||
<point key="canvasLocation" x="-308" y="-1288"/>
|
||||
<point key="canvasLocation" x="-82" y="-1306"/>
|
||||
</window>
|
||||
<customObject id="494" userLabel="EmulatorGLView" customClass="EmulatorGLView"/>
|
||||
<customObject id="M8b-ga-iOS" customClass="EmulatorWindowController" colorLabel="IBBuiltInLabel-Blue">
|
||||
|
@ -439,7 +441,7 @@ CA
|
|||
<outlet property="window" destination="371" id="z3B-S9-PsV"/>
|
||||
</connections>
|
||||
</customObject>
|
||||
<window title="Insert Disks" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" oneShot="NO" releasedWhenClosed="NO" showsToolbarButton="NO" visibleAtLaunch="NO" animationBehavior="default" id="RAk-at-ZT4" userLabel="Window - Insert Disks">
|
||||
<window title="Insert Disks" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" id="RAk-at-ZT4" userLabel="Window - Insert Disks">
|
||||
<windowStyleMask key="styleMask" titled="YES" closable="YES"/>
|
||||
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
|
||||
<rect key="contentRect" x="109" y="132" width="522" height="302"/>
|
||||
|
@ -472,6 +474,9 @@ CA
|
|||
<buttonCell key="cell" type="push" title="Choose..." bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="nVq-kA-8RS">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
<string key="keyEquivalent" base64-UTF8="YES">
|
||||
DQ
|
||||
</string>
|
||||
</buttonCell>
|
||||
<connections>
|
||||
<action selector="chooseDriveA:" target="FHO-g2-V3A" id="aXp-cp-feH"/>
|
||||
|
@ -613,19 +618,13 @@ CA
|
|||
<action selector="startupDiskBChoiceChanged:" target="FHO-g2-V3A" id="tQS-5l-DDf"/>
|
||||
</connections>
|
||||
</button>
|
||||
<box verticalHuggingPriority="750" title="Box" boxType="separator" titlePosition="noTitle" id="7ZU-H6-jQn">
|
||||
<box verticalHuggingPriority="750" boxType="separator" id="7ZU-H6-jQn">
|
||||
<rect key="frame" x="12" y="59" width="498" height="5"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<color key="borderColor" white="0.0" alpha="0.41999999999999998" colorSpace="calibratedWhite"/>
|
||||
<color key="fillColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
|
||||
<font key="titleFont" metaFont="system"/>
|
||||
</box>
|
||||
<box horizontalHuggingPriority="750" title="Box" boxType="separator" titlePosition="noTitle" id="864-Ov-2tE">
|
||||
<box horizontalHuggingPriority="750" boxType="separator" id="864-Ov-2tE">
|
||||
<rect key="frame" x="259" y="70" width="5" height="217"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<color key="borderColor" white="0.0" alpha="0.41999999999999998" colorSpace="calibratedWhite"/>
|
||||
<color key="fillColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
|
||||
<font key="titleFont" metaFont="system"/>
|
||||
</box>
|
||||
<button verticalHuggingPriority="750" id="tLd-IJ-Kjl">
|
||||
<rect key="frame" x="338" y="13" width="85" height="32"/>
|
||||
|
@ -633,9 +632,6 @@ CA
|
|||
<buttonCell key="cell" type="push" title="OK" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="mSV-MT-MmA">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
<string key="keyEquivalent" base64-UTF8="YES">
|
||||
DQ
|
||||
</string>
|
||||
</buttonCell>
|
||||
<connections>
|
||||
<action selector="disksOK:" target="FHO-g2-V3A" id="8qD-fL-VNb"/>
|
||||
|
@ -643,7 +639,7 @@ DQ
|
|||
</button>
|
||||
</subviews>
|
||||
</view>
|
||||
<point key="canvasLocation" x="-139" y="-901"/>
|
||||
<point key="canvasLocation" x="-530" y="-867"/>
|
||||
</window>
|
||||
<customObject id="FHO-g2-V3A" customClass="EmulatorDiskController">
|
||||
<connections>
|
||||
|
@ -656,11 +652,12 @@ DQ
|
|||
<outlet property="diskInA" destination="cb9-Pc-Ggd" id="chv-2S-Y2R"/>
|
||||
<outlet property="diskInB" destination="5oU-oN-vUH" id="8fb-s5-EKa"/>
|
||||
<outlet property="disksWindow" destination="RAk-at-ZT4" id="4wu-vw-EhL"/>
|
||||
<outlet property="okButton" destination="tLd-IJ-Kjl" id="dvn-gG-jzv"/>
|
||||
<outlet property="startupLoadDiskA" destination="Ur3-rW-YJG" id="re3-gT-qj3"/>
|
||||
<outlet property="startupLoadDiskB" destination="Ceo-uO-cRu" id="V0B-0f-YZu"/>
|
||||
</connections>
|
||||
</customObject>
|
||||
<window title="Apple2Mac Preferences" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" oneShot="NO" releasedWhenClosed="NO" showsToolbarButton="NO" visibleAtLaunch="NO" animationBehavior="default" id="Mzv-VG-jce" userLabel="Window - Prefs" customClass="EmulatorWindow">
|
||||
<window title="Apple2Mac Preferences" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" id="Mzv-VG-jce" userLabel="Window - Prefs" customClass="EmulatorWindow">
|
||||
<windowStyleMask key="styleMask" titled="YES" closable="YES"/>
|
||||
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
|
||||
<rect key="contentRect" x="109" y="132" width="580" height="360"/>
|
||||
|
@ -736,12 +733,9 @@ DQ
|
|||
<action selector="peggedChoiceChanged:" target="mUW-Rh-bL1" id="K2H-Vc-15h"/>
|
||||
</connections>
|
||||
</button>
|
||||
<box verticalHuggingPriority="750" title="Box" boxType="separator" titlePosition="noTitle" id="9U0-v9-wTm">
|
||||
<box verticalHuggingPriority="750" boxType="separator" id="9U0-v9-wTm">
|
||||
<rect key="frame" x="17" y="183" width="508" height="5"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<color key="borderColor" white="0.0" alpha="0.41999999999999998" colorSpace="calibratedWhite"/>
|
||||
<color key="fillColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
|
||||
<font key="titleFont" metaFont="system"/>
|
||||
</box>
|
||||
<slider verticalHuggingPriority="750" id="y10-Rm-oDB">
|
||||
<rect key="frame" x="15" y="115" width="404" height="27"/>
|
||||
|
@ -780,7 +774,7 @@ DQ
|
|||
</buttonCell>
|
||||
<cells>
|
||||
<column>
|
||||
<buttonCell type="radio" title="No soundcard" imagePosition="left" alignment="left" enabled="NO" tag="1" inset="2" id="QsT-B1-n2t">
|
||||
<buttonCell type="radio" title="No soundcard" imagePosition="left" alignment="left" enabled="NO" state="on" tag="1" inset="2" id="QsT-B1-n2t">
|
||||
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
</buttonCell>
|
||||
|
@ -809,12 +803,12 @@ DQ
|
|||
<popUpButton verticalHuggingPriority="750" id="1sF-py-jCs">
|
||||
<rect key="frame" x="115" y="271" width="158" height="26"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<popUpButtonCell key="cell" type="push" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" id="eVj-ax-48A">
|
||||
<popUpButtonCell key="cell" type="push" title="Monochrome" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" selectedItem="PX0-X3-MxY" id="eVj-ax-48A">
|
||||
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="menu"/>
|
||||
<menu key="menu" id="gbp-xU-CmX">
|
||||
<items>
|
||||
<menuItem title="Black/white" id="PX0-X3-MxY">
|
||||
<menuItem title="Monochrome" state="on" id="PX0-X3-MxY">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
</menuItem>
|
||||
<menuItem title="Color" id="TRN-Jh-rFc">
|
||||
|
@ -823,6 +817,15 @@ DQ
|
|||
<menuItem title="Interpolated" id="RgR-Oe-oo5">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
</menuItem>
|
||||
<menuItem title="Color Monitor" id="60c-9H-Yr8">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
</menuItem>
|
||||
<menuItem title="Monochrome TV" id="lQA-Eh-TKs">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
</menuItem>
|
||||
<menuItem title="Color TV" id="b41-R4-5E3">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</popUpButtonCell>
|
||||
|
@ -830,22 +833,8 @@ DQ
|
|||
<action selector="colorChoiceChanged:" target="mUW-Rh-bL1" id="M58-28-Lmr"/>
|
||||
</connections>
|
||||
</popUpButton>
|
||||
<slider verticalHuggingPriority="750" id="9FG-IJ-hYc">
|
||||
<rect key="frame" x="115" y="229" width="404" height="27"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<sliderCell key="cell" enabled="NO" state="on" alignment="left" maxValue="100" doubleValue="50" tickMarkPosition="below" numberOfTickMarks="5" sliderType="linear" id="Cma-o2-8gh"/>
|
||||
</slider>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" id="RsU-77-Dkx">
|
||||
<rect key="frame" x="15" y="241" width="96" height="17"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Graphic Effects :" id="foK-d1-Lrb">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" id="dak-eg-hHn">
|
||||
<rect key="frame" x="15" y="277" width="96" height="17"/>
|
||||
<rect key="frame" x="15" y="276" width="96" height="17"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Color :" id="eHo-1T-edz">
|
||||
<font key="font" metaFont="system"/>
|
||||
|
@ -853,6 +842,47 @@ DQ
|
|||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" id="rDh-8p-gf0">
|
||||
<rect key="frame" x="15" y="245" width="96" height="17"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Monochrome :" id="6zV-cm-vLN">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<popUpButton verticalHuggingPriority="750" id="9bP-5g-S3a">
|
||||
<rect key="frame" x="115" y="240" width="158" height="26"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<popUpButtonCell key="cell" type="push" title="Black/white" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" selectedItem="7Nj-L6-N5K" id="UkC-75-g1J">
|
||||
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="menu"/>
|
||||
<menu key="menu" id="8h0-lQ-adO">
|
||||
<items>
|
||||
<menuItem title="Black/white" state="on" id="7Nj-L6-N5K">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
</menuItem>
|
||||
<menuItem title="Green Screen" id="8Mv-8d-hgV">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</popUpButtonCell>
|
||||
<connections>
|
||||
<action selector="monochromeColorChoiceChanged:" target="mUW-Rh-bL1" id="FIq-tn-pNv"/>
|
||||
</connections>
|
||||
</popUpButton>
|
||||
<button verticalHuggingPriority="750" id="0Av-wg-y41">
|
||||
<rect key="frame" x="115" y="219" width="142" height="18"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<buttonCell key="cell" type="check" title="Show half scanlines" bezelStyle="regularSquare" imagePosition="left" inset="2" id="q9I-GX-oEP">
|
||||
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
</buttonCell>
|
||||
<connections>
|
||||
<action selector="scanlinesChoiceChanged:" target="mUW-Rh-bL1" id="7Uf-Tg-ALt"/>
|
||||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
</view>
|
||||
</tabViewItem>
|
||||
|
@ -861,12 +891,9 @@ DQ
|
|||
<rect key="frame" x="10" y="33" width="534" height="298"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<box horizontalHuggingPriority="750" title="Box" boxType="separator" titlePosition="noTitle" id="Fkg-X3-0XG">
|
||||
<box horizontalHuggingPriority="750" boxType="separator" id="Fkg-X3-0XG">
|
||||
<rect key="frame" x="265" y="9" width="5" height="286"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<color key="borderColor" white="0.0" alpha="0.41999999999999998" colorSpace="calibratedWhite"/>
|
||||
<color key="fillColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
|
||||
<font key="titleFont" metaFont="system"/>
|
||||
</box>
|
||||
<customView id="OWJ-x7-P0q" customClass="EmulatorJoystickCalibrationView">
|
||||
<rect key="frame" x="276" y="39" width="256" height="256"/>
|
||||
|
@ -1004,7 +1031,7 @@ DQ
|
|||
</tabView>
|
||||
</subviews>
|
||||
</view>
|
||||
<point key="canvasLocation" x="-286" y="-1308"/>
|
||||
<point key="canvasLocation" x="-576" y="-1238"/>
|
||||
</window>
|
||||
<customObject id="mUW-Rh-bL1" customClass="EmulatorPrefsController">
|
||||
<connections>
|
||||
|
@ -1026,6 +1053,8 @@ DQ
|
|||
<outlet property="joystickStepLabel" destination="ea3-X4-r6a" id="JKX-kB-tcM"/>
|
||||
<outlet property="joystickStepper" destination="BrH-bm-tx3" id="PmM-yE-XNH"/>
|
||||
<outlet property="joystickStepperLabel" destination="e2h-SS-aex" id="I6X-YN-AmA"/>
|
||||
<outlet property="monochromeColorChoice" destination="9bP-5g-S3a" id="dzI-JR-diH"/>
|
||||
<outlet property="scanlinesChoice" destination="0Av-wg-y41" id="U1V-Re-wVs"/>
|
||||
<outlet property="soundCardChoice" destination="3d5-Z5-xDN" id="uHI-Ip-s2E"/>
|
||||
<outlet property="window" destination="Mzv-VG-jce" id="86q-Ys-9Mt"/>
|
||||
</connections>
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="9531" systemVersion="15C50" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none">
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="14490.70" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none">
|
||||
<dependencies>
|
||||
<deployment version="1080" identifier="macosx"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="9531"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14490.70"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<customObject id="-2" userLabel="File's Owner" customClass="NSApplication">
|
||||
|
@ -379,7 +380,7 @@ CA
|
|||
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
|
||||
<rect key="contentRect" x="200" y="200" width="568" height="384"/>
|
||||
<rect key="screenRect" x="0.0" y="0.0" width="1920" height="1178"/>
|
||||
<view key="contentView" id="372" customClass="EmulatorGLView">
|
||||
<view key="contentView" id="372">
|
||||
<rect key="frame" x="0.0" y="0.0" width="568" height="384"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</view>
|
||||
|
@ -452,7 +453,7 @@ CA
|
|||
<outlet property="window" destination="371" id="z3B-S9-PsV"/>
|
||||
</connections>
|
||||
</customObject>
|
||||
<window title="Insert Disks" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" oneShot="NO" releasedWhenClosed="NO" showsToolbarButton="NO" visibleAtLaunch="NO" animationBehavior="default" id="RAk-at-ZT4" userLabel="Window - Insert Disks">
|
||||
<window title="Insert Disks" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" id="RAk-at-ZT4" userLabel="Window - Insert Disks">
|
||||
<windowStyleMask key="styleMask" titled="YES" closable="YES"/>
|
||||
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
|
||||
<rect key="contentRect" x="109" y="132" width="522" height="302"/>
|
||||
|
@ -626,19 +627,13 @@ CA
|
|||
<action selector="startupDiskBChoiceChanged:" target="FHO-g2-V3A" id="tQS-5l-DDf"/>
|
||||
</connections>
|
||||
</button>
|
||||
<box verticalHuggingPriority="750" title="Box" boxType="separator" titlePosition="noTitle" id="7ZU-H6-jQn">
|
||||
<box verticalHuggingPriority="750" boxType="separator" id="7ZU-H6-jQn">
|
||||
<rect key="frame" x="12" y="59" width="498" height="5"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<color key="borderColor" white="0.0" alpha="0.41999999999999998" colorSpace="calibratedWhite"/>
|
||||
<color key="fillColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
|
||||
<font key="titleFont" metaFont="system"/>
|
||||
</box>
|
||||
<box horizontalHuggingPriority="750" title="Box" boxType="separator" titlePosition="noTitle" id="864-Ov-2tE">
|
||||
<box horizontalHuggingPriority="750" boxType="separator" id="864-Ov-2tE">
|
||||
<rect key="frame" x="259" y="70" width="5" height="217"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<color key="borderColor" white="0.0" alpha="0.41999999999999998" colorSpace="calibratedWhite"/>
|
||||
<color key="fillColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
|
||||
<font key="titleFont" metaFont="system"/>
|
||||
</box>
|
||||
<button verticalHuggingPriority="750" id="tLd-IJ-Kjl">
|
||||
<rect key="frame" x="338" y="13" width="85" height="32"/>
|
||||
|
@ -673,7 +668,7 @@ DQ
|
|||
<outlet property="startupLoadDiskB" destination="Ceo-uO-cRu" id="V0B-0f-YZu"/>
|
||||
</connections>
|
||||
</customObject>
|
||||
<window title="Apple2Mac Preferences" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" oneShot="NO" releasedWhenClosed="NO" showsToolbarButton="NO" visibleAtLaunch="NO" animationBehavior="default" id="Mzv-VG-jce" userLabel="Window - Prefs" customClass="EmulatorWindow">
|
||||
<window title="Apple2Mac Preferences" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" id="Mzv-VG-jce" userLabel="Window - Prefs" customClass="EmulatorWindow">
|
||||
<windowStyleMask key="styleMask" titled="YES" closable="YES"/>
|
||||
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
|
||||
<rect key="contentRect" x="109" y="132" width="580" height="360"/>
|
||||
|
@ -749,12 +744,9 @@ DQ
|
|||
<action selector="peggedChoiceChanged:" target="mUW-Rh-bL1" id="K2H-Vc-15h"/>
|
||||
</connections>
|
||||
</button>
|
||||
<box verticalHuggingPriority="750" title="Box" boxType="separator" titlePosition="noTitle" id="9U0-v9-wTm">
|
||||
<box verticalHuggingPriority="750" boxType="separator" id="9U0-v9-wTm">
|
||||
<rect key="frame" x="17" y="183" width="508" height="5"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<color key="borderColor" white="0.0" alpha="0.41999999999999998" colorSpace="calibratedWhite"/>
|
||||
<color key="fillColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
|
||||
<font key="titleFont" metaFont="system"/>
|
||||
</box>
|
||||
<slider verticalHuggingPriority="750" id="y10-Rm-oDB">
|
||||
<rect key="frame" x="15" y="115" width="404" height="27"/>
|
||||
|
@ -874,12 +866,9 @@ DQ
|
|||
<rect key="frame" x="10" y="33" width="534" height="298"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<box horizontalHuggingPriority="750" title="Box" boxType="separator" titlePosition="noTitle" id="Fkg-X3-0XG">
|
||||
<box horizontalHuggingPriority="750" boxType="separator" id="Fkg-X3-0XG">
|
||||
<rect key="frame" x="265" y="9" width="5" height="286"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<color key="borderColor" white="0.0" alpha="0.41999999999999998" colorSpace="calibratedWhite"/>
|
||||
<color key="fillColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
|
||||
<font key="titleFont" metaFont="system"/>
|
||||
</box>
|
||||
<customView id="OWJ-x7-P0q" customClass="EmulatorJoystickCalibrationView">
|
||||
<rect key="frame" x="276" y="39" width="256" height="256"/>
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
[defaults setDouble:CPU_SCALE_SLOWEST forKey:kApple2AltSpeed];
|
||||
[defaults setBool:NO forKey:kApple2CPUSpeedIsMax];
|
||||
[defaults setBool:NO forKey:kApple2AltSpeedIsMax];
|
||||
[defaults setInteger:COLOR_INTERP forKey:kApple2ColorConfig];
|
||||
[defaults setInteger:COLOR_MODE_INTERP forKey:kApple2ColorConfig];
|
||||
// [defaults setInteger:JOY_KPAD forKey:kApple2JoystickConfig];
|
||||
[defaults setBool:YES forKey:kApple2JoystickAutoRecenter];
|
||||
[defaults removeObjectForKey:kApple2PrefStartupDiskA];
|
||||
|
@ -72,9 +72,9 @@
|
|||
}
|
||||
|
||||
NSInteger mode = [defaults integerForKey:kApple2ColorConfig];
|
||||
if (! ((mode >= COLOR_NONE) && (mode < NUM_COLOROPTS)) )
|
||||
if (! ((mode >= COLOR_MODE_MONO) && (mode < NUM_COLOROPTS)) )
|
||||
{
|
||||
mode = COLOR_NONE;
|
||||
mode = COLOR_MODE_DEFAULT;
|
||||
}
|
||||
//[self.videoModePicker d:mode];
|
||||
//color_mode = (color_mode_t)mode;
|
||||
|
|
|
@ -33,9 +33,21 @@
|
|||
@property (assign) IBOutlet NSButton *chooseDiskB;
|
||||
@property (assign) IBOutlet NSButton *startupLoadDiskA;
|
||||
@property (assign) IBOutlet NSButton *startupLoadDiskB;
|
||||
@property (assign) IBOutlet NSButton *okButton;
|
||||
|
||||
- (void)loadPrefsForDomain:(const char *)domain;
|
||||
|
||||
@end
|
||||
|
||||
static EmulatorDiskController *diskInstance = nil;
|
||||
|
||||
static void prefsChangeCallback(const char *domain)
|
||||
{
|
||||
(void)domain;
|
||||
assert(diskInstance);
|
||||
[diskInstance loadPrefsForDomain:domain];
|
||||
}
|
||||
|
||||
@implementation EmulatorDiskController
|
||||
|
||||
- (void)awakeFromNib
|
||||
|
@ -43,7 +55,11 @@
|
|||
#if CRASH_APP_ON_LOAD_BECAUSE_YAY_GJ_APPLE
|
||||
glGetError();
|
||||
#endif
|
||||
|
||||
assert(!diskInstance);
|
||||
diskInstance = self;
|
||||
|
||||
prefs_registerListener(PREF_DOMAIN_VM, prefsChangeCallback);
|
||||
|
||||
[self.diskInA setStringValue:NO_DISK_INSERTED];
|
||||
[self.diskAProperties setStringValue:@""];
|
||||
[self.diskInB setStringValue:NO_DISK_INSERTED];
|
||||
|
@ -52,68 +68,102 @@
|
|||
[self.chooseDiskA setBezelStyle:NSRoundedBezelStyle];
|
||||
[self.startupLoadDiskA setState:NSOffState];
|
||||
[self.startupLoadDiskB setState:NSOffState];
|
||||
|
||||
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
||||
|
||||
NSString *startupDiskA = [defaults stringForKey:kApple2PrefStartupDiskA];
|
||||
BOOL readOnlyA = [defaults boolForKey:kApple2PrefStartupDiskAProtected];
|
||||
if (startupDiskA)
|
||||
}
|
||||
|
||||
- (void)loadPrefsForDomain:(const char *)domain
|
||||
{
|
||||
assert(strcmp(domain, PREF_DOMAIN_VM) == 0);
|
||||
(void)domain;
|
||||
|
||||
{
|
||||
const char *err = disk6_insert(0, [[NSString stringWithFormat:@"%@.gz", startupDiskA] UTF8String], readOnlyA);
|
||||
if (!err)
|
||||
NSString *startupDiskA = nil;
|
||||
char *pathA = NULL;
|
||||
startupDiskA = prefs_copyStringValue(PREF_DOMAIN_VM, PREF_DISK_PATH_A, &pathA) ? [NSString stringWithUTF8String:pathA] : nil;
|
||||
FREE(pathA);
|
||||
|
||||
bool bVal = false;
|
||||
BOOL readOnlyA = prefs_parseBoolValue(PREF_DOMAIN_VM, PREF_DISK_PATH_A_RO, &bVal) ? bVal : true;
|
||||
if (startupDiskA && [startupDiskA length])
|
||||
{
|
||||
[self.diskInA setStringValue:[[startupDiskA pathComponents] lastObject]];
|
||||
[self.startupLoadDiskA setState:NSOnState];
|
||||
[self.diskAProtection setState:(readOnlyA ? NSOnState : NSOffState) atRow:0 column:0];
|
||||
[self.diskAProtection setState:(!readOnlyA ? NSOnState : NSOffState) atRow:0 column:1];
|
||||
const char *path = [startupDiskA UTF8String];
|
||||
int fdA = -1;
|
||||
TEMP_FAILURE_RETRY(fdA = open(path, readOnlyA ? O_RDONLY : O_RDWR));
|
||||
if (fdA == -1) {
|
||||
LOG("OOPS, open failed for path %s (%s)", path, strerror(errno));
|
||||
}
|
||||
const char *err = disk6_insert(fdA, 0, path, readOnlyA);
|
||||
if (fdA >= 0) {
|
||||
TEMP_FAILURE_RETRY(close(fdA));
|
||||
}
|
||||
if (!err)
|
||||
{
|
||||
[self.diskInA setStringValue:[[startupDiskA pathComponents] lastObject]];
|
||||
[self.startupLoadDiskA setState:NSOnState];
|
||||
[self.diskAProtection setState:(readOnlyA ? NSOnState : NSOffState) atRow:0 column:0];
|
||||
[self.diskAProtection setState:(!readOnlyA ? NSOnState : NSOffState) atRow:0 column:1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NSString *startupDiskB = [defaults stringForKey:kApple2PrefStartupDiskB];
|
||||
BOOL readOnlyB = [defaults boolForKey:kApple2PrefStartupDiskBProtected];
|
||||
if (startupDiskB)
|
||||
{
|
||||
const char *err = disk6_insert(1, [[NSString stringWithFormat:@"%@.gz", startupDiskB] UTF8String], readOnlyB);
|
||||
if (!err)
|
||||
NSString *startupDiskB = nil;
|
||||
char *pathB = NULL;
|
||||
startupDiskB = prefs_copyStringValue(PREF_DOMAIN_VM, PREF_DISK_PATH_B, &pathB) ? [NSString stringWithUTF8String:pathB] : nil;
|
||||
FREE(pathB);
|
||||
|
||||
bool bVal = false;
|
||||
BOOL readOnlyB = prefs_parseBoolValue(PREF_DOMAIN_VM, PREF_DISK_PATH_B_RO, &bVal) ? bVal : true;
|
||||
if (startupDiskB && [startupDiskB length])
|
||||
{
|
||||
[self.diskInB setStringValue:[[startupDiskB pathComponents] lastObject]];
|
||||
[self.startupLoadDiskB setState:NSOnState];
|
||||
[self.diskBProtection setState:(readOnlyB ? NSOnState : NSOffState) atRow:0 column:0];
|
||||
[self.diskBProtection setState:(!readOnlyB ? NSOnState : NSOffState) atRow:0 column:1];
|
||||
const char *path = [startupDiskB UTF8String];
|
||||
int fdB = -1;
|
||||
TEMP_FAILURE_RETRY(fdB = open(path, readOnlyB ? O_RDONLY : O_RDWR));
|
||||
if (fdB == -1) {
|
||||
LOG("OOPS, open failed for path %s (%s)", path, strerror(errno));
|
||||
}
|
||||
const char *err = disk6_insert(fdB, 1, path, readOnlyB);
|
||||
if (fdB >= 0) {
|
||||
TEMP_FAILURE_RETRY(close(fdB));
|
||||
}
|
||||
if (!err)
|
||||
{
|
||||
[self.diskInB setStringValue:[[startupDiskB pathComponents] lastObject]];
|
||||
[self.startupLoadDiskB setState:NSOnState];
|
||||
[self.diskBProtection setState:(readOnlyB ? NSOnState : NSOffState) atRow:0 column:0];
|
||||
[self.diskBProtection setState:(!readOnlyB ? NSOnState : NSOffState) atRow:0 column:1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)_savePrefs
|
||||
{
|
||||
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
||||
|
||||
[defaults removeObjectForKey:kApple2PrefStartupDiskA];
|
||||
[defaults removeObjectForKey:kApple2PrefStartupDiskB];
|
||||
[defaults removeObjectForKey:kApple2PrefStartupDiskAProtected];
|
||||
[defaults removeObjectForKey:kApple2PrefStartupDiskBProtected];
|
||||
|
||||
if ([self.startupLoadDiskA state] == NSOnState)
|
||||
if (([self.startupLoadDiskA state] == NSOnState) && (disk6.disk[0].fd >= 0))
|
||||
{
|
||||
if (disk6.disk[0].fd >= 0)
|
||||
{
|
||||
NSString *diskA = [NSString stringWithUTF8String:disk6.disk[0].file_name];
|
||||
[defaults setObject:diskA forKey:kApple2PrefStartupDiskA];
|
||||
NSButtonCell *readOnlyChoice = (NSButtonCell *)[[[self diskAProtection] cells] firstObject];
|
||||
[defaults setBool:([readOnlyChoice state] == NSOnState) forKey:kApple2PrefStartupDiskAProtected];
|
||||
}
|
||||
prefs_setStringValue(PREF_DOMAIN_VM, PREF_DISK_PATH_A, disk6.disk[0].file_name);
|
||||
NSButtonCell *readOnlyChoice = (NSButtonCell *)[[[self diskAProtection] cells] firstObject];
|
||||
prefs_setBoolValue(PREF_DOMAIN_VM, PREF_DISK_PATH_A_RO, ([readOnlyChoice state] == NSOnState));
|
||||
}
|
||||
else
|
||||
{
|
||||
prefs_setStringValue(PREF_DOMAIN_VM, PREF_DISK_PATH_A, "");
|
||||
prefs_setBoolValue(PREF_DOMAIN_VM, PREF_DISK_PATH_A_RO, true);
|
||||
}
|
||||
|
||||
if ([self.startupLoadDiskB state] == NSOnState)
|
||||
if (([self.startupLoadDiskB state] == NSOnState) && (disk6.disk[1].fd >= 0))
|
||||
{
|
||||
if (disk6.disk[1].fd >= 0)
|
||||
{
|
||||
NSString *diskB = [NSString stringWithUTF8String:disk6.disk[1].file_name];
|
||||
[defaults setObject:diskB forKey:kApple2PrefStartupDiskB];
|
||||
NSButtonCell *readOnlyChoice = (NSButtonCell *)[[[self diskBProtection] cells] firstObject];
|
||||
[defaults setBool:([readOnlyChoice state] == NSOnState) forKey:kApple2PrefStartupDiskBProtected];
|
||||
}
|
||||
prefs_setStringValue(PREF_DOMAIN_VM, PREF_DISK_PATH_B, disk6.disk[1].file_name);
|
||||
NSButtonCell *readOnlyChoice = (NSButtonCell *)[[[self diskBProtection] cells] firstObject];
|
||||
prefs_setBoolValue(PREF_DOMAIN_VM, PREF_DISK_PATH_B_RO, ([readOnlyChoice state] == NSOnState) );
|
||||
}
|
||||
else
|
||||
{
|
||||
prefs_setStringValue(PREF_DOMAIN_VM, PREF_DISK_PATH_B, "");
|
||||
prefs_setBoolValue(PREF_DOMAIN_VM, PREF_DISK_PATH_B_RO, true);
|
||||
}
|
||||
|
||||
//prefs_sync(PREF_DOMAIN_VM); -- do not sync here since that will trigger reload of startup disks
|
||||
prefs_save();
|
||||
}
|
||||
|
||||
- (void)_protectionChangedForDrive:(int)drive
|
||||
|
@ -145,50 +195,69 @@
|
|||
{
|
||||
disk6_eject(drive);
|
||||
|
||||
const char *errMsg = disk6_insert(drive, [path UTF8String], readOnly);
|
||||
int fd = -1;
|
||||
const char *cPath = [path UTF8String];
|
||||
TEMP_FAILURE_RETRY(fd = open(cPath, readOnly ? O_RDONLY : O_RDWR));
|
||||
if (fd == -1) {
|
||||
LOG("OOPS, open failed for path %s (%s)", cPath, strerror(errno));
|
||||
}
|
||||
const char *errMsg = disk6_insert(fd, drive, cPath, readOnly);
|
||||
if (fd >= 0) {
|
||||
TEMP_FAILURE_RETRY(close(fd));
|
||||
}
|
||||
if (errMsg)
|
||||
{
|
||||
path = [NSString stringWithFormat:@"%@.gz", path];
|
||||
errMsg = disk6_insert(drive, [path UTF8String], readOnly);
|
||||
if (errMsg)
|
||||
NSAlert *alert = [NSAlert alertWithError:[NSError errorWithDomain:[NSString stringWithUTF8String:errMsg] code:-1 userInfo:nil]];
|
||||
[alert beginSheetModalForWindow:[self disksWindow] completionHandler:nil];
|
||||
if (!drive)
|
||||
{
|
||||
NSAlert *alert = [NSAlert alertWithError:[NSError errorWithDomain:[NSString stringWithUTF8String:errMsg] code:-1 userInfo:nil]];
|
||||
[alert beginSheetModalForWindow:[self disksWindow] completionHandler:nil];
|
||||
if (!drive)
|
||||
{
|
||||
[[self diskInA] setStringValue:NO_DISK_INSERTED];
|
||||
[[self diskAProperties] setStringValue:@""];
|
||||
}
|
||||
else
|
||||
{
|
||||
[[self diskInB] setStringValue:NO_DISK_INSERTED];
|
||||
[[self diskBProperties] setStringValue:@""];
|
||||
}
|
||||
return NO;
|
||||
[[self diskInA] setStringValue:NO_DISK_INSERTED];
|
||||
[[self diskAProperties] setStringValue:@""];
|
||||
}
|
||||
else
|
||||
{
|
||||
[[self diskInB] setStringValue:NO_DISK_INSERTED];
|
||||
[[self diskBProperties] setStringValue:@""];
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
path = [NSString stringWithUTF8String:disk6.disk[drive].file_name];
|
||||
NSString *imageName = [[path pathComponents] lastObject];
|
||||
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
||||
|
||||
|
||||
if (drive == 0)
|
||||
{
|
||||
[[self diskInA] setStringValue:imageName];
|
||||
if ([[defaults stringForKey:kApple2PrefStartupDiskA] isEqualToString:path])
|
||||
|
||||
bool isStartupDiskA = false;
|
||||
{
|
||||
char *pathA = NULL;
|
||||
if (prefs_copyStringValue(PREF_DOMAIN_VM, PREF_DISK_PATH_A, &pathA)) {
|
||||
isStartupDiskA = (strcmp(pathA, disk6.disk[drive].file_name) == 0);
|
||||
}
|
||||
FREE(pathA);
|
||||
}
|
||||
|
||||
if (isStartupDiskA)
|
||||
{
|
||||
[self.startupLoadDiskA setState:NSOnState];
|
||||
//[self.diskAProtection setState:(readOnly ? NSOnState : NSOffState) atRow:0 column:0];
|
||||
//[self.diskAProtection setState:(!readOnly ? NSOnState : NSOffState) atRow:0 column:1];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
[[self diskInB] setStringValue:imageName];
|
||||
if ([[defaults stringForKey:kApple2PrefStartupDiskB] isEqualToString:path])
|
||||
|
||||
bool isStartupDiskB = false;
|
||||
{
|
||||
char *pathB = NULL;
|
||||
if (prefs_copyStringValue(PREF_DOMAIN_VM, PREF_DISK_PATH_B, &pathB)) {
|
||||
isStartupDiskB = (strcmp(pathB, disk6.disk[drive].file_name) == 0);
|
||||
}
|
||||
FREE(pathB);
|
||||
}
|
||||
|
||||
if (isStartupDiskB)
|
||||
{
|
||||
[self.startupLoadDiskB setState:NSOnState];
|
||||
//[self.diskBProtection setState:(readOnly ? NSOnState : NSOffState) atRow:0 column:0];
|
||||
//[self.diskBProtection setState:(!readOnly ? NSOnState : NSOffState) atRow:0 column:1];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -236,7 +305,7 @@
|
|||
{
|
||||
extension0 = extension1;
|
||||
}
|
||||
return extension0;
|
||||
return [extension0 lowercaseString];
|
||||
}
|
||||
|
||||
+ (void)chooseDiskForWindow:(NSWindow *)window completionHandler:(DiskCompletionHandler)handler
|
||||
|
@ -288,6 +357,9 @@
|
|||
return;
|
||||
}
|
||||
|
||||
[self.chooseDiskA setKeyEquivalent:@""];
|
||||
[self.okButton setKeyEquivalent:@"\r"];
|
||||
|
||||
[(drive == 0) ? self.startupLoadDiskA : self.startupLoadDiskB setState:NSOffState];
|
||||
[self _insertDisketteInDrive:drive path:path type:extension readOnly:readOnly];
|
||||
}
|
||||
|
@ -318,6 +390,9 @@
|
|||
|
||||
- (IBAction)disksOK:(id)sender
|
||||
{
|
||||
[self.chooseDiskA setKeyEquivalent:@"\r"];
|
||||
[self.okButton setKeyEquivalent:@""];
|
||||
|
||||
[[self disksWindow] close];
|
||||
}
|
||||
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
// Based on sample code from https://developer.apple.com/library/mac/samplecode/GLEssentials/Introduction/Intro.html
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import <QuartzCore/CVDisplayLink.h>
|
||||
|
||||
#import "modelUtil.h"
|
||||
#import "imageUtil.h"
|
||||
|
|
|
@ -37,6 +37,8 @@ const NSString *kDrawTimerNotification = @"kDrawTimerNotification";
|
|||
@property (nonatomic, retain) NSTimer *timer;
|
||||
#endif
|
||||
|
||||
@property (nonatomic) BOOL prepared;
|
||||
|
||||
- (void)initGL;
|
||||
|
||||
@end
|
||||
|
@ -166,6 +168,8 @@ static CVReturn displayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeSt
|
|||
|
||||
// Register to be notified when the window closes so we can stop the displaylink
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(windowWillClose:) name:NSWindowWillCloseNotification object:[self window]];
|
||||
|
||||
self.prepared = true;
|
||||
}
|
||||
|
||||
- (void)windowWillClose:(NSNotification*)notification
|
||||
|
@ -316,6 +320,11 @@ static CVReturn displayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeSt
|
|||
// Called during resize operations
|
||||
// Avoid flickering during resize by drawing
|
||||
[[self openGLContext] makeCurrentContext];
|
||||
if (UNLIKELY(!self.prepared)) {
|
||||
NSAlert *alert = [NSAlert alertWithError:[NSError errorWithDomain:@"NSOpenGLView is now deprecated and has a bug ... please restart this app. FIXME TODO : likely we're being forced to move to Metal because Ninjaz and Rockstarz said so :P" code:-1 userInfo:nil]];
|
||||
[alert beginSheetModalForWindow:[self window] completionHandler:nil];
|
||||
return;
|
||||
}
|
||||
[self drawView];
|
||||
}
|
||||
|
||||
|
@ -357,6 +366,8 @@ static CVReturn displayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeSt
|
|||
|
||||
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)application
|
||||
{
|
||||
cpu_pause();
|
||||
prefs_save();
|
||||
disk6_eject(0);
|
||||
disk6_eject(1);
|
||||
return NSTerminateNow;
|
||||
|
|
|
@ -13,4 +13,6 @@
|
|||
|
||||
@interface EmulatorJoystickController : NSObject
|
||||
|
||||
+ (EmulatorJoystickController *)sharedInstance;
|
||||
|
||||
@end
|
||||
|
|
|
@ -114,7 +114,7 @@
|
|||
#ifdef KEYPAD_JOYSTICK
|
||||
if (joy_mode == JOY_KPAD)
|
||||
{
|
||||
c_keys_handle_input(-1, 0, 0);
|
||||
keys_handleInput(/*scancode:*/-1, /*is_pressed:*/false, /*is_ascii:*/false);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -179,11 +179,11 @@
|
|||
#endif
|
||||
|
||||
// sample buttons only if apple keys aren't pressed. keys get set to 0xff, and js buttons are set to 0x80.
|
||||
if ((buttonNumber == 0x01) && !(joy_button0 & 0x7f)) {
|
||||
joy_button0 = 0x80;
|
||||
if ((buttonNumber == 0x01) && !(run_args.joy_button0 & 0x7f)) {
|
||||
run_args.joy_button0 = 0x80;
|
||||
}
|
||||
if ((buttonNumber == 0x02) && !(joy_button1 & 0x7f)) {
|
||||
joy_button1 = 0x80;
|
||||
if ((buttonNumber == 0x02) && !(run_args.joy_button1 & 0x7f)) {
|
||||
run_args.joy_button1 = 0x80;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -196,11 +196,11 @@
|
|||
#endif
|
||||
|
||||
// sample buttons only if apple keys aren't pressed. keys get set to 0xff, and js buttons are set to 0x80.
|
||||
if ((buttonNumber == 0x01) && !(joy_button0 & 0x7f)) {
|
||||
joy_button0 = 0x0;
|
||||
if ((buttonNumber == 0x01) && !(run_args.joy_button0 & 0x7f)) {
|
||||
run_args.joy_button0 = 0x0;
|
||||
}
|
||||
if ((buttonNumber == 0x02) && !(joy_button1 & 0x7f)) {
|
||||
joy_button1 = 0x0;
|
||||
if ((buttonNumber == 0x02) && !(run_args.joy_button1 & 0x7f)) {
|
||||
run_args.joy_button1 = 0x0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -11,11 +11,6 @@
|
|||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
#define kApple2PrefStartupDiskA @"kApple2PrefStartupDiskA"
|
||||
#define kApple2PrefStartupDiskAProtected @"kApple2PrefStartupDiskAProtected"
|
||||
#define kApple2PrefStartupDiskB @"kApple2PrefStartupDiskB"
|
||||
#define kApple2PrefStartupDiskBProtected @"kApple2PrefStartupDiskBProtected"
|
||||
|
||||
@interface EmulatorPrefsController : NSWindowController
|
||||
|
||||
@end
|
||||
|
|
|
@ -15,18 +15,6 @@
|
|||
#import "EmulatorWindowController.h"
|
||||
#import "common.h"
|
||||
|
||||
#define kApple2SavedPrefs @"kApple2SavedPrefs"
|
||||
#define kApple2CPUSpeed @"kApple2CPUSpeed"
|
||||
#define kApple2CPUSpeedIsMax @"kApple2CPUSpeedIsMax"
|
||||
#define kApple2AltSpeed @"kApple2AltSpeed"
|
||||
#define kApple2AltSpeedIsMax @"kApple2AltSpeedIsMax"
|
||||
#define kApple2SoundcardConfig @"kApple2SoundcardConfig"
|
||||
#define kApple2ColorConfig @"kApple2ColorConfig"
|
||||
#define kApple2JoystickConfig @"kApple2JoystickConfig"
|
||||
#define kApple2JoystickAutoRecenter @"kApple2JoystickAutoRecenter"
|
||||
#define kApple2JoystickClipToRadius @"kApple2JoystickClipToRadius"
|
||||
#define kApple2JoystickStep @"kApple2JoystickStep"
|
||||
|
||||
@interface EmulatorPrefsController ()
|
||||
|
||||
@property (assign) IBOutlet NSSlider *cpuSlider;
|
||||
|
@ -39,6 +27,8 @@
|
|||
@property (assign) IBOutlet NSMatrix *soundCardChoice;
|
||||
|
||||
@property (assign) IBOutlet NSPopUpButton *colorChoice;
|
||||
@property (assign) IBOutlet NSPopUpButton *monochromeColorChoice;
|
||||
@property (assign) IBOutlet NSButton *scanlinesChoice;
|
||||
|
||||
@property (assign) IBOutlet NSPopUpButton *joystickChoice;
|
||||
@property (assign) IBOutlet NSButton *joystickRecenter;
|
||||
|
@ -53,34 +43,47 @@
|
|||
@property (assign) IBOutlet NSTextField *button1Pressed;
|
||||
@property (assign) IBOutlet EmulatorJoystickCalibrationView *joystickCalibrationView;
|
||||
|
||||
- (void)loadPrefsForDomain:(const char *)domain;
|
||||
|
||||
@end
|
||||
|
||||
static EmulatorPrefsController *prefsInstance = nil;
|
||||
|
||||
static void prefsChangeCallback(const char *domain)
|
||||
{
|
||||
assert(prefsInstance);
|
||||
[prefsInstance loadPrefsForDomain:domain];
|
||||
}
|
||||
|
||||
@implementation EmulatorPrefsController
|
||||
|
||||
- (void)awakeFromNib
|
||||
{
|
||||
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
||||
BOOL firstTime = ![defaults boolForKey:kApple2SavedPrefs];
|
||||
if (firstTime)
|
||||
assert(!prefsInstance);
|
||||
prefsInstance = self;
|
||||
|
||||
prefs_registerListener(PREF_DOMAIN_AUDIO, prefsChangeCallback);
|
||||
prefs_registerListener(PREF_DOMAIN_INTERFACE, prefsChangeCallback);
|
||||
prefs_registerListener(PREF_DOMAIN_JOYSTICK, prefsChangeCallback);
|
||||
prefs_registerListener(PREF_DOMAIN_KEYBOARD, prefsChangeCallback);
|
||||
//prefs_registerListener(PREF_DOMAIN_TOUCHSCREEN, prefsChangeCallback);
|
||||
prefs_registerListener(PREF_DOMAIN_VIDEO, prefsChangeCallback);
|
||||
prefs_registerListener(PREF_DOMAIN_VM, prefsChangeCallback);
|
||||
|
||||
[self _setupJoystickUI];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(drawJoystickCalibration:) name:(NSString *)kDrawTimerNotification object:nil];
|
||||
}
|
||||
|
||||
- (void)loadPrefsForDomain:(const char *)domain
|
||||
{
|
||||
domain = NULL; (void)domain;
|
||||
float fVal, fValDisplay;
|
||||
fVal = prefs_parseFloatValue(PREF_DOMAIN_VM, PREF_CPU_SCALE, &fVal) ? fVal/100 : 1.0;
|
||||
fValDisplay = fVal;
|
||||
if (fVal >= CPU_SCALE_FASTEST)
|
||||
{
|
||||
[defaults setBool:YES forKey:kApple2SavedPrefs];
|
||||
[defaults setDouble:1.0 forKey:kApple2CPUSpeed];
|
||||
[defaults setDouble:CPU_SCALE_SLOWEST forKey:kApple2AltSpeed];
|
||||
[defaults setBool:NO forKey:kApple2CPUSpeedIsMax];
|
||||
[defaults setBool:NO forKey:kApple2AltSpeedIsMax];
|
||||
[defaults setInteger:COLOR_INTERP forKey:kApple2ColorConfig];
|
||||
[defaults setInteger:JOY_KPAD forKey:kApple2JoystickConfig];
|
||||
[defaults setBool:YES forKey:kApple2JoystickAutoRecenter];
|
||||
[defaults removeObjectForKey:kApple2PrefStartupDiskA];
|
||||
[defaults removeObjectForKey:kApple2PrefStartupDiskB];
|
||||
}
|
||||
|
||||
cpu_scale_factor = [defaults doubleForKey:kApple2CPUSpeed];
|
||||
[self.cpuSlider setDoubleValue:cpu_scale_factor];
|
||||
[self.cpuSliderLabel setStringValue:[NSString stringWithFormat:@"%.0f%%", cpu_scale_factor*100]];
|
||||
if ([defaults boolForKey:kApple2CPUSpeedIsMax])
|
||||
{
|
||||
cpu_scale_factor = CPU_SCALE_FASTEST;
|
||||
fVal = CPU_SCALE_FASTEST;
|
||||
fValDisplay = CPU_SCALE_FASTEST_PIVOT;
|
||||
[self.cpuMaxChoice setState:NSOnState];
|
||||
[self.cpuSlider setEnabled:NO];
|
||||
}
|
||||
|
@ -89,13 +92,15 @@
|
|||
[self.cpuMaxChoice setState:NSOffState];
|
||||
[self.cpuSlider setEnabled:YES];
|
||||
}
|
||||
|
||||
cpu_altscale_factor = [defaults doubleForKey:kApple2AltSpeed];
|
||||
[self.altSlider setDoubleValue:cpu_altscale_factor];
|
||||
[self.altSliderLabel setStringValue:[NSString stringWithFormat:@"%.0f%%", cpu_altscale_factor*100]];
|
||||
if ([defaults boolForKey:kApple2AltSpeedIsMax])
|
||||
[self.cpuSlider setFloatValue:fVal];
|
||||
[self.cpuSliderLabel setStringValue:[NSString stringWithFormat:@"%.0f%%", fValDisplay*100]];
|
||||
|
||||
fVal = prefs_parseFloatValue(PREF_DOMAIN_VM, PREF_CPU_SCALE_ALT, &fVal) ? fVal/100 : 1.0;
|
||||
fValDisplay = fVal;
|
||||
if (fVal >= CPU_SCALE_FASTEST)
|
||||
{
|
||||
cpu_altscale_factor = CPU_SCALE_FASTEST;
|
||||
fVal = CPU_SCALE_FASTEST;
|
||||
fValDisplay = CPU_SCALE_FASTEST_PIVOT;
|
||||
[self.altMaxChoice setState:NSOnState];
|
||||
[self.altSlider setEnabled:NO];
|
||||
}
|
||||
|
@ -104,50 +109,34 @@
|
|||
[self.altMaxChoice setState:NSOffState];
|
||||
[self.altSlider setEnabled:YES];
|
||||
}
|
||||
|
||||
[self.altSlider setFloatValue:fVal];
|
||||
[self.altSliderLabel setStringValue:[NSString stringWithFormat:@"%.0f%%", fValDisplay*100]];
|
||||
|
||||
#warning TODO : actually implement sound card choices
|
||||
[self.soundCardChoice deselectAllCells];
|
||||
[self.soundCardChoice selectCellAtRow:1 column:0];
|
||||
|
||||
NSInteger mode = [defaults integerForKey:kApple2ColorConfig];
|
||||
if (! ((mode >= COLOR_NONE) && (mode < NUM_COLOROPTS)) )
|
||||
{
|
||||
mode = COLOR_NONE;
|
||||
}
|
||||
[self.colorChoice selectItemAtIndex:mode];
|
||||
prefs_setLongValue(PREF_DOMAIN_VIDEO, PREF_COLOR_MODE, (color_mode_t)mode);
|
||||
prefs_sync(PREF_DOMAIN_VIDEO);
|
||||
|
||||
mode = [defaults integerForKey:kApple2JoystickConfig];
|
||||
if (! ((mode >= JOY_PCJOY) && (mode < NUM_JOYOPTS)) )
|
||||
{
|
||||
mode = JOY_PCJOY;
|
||||
}
|
||||
joy_mode = (joystick_mode_t)mode;
|
||||
[self.joystickChoice selectItemAtIndex:mode];
|
||||
long lVal = 0;
|
||||
NSInteger mode;
|
||||
mode = prefs_parseLongValue(PREF_DOMAIN_VIDEO, PREF_COLOR_MODE, &lVal, /*base:*/10) ? getColorMode(lVal) : COLOR_MODE_DEFAULT;
|
||||
[self.colorChoice selectItemAtIndex:mode];
|
||||
|
||||
mode = prefs_parseLongValue(PREF_DOMAIN_VIDEO, PREF_MONO_MODE, &lVal, /*base:*/10) ? getMonoMode(lVal) : MONO_MODE_DEFAULT;
|
||||
[self.monochromeColorChoice selectItemAtIndex:mode];
|
||||
|
||||
bool bVal = prefs_parseBoolValue(PREF_DOMAIN_VIDEO, PREF_SHOW_HALF_SCANLINES, &bVal) ? bVal : true;
|
||||
[self.scanlinesChoice setState:bVal ? NSOnState : NSOffState];
|
||||
|
||||
[self.joystickChoice selectItemAtIndex:(NSInteger)joy_mode];
|
||||
|
||||
#ifdef KEYPAD_JOYSTICK
|
||||
bool autoRecenter = [defaults integerForKey:kApple2JoystickAutoRecenter];
|
||||
[self.joystickRecenter setState:autoRecenter ? NSOnState : NSOffState];
|
||||
prefs_setBoolValue(PREF_DOMAIN_JOYSTICK, PREF_JOYSTICK_KPAD_AUTO_RECENTER, autoRecenter);
|
||||
|
||||
long joyStep = [defaults integerForKey:kApple2JoystickStep];
|
||||
if (!joyStep)
|
||||
{
|
||||
joyStep = 1;
|
||||
}
|
||||
[self.joystickStepLabel setIntegerValue:joyStep];
|
||||
[self.joystickStepper setIntegerValue:joyStep];
|
||||
prefs_setLongValue(PREF_DOMAIN_JOYSTICK, PREF_JOYSTICK_KPAD_STEP, joyStep);
|
||||
|
||||
prefs_sync(PREF_DOMAIN_JOYSTICK);
|
||||
[self.joystickRecenter setState:joy_auto_recenter ? NSOnState : NSOffState];
|
||||
|
||||
[self.joystickStepLabel setIntegerValue:joy_step];
|
||||
[self.joystickStepper setIntegerValue:joy_step];
|
||||
#endif
|
||||
|
||||
joy_clip_to_radius = [defaults boolForKey:kApple2JoystickClipToRadius];
|
||||
[self.joystickClipToRadius setState:joy_clip_to_radius ? NSOnState : NSOffState];
|
||||
|
||||
[self _setupJoystickUI];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(drawJoystickCalibration:) name:(NSString *)kDrawTimerNotification object:nil];
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
|
@ -156,49 +145,13 @@
|
|||
[super dealloc];
|
||||
}
|
||||
|
||||
- (void)_savePrefs
|
||||
{
|
||||
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
||||
[defaults setBool:YES forKey:kApple2SavedPrefs];
|
||||
[defaults setDouble:cpu_scale_factor forKey:kApple2CPUSpeed];
|
||||
[defaults setDouble:cpu_altscale_factor forKey:kApple2AltSpeed];
|
||||
[defaults setBool:([self.cpuMaxChoice state] == NSOnState) forKey:kApple2CPUSpeedIsMax];
|
||||
[defaults setBool:([self.altMaxChoice state] == NSOnState) forKey:kApple2AltSpeedIsMax];
|
||||
|
||||
long lVal = 0;
|
||||
color_mode_t mode = prefs_parseLongValue(PREF_DOMAIN_VIDEO, PREF_COLOR_MODE, &lVal, /*base:*/10) ? (color_mode_t)lVal : COLOR_INTERP;
|
||||
[defaults setInteger:mode forKey:kApple2ColorConfig];
|
||||
[defaults setInteger:joy_mode forKey:kApple2JoystickConfig];
|
||||
|
||||
long joyStep = prefs_parseLongValue(PREF_DOMAIN_JOYSTICK, PREF_JOYSTICK_KPAD_STEP, &lVal, /*base:*/10) ? lVal : 1;
|
||||
[defaults setInteger:joyStep forKey:kApple2JoystickStep];
|
||||
|
||||
bool bVal = false;
|
||||
bool autoRecenter = prefs_parseBoolValue(PREF_DOMAIN_JOYSTICK, PREF_JOYSTICK_KPAD_AUTO_RECENTER, &bVal) ? bVal : true;
|
||||
[defaults setBool:autoRecenter forKey:kApple2JoystickAutoRecenter];
|
||||
[defaults setBool:joy_clip_to_radius forKey:kApple2JoystickClipToRadius];
|
||||
|
||||
prefs_sync(PREF_DOMAIN_JOYSTICK);
|
||||
}
|
||||
|
||||
- (IBAction)sliderDidMove:(id)sender
|
||||
{
|
||||
NSSlider *slider = (NSSlider *)sender;
|
||||
double value = [slider doubleValue];
|
||||
if (slider == self.cpuSlider)
|
||||
{
|
||||
cpu_scale_factor = value;
|
||||
[self.cpuSliderLabel setStringValue:[NSString stringWithFormat:@"%.0f%%", value*100]];
|
||||
}
|
||||
else
|
||||
{
|
||||
cpu_altscale_factor = value;
|
||||
[self.altSliderLabel setStringValue:[NSString stringWithFormat:@"%.0f%%", value*100]];
|
||||
}
|
||||
|
||||
timing_initialize();
|
||||
|
||||
[self _savePrefs];
|
||||
prefs_setFloatValue(PREF_DOMAIN_VM, (slider == self.cpuSlider) ? PREF_CPU_SCALE : PREF_CPU_SCALE_ALT, value*100);
|
||||
prefs_sync(PREF_DOMAIN_VM);
|
||||
prefs_save();
|
||||
}
|
||||
|
||||
- (IBAction)peggedChoiceChanged:(id)sender
|
||||
|
@ -206,33 +159,42 @@
|
|||
NSButton *maxButton = (NSButton *)sender;
|
||||
if (maxButton == self.cpuMaxChoice)
|
||||
{
|
||||
[self.cpuSlider setEnabled:([maxButton state] != NSOnState)];
|
||||
cpu_scale_factor = ([maxButton state] == NSOnState) ? CPU_SCALE_FASTEST : [self.cpuSlider doubleValue];
|
||||
double value = ([maxButton state] == NSOnState) ? CPU_SCALE_FASTEST : [self.cpuSlider doubleValue];
|
||||
prefs_setFloatValue(PREF_DOMAIN_VM, PREF_CPU_SCALE, value*100);
|
||||
}
|
||||
else
|
||||
{
|
||||
[self.altSlider setEnabled:([maxButton state] != NSOnState)];
|
||||
cpu_altscale_factor = ([maxButton state] == NSOnState) ? CPU_SCALE_FASTEST : [self.altSlider doubleValue];
|
||||
double value = ([maxButton state] == NSOnState) ? CPU_SCALE_FASTEST : [self.altSlider doubleValue];
|
||||
prefs_setFloatValue(PREF_DOMAIN_VM, PREF_CPU_SCALE_ALT, value*100);
|
||||
}
|
||||
|
||||
timing_initialize();
|
||||
|
||||
[self _savePrefs];
|
||||
prefs_sync(PREF_DOMAIN_VM);
|
||||
prefs_save();
|
||||
}
|
||||
|
||||
- (IBAction)colorChoiceChanged:(id)sender
|
||||
{
|
||||
NSInteger mode = [self.colorChoice indexOfSelectedItem];
|
||||
if (! ((mode >= COLOR_NONE) && (mode < NUM_COLOROPTS)) )
|
||||
{
|
||||
mode = COLOR_NONE;
|
||||
}
|
||||
mode = getColorMode(mode);
|
||||
prefs_setLongValue(PREF_DOMAIN_VIDEO, PREF_COLOR_MODE, mode);
|
||||
prefs_sync(PREF_DOMAIN_VIDEO);
|
||||
[self _savePrefs];
|
||||
|
||||
#warning HACK TODO FIXME need to refactor video resetting procedure
|
||||
video_reset();
|
||||
prefs_save();
|
||||
}
|
||||
|
||||
- (IBAction)monochromeColorChoiceChanged:(id)sender {
|
||||
NSInteger mode = [self.monochromeColorChoice indexOfSelectedItem];
|
||||
mode = getMonoMode(mode);
|
||||
prefs_setLongValue(PREF_DOMAIN_VIDEO, PREF_MONO_MODE, mode);
|
||||
prefs_sync(PREF_DOMAIN_VIDEO);
|
||||
prefs_save();
|
||||
}
|
||||
|
||||
- (IBAction)scanlinesChoiceChanged:(id)sender
|
||||
{
|
||||
NSControlStateValue state = [self.scanlinesChoice state];
|
||||
prefs_setBoolValue(PREF_DOMAIN_VIDEO, PREF_SHOW_HALF_SCANLINES, state == NSControlStateValueOn);
|
||||
prefs_sync(PREF_DOMAIN_VIDEO);
|
||||
prefs_save();
|
||||
}
|
||||
|
||||
- (IBAction)soundCardChoiceChanged:(id)sender
|
||||
|
@ -257,34 +219,35 @@
|
|||
- (IBAction)joystickChoiceChanged:(id)sender
|
||||
{
|
||||
NSInteger mode = [self.joystickChoice indexOfSelectedItem];
|
||||
if (! ((mode >= JOY_PCJOY) && (mode < NUM_JOYOPTS)) )
|
||||
{
|
||||
mode = JOY_PCJOY;
|
||||
}
|
||||
joy_mode = (joystick_mode_t)mode;
|
||||
[self _setupJoystickUI];
|
||||
[self _savePrefs];
|
||||
mode = getJoyMode(mode);
|
||||
prefs_setLongValue(PREF_DOMAIN_JOYSTICK, PREF_JOYSTICK_MODE, mode);
|
||||
prefs_sync(PREF_DOMAIN_JOYSTICK);
|
||||
prefs_save();
|
||||
}
|
||||
|
||||
- (IBAction)autoRecenterChoiceChanged:(id)sender
|
||||
{
|
||||
bool autoRecenter = ([self.joystickRecenter state] == NSOnState);
|
||||
prefs_setBoolValue(PREF_DOMAIN_JOYSTICK, PREF_JOYSTICK_KPAD_AUTO_RECENTER, autoRecenter);
|
||||
[self _savePrefs];
|
||||
prefs_sync(PREF_DOMAIN_JOYSTICK);
|
||||
prefs_save();
|
||||
}
|
||||
|
||||
- (IBAction)clipToRadiusChoiceChanged:(id)sender
|
||||
{
|
||||
joy_clip_to_radius = ([self.joystickClipToRadius state] == NSOnState);
|
||||
[self _savePrefs];
|
||||
bool clipToRadius = ([self.joystickClipToRadius state] == NSOnState);
|
||||
prefs_setBoolValue(PREF_DOMAIN_JOYSTICK, PREF_JOYSTICK_CLIP_TO_RADIUS, clipToRadius);
|
||||
prefs_sync(PREF_DOMAIN_JOYSTICK);
|
||||
prefs_save();
|
||||
}
|
||||
|
||||
- (IBAction)stepValueChanged:(id)sender
|
||||
{
|
||||
long joyStep = [self.joystickStepper intValue];
|
||||
[self.joystickStepLabel setIntegerValue:joyStep];
|
||||
prefs_setLongValue(PREF_DOMAIN_JOYSTICK, PREF_JOYSTICK_KPAD_AUTO_RECENTER, joyStep);
|
||||
[self _savePrefs];
|
||||
prefs_setLongValue(PREF_DOMAIN_JOYSTICK, PREF_JOYSTICK_KPAD_STEP, joyStep);
|
||||
prefs_sync(PREF_DOMAIN_JOYSTICK);
|
||||
prefs_save();
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
@ -295,8 +258,8 @@
|
|||
if (![self.joystickCalibrationView isHidden])
|
||||
{
|
||||
[self.joystickCalibrationView setNeedsDisplay:YES];
|
||||
[self.button0Pressed setHidden:!(joy_button0)];
|
||||
[self.button1Pressed setHidden:!(joy_button1)];
|
||||
[self.button0Pressed setHidden:!(run_args.joy_button0)];
|
||||
[self.button1Pressed setHidden:!(run_args.joy_button1)];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -309,11 +272,11 @@
|
|||
{
|
||||
case ALT_LT:
|
||||
leftAltEngaged = !leftAltEngaged;
|
||||
c_keys_handle_input(SCODE_L_ALT, /*pressed:*/leftAltEngaged, /*cooked:*/0);
|
||||
keys_handleInput(SCODE_L_ALT, /*is_pressed:*/leftAltEngaged, /*is_ascii:*/false);
|
||||
break;
|
||||
case ALT_RT:
|
||||
rightAltEngaged = !rightAltEngaged;
|
||||
c_keys_handle_input(SCODE_R_ALT, /*pressed:*/rightAltEngaged, /*cooked:*/0);
|
||||
keys_handleInput(SCODE_R_ALT, /*is_pressed:*/rightAltEngaged, /*is_ascii:*/false);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -324,8 +287,8 @@
|
|||
leftAltEngaged = NO;
|
||||
rightAltEngaged = NO;
|
||||
}
|
||||
[self.button0Pressed setHidden:!(joy_button0)];
|
||||
[self.button1Pressed setHidden:!(joy_button1)];
|
||||
[self.button0Pressed setHidden:!(run_args.joy_button0)];
|
||||
[self.button1Pressed setHidden:!(run_args.joy_button1)];
|
||||
}
|
||||
|
||||
- (void)_handleKeyEvent:(NSEvent *)event pressed:(BOOL)pressed
|
||||
|
@ -335,16 +298,16 @@
|
|||
switch (scode)
|
||||
{
|
||||
case NSUpArrowFunctionKey:
|
||||
c_keys_handle_input(SCODE_U, pressed, /*cooked:*/0);
|
||||
keys_handleInput(SCODE_U, pressed, /*is_ascii:*/false);
|
||||
break;
|
||||
case NSDownArrowFunctionKey:
|
||||
c_keys_handle_input(SCODE_D, pressed, /*cooked:*/0);
|
||||
keys_handleInput(SCODE_D, pressed, /*is_ascii:*/false);
|
||||
break;
|
||||
case NSLeftArrowFunctionKey:
|
||||
c_keys_handle_input(SCODE_L, pressed, /*cooked:*/0);
|
||||
keys_handleInput(SCODE_L, pressed, /*is_ascii:*/false);
|
||||
break;
|
||||
case NSRightArrowFunctionKey:
|
||||
c_keys_handle_input(SCODE_R, pressed, /*cooked:*/0);
|
||||
keys_handleInput(SCODE_R, pressed, /*is_ascii:*/false);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
|
|
@ -106,9 +106,10 @@
|
|||
{
|
||||
cpu_pause();
|
||||
timing_toggleCPUSpeed();
|
||||
if (video_animations && video_animations->animation_showCPUSpeed)
|
||||
video_animation_s *anim = video_getAnimationDriver();
|
||||
if (anim && anim->animation_showCPUSpeed)
|
||||
{
|
||||
video_animations->animation_showCPUSpeed();
|
||||
anim->animation_showCPUSpeed();
|
||||
}
|
||||
cpu_resume();
|
||||
}
|
||||
|
@ -141,9 +142,10 @@
|
|||
[[self pauseItem] setLabel:@"Running"];
|
||||
cpu_resume();
|
||||
}
|
||||
if (video_animations && video_animations->animation_showPaused)
|
||||
video_animation_s *anim = video_getAnimationDriver();
|
||||
if (anim && anim->animation_showPaused)
|
||||
{
|
||||
video_animations->animation_showPaused();
|
||||
anim->animation_showPaused();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -250,27 +252,27 @@
|
|||
}
|
||||
|
||||
case SHIFT_LT:
|
||||
c_keys_handle_input(SCODE_L_SHIFT, ([event modifierFlags] & NSShiftKeyMask), 0);
|
||||
keys_handleInput(SCODE_L_SHIFT, /*is_pressed:*/([event modifierFlags] & NSShiftKeyMask), /*is_ascii:*/false);
|
||||
break;
|
||||
|
||||
case SHIFT_RT:
|
||||
c_keys_handle_input(SCODE_R_SHIFT, ([event modifierFlags] & NSShiftKeyMask), 0);
|
||||
keys_handleInput(SCODE_R_SHIFT, /*is_pressed:*/([event modifierFlags] & NSShiftKeyMask), /*is_ascii:*/false);
|
||||
break;
|
||||
|
||||
case CTRL_LT:
|
||||
c_keys_handle_input(SCODE_L_CTRL, ([event modifierFlags] & NSControlKeyMask), 0);
|
||||
keys_handleInput(SCODE_L_CTRL, /*is_pressed:*/([event modifierFlags] & NSControlKeyMask), /*is_ascii:*/false);
|
||||
break;
|
||||
|
||||
case CTRL_RT:
|
||||
c_keys_handle_input(SCODE_R_CTRL, ([event modifierFlags] & NSControlKeyMask), 0);
|
||||
keys_handleInput(SCODE_R_CTRL, /*is_pressed:*/([event modifierFlags] & NSControlKeyMask), /*is_ascii:*/false);
|
||||
break;
|
||||
|
||||
case ALT_LT:
|
||||
c_keys_handle_input(SCODE_L_ALT, ([event modifierFlags] & NSAlternateKeyMask), 0);
|
||||
keys_handleInput(SCODE_L_ALT, /*is_pressed:*/([event modifierFlags] & NSAlternateKeyMask), /*is_ascii:*/false);
|
||||
break;
|
||||
|
||||
case ALT_RT:
|
||||
c_keys_handle_input(SCODE_R_ALT, ([event modifierFlags] & NSAlternateKeyMask), 0);
|
||||
keys_handleInput(SCODE_R_ALT, /*is_pressed:*/([event modifierFlags] & NSAlternateKeyMask), /*is_ascii:*/false);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -343,6 +345,9 @@
|
|||
case NSInsertFunctionKey:
|
||||
scode = SCODE_INS;
|
||||
break;
|
||||
case NSDeleteCharacter:
|
||||
scode = SCODE_L;
|
||||
break;
|
||||
case NSDeleteFunctionKey:
|
||||
scode = SCODE_DEL;
|
||||
break;
|
||||
|
@ -373,7 +378,7 @@
|
|||
default:
|
||||
if ([event modifierFlags] & NSControlKeyMask)
|
||||
{
|
||||
scode = c_keys_ascii_to_scancode(scode);
|
||||
scode = keys_ascii2Scancode(scode);
|
||||
cooked = 0;
|
||||
}
|
||||
else
|
||||
|
@ -383,7 +388,7 @@
|
|||
break;
|
||||
}
|
||||
|
||||
c_keys_handle_input(scode, pressed, cooked);
|
||||
keys_handleInput(scode, pressed, cooked);
|
||||
}
|
||||
|
||||
- (void)keyUp:(NSEvent *)event
|
||||
|
|
|
@ -86,13 +86,13 @@
|
|||
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryAmbient error:&error];
|
||||
if (error)
|
||||
{
|
||||
ERRLOG("Error setting AVAudioSessionCategoryAmbient : %s", [[error description] UTF8String]);
|
||||
LOG("Error setting AVAudioSessionCategoryAmbient : %s", [[error description] UTF8String]);
|
||||
error = nil;
|
||||
}
|
||||
[[AVAudioSession sharedInstance] setActive:YES error:&error];
|
||||
if (error)
|
||||
{
|
||||
ERRLOG("Error activating AVAudioSession : %s", [[error description] UTF8String]);
|
||||
LOG("Error activating AVAudioSession : %s", [[error description] UTF8String]);
|
||||
error = nil;
|
||||
}
|
||||
}
|
||||
|
@ -103,7 +103,7 @@
|
|||
[[AVAudioSession sharedInstance] setActive:NO error:&error];
|
||||
if (error)
|
||||
{
|
||||
ERRLOG("Error deactivating AVAudioSession : %s", [[error description] UTF8String]);
|
||||
LOG("Error deactivating AVAudioSession : %s", [[error description] UTF8String]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -119,9 +119,12 @@
|
|||
NSString *disks[] = { @"disks", @"external-disks", NULL};
|
||||
|
||||
NSString **str = &disks[0];
|
||||
assert(data_dir == NULL);
|
||||
while (*str) {
|
||||
NSString *apple2ixDirString = [documentsDir stringByAppendingPathComponent:apple2ix];
|
||||
data_dir = strdup([apple2ixDirString UTF8String]);
|
||||
if (data_dir == NULL) {
|
||||
data_dir = STRDUP([apple2ixDirString UTF8String]);
|
||||
}
|
||||
|
||||
NSString *documentsPath = [apple2ixDirString stringByAppendingPathComponent:*str];
|
||||
NSString *resourcesPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:*str];
|
||||
|
@ -142,14 +145,14 @@
|
|||
|
||||
if (error)
|
||||
{
|
||||
ERRLOG("Could not create directory. Error: %s", [[error description] UTF8String]);
|
||||
LOG("Could not create directory. Error: %s", [[error description] UTF8String]);
|
||||
return;
|
||||
}
|
||||
|
||||
NSArray *fileList = [fileManager contentsOfDirectoryAtPath:resourcesPath error:&error];
|
||||
if (error)
|
||||
{
|
||||
ERRLOG("Could not list contents of bundle. Error: %s", [[error description] UTF8String]);
|
||||
LOG("Could not list contents of bundle. Error: %s", [[error description] UTF8String]);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -174,7 +177,7 @@
|
|||
[fileManager copyItemAtPath:resourcesFile toPath:documentsFile error:&error];
|
||||
if (error)
|
||||
{
|
||||
ERRLOG("Could not copy file. Error: %s", [[error description] UTF8String]);
|
||||
LOG("Could not copy file. Error: %s", [[error description] UTF8String]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -300,25 +300,35 @@ static inline void _handleTouch(EAGLView *self, SEL _cmd, UITouch *touch, interf
|
|||
// touched menu item ...
|
||||
if ((flags & TOUCH_FLAGS_INPUT_DEVICE_CHANGE) != 0)
|
||||
{
|
||||
video_animation_s *anim = video_getAnimationDriver();
|
||||
if ((flags & TOUCH_FLAGS_KBD) != 0)
|
||||
{
|
||||
//keydriver_setTouchKeyboardOwnsScreen(true);
|
||||
//joydriver_setTouchJoystickOwnsScreen(false);
|
||||
video_animations->animation_showTouchKeyboard();
|
||||
if (anim && anim->animation_showTouchKeyboard)
|
||||
{
|
||||
anim->animation_showTouchKeyboard();
|
||||
}
|
||||
}
|
||||
else if ((flags & TOUCH_FLAGS_JOY) != 0)
|
||||
{
|
||||
//keydriver_setTouchKeyboardOwnsScreen(false);
|
||||
//joydriver_setTouchJoystickOwnsScreen(true);
|
||||
//joydriver_setTouchVariant(EMULATED_JOYSTICK);
|
||||
video_animations->animation_showTouchJoystick();
|
||||
if (anim && anim->animation_showTouchKeyboard)
|
||||
{
|
||||
anim->animation_showTouchJoystick();
|
||||
}
|
||||
}
|
||||
else if ((flags & TOUCH_FLAGS_JOY_KPAD) != 0)
|
||||
{
|
||||
//keydriver_setTouchKeyboardOwnsScreen(false);
|
||||
//joydriver_setTouchJoystickOwnsScreen(true);
|
||||
//joydriver_setTouchVariant(EMULATED_KEYPAD);
|
||||
video_animations->animation_showTouchJoystick();
|
||||
if (anim && anim->animation_showTouchKeyboard)
|
||||
{
|
||||
anim->animation_showTouchJoystick();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
|
@ -7,16 +7,16 @@
|
|||
<key>CFBundleExecutable</key>
|
||||
<string>${EXECUTABLE_NAME}</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>org.dribin.dave.DDHidLib</string>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>${CURRENT_MARKETING_VERSION}</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>${CURRENT_PROJECT_VERSION}</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>${CURRENT_MARKETING_VERSION}</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
|
@ -85,8 +85,8 @@
|
|||
55D5927D0BAE306E00364849 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 55D5927B0BAE306E00364849 /* InfoPlist.strings */; };
|
||||
55D592940BAE30B600364849 /* MainMenu.nib in Resources */ = {isa = PBXBuildFile; fileRef = 55D592920BAE30B600364849 /* MainMenu.nib */; };
|
||||
55D593290BAE3ABD00364849 /* DDHidLib.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 55193E500B93F2EE004C0C98 /* DDHidLib.framework */; };
|
||||
55D593390BAE3ADF00364849 /* DDHidLib.framework in Copy Files to Frameworks */ = {isa = PBXBuildFile; fileRef = 55193E500B93F2EE004C0C98 /* DDHidLib.framework */; };
|
||||
55D593660BAE3B5D00364849 /* DDHidLib.framework in Copy Files to Frameworks */ = {isa = PBXBuildFile; fileRef = 55193E500B93F2EE004C0C98 /* DDHidLib.framework */; };
|
||||
55D593390BAE3ADF00364849 /* DDHidLib.framework in Copy Files to Frameworks */ = {isa = PBXBuildFile; fileRef = 55193E500B93F2EE004C0C98 /* DDHidLib.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
|
||||
55D593660BAE3B5D00364849 /* DDHidLib.framework in Copy Files to Frameworks */ = {isa = PBXBuildFile; fileRef = 55193E500B93F2EE004C0C98 /* DDHidLib.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
|
||||
55D593750BAE3B7500364849 /* DDHidLib.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 55193E500B93F2EE004C0C98 /* DDHidLib.framework */; };
|
||||
55D5937B0BAE3B8800364849 /* DDHidKeyboard.h in Headers */ = {isa = PBXBuildFile; fileRef = 55CA60E30BA0F2530012CF7B /* DDHidKeyboard.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
55D5937C0BAE3B8800364849 /* DDHidKeyboard.m in Sources */ = {isa = PBXBuildFile; fileRef = 55CA60E40BA0F2530012CF7B /* DDHidKeyboard.m */; };
|
||||
|
@ -624,7 +624,7 @@
|
|||
29B97313FDCFA39411CA2CEA /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastUpgradeCheck = 0460;
|
||||
LastUpgradeCheck = 0930;
|
||||
};
|
||||
buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "DDHidLib" */;
|
||||
compatibilityVersion = "Xcode 3.2";
|
||||
|
@ -831,6 +831,7 @@
|
|||
551711290B8F420E00C82155 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
|
@ -843,6 +844,7 @@
|
|||
5517112A0B8F420E00C82155 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
COPY_PHASE_STRIP = YES;
|
||||
GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
|
||||
|
@ -854,6 +856,7 @@
|
|||
55193E540B93F2EF004C0C98 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
|
@ -873,6 +876,7 @@
|
|||
"-framework",
|
||||
AppKit,
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.dribin.dave.DDHidLib;
|
||||
PRODUCT_NAME = DDHidLib;
|
||||
ZERO_LINK = NO;
|
||||
};
|
||||
|
@ -881,6 +885,7 @@
|
|||
55193E550B93F2EF004C0C98 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
COPY_PHASE_STRIP = YES;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
|
@ -898,6 +903,7 @@
|
|||
"-framework",
|
||||
AppKit,
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.dribin.dave.DDHidLib;
|
||||
PRODUCT_NAME = DDHidLib;
|
||||
ZERO_LINK = NO;
|
||||
};
|
||||
|
@ -907,6 +913,7 @@
|
|||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 55D592200BAE2E4500364849 /* versions.xcconfig */;
|
||||
buildSettings = {
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
|
@ -923,6 +930,7 @@
|
|||
"-framework",
|
||||
AppKit,
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.dribin.dave.ddhidlib.HIDDeviceTest;
|
||||
PRODUCT_NAME = HIDDeviceTest;
|
||||
WRAPPER_EXTENSION = app;
|
||||
};
|
||||
|
@ -932,6 +940,7 @@
|
|||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 55D592200BAE2E4500364849 /* versions.xcconfig */;
|
||||
buildSettings = {
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
COPY_PHASE_STRIP = YES;
|
||||
GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
|
||||
|
@ -946,6 +955,7 @@
|
|||
"-framework",
|
||||
AppKit,
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.dribin.dave.ddhidlib.HIDDeviceTest;
|
||||
PRODUCT_NAME = HIDDeviceTest;
|
||||
WRAPPER_EXTENSION = app;
|
||||
};
|
||||
|
@ -954,6 +964,7 @@
|
|||
559CBBE70B5B338B00C8FD74 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
|
@ -977,6 +988,7 @@
|
|||
559CBBE80B5B338B00C8FD74 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
COPY_PHASE_STRIP = YES;
|
||||
GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
|
||||
|
@ -999,6 +1011,7 @@
|
|||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 55D592200BAE2E4500364849 /* versions.xcconfig */;
|
||||
buildSettings = {
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
|
@ -1007,6 +1020,7 @@
|
|||
INFOPLIST_FILE = browser/Info.plist;
|
||||
INSTALL_PATH = "$(HOME)/Applications";
|
||||
OTHER_LDFLAGS = "-ObjC";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.dribin.dave.ddhidlib.HIDBrowser;
|
||||
PRODUCT_NAME = HIDBrowser;
|
||||
WRAPPER_EXTENSION = app;
|
||||
ZERO_LINK = NO;
|
||||
|
@ -1017,12 +1031,14 @@
|
|||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 55D592200BAE2E4500364849 /* versions.xcconfig */;
|
||||
buildSettings = {
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
|
||||
GCC_MODEL_TUNING = G5;
|
||||
INFOPLIST_FILE = browser/Info.plist;
|
||||
INSTALL_PATH = "$(HOME)/Applications";
|
||||
OTHER_LDFLAGS = "-ObjC";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.dribin.dave.ddhidlib.HIDBrowser;
|
||||
PRODUCT_NAME = HIDBrowser;
|
||||
WRAPPER_EXTENSION = app;
|
||||
ZERO_LINK = NO;
|
||||
|
@ -1033,12 +1049,37 @@
|
|||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 55D592200BAE2E4500364849 /* versions.xcconfig */;
|
||||
buildSettings = {
|
||||
ARCHS = "$(NATIVE_ARCH_ACTUAL)";
|
||||
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = NO;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.7;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = macosx;
|
||||
};
|
||||
name = Debug;
|
||||
|
@ -1047,10 +1088,33 @@
|
|||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 55D592200BAE2E4500364849 /* versions.xcconfig */;
|
||||
buildSettings = {
|
||||
ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
|
||||
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = NO;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.7;
|
||||
SDKROOT = macosx;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
|
@ -9,19 +9,19 @@
|
|||
<key>CFBundleIconFile</key>
|
||||
<string></string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>org.dribin.dave.ddhidlib.HIDBrowser</string>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>${PRODUCT_NAME}</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>${CURRENT_MARKETING_VERSION}</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>${CURRENT_PROJECT_VERSION}</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>${CURRENT_MARKETING_VERSION}</string>
|
||||
<key>NSMainNibFile</key>
|
||||
<string>MainMenu</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
|
@ -7,17 +7,17 @@
|
|||
<key>CFBundleExecutable</key>
|
||||
<string>${EXECUTABLE_NAME}</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>org.dribin.dave.ddhidlib.HIDDeviceTest</string>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>${CURRENT_MARKETING_VERSION}</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>${CURRENT_PROJECT_VERSION}</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>${CURRENT_MARKETING_VERSION}</string>
|
||||
<key>NSMainNibFile</key>
|
||||
<string>MainMenu</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
|
|
|
@ -155,8 +155,7 @@ return retVal;
|
|||
withClass: (Class) hidClass
|
||||
skipZeroLocations: (BOOL) skipZeroLocations;
|
||||
{
|
||||
|
||||
(void)((id(*)(id, SEL))objc_msgSend((id)matchDictionary, @selector(retain)));
|
||||
CFRetain(matchDictionary);
|
||||
|
||||
// Now search I/O Registry for matching devices.
|
||||
io_iterator_t hidObjectIterator = MACH_PORT_NULL;
|
||||
|
|
|
@ -53,7 +53,7 @@
|
|||
|
||||
- (NSArray *) buttonElements;
|
||||
|
||||
- (unsigned) numberOfButtons;
|
||||
- (NSUInteger) numberOfButtons;
|
||||
|
||||
- (void) addElementsToQueue: (DDHidQueue *) queue;
|
||||
|
||||
|
|
|
@ -122,7 +122,7 @@
|
|||
return mButtonElements;
|
||||
}
|
||||
|
||||
- (unsigned) numberOfButtons;
|
||||
- (NSUInteger) numberOfButtons;
|
||||
{
|
||||
return [mButtonElements count];
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
|
||||
#import "DDHidQueue.h"
|
||||
#import "DDHidElement.h"
|
||||
#import "DDHIdEvent.h"
|
||||
#import "DDHidEvent.h"
|
||||
#import "NSXReturnThrowError.h"
|
||||
|
||||
static void queueCallbackFunction(void* target, IOReturn result, void* refcon,
|
||||
|
|
|
@ -11,22 +11,29 @@
|
|||
|
||||
#if TARGET_OS_IPHONE
|
||||
# import "AppDelegate.h"
|
||||
#elif TARGET_OS_MAC
|
||||
# import <AppKit/NSApplication.h>
|
||||
#else
|
||||
# error what new devilry is this?
|
||||
#endif
|
||||
|
||||
extern int argc;
|
||||
extern const char **argv;
|
||||
#include "common.h"
|
||||
|
||||
int main(int argc_, const char *argv_[])
|
||||
int main(int argc_, char *argv_[])
|
||||
{
|
||||
int retVal = 1;
|
||||
argc = argc_;
|
||||
argv = argv_;
|
||||
|
||||
|
||||
#if !TESTING
|
||||
cpu_pause();
|
||||
#endif
|
||||
|
||||
@autoreleasepool {
|
||||
#if TARGET_OS_IPHONE
|
||||
retVal = UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
|
||||
#else
|
||||
retVal = NSApplicationMain(argc, argv);
|
||||
retVal = NSApplicationMain(argc, (const char **)argv);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
98
Makefile.am
98
Makefile.am
|
@ -14,13 +14,14 @@ noinst_HEADERS = src/common.h src/cpu.h src/disk.h src/glue.h src/vm.h \
|
|||
src/timing.h src/uthash.h src/video/video.h src/zlib-helpers.h \
|
||||
\
|
||||
src/x86/glue-prologue.h \
|
||||
src/meta/debug.h src/meta/trace.h \
|
||||
src/x86/glue-offsets.h src/x86/glue-offsets32.h src/x86/glue-offsets64.h \
|
||||
src/meta/debug.h src/meta/log.h src/meta/systrace.h \
|
||||
\
|
||||
src/audio/alhelpers.h src/audio/AY8910.h src/audio/mockingboard.h \
|
||||
src/audio/peripherals.h src/audio/soundcore.h src/audio/speaker.h \
|
||||
src/audio/SSI263Phonemes.h
|
||||
|
||||
noinst_PROGRAMS = genfont genrom
|
||||
noinst_PROGRAMS = genfont genrom glue_offsets
|
||||
|
||||
###############################################################################
|
||||
# Apple //ix and supporting sources
|
||||
|
@ -31,12 +32,13 @@ ASM_SRC_x86 = \
|
|||
src/x86/glue.S src/x86/cpu.S
|
||||
|
||||
VIDEO_SRC = \
|
||||
src/video/xvideo.c \
|
||||
src/video/glvideo.c \
|
||||
src/video/glutinput.c \
|
||||
src/video/glnode.c \
|
||||
src/video/glhudmodel.c \
|
||||
src/video/glalert.c \
|
||||
src/video/ncvideo.c \
|
||||
src/video/xvideo.c \
|
||||
src/video_util/matrixUtil.c \
|
||||
src/video_util/modelUtil.c \
|
||||
src/video_util/sourceUtil.c \
|
||||
|
@ -46,29 +48,49 @@ AUDIO_SRC = \
|
|||
src/audio/soundcore.c src/audio/soundcore-openal.c src/audio/speaker.c \
|
||||
src/audio/playqueue.c src/audio/alhelpers.c src/audio/mockingboard.c \
|
||||
src/audio/AY8910.c
|
||||
|
||||
META_SRC = \
|
||||
src/meta/debug.l src/meta/debugger.c src/meta/opcodes.c src/test/sha1.c \
|
||||
src/meta/lintrace.c
|
||||
|
||||
|
||||
# NOTE : selectively enabled through configuration process ...
|
||||
EXTRA_apple2ix_SOURCES = $(ASM_SRC_x86) $(VIDEO_SRC) $(AUDIO_SRC) $(META_SRC)
|
||||
EXTRA_apple2ix_SOURCES = $(ASM_SRC_x86) $(VIDEO_SRC) $(AUDIO_SRC)
|
||||
|
||||
apple2ix_SOURCES = src/font.c src/rom.c src/misc.c src/display.c src/vm.c \
|
||||
src/timing.c src/zlib-helpers.c src/joystick.c src/keys.c src/prefs.c \
|
||||
src/interface.c src/disk.c src/cpu-supp.c src/json_parse.c src/memmngt.c \
|
||||
externals/jsmn/jsmn.c
|
||||
apple2ix_SOURCES = \
|
||||
externals/jsmn/jsmn.c \
|
||||
src/cpu-supp.c \
|
||||
src/disk.c \
|
||||
src/display.c \
|
||||
src/font.c \
|
||||
src/interface.c \
|
||||
src/joystick.c \
|
||||
src/json_parse.c \
|
||||
src/keys.c \
|
||||
src/meta/darwin-shim.c \
|
||||
src/meta/debug.l \
|
||||
src/meta/debugger.c \
|
||||
src/meta/systrace.c \
|
||||
src/meta/log.c \
|
||||
src/meta/memmngt.c \
|
||||
src/meta/opcodes.c \
|
||||
src/misc.c \
|
||||
src/prefs.c \
|
||||
src/rom.c \
|
||||
src/test/sha1.c \
|
||||
src/timing.c \
|
||||
src/video/video.c \
|
||||
src/video/ntsc.c \
|
||||
src/vm.c \
|
||||
src/zlib-helpers.c
|
||||
|
||||
apple2ix_CFLAGS = @AM_CFLAGS@ @X_CFLAGS@
|
||||
apple2ix_CCASFLAGS = $(apple2ix_CFLAGS)
|
||||
apple2ix_LDFLAGS = -Wl,-z,noexecstack
|
||||
apple2ix_LDADD = @ASM_O@ @VIDEO_O@ @AUDIO_O@ @META_O@ @X_LIBS@
|
||||
apple2ix_DEPENDENCIES = @ASM_O@ @VIDEO_O@ @AUDIO_O@ @META_O@
|
||||
apple2ix_LDADD = @ASM_O@ @VIDEO_O@ @AUDIO_O@ @X_LIBS@
|
||||
apple2ix_DEPENDENCIES = @ASM_O@ @VIDEO_O@ @AUDIO_O@
|
||||
|
||||
genfont_SOURCES = src/genfont.c
|
||||
|
||||
genrom_SOURCES = src/genrom.c
|
||||
|
||||
glue_offsets_SOURCES = src/glue-offsets.c
|
||||
|
||||
src/font.c: src/font.txt genfont
|
||||
./genfont < $< > $@
|
||||
|
||||
|
@ -95,9 +117,9 @@ testcpu_SOURCES = src/test/testcpu.c $(A2_TEST_SOURCES)
|
|||
testcpu_CFLAGS = $(A2_TEST_CFLAGS) -DTEST_CPU=1
|
||||
testcpu_CCASFLAGS = $(testcpu_CFLAGS)
|
||||
testcpu_LDFLAGS = $(apple2ix_LDFLAGS)
|
||||
testcpu_LDADD = @testcpu_ASM_O@ @testcpu_VIDEO_O@ @testcpu_AUDIO_O@ @testcpu_META_O@ @X_LIBS@
|
||||
testcpu_DEPENDENCIES = @testcpu_ASM_O@ @testcpu_VIDEO_O@ @testcpu_AUDIO_O@ @testcpu_META_O@
|
||||
EXTRA_testcpu_SOURCES = $(ASM_SRC_x86) $(VIDEO_SRC) $(AUDIO_SRC) $(META_SRC)
|
||||
testcpu_LDADD = @testcpu_ASM_O@ @testcpu_VIDEO_O@ @testcpu_AUDIO_O@ @X_LIBS@
|
||||
testcpu_DEPENDENCIES = @testcpu_ASM_O@ @testcpu_VIDEO_O@ @testcpu_AUDIO_O@
|
||||
EXTRA_testcpu_SOURCES = $(ASM_SRC_x86) $(VIDEO_SRC) $(AUDIO_SRC)
|
||||
|
||||
#######################################
|
||||
|
||||
|
@ -105,19 +127,19 @@ testdisk_SOURCES = src/test/testdisk.c $(A2_TEST_SOURCES)
|
|||
testdisk_CFLAGS = $(A2_TEST_CFLAGS) -DTEST_DISK=1 -DDISK_TRACING=1
|
||||
testdisk_CCASFLAGS = $(testdisk_CFLAGS)
|
||||
testdisk_LDFLAGS = $(apple2ix_LDFLAGS)
|
||||
testdisk_LDADD = @testdisk_ASM_O@ @testdisk_VIDEO_O@ @testdisk_AUDIO_O@ @testdisk_META_O@ @X_LIBS@
|
||||
testdisk_DEPENDENCIES = @testdisk_ASM_O@ @testdisk_VIDEO_O@ @testdisk_AUDIO_O@ @testdisk_META_O@
|
||||
EXTRA_testdisk_SOURCES = $(ASM_SRC_x86) $(VIDEO_SRC) $(AUDIO_SRC) $(META_SRC)
|
||||
testdisk_LDADD = @testdisk_ASM_O@ @testdisk_VIDEO_O@ @testdisk_AUDIO_O@ @X_LIBS@
|
||||
testdisk_DEPENDENCIES = @testdisk_ASM_O@ @testdisk_VIDEO_O@ @testdisk_AUDIO_O@
|
||||
EXTRA_testdisk_SOURCES = $(ASM_SRC_x86) $(VIDEO_SRC) $(AUDIO_SRC)
|
||||
|
||||
#######################################
|
||||
|
||||
testdisplay_SOURCES = src/test/testdisplay.c $(A2_TEST_SOURCES)
|
||||
testdisplay_CFLAGS = $(A2_TEST_CFLAGS) -DTEST_DISPLAY=1
|
||||
testdisplay_CFLAGS = $(A2_TEST_CFLAGS) -DTEST_DISPLAY=1 -DVIDEO_TRACING=1
|
||||
testdisplay_CCASFLAGS = $(testdisplay_CFLAGS)
|
||||
testdisplay_LDFLAGS = $(apple2ix_LDFLAGS)
|
||||
testdisplay_LDADD = @testdisplay_ASM_O@ @testdisplay_VIDEO_O@ @testdisplay_AUDIO_O@ @testdisplay_META_O@ @X_LIBS@
|
||||
testdisplay_DEPENDENCIES = @testdisplay_ASM_O@ @testdisplay_VIDEO_O@ @testdisplay_AUDIO_O@ @testdisplay_META_O@
|
||||
EXTRA_testdisplay_SOURCES = $(ASM_SRC_x86) $(VIDEO_SRC) $(AUDIO_SRC) $(META_SRC)
|
||||
testdisplay_LDADD = @testdisplay_ASM_O@ @testdisplay_VIDEO_O@ @testdisplay_AUDIO_O@ @X_LIBS@
|
||||
testdisplay_DEPENDENCIES = @testdisplay_ASM_O@ @testdisplay_VIDEO_O@ @testdisplay_AUDIO_O@
|
||||
EXTRA_testdisplay_SOURCES = $(ASM_SRC_x86) $(VIDEO_SRC) $(AUDIO_SRC)
|
||||
|
||||
#######################################
|
||||
|
||||
|
@ -125,19 +147,19 @@ testprefs_SOURCES = src/test/testprefs.c $(A2_TEST_SOURCES)
|
|||
testprefs_CFLAGS = $(A2_TEST_CFLAGS) -DTEST_PREFS=1
|
||||
testprefs_CCASFLAGS = $(testprefs_CFLAGS)
|
||||
testprefs_LDFLAGS = $(apple2ix_LDFLAGS)
|
||||
testprefs_LDADD = @testprefs_ASM_O@ @testprefs_VIDEO_O@ @testprefs_AUDIO_O@ @testprefs_META_O@ @X_LIBS@
|
||||
testprefs_DEPENDENCIES = @testprefs_ASM_O@ @testprefs_VIDEO_O@ @testprefs_AUDIO_O@ @testprefs_META_O@
|
||||
EXTRA_testprefs_SOURCES = $(ASM_SRC_x86) $(VIDEO_SRC) $(AUDIO_SRC) $(META_SRC)
|
||||
testprefs_LDADD = @testprefs_ASM_O@ @testprefs_VIDEO_O@ @testprefs_AUDIO_O@ @X_LIBS@
|
||||
testprefs_DEPENDENCIES = @testprefs_ASM_O@ @testprefs_VIDEO_O@ @testprefs_AUDIO_O@
|
||||
EXTRA_testprefs_SOURCES = $(ASM_SRC_x86) $(VIDEO_SRC) $(AUDIO_SRC)
|
||||
|
||||
#######################################
|
||||
|
||||
testtrace_SOURCES = src/test/testtrace.c $(A2_TEST_SOURCES)
|
||||
testtrace_CFLAGS = $(A2_TEST_CFLAGS) -DTEST_TRACE=1 -DCPU_TRACING=1 -DDISK_TRACING=1 -DVM_TRACING=1 -DSPEAKER_TRACING=1 -DMB_TRACING=1
|
||||
testtrace_CFLAGS = $(A2_TEST_CFLAGS) -DTEST_TRACE=1 -DCPU_TRACING=1 -DDISK_TRACING=1 -DVM_TRACING=1 -DSPEAKER_TRACING=1 -DMB_TRACING=1 -DVIDEO_TRACING=1
|
||||
testtrace_CCASFLAGS = $(testtrace_CFLAGS)
|
||||
testtrace_LDFLAGS = $(apple2ix_LDFLAGS)
|
||||
testtrace_LDADD = @testtrace_ASM_O@ @testtrace_VIDEO_O@ @testtrace_AUDIO_O@ @testtrace_META_O@ @X_LIBS@
|
||||
testtrace_DEPENDENCIES = @testtrace_ASM_O@ @testtrace_VIDEO_O@ @testtrace_AUDIO_O@ @testtrace_META_O@
|
||||
EXTRA_testtrace_SOURCES = $(ASM_SRC_x86) $(VIDEO_SRC) $(AUDIO_SRC) $(META_SRC)
|
||||
testtrace_LDADD = @testtrace_ASM_O@ @testtrace_VIDEO_O@ @testtrace_AUDIO_O@ @X_LIBS@
|
||||
testtrace_DEPENDENCIES = @testtrace_ASM_O@ @testtrace_VIDEO_O@ @testtrace_AUDIO_O@
|
||||
EXTRA_testtrace_SOURCES = $(ASM_SRC_x86) $(VIDEO_SRC) $(AUDIO_SRC)
|
||||
|
||||
#######################################
|
||||
|
||||
|
@ -145,9 +167,9 @@ testui_SOURCES = src/test/testui.c $(A2_TEST_SOURCES)
|
|||
testui_CFLAGS = $(A2_TEST_CFLAGS) -DTEST_UI=1
|
||||
testui_CCASFLAGS = $(testui_CFLAGS)
|
||||
testui_LDFLAGS = $(apple2ix_LDFLAGS)
|
||||
testui_LDADD = @testui_ASM_O@ @testui_VIDEO_O@ @testui_AUDIO_O@ @testui_META_O@ @X_LIBS@
|
||||
testui_DEPENDENCIES = @testui_ASM_O@ @testui_VIDEO_O@ @testui_AUDIO_O@ @testui_META_O@
|
||||
EXTRA_testui_SOURCES = $(ASM_SRC_x86) $(VIDEO_SRC) $(AUDIO_SRC) $(META_SRC)
|
||||
testui_LDADD = @testui_ASM_O@ @testui_VIDEO_O@ @testui_AUDIO_O@ @X_LIBS@
|
||||
testui_DEPENDENCIES = @testui_ASM_O@ @testui_VIDEO_O@ @testui_AUDIO_O@
|
||||
EXTRA_testui_SOURCES = $(ASM_SRC_x86) $(VIDEO_SRC) $(AUDIO_SRC)
|
||||
|
||||
#######################################
|
||||
|
||||
|
@ -155,9 +177,9 @@ testvm_SOURCES = src/test/testvm.c $(A2_TEST_SOURCES)
|
|||
testvm_CFLAGS = $(A2_TEST_CFLAGS) -DTEST_VM=1
|
||||
testvm_CCASFLAGS = $(testvm_CFLAGS)
|
||||
testvm_LDFLAGS = $(apple2ix_LDFLAGS)
|
||||
testvm_LDADD = @testvm_ASM_O@ @testvm_VIDEO_O@ @testvm_AUDIO_O@ @testvm_META_O@ @X_LIBS@
|
||||
testvm_DEPENDENCIES = @testvm_ASM_O@ @testvm_VIDEO_O@ @testvm_AUDIO_O@ @testvm_META_O@
|
||||
EXTRA_testvm_SOURCES = $(ASM_SRC_x86) $(VIDEO_SRC) $(AUDIO_SRC) $(META_SRC)
|
||||
testvm_LDADD = @testvm_ASM_O@ @testvm_VIDEO_O@ @testvm_AUDIO_O@ @X_LIBS@
|
||||
testvm_DEPENDENCIES = @testvm_ASM_O@ @testvm_VIDEO_O@ @testvm_AUDIO_O@
|
||||
EXTRA_testvm_SOURCES = $(ASM_SRC_x86) $(VIDEO_SRC) $(AUDIO_SRC)
|
||||
|
||||
###############################################################################
|
||||
# Misc & Installation
|
||||
|
|
277
NEWS
277
NEWS
|
@ -1,277 +0,0 @@
|
|||
Changed in 0.8:
|
||||
|
||||
Upgraded to modern-ish times...X11 now uses 32bit color!
|
||||
|
||||
Audio is now OpenAL instead of raw PC speaker access. We are indebted to
|
||||
AppleWin for much of the sound code including preliminary suport for
|
||||
Mockingboard emulation.
|
||||
|
||||
Bugfix and simplification for PC Joystick. Joystick emulation is now
|
||||
bug-for-bug compatible with original Apple ][. Better calibration routines and
|
||||
better "feel" for emulation of joystick on keypad/arrow-keys.
|
||||
|
||||
Better emulation fidelity overall by counting 6502 CPU cycles. This was
|
||||
necessary for proper output of stream digital audio in OpenAL.
|
||||
|
||||
Significant interface and preferences changes and simplifications.
|
||||
|
||||
Changed in 0.7.4:
|
||||
|
||||
Many bugs have been fixed, including a calling-convention mistake that
|
||||
could cause unpredictable behavior on reboot. Potential buffer overflows
|
||||
have also been corrected.
|
||||
|
||||
Some key assignments have changed. Joystick buttons are now Left-Alt,
|
||||
Right-Alt & Insert. Delete, formerly a joystick button, now produces the
|
||||
DEL ascii code. Reboot is now Break (Ctrl-Pause), and Reset is now
|
||||
Ctrl-Printscreen. (This is reversed from 0.7.3)
|
||||
|
||||
Some significant optimizations were also made in the assembly code. The
|
||||
large memory-access indirection table is now compressed using virtual
|
||||
memory tricks, to slightly reduce cache load and swap requirements.
|
||||
|
||||
Also many cleanups have been made in the internal code. This is
|
||||
user-invisible, and far from complete. When done, it will become easier to
|
||||
add new interface cards, video drivers, and other stuff, as well as port
|
||||
to other unixes.
|
||||
|
||||
Changed in 0.7.3:
|
||||
|
||||
More makefile/configuration bugs were fixed.
|
||||
|
||||
The `Mystery House' sample disk, which was accidently omitted from my
|
||||
distributions, has been reinstated. Also, I've added a new sample
|
||||
disk image - William Night's emulator performance tests.
|
||||
|
||||
Changed in 0.7.2:
|
||||
|
||||
The configure script will now react to absence of X Windows or SVGAlib by
|
||||
only building an emulator for the remaining graphics system.
|
||||
|
||||
A makefile bug that caused xapple-80col not to depend on
|
||||
all it's source files was fixed. Also, the alternate character set is now
|
||||
correctly restored on exit from the <F10> menu.
|
||||
|
||||
Some major cleanups were done to the assembly-language files. This is
|
||||
invisible to the user, but should make further enhancement a little saner.
|
||||
|
||||
The banners on the source code have been synchronized.
|
||||
|
||||
Changed in 0.7.1:
|
||||
|
||||
1. Fixed a makefile bug that caused xapple-80col to be miscompiled.
|
||||
|
||||
2. Put sample .apple2 (config file) back in. It was accidentally excluded
|
||||
from 0.7.
|
||||
|
||||
3. The SVGA emulator is again named `apple2', not `sapple2'.
|
||||
|
||||
Changed in 0.7: (Sep 98)
|
||||
|
||||
Version 0.7 - Michael Deutschmann <michael@talamasca.wkpowerlink.com>
|
||||
|
||||
1. Replaced "character.rom" and Aaron's MouseText table in misc.c with
|
||||
a single file, font.txt, which is converted into a packed c table by a
|
||||
generator utility.
|
||||
|
||||
2. Overhauled Makefile system. We now use GNU autoconf/automake.
|
||||
|
||||
Note: This hasn't been tested extensively. Also, there are a few automake
|
||||
tricks I haven't bothered with - I added them to TODO.
|
||||
|
||||
Changed is 0.06: (Aug 98)
|
||||
-------------------------
|
||||
|
||||
Version 0.06 - Aaron Culliney <chernabog@baldmountain.bbn.com,
|
||||
aculline@bbn.com>
|
||||
My code changes have nothing to do with my employer, GTE
|
||||
Internetworking, BBN Technologies. They were written completely on my
|
||||
own time and on my own machine.
|
||||
|
||||
1) Separated SVGAlib specific stuff into svideo.c. Added X Windows
|
||||
frontend support in xvideo.c. The X frontend works by doing an
|
||||
X(Shm)PutImage() of the emulator's framebuffer around 30 times a
|
||||
second. This saves us from changing the internal video routines (they
|
||||
assume direct access to an 8bit framebuffer), and it's a heck of a lot
|
||||
faster than trying to do an XPutPixels() on each change. The X
|
||||
frontend only currently works for 8bit displays. Make sure you run it
|
||||
using a mode (specified in XF86Config) that has a bit depth of 8 (not
|
||||
16 or greater).
|
||||
|
||||
2) We now build three versions of the emulator: svideo_320x200,
|
||||
xvideo_320x200, xvideo_640x400. The last one really isn't 640x400 for
|
||||
optimization reasons (568x384) although it probably should be...
|
||||
Sorry, but there's no support for switching resolutions on the fly, we
|
||||
ifdef it in with a new define "_640x400".
|
||||
|
||||
3) Provided 80column support for the 640x400 X version. Now you
|
||||
can PR#3 (running as //e) and get 80 columns. This change required
|
||||
a resolution of at least 560 horizontal pixels (Apple //e specs).
|
||||
|
||||
4) Both SVGA and X versions need to be suid root (for PC speaker port
|
||||
access and SVGA stuff). But both versions now give up root access
|
||||
during video initialization. This means that disk access is now done
|
||||
as *you* (not root) even when g(un)zipping images for loading.
|
||||
Before images would be g(un)zipped as root. There was something about
|
||||
this that made me uneasy... Now it's up to you to give the
|
||||
appropriate user/group permissions to your disk image repository.
|
||||
I make no claim about the security fitness of this emulator. See the
|
||||
other READMEs and files for more information/disclaimers.
|
||||
|
||||
5) Did a 180 on the disk image selection menu. <RET> now tries
|
||||
to open disk images as read-only, 'W' for both read-write.
|
||||
Of course this will only work if you have the correct
|
||||
file permissions set (see 5 above). I find this more convenient b/c
|
||||
I play alot of the arcade games where you don't ever save game state.
|
||||
|
||||
6) Removed the disk "Information" submenu. I never use it. Do you?
|
||||
|
||||
|
||||
|
||||
Changes in 0.05: (Feb 98)
|
||||
-------------------------
|
||||
|
||||
Version 0.05 - Aaron Culliney <chernabog@baldmountain.bbn.com,
|
||||
aculline@bbn.com>
|
||||
My code changes have nothing to do with my employer, GTE
|
||||
Internetworking, BBN Technologies. They were written completely on my
|
||||
own time and on my own machine.
|
||||
|
||||
1) Added support for 65c02 instructions. The programs that
|
||||
I've tested which use them work just fine.
|
||||
|
||||
2) Added support for 128k //e EXCEPT 80 column mode, B/W
|
||||
DHIRES mode, and MouseText character set. The two unimplemented video
|
||||
modes require major changes to current video routines, thus a next
|
||||
version... New supported images are copy ii+ 9.0, diagnostics //e,
|
||||
marble madness, airheart, legend of blacksilver, pirates!...
|
||||
|
||||
3) Fixed some old problems with HIRES colors being off around
|
||||
byte edges in interpolated/color modes. but we still give you the
|
||||
option to use these "lazy" modes since emulation is faster with them
|
||||
enabled...
|
||||
|
||||
4) You now have several new options in your .apple2 file. I
|
||||
suggest either copying the distributed one over your existing one, or
|
||||
merging the changes in.
|
||||
|
||||
5) Fixed some potential security bugs where a user could
|
||||
traverse into sensitive directories by using the disk selection
|
||||
interface. The current emulator version is not guaranteed to be
|
||||
foolproof since it has to be installed suid root for normal users to
|
||||
use it. Sysadmins should take extra precautions as they see fit.
|
||||
|
||||
6) Added and deprecated some options in the debugger interface
|
||||
to support the new 128k //e. see the DEBUGGER file for more info.
|
||||
DEBUGGER support is not default compiled in.
|
||||
|
||||
7) added some extra options to the .config file that you build
|
||||
into the emulator. One big one: a way to set the max delay count in
|
||||
the emulator to bring Apple ][ emulation rates down to normal on high
|
||||
end pentiums!... 100 is the default delay rate (which works just fine
|
||||
for low end 386-Pentium100's).
|
||||
|
||||
|
||||
|
||||
Changes in 0.04: (June 97)
|
||||
-----------------------------
|
||||
|
||||
Version 0.04 - Aaron Culliney <chernabog@baldmountain.bbn.com,
|
||||
aculline@bbn.com>
|
||||
My code changes have nothing to do with my employer, BBN. They were
|
||||
written completely on my own time and on my own machine.
|
||||
|
||||
1) Added PC Joystick Support. You must have the joystick
|
||||
kernel loadable module 0.8.0 correctly configured and installed to use
|
||||
this feature.
|
||||
|
||||
2) Changed the way the emulator handles the language card
|
||||
memory space. We no longer patch rom/ram on lc_c08x functions. I did
|
||||
this because under certain conditions the previous versions of the
|
||||
emulator would run a lot slower. Now you may notice the emulator
|
||||
running a tad slower in general (because of the range checking), but
|
||||
Ultima 4 and Arctic Fox (formerly unplayable) should now be just fine.
|
||||
|
||||
3) Changed the way the .apple2 preferences file is handled. I
|
||||
Did this mainly to support saving of PC Joystick parameters, and I'd
|
||||
rather let flex do the dirty work of regexp matching.
|
||||
|
||||
4) Changed the disk interface and main interface menu. In the
|
||||
disk interface, you can now see which disk is in the drive, and with
|
||||
what permission <rw1> for read/write drive 1. You can eject this disk
|
||||
or force it to be write-protected. In the main menu screen, you have
|
||||
more parameters to play around with (associated with the pc joystick
|
||||
add-on).
|
||||
|
||||
5) Disk image files are now opened with user privileges, not
|
||||
root privileges, even though the program is suid root. gzip'ed disks
|
||||
are still handled as root, but we no longer call the unsecure system()
|
||||
to do the dirty work. Instead we fork and directly exec "/bin/gzip".
|
||||
|
||||
5) General bug fixes and enhancements.
|
||||
|
||||
|
||||
Changes in 0.03: (Jan-Feb 97)
|
||||
-----------------------------
|
||||
|
||||
Version 0.03 - Aaron Culliney <chernabog@baldmountain.bbn.com>
|
||||
My code changes have nothing to do with my employer, BBN. They were
|
||||
written completely on my own time and on my own machine.
|
||||
|
||||
1) Fixed language card initialization bug.
|
||||
|
||||
2) Improved colors. Seems that Greens and purples we're
|
||||
switched around. The colors are still slightly off, and color
|
||||
interpolation seems screwy (TODO).
|
||||
|
||||
3) Added apple II debugger interface. This requires flex
|
||||
version 2.5.2. (You can compile this into the program or leave it
|
||||
out.) Type F7 to get into the debugger and type a '?' to see a
|
||||
command summary. Check out the file DEBUGGER for more info.
|
||||
|
||||
4) Added support for standard 232960 .nib disks.
|
||||
|
||||
5) Added a more intuitive interface to selecting disks. You
|
||||
can now traverse forward and backward in a directory hierarchy with
|
||||
the base directory set by your .apple2 config file.
|
||||
|
||||
6) changed keymap: shift-p = @ and shift-N = ^, just like my
|
||||
old II+ keyboard.
|
||||
|
||||
Changes in 0.02: (8 Dec 1995)
|
||||
-----------------------------
|
||||
|
||||
* Ctrl-C will not kill the emulator with newer SVGAlib. Please
|
||||
use SVGAlib > 1.2.9 for best results.
|
||||
|
||||
* Rudimentory REPT key handling. It's too fast though.
|
||||
|
||||
* The assembler files now compiles under ELF.
|
||||
|
||||
* Not every SVGA card can do page-flipping. The emulator now
|
||||
checks for this and fall back to VGA if it can't.
|
||||
|
||||
* Keymap has changed a bit. Backspace and ']' is now <-, '[' is
|
||||
REPT.
|
||||
|
||||
* Disk extension changed to the more common .dsk (and a2d.info to
|
||||
dsk.info).
|
||||
|
||||
|
||||
Changes in 0.01: (9 Oct 1994)
|
||||
-----------------------------
|
||||
|
||||
* Standard VGA support with some performance degradation.
|
||||
(When page flipping occurs, 64K memory banks are swapped;
|
||||
hence the performance degradation.)
|
||||
|
||||
* -vga flag switch added, e.g. "apple2 -vga"; forces standard
|
||||
VGA detection.
|
||||
|
||||
* (Trident) TVGA8900 page flipping bug fixed.
|
||||
|
||||
* File names may now contain any character codes. (The previous
|
||||
version had some problems with compressing/uncompressing file
|
||||
names with extraordinary characters.)
|
||||
|
||||
* Diskette selection retains last cursor position.
|
58
PROBLEMS
58
PROBLEMS
|
@ -1,58 +0,0 @@
|
|||
Known issues with the emulator:
|
||||
|
||||
Emulation Fidelity:
|
||||
|
||||
- Disk emulation. The emulator is not very realistic. It handles almost
|
||||
all non-copyprotected disk access okay, but copyprotected or diagnostic
|
||||
programs may be confused by our drive, which magically spins at precisely
|
||||
the optimal speed. (see Specific Programs, below).
|
||||
|
||||
- Medium Resolution graphics. This is a rarely used //e mode that is to
|
||||
Low-Res what 80 Column text is to 40 column text. We don't support it as
|
||||
yet, although it should be relatively simple.
|
||||
|
||||
- We don't emulate the //e's vertical blanking interval detection feature.
|
||||
This is on the TODO list.
|
||||
|
||||
Graphics:
|
||||
|
||||
- Composite graphics artifacts are not emulated. This is on the TODO list.
|
||||
|
||||
- B/W color setting does not apply to lores or double hires. This
|
||||
generally is not an issue in practice though, as it's really only needed
|
||||
to avoid color fringing in b/w hires images.
|
||||
|
||||
- Double Hires mode is always 140x192 color. Some applications use it as
|
||||
a 560x192 b/w display however. Note that most applications indicate
|
||||
which mode they want using the high bit of the dhires data bytes, so it
|
||||
wouldn't need to be a preferences setting.
|
||||
|
||||
- If an 80-column mode is selected in the low-res emulator, nothing will
|
||||
be written to the display -- the image from the last video mode will
|
||||
remain on the screen. If a menu is brought up it will `stick'. This may
|
||||
make people think the emulator crashed, although it will recover if the
|
||||
application returns to 40-column mode.
|
||||
|
||||
Keyboard:
|
||||
|
||||
- Presently, the Backspace key is interpreted as Left-Arrow (Code 0x88).
|
||||
It could be argued that it should be interpreted as Delete (Code 0xff)
|
||||
instead. Real Apples had no seperate Backspace key, but the //e's Delete
|
||||
key was in an analogous position to the PC's Backspace). The PC
|
||||
keyboard's Delete is assigned to 0xff (in //e mode).
|
||||
|
||||
Specific Programs:
|
||||
|
||||
- Some programs (Computist's Nibbler, Sword of Kadash Master copy for
|
||||
example) lock up. It appears (in debugger) that they are reading the disk
|
||||
with the motor off. Perhaps they pulsed the real Apple's drive motor to make
|
||||
it turn slower?
|
||||
|
||||
- ProDOS will refuse to format disks, claiming that the disk is too slow.
|
||||
|
||||
- ``Alternate Reality: The City'' seems to get jammed, rapidly changing
|
||||
the video mode. I'm not sure if this is a real failure, or just a special
|
||||
effect that takes longer than I'm willing to wait to finish (mode switches
|
||||
would be much faster on a real Apple.) I can get into the program
|
||||
with some nontrivial debugger manipulation to `short out' the offending loops.
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user