diff -r 177f29ae5279 Android.mk --- a/Android.mk Sat Feb 16 23:09:10 2013 -0800 +++ b/Android.mk Mon Feb 18 02:41:37 2013 +0100 @@ -42,6 +42,6 @@ $(wildcard $(LOCAL_PATH)/src/video/android/*.c)) LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -LOCAL_LDLIBS := -ldl -lGLESv1_CM -lGLESv2 -llog +LOCAL_LDLIBS := -ldl -lGLESv1_CM -lGLESv2 -llog -landroid include $(BUILD_SHARED_LIBRARY) diff -r 177f29ae5279 android-project/src/org/libsdl/app/SDLActivity.java --- a/android-project/src/org/libsdl/app/SDLActivity.java Sat Feb 16 23:09:10 2013 -0800 +++ b/android-project/src/org/libsdl/app/SDLActivity.java Mon Feb 18 02:41:37 2013 +0100 @@ -24,6 +24,8 @@ import android.content.*; import java.lang.*; +import java.util.List; +import java.util.ArrayList; /** @@ -36,12 +38,16 @@ // Main components private static SDLActivity mSingleton; + private static _SDLSurface _mSurface; private static SDLSurface mSurface; private static View mTextEdit; private static ViewGroup mLayout; // This is what SDL runs in. It invokes SDL_main(), eventually private static Thread mSDLThread; + + // Joystick + private static List mJoyIdList; // Audio private static Thread mAudioThread; @@ -75,14 +81,23 @@ mIsPaused = false; // Set up the surface - mSurface = new SDLSurface(getApplication()); - - mLayout = new AbsoluteLayout(this); - mLayout.addView(mSurface); - - setContentView(mLayout); - - SurfaceHolder holder = mSurface.getHolder(); + if(Build.VERSION.SDK_INT >= 12) { + _mSurface = new _SDLSurface(getApplication()); + mLayout = new AbsoluteLayout(this); + mLayout.addView(_mSurface); + + setContentView(mLayout); + + SurfaceHolder holder = _mSurface.getHolder(); + } else { + mSurface = new SDLSurface(getApplication()); + mLayout = new AbsoluteLayout(this); + mLayout.addView(mSurface); + + setContentView(mLayout); + + SurfaceHolder holder = mSurface.getHolder(); + } } // Events @@ -156,6 +171,10 @@ public static native void nativePause(); public static native void nativeResume(); public static native void onNativeResize(int x, int y, int format); + public static native void onNativePadDown(int padId, int keycode); + public static native void onNativePadUp(int padId, int keycode); + public static native void onNativeJoy(int joyId, int action, + float x, float y); public static native void onNativeKeyDown(int keycode); public static native void onNativeKeyUp(int keycode); public static native void onNativeTouch(int touchDevId, int pointerFingerId, @@ -180,6 +199,54 @@ mSingleton.sendCommand(COMMAND_CHANGE_TITLE, title); } + // Create a list of valid ID's the first time this function is called + private static void createJoystickList() { + if(mJoyIdList != null) { + return; + } + + mJoyIdList = new ArrayList(); + + int[] deviceIds = InputDevice.getDeviceIds(); + for(int i=0; i= 12) { + return InputDevice.getDevice(mJoyIdList.get(joy)).getMotionRanges().size(); + } else { + return 2; + } + } + + public static int getJoyId(int devId) { + int i=0; + + createJoystickList(); + + return mJoyIdList.indexOf(devId); + } + public static void sendMessage(int command, int param) { mSingleton.sendCommand(command, Integer.valueOf(param)); } @@ -300,12 +367,17 @@ } public static boolean createEGLSurface() { + EGLSurface surface; if (SDLActivity.mEGLDisplay != null && SDLActivity.mEGLConfig != null) { EGL10 egl = (EGL10)EGLContext.getEGL(); if (SDLActivity.mEGLContext == null) createEGLContext(); Log.v("SDL", "Creating new EGL Surface"); - EGLSurface surface = egl.eglCreateWindowSurface(SDLActivity.mEGLDisplay, SDLActivity.mEGLConfig, SDLActivity.mSurface, null); + if(Build.VERSION.SDK_INT >= 12) { + surface = egl.eglCreateWindowSurface(SDLActivity.mEGLDisplay, SDLActivity.mEGLConfig, SDLActivity._mSurface, null); + } else { + surface = egl.eglCreateWindowSurface(SDLActivity.mEGLDisplay, SDLActivity.mEGLConfig, SDLActivity.mSurface, null); + } if (surface == EGL10.EGL_NO_SURFACE) { Log.e("SDL", "Couldn't create surface"); return false; @@ -454,6 +526,41 @@ } +class _SDLSurface extends SDLSurface implements View.OnGenericMotionListener { + // Keep track of the surface size to normalize touch events + private static float mWidth, mHeight; + + // Startup + public _SDLSurface(Context context) { + super(context); + getHolder().addCallback(this); + setOnGenericMotionListener(this); + + // Some arbitrary defaults to avoid a potential division by zero + mWidth = 1.0f; + mHeight = 1.0f; + } + + // Generic Motion (mouse hover, joystick...) events + public boolean onGenericMotion(View v, MotionEvent event) { + int actionPointerIndex = event.getActionIndex(); + int action = event.getActionMasked(); + + if ( (event.getSource() & InputDevice.SOURCE_JOYSTICK) != 0) { + switch(action) { + case MotionEvent.ACTION_MOVE: + int id = SDLActivity.getJoyId( event.getDeviceId() ); + float x = event.getAxisValue(MotionEvent.AXIS_X, actionPointerIndex); + float y = event.getAxisValue(MotionEvent.AXIS_Y, actionPointerIndex); + SDLActivity.onNativeJoy(id, action, x, y); + + break; + } + } + return true; + } +} + /** SDLSurface. This is what we draw on, so we need to know when it's created in order to do anything useful. @@ -478,7 +585,7 @@ setFocusableInTouchMode(true); requestFocus(); setOnKeyListener(this); - setOnTouchListener(this); + setOnTouchListener(this); mSensorManager = (SensorManager)context.getSystemService("sensor"); @@ -570,15 +677,25 @@ // Key events public boolean onKey(View v, int keyCode, KeyEvent event) { - - if (event.getAction() == KeyEvent.ACTION_DOWN) { - //Log.v("SDL", "key down: " + keyCode); - SDLActivity.onNativeKeyDown(keyCode); + // Dispatch the different events depending on where they come from + if(event.getSource() == InputDevice.SOURCE_KEYBOARD) { + if (event.getAction() == KeyEvent.ACTION_DOWN) { + //Log.v("SDL", "key down: " + keyCode); + SDLActivity.onNativeKeyDown(keyCode); + } + else if (event.getAction() == KeyEvent.ACTION_UP) { + //Log.v("SDL", "key up: " + keyCode); + SDLActivity.onNativeKeyUp(keyCode); + } return true; - } - else if (event.getAction() == KeyEvent.ACTION_UP) { - //Log.v("SDL", "key up: " + keyCode); - SDLActivity.onNativeKeyUp(keyCode); + } else if ( (event.getSource() & InputDevice.SOURCE_GAMEPAD) != 0 || + (event.getSource() & InputDevice.SOURCE_DPAD) != 0 ) { + int id = SDLActivity.getJoyId( event.getDeviceId() ); + if (event.getAction() == KeyEvent.ACTION_DOWN) { + SDLActivity.onNativePadDown(id, keyCode); + } else if (event.getAction() == KeyEvent.ACTION_UP) { + SDLActivity.onNativePadUp(id, keyCode); + } return true; } @@ -614,7 +731,7 @@ } } return true; - } + } // Sensor events public void enableSensor(int sensortype, boolean enabled) { diff -r 177f29ae5279 src/core/android/SDL_android.cpp --- a/src/core/android/SDL_android.cpp Sat Feb 16 23:09:10 2013 -0800 +++ b/src/core/android/SDL_android.cpp Mon Feb 18 02:41:37 2013 +0100 @@ -31,11 +31,13 @@ extern "C" { #include "../../events/SDL_events_c.h" +#include "../../joystick/android/SDL_androidjoystick.h" #include "../../video/android/SDL_androidkeyboard.h" #include "../../video/android/SDL_androidtouch.h" #include "../../video/android/SDL_androidvideo.h" #include +#include #include #include #include @@ -147,6 +149,27 @@ Android_SetScreenResolution(width, height, format); } +// Paddown +extern "C" void Java_org_libsdl_app_SDLActivity_onNativePadDown( + JNIEnv* env, jclass jcls, jint padId, jint keycode) +{ + Android_OnPadDown(padId, keycode); +} + +// Padup +extern "C" void Java_org_libsdl_app_SDLActivity_onNativePadUp( + JNIEnv* env, jclass jcls, jint padId, jint keycode) +{ + Android_OnPadUp(padId, keycode); +} + +// Joysticks +extern "C" void Java_org_libsdl_app_SDLActivity_onNativeJoy( + JNIEnv* env, jclass jcls, jint joyId, jint action, jfloat x, jfloat y) +{ + Android_OnJoy(joyId, action, x, y); +} + // Keydown extern "C" void Java_org_libsdl_app_SDLActivity_onNativeKeyDown( JNIEnv* env, jclass jcls, jint keycode) @@ -1082,6 +1105,69 @@ return 0; } +// return the total number of plugged in joysticks +extern "C" int Android_JNI_GetNumJoysticks() +{ + JNIEnv* env = Android_JNI_GetEnv(); + if (!env) { + return -1; + } + jmethodID mid = env->GetStaticMethodID(mActivityClass, "getNumJoysticks", "()I"); + if (!mid) { + return -1; + } + + return env->CallIntMethod(mActivityClass, mid); +} + +// Return the name of joystick number "index" +extern "C" char* Android_JNI_GetJoystickName(int index) +{ + JNIEnv* env = Android_JNI_GetEnv(); + if (!env) { + return SDL_strdup(""); + } + + jmethodID mid = env->GetStaticMethodID(mActivityClass, "getJoystickName", "(I)Ljava/lang/String;"); + if (!mid) { + return SDL_strdup(""); + } + jstring string = reinterpret_cast(env->CallStaticObjectMethod(mActivityClass, mid, index)); + const char* utf = env->GetStringUTFChars(string, 0); + if (!utf) { + return SDL_strdup(""); + } + + char* text = SDL_strdup(utf); + env->ReleaseStringUTFChars(string, utf); + return text; +} + +// return the number of axes in the given joystick +extern "C" int Android_JNI_GetJoystickAxes(int index) +{ + JNIEnv* env = Android_JNI_GetEnv(); + if (!env) { + return -1; + } + jmethodID mid = env->GetStaticMethodID(mActivityClass, "getJoystickAxes", "(I)I"); + if (!mid) { + return -1; + } + + return env->CallIntMethod(mActivityClass, mid, index); +} + +// Return the name of the default accelerometer +// This is much easier to be done with NDK than with JNI +extern "C" char* Android_GetAccelName() +{ + ASensorManager* mSensorManager = ASensorManager_getInstance(); + ASensor const* mAccelerometer = ASensorManager_getDefaultSensor(mSensorManager, ASENSOR_TYPE_ACCELEROMETER); + + return SDL_strdup(ASensor_getName(mAccelerometer)); +} + // sends message to be handled on the UI event dispatch thread extern "C" int Android_JNI_SendMessage(int command, int param) { diff -r 177f29ae5279 src/core/android/SDL_android.h --- a/src/core/android/SDL_android.h Sat Feb 16 23:09:10 2013 -0800 +++ b/src/core/android/SDL_android.h Mon Feb 18 02:41:37 2013 +0100 @@ -60,6 +60,12 @@ /* Power support */ int Android_JNI_GetPowerInfo(int* plugged, int* charged, int* battery, int* seconds, int* percent); +/* Joystick/accelerometer support */ +int Android_JNI_GetNumJoysticks(); +char* Android_JNI_GetJoystickName(int i); +int Android_JNI_GetJoystickAxes(int index); +char* Android_GetAccelName(); + // Threads #include static void Android_JNI_ThreadDestroyed(void*); diff -r 177f29ae5279 src/joystick/android/SDL_androidjoystick.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/joystick/android/SDL_androidjoystick.c Mon Feb 18 02:41:37 2013 +0100 @@ -0,0 +1,252 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2012 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +#include "SDL_config.h" + +#ifdef SDL_JOYSTICK_ANDROID + +/* This is the system specific header for the SDL joystick API */ +#include /* For the definition of NULL */ + +#include "SDL_error.h" +#include "SDL_events.h" +#include "SDL_joystick.h" +#include "../SDL_sysjoystick.h" +#include "../SDL_joystick_c.h" +#include "../../core/android/SDL_android.h" + +#define MAX_JOYSTICKS 8 + +//HACK!! +static SDL_Joystick *SYS_Joysticks[MAX_JOYSTICKS]; +static char *SYS_JoystickNames[MAX_JOYSTICKS]; +static int SYS_numjoysticks; + +/* Function to convert Android keyCodes into SDL ones. + * This code manipulation is done to get a sequential list of codes. + */ +int +keycode_to_SDL(int keycode) +{ + if(keycode < 96) + return keycode-19; + else if(keycode < 188) + return keycode-91; + else + return keycode-168; +} + +/* Function to scan the system for joysticks. + * This function should set SYS_numjoysticks to the number of available + * joysticks. Joystick 0 should be the system default joystick. + * It should return 0, or -1 on an unrecoverable fatal error. + */ +int +SDL_SYS_JoystickInit(void) +{ + int i = 0; + // The latest entry is for the accelerometer + // TODO: handle the case where SYS_numjoysticks > MAX_JOYSTICKS + SYS_numjoysticks = Android_JNI_GetNumJoysticks()+1; + SDL_memset(SYS_JoystickNames, 0, (sizeof SYS_JoystickNames)); + SDL_memset(SYS_Joysticks, 0, (sizeof SYS_Joysticks)); + + for (i = 0; i < (SYS_numjoysticks-1); i++) + { + SYS_JoystickNames[i] = Android_JNI_GetJoystickName(i); + } + SYS_JoystickNames[i] = Android_GetAccelName(); + + return (SYS_numjoysticks); +} + +int SDL_SYS_NumJoysticks() +{ + return SYS_numjoysticks; +} + +void SDL_SYS_JoystickDetect() +{ +} + +SDL_bool SDL_SYS_JoystickNeedsPolling() +{ + return SDL_FALSE; +} + +/* Function to get the device-dependent name of a joystick */ +const char * +SDL_SYS_JoystickNameForDeviceIndex(int device_index) +{ + return SYS_JoystickNames[device_index]; +} + +/* Function to perform the mapping from device index to the instance id for this index */ +SDL_JoystickID SDL_SYS_GetInstanceIdOfDeviceIndex(int device_index) +{ + return device_index; +} + +/* Function to open a joystick for use. + The joystick to open is specified by the index field of the joystick. + This should fill the nbuttons and naxes fields of the joystick structure. + It returns 0, or -1 if there is an error. + */ +int +SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index) +{ + // Handle the accelerometer separately + if( device_index < (SYS_numjoysticks-1) ) + { + // TODO: How to get the rest of the info?? + // 36 is the maximum number of handled buttons + joystick->nbuttons = 36; + joystick->nhats = 0; + joystick->nballs = 0; + joystick->naxes = Android_JNI_GetJoystickAxes(device_index); + } + else if( device_index == (SYS_numjoysticks-1) ) + { + joystick->nbuttons = 0; + joystick->nhats = 0; + joystick->nballs = 0; + joystick->naxes = 3; + } + else + { + return -1; + } + + // Extremely hacky + SYS_Joysticks[device_index] = joystick; + + return 0; +} + + +/* Function to update the state of a joystick - called as a device poll. + * This function shouldn't update the joystick structure directly, + * but instead should call SDL_PrivateJoystick*() to deliver events + * and update joystick device state. + */ +void +SDL_SYS_JoystickUpdate(SDL_Joystick * joystick) +{ + int i; + Sint16 value; + float values[3]; + + if( joystick->instance_id == (SYS_numjoysticks-1) ) + { + if (Android_JNI_GetAccelerometerValues(values)) + { + for ( i = 0; i < 3; i++ ) + { + value = (Sint16)(values[i] * 32767.0f); + SDL_PrivateJoystickAxis(joystick, i, value); + } + } + } +} + +/* Function to determine is this joystick is attached to the system right now */ +SDL_bool SDL_SYS_JoystickAttached(SDL_Joystick *joystick) +{ + return SDL_TRUE; +} + +/* Function to close a joystick after use */ +void +SDL_SYS_JoystickClose(SDL_Joystick * joystick) +{ +} + +/* Function to perform any system-specific joystick related cleanup */ +void +SDL_SYS_JoystickQuit(void) +{ + int i; + + for (i = 0; iname; + SDL_zero( guid ); + SDL_memcpy( &guid, name, SDL_min( sizeof(guid), SDL_strlen( name ) ) ); + return guid; +} + +int +Android_OnPadDown(int padId, int keycode) +{ + SDL_PrivateJoystickButton(SYS_Joysticks[padId], keycode_to_SDL(keycode), SDL_PRESSED); + + return 0; +} + +int +Android_OnPadUp(int padId, int keycode) +{ + SDL_PrivateJoystickButton(SYS_Joysticks[padId], keycode_to_SDL(keycode), SDL_RELEASED); + + return 0; +} + +int +Android_OnJoy(int joyId, int action, float x, float y) +{ + // Android gives joy info normalized as [-1.0, 1.0] + // TODO: Are the reported values right? + SDL_PrivateJoystickAxis(SYS_Joysticks[joyId], 0, (Sint16) (32767.*x) ); + SDL_PrivateJoystickAxis(SYS_Joysticks[joyId], 1, (Sint16) (32767.*y) ); + + return 0; +} + +#endif /* SDL_JOYSTICK_ANDROID */ + +/* vi: set ts=4 sw=4 expandtab: */ \ No newline at end of file diff -r 177f29ae5279 src/joystick/android/SDL_androidjoystick.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/joystick/android/SDL_androidjoystick.h Mon Feb 18 02:41:37 2013 +0100 @@ -0,0 +1,27 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2012 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "SDL_config.h" + +extern int Android_OnPadDown(int padId, int keycode); +extern int Android_OnPadUp(int padId, int keycode); +extern int Android_OnJoy(int joyId, int action, float x, float y); + +/* vi: set ts=4 sw=4 expandtab: */ \ No newline at end of file diff -r 177f29ae5279 src/joystick/android/SDL_sysjoystick.c --- a/src/joystick/android/SDL_sysjoystick.c Sat Feb 16 23:09:10 2013 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,156 +0,0 @@ -/* - Simple DirectMedia Layer - Copyright (C) 1997-2013 Sam Lantinga - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. -*/ - -#include "SDL_config.h" - -#ifdef SDL_JOYSTICK_ANDROID - -/* This is the system specific header for the SDL joystick API */ -#include /* For the definition of NULL */ - -#include "SDL_error.h" -#include "SDL_events.h" -#include "SDL_joystick.h" -#include "../SDL_sysjoystick.h" -#include "../SDL_joystick_c.h" -#include "../../core/android/SDL_android.h" - -static const char *accelerometerName = "Android accelerometer"; - -/* Function to scan the system for joysticks. - * This function should set SDL_numjoysticks to the number of available - * joysticks. Joystick 0 should be the system default joystick. - * It should return 0, or -1 on an unrecoverable fatal error. - */ -int -SDL_SYS_JoystickInit(void) -{ - return (1); -} - -int SDL_SYS_NumJoysticks() -{ - return 1; -} - -void SDL_SYS_JoystickDetect() -{ -} - -SDL_bool SDL_SYS_JoystickNeedsPolling() -{ - return SDL_FALSE; -} - -/* Function to get the device-dependent name of a joystick */ -const char * -SDL_SYS_JoystickNameForDeviceIndex(int device_index) -{ - return accelerometerName; -} - -/* Function to perform the mapping from device index to the instance id for this index */ -SDL_JoystickID SDL_SYS_GetInstanceIdOfDeviceIndex(int device_index) -{ - return device_index; -} - -/* Function to open a joystick for use. - The joystick to open is specified by the index field of the joystick. - This should fill the nbuttons and naxes fields of the joystick structure. - It returns 0, or -1 if there is an error. - */ -int -SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index) -{ - if (device_index == 0) { - joystick->nbuttons = 0; - joystick->nhats = 0; - joystick->nballs = 0; - joystick->naxes = 3; - return 0; - } else { - SDL_SetError("No joystick available with that index"); - return (-1); - } -} - -/* Function to determine is this joystick is attached to the system right now */ -SDL_bool SDL_SYS_JoystickAttached(SDL_Joystick *joystick) -{ - return SDL_TRUE; -} - -/* Function to update the state of a joystick - called as a device poll. - * This function shouldn't update the joystick structure directly, - * but instead should call SDL_PrivateJoystick*() to deliver events - * and update joystick device state. - */ -void -SDL_SYS_JoystickUpdate(SDL_Joystick * joystick) -{ - int i; - Sint16 value; - float values[3]; - - if (Android_JNI_GetAccelerometerValues(values)) { - for ( i = 0; i < 3; i++ ) { - value = (Sint16)(values[i] * 32767.0f); - SDL_PrivateJoystickAxis(joystick, i, value); - } - } -} - -/* Function to close a joystick after use */ -void -SDL_SYS_JoystickClose(SDL_Joystick * joystick) -{ -} - -/* Function to perform any system-specific joystick related cleanup */ -void -SDL_SYS_JoystickQuit(void) -{ -} - -SDL_JoystickGUID SDL_SYS_JoystickGetDeviceGUID( int device_index ) -{ - SDL_JoystickGUID guid; - // the GUID is just the first 16 chars of the name for now - const char *name = SDL_SYS_JoystickNameForDeviceIndex( device_index ); - SDL_zero( guid ); - SDL_memcpy( &guid, name, SDL_min( sizeof(guid), SDL_strlen( name ) ) ); - return guid; -} - -SDL_JoystickGUID SDL_SYS_JoystickGetGUID(SDL_Joystick * joystick) -{ - SDL_JoystickGUID guid; - // the GUID is just the first 16 chars of the name for now - const char *name = joystick->name; - SDL_zero( guid ); - SDL_memcpy( &guid, name, SDL_min( sizeof(guid), SDL_strlen( name ) ) ); - return guid; -} - -#endif /* SDL_JOYSTICK_ANDROID */ - -/* vi: set ts=4 sw=4 expandtab: */