1 package org
.libsdl
.app
;
3 import java
.util
.ArrayList
;
4 import java
.util
.Collections
;
5 import java
.util
.Comparator
;
8 import android
.content
.Context
;
10 import android
.view
.*;
11 import android
.util
.Log
;
14 public class SDLControllerManager
17 public static native int nativeSetupJNI();
19 public static native int nativeAddJoystick(int device_id
, String name
, String desc
,
20 int is_accelerometer
, int nbuttons
,
21 int naxes
, int nhats
, int nballs
);
22 public static native int nativeRemoveJoystick(int device_id
);
23 public static native int nativeAddHaptic(int device_id
, String name
);
24 public static native int nativeRemoveHaptic(int device_id
);
25 public static native int onNativePadDown(int device_id
, int keycode
);
26 public static native int onNativePadUp(int device_id
, int keycode
);
27 public static native void onNativeJoy(int device_id
, int axis
,
29 public static native void onNativeHat(int device_id
, int hat_id
,
32 protected static SDLJoystickHandler mJoystickHandler
;
33 protected static SDLHapticHandler mHapticHandler
;
35 private static final String TAG
= "SDLControllerManager";
37 public static void initialize() {
38 mJoystickHandler
= null;
39 mHapticHandler
= null;
41 SDLControllerManager
.setup();
44 public static void setup() {
45 if (Build
.VERSION
.SDK_INT
>= 16) {
46 mJoystickHandler
= new SDLJoystickHandler_API16();
47 } else if (Build
.VERSION
.SDK_INT
>= 12) {
48 mJoystickHandler
= new SDLJoystickHandler_API12();
50 mJoystickHandler
= new SDLJoystickHandler();
52 mHapticHandler
= new SDLHapticHandler();
55 // Joystick glue code, just a series of stubs that redirect to the SDLJoystickHandler instance
56 public static boolean handleJoystickMotionEvent(MotionEvent event
) {
57 return mJoystickHandler
.handleMotionEvent(event
);
61 * This method is called by SDL using JNI.
63 public static void pollInputDevices() {
64 mJoystickHandler
.pollInputDevices();
68 * This method is called by SDL using JNI.
70 public static void pollHapticDevices() {
71 mHapticHandler
.pollHapticDevices();
75 * This method is called by SDL using JNI.
77 public static void hapticRun(int device_id
, int length
) {
78 mHapticHandler
.run(device_id
, length
);
81 // Check if a given device is considered a possible SDL joystick
82 public static boolean isDeviceSDLJoystick(int deviceId
) {
83 InputDevice device
= InputDevice
.getDevice(deviceId
);
84 // We cannot use InputDevice.isVirtual before API 16, so let's accept
85 // only nonnegative device ids (VIRTUAL_KEYBOARD equals -1)
86 if ((device
== null) || (deviceId
< 0)) {
89 int sources
= device
.getSources();
91 if ((sources
& InputDevice
.SOURCE_CLASS_JOYSTICK
) == InputDevice
.SOURCE_CLASS_JOYSTICK
) {
92 Log
.v(TAG
, "Input device " + device
.getName() + " is a joystick.");
94 if ((sources
& InputDevice
.SOURCE_DPAD
) == InputDevice
.SOURCE_DPAD
) {
95 Log
.v(TAG
, "Input device " + device
.getName() + " is a dpad.");
97 if ((sources
& InputDevice
.SOURCE_GAMEPAD
) == InputDevice
.SOURCE_GAMEPAD
) {
98 Log
.v(TAG
, "Input device " + device
.getName() + " is a gamepad.");
101 return (((sources
& InputDevice
.SOURCE_CLASS_JOYSTICK
) == InputDevice
.SOURCE_CLASS_JOYSTICK
) ||
102 ((sources
& InputDevice
.SOURCE_DPAD
) == InputDevice
.SOURCE_DPAD
) ||
103 ((sources
& InputDevice
.SOURCE_GAMEPAD
) == InputDevice
.SOURCE_GAMEPAD
)
109 /* A null joystick handler for API level < 12 devices (the accelerometer is handled separately) */
110 class SDLJoystickHandler
{
113 * Handles given MotionEvent.
114 * @param event the event to be handled.
115 * @return if given event was processed.
117 public boolean handleMotionEvent(MotionEvent event
) {
122 * Handles adding and removing of input devices.
124 public void pollInputDevices() {
128 /* Actual joystick functionality available for API >= 12 devices */
129 class SDLJoystickHandler_API12
extends SDLJoystickHandler
{
131 static class SDLJoystick
{
132 public int device_id
;
135 public ArrayList
<InputDevice
.MotionRange
> axes
;
136 public ArrayList
<InputDevice
.MotionRange
> hats
;
138 static class RangeComparator
implements Comparator
<InputDevice
.MotionRange
> {
140 public int compare(InputDevice
.MotionRange arg0
, InputDevice
.MotionRange arg1
) {
141 return arg0
.getAxis() - arg1
.getAxis();
145 private ArrayList
<SDLJoystick
> mJoysticks
;
147 public SDLJoystickHandler_API12() {
149 mJoysticks
= new ArrayList
<SDLJoystick
>();
153 public void pollInputDevices() {
154 int[] deviceIds
= InputDevice
.getDeviceIds();
155 // It helps processing the device ids in reverse order
156 // For example, in the case of the XBox 360 wireless dongle,
157 // so the first controller seen by SDL matches what the receiver
158 // considers to be the first controller
160 for(int i
=deviceIds
.length
-1; i
>-1; i
--) {
161 SDLJoystick joystick
= getJoystick(deviceIds
[i
]);
162 if (joystick
== null) {
163 joystick
= new SDLJoystick();
164 InputDevice joystickDevice
= InputDevice
.getDevice(deviceIds
[i
]);
165 if (SDLControllerManager
.isDeviceSDLJoystick(deviceIds
[i
])) {
166 joystick
.device_id
= deviceIds
[i
];
167 joystick
.name
= joystickDevice
.getName();
168 joystick
.desc
= getJoystickDescriptor(joystickDevice
);
169 joystick
.axes
= new ArrayList
<InputDevice
.MotionRange
>();
170 joystick
.hats
= new ArrayList
<InputDevice
.MotionRange
>();
172 List
<InputDevice
.MotionRange
> ranges
= joystickDevice
.getMotionRanges();
173 Collections
.sort(ranges
, new RangeComparator());
174 for (InputDevice
.MotionRange range
: ranges
) {
175 if ((range
.getSource() & InputDevice
.SOURCE_CLASS_JOYSTICK
) != 0) {
176 if (range
.getAxis() == MotionEvent
.AXIS_HAT_X
||
177 range
.getAxis() == MotionEvent
.AXIS_HAT_Y
) {
178 joystick
.hats
.add(range
);
181 joystick
.axes
.add(range
);
186 mJoysticks
.add(joystick
);
187 SDLControllerManager
.nativeAddJoystick(joystick
.device_id
, joystick
.name
, joystick
.desc
, 0, -1,
188 joystick
.axes
.size(), joystick
.hats
.size()/2, 0);
193 /* Check removed devices */
194 ArrayList
<Integer
> removedDevices
= new ArrayList
<Integer
>();
195 for(int i
=0; i
< mJoysticks
.size(); i
++) {
196 int device_id
= mJoysticks
.get(i
).device_id
;
198 for (j
=0; j
< deviceIds
.length
; j
++) {
199 if (device_id
== deviceIds
[j
]) break;
201 if (j
== deviceIds
.length
) {
202 removedDevices
.add(Integer
.valueOf(device_id
));
206 for(int i
=0; i
< removedDevices
.size(); i
++) {
207 int device_id
= removedDevices
.get(i
).intValue();
208 SDLControllerManager
.nativeRemoveJoystick(device_id
);
209 for (int j
=0; j
< mJoysticks
.size(); j
++) {
210 if (mJoysticks
.get(j
).device_id
== device_id
) {
211 mJoysticks
.remove(j
);
218 protected SDLJoystick
getJoystick(int device_id
) {
219 for(int i
=0; i
< mJoysticks
.size(); i
++) {
220 if (mJoysticks
.get(i
).device_id
== device_id
) {
221 return mJoysticks
.get(i
);
228 public boolean handleMotionEvent(MotionEvent event
) {
229 if ((event
.getSource() & InputDevice
.SOURCE_JOYSTICK
) != 0) {
230 int actionPointerIndex
= event
.getActionIndex();
231 int action
= event
.getActionMasked();
233 case MotionEvent
.ACTION_MOVE
:
234 SDLJoystick joystick
= getJoystick(event
.getDeviceId());
235 if ( joystick
!= null ) {
236 for (int i
= 0; i
< joystick
.axes
.size(); i
++) {
237 InputDevice
.MotionRange range
= joystick
.axes
.get(i
);
238 /* Normalize the value to -1...1 */
239 float value
= ( event
.getAxisValue( range
.getAxis(), actionPointerIndex
) - range
.getMin() ) / range
.getRange() * 2.0f - 1.0f;
240 SDLControllerManager
.onNativeJoy(joystick
.device_id
, i
, value
);
242 for (int i
= 0; i
< joystick
.hats
.size(); i
+=2) {
243 int hatX
= Math
.round(event
.getAxisValue( joystick
.hats
.get(i
).getAxis(), actionPointerIndex
) );
244 int hatY
= Math
.round(event
.getAxisValue( joystick
.hats
.get(i
+1).getAxis(), actionPointerIndex
) );
245 SDLControllerManager
.onNativeHat(joystick
.device_id
, i
/2, hatX
, hatY
);
256 public String
getJoystickDescriptor(InputDevice joystickDevice
) {
257 return joystickDevice
.getName();
262 class SDLJoystickHandler_API16
extends SDLJoystickHandler_API12
{
265 public String
getJoystickDescriptor(InputDevice joystickDevice
) {
266 String desc
= joystickDevice
.getDescriptor();
268 if (desc
!= null && !desc
.equals("")) {
272 return super.getJoystickDescriptor(joystickDevice
);
276 class SDLHapticHandler
{
279 public int device_id
;
284 private ArrayList
<SDLHaptic
> mHaptics
;
286 public SDLHapticHandler() {
287 mHaptics
= new ArrayList
<SDLHaptic
>();
290 public void run(int device_id
, int length
) {
291 SDLHaptic haptic
= getHaptic(device_id
);
292 if (haptic
!= null) {
293 haptic
.vib
.vibrate (length
);
297 public void pollHapticDevices() {
299 final int deviceId_VIBRATOR_SERVICE
= 999999;
300 boolean hasVibratorService
= false;
302 int[] deviceIds
= InputDevice
.getDeviceIds();
303 // It helps processing the device ids in reverse order
304 // For example, in the case of the XBox 360 wireless dongle,
305 // so the first controller seen by SDL matches what the receiver
306 // considers to be the first controller
308 if (Build
.VERSION
.SDK_INT
>= 16)
310 for (int i
= deviceIds
.length
- 1; i
> -1; i
--) {
311 SDLHaptic haptic
= getHaptic(deviceIds
[i
]);
312 if (haptic
== null) {
313 InputDevice device
= InputDevice
.getDevice(deviceIds
[i
]);
314 Vibrator vib
= device
.getVibrator();
315 if (vib
.hasVibrator()) {
316 haptic
= new SDLHaptic();
317 haptic
.device_id
= deviceIds
[i
];
318 haptic
.name
= device
.getName();
320 mHaptics
.add(haptic
);
321 SDLControllerManager
.nativeAddHaptic(haptic
.device_id
, haptic
.name
);
327 /* Check VIBRATOR_SERVICE */
328 Vibrator vib
= (Vibrator
) SDL
.getContext().getSystemService(Context
.VIBRATOR_SERVICE
);
330 if (Build
.VERSION
.SDK_INT
>= 11) {
331 hasVibratorService
= vib
.hasVibrator();
333 hasVibratorService
= true;
336 if (hasVibratorService
) {
337 SDLHaptic haptic
= getHaptic(deviceId_VIBRATOR_SERVICE
);
338 if (haptic
== null) {
339 haptic
= new SDLHaptic();
340 haptic
.device_id
= deviceId_VIBRATOR_SERVICE
;
341 haptic
.name
= "VIBRATOR_SERVICE";
343 mHaptics
.add(haptic
);
344 SDLControllerManager
.nativeAddHaptic(haptic
.device_id
, haptic
.name
);
349 /* Check removed devices */
350 ArrayList
<Integer
> removedDevices
= new ArrayList
<Integer
>();
351 for(int i
=0; i
< mHaptics
.size(); i
++) {
352 int device_id
= mHaptics
.get(i
).device_id
;
354 for (j
=0; j
< deviceIds
.length
; j
++) {
355 if (device_id
== deviceIds
[j
]) break;
358 if (device_id
== deviceId_VIBRATOR_SERVICE
&& hasVibratorService
) {
359 // don't remove the vibrator if it is still present
360 } else if (j
== deviceIds
.length
) {
361 removedDevices
.add(device_id
);
365 for(int i
=0; i
< removedDevices
.size(); i
++) {
366 int device_id
= removedDevices
.get(i
);
367 SDLControllerManager
.nativeRemoveHaptic(device_id
);
368 for (int j
=0; j
< mHaptics
.size(); j
++) {
369 if (mHaptics
.get(j
).device_id
== device_id
) {
377 protected SDLHaptic
getHaptic(int device_id
) {
378 for(int i
=0; i
< mHaptics
.size(); i
++) {
379 if (mHaptics
.get(i
).device_id
== device_id
) {
380 return mHaptics
.get(i
);
387 class SDLGenericMotionListener_API12
implements View
.OnGenericMotionListener
{
388 // Generic Motion (mouse hover, joystick...) events go here
390 public boolean onGenericMotion(View v
, MotionEvent event
) {
394 switch ( event
.getSource() ) {
395 case InputDevice
.SOURCE_JOYSTICK
:
396 case InputDevice
.SOURCE_GAMEPAD
:
397 case InputDevice
.SOURCE_DPAD
:
398 return SDLControllerManager
.handleJoystickMotionEvent(event
);
400 case InputDevice
.SOURCE_MOUSE
:
401 if (!SDLActivity
.mSeparateMouseAndTouch
) {
404 action
= event
.getActionMasked();
406 case MotionEvent
.ACTION_SCROLL
:
407 x
= event
.getAxisValue(MotionEvent
.AXIS_HSCROLL
, 0);
408 y
= event
.getAxisValue(MotionEvent
.AXIS_VSCROLL
, 0);
409 SDLActivity
.onNativeMouse(0, action
, x
, y
);
412 case MotionEvent
.ACTION_HOVER_MOVE
:
416 SDLActivity
.onNativeMouse(0, action
, x
, y
);
428 // Event was not managed