WinRT: merged with SDL 2.0.1 codebase

This commit is contained in:
David Ludwig
2013-10-27 21:26:46 -04:00
343 changed files with 12735 additions and 7248 deletions

View File

@@ -33,19 +33,20 @@
#include "../../video/android/SDL_androidkeyboard.h"
#include "../../video/android/SDL_androidtouch.h"
#include "../../video/android/SDL_androidvideo.h"
#include "../../video/android/SDL_androidwindow.h"
#include <android/log.h>
#include <pthread.h>
#include <sys/types.h>
#include <unistd.h>
#define LOG_TAG "SDL_android"
//#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
//#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
/* #define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__) */
/* #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__) */
#define LOGI(...) do {} while (false)
#define LOGE(...) do {} while (false)
/* Uncomment this to log messages entering and exiting methods in this file */
//#define DEBUG_JNI
/* #define DEBUG_JNI */
static void Android_JNI_ThreadDestroyed(void*);
@@ -63,19 +64,18 @@ static void Android_JNI_ThreadDestroyed(void*);
static pthread_key_t mThreadKey;
static JavaVM* mJavaVM;
// Main activity
/* Main activity */
static jclass mActivityClass;
// method signatures
static jmethodID midCreateGLContext;
static jmethodID midDeleteGLContext;
/* method signatures */
static jmethodID midGetNativeSurface;
static jmethodID midFlipBuffers;
static jmethodID midAudioInit;
static jmethodID midAudioWriteShortBuffer;
static jmethodID midAudioWriteByteBuffer;
static jmethodID midAudioQuit;
// Accelerometer data storage
/* Accelerometer data storage */
static float fLastAccelerometer[3];
static bool bHasNewData;
@@ -83,7 +83,7 @@ static bool bHasNewData;
Functions called by JNI
*******************************************************************************/
// Library init
/* Library init */
jint JNI_OnLoad(JavaVM* vm, void* reserved)
{
JNIEnv *env;
@@ -107,7 +107,7 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved)
return JNI_VERSION_1_4;
}
// Called before SDL_main() to initialize JNI bindings
/* Called before SDL_main() to initialize JNI bindings */
void SDL_Android_Init(JNIEnv* mEnv, jclass cls)
{
__android_log_print(ANDROID_LOG_INFO, "SDL", "SDL_Android_Init()");
@@ -116,10 +116,8 @@ void SDL_Android_Init(JNIEnv* mEnv, jclass cls)
mActivityClass = (jclass)((*mEnv)->NewGlobalRef(mEnv, cls));
midCreateGLContext = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass,
"createGLContext","(II[I)Z");
midDeleteGLContext = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass,
"deleteGLContext","()V");
midGetNativeSurface = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass,
"getNativeSurface","()Landroid/view/Surface;");
midFlipBuffers = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass,
"flipBuffers","()V");
midAudioInit = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass,
@@ -133,14 +131,14 @@ void SDL_Android_Init(JNIEnv* mEnv, jclass cls)
bHasNewData = false;
if(!midCreateGLContext || !midFlipBuffers || !midAudioInit ||
if(!midGetNativeSurface || !midFlipBuffers || !midAudioInit ||
!midAudioWriteShortBuffer || !midAudioWriteByteBuffer || !midAudioQuit) {
__android_log_print(ANDROID_LOG_WARN, "SDL", "SDL: Couldn't locate Java callbacks, check that they're named and typed correctly");
}
__android_log_print(ANDROID_LOG_INFO, "SDL", "SDL_Android_Init() finished!");
}
// Resize
/* Resize */
void Java_org_libsdl_app_SDLActivity_onNativeResize(
JNIEnv* env, jclass jcls,
jint width, jint height, jint format)
@@ -148,21 +146,80 @@ void Java_org_libsdl_app_SDLActivity_onNativeResize(
Android_SetScreenResolution(width, height, format);
}
// Keydown
/* Surface Created */
void Java_org_libsdl_app_SDLActivity_onNativeSurfaceChanged(JNIEnv* env, jclass jcls)
{
SDL_WindowData *data;
SDL_VideoDevice *_this;
if (Android_Window == NULL || Android_Window->driverdata == NULL ) {
return;
}
_this = SDL_GetVideoDevice();
data = (SDL_WindowData *) Android_Window->driverdata;
/* If the surface has been previously destroyed by onNativeSurfaceDestroyed, recreate it here */
if (data->egl_surface == EGL_NO_SURFACE) {
if(data->native_window) {
ANativeWindow_release(data->native_window);
}
data->native_window = Android_JNI_GetNativeWindow();
data->egl_surface = SDL_EGL_CreateSurface(_this, (NativeWindowType) data->native_window);
}
/* GL Context handling is done in the event loop because this function is run from the Java thread */
}
/* Surface Destroyed */
void Java_org_libsdl_app_SDLActivity_onNativeSurfaceDestroyed(JNIEnv* env, jclass jcls)
{
/* We have to clear the current context and destroy the egl surface here
* Otherwise there's BAD_NATIVE_WINDOW errors coming from eglCreateWindowSurface on resume
* Ref: http://stackoverflow.com/questions/8762589/eglcreatewindowsurface-on-ics-and-switching-from-2d-to-3d
*/
SDL_WindowData *data;
SDL_VideoDevice *_this;
if (Android_Window == NULL || Android_Window->driverdata == NULL ) {
return;
}
_this = SDL_GetVideoDevice();
data = (SDL_WindowData *) Android_Window->driverdata;
if (data->egl_surface != EGL_NO_SURFACE) {
SDL_EGL_MakeCurrent(_this, NULL, NULL);
SDL_EGL_DestroySurface(_this, data->egl_surface);
data->egl_surface = EGL_NO_SURFACE;
}
/* GL Context handling is done in the event loop because this function is run from the Java thread */
}
void Java_org_libsdl_app_SDLActivity_nativeFlipBuffers(JNIEnv* env, jclass jcls)
{
SDL_GL_SwapWindow(Android_Window);
}
/* Keydown */
void Java_org_libsdl_app_SDLActivity_onNativeKeyDown(
JNIEnv* env, jclass jcls, jint keycode)
{
Android_OnKeyDown(keycode);
}
// Keyup
/* Keyup */
void Java_org_libsdl_app_SDLActivity_onNativeKeyUp(
JNIEnv* env, jclass jcls, jint keycode)
{
Android_OnKeyUp(keycode);
}
// Keyboard Focus Lost
/* Keyboard Focus Lost */
void Java_org_libsdl_app_SDLActivity_onNativeKeyboardFocusLost(
JNIEnv* env, jclass jcls)
{
@@ -171,7 +228,7 @@ void Java_org_libsdl_app_SDLActivity_onNativeKeyboardFocusLost(
}
// Touch
/* Touch */
void Java_org_libsdl_app_SDLActivity_onNativeTouch(
JNIEnv* env, jclass jcls,
jint touch_device_id_in, jint pointer_finger_id_in,
@@ -180,7 +237,7 @@ void Java_org_libsdl_app_SDLActivity_onNativeTouch(
Android_OnTouch(touch_device_id_in, pointer_finger_id_in, action, x, y, p);
}
// Accelerometer
/* Accelerometer */
void Java_org_libsdl_app_SDLActivity_onNativeAccel(
JNIEnv* env, jclass jcls,
jfloat x, jfloat y, jfloat z)
@@ -191,23 +248,23 @@ void Java_org_libsdl_app_SDLActivity_onNativeAccel(
bHasNewData = true;
}
// Low memory
/* Low memory */
void Java_org_libsdl_app_SDLActivity_nativeLowMemory(
JNIEnv* env, jclass cls)
{
SDL_SendAppEvent(SDL_APP_LOWMEMORY);
}
// Quit
/* Quit */
void Java_org_libsdl_app_SDLActivity_nativeQuit(
JNIEnv* env, jclass cls)
{
// Inject a SDL_QUIT event
/* Inject a SDL_QUIT event */
SDL_SendQuit();
SDL_SendAppEvent(SDL_APP_TERMINATING);
}
// Pause
/* Pause */
void Java_org_libsdl_app_SDLActivity_nativePause(
JNIEnv* env, jclass cls)
{
@@ -223,7 +280,7 @@ void Java_org_libsdl_app_SDLActivity_nativePause(
SDL_SendAppEvent(SDL_APP_DIDENTERBACKGROUND);
}
// Resume
/* Resume */
void Java_org_libsdl_app_SDLActivity_nativeResume(
JNIEnv* env, jclass cls)
{
@@ -317,47 +374,17 @@ static SDL_bool LocalReferenceHolder_IsActive()
return s_active > 0;
}
SDL_bool Android_JNI_CreateContext(int majorVersion, int minorVersion,
int red, int green, int blue, int alpha,
int buffer, int depth, int stencil,
int buffers, int samples)
ANativeWindow* Android_JNI_GetNativeWindow(void)
{
ANativeWindow* anw;
jobject s;
JNIEnv *env = Android_JNI_GetEnv();
jint attribs[] = {
EGL_RED_SIZE, red,
EGL_GREEN_SIZE, green,
EGL_BLUE_SIZE, blue,
EGL_ALPHA_SIZE, alpha,
EGL_BUFFER_SIZE, buffer,
EGL_DEPTH_SIZE, depth,
EGL_STENCIL_SIZE, stencil,
EGL_SAMPLE_BUFFERS, buffers,
EGL_SAMPLES, samples,
EGL_RENDERABLE_TYPE, (majorVersion == 1 ? EGL_OPENGL_ES_BIT : EGL_OPENGL_ES2_BIT),
EGL_NONE
};
int len = SDL_arraysize(attribs);
jintArray array;
array = (*env)->NewIntArray(env, len);
(*env)->SetIntArrayRegion(env, array, 0, len, attribs);
jboolean success = (*env)->CallStaticBooleanMethod(env, mActivityClass, midCreateGLContext, majorVersion, minorVersion, array);
(*env)->DeleteLocalRef(env, array);
return success ? SDL_TRUE : SDL_FALSE;
}
SDL_bool Android_JNI_DeleteContext(void)
{
/* There's only one context, so no parameter for now */
JNIEnv *env = Android_JNI_GetEnv();
(*env)->CallStaticVoidMethod(env, mActivityClass, midDeleteGLContext);
return SDL_TRUE;
s = (*env)->CallStaticObjectMethod(env, mActivityClass, midGetNativeSurface);
anw = ANativeWindow_fromSurface(env, s);
(*env)->DeleteLocalRef(env, s);
return anw;
}
void Android_JNI_SwapWindow()
@@ -441,9 +468,9 @@ int Android_JNI_SetupThread(void) {
return 1;
}
//
// Audio support
//
/*
* Audio support
*/
static jboolean audioBuffer16Bit = JNI_FALSE;
static jboolean audioBufferStereo = JNI_FALSE;
static jobject audioBuffer = NULL;
@@ -541,8 +568,8 @@ void Android_JNI_CloseAudioDevice()
}
}
// Test for an exception and call SDL_SetError with its detail if one occurs
// If the parameter silent is truthy then SDL_SetError() will not be called.
/* Test for an exception and call SDL_SetError with its detail if one occurs */
/* If the parameter silent is truthy then SDL_SetError() will not be called. */
static bool Android_JNI_ExceptionOccurred(bool silent)
{
SDL_assert(LocalReferenceHolder_IsActive());
@@ -552,7 +579,7 @@ static bool Android_JNI_ExceptionOccurred(bool silent)
if (exception != NULL) {
jmethodID mid;
// Until this happens most JNI operations have undefined behaviour
/* Until this happens most JNI operations have undefined behaviour */
(*mEnv)->ExceptionClear(mEnv);
if (!silent) {
@@ -608,13 +635,13 @@ static int Internal_Android_JNI_FileOpen(SDL_RWops* ctx)
fileNameJString = (jstring)ctx->hidden.androidio.fileNameRef;
ctx->hidden.androidio.position = 0;
// context = SDLActivity.getContext();
/* context = SDLActivity.getContext(); */
mid = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass,
"getContext","()Landroid/content/Context;");
context = (*mEnv)->CallStaticObjectMethod(mEnv, mActivityClass, mid);
// assetManager = context.getAssets();
/* assetManager = context.getAssets(); */
mid = (*mEnv)->GetMethodID(mEnv, (*mEnv)->GetObjectClass(mEnv, context),
"getAssets", "()Landroid/content/res/AssetManager;");
assetManager = (*mEnv)->CallObjectMethod(mEnv, context, mid);
@@ -647,34 +674,35 @@ static int Internal_Android_JNI_FileOpen(SDL_RWops* ctx)
ctx->hidden.androidio.fd = (*mEnv)->GetIntField(mEnv, fd, descriptor);
ctx->hidden.androidio.assetFileDescriptorRef = (*mEnv)->NewGlobalRef(mEnv, inputStream);
// Seek to the correct offset in the file.
/* Seek to the correct offset in the file. */
lseek(ctx->hidden.androidio.fd, (off_t)ctx->hidden.androidio.offset, SEEK_SET);
if (false) {
fallback:
// Disabled log message because of spam on the Nexus 7
//__android_log_print(ANDROID_LOG_DEBUG, "SDL", "Falling back to legacy InputStream method for opening file");
/* Disabled log message because of spam on the Nexus 7 */
/* __android_log_print(ANDROID_LOG_DEBUG, "SDL", "Falling back to legacy InputStream method for opening file"); */
/* Try the old method using InputStream */
ctx->hidden.androidio.assetFileDescriptorRef = NULL;
// inputStream = assetManager.open(<filename>);
/* inputStream = assetManager.open(<filename>); */
mid = (*mEnv)->GetMethodID(mEnv, (*mEnv)->GetObjectClass(mEnv, assetManager),
"open", "(Ljava/lang/String;I)Ljava/io/InputStream;");
inputStream = (*mEnv)->CallObjectMethod(mEnv, assetManager, mid, fileNameJString, 1 /*ACCESS_RANDOM*/);
inputStream = (*mEnv)->CallObjectMethod(mEnv, assetManager, mid, fileNameJString, 1 /* ACCESS_RANDOM */);
if (Android_JNI_ExceptionOccurred(false)) {
goto failure;
}
ctx->hidden.androidio.inputStreamRef = (*mEnv)->NewGlobalRef(mEnv, inputStream);
// Despite all the visible documentation on [Asset]InputStream claiming
// that the .available() method is not guaranteed to return the entire file
// size, comments in <sdk>/samples/<ver>/ApiDemos/src/com/example/ ...
// android/apis/content/ReadAsset.java imply that Android's
// AssetInputStream.available() /will/ always return the total file size
// size = inputStream.available();
/* Despite all the visible documentation on [Asset]InputStream claiming
* that the .available() method is not guaranteed to return the entire file
* size, comments in <sdk>/samples/<ver>/ApiDemos/src/com/example/ ...
* android/apis/content/ReadAsset.java imply that Android's
* AssetInputStream.available() /will/ always return the total file size
*/
/* size = inputStream.available(); */
mid = (*mEnv)->GetMethodID(mEnv, (*mEnv)->GetObjectClass(mEnv, inputStream),
"available", "()I");
ctx->hidden.androidio.size = (long)(*mEnv)->CallIntMethod(mEnv, inputStream, mid);
@@ -682,7 +710,7 @@ fallback:
goto failure;
}
// readableByteChannel = Channels.newChannel(inputStream);
/* readableByteChannel = Channels.newChannel(inputStream); */
channels = (*mEnv)->FindClass(mEnv, "java/nio/channels/Channels");
mid = (*mEnv)->GetStaticMethodID(mEnv, channels,
"newChannel",
@@ -696,7 +724,7 @@ fallback:
ctx->hidden.androidio.readableByteChannelRef =
(*mEnv)->NewGlobalRef(mEnv, readableByteChannel);
// Store .read id for reading purposes
/* Store .read id for reading purposes */
mid = (*mEnv)->GetMethodID(mEnv, (*mEnv)->GetObjectClass(mEnv, readableByteChannel),
"read", "(Ljava/nio/ByteBuffer;)I");
ctx->hidden.androidio.readMethod = mid;
@@ -762,7 +790,7 @@ size_t Android_JNI_FileRead(SDL_RWops* ctx, void* buffer,
if (ctx->hidden.androidio.assetFileDescriptorRef) {
size_t bytesMax = size * maxnum;
if (ctx->hidden.androidio.size != -1 /*UNKNOWN_LENGTH*/ && ctx->hidden.androidio.position + bytesMax > ctx->hidden.androidio.size) {
if (ctx->hidden.androidio.size != -1 /* UNKNOWN_LENGTH */ && ctx->hidden.androidio.position + bytesMax > ctx->hidden.androidio.size) {
bytesMax = ctx->hidden.androidio.size - ctx->hidden.androidio.position;
}
size_t result = read(ctx->hidden.androidio.fd, buffer, bytesMax );
@@ -792,7 +820,7 @@ size_t Android_JNI_FileRead(SDL_RWops* ctx, void* buffer,
jobject byteBuffer = (*mEnv)->NewDirectByteBuffer(mEnv, buffer, bytesRemaining);
while (bytesRemaining > 0) {
// result = readableByteChannel.read(...);
/* result = readableByteChannel.read(...); */
int result = (*mEnv)->CallIntMethod(mEnv, readableByteChannel, readMethod, byteBuffer);
if (Android_JNI_ExceptionOccurred(false)) {
@@ -850,7 +878,7 @@ static int Internal_Android_JNI_FileClose(SDL_RWops* ctx, bool release)
else {
jobject inputStream = (jobject)ctx->hidden.androidio.inputStreamRef;
// inputStream.close();
/* inputStream.close(); */
jmethodID mid = (*mEnv)->GetMethodID(mEnv, (*mEnv)->GetObjectClass(mEnv, inputStream),
"close", "()V");
(*mEnv)->CallVoidMethod(mEnv, inputStream, mid);
@@ -881,12 +909,12 @@ Sint64 Android_JNI_FileSeek(SDL_RWops* ctx, Sint64 offset, int whence)
if (ctx->hidden.androidio.assetFileDescriptorRef) {
switch (whence) {
case RW_SEEK_SET:
if (ctx->hidden.androidio.size != -1 /*UNKNOWN_LENGTH*/ && offset > ctx->hidden.androidio.size) offset = ctx->hidden.androidio.size;
if (ctx->hidden.androidio.size != -1 /* UNKNOWN_LENGTH */ && offset > ctx->hidden.androidio.size) offset = ctx->hidden.androidio.size;
offset += ctx->hidden.androidio.offset;
break;
case RW_SEEK_CUR:
offset += ctx->hidden.androidio.position;
if (ctx->hidden.androidio.size != -1 /*UNKNOWN_LENGTH*/ && offset > ctx->hidden.androidio.size) offset = ctx->hidden.androidio.size;
if (ctx->hidden.androidio.size != -1 /* UNKNOWN_LENGTH */ && offset > ctx->hidden.androidio.size) offset = ctx->hidden.androidio.size;
offset += ctx->hidden.androidio.offset;
break;
case RW_SEEK_END:
@@ -929,7 +957,7 @@ Sint64 Android_JNI_FileSeek(SDL_RWops* ctx, Sint64 offset, int whence)
if (movement > 0) {
unsigned char buffer[4096];
// The easy case where we're seeking forwards
/* The easy case where we're seeking forwards */
while (movement > 0) {
Sint64 amount = sizeof (buffer);
if (amount > movement) {
@@ -937,7 +965,7 @@ Sint64 Android_JNI_FileSeek(SDL_RWops* ctx, Sint64 offset, int whence)
}
size_t result = Android_JNI_FileRead(ctx, buffer, 1, amount);
if (result <= 0) {
// Failed to read/skip the required amount, so fail
/* Failed to read/skip the required amount, so fail */
return -1;
}
@@ -945,8 +973,8 @@ Sint64 Android_JNI_FileSeek(SDL_RWops* ctx, Sint64 offset, int whence)
}
} else if (movement < 0) {
// We can't seek backwards so we have to reopen the file and seek
// forwards which obviously isn't very efficient
/* We can't seek backwards so we have to reopen the file and seek */
/* forwards which obviously isn't very efficient */
Internal_Android_JNI_FileClose(ctx, false);
Internal_Android_JNI_FileOpen(ctx);
Android_JNI_FileSeek(ctx, newPosition, RW_SEEK_SET);
@@ -962,7 +990,7 @@ int Android_JNI_FileClose(SDL_RWops* ctx)
return Internal_Android_JNI_FileClose(ctx, true);
}
// returns a new global reference which needs to be released later
/* returns a new global reference which needs to be released later */
static jobject Android_JNI_GetSystemServiceObject(const char* name)
{
struct LocalReferenceHolder refs = LocalReferenceHolder_Setup(__FUNCTION__);
@@ -1062,9 +1090,10 @@ SDL_bool Android_JNI_HasClipboardText()
}
// returns 0 on success or -1 on error (others undefined then)
// returns truthy or falsy value in plugged, charged and battery
// returns the value in seconds and percent or -1 if not available
/* returns 0 on success or -1 on error (others undefined then)
* returns truthy or falsy value in plugged, charged and battery
* returns the value in seconds and percent or -1 if not available
*/
int Android_JNI_GetPowerInfo(int* plugged, int* charged, int* battery, int* seconds, int* percent)
{
struct LocalReferenceHolder refs = LocalReferenceHolder_Setup(__FUNCTION__);
@@ -1112,38 +1141,38 @@ int Android_JNI_GetPowerInfo(int* plugged, int* charged, int* battery, int* seco
(*env)->DeleteLocalRef(env, bname);
if (plugged) {
GET_INT_EXTRA(plug, "plugged") // == BatteryManager.EXTRA_PLUGGED (API 5)
GET_INT_EXTRA(plug, "plugged") /* == BatteryManager.EXTRA_PLUGGED (API 5) */
if (plug == -1) {
LocalReferenceHolder_Cleanup(&refs);
return -1;
}
// 1 == BatteryManager.BATTERY_PLUGGED_AC
// 2 == BatteryManager.BATTERY_PLUGGED_USB
/* 1 == BatteryManager.BATTERY_PLUGGED_AC */
/* 2 == BatteryManager.BATTERY_PLUGGED_USB */
*plugged = (0 < plug) ? 1 : 0;
}
if (charged) {
GET_INT_EXTRA(status, "status") // == BatteryManager.EXTRA_STATUS (API 5)
GET_INT_EXTRA(status, "status") /* == BatteryManager.EXTRA_STATUS (API 5) */
if (status == -1) {
LocalReferenceHolder_Cleanup(&refs);
return -1;
}
// 5 == BatteryManager.BATTERY_STATUS_FULL
/* 5 == BatteryManager.BATTERY_STATUS_FULL */
*charged = (status == 5) ? 1 : 0;
}
if (battery) {
GET_BOOL_EXTRA(present, "present") // == BatteryManager.EXTRA_PRESENT (API 5)
GET_BOOL_EXTRA(present, "present") /* == BatteryManager.EXTRA_PRESENT (API 5) */
*battery = present ? 1 : 0;
}
if (seconds) {
*seconds = -1; // not possible
*seconds = -1; /* not possible */
}
if (percent) {
GET_INT_EXTRA(level, "level") // == BatteryManager.EXTRA_LEVEL (API 5)
GET_INT_EXTRA(scale, "scale") // == BatteryManager.EXTRA_SCALE (API 5)
GET_INT_EXTRA(level, "level") /* == BatteryManager.EXTRA_LEVEL (API 5) */
GET_INT_EXTRA(scale, "scale") /* == BatteryManager.EXTRA_SCALE (API 5) */
if ((level == -1) || (scale == -1)) {
LocalReferenceHolder_Cleanup(&refs);
return -1;
@@ -1157,7 +1186,33 @@ int Android_JNI_GetPowerInfo(int* plugged, int* charged, int* battery, int* seco
return 0;
}
// sends message to be handled on the UI event dispatch thread
/* returns number of found touch devices as return value and ids in parameter ids */
int Android_JNI_GetTouchDeviceIds(int **ids) {
JNIEnv *env = Android_JNI_GetEnv();
jint sources = 4098; /* == InputDevice.SOURCE_TOUCHSCREEN */
jmethodID mid = (*env)->GetStaticMethodID(env, mActivityClass, "inputGetInputDeviceIds", "(I)[I");
jintArray array = (jintArray) (*env)->CallStaticObjectMethod(env, mActivityClass, mid, sources);
int number = 0;
*ids = NULL;
if (array) {
number = (int) (*env)->GetArrayLength(env, array);
if (0 < number) {
jint* elements = (*env)->GetIntArrayElements(env, array, NULL);
if (elements) {
int i;
*ids = SDL_malloc(number * sizeof (**ids));
for (i = 0; i < number; ++i) { /* not assuming sizeof (jint) == sizeof (int) */
(*ids)[i] = elements[i];
}
(*env)->ReleaseIntArrayElements(env, array, elements, JNI_ABORT);
}
}
(*env)->DeleteLocalRef(env, array);
}
return number;
}
/* sends message to be handled on the UI event dispatch thread */
int Android_JNI_SendMessage(int command, int param)
{
JNIEnv *env = Android_JNI_GetEnv();
@@ -1192,15 +1247,17 @@ void Android_JNI_ShowTextInput(SDL_Rect *inputRect)
void Android_JNI_HideTextInput()
{
// has to match Activity constant
/* has to match Activity constant */
const int COMMAND_TEXTEDIT_HIDE = 3;
Android_JNI_SendMessage(COMMAND_TEXTEDIT_HIDE, 0);
}
/*
//////////////////////////////////////////////////////////////////////////////
//
// Functions exposed to SDL applications in SDL_system.h
//
//////////////////////////////////////////////////////////////////////////////
*/
void *SDL_AndroidGetJNIEnv()
{
@@ -1220,7 +1277,7 @@ void *SDL_AndroidGetActivity()
return NULL;
}
// return SDLActivity.getContext();
/* return SDLActivity.getContext(); */
mid = (*env)->GetStaticMethodID(env, mActivityClass,
"getContext","()Landroid/content/Context;");
return (*env)->CallStaticObjectMethod(env, mActivityClass, mid);
@@ -1244,12 +1301,12 @@ const char * SDL_AndroidGetInternalStoragePath()
return NULL;
}
// context = SDLActivity.getContext();
/* context = SDLActivity.getContext(); */
mid = (*env)->GetStaticMethodID(env, mActivityClass,
"getContext","()Landroid/content/Context;");
context = (*env)->CallStaticObjectMethod(env, mActivityClass, mid);
// fileObj = context.getFilesDir();
/* fileObj = context.getFilesDir(); */
mid = (*env)->GetMethodID(env, (*env)->GetObjectClass(env, context),
"getFilesDir", "()Ljava/io/File;");
fileObject = (*env)->CallObjectMethod(env, context, mid);
@@ -1259,7 +1316,7 @@ const char * SDL_AndroidGetInternalStoragePath()
return NULL;
}
// path = fileObject.getAbsolutePath();
/* path = fileObject.getAbsolutePath(); */
mid = (*env)->GetMethodID(env, (*env)->GetObjectClass(env, fileObject),
"getAbsolutePath", "()Ljava/lang/String;");
pathString = (jstring)(*env)->CallObjectMethod(env, fileObject, mid);
@@ -1295,7 +1352,7 @@ int SDL_AndroidGetExternalStorageState()
state = (*env)->GetStringUTFChars(env, stateString, NULL);
// Print an info message so people debugging know the storage state
/* Print an info message so people debugging know the storage state */
__android_log_print(ANDROID_LOG_INFO, "SDL", "external storage state: %s", state);
if (SDL_strcmp(state, "mounted") == 0) {
@@ -1330,12 +1387,12 @@ const char * SDL_AndroidGetExternalStoragePath()
return NULL;
}
// context = SDLActivity.getContext();
/* context = SDLActivity.getContext(); */
mid = (*env)->GetStaticMethodID(env, mActivityClass,
"getContext","()Landroid/content/Context;");
context = (*env)->CallStaticObjectMethod(env, mActivityClass, mid);
// fileObj = context.getExternalFilesDir();
/* fileObj = context.getExternalFilesDir(); */
mid = (*env)->GetMethodID(env, (*env)->GetObjectClass(env, context),
"getExternalFilesDir", "(Ljava/lang/String;)Ljava/io/File;");
fileObject = (*env)->CallObjectMethod(env, context, mid, NULL);
@@ -1345,7 +1402,7 @@ const char * SDL_AndroidGetExternalStoragePath()
return NULL;
}
// path = fileObject.getAbsolutePath();
/* path = fileObject.getAbsolutePath(); */
mid = (*env)->GetMethodID(env, (*env)->GetObjectClass(env, fileObject),
"getAbsolutePath", "()Ljava/lang/String;");
pathString = (jstring)(*env)->CallObjectMethod(env, fileObject, mid);

View File

@@ -27,16 +27,20 @@ extern "C" {
/* *INDENT-ON* */
#endif
#include <EGL/eglplatform.h>
#include <android/native_window_jni.h>
#include "SDL_rect.h"
/* Interface from the SDL library into the Android Java activity */
extern SDL_bool Android_JNI_CreateContext(int majorVersion, int minorVersion, int red, int green, int blue, int alpha, int buffer, int depth, int stencil, int buffers, int samples);
extern SDL_bool Android_JNI_DeleteContext(void);
/* extern SDL_bool Android_JNI_CreateContext(int majorVersion, int minorVersion, int red, int green, int blue, int alpha, int buffer, int depth, int stencil, int buffers, int samples);
extern SDL_bool Android_JNI_DeleteContext(void); */
extern void Android_JNI_SwapWindow();
extern void Android_JNI_SetActivityTitle(const char *title);
extern SDL_bool Android_JNI_GetAccelerometerValues(float values[3]);
extern void Android_JNI_ShowTextInput(SDL_Rect *inputRect);
extern void Android_JNI_HideTextInput();
extern ANativeWindow* Android_JNI_GetNativeWindow(void);
/* Audio support */
extern int Android_JNI_OpenAudioDevice(int sampleRate, int is16Bit, int channelCount, int desiredBufferFrames);
@@ -61,6 +65,9 @@ SDL_bool Android_JNI_HasClipboardText();
/* Power support */
int Android_JNI_GetPowerInfo(int* plugged, int* charged, int* battery, int* seconds, int* percent);
/* Touch support */
int Android_JNI_GetTouchDeviceIds(int **ids);
/* Threads */
#include <jni.h>
JNIEnv *Android_JNI_GetEnv(void);

398
src/core/linux/SDL_udev.c Normal file
View File

@@ -0,0 +1,398 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
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.
*/
/*
* To list the properties of a device, try something like:
* udevadm info -a -n snd/hwC0D0 (for a sound card)
* udevadm info --query=all -n input/event3 (for a keyboard, mouse, etc)
* udevadm info --query=property -n input/event2
*/
#include "SDL_udev.h"
#ifdef SDL_USE_LIBUDEV
static char* SDL_UDEV_LIBS[] = { "libudev.so.1", "libudev.so.0" };
#define _THIS SDL_UDEV_PrivateData *_this
static _THIS = NULL;
#include "SDL.h"
static SDL_bool SDL_UDEV_load_sym(const char *fn, void **addr);
static int SDL_UDEV_load_syms(void);
static SDL_bool SDL_UDEV_hotplug_update_available(void);
static void device_event(SDL_UDEV_deviceevent type, struct udev_device *dev);
static SDL_bool
SDL_UDEV_load_sym(const char *fn, void **addr)
{
*addr = SDL_LoadFunction(_this->udev_handle, fn);
if (*addr == NULL) {
/* Don't call SDL_SetError(): SDL_LoadFunction already did. */
return SDL_FALSE;
}
return SDL_TRUE;
}
static int
SDL_UDEV_load_syms(void)
{
/* cast funcs to char* first, to please GCC's strict aliasing rules. */
#define SDL_UDEV_SYM(x) \
if (!SDL_UDEV_load_sym(#x, (void **) (char *) & _this->x)) return -1
SDL_UDEV_SYM(udev_device_get_action);
SDL_UDEV_SYM(udev_device_get_devnode);
SDL_UDEV_SYM(udev_device_get_subsystem);
SDL_UDEV_SYM(udev_device_get_property_value);
SDL_UDEV_SYM(udev_device_new_from_syspath);
SDL_UDEV_SYM(udev_device_unref);
SDL_UDEV_SYM(udev_enumerate_add_match_property);
SDL_UDEV_SYM(udev_enumerate_add_match_subsystem);
SDL_UDEV_SYM(udev_enumerate_get_list_entry);
SDL_UDEV_SYM(udev_enumerate_new);
SDL_UDEV_SYM(udev_enumerate_scan_devices);
SDL_UDEV_SYM(udev_enumerate_unref);
SDL_UDEV_SYM(udev_list_entry_get_name);
SDL_UDEV_SYM(udev_list_entry_get_next);
SDL_UDEV_SYM(udev_monitor_enable_receiving);
SDL_UDEV_SYM(udev_monitor_filter_add_match_subsystem_devtype);
SDL_UDEV_SYM(udev_monitor_get_fd);
SDL_UDEV_SYM(udev_monitor_new_from_netlink);
SDL_UDEV_SYM(udev_monitor_receive_device);
SDL_UDEV_SYM(udev_monitor_unref);
SDL_UDEV_SYM(udev_new);
SDL_UDEV_SYM(udev_unref);
SDL_UDEV_SYM(udev_device_new_from_devnum);
SDL_UDEV_SYM(udev_device_get_devnum);
#undef SDL_UDEV_SYM
return 0;
}
static SDL_bool
SDL_UDEV_hotplug_update_available(void)
{
if (_this->udev_mon != NULL) {
const int fd = _this->udev_monitor_get_fd(_this->udev_mon);
fd_set fds;
struct timeval tv;
FD_ZERO(&fds);
FD_SET(fd, &fds);
tv.tv_sec = 0;
tv.tv_usec = 0;
if ((select(fd+1, &fds, NULL, NULL, &tv) > 0) && (FD_ISSET(fd, &fds))) {
return SDL_TRUE;
}
}
return SDL_FALSE;
}
int
SDL_UDEV_Init(void)
{
int retval = 0;
if (_this == NULL) {
_this = (SDL_UDEV_PrivateData *) SDL_calloc(1, sizeof(*_this));
if(_this == NULL) {
return SDL_OutOfMemory();
}
retval = SDL_UDEV_LoadLibrary();
if (retval < 0) {
SDL_UDEV_Quit();
return retval;
}
/* Set up udev monitoring
* Listen for input devices (mouse, keyboard, joystick, etc) and sound devices
*/
_this->udev = _this->udev_new();
if (_this->udev == NULL) {
SDL_UDEV_Quit();
return SDL_SetError("udev_new() failed");
}
_this->udev_mon = _this->udev_monitor_new_from_netlink(_this->udev, "udev");
if (_this->udev_mon == NULL) {
SDL_UDEV_Quit();
return SDL_SetError("udev_monitor_new_from_netlink() failed");
}
_this->udev_monitor_filter_add_match_subsystem_devtype(_this->udev_mon, "input", NULL);
_this->udev_monitor_filter_add_match_subsystem_devtype(_this->udev_mon, "sound", NULL);
_this->udev_monitor_enable_receiving(_this->udev_mon);
/* Do an initial scan of existing devices */
SDL_UDEV_Scan();
}
_this->ref_count += 1;
return retval;
}
void
SDL_UDEV_Quit(void)
{
SDL_UDEV_CallbackList *item;
if (_this == NULL) {
return;
}
_this->ref_count -= 1;
if (_this->ref_count < 1) {
if (_this->udev_mon != NULL) {
_this->udev_monitor_unref(_this->udev_mon);
_this->udev_mon = NULL;
}
if (_this->udev != NULL) {
_this->udev_unref(_this->udev);
_this->udev = NULL;
}
/* Remove existing devices */
while (_this->first != NULL) {
item = _this->first;
_this->first = _this->first->next;
SDL_free(item);
}
SDL_UDEV_UnloadLibrary();
SDL_free(_this);
_this = NULL;
}
}
void
SDL_UDEV_Scan(void)
{
struct udev_enumerate *enumerate = NULL;
struct udev_list_entry *devs = NULL;
struct udev_list_entry *item = NULL;
if (_this == NULL) {
return;
}
enumerate = _this->udev_enumerate_new(_this->udev);
if (enumerate == NULL) {
SDL_UDEV_Quit();
SDL_SetError("udev_monitor_new_from_netlink() failed");
return;
}
_this->udev_enumerate_add_match_subsystem(enumerate, "input");
_this->udev_enumerate_add_match_subsystem(enumerate, "sound");
_this->udev_enumerate_scan_devices(enumerate);
devs = _this->udev_enumerate_get_list_entry(enumerate);
for (item = devs; item; item = _this->udev_list_entry_get_next(item)) {
const char *path = _this->udev_list_entry_get_name(item);
struct udev_device *dev = _this->udev_device_new_from_syspath(_this->udev, path);
if (dev != NULL) {
device_event(SDL_UDEV_DEVICEADDED, dev);
_this->udev_device_unref(dev);
}
}
_this->udev_enumerate_unref(enumerate);
}
void
SDL_UDEV_UnloadLibrary(void)
{
if (_this == NULL) {
return;
}
if (_this->udev_handle != NULL) {
SDL_UnloadObject(_this->udev_handle);
_this->udev_handle = NULL;
}
}
int
SDL_UDEV_LoadLibrary(void)
{
int retval = 0, i;
if (_this == NULL) {
return SDL_SetError("UDEV not initialized");
}
if (_this->udev_handle == NULL) {
for( i = 0 ; i < SDL_arraysize(SDL_UDEV_LIBS); i++) {
_this->udev_handle = SDL_LoadObject(SDL_UDEV_LIBS[i]);
if (_this->udev_handle != NULL) {
retval = SDL_UDEV_load_syms();
if (retval < 0) {
SDL_UDEV_UnloadLibrary();
}
else {
break;
}
}
}
if (_this->udev_handle == NULL) {
retval = -1;
/* Don't call SDL_SetError(): SDL_LoadObject already did. */
}
}
return retval;
}
static void
device_event(SDL_UDEV_deviceevent type, struct udev_device *dev)
{
const char *subsystem;
const char *val = NULL;
int devclass = 0;
const char *path;
SDL_UDEV_CallbackList *item;
path = _this->udev_device_get_devnode(dev);
if (path == NULL) {
return;
}
subsystem = _this->udev_device_get_subsystem(dev);
if (SDL_strcmp(subsystem, "sound") == 0) {
devclass = SDL_UDEV_DEVICE_SOUND;
} else if (SDL_strcmp(subsystem, "input") == 0) {
val = _this->udev_device_get_property_value(dev, "ID_INPUT_JOYSTICK");
if (val != NULL && SDL_strcmp(val, "1") == 0 ) {
devclass |= SDL_UDEV_DEVICE_JOYSTICK;
}
val = _this->udev_device_get_property_value(dev, "ID_INPUT_MOUSE");
if (val != NULL && SDL_strcmp(val, "1") == 0 ) {
devclass |= SDL_UDEV_DEVICE_MOUSE;
}
val = _this->udev_device_get_property_value(dev, "ID_INPUT_KEYBOARD");
if (val != NULL && SDL_strcmp(val, "1") == 0 ) {
devclass |= SDL_UDEV_DEVICE_KEYBOARD;
}
if (devclass == 0) {
return;
}
} else {
return;
}
/* Process callbacks */
for (item = _this->first; item != NULL; item = item->next) {
item->callback(type, devclass, path);
}
}
void
SDL_UDEV_Poll(void)
{
struct udev_device *dev = NULL;
const char *action = NULL;
if (_this == NULL) {
return;
}
while (SDL_UDEV_hotplug_update_available()) {
dev = _this->udev_monitor_receive_device(_this->udev_mon);
if (dev == NULL) {
break;
}
action = _this->udev_device_get_action(dev);
if (SDL_strcmp(action, "add") == 0) {
device_event(SDL_UDEV_DEVICEADDED, dev);
} else if (SDL_strcmp(action, "remove") == 0) {
device_event(SDL_UDEV_DEVICEREMOVED, dev);
}
_this->udev_device_unref(dev);
}
}
int
SDL_UDEV_AddCallback(SDL_UDEV_Callback cb)
{
SDL_UDEV_CallbackList *item;
item = (SDL_UDEV_CallbackList *) SDL_calloc(1, sizeof (SDL_UDEV_CallbackList));
if (item == NULL) {
return SDL_OutOfMemory();
}
item->callback = cb;
if (_this->last == NULL) {
_this->first = _this->last = item;
} else {
_this->last->next = item;
_this->last = item;
}
return 1;
}
void
SDL_UDEV_DelCallback(SDL_UDEV_Callback cb)
{
SDL_UDEV_CallbackList *item;
SDL_UDEV_CallbackList *prev = NULL;
for (item = _this->first; item != NULL; item = item->next) {
/* found it, remove it. */
if (item->callback == cb) {
if (prev != NULL) {
prev->next = item->next;
} else {
SDL_assert(_this->first == item);
_this->first = item->next;
}
if (item == _this->last) {
_this->last = prev;
}
SDL_free(item);
return;
}
prev = item;
}
}
#endif /* SDL_USE_LIBUDEV */

115
src/core/linux/SDL_udev.h Normal file
View File

@@ -0,0 +1,115 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
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"
#ifndef _SDL_udev_h
#define _SDL_udev_h
#if HAVE_LIBUDEV_H
#ifndef SDL_USE_LIBUDEV
#define SDL_USE_LIBUDEV 1
#endif
#include "SDL_loadso.h"
#include "SDL_events.h"
#include <libudev.h>
#include <sys/time.h>
#include <sys/types.h>
/**
* \brief Device type
*/
typedef enum
{
SDL_UDEV_DEVICEADDED = 0x0001,
SDL_UDEV_DEVICEREMOVED
} SDL_UDEV_deviceevent;
/* A device can be any combination of these classes */
typedef enum
{
SDL_UDEV_DEVICE_MOUSE = 0x0001,
SDL_UDEV_DEVICE_KEYBOARD = 0x0002,
SDL_UDEV_DEVICE_JOYSTICK = 0x0004,
SDL_UDEV_DEVICE_SOUND = 0x0008
} SDL_UDEV_deviceclass;
typedef void (*SDL_UDEV_Callback)(SDL_UDEV_deviceevent udev_type, int udev_class, const char *devpath);
typedef struct SDL_UDEV_CallbackList {
SDL_UDEV_Callback callback;
struct SDL_UDEV_CallbackList *next;
} SDL_UDEV_CallbackList;
typedef struct SDL_UDEV_PrivateData
{
const char *udev_library;
void *udev_handle;
struct udev *udev;
struct udev_monitor *udev_mon;
int ref_count;
SDL_UDEV_CallbackList *first, *last;
/* Function pointers */
const char *(*udev_device_get_action)(struct udev_device *);
const char *(*udev_device_get_devnode)(struct udev_device *);
const char *(*udev_device_get_subsystem)(struct udev_device *);
const char *(*udev_device_get_property_value)(struct udev_device *, const char *);
struct udev_device *(*udev_device_new_from_syspath)(struct udev *, const char *);
void (*udev_device_unref)(struct udev_device *);
int (*udev_enumerate_add_match_property)(struct udev_enumerate *, const char *, const char *);
int (*udev_enumerate_add_match_subsystem)(struct udev_enumerate *, const char *);
struct udev_list_entry *(*udev_enumerate_get_list_entry)(struct udev_enumerate *);
struct udev_enumerate *(*udev_enumerate_new)(struct udev *);
int (*udev_enumerate_scan_devices)(struct udev_enumerate *);
void (*udev_enumerate_unref)(struct udev_enumerate *);
const char *(*udev_list_entry_get_name)(struct udev_list_entry *);
struct udev_list_entry *(*udev_list_entry_get_next)(struct udev_list_entry *);
int (*udev_monitor_enable_receiving)(struct udev_monitor *);
int (*udev_monitor_filter_add_match_subsystem_devtype)(struct udev_monitor *, const char *, const char *);
int (*udev_monitor_get_fd)(struct udev_monitor *);
struct udev_monitor *(*udev_monitor_new_from_netlink)(struct udev *, const char *);
struct udev_device *(*udev_monitor_receive_device)(struct udev_monitor *);
void (*udev_monitor_unref)(struct udev_monitor *);
struct udev *(*udev_new)(void);
void (*udev_unref)(struct udev *);
struct udev_device * (*udev_device_new_from_devnum)(struct udev *udev, char type, dev_t devnum);
dev_t (*udev_device_get_devnum) (struct udev_device *udev_device);
} SDL_UDEV_PrivateData;
extern int SDL_UDEV_Init(void);
extern void SDL_UDEV_Quit(void);
extern void SDL_UDEV_UnloadLibrary(void);
extern int SDL_UDEV_LoadLibrary(void);
extern void SDL_UDEV_Poll(void);
extern void SDL_UDEV_Scan(void);
extern int SDL_UDEV_AddCallback(SDL_UDEV_Callback cb);
extern void SDL_UDEV_DelCallback(SDL_UDEV_Callback cb);
#endif /* HAVE_LIBUDEV_H */
#endif /* _SDL_udev_h */

View File

@@ -22,8 +22,8 @@
#if defined(__WIN32__) || defined(__WINRT__)
#include "SDL_error.h"
#include "SDL_windows.h"
#include "SDL_error.h"
#include "SDL_assert.h"
#include <objbase.h> /* for CoInitialize/CoUninitialize (Win32 only) */

View File

@@ -38,9 +38,10 @@
/* Routines to convert from UTF8 to native Windows text */
#if UNICODE
#define WIN_StringToUTF8(S) SDL_iconv_string("UTF-8", "UCS-2-INTERNAL", (char *)(S), (SDL_wcslen(S)+1)*sizeof(WCHAR))
#define WIN_UTF8ToString(S) (WCHAR *)SDL_iconv_string("UCS-2-INTERNAL", "UTF-8", (char *)(S), SDL_strlen(S)+1)
#define WIN_StringToUTF8(S) SDL_iconv_string("UTF-8", "UTF-16LE", (char *)(S), (SDL_wcslen(S)+1)*sizeof(WCHAR))
#define WIN_UTF8ToString(S) (WCHAR *)SDL_iconv_string("UTF-16LE", "UTF-8", (char *)(S), SDL_strlen(S)+1)
#else
/* !!! FIXME: UTF8ToString() can just be a SDL_strdup() here. */
#define WIN_StringToUTF8(S) SDL_iconv_string("UTF-8", "ASCII", (char *)(S), (SDL_strlen(S)+1))
#define WIN_UTF8ToString(S) SDL_iconv_string("ASCII", "UTF-8", (char *)(S), SDL_strlen(S)+1)
#endif