mirror of
https://github.com/jamessanford/kegs.git
synced 2025-01-09 20:30:59 +00:00
Initial Android application.
This commit is contained in:
parent
a9f6a3f1b0
commit
814d298c4c
20
AndroidManifest.xml
Normal file
20
AndroidManifest.xml
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
package="com.froop.app.kegs"
|
||||||
|
android:installLocation="auto">
|
||||||
|
|
||||||
|
<uses-sdk android:minSdkVersion="8" android:targetSdkVersion="16" />
|
||||||
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
||||||
|
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
||||||
|
|
||||||
|
<application android:label="KEGS" android:hardwareAccelerated="true">
|
||||||
|
<activity android:name="KegsMain" android:launchMode="singleInstance" android:configChanges="orientation|keyboardHidden|screenSize" android:windowSoftInputMode="stateAlwaysVisible|adjustPan">
|
||||||
|
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity>
|
||||||
|
</application>
|
||||||
|
</manifest>
|
23
README.md
Normal file
23
README.md
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
Port of Kent Dickey's KEGS Apple IIgs Emulator to Android.
|
||||||
|
|
||||||
|
Work in progress! Currently optimized for tablet. Screen may be cropped on phones.
|
||||||
|
|
||||||
|
Config file and disk images in /mnt/sdcard/KEGS/
|
||||||
|
To attach disk images, use the F4 button to enter KEGS configuration.
|
||||||
|
|
||||||
|
The touch screen acts as a big trackpad for the mouse. To click and drag,
|
||||||
|
for example to pull down GS/OS menus, you need to Long Press first)
|
||||||
|
|
||||||
|
What's not ready yet:
|
||||||
|
- No audio.
|
||||||
|
- No joystick.
|
||||||
|
- Screen scaling to fit your device.
|
||||||
|
- Native UI configuration options.
|
||||||
|
|
||||||
|
Source code:
|
||||||
|
https://github.com/jamessanford/kegs/
|
||||||
|
|
||||||
|
To build from source:
|
||||||
|
android update project -p . -s
|
||||||
|
(cd jni && ndk-build)
|
||||||
|
ant debug install
|
53
res/layout/main.xml
Normal file
53
res/layout/main.xml
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:id="@+id/mainview"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<com.froop.app.kegs.KegsView
|
||||||
|
android:id="@+id/kegsview"
|
||||||
|
android:layout_width="704px"
|
||||||
|
android:layout_height="462px"/>
|
||||||
|
|
||||||
|
<LinearLayout orientation="horiontal" android:layout_width="wrap_content" android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<Button android:id="@+id/key_escape" android:text="Esc" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="left|bottom" />
|
||||||
|
|
||||||
|
<Button android:id="@+id/key_return" android:text="Return" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="left|bottom" />
|
||||||
|
|
||||||
|
<Button android:id="@+id/key_tab" android:text="Tab" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="left|bottom" />
|
||||||
|
|
||||||
|
<Button android:id="@+id/key_f4" android:text="F4" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="left|bottom" />
|
||||||
|
|
||||||
|
<ToggleButton android:id="@+id/key_control"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="left|bottom"
|
||||||
|
android:textOn="Ctrl"
|
||||||
|
android:textOff="Ctrl" />
|
||||||
|
|
||||||
|
<ToggleButton android:id="@+id/key_open_apple"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="left|bottom"
|
||||||
|
android:textOn="Cmd"
|
||||||
|
android:textOff="Cmd" />
|
||||||
|
|
||||||
|
<ToggleButton android:id="@+id/key_closed_apple"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="left|bottom"
|
||||||
|
android:textOn="Opt"
|
||||||
|
android:textOff="Opt" />
|
||||||
|
|
||||||
|
<Button android:id="@+id/key_left" android:text="Left" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="left|bottom" />
|
||||||
|
|
||||||
|
<Button android:id="@+id/key_right" android:text="Right" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="left|bottom" />
|
||||||
|
|
||||||
|
<Button android:id="@+id/key_up" android:text="Up" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="left|bottom" />
|
||||||
|
|
||||||
|
<Button android:id="@+id/key_down" android:text="Down" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="left|bottom" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</FrameLayout>
|
50
src/com/froop/app/kegs/Config.java
Normal file
50
src/com/froop/app/kegs/Config.java
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
package com.froop.app.kegs;
|
||||||
|
|
||||||
|
import android.os.Environment;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
|
||||||
|
// Ick.
|
||||||
|
|
||||||
|
class Config {
|
||||||
|
public static final File mPath = Environment.getExternalStorageDirectory();
|
||||||
|
public static final String mConfigFile = "KEGS/config.kegs";
|
||||||
|
public static final String mROM03 = "KEGS/ROM.03";
|
||||||
|
public static final String mROM01 = "KEGS/ROM.01";
|
||||||
|
|
||||||
|
static public String whichRomFile() {
|
||||||
|
File rom = new File(mPath, mROM03);
|
||||||
|
if (rom != null && rom.exists()) {
|
||||||
|
return rom.getPath();
|
||||||
|
}
|
||||||
|
|
||||||
|
rom = new File(mPath, mROM01);
|
||||||
|
if (rom != null && rom.exists()) {
|
||||||
|
return rom.getPath();
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void checkConfig(String rom_path) {
|
||||||
|
File config = new File(mPath, mConfigFile);
|
||||||
|
if (config == null || !config.exists()) {
|
||||||
|
createConfig(rom_path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void createConfig(String rom_path) {
|
||||||
|
try {
|
||||||
|
final byte[] data_bytes = String.format(
|
||||||
|
"g_cfg_rom_path = %s\ng_limit_speed = 3\n", rom_path).getBytes();
|
||||||
|
File config = new File(mPath, mConfigFile);
|
||||||
|
config.createNewFile();
|
||||||
|
FileOutputStream out = new FileOutputStream(config);
|
||||||
|
out.write(data_bytes, 0, data_bytes.length);
|
||||||
|
out.close();
|
||||||
|
} catch (java.io.IOException e) {
|
||||||
|
// kegs will fail and exit with no config
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
110
src/com/froop/app/kegs/DownloadHelper.java
Normal file
110
src/com/froop/app/kegs/DownloadHelper.java
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
package com.froop.app.kegs;
|
||||||
|
|
||||||
|
import android.util.Log;
|
||||||
|
import java.io.BufferedInputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.net.MalformedURLException;
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
|
import java.net.URL;
|
||||||
|
|
||||||
|
// Ick. Look elsewhere.
|
||||||
|
|
||||||
|
public class DownloadHelper {
|
||||||
|
private URL mURL;
|
||||||
|
private HttpURLConnection mConnection;
|
||||||
|
private InputStream mStream;
|
||||||
|
|
||||||
|
private boolean openInputStream() {
|
||||||
|
try {
|
||||||
|
mConnection = (HttpURLConnection)mURL.openConnection();
|
||||||
|
mConnection.connect();
|
||||||
|
if (mConnection.getResponseCode() != HttpURLConnection.HTTP_OK) {
|
||||||
|
mConnection.disconnect();
|
||||||
|
Log.e("kegs", "HTTP ERROR " + mConnection.getResponseCode());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.e("kegs", "HTTP I/O EXCEPTION");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
mStream = new BufferedInputStream(mConnection.getInputStream());
|
||||||
|
} catch (IOException e) {
|
||||||
|
mConnection.disconnect();
|
||||||
|
Log.e("kegs", "INPUTSTREAM I/O EXCEPTION");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean setURL(String url_string) {
|
||||||
|
try {
|
||||||
|
mURL = new URL(url_string);
|
||||||
|
} catch (MalformedURLException e) {
|
||||||
|
Log.e("kegs", "MALFORMED URL");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Should be valid to call if open() works.
|
||||||
|
public void close() {
|
||||||
|
mConnection.disconnect();
|
||||||
|
mStream = null;
|
||||||
|
mConnection = null;
|
||||||
|
mURL = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean open(String url_string) {
|
||||||
|
if (!setURL(url_string)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!openInputStream()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean save(String url_string, String local_file) {
|
||||||
|
final File final_file = new File(local_file);
|
||||||
|
final File dir = new File(final_file.getParent());
|
||||||
|
dir.mkdirs();
|
||||||
|
|
||||||
|
final File output_file = new File(dir, "tmp");
|
||||||
|
output_file.delete(); // in case an earlier attempt failed
|
||||||
|
FileOutputStream out;
|
||||||
|
try {
|
||||||
|
output_file.createNewFile();
|
||||||
|
out = new FileOutputStream(output_file);
|
||||||
|
} catch (java.io.IOException e) {
|
||||||
|
Log.e("kegs", "unable to create " + local_file);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!open(url_string)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
byte buf[] = new byte[4096];
|
||||||
|
try {
|
||||||
|
do {
|
||||||
|
int numread = mStream.read(buf);
|
||||||
|
if (numread <= 0) {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
out.write(buf, 0, numread);
|
||||||
|
}
|
||||||
|
} while (true);
|
||||||
|
out.close();
|
||||||
|
close();
|
||||||
|
} catch (java.io.IOException e) {
|
||||||
|
Log.e("kegs", "error while downloading " + url_string);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return output_file.renameTo(final_file);
|
||||||
|
}
|
||||||
|
}
|
136
src/com/froop/app/kegs/KegsKeyboard.java
Normal file
136
src/com/froop/app/kegs/KegsKeyboard.java
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
package com.froop.app.kegs;
|
||||||
|
|
||||||
|
import android.util.Log;
|
||||||
|
import android.view.KeyCharacterMap;
|
||||||
|
import android.view.KeyEvent;
|
||||||
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
|
|
||||||
|
class KegsKeyboard {
|
||||||
|
public final static int KEY_ESCAPE = 0x35;
|
||||||
|
public final static int KEY_RETURN = 0x24;
|
||||||
|
public final static int KEY_BACKSPACE = 0x33; // 0x75 == delete
|
||||||
|
public final static int KEY_TAB = 0x30;
|
||||||
|
public final static int KEY_SPACE = 0x31;
|
||||||
|
public final static int KEY_F4 = 0x76;
|
||||||
|
public final static int KEY_LEFT = 0x3b;
|
||||||
|
public final static int KEY_RIGHT = 0x3c;
|
||||||
|
public final static int KEY_UP = 0x3e;
|
||||||
|
public final static int KEY_DOWN = 0x3d;
|
||||||
|
public final static int KEY_SHIFT = 0x38;
|
||||||
|
public final static int KEY_RESET = 0x7f;
|
||||||
|
|
||||||
|
// These keys can be set to stick down by calling keyDownSticky()
|
||||||
|
// They will release on a normal keypress.
|
||||||
|
// To indicate release on the GUI, get notified via setOnStickyReset()
|
||||||
|
public final static int KEY_CONTROL = 0x36;
|
||||||
|
public final static int KEY_OPEN_APPLE = 0x37;
|
||||||
|
public final static int KEY_CLOSED_APPLE = 0x3a;
|
||||||
|
|
||||||
|
private int mSticky = 0; // Bitmask for sticky keys.
|
||||||
|
private final static int STICKY_CONTROL = 1;
|
||||||
|
private final static int STICKY_OPEN_APPLE = 2;
|
||||||
|
private final static int STICKY_CLOSED_APPLE = 4;
|
||||||
|
|
||||||
|
interface StickyReset {
|
||||||
|
void onStickyReset();
|
||||||
|
}
|
||||||
|
private StickyReset mNotify;
|
||||||
|
|
||||||
|
// NOTE: Using event.getDeviceId() at runtime isn't working.
|
||||||
|
protected KeyCharacterMap keymap = KeyCharacterMap.load(KeyCharacterMap.BUILT_IN_KEYBOARD);
|
||||||
|
|
||||||
|
private ConcurrentLinkedQueue mEventQueue;
|
||||||
|
|
||||||
|
public KegsKeyboard(ConcurrentLinkedQueue q) {
|
||||||
|
mEventQueue = q;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOnStickyReset(StickyReset notify) {
|
||||||
|
mNotify = notify;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle 'space' through to ~.
|
||||||
|
public boolean handleAsciiKey(int key_id) {
|
||||||
|
if (key_id < 0x20 || key_id > 0x7e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
key_id -= 0x20;
|
||||||
|
final KeyTable.A2Key a2key = KeyTable.ascii.get(key_id);
|
||||||
|
if (a2key.use_shift) {
|
||||||
|
mEventQueue.add(new KegsView.KeyKegsEvent(KEY_SHIFT, false));
|
||||||
|
keyDownUp(a2key.keycode);
|
||||||
|
mEventQueue.add(new KegsView.KeyKegsEvent(KEY_SHIFT, true));
|
||||||
|
} else {
|
||||||
|
keyDownUp(a2key.keycode);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean keyEvent(KeyEvent event) {
|
||||||
|
if (event.getAction() == KeyEvent.ACTION_DOWN) {
|
||||||
|
int keyCode = event.getKeyCode();
|
||||||
|
if (keyCode == KeyEvent.KEYCODE_ENTER) {
|
||||||
|
keyDownUp(KEY_RETURN);
|
||||||
|
return true;
|
||||||
|
} else if (keyCode == KeyEvent.KEYCODE_SPACE) {
|
||||||
|
keyDownUp(KEY_SPACE);
|
||||||
|
return true;
|
||||||
|
} else if (keyCode == KeyEvent.KEYCODE_TAB) {
|
||||||
|
keyDownUp(KEY_TAB);
|
||||||
|
return true;
|
||||||
|
} else if (keyCode == KeyEvent.KEYCODE_DEL) {
|
||||||
|
keyDownUp(KEY_BACKSPACE);
|
||||||
|
return true;
|
||||||
|
} else if (keymap == null) {
|
||||||
|
return false;
|
||||||
|
} else if (keymap.isPrintingKey(keyCode)) {
|
||||||
|
int key_id = keymap.get(keyCode, event.getMetaState());
|
||||||
|
return handleAsciiKey(key_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void resetStickyKeys() {
|
||||||
|
if (mSticky != 0) {
|
||||||
|
if ((mSticky & STICKY_CONTROL) != 0) {
|
||||||
|
mEventQueue.add(new KegsView.KeyKegsEvent(KEY_CONTROL, true));
|
||||||
|
}
|
||||||
|
if ((mSticky & STICKY_OPEN_APPLE) != 0) {
|
||||||
|
mEventQueue.add(new KegsView.KeyKegsEvent(KEY_OPEN_APPLE, true));
|
||||||
|
}
|
||||||
|
if ((mSticky & STICKY_CLOSED_APPLE) != 0) {
|
||||||
|
mEventQueue.add(new KegsView.KeyKegsEvent(KEY_CLOSED_APPLE, true));
|
||||||
|
}
|
||||||
|
mSticky = 0;
|
||||||
|
if (mNotify != null) {
|
||||||
|
mNotify.onStickyReset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void keyDownSticky(int key_id, boolean key_up) {
|
||||||
|
int mask = 0;
|
||||||
|
if (key_id == KEY_CONTROL) {
|
||||||
|
mEventQueue.add(new KegsView.KeyKegsEvent(KEY_CONTROL, key_up));
|
||||||
|
mask = STICKY_CONTROL;
|
||||||
|
} else if (key_id == KEY_OPEN_APPLE) {
|
||||||
|
mEventQueue.add(new KegsView.KeyKegsEvent(KEY_OPEN_APPLE, key_up));
|
||||||
|
mask = STICKY_OPEN_APPLE;
|
||||||
|
} else if (key_id == KEY_CLOSED_APPLE) {
|
||||||
|
mEventQueue.add(new KegsView.KeyKegsEvent(KEY_CLOSED_APPLE, key_up));
|
||||||
|
mask = STICKY_CLOSED_APPLE;
|
||||||
|
}
|
||||||
|
if (key_up) {
|
||||||
|
mSticky &= ~mask;
|
||||||
|
} else {
|
||||||
|
mSticky |= mask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void keyDownUp(int key_id) {
|
||||||
|
mEventQueue.add(new KegsView.KeyKegsEvent(key_id, false)); // key down
|
||||||
|
mEventQueue.add(new KegsView.KeyKegsEvent(key_id, true)); // key up
|
||||||
|
resetStickyKeys();
|
||||||
|
}
|
||||||
|
}
|
220
src/com/froop/app/kegs/KegsMain.java
Normal file
220
src/com/froop/app/kegs/KegsMain.java
Normal file
@ -0,0 +1,220 @@
|
|||||||
|
package com.froop.app.kegs;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.app.AlertDialog;
|
||||||
|
import android.app.Dialog;
|
||||||
|
import android.app.DialogFragment;
|
||||||
|
import android.app.ProgressDialog;
|
||||||
|
import android.content.DialogInterface;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.os.AsyncTask;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.view.GestureDetector;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.KeyEvent;
|
||||||
|
import android.view.MotionEvent;
|
||||||
|
import android.view.View.OnTouchListener;
|
||||||
|
import android.widget.Button;
|
||||||
|
import android.widget.ToggleButton;
|
||||||
|
|
||||||
|
public class KegsMain extends Activity implements KegsKeyboard.StickyReset {
|
||||||
|
private static final String FRAGMENT_ROM = "rom";
|
||||||
|
private static final String FRAGMENT_DOWNLOAD = "download";
|
||||||
|
private static final String FRAGMENT_ERROR = "error";
|
||||||
|
|
||||||
|
private KegsView mKegsView;
|
||||||
|
private KegsTouch mKegsTouch;
|
||||||
|
private KegsKeyboard mKegsKeyboard;
|
||||||
|
|
||||||
|
private View.OnClickListener mButtonClick = new View.OnClickListener() {
|
||||||
|
public void onClick(View v) {
|
||||||
|
// Log.e("kegs", "button clicked");
|
||||||
|
int click_id = v.getId();
|
||||||
|
int key_id = -1;
|
||||||
|
boolean sticky = false;
|
||||||
|
if (click_id == R.id.key_escape) {
|
||||||
|
key_id = KegsKeyboard.KEY_ESCAPE;
|
||||||
|
} else if (click_id == R.id.key_return) {
|
||||||
|
key_id = KegsKeyboard.KEY_RETURN;
|
||||||
|
} else if (click_id == R.id.key_f4) {
|
||||||
|
key_id = KegsKeyboard.KEY_F4;
|
||||||
|
} else if (click_id == R.id.key_tab) {
|
||||||
|
key_id = KegsKeyboard.KEY_TAB;
|
||||||
|
} else if (click_id == R.id.key_control) {
|
||||||
|
key_id = KegsKeyboard.KEY_CONTROL;
|
||||||
|
sticky = true;
|
||||||
|
} else if (click_id == R.id.key_open_apple) {
|
||||||
|
key_id = KegsKeyboard.KEY_OPEN_APPLE;
|
||||||
|
sticky = true;
|
||||||
|
} else if (click_id == R.id.key_closed_apple) {
|
||||||
|
key_id = KegsKeyboard.KEY_CLOSED_APPLE;
|
||||||
|
sticky = true;
|
||||||
|
} else if (click_id == R.id.key_left) {
|
||||||
|
key_id = KegsKeyboard.KEY_LEFT;
|
||||||
|
} else if (click_id == R.id.key_right) {
|
||||||
|
key_id = KegsKeyboard.KEY_RIGHT;
|
||||||
|
} else if (click_id == R.id.key_up) {
|
||||||
|
key_id = KegsKeyboard.KEY_UP;
|
||||||
|
} else if (click_id == R.id.key_down) {
|
||||||
|
key_id = KegsKeyboard.KEY_DOWN;
|
||||||
|
} else {
|
||||||
|
Log.e("kegs", "UNKNOWN BUTTON " + click_id + " CLICKED");
|
||||||
|
}
|
||||||
|
if (key_id != -1) {
|
||||||
|
if (sticky) {
|
||||||
|
mKegsKeyboard.keyDownSticky(key_id, !((ToggleButton)v).isChecked());
|
||||||
|
} else {
|
||||||
|
mKegsKeyboard.keyDownUp(key_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public void onStickyReset() {
|
||||||
|
((ToggleButton)findViewById(R.id.key_control)).setChecked(false);
|
||||||
|
((ToggleButton)findViewById(R.id.key_open_apple)).setChecked(false);
|
||||||
|
((ToggleButton)findViewById(R.id.key_closed_apple)).setChecked(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void getRomFile(String romfile) {
|
||||||
|
final DialogFragment download = new DownloadDialogFragment();
|
||||||
|
download.show(getFragmentManager(), FRAGMENT_DOWNLOAD);
|
||||||
|
new DownloadRom().execute(romfile);
|
||||||
|
}
|
||||||
|
|
||||||
|
class DownloadRom extends AsyncTask<String, Void, Boolean> {
|
||||||
|
private String mRomfile;
|
||||||
|
protected Boolean doInBackground(String ... raw_romfile) {
|
||||||
|
mRomfile = raw_romfile[0];
|
||||||
|
return new DownloadHelper().save(
|
||||||
|
"http://jsan.co/" + mRomfile, Config.mPath.getPath() + "/" + mRomfile);
|
||||||
|
}
|
||||||
|
protected void onPostExecute(Boolean success) {
|
||||||
|
final DialogFragment frag = (DialogFragment)getFragmentManager().findFragmentByTag(FRAGMENT_DOWNLOAD);
|
||||||
|
if (frag != null) {
|
||||||
|
frag.dismiss();
|
||||||
|
}
|
||||||
|
if (!success) {
|
||||||
|
if (!isCancelled()) {
|
||||||
|
final DialogFragment dialog = new ErrorDialogFragment();
|
||||||
|
dialog.show(getFragmentManager(), FRAGMENT_ERROR);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Config.checkConfig(mRomfile);
|
||||||
|
mKegsView.setReady(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class DownloadDialogFragment extends DialogFragment {
|
||||||
|
@Override
|
||||||
|
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||||
|
ProgressDialog dialog = new ProgressDialog(getActivity());
|
||||||
|
// TODO: should probably use an XML layout for this.
|
||||||
|
dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
|
||||||
|
dialog.setMessage("Checking for ROM...");
|
||||||
|
dialog.setProgressNumberFormat(null);
|
||||||
|
dialog.setProgressPercentFormat(null);
|
||||||
|
dialog.setIndeterminate(true);
|
||||||
|
dialog.setCancelable(false);
|
||||||
|
dialog.setCanceledOnTouchOutside(false); // lame
|
||||||
|
return dialog;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ErrorDialogFragment extends DialogFragment {
|
||||||
|
@Override
|
||||||
|
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||||
|
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
|
||||||
|
builder.setMessage("Unable to obtain ROM. Find ROM.01 or ROM.03 and put it in the /KEGS/ directory on your SD Card.");
|
||||||
|
// TODO do getActivity().finish() on button clicks
|
||||||
|
return builder.create();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean dispatchKeyEvent(KeyEvent event) {
|
||||||
|
// TODO: verify that this is all OK, and even Return works immediately.
|
||||||
|
return executeKeyEvent(event) || super.dispatchKeyEvent(event);
|
||||||
|
// return super.dispatchKeyEvent(event) || executeKeyEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean executeKeyEvent(KeyEvent event) {
|
||||||
|
return mKegsKeyboard.keyEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Override
|
||||||
|
// public boolean dispatchGenericMotionEvent(MotionEvent event) {
|
||||||
|
// // Joystick! if ((event.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) != 0 && event.getAction() == MotionEvent.ACTION_MOVE) {}
|
||||||
|
// // See also GameControllerInput.java from ApiDemos
|
||||||
|
// return super.dispatchGenericMotionEvent(event);
|
||||||
|
// }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
setContentView(R.layout.main);
|
||||||
|
|
||||||
|
mKegsView = (KegsView)findViewById(R.id.kegsview);
|
||||||
|
|
||||||
|
mKegsTouch = new KegsTouch(mKegsView.getEventQueue());
|
||||||
|
final GestureDetector inputDetect = new GestureDetector(this, mKegsTouch);
|
||||||
|
|
||||||
|
final View mainView = findViewById(R.id.mainview);
|
||||||
|
mainView.setClickable(true);
|
||||||
|
mainView.setLongClickable(true);
|
||||||
|
mainView.setOnTouchListener(new OnTouchListener() {
|
||||||
|
public boolean onTouch(View v, MotionEvent event) {
|
||||||
|
return inputDetect.onTouchEvent(event);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
mKegsKeyboard = new KegsKeyboard(mKegsView.getEventQueue());
|
||||||
|
mKegsKeyboard.setOnStickyReset(this);
|
||||||
|
|
||||||
|
findViewById(R.id.key_escape).setOnClickListener(mButtonClick);
|
||||||
|
findViewById(R.id.key_return).setOnClickListener(mButtonClick);
|
||||||
|
findViewById(R.id.key_f4).setOnClickListener(mButtonClick);
|
||||||
|
findViewById(R.id.key_control).setOnClickListener(mButtonClick);
|
||||||
|
findViewById(R.id.key_open_apple).setOnClickListener(mButtonClick);
|
||||||
|
findViewById(R.id.key_closed_apple).setOnClickListener(mButtonClick);
|
||||||
|
findViewById(R.id.key_left).setOnClickListener(mButtonClick);
|
||||||
|
findViewById(R.id.key_right).setOnClickListener(mButtonClick);
|
||||||
|
findViewById(R.id.key_up).setOnClickListener(mButtonClick);
|
||||||
|
findViewById(R.id.key_down).setOnClickListener(mButtonClick);
|
||||||
|
|
||||||
|
final String romfile = Config.whichRomFile();
|
||||||
|
if (romfile == null) {
|
||||||
|
final DialogFragment chooseRom = new RomDialogFragment();
|
||||||
|
chooseRom.show(getFragmentManager(), FRAGMENT_ROM);
|
||||||
|
} else {
|
||||||
|
Config.checkConfig(romfile);
|
||||||
|
mKegsView.setReady(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPause() {
|
||||||
|
super.onPause();
|
||||||
|
mKegsView.getThread().onPause();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
mKegsView.getThread().onResume();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onDestroy() {
|
||||||
|
super.onDestroy();
|
||||||
|
Log.w("kegs", "onDestroy called, halting");
|
||||||
|
// Force process to exit. We cannot handle another onCreate
|
||||||
|
// once a KegsView has been active. (JNI kegsmain has already run)
|
||||||
|
java.lang.Runtime.getRuntime().halt(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static {
|
||||||
|
System.loadLibrary("kegs");
|
||||||
|
}
|
||||||
|
}
|
67
src/com/froop/app/kegs/KegsTouch.java
Normal file
67
src/com/froop/app/kegs/KegsTouch.java
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
package com.froop.app.kegs;
|
||||||
|
|
||||||
|
import android.util.Log;
|
||||||
|
import android.view.GestureDetector;
|
||||||
|
import android.view.MotionEvent;
|
||||||
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
|
|
||||||
|
class KegsTouch extends GestureDetector.SimpleOnGestureListener {
|
||||||
|
private ConcurrentLinkedQueue mEventQueue;
|
||||||
|
private int mButton1 = 0;
|
||||||
|
|
||||||
|
public KegsTouch(ConcurrentLinkedQueue q) {
|
||||||
|
mEventQueue = q;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onFling(MotionEvent e1, MotionEvent e2,
|
||||||
|
float velocityX, float velocityY) {
|
||||||
|
// move mouse cursor
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onScroll(MotionEvent e1, MotionEvent e2,
|
||||||
|
float distanceX, float distanceY) {
|
||||||
|
int changeX = (int)distanceX * -1;
|
||||||
|
int changeY = (int)distanceY * -1;
|
||||||
|
mEventQueue.add(
|
||||||
|
new KegsView.MouseKegsEvent(changeX, changeY, mButton1, 1));
|
||||||
|
// if (mButton1 == 1 && e2.getAction() == MotionEvent.ACTION_UP) {
|
||||||
|
// mButton1 = 0;
|
||||||
|
// mEventQueue.add(new KegsView.MouseKegsEvent(0, 0, mButton1, 1));
|
||||||
|
// }
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLongPress(MotionEvent e) {
|
||||||
|
// press mouse button down
|
||||||
|
// Log.e("kegs", "onlongpress");
|
||||||
|
mButton1 = 1;
|
||||||
|
mEventQueue.add(new KegsView.MouseKegsEvent(0, 0, mButton1, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onSingleTapConfirmed(MotionEvent e) {
|
||||||
|
// press mouse button down, then up
|
||||||
|
mButton1 = 1;
|
||||||
|
mEventQueue.add(new KegsView.MouseKegsEvent(0, 0, mButton1, 1));
|
||||||
|
mButton1 = 0;
|
||||||
|
mEventQueue.add(new KegsView.MouseKegsEvent(0, 0, mButton1, 1));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onDoubleTap(MotionEvent e) {
|
||||||
|
mButton1 = 1;
|
||||||
|
mEventQueue.add(new KegsView.MouseKegsEvent(0, 0, mButton1, 1));
|
||||||
|
mButton1 = 0;
|
||||||
|
mEventQueue.add(new KegsView.MouseKegsEvent(0, 0, mButton1, 1));
|
||||||
|
mButton1 = 1;
|
||||||
|
mEventQueue.add(new KegsView.MouseKegsEvent(0, 0, mButton1, 1));
|
||||||
|
mButton1 = 0;
|
||||||
|
mEventQueue.add(new KegsView.MouseKegsEvent(0, 0, mButton1, 1));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
218
src/com/froop/app/kegs/KegsView.java
Normal file
218
src/com/froop/app/kegs/KegsView.java
Normal file
@ -0,0 +1,218 @@
|
|||||||
|
package com.froop.app.kegs;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.res.Resources;
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
import android.graphics.BitmapFactory;
|
||||||
|
import android.graphics.Canvas;
|
||||||
|
import android.graphics.Rect;
|
||||||
|
import android.util.AttributeSet;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.view.SurfaceHolder;
|
||||||
|
import android.view.SurfaceView;
|
||||||
|
import android.view.View;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
|
|
||||||
|
class KegsView extends SurfaceView implements SurfaceHolder.Callback {
|
||||||
|
private static final int mA2Width = 640 + 32 + 32; // kegs defcomm.h
|
||||||
|
private static final int mA2Height = 400 + 32 + 30; // kegs defcomm.h
|
||||||
|
|
||||||
|
// Look also at mPauseLock.
|
||||||
|
private boolean mHaveSurface = false;
|
||||||
|
private boolean mPaused = false;
|
||||||
|
private boolean mReady = false;
|
||||||
|
|
||||||
|
static class KegsEvent {}
|
||||||
|
|
||||||
|
static class KeyKegsEvent extends KegsEvent {
|
||||||
|
public KeyKegsEvent(int key_id, boolean up) {
|
||||||
|
this.key_id = key_id;
|
||||||
|
this.up = up;
|
||||||
|
}
|
||||||
|
public int key_id;
|
||||||
|
public boolean up;
|
||||||
|
}
|
||||||
|
|
||||||
|
static class MouseKegsEvent extends KegsEvent {
|
||||||
|
public MouseKegsEvent(int x, int y, int buttons, int buttons_valid) {
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
this.buttons = buttons;
|
||||||
|
this.buttons_valid = buttons_valid;
|
||||||
|
}
|
||||||
|
public int x;
|
||||||
|
public int y;
|
||||||
|
public int buttons;
|
||||||
|
public int buttons_valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ConcurrentLinkedQueue<KegsEvent> mEventQueue = new ConcurrentLinkedQueue<KegsEvent>();
|
||||||
|
|
||||||
|
class KegsThread extends Thread {
|
||||||
|
private Bitmap mBitmap;
|
||||||
|
private Canvas mCanvas;
|
||||||
|
private SurfaceHolder mSurfaceHolder;
|
||||||
|
private Context mContext;
|
||||||
|
private final ReentrantLock mSurfaceLock = new ReentrantLock();
|
||||||
|
private final ReentrantLock mPauseLock = new ReentrantLock();
|
||||||
|
private final Rect mRect = new Rect(0, 0, mA2Width, mA2Height);
|
||||||
|
// private final Rect mDestRect = new Rect(0, 0, 800, 600);
|
||||||
|
|
||||||
|
public KegsThread(SurfaceHolder surfaceHolder, Context context) {
|
||||||
|
mSurfaceHolder = surfaceHolder;
|
||||||
|
mContext = context;
|
||||||
|
|
||||||
|
mBitmap = Bitmap.createBitmap(mA2Width, mA2Height,
|
||||||
|
Bitmap.Config.ARGB_8888);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Called by surfaceCreated also!
|
||||||
|
public void updateScreen() {
|
||||||
|
mSurfaceLock.lock();
|
||||||
|
mCanvas = mSurfaceHolder.lockCanvas(); // Use mRect ?
|
||||||
|
try {
|
||||||
|
if(mCanvas != null) {
|
||||||
|
mCanvas.drawARGB(255, 0, 0, 0);
|
||||||
|
mCanvas.drawBitmap(mBitmap, 0, 0, null);
|
||||||
|
// scaling tests:
|
||||||
|
// mCanvas.drawBitmap(mBitmap, mRect, mDestRect, null);
|
||||||
|
// Doesn't work well, but consider eliminating the border instead, for phones.
|
||||||
|
mSurfaceHolder.unlockCanvasAndPost(mCanvas);
|
||||||
|
mCanvas = null;
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
mSurfaceLock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void checkForPause() {
|
||||||
|
if (mPaused) {
|
||||||
|
mPauseLock.lock();
|
||||||
|
// deadlock here until onResume. Maybe not efficient.
|
||||||
|
mPauseLock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public native void mainLoop(Bitmap b, ConcurrentLinkedQueue q);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
mainLoop(mBitmap, mEventQueue);
|
||||||
|
// For TESTING:
|
||||||
|
// while (true) {
|
||||||
|
// try {
|
||||||
|
// Thread.sleep(100);
|
||||||
|
// } catch (InterruptedException e) {}
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onPause() {
|
||||||
|
if (!mReady) {
|
||||||
|
return; // bail out, we haven't started doing anything yet
|
||||||
|
}
|
||||||
|
if (!mPaused) {
|
||||||
|
mPaused = true;
|
||||||
|
mPauseLock.lock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onResume() {
|
||||||
|
if (!mReady) {
|
||||||
|
return; // bail out, we haven't started doing anything yet
|
||||||
|
}
|
||||||
|
if (mHaveSurface && mPaused) {
|
||||||
|
mPaused = false;
|
||||||
|
mPauseLock.unlock();
|
||||||
|
}
|
||||||
|
// otherwise, wait for the surface...
|
||||||
|
}
|
||||||
|
|
||||||
|
// Has the thread itself actually paused waiting to acquire the lock?
|
||||||
|
public boolean nowPaused() {
|
||||||
|
return mPauseLock.hasQueuedThreads();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSurfaceSize(int width, int height) {
|
||||||
|
// consider.. mSurfaceLock.lock(); update sizes and bitmap; unlock
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private Context mContext;
|
||||||
|
private KegsThread thread;
|
||||||
|
|
||||||
|
public KegsView(Context context, AttributeSet attrs) {
|
||||||
|
super(context, attrs);
|
||||||
|
|
||||||
|
SurfaceHolder holder = getHolder();
|
||||||
|
holder.addCallback(this);
|
||||||
|
|
||||||
|
thread = new KegsThread(holder, context);
|
||||||
|
|
||||||
|
setFocusable(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public KegsThread getThread() {
|
||||||
|
return thread;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConcurrentLinkedQueue getEventQueue() {
|
||||||
|
return mEventQueue;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onWindowFocusChanged(boolean hasWindowFocus) {
|
||||||
|
// TODO: check to see if this is necessary, for example during alarms or phone calls.
|
||||||
|
// if (!hasWindowFocus) {
|
||||||
|
// thread.onPause();
|
||||||
|
// } else {
|
||||||
|
// thread.onResume();
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
public void surfaceChanged(SurfaceHolder holder,
|
||||||
|
int format, int width, int height) {
|
||||||
|
thread.setSurfaceSize(width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
public native String stringFromJNI();
|
||||||
|
|
||||||
|
public void setReady(boolean ready) {
|
||||||
|
if (ready && !mReady && mHaveSurface) {
|
||||||
|
thread.start();
|
||||||
|
}
|
||||||
|
mReady = ready;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void surfaceCreated(SurfaceHolder holder) {
|
||||||
|
mHaveSurface = true;
|
||||||
|
if (!mReady) {
|
||||||
|
return; // bail out, start the thread later
|
||||||
|
}
|
||||||
|
thread.updateScreen();
|
||||||
|
if (mPaused) {
|
||||||
|
thread.onResume();
|
||||||
|
} else {
|
||||||
|
thread.start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void surfaceDestroyed(SurfaceHolder holder) {
|
||||||
|
Log.w("kegs", "surfaceDestroyed");
|
||||||
|
mHaveSurface = false;
|
||||||
|
if (!mReady) {
|
||||||
|
return; // bail out, we never actually started
|
||||||
|
}
|
||||||
|
if (!mPaused) {
|
||||||
|
thread.onPause();
|
||||||
|
}
|
||||||
|
while (!thread.nowPaused()) {
|
||||||
|
// We are waiting for the thread to actually pause itself,
|
||||||
|
// so that it won't be updating the canvas.
|
||||||
|
try {
|
||||||
|
Thread.sleep(18); // 18ms == just over 1/60th of a second
|
||||||
|
} catch (InterruptedException e) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
115
src/com/froop/app/kegs/KeyTable.java
Normal file
115
src/com/froop/app/kegs/KeyTable.java
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
package com.froop.app.kegs;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
class KeyTable {
|
||||||
|
static class A2Key {
|
||||||
|
public A2Key(int keycode, boolean use_shift) {
|
||||||
|
this.keycode = keycode;
|
||||||
|
this.use_shift = use_shift;
|
||||||
|
}
|
||||||
|
public int keycode;
|
||||||
|
public boolean use_shift;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mapping of ASCII 0x20-0x7e inclusive to the ADB keycode.
|
||||||
|
// 0x20 is element 0.
|
||||||
|
static ArrayList<A2Key> ascii = new ArrayList<A2Key>(96);
|
||||||
|
static {
|
||||||
|
ascii.add(new A2Key(0x31, false)); // <space>
|
||||||
|
ascii.add(new A2Key(0x12, true)); // !
|
||||||
|
ascii.add(new A2Key(0x27, true)); // "
|
||||||
|
ascii.add(new A2Key(0x14, true)); // #
|
||||||
|
ascii.add(new A2Key(0x15, true)); // $
|
||||||
|
ascii.add(new A2Key(0x17, true)); // %
|
||||||
|
ascii.add(new A2Key(0x1a, true)); // &
|
||||||
|
ascii.add(new A2Key(0x27, false)); // '
|
||||||
|
ascii.add(new A2Key(0x19, true)); // (
|
||||||
|
ascii.add(new A2Key(0x1d, true)); // )
|
||||||
|
ascii.add(new A2Key(0x1c, true)); // *
|
||||||
|
ascii.add(new A2Key(0x18, true)); // +
|
||||||
|
ascii.add(new A2Key(0x2b, false)); // ,
|
||||||
|
ascii.add(new A2Key(0x1b, false)); // -
|
||||||
|
ascii.add(new A2Key(0x2f, false)); // .
|
||||||
|
ascii.add(new A2Key(0x2c, false)); // /
|
||||||
|
ascii.add(new A2Key(0x1d, false)); // 0
|
||||||
|
ascii.add(new A2Key(0x12, false)); // 1
|
||||||
|
ascii.add(new A2Key(0x13, false)); // 2
|
||||||
|
ascii.add(new A2Key(0x14, false)); // 3
|
||||||
|
ascii.add(new A2Key(0x15, false)); // 4
|
||||||
|
ascii.add(new A2Key(0x17, false)); // 5
|
||||||
|
ascii.add(new A2Key(0x16, false)); // 6
|
||||||
|
ascii.add(new A2Key(0x1a, false)); // 7
|
||||||
|
ascii.add(new A2Key(0x1c, false)); // 8
|
||||||
|
ascii.add(new A2Key(0x19, false)); // 9
|
||||||
|
ascii.add(new A2Key(0x29, true)); // :
|
||||||
|
ascii.add(new A2Key(0x29, false)); // ;
|
||||||
|
ascii.add(new A2Key(0x2b, true)); // <
|
||||||
|
ascii.add(new A2Key(0x18, false)); // =
|
||||||
|
ascii.add(new A2Key(0x2f, true)); // >
|
||||||
|
ascii.add(new A2Key(0x2c, true)); // ?
|
||||||
|
ascii.add(new A2Key(0x13, true)); // @
|
||||||
|
ascii.add(new A2Key(0x00, true)); // A
|
||||||
|
ascii.add(new A2Key(0x0b, true)); // B
|
||||||
|
ascii.add(new A2Key(0x08, true)); // C
|
||||||
|
ascii.add(new A2Key(0x02, true)); // D
|
||||||
|
ascii.add(new A2Key(0x0e, true)); // E
|
||||||
|
ascii.add(new A2Key(0x03, true)); // F
|
||||||
|
ascii.add(new A2Key(0x05, true)); // G
|
||||||
|
ascii.add(new A2Key(0x04, true)); // H
|
||||||
|
ascii.add(new A2Key(0x22, true)); // I
|
||||||
|
ascii.add(new A2Key(0x26, true)); // J
|
||||||
|
ascii.add(new A2Key(0x28, true)); // K
|
||||||
|
ascii.add(new A2Key(0x25, true)); // L
|
||||||
|
ascii.add(new A2Key(0x2e, true)); // M
|
||||||
|
ascii.add(new A2Key(0x2d, true)); // N
|
||||||
|
ascii.add(new A2Key(0x1f, true)); // O
|
||||||
|
ascii.add(new A2Key(0x23, true)); // P
|
||||||
|
ascii.add(new A2Key(0x0c, true)); // Q
|
||||||
|
ascii.add(new A2Key(0x0f, true)); // R
|
||||||
|
ascii.add(new A2Key(0x01, true)); // S
|
||||||
|
ascii.add(new A2Key(0x11, true)); // T
|
||||||
|
ascii.add(new A2Key(0x20, true)); // U
|
||||||
|
ascii.add(new A2Key(0x09, true)); // V
|
||||||
|
ascii.add(new A2Key(0x0d, true)); // W
|
||||||
|
ascii.add(new A2Key(0x07, true)); // X
|
||||||
|
ascii.add(new A2Key(0x10, true)); // Y
|
||||||
|
ascii.add(new A2Key(0x06, true)); // Z
|
||||||
|
ascii.add(new A2Key(0x21, false)); // [
|
||||||
|
ascii.add(new A2Key(0x2a, false)); // \
|
||||||
|
ascii.add(new A2Key(0x1e, false)); // ]
|
||||||
|
ascii.add(new A2Key(0x16, true)); // ^
|
||||||
|
ascii.add(new A2Key(0x1b, true)); // _
|
||||||
|
ascii.add(new A2Key(0x32, false)); // `
|
||||||
|
ascii.add(new A2Key(0x00, false)); // a
|
||||||
|
ascii.add(new A2Key(0x0b, false)); // b
|
||||||
|
ascii.add(new A2Key(0x08, false)); // c
|
||||||
|
ascii.add(new A2Key(0x02, false)); // d
|
||||||
|
ascii.add(new A2Key(0x0e, false)); // e
|
||||||
|
ascii.add(new A2Key(0x03, false)); // f
|
||||||
|
ascii.add(new A2Key(0x05, false)); // g
|
||||||
|
ascii.add(new A2Key(0x04, false)); // h
|
||||||
|
ascii.add(new A2Key(0x22, false)); // i
|
||||||
|
ascii.add(new A2Key(0x26, false)); // j
|
||||||
|
ascii.add(new A2Key(0x28, false)); // k
|
||||||
|
ascii.add(new A2Key(0x25, false)); // l
|
||||||
|
ascii.add(new A2Key(0x2e, false)); // m
|
||||||
|
ascii.add(new A2Key(0x2d, false)); // n
|
||||||
|
ascii.add(new A2Key(0x1f, false)); // o
|
||||||
|
ascii.add(new A2Key(0x23, false)); // p
|
||||||
|
ascii.add(new A2Key(0x0c, false)); // q
|
||||||
|
ascii.add(new A2Key(0x0f, false)); // r
|
||||||
|
ascii.add(new A2Key(0x01, false)); // s
|
||||||
|
ascii.add(new A2Key(0x11, false)); // t
|
||||||
|
ascii.add(new A2Key(0x20, false)); // u
|
||||||
|
ascii.add(new A2Key(0x09, false)); // v
|
||||||
|
ascii.add(new A2Key(0x0d, false)); // w
|
||||||
|
ascii.add(new A2Key(0x07, false)); // x
|
||||||
|
ascii.add(new A2Key(0x10, false)); // y
|
||||||
|
ascii.add(new A2Key(0x06, false)); // z
|
||||||
|
ascii.add(new A2Key(0x21, true)); // {
|
||||||
|
ascii.add(new A2Key(0x2a, true)); // |
|
||||||
|
ascii.add(new A2Key(0x1e, true)); // }
|
||||||
|
ascii.add(new A2Key(0x32, true)); // ~
|
||||||
|
}
|
||||||
|
}
|
36
src/com/froop/app/kegs/RomDialogFragment.java
Normal file
36
src/com/froop/app/kegs/RomDialogFragment.java
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
package com.froop.app.kegs;
|
||||||
|
|
||||||
|
import android.app.AlertDialog;
|
||||||
|
import android.app.Dialog;
|
||||||
|
import android.app.DialogFragment;
|
||||||
|
import android.content.DialogInterface;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
public class RomDialogFragment extends DialogFragment {
|
||||||
|
@Override
|
||||||
|
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||||
|
final CharSequence[] items = {"I don't own a GS",
|
||||||
|
"I have a ROM 01",
|
||||||
|
"I have a ROM 03"};
|
||||||
|
|
||||||
|
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
|
||||||
|
builder.setTitle("Checking for ROM");
|
||||||
|
builder.setSingleChoiceItems(items, -1,
|
||||||
|
new DialogInterface.OnClickListener() {
|
||||||
|
public void onClick(DialogInterface dialog, int item) {
|
||||||
|
dismiss();
|
||||||
|
if (item == 0) {
|
||||||
|
((KegsMain)getActivity()).finish();
|
||||||
|
} else if (item == 1) {
|
||||||
|
((KegsMain)getActivity()).getRomFile(Config.mROM01);
|
||||||
|
} else if (item == 2) {
|
||||||
|
((KegsMain)getActivity()).getRomFile(Config.mROM03);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
final AlertDialog dialog = builder.create();
|
||||||
|
dialog.setCanceledOnTouchOutside(false); // lame
|
||||||
|
return dialog;
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user