378 lines
13 KiB
Java
378 lines
13 KiB
Java
package com.fteqw;
|
|
import android.view.inputmethod.InputMethodManager;
|
|
import android.view.KeyEvent;
|
|
import android.view.MotionEvent;
|
|
import android.view.InputDevice;
|
|
import android.view.WindowManager;
|
|
|
|
public class FTENativeActivity extends android.app.NativeActivity
|
|
{
|
|
private static native void keypress(int devid, boolean down, int androidkey, int unicode);
|
|
private static native void mousepress(int devid, int buttonbits);
|
|
private static native void motion(int devid, int action, float x, float y, float z, float size);
|
|
private static native boolean wantrelative();
|
|
private static native void axis(int devid, int axisid, float value);
|
|
// private static native void oncreate(String basedir, byte[] savedstate);
|
|
static
|
|
{
|
|
System.loadLibrary("ftedroid");
|
|
}
|
|
|
|
//called by C code on errors / quitting.
|
|
public void showMessageAndQuit(String errormessage)
|
|
{
|
|
final android.app.Activity act = this;
|
|
final String errormsg = errormessage;
|
|
if (errormsg.equals(""))
|
|
{ //just quit
|
|
finish();
|
|
System.exit(0);
|
|
}
|
|
else runOnUiThread(new Runnable()
|
|
{ //show an error message, then quit.
|
|
public void run()
|
|
{
|
|
// act.getView().setVisibility(android.view.View.GONE);
|
|
android.app.AlertDialog ad = new android.app.AlertDialog.Builder(act).create();
|
|
ad.setTitle("Fatal Error");
|
|
ad.setMessage(errormsg);
|
|
ad.setCancelable(false);
|
|
ad.setButton("Ok", new android.content.DialogInterface.OnClickListener()
|
|
{
|
|
public void onClick(android.content.DialogInterface dialog, int which)
|
|
{
|
|
finish();
|
|
System.exit(0);
|
|
}
|
|
});
|
|
ad.show();
|
|
}
|
|
});
|
|
}
|
|
public void updateScreenKeepOn(final boolean keepon)
|
|
{
|
|
final android.app.Activity act = this;
|
|
runOnUiThread(new Runnable()
|
|
{
|
|
public void run()
|
|
{
|
|
if (keepon)
|
|
act.getWindow().setFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON, WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
|
|
else
|
|
act.getWindow().setFlags(0, WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
|
|
}
|
|
});
|
|
}
|
|
|
|
|
|
//called by C code to set orientation.
|
|
public void updateOrientation(String orientation)
|
|
{
|
|
final String ors = orientation;
|
|
runOnUiThread(new Runnable()
|
|
{
|
|
public void run()
|
|
{
|
|
int ori = android.content.pm.ActivityInfo.SCREEN_ORIENTATION_SENSOR;
|
|
if (ors.equalsIgnoreCase("unspecified"))
|
|
ori = android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
|
|
else if (ors.equalsIgnoreCase("landscape"))
|
|
ori = android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
|
|
else if (ors.equalsIgnoreCase("portrait"))
|
|
ori = android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
|
|
else if (ors.equalsIgnoreCase("user"))
|
|
ori = android.content.pm.ActivityInfo.SCREEN_ORIENTATION_USER;
|
|
else if (ors.equalsIgnoreCase("behind"))
|
|
ori = android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
|
|
else if (ors.equalsIgnoreCase("sensor"))
|
|
ori = android.content.pm.ActivityInfo.SCREEN_ORIENTATION_SENSOR;
|
|
else if (ors.equalsIgnoreCase("nosensor"))
|
|
ori = android.content.pm.ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
|
|
//the following are api level 9+
|
|
else if (ors.equalsIgnoreCase("sensorlandscape"))
|
|
ori = 6;//android.content.pm.ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE;
|
|
else if (ors.equalsIgnoreCase("sensorportrait"))
|
|
ori = 7;//android.content.pm.ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT;
|
|
else if (ors.equalsIgnoreCase("reverselandscape"))
|
|
ori = 8;//android.content.pm.ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
|
|
else if (ors.equalsIgnoreCase("reverseportrait"))
|
|
ori = 9;//android.content.pm.ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT;
|
|
else if (ors.equalsIgnoreCase("fullsensor"))
|
|
ori = 10;//android.content.pm.ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR;
|
|
//and the default, because specifying it again is always useless.
|
|
else
|
|
ori = android.content.pm.ActivityInfo.SCREEN_ORIENTATION_SENSOR;
|
|
android.util.Log.i("FTEDroid", "Orientation changed to " + ori + " (" + ors + ").");
|
|
setRequestedOrientation(ori);
|
|
}
|
|
});
|
|
};
|
|
|
|
|
|
//keyboard stuff, called from C.
|
|
public void showKeyboard(int softkeyflags)
|
|
{ //needed because the ndk's ANativeActivity_showSoftInput is defective
|
|
final android.app.Activity act = this;
|
|
final int flags = softkeyflags;
|
|
runOnUiThread(new Runnable()
|
|
{
|
|
public void run()
|
|
{
|
|
if (flags != 0)
|
|
{
|
|
InputMethodManager imm = (InputMethodManager)getSystemService(android.content.Context.INPUT_METHOD_SERVICE);
|
|
imm.showSoftInput(act.getWindow().getDecorView(), InputMethodManager.SHOW_FORCED);
|
|
}
|
|
else
|
|
{
|
|
InputMethodManager imm = (InputMethodManager)getSystemService(android.content.Context.INPUT_METHOD_SERVICE);
|
|
imm.hideSoftInputFromWindow(act.getWindow().getDecorView().getWindowToken(), 0);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
@Override
|
|
protected void onCreate(android.os.Bundle savedInstanceState)
|
|
{
|
|
/* getWindow().takeSurface(this);
|
|
getWindow().setFormat(PixelFormat.RGB_565);
|
|
getWindow().setSoftInputMode(
|
|
WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED
|
|
| WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
|
|
mNativeContentView = new NativeContentView(this);
|
|
mNativeContentView.mActivity = this;
|
|
setContentView(mNativeContentView);
|
|
mNativeContentView.requestFocus();
|
|
mNativeContentView.getViewTreeObserver().addOnGlobalLayoutListener(this);
|
|
|
|
byte[] nativeSavedState = savedInstanceState != null
|
|
? savedInstanceState.getByteArray(KEY_NATIVE_SAVED_STATE) : null;
|
|
mNativeHandle = oncreate(
|
|
getAbsolutePath(getFilesDir()), getAbsolutePath(getObbDir()),
|
|
getAbsolutePath(getExternalFilesDir(null)),
|
|
Build.VERSION.SDK_INT, getAssets(), nativeSavedState);
|
|
*/
|
|
// if (Build.VERSION.SDK_INT >= 19)
|
|
// {
|
|
// int flags = 0;
|
|
// flags |= 4096/*SYSTEM_UI_FLAG_IMMERSIVE_STICKY, api 19*/;
|
|
// flags |= 4/*SYSTEM_UI_FLAG_FULLSCREEN, api 16*/;
|
|
// flags |= 2/*SYSTEM_UI_FLAG_HIDE_NAVIGATION, api 14*/;
|
|
// mNativeContentView.setSystemUiVisibility(flags); /*api 11*/
|
|
// }
|
|
|
|
super.onCreate(savedInstanceState);
|
|
//Needed because the InputQueue stuff blocks dispatchKeyEvent
|
|
getWindow().takeInputQueue(null);
|
|
}
|
|
@Override
|
|
public boolean dispatchKeyEvent(KeyEvent event)
|
|
{ //needed because AKeyEvent_getUnicode is missing completely.
|
|
int act = event.getAction();
|
|
if (act == KeyEvent.ACTION_DOWN)
|
|
{
|
|
int metastate = event.getMetaState();
|
|
int unichar = event.getUnicodeChar(metastate);
|
|
if (unichar == 0)
|
|
unichar = event.getUnicodeChar();
|
|
if (unichar == 0)
|
|
unichar = event.getDisplayLabel();
|
|
|
|
keypress(event.getDeviceId(), true, event.getKeyCode(), unichar);
|
|
return true;
|
|
}
|
|
else if (act == KeyEvent.ACTION_UP)
|
|
{
|
|
keypress(event.getDeviceId(), false, event.getKeyCode(), 0);
|
|
return true;
|
|
}
|
|
else
|
|
android.util.Log.i("FTEDroid", "other type of event");
|
|
//ignore ACTION_MULTIPLE or whatever it is, apparently its deprecated anyway.
|
|
|
|
return super.dispatchKeyEvent(event);
|
|
}
|
|
|
|
private static boolean canrelative;
|
|
private static int AXIS_RELATIVE_X;//MotionEvent 24
|
|
private static int AXIS_RELATIVE_Y;//MotionEvent 24
|
|
private static java.lang.reflect.Method MotionEvent_getAxisValueP; //MotionEvent 12
|
|
private static int SOURCE_MOUSE; //InputDevice
|
|
private static boolean canbuttons;
|
|
private static java.lang.reflect.Method MotionEvent_getButtonState; //MotionEvent 14
|
|
|
|
private static boolean canjoystick;
|
|
private static java.lang.reflect.Method MotionEvent_getAxisValueJ;
|
|
private static java.lang.reflect.Method InputDevice_getMotionRange;
|
|
private static int SOURCE_JOYSTICK; //InputDevice
|
|
private static int AXIS_X;
|
|
private static int AXIS_Y;
|
|
private static int AXIS_LTRIGGER;
|
|
private static int AXIS_Z;
|
|
private static int AXIS_RZ;
|
|
private static int AXIS_RTRIGGER;
|
|
static
|
|
{
|
|
//if (android.os.Build.VERSION.SDK_INT >= 12)
|
|
try
|
|
{
|
|
MotionEvent_getAxisValueP = MotionEvent.class.getMethod("getAxisValue", int.class, int.class); //api12
|
|
java.lang.reflect.Field relX = MotionEvent.class.getField("AXIS_RELATIVE_X"); //api24ish
|
|
java.lang.reflect.Field relY = MotionEvent.class.getField("AXIS_RELATIVE_Y"); //api24ish
|
|
AXIS_RELATIVE_X = (Integer)relX.get(null);
|
|
AXIS_RELATIVE_Y = (Integer)relY.get(null);
|
|
SOURCE_MOUSE = (Integer)InputDevice.class.getField("SOURCE_MOUSE").get(null);
|
|
canrelative = true; //yay, no exceptions.
|
|
android.util.Log.i("FTEDroid", "relative mouse supported");
|
|
|
|
MotionEvent_getButtonState = MotionEvent.class.getMethod("getButtonState");
|
|
canbuttons = true;
|
|
android.util.Log.i("FTEDroid", "mouse buttons supported");
|
|
} catch(Exception e) {
|
|
canrelative = false;
|
|
android.util.Log.i("FTEDroid", "relative mouse not supported");
|
|
}
|
|
try
|
|
{
|
|
MotionEvent_getAxisValueJ = MotionEvent.class.getMethod("getAxisValue", int.class); //api12
|
|
InputDevice_getMotionRange = InputDevice.class.getMethod("getMotionRange", int.class); //api12
|
|
AXIS_X = (Integer)MotionEvent.class.getField("AXIS_X").get(null);
|
|
AXIS_Y = (Integer)MotionEvent.class.getField("AXIS_Y").get(null);
|
|
AXIS_LTRIGGER = (Integer)MotionEvent.class.getField("AXIS_LTRIGGER").get(null);
|
|
AXIS_Z = (Integer)MotionEvent.class.getField("AXIS_Z").get(null);
|
|
AXIS_RZ = (Integer)MotionEvent.class.getField("AXIS_RZ").get(null);
|
|
AXIS_RTRIGGER = (Integer)MotionEvent.class.getField("AXIS_RTRIGGER").get(null);
|
|
SOURCE_JOYSTICK = (Integer)InputDevice.class.getField("SOURCE_JOYSTICK").get(null);
|
|
canjoystick = true;
|
|
android.util.Log.i("FTEDroid", "gamepad supported");
|
|
} catch(Exception e) {
|
|
canjoystick = false;
|
|
android.util.Log.i("FTEDroid", "gamepad not supported");
|
|
}
|
|
}
|
|
private static void handleJoystickAxis(MotionEvent event, InputDevice dev, int aaxis, int qaxis)
|
|
{
|
|
try
|
|
{
|
|
final InputDevice.MotionRange range = (InputDevice.MotionRange)InputDevice_getMotionRange.invoke(dev, aaxis, event.getSource());
|
|
if (range != null)
|
|
{
|
|
final float flat = range.getFlat();
|
|
float v = (Float)MotionEvent_getAxisValueJ.invoke(event, aaxis, 0);
|
|
if (Math.abs(v) < flat)
|
|
v = 0; //read as 0 if its within the deadzone.
|
|
axis(event.getDeviceId(), qaxis, v);
|
|
}
|
|
}
|
|
catch(Exception e)
|
|
{
|
|
}
|
|
}
|
|
private boolean motionEvent(MotionEvent event)
|
|
{
|
|
int id;
|
|
float x, y, size;
|
|
final int act = event.getAction();
|
|
|
|
//handle gamepad axis
|
|
if ((event.getSource() & SOURCE_JOYSTICK)!=0 && event.getAction() == MotionEvent.ACTION_MOVE)
|
|
{
|
|
InputDevice dev = event.getDevice();
|
|
handleJoystickAxis(event, dev, AXIS_X, 0);
|
|
handleJoystickAxis(event, dev, AXIS_Y, 1);
|
|
handleJoystickAxis(event, dev, AXIS_LTRIGGER, 2);
|
|
|
|
handleJoystickAxis(event, dev, AXIS_Z, 3);
|
|
handleJoystickAxis(event, dev, AXIS_RZ, 4);
|
|
handleJoystickAxis(event, dev, AXIS_RTRIGGER, 5);
|
|
|
|
return true;
|
|
}
|
|
|
|
final int pointerCount = event.getPointerCount();
|
|
int i;
|
|
for (i = 0; i < pointerCount; i++)
|
|
{
|
|
if (canrelative && event.getSource() == SOURCE_MOUSE && wantrelative())
|
|
{
|
|
try
|
|
{
|
|
x = (Float)MotionEvent_getAxisValueP.invoke(event, AXIS_RELATIVE_X, i);
|
|
y = (Float)MotionEvent_getAxisValueP.invoke(event, AXIS_RELATIVE_Y, i);
|
|
motion(event.getPointerId(i), 1, x, y, 0, event.getSize(i));
|
|
}
|
|
catch(Exception e)
|
|
{
|
|
android.util.Log.i("FTEDroid", "exception using relative mouse");
|
|
canrelative=false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
motion(event.getPointerId(i), 0, event.getX(i), event.getY(i), 0, event.getSize(i));
|
|
}
|
|
}
|
|
|
|
switch(act & event.ACTION_MASK)
|
|
{
|
|
case MotionEvent.ACTION_DOWN:
|
|
case MotionEvent.ACTION_POINTER_DOWN:
|
|
id = ((act&event.ACTION_POINTER_ID_MASK) >> event.ACTION_POINTER_ID_SHIFT);
|
|
x = event.getX(id);
|
|
y = event.getY(id);
|
|
size = event.getSize(id);
|
|
id = event.getPointerId(id);
|
|
if (canbuttons)
|
|
{
|
|
try {mousepress(id, (Integer)MotionEvent_getButtonState.invoke(event));}
|
|
catch(Exception e){}
|
|
}
|
|
else
|
|
motion(id, 2, x, y, 0, size);
|
|
break;
|
|
case MotionEvent.ACTION_UP:
|
|
case MotionEvent.ACTION_POINTER_UP:
|
|
id = ((act&event.ACTION_POINTER_ID_MASK) >> event.ACTION_POINTER_ID_SHIFT);
|
|
x = event.getX(id);
|
|
y = event.getY(id);
|
|
size = event.getSize(id);
|
|
id = event.getPointerId(id);
|
|
if (canbuttons)
|
|
{
|
|
try {mousepress(id, (Integer)MotionEvent_getButtonState.invoke(event));}
|
|
catch(Exception e){}
|
|
}
|
|
else
|
|
motion(id, 3, x, y, 0, size);
|
|
break;
|
|
case MotionEvent.ACTION_MOVE:
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public boolean dispatchTouchEvent(MotionEvent event)
|
|
{ //works when mouse is pressed...
|
|
return motionEvent(event);
|
|
}
|
|
// @Override
|
|
public boolean dispatchGenericMotionEvent(MotionEvent event)
|
|
{ //works even when mouse is not pressed
|
|
return motionEvent(event);
|
|
}
|
|
|
|
|
|
//launching stuff
|
|
/*private static native int unicodeKeyPress(int unicode);
|
|
@Override
|
|
void onNewIntent(Intent intent)
|
|
{
|
|
super.onNewIntent(intent);
|
|
}*/
|
|
}
|
|
|