Mercurial > repos > blastem
comparison android/src/org/libsdl/app/SDLControllerManager.java @ 1839:78abbabfd58d
Get Android build working again and update for SDL 2.0.7 (last version to support older versions of Android)
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Sun, 14 Apr 2019 23:37:11 -0700 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
1836:601ef72cc16f | 1839:78abbabfd58d |
---|---|
1 package org.libsdl.app; | |
2 | |
3 import java.util.ArrayList; | |
4 import java.util.Collections; | |
5 import java.util.Comparator; | |
6 import java.util.List; | |
7 import java.util.Objects; | |
8 | |
9 import android.content.Context; | |
10 import android.os.*; | |
11 import android.view.*; | |
12 import android.util.Log; | |
13 | |
14 | |
15 public class SDLControllerManager | |
16 { | |
17 | |
18 public static native int nativeSetupJNI(); | |
19 | |
20 public static native int nativeAddJoystick(int device_id, String name, String desc, | |
21 int is_accelerometer, int nbuttons, | |
22 int naxes, int nhats, int nballs); | |
23 public static native int nativeRemoveJoystick(int device_id); | |
24 public static native int nativeAddHaptic(int device_id, String name); | |
25 public static native int nativeRemoveHaptic(int device_id); | |
26 public static native int onNativePadDown(int device_id, int keycode); | |
27 public static native int onNativePadUp(int device_id, int keycode); | |
28 public static native void onNativeJoy(int device_id, int axis, | |
29 float value); | |
30 public static native void onNativeHat(int device_id, int hat_id, | |
31 int x, int y); | |
32 | |
33 protected static SDLJoystickHandler mJoystickHandler; | |
34 protected static SDLHapticHandler mHapticHandler; | |
35 | |
36 private static final String TAG = "SDLControllerManager"; | |
37 | |
38 public static void initialize() { | |
39 mJoystickHandler = null; | |
40 mHapticHandler = null; | |
41 | |
42 SDLControllerManager.setup(); | |
43 } | |
44 | |
45 public static void setup() { | |
46 if (Build.VERSION.SDK_INT >= 16) { | |
47 mJoystickHandler = new SDLJoystickHandler_API16(); | |
48 } else if (Build.VERSION.SDK_INT >= 12) { | |
49 mJoystickHandler = new SDLJoystickHandler_API12(); | |
50 } else { | |
51 mJoystickHandler = new SDLJoystickHandler(); | |
52 } | |
53 mHapticHandler = new SDLHapticHandler(); | |
54 } | |
55 | |
56 // Joystick glue code, just a series of stubs that redirect to the SDLJoystickHandler instance | |
57 public static boolean handleJoystickMotionEvent(MotionEvent event) { | |
58 return mJoystickHandler.handleMotionEvent(event); | |
59 } | |
60 | |
61 /** | |
62 * This method is called by SDL using JNI. | |
63 */ | |
64 public static void pollInputDevices() { | |
65 mJoystickHandler.pollInputDevices(); | |
66 } | |
67 | |
68 /** | |
69 * This method is called by SDL using JNI. | |
70 */ | |
71 public static void pollHapticDevices() { | |
72 mHapticHandler.pollHapticDevices(); | |
73 } | |
74 | |
75 /** | |
76 * This method is called by SDL using JNI. | |
77 */ | |
78 public static void hapticRun(int device_id, int length) { | |
79 mHapticHandler.run(device_id, length); | |
80 } | |
81 | |
82 // Check if a given device is considered a possible SDL joystick | |
83 public static boolean isDeviceSDLJoystick(int deviceId) { | |
84 InputDevice device = InputDevice.getDevice(deviceId); | |
85 // We cannot use InputDevice.isVirtual before API 16, so let's accept | |
86 // only nonnegative device ids (VIRTUAL_KEYBOARD equals -1) | |
87 if ((device == null) || (deviceId < 0)) { | |
88 return false; | |
89 } | |
90 int sources = device.getSources(); | |
91 | |
92 if ((sources & InputDevice.SOURCE_CLASS_JOYSTICK) == InputDevice.SOURCE_CLASS_JOYSTICK) { | |
93 Log.v(TAG, "Input device " + device.getName() + " is a joystick."); | |
94 } | |
95 if ((sources & InputDevice.SOURCE_DPAD) == InputDevice.SOURCE_DPAD) { | |
96 Log.v(TAG, "Input device " + device.getName() + " is a dpad."); | |
97 } | |
98 if ((sources & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD) { | |
99 Log.v(TAG, "Input device " + device.getName() + " is a gamepad."); | |
100 } | |
101 | |
102 return (((sources & InputDevice.SOURCE_CLASS_JOYSTICK) == InputDevice.SOURCE_CLASS_JOYSTICK) || | |
103 ((sources & InputDevice.SOURCE_DPAD) == InputDevice.SOURCE_DPAD) || | |
104 ((sources & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD) | |
105 ); | |
106 } | |
107 | |
108 } | |
109 | |
110 /* A null joystick handler for API level < 12 devices (the accelerometer is handled separately) */ | |
111 class SDLJoystickHandler { | |
112 | |
113 /** | |
114 * Handles given MotionEvent. | |
115 * @param event the event to be handled. | |
116 * @return if given event was processed. | |
117 */ | |
118 public boolean handleMotionEvent(MotionEvent event) { | |
119 return false; | |
120 } | |
121 | |
122 /** | |
123 * Handles adding and removing of input devices. | |
124 */ | |
125 public void pollInputDevices() { | |
126 } | |
127 } | |
128 | |
129 /* Actual joystick functionality available for API >= 12 devices */ | |
130 class SDLJoystickHandler_API12 extends SDLJoystickHandler { | |
131 | |
132 static class SDLJoystick { | |
133 public int device_id; | |
134 public String name; | |
135 public String desc; | |
136 public ArrayList<InputDevice.MotionRange> axes; | |
137 public ArrayList<InputDevice.MotionRange> hats; | |
138 } | |
139 static class RangeComparator implements Comparator<InputDevice.MotionRange> { | |
140 @Override | |
141 public int compare(InputDevice.MotionRange arg0, InputDevice.MotionRange arg1) { | |
142 return arg0.getAxis() - arg1.getAxis(); | |
143 } | |
144 } | |
145 | |
146 private ArrayList<SDLJoystick> mJoysticks; | |
147 | |
148 public SDLJoystickHandler_API12() { | |
149 | |
150 mJoysticks = new ArrayList<SDLJoystick>(); | |
151 } | |
152 | |
153 @Override | |
154 public void pollInputDevices() { | |
155 int[] deviceIds = InputDevice.getDeviceIds(); | |
156 // It helps processing the device ids in reverse order | |
157 // For example, in the case of the XBox 360 wireless dongle, | |
158 // so the first controller seen by SDL matches what the receiver | |
159 // considers to be the first controller | |
160 | |
161 for(int i=deviceIds.length-1; i>-1; i--) { | |
162 SDLJoystick joystick = getJoystick(deviceIds[i]); | |
163 if (joystick == null) { | |
164 joystick = new SDLJoystick(); | |
165 InputDevice joystickDevice = InputDevice.getDevice(deviceIds[i]); | |
166 if (SDLControllerManager.isDeviceSDLJoystick(deviceIds[i])) { | |
167 joystick.device_id = deviceIds[i]; | |
168 joystick.name = joystickDevice.getName(); | |
169 joystick.desc = getJoystickDescriptor(joystickDevice); | |
170 joystick.axes = new ArrayList<InputDevice.MotionRange>(); | |
171 joystick.hats = new ArrayList<InputDevice.MotionRange>(); | |
172 | |
173 List<InputDevice.MotionRange> ranges = joystickDevice.getMotionRanges(); | |
174 Collections.sort(ranges, new RangeComparator()); | |
175 for (InputDevice.MotionRange range : ranges ) { | |
176 if ((range.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) { | |
177 if (range.getAxis() == MotionEvent.AXIS_HAT_X || | |
178 range.getAxis() == MotionEvent.AXIS_HAT_Y) { | |
179 joystick.hats.add(range); | |
180 } | |
181 else { | |
182 joystick.axes.add(range); | |
183 } | |
184 } | |
185 } | |
186 | |
187 mJoysticks.add(joystick); | |
188 SDLControllerManager.nativeAddJoystick(joystick.device_id, joystick.name, joystick.desc, 0, -1, | |
189 joystick.axes.size(), joystick.hats.size()/2, 0); | |
190 } | |
191 } | |
192 } | |
193 | |
194 /* Check removed devices */ | |
195 ArrayList<Integer> removedDevices = new ArrayList<Integer>(); | |
196 for(int i=0; i < mJoysticks.size(); i++) { | |
197 int device_id = mJoysticks.get(i).device_id; | |
198 int j; | |
199 for (j=0; j < deviceIds.length; j++) { | |
200 if (device_id == deviceIds[j]) break; | |
201 } | |
202 if (j == deviceIds.length) { | |
203 removedDevices.add(Integer.valueOf(device_id)); | |
204 } | |
205 } | |
206 | |
207 for(int i=0; i < removedDevices.size(); i++) { | |
208 int device_id = removedDevices.get(i).intValue(); | |
209 SDLControllerManager.nativeRemoveJoystick(device_id); | |
210 for (int j=0; j < mJoysticks.size(); j++) { | |
211 if (mJoysticks.get(j).device_id == device_id) { | |
212 mJoysticks.remove(j); | |
213 break; | |
214 } | |
215 } | |
216 } | |
217 } | |
218 | |
219 protected SDLJoystick getJoystick(int device_id) { | |
220 for(int i=0; i < mJoysticks.size(); i++) { | |
221 if (mJoysticks.get(i).device_id == device_id) { | |
222 return mJoysticks.get(i); | |
223 } | |
224 } | |
225 return null; | |
226 } | |
227 | |
228 @Override | |
229 public boolean handleMotionEvent(MotionEvent event) { | |
230 if ((event.getSource() & InputDevice.SOURCE_JOYSTICK) != 0) { | |
231 int actionPointerIndex = event.getActionIndex(); | |
232 int action = event.getActionMasked(); | |
233 switch(action) { | |
234 case MotionEvent.ACTION_MOVE: | |
235 SDLJoystick joystick = getJoystick(event.getDeviceId()); | |
236 if ( joystick != null ) { | |
237 for (int i = 0; i < joystick.axes.size(); i++) { | |
238 InputDevice.MotionRange range = joystick.axes.get(i); | |
239 /* Normalize the value to -1...1 */ | |
240 float value = ( event.getAxisValue( range.getAxis(), actionPointerIndex) - range.getMin() ) / range.getRange() * 2.0f - 1.0f; | |
241 SDLControllerManager.onNativeJoy(joystick.device_id, i, value ); | |
242 } | |
243 for (int i = 0; i < joystick.hats.size(); i+=2) { | |
244 int hatX = Math.round(event.getAxisValue( joystick.hats.get(i).getAxis(), actionPointerIndex ) ); | |
245 int hatY = Math.round(event.getAxisValue( joystick.hats.get(i+1).getAxis(), actionPointerIndex ) ); | |
246 SDLControllerManager.onNativeHat(joystick.device_id, i/2, hatX, hatY ); | |
247 } | |
248 } | |
249 break; | |
250 default: | |
251 break; | |
252 } | |
253 } | |
254 return true; | |
255 } | |
256 | |
257 public String getJoystickDescriptor(InputDevice joystickDevice) { | |
258 return joystickDevice.getName(); | |
259 } | |
260 } | |
261 | |
262 | |
263 class SDLJoystickHandler_API16 extends SDLJoystickHandler_API12 { | |
264 | |
265 @Override | |
266 public String getJoystickDescriptor(InputDevice joystickDevice) { | |
267 String desc = joystickDevice.getDescriptor(); | |
268 | |
269 if (desc != null && !Objects.equals(desc, "")) { | |
270 return desc; | |
271 } | |
272 | |
273 return super.getJoystickDescriptor(joystickDevice); | |
274 } | |
275 } | |
276 | |
277 class SDLHapticHandler { | |
278 | |
279 class SDLHaptic { | |
280 public int device_id; | |
281 public String name; | |
282 public Vibrator vib; | |
283 } | |
284 | |
285 private ArrayList<SDLHaptic> mHaptics; | |
286 | |
287 public SDLHapticHandler() { | |
288 mHaptics = new ArrayList<SDLHaptic>(); | |
289 } | |
290 | |
291 public void run(int device_id, int length) { | |
292 SDLHaptic haptic = getHaptic(device_id); | |
293 if (haptic != null) { | |
294 haptic.vib.vibrate (length); | |
295 } | |
296 } | |
297 | |
298 public void pollHapticDevices() { | |
299 | |
300 final int deviceId_VIBRATOR_SERVICE = 999999; | |
301 boolean hasVibratorService = false; | |
302 | |
303 int[] deviceIds = InputDevice.getDeviceIds(); | |
304 // It helps processing the device ids in reverse order | |
305 // For example, in the case of the XBox 360 wireless dongle, | |
306 // so the first controller seen by SDL matches what the receiver | |
307 // considers to be the first controller | |
308 | |
309 if (Build.VERSION.SDK_INT >= 16) | |
310 { | |
311 for (int i = deviceIds.length - 1; i > -1; i--) { | |
312 SDLHaptic haptic = getHaptic(deviceIds[i]); | |
313 if (haptic == null) { | |
314 InputDevice device = InputDevice.getDevice(deviceIds[i]); | |
315 Vibrator vib = device.getVibrator(); | |
316 if (vib.hasVibrator()) { | |
317 haptic = new SDLHaptic(); | |
318 haptic.device_id = deviceIds[i]; | |
319 haptic.name = device.getName(); | |
320 haptic.vib = vib; | |
321 mHaptics.add(haptic); | |
322 SDLControllerManager.nativeAddHaptic(haptic.device_id, haptic.name); | |
323 } | |
324 } | |
325 } | |
326 } | |
327 | |
328 /* Check VIBRATOR_SERVICE */ | |
329 Vibrator vib = (Vibrator) SDL.getContext().getSystemService(Context.VIBRATOR_SERVICE); | |
330 if (vib != null) { | |
331 if (Build.VERSION.SDK_INT >= 11) { | |
332 hasVibratorService = vib.hasVibrator(); | |
333 } else { | |
334 hasVibratorService = true; | |
335 } | |
336 | |
337 if (hasVibratorService) { | |
338 SDLHaptic haptic = getHaptic(deviceId_VIBRATOR_SERVICE); | |
339 if (haptic == null) { | |
340 haptic = new SDLHaptic(); | |
341 haptic.device_id = deviceId_VIBRATOR_SERVICE; | |
342 haptic.name = "VIBRATOR_SERVICE"; | |
343 haptic.vib = vib; | |
344 mHaptics.add(haptic); | |
345 SDLControllerManager.nativeAddHaptic(haptic.device_id, haptic.name); | |
346 } | |
347 } | |
348 } | |
349 | |
350 /* Check removed devices */ | |
351 ArrayList<Integer> removedDevices = new ArrayList<Integer>(); | |
352 for(int i=0; i < mHaptics.size(); i++) { | |
353 int device_id = mHaptics.get(i).device_id; | |
354 int j; | |
355 for (j=0; j < deviceIds.length; j++) { | |
356 if (device_id == deviceIds[j]) break; | |
357 } | |
358 | |
359 if (device_id == deviceId_VIBRATOR_SERVICE && hasVibratorService) { | |
360 // don't remove the vibrator if it is still present | |
361 } else if (j == deviceIds.length) { | |
362 removedDevices.add(device_id); | |
363 } | |
364 } | |
365 | |
366 for(int i=0; i < removedDevices.size(); i++) { | |
367 int device_id = removedDevices.get(i); | |
368 SDLControllerManager.nativeRemoveHaptic(device_id); | |
369 for (int j=0; j < mHaptics.size(); j++) { | |
370 if (mHaptics.get(j).device_id == device_id) { | |
371 mHaptics.remove(j); | |
372 break; | |
373 } | |
374 } | |
375 } | |
376 } | |
377 | |
378 protected SDLHaptic getHaptic(int device_id) { | |
379 for(int i=0; i < mHaptics.size(); i++) { | |
380 if (mHaptics.get(i).device_id == device_id) { | |
381 return mHaptics.get(i); | |
382 } | |
383 } | |
384 return null; | |
385 } | |
386 } | |
387 | |
388 class SDLGenericMotionListener_API12 implements View.OnGenericMotionListener { | |
389 // Generic Motion (mouse hover, joystick...) events go here | |
390 @Override | |
391 public boolean onGenericMotion(View v, MotionEvent event) { | |
392 float x, y; | |
393 int action; | |
394 | |
395 switch ( event.getSource() ) { | |
396 case InputDevice.SOURCE_JOYSTICK: | |
397 case InputDevice.SOURCE_GAMEPAD: | |
398 case InputDevice.SOURCE_DPAD: | |
399 return SDLControllerManager.handleJoystickMotionEvent(event); | |
400 | |
401 case InputDevice.SOURCE_MOUSE: | |
402 if (!SDLActivity.mSeparateMouseAndTouch) { | |
403 break; | |
404 } | |
405 action = event.getActionMasked(); | |
406 switch (action) { | |
407 case MotionEvent.ACTION_SCROLL: | |
408 x = event.getAxisValue(MotionEvent.AXIS_HSCROLL, 0); | |
409 y = event.getAxisValue(MotionEvent.AXIS_VSCROLL, 0); | |
410 SDLActivity.onNativeMouse(0, action, x, y); | |
411 return true; | |
412 | |
413 case MotionEvent.ACTION_HOVER_MOVE: | |
414 x = event.getX(0); | |
415 y = event.getY(0); | |
416 | |
417 SDLActivity.onNativeMouse(0, action, x, y); | |
418 return true; | |
419 | |
420 default: | |
421 break; | |
422 } | |
423 break; | |
424 | |
425 default: | |
426 break; | |
427 } | |
428 | |
429 // Event was not managed | |
430 return false; | |
431 } | |
432 } | |
433 |