mirror of
https://github.com/encounter/SDL.git
synced 2025-12-14 07:36:09 +00:00
WinRT: merged with SDL 2.0.1 codebase
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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
398
src/core/linux/SDL_udev.c
Normal 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
115
src/core/linux/SDL_udev.h
Normal 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 */
|
||||
@@ -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) */
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user