Skip to content

Commit

Permalink
[Android] Hotplugging support for joysticks
Browse files Browse the repository at this point in the history
  • Loading branch information
gabomdq committed Dec 10, 2013
1 parent d01ad02 commit bfcd28c
Show file tree
Hide file tree
Showing 6 changed files with 434 additions and 294 deletions.
1 change: 1 addition & 0 deletions WhatsNew.txt
Expand Up @@ -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
Expand Down
173 changes: 81 additions & 92 deletions android-project/src/org/libsdl/app/SDLActivity.java
Expand Up @@ -256,9 +256,9 @@ boolean sendCommand(int command, Object data) {
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);
Expand All @@ -270,6 +270,10 @@ public static native void onNativeTouch(int touchDevId, int pointerFingerId,
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();
Expand Down Expand Up @@ -460,29 +464,16 @@ public static int[] inputGetInputDeviceIds(int sources) {
}

// 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();
}
}

}

/**
Expand Down Expand Up @@ -660,16 +651,13 @@ public boolean onKey(View v, int keyCode, KeyEvent event) {

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;
}
}
}
Expand Down Expand Up @@ -916,91 +904,93 @@ public boolean deleteSurroundingText(int beforeLength, int afterLength) {

/* 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;
}

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);
}
}

/* Check removed devices */
ArrayList<Integer> removedDevices = new ArrayList<Integer>();
for(int i=0; i < mJoysticks.size(); i++) {
int device_id = mJoysticks.get(i).device_id;
int j;
for (j=0; j < deviceIds.length; j++) {
if (device_id == deviceIds[j]) break;
}
if (j == deviceIds.length) {
removedDevices.add(device_id);
}
}

for(int i=0; i < removedDevices.size(); i++) {
int device_id = removedDevices.get(i);
SDLActivity.nativeRemoveJoystick(device_id);
for (int j=0; j < mJoysticks.size(); j++) {
if (mJoysticks.get(j).device_id == device_id) {
mJoysticks.remove(j);
break;
}
}
}
}

@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) {
protected SDLJoystick getJoystick(int device_id) {
for(int i=0; i < mJoysticks.size(); i++) {
if (mJoysticks.get(i).id == devId) {
return i;
if (mJoysticks.get(i).device_id == device_id) {
return mJoysticks.get(i);
}
}
return -1;
return null;
}

@Override
Expand All @@ -1010,14 +1000,13 @@ public boolean handleMotionEvent(MotionEvent event) {
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;
Expand Down

0 comments on commit bfcd28c

Please sign in to comment.