|
|
@@ -5,7 +5,9 @@ package org.libsdl.app;
|
|
|
import java.io.File;
|
|
|
import java.util.ArrayList;
|
|
|
import java.util.Arrays;
|
|
|
+import java.util.Collections;
|
|
|
import java.util.Comparator;
|
|
|
+import java.util.List;
|
|
|
|
|
|
import android.app.*;
|
|
|
import android.content.*;
|
|
|
@@ -26,26 +28,25 @@ import android.hardware.*;
|
|
|
SDL Activity
|
|
|
*/
|
|
|
public class SDLActivity extends Activity {
|
|
|
- // Urho3D: adjust log level, no verbose in production code, first check log level for non-trivial message construction
|
|
|
private static final String TAG = "SDL";
|
|
|
|
|
|
// Keep track of the paused state
|
|
|
- public static boolean mIsPaused = false, mIsSurfaceReady = false, mHasFocus = true;
|
|
|
+ public static boolean mIsPaused, mIsSurfaceReady, mHasFocus;
|
|
|
+ public static boolean mExitCalledFromJava;
|
|
|
|
|
|
// Main components
|
|
|
protected static SDLActivity mSingleton;
|
|
|
protected static SDLSurface mSurface;
|
|
|
protected static View mTextEdit;
|
|
|
protected static ViewGroup mLayout;
|
|
|
+ protected static SDLJoystickHandler mJoystickHandler;
|
|
|
|
|
|
// This is what SDL runs in. It invokes SDL_main(), eventually
|
|
|
protected static Thread mSDLThread;
|
|
|
-
|
|
|
+
|
|
|
// Audio
|
|
|
- protected static Thread mAudioThread;
|
|
|
protected static AudioTrack mAudioTrack;
|
|
|
|
|
|
-
|
|
|
// Urho3D: flag to load the .so and a new method load them
|
|
|
private static boolean mIsSharedLibraryLoaded = false;
|
|
|
|
|
|
@@ -55,13 +56,31 @@ public class SDLActivity extends Activity {
|
|
|
}
|
|
|
return true;
|
|
|
}
|
|
|
+
|
|
|
+
|
|
|
+ public static void initialize() {
|
|
|
+ // The static nature of the singleton and Android quirkyness force us to initialize everything here
|
|
|
+ // Otherwise, when exiting the app and returning to it, these variables *keep* their pre exit values
|
|
|
+ mSingleton = null;
|
|
|
+ mSurface = null;
|
|
|
+ mTextEdit = null;
|
|
|
+ mLayout = null;
|
|
|
+ mJoystickHandler = null;
|
|
|
+ mSDLThread = null;
|
|
|
+ mAudioTrack = null;
|
|
|
+ mExitCalledFromJava = false;
|
|
|
+ mIsPaused = false;
|
|
|
+ mIsSurfaceReady = false;
|
|
|
+ mHasFocus = true;
|
|
|
+ }
|
|
|
|
|
|
// Setup
|
|
|
@Override
|
|
|
protected void onCreate(Bundle savedInstanceState) {
|
|
|
- //Log.v("SDL", "onCreate()");
|
|
|
+ Log.v("SDL", "onCreate():" + mSingleton);
|
|
|
super.onCreate(savedInstanceState);
|
|
|
|
|
|
+ SDLActivity.initialize();
|
|
|
// So we can call stuff from static callbacks
|
|
|
mSingleton = this;
|
|
|
|
|
|
@@ -88,6 +107,13 @@ public class SDLActivity extends Activity {
|
|
|
|
|
|
// Set up the surface
|
|
|
mSurface = new SDLSurface(getApplication());
|
|
|
+
|
|
|
+ if(Build.VERSION.SDK_INT >= 12) {
|
|
|
+ mJoystickHandler = new SDLJoystickHandler_API12();
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ mJoystickHandler = new SDLJoystickHandler();
|
|
|
+ }
|
|
|
|
|
|
mLayout = new AbsoluteLayout(this);
|
|
|
mLayout.addView(mSurface);
|
|
|
@@ -131,23 +157,28 @@ public class SDLActivity extends Activity {
|
|
|
|
|
|
@Override
|
|
|
protected void onDestroy() {
|
|
|
- super.onDestroy();
|
|
|
Log.v("SDL", "onDestroy()");
|
|
|
+ // Send a quit message to the application
|
|
|
+ SDLActivity.mExitCalledFromJava = true;
|
|
|
// Urho3D - Send a quit message to the application only when native library has been loaded
|
|
|
if (mIsSharedLibraryLoaded)
|
|
|
SDLActivity.nativeQuit();
|
|
|
|
|
|
// Now wait for the SDL thread to quit
|
|
|
- if (mSDLThread != null) {
|
|
|
+ if (SDLActivity.mSDLThread != null) {
|
|
|
try {
|
|
|
- mSDLThread.join();
|
|
|
+ SDLActivity.mSDLThread.join();
|
|
|
} catch(Exception e) {
|
|
|
Log.v("SDL", "Problem stopping thread: " + e);
|
|
|
}
|
|
|
- mSDLThread = null;
|
|
|
+ SDLActivity.mSDLThread = null;
|
|
|
|
|
|
//Log.v("SDL", "Finished waiting for SDL thread");
|
|
|
}
|
|
|
+
|
|
|
+ super.onDestroy();
|
|
|
+ // Reset everything in case the user re opens the app
|
|
|
+ SDLActivity.initialize();
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
@@ -190,14 +221,18 @@ public class SDLActivity extends Activity {
|
|
|
mSurface.enableSensor(Sensor.TYPE_ACCELEROMETER, true);
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ /* The native thread has finished */
|
|
|
+ public static void handleNativeExit() {
|
|
|
+ SDLActivity.mSDLThread = null;
|
|
|
+ mSingleton.finish();
|
|
|
+ }
|
|
|
|
|
|
|
|
|
// Messages from the SDLMain thread
|
|
|
static final int COMMAND_CHANGE_TITLE = 1;
|
|
|
static final int COMMAND_UNUSED = 2;
|
|
|
static final int COMMAND_TEXTEDIT_HIDE = 3;
|
|
|
- // Urho3D: added
|
|
|
- static final int COMMAND_FINISH = 4;
|
|
|
|
|
|
protected static final int COMMAND_USER = 0x8000;
|
|
|
|
|
|
@@ -242,11 +277,6 @@ public class SDLActivity extends Activity {
|
|
|
imm.hideSoftInputFromWindow(mTextEdit.getWindowToken(), 0);
|
|
|
}
|
|
|
break;
|
|
|
- // Urho3D: added
|
|
|
- case COMMAND_FINISH:
|
|
|
- if (context instanceof Activity)
|
|
|
- ((Activity) context).finish();
|
|
|
- break;
|
|
|
|
|
|
default:
|
|
|
if ((context instanceof SDLActivity) && !((SDLActivity) context).onUnhandledMessage(msg.arg1, msg.obj)) {
|
|
|
@@ -275,6 +305,12 @@ public class SDLActivity extends Activity {
|
|
|
public static native void nativePause();
|
|
|
public static native void nativeResume();
|
|
|
public static native void onNativeResize(int x, int y, int format);
|
|
|
+ public static native int onNativePadDown(int device_id, int keycode);
|
|
|
+ public static native int onNativePadUp(int device_id, int keycode);
|
|
|
+ public static native void onNativeJoy(int device_id, int axis,
|
|
|
+ float value);
|
|
|
+ public static native void onNativeHat(int device_id, int hat_id,
|
|
|
+ int x, int y);
|
|
|
public static native void onNativeKeyDown(int keycode);
|
|
|
public static native void onNativeKeyUp(int keycode);
|
|
|
public static native void onNativeKeyboardFocusLost();
|
|
|
@@ -285,6 +321,10 @@ public class SDLActivity extends Activity {
|
|
|
public static native void onNativeSurfaceChanged();
|
|
|
public static native void onNativeSurfaceDestroyed();
|
|
|
public static native void nativeFlipBuffers();
|
|
|
+ public static native int nativeAddJoystick(int device_id, String name,
|
|
|
+ int is_accelerometer, int nbuttons,
|
|
|
+ int naxes, int nhats, int nballs);
|
|
|
+ public static native int nativeRemoveJoystick(int device_id);
|
|
|
|
|
|
public static void flipBuffers() {
|
|
|
SDLActivity.nativeFlipBuffers();
|
|
|
@@ -295,12 +335,6 @@ public class SDLActivity extends Activity {
|
|
|
return mSingleton.sendCommand(COMMAND_CHANGE_TITLE, title);
|
|
|
}
|
|
|
|
|
|
- // Urho3D: added function
|
|
|
- public static void finishActivity()
|
|
|
- {
|
|
|
- mSingleton.sendCommand(COMMAND_FINISH, null);
|
|
|
- }
|
|
|
-
|
|
|
public static boolean sendMessage(int command, int param) {
|
|
|
return mSingleton.sendCommand(command, Integer.valueOf(param));
|
|
|
}
|
|
|
@@ -309,6 +343,34 @@ public class SDLActivity extends Activity {
|
|
|
return mSingleton;
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * @return result of getSystemService(name) but executed on UI thread.
|
|
|
+ */
|
|
|
+ public Object getSystemServiceFromUiThread(final String name) {
|
|
|
+ final Object lock = new Object();
|
|
|
+ final Object[] results = new Object[2]; // array for writable variables
|
|
|
+ synchronized (lock) {
|
|
|
+ runOnUiThread(new Runnable() {
|
|
|
+ @Override
|
|
|
+ public void run() {
|
|
|
+ synchronized (lock) {
|
|
|
+ results[0] = getSystemService(name);
|
|
|
+ results[1] = Boolean.TRUE;
|
|
|
+ lock.notify();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+ if (results[1] == null) {
|
|
|
+ try {
|
|
|
+ lock.wait();
|
|
|
+ } catch (InterruptedException ex) {
|
|
|
+ ex.printStackTrace();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return results[0];
|
|
|
+ }
|
|
|
+
|
|
|
static class ShowTextInputTask implements Runnable {
|
|
|
/*
|
|
|
* This is used to regulate the pan&scan method to have some offset from
|
|
|
@@ -451,6 +513,18 @@ public class SDLActivity extends Activity {
|
|
|
}
|
|
|
return Arrays.copyOf(filtered, used);
|
|
|
}
|
|
|
+
|
|
|
+ // Joystick glue code, just a series of stubs that redirect to the SDLJoystickHandler instance
|
|
|
+ public static boolean handleJoystickMotionEvent(MotionEvent event) {
|
|
|
+ return mJoystickHandler.handleMotionEvent(event);
|
|
|
+ }
|
|
|
+
|
|
|
+ public static void pollInputDevices() {
|
|
|
+ if (SDLActivity.mSDLThread != null) {
|
|
|
+ mJoystickHandler.pollInputDevices();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -496,6 +570,10 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
|
|
|
|
|
|
mDisplay = ((WindowManager)context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
|
|
|
mSensorManager = (SensorManager)context.getSystemService(Context.SENSOR_SERVICE);
|
|
|
+
|
|
|
+ if(Build.VERSION.SDK_INT >= 12) {
|
|
|
+ setOnGenericMotionListener(new SDLGenericMotionListener_API12());
|
|
|
+ }
|
|
|
|
|
|
// Some arbitrary defaults to avoid a potential division by zero
|
|
|
mWidth = 1.0f;
|
|
|
@@ -591,6 +669,23 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
|
|
|
SDLActivity.mSDLThread = new Thread(new SDLMain(), "SDLThread");
|
|
|
enableSensor(Sensor.TYPE_ACCELEROMETER, true);
|
|
|
SDLActivity.mSDLThread.start();
|
|
|
+
|
|
|
+ // Set up a listener thread to catch when the native thread ends
|
|
|
+ new Thread(new Runnable(){
|
|
|
+ @Override
|
|
|
+ public void run(){
|
|
|
+ try {
|
|
|
+ SDLActivity.mSDLThread.join();
|
|
|
+ }
|
|
|
+ catch(Exception e){}
|
|
|
+ finally{
|
|
|
+ // Native thread has finished
|
|
|
+ if (! SDLActivity.mExitCalledFromJava) {
|
|
|
+ SDLActivity.handleNativeExit();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }).start();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -602,16 +697,34 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
|
|
|
// Key events
|
|
|
@Override
|
|
|
public boolean onKey(View v, int keyCode, KeyEvent event) {
|
|
|
+ // Dispatch the different events depending on where they come from
|
|
|
+ // Some SOURCE_DPAD or SOURCE_GAMEPAD are also SOURCE_KEYBOARD
|
|
|
+ // So, we try to process them as DPAD or GAMEPAD events first, if that fails we try them as KEYBOARD
|
|
|
|
|
|
- if (event.getAction() == KeyEvent.ACTION_DOWN) {
|
|
|
- //Log.v("SDL", "key down: " + keyCode);
|
|
|
- SDLActivity.onNativeKeyDown(keyCode);
|
|
|
- return true;
|
|
|
+ if ( (event.getSource() & 0x00000401) != 0 || /* API 12: SOURCE_GAMEPAD */
|
|
|
+ (event.getSource() & InputDevice.SOURCE_DPAD) != 0 ) {
|
|
|
+ if (event.getAction() == KeyEvent.ACTION_DOWN) {
|
|
|
+ if (SDLActivity.onNativePadDown(event.getDeviceId(), keyCode) == 0) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ } else if (event.getAction() == KeyEvent.ACTION_UP) {
|
|
|
+ if (SDLActivity.onNativePadUp(event.getDeviceId(), keyCode) == 0) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
- else if (event.getAction() == KeyEvent.ACTION_UP) {
|
|
|
- //Log.v("SDL", "key up: " + keyCode);
|
|
|
- SDLActivity.onNativeKeyUp(keyCode);
|
|
|
- return true;
|
|
|
+
|
|
|
+ if( (event.getSource() & InputDevice.SOURCE_KEYBOARD) != 0) {
|
|
|
+ if (event.getAction() == KeyEvent.ACTION_DOWN) {
|
|
|
+ //Log.v("SDL", "key down: " + keyCode);
|
|
|
+ SDLActivity.onNativeKeyDown(keyCode);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ else if (event.getAction() == KeyEvent.ACTION_UP) {
|
|
|
+ //Log.v("SDL", "key up: " + keyCode);
|
|
|
+ SDLActivity.onNativeKeyUp(keyCode);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
return false;
|
|
|
@@ -620,31 +733,48 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
|
|
|
// Touch events
|
|
|
@Override
|
|
|
public boolean onTouch(View v, MotionEvent event) {
|
|
|
- final int touchDevId = event.getDeviceId();
|
|
|
- final int pointerCount = event.getPointerCount();
|
|
|
- // touchId, pointerId, action, x, y, pressure
|
|
|
- int actionPointerIndex = (event.getAction() & MotionEvent.ACTION_POINTER_ID_MASK) >> MotionEvent.ACTION_POINTER_ID_SHIFT; /* API 8: event.getActionIndex(); */
|
|
|
- int pointerFingerId = event.getPointerId(actionPointerIndex);
|
|
|
- int action = (event.getAction() & MotionEvent.ACTION_MASK); /* API 8: event.getActionMasked(); */
|
|
|
-
|
|
|
- float x = event.getX(actionPointerIndex) / mWidth;
|
|
|
- float y = event.getY(actionPointerIndex) / mHeight;
|
|
|
- float p = event.getPressure(actionPointerIndex);
|
|
|
-
|
|
|
- if (action == MotionEvent.ACTION_MOVE && pointerCount > 1) {
|
|
|
- // TODO send motion to every pointer if its position has
|
|
|
- // changed since prev event.
|
|
|
- for (int i = 0; i < pointerCount; i++) {
|
|
|
+ /* Ref: http://developer.android.com/training/gestures/multi.html */
|
|
|
+ final int touchDevId = event.getDeviceId();
|
|
|
+ final int pointerCount = event.getPointerCount();
|
|
|
+ int action = event.getActionMasked();
|
|
|
+ int pointerFingerId;
|
|
|
+ int i = -1;
|
|
|
+ float x,y,p;
|
|
|
+
|
|
|
+ switch(action) {
|
|
|
+ case MotionEvent.ACTION_MOVE:
|
|
|
+ for (i = 0; i < pointerCount; i++) {
|
|
|
pointerFingerId = event.getPointerId(i);
|
|
|
x = event.getX(i) / mWidth;
|
|
|
y = event.getY(i) / mHeight;
|
|
|
p = event.getPressure(i);
|
|
|
SDLActivity.onNativeTouch(touchDevId, pointerFingerId, action, x, y, p);
|
|
|
}
|
|
|
- } else {
|
|
|
+ break;
|
|
|
+
|
|
|
+ case MotionEvent.ACTION_UP:
|
|
|
+ case MotionEvent.ACTION_DOWN:
|
|
|
+ // Primary pointer up/down, the index is always zero
|
|
|
+ i = 0;
|
|
|
+ case MotionEvent.ACTION_POINTER_UP:
|
|
|
+ case MotionEvent.ACTION_POINTER_DOWN:
|
|
|
+ // Non primary pointer up/down
|
|
|
+ if (i == -1) {
|
|
|
+ i = event.getActionIndex();
|
|
|
+ }
|
|
|
+
|
|
|
+ pointerFingerId = event.getPointerId(i);
|
|
|
+ x = event.getX(i) / mWidth;
|
|
|
+ y = event.getY(i) / mHeight;
|
|
|
+ p = event.getPressure(i);
|
|
|
SDLActivity.onNativeTouch(touchDevId, pointerFingerId, action, x, y, p);
|
|
|
- }
|
|
|
- return true;
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ return true;
|
|
|
}
|
|
|
|
|
|
// Sensor events
|
|
|
@@ -691,8 +821,7 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
|
|
|
y / SensorManager.GRAVITY_EARTH,
|
|
|
event.values[2] / SensorManager.GRAVITY_EARTH - 1);
|
|
|
}
|
|
|
- }
|
|
|
-
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/* This is a fake invisible editor view that receives the input and defines the
|
|
|
@@ -812,5 +941,163 @@ class SDLInputConnection extends BaseInputConnection {
|
|
|
|
|
|
public native void nativeSetComposingText(String text, int newCursorPosition);
|
|
|
|
|
|
+ @Override
|
|
|
+ public boolean deleteSurroundingText(int beforeLength, int afterLength) {
|
|
|
+ // Workaround to capture backspace key. Ref: http://stackoverflow.com/questions/14560344/android-backspace-in-webview-baseinputconnection
|
|
|
+ if (beforeLength == 1 && afterLength == 0) {
|
|
|
+ // backspace
|
|
|
+ return super.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL))
|
|
|
+ && super.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DEL));
|
|
|
+ }
|
|
|
+
|
|
|
+ return super.deleteSurroundingText(beforeLength, afterLength);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/* A null joystick handler for API level < 12 devices (the accelerometer is handled separately) */
|
|
|
+class SDLJoystickHandler {
|
|
|
+
|
|
|
+ public boolean handleMotionEvent(MotionEvent event) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ public void pollInputDevices() {
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/* Actual joystick functionality available for API >= 12 devices */
|
|
|
+class SDLJoystickHandler_API12 extends SDLJoystickHandler {
|
|
|
+
|
|
|
+ class SDLJoystick {
|
|
|
+ public int device_id;
|
|
|
+ public String name;
|
|
|
+ public ArrayList<InputDevice.MotionRange> axes;
|
|
|
+ public ArrayList<InputDevice.MotionRange> hats;
|
|
|
+ }
|
|
|
+ class RangeComparator implements Comparator<InputDevice.MotionRange>
|
|
|
+ {
|
|
|
+ @Override
|
|
|
+ public int compare(InputDevice.MotionRange arg0, InputDevice.MotionRange arg1) {
|
|
|
+ return arg0.getAxis() - arg1.getAxis();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private ArrayList<SDLJoystick> mJoysticks;
|
|
|
+
|
|
|
+ public SDLJoystickHandler_API12() {
|
|
|
+
|
|
|
+ mJoysticks = new ArrayList<SDLJoystick>();
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void pollInputDevices() {
|
|
|
+ int[] deviceIds = InputDevice.getDeviceIds();
|
|
|
+ // It helps processing the device ids in reverse order
|
|
|
+ // For example, in the case of the XBox 360 wireless dongle,
|
|
|
+ // so the first controller seen by SDL matches what the receiver
|
|
|
+ // considers to be the first controller
|
|
|
+
|
|
|
+ for(int i=deviceIds.length-1; i>-1; i--) {
|
|
|
+ SDLJoystick joystick = getJoystick(deviceIds[i]);
|
|
|
+ if (joystick == null) {
|
|
|
+ joystick = new SDLJoystick();
|
|
|
+ InputDevice joystickDevice = InputDevice.getDevice(deviceIds[i]);
|
|
|
+ if( (joystickDevice.getSources() & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
|
|
|
+ joystick.device_id = deviceIds[i];
|
|
|
+ joystick.name = joystickDevice.getName();
|
|
|
+ joystick.axes = new ArrayList<InputDevice.MotionRange>();
|
|
|
+ joystick.hats = new ArrayList<InputDevice.MotionRange>();
|
|
|
+
|
|
|
+ List<InputDevice.MotionRange> ranges = joystickDevice.getMotionRanges();
|
|
|
+ Collections.sort(ranges, new RangeComparator());
|
|
|
+ for (InputDevice.MotionRange range : ranges ) {
|
|
|
+ if ((range.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) != 0 ) {
|
|
|
+ if (range.getAxis() == MotionEvent.AXIS_HAT_X ||
|
|
|
+ range.getAxis() == MotionEvent.AXIS_HAT_Y) {
|
|
|
+ joystick.hats.add(range);
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ joystick.axes.add(range);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ mJoysticks.add(joystick);
|
|
|
+ SDLActivity.nativeAddJoystick(joystick.device_id, joystick.name, 0, -1,
|
|
|
+ joystick.axes.size(), joystick.hats.size()/2, 0);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Check removed devices */
|
|
|
+ ArrayList<Integer> removedDevices = new ArrayList<Integer>();
|
|
|
+ for(int i=0; i < mJoysticks.size(); i++) {
|
|
|
+ int device_id = mJoysticks.get(i).device_id;
|
|
|
+ int j;
|
|
|
+ for (j=0; j < deviceIds.length; j++) {
|
|
|
+ if (device_id == deviceIds[j]) break;
|
|
|
+ }
|
|
|
+ if (j == deviceIds.length) {
|
|
|
+ removedDevices.add(device_id);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ for(int i=0; i < removedDevices.size(); i++) {
|
|
|
+ int device_id = removedDevices.get(i);
|
|
|
+ SDLActivity.nativeRemoveJoystick(device_id);
|
|
|
+ for (int j=0; j < mJoysticks.size(); j++) {
|
|
|
+ if (mJoysticks.get(j).device_id == device_id) {
|
|
|
+ mJoysticks.remove(j);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ protected SDLJoystick getJoystick(int device_id) {
|
|
|
+ for(int i=0; i < mJoysticks.size(); i++) {
|
|
|
+ if (mJoysticks.get(i).device_id == device_id) {
|
|
|
+ return mJoysticks.get(i);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public boolean handleMotionEvent(MotionEvent event) {
|
|
|
+ if ( (event.getSource() & InputDevice.SOURCE_JOYSTICK) != 0) {
|
|
|
+ int actionPointerIndex = event.getActionIndex();
|
|
|
+ int action = event.getActionMasked();
|
|
|
+ switch(action) {
|
|
|
+ case MotionEvent.ACTION_MOVE:
|
|
|
+ SDLJoystick joystick = getJoystick(event.getDeviceId());
|
|
|
+ if ( joystick != null ) {
|
|
|
+ for (int i = 0; i < joystick.axes.size(); i++) {
|
|
|
+ InputDevice.MotionRange range = joystick.axes.get(i);
|
|
|
+ /* Normalize the value to -1...1 */
|
|
|
+ float value = ( event.getAxisValue( range.getAxis(), actionPointerIndex) - range.getMin() ) / range.getRange() * 2.0f - 1.0f;
|
|
|
+ SDLActivity.onNativeJoy(joystick.device_id, i, value );
|
|
|
+ }
|
|
|
+ for (int i = 0; i < joystick.hats.size(); i+=2) {
|
|
|
+ int hatX = Math.round(event.getAxisValue( joystick.hats.get(i).getAxis(), actionPointerIndex ) );
|
|
|
+ int hatY = Math.round(event.getAxisValue( joystick.hats.get(i+1).getAxis(), actionPointerIndex ) );
|
|
|
+ SDLActivity.onNativeHat(joystick.device_id, i/2, hatX, hatY );
|
|
|
+ }
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
+class SDLGenericMotionListener_API12 implements View.OnGenericMotionListener {
|
|
|
+ // Generic Motion (mouse hover, joystick...) events go here
|
|
|
+ // We only have joysticks yet
|
|
|
+ @Override
|
|
|
+ public boolean onGenericMotion(View v, MotionEvent event) {
|
|
|
+ return SDLActivity.handleJoystickMotionEvent(event);
|
|
|
+ }
|
|
|
+}
|