mirror of
https://github.com/libsdl-org/SDL.git
synced 2026-09-20 17:46:09 +08:00
[Android] Hotplugging support for joysticks
This commit is contained in:
@@ -16,6 +16,7 @@ Android:
|
||||
* Joystick support (minimum SDK version required to build SDL is now 12,
|
||||
the required runtime version remains at 10, but on such devices joystick
|
||||
support won't be available).
|
||||
* Hotplugging support for joysticks
|
||||
|
||||
Linux:
|
||||
* Fixed fullscreen and focused behavior when receiving NotifyGrab events
|
||||
|
||||
@@ -256,9 +256,9 @@ public class SDLActivity extends Activity {
|
||||
public static native void nativePause();
|
||||
public static native void nativeResume();
|
||||
public static native void onNativeResize(int x, int y, int format);
|
||||
public static native int onNativePadDown(int padId, int keycode);
|
||||
public static native int onNativePadUp(int padId, int keycode);
|
||||
public static native void onNativeJoy(int joyId, int axis,
|
||||
public static native int onNativePadDown(int device_id, int keycode);
|
||||
public static native int onNativePadUp(int device_id, int keycode);
|
||||
public static native void onNativeJoy(int device_id, int axis,
|
||||
float value);
|
||||
public static native void onNativeKeyDown(int keycode);
|
||||
public static native void onNativeKeyUp(int keycode);
|
||||
@@ -270,6 +270,10 @@ public class SDLActivity extends Activity {
|
||||
public static native void onNativeSurfaceChanged();
|
||||
public static native void onNativeSurfaceDestroyed();
|
||||
public static native void nativeFlipBuffers();
|
||||
public static native int nativeAddJoystick(int device_id, String name,
|
||||
int is_accelerometer, int nbuttons,
|
||||
int naxes, int nhats, int nballs);
|
||||
public static native int nativeRemoveJoystick(int device_id);
|
||||
|
||||
public static void flipBuffers() {
|
||||
SDLActivity.nativeFlipBuffers();
|
||||
@@ -460,29 +464,16 @@ public class SDLActivity extends Activity {
|
||||
}
|
||||
|
||||
// Joystick glue code, just a series of stubs that redirect to the SDLJoystickHandler instance
|
||||
public static int getNumJoysticks() {
|
||||
return mJoystickHandler.getNumJoysticks();
|
||||
}
|
||||
|
||||
public static String getJoystickName(int joy) {
|
||||
return mJoystickHandler.getJoystickName(joy);
|
||||
}
|
||||
|
||||
public static int getJoystickAxes(int joy) {
|
||||
return mJoystickHandler.getJoystickAxes(joy);
|
||||
}
|
||||
|
||||
public static boolean handleJoystickMotionEvent(MotionEvent event) {
|
||||
return mJoystickHandler.handleMotionEvent(event);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param devId the device id to get opened joystick id for.
|
||||
* @return joystick id for device id or -1 if there is none.
|
||||
*/
|
||||
public static int getJoyId(int devId) {
|
||||
return mJoystickHandler.getJoyId(devId);
|
||||
public static void pollInputDevices() {
|
||||
if (SDLActivity.mSDLThread != null) {
|
||||
mJoystickHandler.pollInputDevices();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -660,16 +651,13 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
|
||||
|
||||
if ( (event.getSource() & 0x00000401) != 0 || /* API 12: SOURCE_GAMEPAD */
|
||||
(event.getSource() & InputDevice.SOURCE_DPAD) != 0 ) {
|
||||
int id = SDLActivity.getJoyId( event.getDeviceId() );
|
||||
if (id != -1) {
|
||||
if (event.getAction() == KeyEvent.ACTION_DOWN) {
|
||||
if (SDLActivity.onNativePadDown(id, keyCode) == 0) {
|
||||
return true;
|
||||
}
|
||||
} else if (event.getAction() == KeyEvent.ACTION_UP) {
|
||||
if (SDLActivity.onNativePadUp(id, keyCode) == 0) {
|
||||
return true;
|
||||
}
|
||||
if (event.getAction() == KeyEvent.ACTION_DOWN) {
|
||||
if (SDLActivity.onNativePadDown(event.getDeviceId(), keyCode) == 0) {
|
||||
return true;
|
||||
}
|
||||
} else if (event.getAction() == KeyEvent.ACTION_UP) {
|
||||
if (SDLActivity.onNativePadUp(event.getDeviceId(), keyCode) == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -916,36 +904,20 @@ class SDLInputConnection extends BaseInputConnection {
|
||||
|
||||
/* A null joystick handler for API level < 12 devices (the accelerometer is handled separately) */
|
||||
class SDLJoystickHandler {
|
||||
public int getNumJoysticks() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public String getJoystickName(int joy) {
|
||||
return "";
|
||||
}
|
||||
|
||||
public int getJoystickAxes(int joy) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param devId the device id to get opened joystick id for.
|
||||
* @return joystick id for device id or -1 if there is none.
|
||||
*/
|
||||
public int getJoyId(int devId) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
public boolean handleMotionEvent(MotionEvent event) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void pollInputDevices() {
|
||||
}
|
||||
}
|
||||
|
||||
/* Actual joystick functionality available for API >= 12 devices */
|
||||
class SDLJoystickHandler_API12 extends SDLJoystickHandler {
|
||||
|
||||
class SDLJoystick {
|
||||
public int id;
|
||||
public int device_id;
|
||||
public String name;
|
||||
public ArrayList<InputDevice.MotionRange> axes;
|
||||
}
|
||||
@@ -953,54 +925,72 @@ class SDLJoystickHandler_API12 extends SDLJoystickHandler {
|
||||
private ArrayList<SDLJoystick> mJoysticks;
|
||||
|
||||
public SDLJoystickHandler_API12() {
|
||||
/* FIXME: Move the joystick initialization code to its own function and support hotplugging of devices */
|
||||
|
||||
mJoysticks = new ArrayList<SDLJoystick>();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void pollInputDevices() {
|
||||
int[] deviceIds = InputDevice.getDeviceIds();
|
||||
for(int i=0; i<deviceIds.length; i++) {
|
||||
SDLJoystick joystick = new SDLJoystick();
|
||||
InputDevice joystickDevice = InputDevice.getDevice(deviceIds[i]);
|
||||
|
||||
if( (joystickDevice.getSources() & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
|
||||
joystick.id = deviceIds[i];
|
||||
joystick.name = joystickDevice.getName();
|
||||
joystick.axes = new ArrayList<InputDevice.MotionRange>();
|
||||
|
||||
for (InputDevice.MotionRange range : joystickDevice.getMotionRanges()) {
|
||||
if ( (range.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
|
||||
joystick.axes.add(range);
|
||||
}
|
||||
// It helps processing the device ids in reverse order
|
||||
// For example, in the case of the XBox 360 wireless dongle,
|
||||
// so the first controller seen by SDL matches what the receiver
|
||||
// considers to be the first controller
|
||||
|
||||
for(int i=deviceIds.length-1; i>-1; i--) {
|
||||
SDLJoystick joystick = getJoystick(deviceIds[i]);
|
||||
if (joystick == null) {
|
||||
joystick = new SDLJoystick();
|
||||
InputDevice joystickDevice = InputDevice.getDevice(deviceIds[i]);
|
||||
if( (joystickDevice.getSources() & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
|
||||
joystick.device_id = deviceIds[i];
|
||||
joystick.name = joystickDevice.getName();
|
||||
joystick.axes = new ArrayList<InputDevice.MotionRange>();
|
||||
|
||||
for (InputDevice.MotionRange range : joystickDevice.getMotionRanges()) {
|
||||
if ( (range.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
|
||||
joystick.axes.add(range);
|
||||
}
|
||||
}
|
||||
|
||||
mJoysticks.add(joystick);
|
||||
SDLActivity.nativeAddJoystick(joystick.device_id, joystick.name, 0, -1, joystick.axes.size(), 0, 0);
|
||||
}
|
||||
|
||||
mJoysticks.add(joystick);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNumJoysticks() {
|
||||
return mJoysticks.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getJoystickName(int joy) {
|
||||
return mJoysticks.get(joy).name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getJoystickAxes(int joy) {
|
||||
return mJoysticks.get(joy).axes.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getJoyId(int devId) {
|
||||
|
||||
/* Check removed devices */
|
||||
ArrayList<Integer> removedDevices = new ArrayList<Integer>();
|
||||
for(int i=0; i < mJoysticks.size(); i++) {
|
||||
if (mJoysticks.get(i).id == devId) {
|
||||
return i;
|
||||
int device_id = mJoysticks.get(i).device_id;
|
||||
int j;
|
||||
for (j=0; j < deviceIds.length; j++) {
|
||||
if (device_id == deviceIds[j]) break;
|
||||
}
|
||||
if (j == deviceIds.length) {
|
||||
removedDevices.add(device_id);
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
|
||||
for(int i=0; i < removedDevices.size(); i++) {
|
||||
int device_id = removedDevices.get(i);
|
||||
SDLActivity.nativeRemoveJoystick(device_id);
|
||||
for (int j=0; j < mJoysticks.size(); j++) {
|
||||
if (mJoysticks.get(j).device_id == device_id) {
|
||||
mJoysticks.remove(j);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected SDLJoystick getJoystick(int device_id) {
|
||||
for(int i=0; i < mJoysticks.size(); i++) {
|
||||
if (mJoysticks.get(i).device_id == device_id) {
|
||||
return mJoysticks.get(i);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1010,14 +1000,13 @@ class SDLJoystickHandler_API12 extends SDLJoystickHandler {
|
||||
int action = event.getActionMasked();
|
||||
switch(action) {
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
int id = getJoyId( event.getDeviceId() );
|
||||
if ( id != -1 ) {
|
||||
SDLJoystick joystick = mJoysticks.get(id);
|
||||
SDLJoystick joystick = getJoystick(event.getDeviceId());
|
||||
if ( joystick != null ) {
|
||||
for (int i = 0; i < joystick.axes.size(); i++) {
|
||||
InputDevice.MotionRange range = joystick.axes.get(i);
|
||||
/* Normalize the value to -1...1 */
|
||||
float value = ( event.getAxisValue( range.getAxis(), actionPointerIndex) - range.getMin() ) / range.getRange() * 2.0f - 1.0f;
|
||||
SDLActivity.onNativeJoy(id, i, value );
|
||||
SDLActivity.onNativeJoy(joystick.device_id, i, value );
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
#include "../../video/android/SDL_androidtouch.h"
|
||||
#include "../../video/android/SDL_androidvideo.h"
|
||||
#include "../../video/android/SDL_androidwindow.h"
|
||||
#include "../../joystick/android/SDL_sysjoystick.h"
|
||||
#include "../../joystick/android/SDL_sysjoystick_c.h"
|
||||
|
||||
#include <android/log.h>
|
||||
#include <pthread.h>
|
||||
@@ -75,6 +75,7 @@ static jmethodID midAudioInit;
|
||||
static jmethodID midAudioWriteShortBuffer;
|
||||
static jmethodID midAudioWriteByteBuffer;
|
||||
static jmethodID midAudioQuit;
|
||||
static jmethodID midPollInputDevices;
|
||||
|
||||
/* Accelerometer data storage */
|
||||
static float fLastAccelerometer[3];
|
||||
@@ -127,11 +128,13 @@ void SDL_Android_Init(JNIEnv* mEnv, jclass cls)
|
||||
"audioWriteByteBuffer", "([B)V");
|
||||
midAudioQuit = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass,
|
||||
"audioQuit", "()V");
|
||||
midPollInputDevices = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass,
|
||||
"pollInputDevices", "()V");
|
||||
|
||||
bHasNewData = false;
|
||||
|
||||
if(!midGetNativeSurface || !midFlipBuffers || !midAudioInit ||
|
||||
!midAudioWriteShortBuffer || !midAudioWriteByteBuffer || !midAudioQuit) {
|
||||
!midAudioWriteShortBuffer || !midAudioWriteByteBuffer || !midAudioQuit || !midPollInputDevices) {
|
||||
__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!");
|
||||
@@ -148,25 +151,47 @@ void Java_org_libsdl_app_SDLActivity_onNativeResize(
|
||||
// Paddown
|
||||
int Java_org_libsdl_app_SDLActivity_onNativePadDown(
|
||||
JNIEnv* env, jclass jcls,
|
||||
jint padId, jint keycode)
|
||||
jint device_id, jint keycode)
|
||||
{
|
||||
return Android_OnPadDown(padId, keycode);
|
||||
return Android_OnPadDown(device_id, keycode);
|
||||
}
|
||||
|
||||
// Padup
|
||||
int Java_org_libsdl_app_SDLActivity_onNativePadUp(
|
||||
JNIEnv* env, jclass jcls,
|
||||
jint padId, jint keycode)
|
||||
jint device_id, jint keycode)
|
||||
{
|
||||
return Android_OnPadUp(padId, keycode);
|
||||
return Android_OnPadUp(device_id, keycode);
|
||||
}
|
||||
|
||||
/* Joy */
|
||||
void Java_org_libsdl_app_SDLActivity_onNativeJoy(
|
||||
JNIEnv* env, jclass jcls,
|
||||
jint joyId, jint axis, jfloat value)
|
||||
jint device_id, jint axis, jfloat value)
|
||||
{
|
||||
Android_OnJoy(joyId, axis, value);
|
||||
Android_OnJoy(device_id, axis, value);
|
||||
}
|
||||
|
||||
|
||||
int Java_org_libsdl_app_SDLActivity_nativeAddJoystick(
|
||||
JNIEnv* env, jclass jcls,
|
||||
jint device_id, jstring device_name, jint is_accelerometer,
|
||||
jint nbuttons, jint naxes, jint nhats, jint nballs)
|
||||
{
|
||||
int retval;
|
||||
const char *name = (*env)->GetStringUTFChars(env, device_name, NULL);
|
||||
|
||||
retval = Android_AddJoystick(device_id, name, (SDL_bool) is_accelerometer, nbuttons, naxes, nhats, nballs);
|
||||
|
||||
(*env)->ReleaseStringUTFChars(env, device_name, name);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
int Java_org_libsdl_app_SDLActivity_nativeRemoveJoystick(
|
||||
JNIEnv* env, jclass jcls, jint device_id)
|
||||
{
|
||||
return Android_RemoveJoystick(device_id);
|
||||
}
|
||||
|
||||
|
||||
@@ -1247,62 +1272,12 @@ int Android_JNI_GetTouchDeviceIds(int **ids) {
|
||||
return number;
|
||||
}
|
||||
|
||||
/* return the total number of plugged in joysticks */
|
||||
int Android_JNI_GetNumJoysticks()
|
||||
void Android_JNI_PollInputDevices()
|
||||
{
|
||||
JNIEnv* env = Android_JNI_GetEnv();
|
||||
if (!env) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
jmethodID mid = (*env)->GetStaticMethodID(env, mActivityClass, "getNumJoysticks", "()I");
|
||||
if (!mid) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return (int)(*env)->CallStaticIntMethod(env, mActivityClass, mid);
|
||||
JNIEnv *env = Android_JNI_GetEnv();
|
||||
(*env)->CallStaticVoidMethod(env, mActivityClass, midPollInputDevices);
|
||||
}
|
||||
|
||||
/* Return the name of joystick number "i" */
|
||||
char* Android_JNI_GetJoystickName(int i)
|
||||
{
|
||||
JNIEnv* env = Android_JNI_GetEnv();
|
||||
if (!env) {
|
||||
return SDL_strdup("");
|
||||
}
|
||||
|
||||
jmethodID mid = (*env)->GetStaticMethodID(env, mActivityClass, "getJoystickName", "(I)Ljava/lang/String;");
|
||||
if (!mid) {
|
||||
return SDL_strdup("");
|
||||
}
|
||||
jstring string = (jstring)((*env)->CallStaticObjectMethod(env, mActivityClass, mid, i));
|
||||
const char* utf = (*env)->GetStringUTFChars(env, string, 0);
|
||||
if (!utf) {
|
||||
return SDL_strdup("");
|
||||
}
|
||||
|
||||
char* text = SDL_strdup(utf);
|
||||
(*env)->ReleaseStringUTFChars(env, string, utf);
|
||||
return text;
|
||||
}
|
||||
|
||||
/* return the number of axes in the given joystick */
|
||||
int Android_JNI_GetJoystickAxes(int joy)
|
||||
{
|
||||
JNIEnv* env = Android_JNI_GetEnv();
|
||||
if (!env) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
jmethodID mid = (*env)->GetStaticMethodID(env, mActivityClass, "getJoystickAxes", "(I)I");
|
||||
if (!mid) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return (int)(*env)->CallIntMethod(env, mActivityClass, mid, joy);
|
||||
}
|
||||
|
||||
|
||||
/* sends message to be handled on the UI event dispatch thread */
|
||||
int Android_JNI_SendMessage(int command, int param)
|
||||
{
|
||||
|
||||
@@ -66,9 +66,8 @@ SDL_bool Android_JNI_HasClipboardText();
|
||||
int Android_JNI_GetPowerInfo(int* plugged, int* charged, int* battery, int* seconds, int* percent);
|
||||
|
||||
/* Joystick support */
|
||||
int Android_JNI_GetNumJoysticks();
|
||||
char* Android_JNI_GetJoystickName(int i);
|
||||
int Android_JNI_GetJoystickAxes(int joy);
|
||||
void Android_JNI_PollInputDevices();
|
||||
|
||||
|
||||
/* Touch support */
|
||||
int Android_JNI_GetTouchDeviceIds(int **ids);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -21,8 +21,31 @@
|
||||
|
||||
#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 axisnum, float value);
|
||||
#ifdef SDL_JOYSTICK_ANDROID
|
||||
#include "../SDL_sysjoystick.h"
|
||||
|
||||
extern int Android_OnPadDown(int device_id, int keycode);
|
||||
extern int Android_OnPadUp(int device_id, int keycode);
|
||||
extern int Android_OnJoy(int device_id, int axisnum, float value);
|
||||
extern int Android_AddJoystick(int device_id, const char *name, SDL_bool is_accelerometer, int nbuttons, int naxes, int nhats, int nballs);
|
||||
extern int Android_RemoveJoystick(int device_id);
|
||||
|
||||
/* A linked list of available joysticks */
|
||||
typedef struct SDL_joylist_item
|
||||
{
|
||||
int device_instance;
|
||||
int device_id; /* Android's device id */
|
||||
char *name; /* "SideWinder 3D Pro" or whatever */
|
||||
SDL_JoystickGUID guid;
|
||||
SDL_bool is_accelerometer;
|
||||
SDL_Joystick *joystick;
|
||||
int nbuttons, naxes, nhats, nballs;
|
||||
|
||||
struct SDL_joylist_item *next;
|
||||
} SDL_joylist_item;
|
||||
|
||||
typedef SDL_joylist_item joystick_hwdata;
|
||||
|
||||
#endif /* SDL_JOYSTICK_ANDROID */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
Reference in New Issue
Block a user