SDLControllerManager.java 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849
  1. package org.libsdl.app;
  2. import java.util.ArrayList;
  3. import java.util.Collections;
  4. import java.util.Comparator;
  5. import java.util.List;
  6. import android.content.Context;
  7. import android.os.*;
  8. import android.view.*;
  9. import android.util.Log;
  10. public class SDLControllerManager
  11. {
  12. public static native int nativeSetupJNI();
  13. public static native int nativeAddJoystick(int device_id, String name, String desc,
  14. int vendor_id, int product_id,
  15. boolean is_accelerometer, int button_mask,
  16. int naxes, int nhats, int nballs);
  17. public static native int nativeRemoveJoystick(int device_id);
  18. public static native int nativeAddHaptic(int device_id, String name);
  19. public static native int nativeRemoveHaptic(int device_id);
  20. public static native int onNativePadDown(int device_id, int keycode);
  21. public static native int onNativePadUp(int device_id, int keycode);
  22. public static native void onNativeJoy(int device_id, int axis,
  23. float value);
  24. public static native void onNativeHat(int device_id, int hat_id,
  25. int x, int y);
  26. protected static SDLJoystickHandler mJoystickHandler;
  27. protected static SDLHapticHandler mHapticHandler;
  28. private static final String TAG = "SDLControllerManager";
  29. public static void initialize() {
  30. mJoystickHandler = null;
  31. mHapticHandler = null;
  32. SDLControllerManager.setup();
  33. }
  34. public static void setup() {
  35. if (Build.VERSION.SDK_INT >= 19) {
  36. mJoystickHandler = new SDLJoystickHandler_API19();
  37. } else if (Build.VERSION.SDK_INT >= 16) {
  38. mJoystickHandler = new SDLJoystickHandler_API16();
  39. } else if (Build.VERSION.SDK_INT >= 12) {
  40. mJoystickHandler = new SDLJoystickHandler_API12();
  41. } else {
  42. mJoystickHandler = new SDLJoystickHandler();
  43. }
  44. if (Build.VERSION.SDK_INT >= 26) {
  45. mHapticHandler = new SDLHapticHandler_API26();
  46. } else {
  47. mHapticHandler = new SDLHapticHandler();
  48. }
  49. }
  50. // Joystick glue code, just a series of stubs that redirect to the SDLJoystickHandler instance
  51. public static boolean handleJoystickMotionEvent(MotionEvent event) {
  52. return mJoystickHandler.handleMotionEvent(event);
  53. }
  54. /**
  55. * This method is called by SDL using JNI.
  56. */
  57. public static void pollInputDevices() {
  58. mJoystickHandler.pollInputDevices();
  59. }
  60. /**
  61. * This method is called by SDL using JNI.
  62. */
  63. public static void pollHapticDevices() {
  64. mHapticHandler.pollHapticDevices();
  65. }
  66. /**
  67. * This method is called by SDL using JNI.
  68. */
  69. public static void hapticRun(int device_id, float intensity, int length) {
  70. mHapticHandler.run(device_id, intensity, length);
  71. }
  72. /**
  73. * This method is called by SDL using JNI.
  74. */
  75. public static void hapticStop(int device_id)
  76. {
  77. mHapticHandler.stop(device_id);
  78. }
  79. // Check if a given device is considered a possible SDL joystick
  80. public static boolean isDeviceSDLJoystick(int deviceId) {
  81. InputDevice device = InputDevice.getDevice(deviceId);
  82. // We cannot use InputDevice.isVirtual before API 16, so let's accept
  83. // only nonnegative device ids (VIRTUAL_KEYBOARD equals -1)
  84. if ((device == null) || (deviceId < 0)) {
  85. return false;
  86. }
  87. int sources = device.getSources();
  88. /* This is called for every button press, so let's not spam the logs */
  89. /**
  90. if ((sources & InputDevice.SOURCE_CLASS_JOYSTICK) == InputDevice.SOURCE_CLASS_JOYSTICK) {
  91. Log.v(TAG, "Input device " + device.getName() + " is a joystick.");
  92. }
  93. if ((sources & InputDevice.SOURCE_DPAD) == InputDevice.SOURCE_DPAD) {
  94. Log.v(TAG, "Input device " + device.getName() + " is a dpad.");
  95. }
  96. if ((sources & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD) {
  97. Log.v(TAG, "Input device " + device.getName() + " is a gamepad.");
  98. }
  99. **/
  100. return (((sources & InputDevice.SOURCE_CLASS_JOYSTICK) == InputDevice.SOURCE_CLASS_JOYSTICK) ||
  101. ((sources & InputDevice.SOURCE_DPAD) == InputDevice.SOURCE_DPAD) ||
  102. ((sources & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD)
  103. );
  104. }
  105. }
  106. /* A null joystick handler for API level < 12 devices (the accelerometer is handled separately) */
  107. class SDLJoystickHandler {
  108. /**
  109. * Handles given MotionEvent.
  110. * @param event the event to be handled.
  111. * @return if given event was processed.
  112. */
  113. public boolean handleMotionEvent(MotionEvent event) {
  114. return false;
  115. }
  116. /**
  117. * Handles adding and removing of input devices.
  118. */
  119. public void pollInputDevices() {
  120. }
  121. }
  122. /* Actual joystick functionality available for API >= 12 devices */
  123. class SDLJoystickHandler_API12 extends SDLJoystickHandler {
  124. static class SDLJoystick {
  125. public int device_id;
  126. public String name;
  127. public String desc;
  128. public ArrayList<InputDevice.MotionRange> axes;
  129. public ArrayList<InputDevice.MotionRange> hats;
  130. }
  131. static class RangeComparator implements Comparator<InputDevice.MotionRange> {
  132. @Override
  133. public int compare(InputDevice.MotionRange arg0, InputDevice.MotionRange arg1) {
  134. // Some controllers, like the Moga Pro 2, return AXIS_GAS (22) for right trigger and AXIS_BRAKE (23) for left trigger - swap them so they're sorted in the right order for SDL
  135. int arg0Axis = arg0.getAxis();
  136. int arg1Axis = arg1.getAxis();
  137. if (arg0Axis == MotionEvent.AXIS_GAS) {
  138. arg0Axis = MotionEvent.AXIS_BRAKE;
  139. } else if (arg0Axis == MotionEvent.AXIS_BRAKE) {
  140. arg0Axis = MotionEvent.AXIS_GAS;
  141. }
  142. if (arg1Axis == MotionEvent.AXIS_GAS) {
  143. arg1Axis = MotionEvent.AXIS_BRAKE;
  144. } else if (arg1Axis == MotionEvent.AXIS_BRAKE) {
  145. arg1Axis = MotionEvent.AXIS_GAS;
  146. }
  147. return arg0Axis - arg1Axis;
  148. }
  149. }
  150. private ArrayList<SDLJoystick> mJoysticks;
  151. public SDLJoystickHandler_API12() {
  152. mJoysticks = new ArrayList<SDLJoystick>();
  153. }
  154. @Override
  155. public void pollInputDevices() {
  156. int[] deviceIds = InputDevice.getDeviceIds();
  157. for(int i=0; i < deviceIds.length; ++i) {
  158. SDLJoystick joystick = getJoystick(deviceIds[i]);
  159. if (joystick == null) {
  160. joystick = new SDLJoystick();
  161. InputDevice joystickDevice = InputDevice.getDevice(deviceIds[i]);
  162. if (SDLControllerManager.isDeviceSDLJoystick(deviceIds[i])) {
  163. joystick.device_id = deviceIds[i];
  164. joystick.name = joystickDevice.getName();
  165. joystick.desc = getJoystickDescriptor(joystickDevice);
  166. joystick.axes = new ArrayList<InputDevice.MotionRange>();
  167. joystick.hats = new ArrayList<InputDevice.MotionRange>();
  168. List<InputDevice.MotionRange> ranges = joystickDevice.getMotionRanges();
  169. Collections.sort(ranges, new RangeComparator());
  170. for (InputDevice.MotionRange range : ranges ) {
  171. if ((range.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
  172. if (range.getAxis() == MotionEvent.AXIS_HAT_X ||
  173. range.getAxis() == MotionEvent.AXIS_HAT_Y) {
  174. joystick.hats.add(range);
  175. }
  176. else {
  177. joystick.axes.add(range);
  178. }
  179. }
  180. }
  181. mJoysticks.add(joystick);
  182. SDLControllerManager.nativeAddJoystick(joystick.device_id, joystick.name, joystick.desc, getVendorId(joystickDevice), getProductId(joystickDevice), false, getButtonMask(joystickDevice), joystick.axes.size(), joystick.hats.size()/2, 0);
  183. }
  184. }
  185. }
  186. /* Check removed devices */
  187. ArrayList<Integer> removedDevices = new ArrayList<Integer>();
  188. for(int i=0; i < mJoysticks.size(); i++) {
  189. int device_id = mJoysticks.get(i).device_id;
  190. int j;
  191. for (j=0; j < deviceIds.length; j++) {
  192. if (device_id == deviceIds[j]) break;
  193. }
  194. if (j == deviceIds.length) {
  195. removedDevices.add(Integer.valueOf(device_id));
  196. }
  197. }
  198. for(int i=0; i < removedDevices.size(); i++) {
  199. int device_id = removedDevices.get(i).intValue();
  200. SDLControllerManager.nativeRemoveJoystick(device_id);
  201. for (int j=0; j < mJoysticks.size(); j++) {
  202. if (mJoysticks.get(j).device_id == device_id) {
  203. mJoysticks.remove(j);
  204. break;
  205. }
  206. }
  207. }
  208. }
  209. protected SDLJoystick getJoystick(int device_id) {
  210. for(int i=0; i < mJoysticks.size(); i++) {
  211. if (mJoysticks.get(i).device_id == device_id) {
  212. return mJoysticks.get(i);
  213. }
  214. }
  215. return null;
  216. }
  217. @Override
  218. public boolean handleMotionEvent(MotionEvent event) {
  219. if ((event.getSource() & InputDevice.SOURCE_JOYSTICK) != 0) {
  220. int actionPointerIndex = event.getActionIndex();
  221. int action = event.getActionMasked();
  222. switch(action) {
  223. case MotionEvent.ACTION_MOVE:
  224. SDLJoystick joystick = getJoystick(event.getDeviceId());
  225. if ( joystick != null ) {
  226. for (int i = 0; i < joystick.axes.size(); i++) {
  227. InputDevice.MotionRange range = joystick.axes.get(i);
  228. /* Normalize the value to -1...1 */
  229. float value = ( event.getAxisValue( range.getAxis(), actionPointerIndex) - range.getMin() ) / range.getRange() * 2.0f - 1.0f;
  230. SDLControllerManager.onNativeJoy(joystick.device_id, i, value );
  231. }
  232. for (int i = 0; i < joystick.hats.size(); i+=2) {
  233. int hatX = Math.round(event.getAxisValue( joystick.hats.get(i).getAxis(), actionPointerIndex ) );
  234. int hatY = Math.round(event.getAxisValue( joystick.hats.get(i+1).getAxis(), actionPointerIndex ) );
  235. SDLControllerManager.onNativeHat(joystick.device_id, i/2, hatX, hatY );
  236. }
  237. }
  238. break;
  239. default:
  240. break;
  241. }
  242. }
  243. return true;
  244. }
  245. public String getJoystickDescriptor(InputDevice joystickDevice) {
  246. return joystickDevice.getName();
  247. }
  248. public int getProductId(InputDevice joystickDevice) {
  249. return 0;
  250. }
  251. public int getVendorId(InputDevice joystickDevice) {
  252. return 0;
  253. }
  254. public int getButtonMask(InputDevice joystickDevice) {
  255. return -1;
  256. }
  257. }
  258. class SDLJoystickHandler_API16 extends SDLJoystickHandler_API12 {
  259. @Override
  260. public String getJoystickDescriptor(InputDevice joystickDevice) {
  261. String desc = joystickDevice.getDescriptor();
  262. if (desc != null && !desc.isEmpty()) {
  263. return desc;
  264. }
  265. return super.getJoystickDescriptor(joystickDevice);
  266. }
  267. }
  268. class SDLJoystickHandler_API19 extends SDLJoystickHandler_API16 {
  269. @Override
  270. public int getProductId(InputDevice joystickDevice) {
  271. return joystickDevice.getProductId();
  272. }
  273. @Override
  274. public int getVendorId(InputDevice joystickDevice) {
  275. return joystickDevice.getVendorId();
  276. }
  277. @Override
  278. public int getButtonMask(InputDevice joystickDevice) {
  279. int button_mask = 0;
  280. int[] keys = new int[] {
  281. KeyEvent.KEYCODE_BUTTON_A,
  282. KeyEvent.KEYCODE_BUTTON_B,
  283. KeyEvent.KEYCODE_BUTTON_X,
  284. KeyEvent.KEYCODE_BUTTON_Y,
  285. KeyEvent.KEYCODE_BACK,
  286. KeyEvent.KEYCODE_BUTTON_MODE,
  287. KeyEvent.KEYCODE_BUTTON_START,
  288. KeyEvent.KEYCODE_BUTTON_THUMBL,
  289. KeyEvent.KEYCODE_BUTTON_THUMBR,
  290. KeyEvent.KEYCODE_BUTTON_L1,
  291. KeyEvent.KEYCODE_BUTTON_R1,
  292. KeyEvent.KEYCODE_DPAD_UP,
  293. KeyEvent.KEYCODE_DPAD_DOWN,
  294. KeyEvent.KEYCODE_DPAD_LEFT,
  295. KeyEvent.KEYCODE_DPAD_RIGHT,
  296. KeyEvent.KEYCODE_BUTTON_SELECT,
  297. KeyEvent.KEYCODE_DPAD_CENTER,
  298. // These don't map into any SDL controller buttons directly
  299. KeyEvent.KEYCODE_BUTTON_L2,
  300. KeyEvent.KEYCODE_BUTTON_R2,
  301. KeyEvent.KEYCODE_BUTTON_C,
  302. KeyEvent.KEYCODE_BUTTON_Z,
  303. KeyEvent.KEYCODE_BUTTON_1,
  304. KeyEvent.KEYCODE_BUTTON_2,
  305. KeyEvent.KEYCODE_BUTTON_3,
  306. KeyEvent.KEYCODE_BUTTON_4,
  307. KeyEvent.KEYCODE_BUTTON_5,
  308. KeyEvent.KEYCODE_BUTTON_6,
  309. KeyEvent.KEYCODE_BUTTON_7,
  310. KeyEvent.KEYCODE_BUTTON_8,
  311. KeyEvent.KEYCODE_BUTTON_9,
  312. KeyEvent.KEYCODE_BUTTON_10,
  313. KeyEvent.KEYCODE_BUTTON_11,
  314. KeyEvent.KEYCODE_BUTTON_12,
  315. KeyEvent.KEYCODE_BUTTON_13,
  316. KeyEvent.KEYCODE_BUTTON_14,
  317. KeyEvent.KEYCODE_BUTTON_15,
  318. KeyEvent.KEYCODE_BUTTON_16,
  319. };
  320. int[] masks = new int[] {
  321. (1 << 0), // A -> A
  322. (1 << 1), // B -> B
  323. (1 << 2), // X -> X
  324. (1 << 3), // Y -> Y
  325. (1 << 4), // BACK -> BACK
  326. (1 << 5), // MODE -> GUIDE
  327. (1 << 6), // START -> START
  328. (1 << 7), // THUMBL -> LEFTSTICK
  329. (1 << 8), // THUMBR -> RIGHTSTICK
  330. (1 << 9), // L1 -> LEFTSHOULDER
  331. (1 << 10), // R1 -> RIGHTSHOULDER
  332. (1 << 11), // DPAD_UP -> DPAD_UP
  333. (1 << 12), // DPAD_DOWN -> DPAD_DOWN
  334. (1 << 13), // DPAD_LEFT -> DPAD_LEFT
  335. (1 << 14), // DPAD_RIGHT -> DPAD_RIGHT
  336. (1 << 4), // SELECT -> BACK
  337. (1 << 0), // DPAD_CENTER -> A
  338. (1 << 15), // L2 -> ??
  339. (1 << 16), // R2 -> ??
  340. (1 << 17), // C -> ??
  341. (1 << 18), // Z -> ??
  342. (1 << 20), // 1 -> ??
  343. (1 << 21), // 2 -> ??
  344. (1 << 22), // 3 -> ??
  345. (1 << 23), // 4 -> ??
  346. (1 << 24), // 5 -> ??
  347. (1 << 25), // 6 -> ??
  348. (1 << 26), // 7 -> ??
  349. (1 << 27), // 8 -> ??
  350. (1 << 28), // 9 -> ??
  351. (1 << 29), // 10 -> ??
  352. (1 << 30), // 11 -> ??
  353. (1 << 31), // 12 -> ??
  354. // We're out of room...
  355. 0xFFFFFFFF, // 13 -> ??
  356. 0xFFFFFFFF, // 14 -> ??
  357. 0xFFFFFFFF, // 15 -> ??
  358. 0xFFFFFFFF, // 16 -> ??
  359. };
  360. boolean[] has_keys = joystickDevice.hasKeys(keys);
  361. for (int i = 0; i < keys.length; ++i) {
  362. if (has_keys[i]) {
  363. button_mask |= masks[i];
  364. }
  365. }
  366. return button_mask;
  367. }
  368. }
  369. class SDLHapticHandler_API26 extends SDLHapticHandler {
  370. @Override
  371. public void run(int device_id, float intensity, int length) {
  372. SDLHaptic haptic = getHaptic(device_id);
  373. if (haptic != null) {
  374. Log.d("SDL", "Rtest: Vibe with intensity " + intensity + " for " + length);
  375. if (intensity == 0.0f) {
  376. stop(device_id);
  377. return;
  378. }
  379. int vibeValue = Math.round(intensity * 255);
  380. if (vibeValue > 255) {
  381. vibeValue = 255;
  382. }
  383. if (vibeValue < 1) {
  384. stop(device_id);
  385. return;
  386. }
  387. try {
  388. haptic.vib.vibrate(VibrationEffect.createOneShot(length, vibeValue));
  389. }
  390. catch (Exception e) {
  391. // Fall back to the generic method, which uses DEFAULT_AMPLITUDE, but works even if
  392. // something went horribly wrong with the Android 8.0 APIs.
  393. haptic.vib.vibrate(length);
  394. }
  395. }
  396. }
  397. }
  398. class SDLHapticHandler {
  399. class SDLHaptic {
  400. public int device_id;
  401. public String name;
  402. public Vibrator vib;
  403. }
  404. private ArrayList<SDLHaptic> mHaptics;
  405. public SDLHapticHandler() {
  406. mHaptics = new ArrayList<SDLHaptic>();
  407. }
  408. public void run(int device_id, float intensity, int length) {
  409. SDLHaptic haptic = getHaptic(device_id);
  410. if (haptic != null) {
  411. haptic.vib.vibrate(length);
  412. }
  413. }
  414. public void stop(int device_id) {
  415. SDLHaptic haptic = getHaptic(device_id);
  416. if (haptic != null) {
  417. haptic.vib.cancel();
  418. }
  419. }
  420. public void pollHapticDevices() {
  421. final int deviceId_VIBRATOR_SERVICE = 999999;
  422. boolean hasVibratorService = false;
  423. int[] deviceIds = InputDevice.getDeviceIds();
  424. // It helps processing the device ids in reverse order
  425. // For example, in the case of the XBox 360 wireless dongle,
  426. // so the first controller seen by SDL matches what the receiver
  427. // considers to be the first controller
  428. if (Build.VERSION.SDK_INT >= 16)
  429. {
  430. for (int i = deviceIds.length - 1; i > -1; i--) {
  431. SDLHaptic haptic = getHaptic(deviceIds[i]);
  432. if (haptic == null) {
  433. InputDevice device = InputDevice.getDevice(deviceIds[i]);
  434. Vibrator vib = device.getVibrator();
  435. if (vib.hasVibrator()) {
  436. haptic = new SDLHaptic();
  437. haptic.device_id = deviceIds[i];
  438. haptic.name = device.getName();
  439. haptic.vib = vib;
  440. mHaptics.add(haptic);
  441. SDLControllerManager.nativeAddHaptic(haptic.device_id, haptic.name);
  442. }
  443. }
  444. }
  445. }
  446. /* Check VIBRATOR_SERVICE */
  447. Vibrator vib = (Vibrator) SDL.getContext().getSystemService(Context.VIBRATOR_SERVICE);
  448. if (vib != null) {
  449. if (Build.VERSION.SDK_INT >= 11) {
  450. hasVibratorService = vib.hasVibrator();
  451. } else {
  452. hasVibratorService = true;
  453. }
  454. if (hasVibratorService) {
  455. SDLHaptic haptic = getHaptic(deviceId_VIBRATOR_SERVICE);
  456. if (haptic == null) {
  457. haptic = new SDLHaptic();
  458. haptic.device_id = deviceId_VIBRATOR_SERVICE;
  459. haptic.name = "VIBRATOR_SERVICE";
  460. haptic.vib = vib;
  461. mHaptics.add(haptic);
  462. SDLControllerManager.nativeAddHaptic(haptic.device_id, haptic.name);
  463. }
  464. }
  465. }
  466. /* Check removed devices */
  467. ArrayList<Integer> removedDevices = new ArrayList<Integer>();
  468. for(int i=0; i < mHaptics.size(); i++) {
  469. int device_id = mHaptics.get(i).device_id;
  470. int j;
  471. for (j=0; j < deviceIds.length; j++) {
  472. if (device_id == deviceIds[j]) break;
  473. }
  474. if (device_id == deviceId_VIBRATOR_SERVICE && hasVibratorService) {
  475. // don't remove the vibrator if it is still present
  476. } else if (j == deviceIds.length) {
  477. removedDevices.add(device_id);
  478. }
  479. }
  480. for(int i=0; i < removedDevices.size(); i++) {
  481. int device_id = removedDevices.get(i);
  482. SDLControllerManager.nativeRemoveHaptic(device_id);
  483. for (int j=0; j < mHaptics.size(); j++) {
  484. if (mHaptics.get(j).device_id == device_id) {
  485. mHaptics.remove(j);
  486. break;
  487. }
  488. }
  489. }
  490. }
  491. protected SDLHaptic getHaptic(int device_id) {
  492. for(int i=0; i < mHaptics.size(); i++) {
  493. if (mHaptics.get(i).device_id == device_id) {
  494. return mHaptics.get(i);
  495. }
  496. }
  497. return null;
  498. }
  499. }
  500. class SDLGenericMotionListener_API12 implements View.OnGenericMotionListener {
  501. // Generic Motion (mouse hover, joystick...) events go here
  502. @Override
  503. public boolean onGenericMotion(View v, MotionEvent event) {
  504. float x, y;
  505. int action;
  506. switch ( event.getSource() ) {
  507. case InputDevice.SOURCE_JOYSTICK:
  508. case InputDevice.SOURCE_GAMEPAD:
  509. case InputDevice.SOURCE_DPAD:
  510. return SDLControllerManager.handleJoystickMotionEvent(event);
  511. case InputDevice.SOURCE_MOUSE:
  512. if (!SDLActivity.mSeparateMouseAndTouch) {
  513. break;
  514. }
  515. action = event.getActionMasked();
  516. switch (action) {
  517. case MotionEvent.ACTION_SCROLL:
  518. x = event.getAxisValue(MotionEvent.AXIS_HSCROLL, 0);
  519. y = event.getAxisValue(MotionEvent.AXIS_VSCROLL, 0);
  520. SDLActivity.onNativeMouse(0, action, x, y, false);
  521. return true;
  522. case MotionEvent.ACTION_HOVER_MOVE:
  523. x = event.getX(0);
  524. y = event.getY(0);
  525. SDLActivity.onNativeMouse(0, action, x, y, false);
  526. return true;
  527. default:
  528. break;
  529. }
  530. break;
  531. default:
  532. break;
  533. }
  534. // Event was not managed
  535. return false;
  536. }
  537. public boolean supportsRelativeMouse() {
  538. return false;
  539. }
  540. public boolean inRelativeMode() {
  541. return false;
  542. }
  543. public boolean setRelativeMouseEnabled(boolean enabled) {
  544. return false;
  545. }
  546. public void reclaimRelativeMouseModeIfNeeded()
  547. {
  548. }
  549. public float getEventX(MotionEvent event) {
  550. return event.getX(0);
  551. }
  552. public float getEventY(MotionEvent event) {
  553. return event.getY(0);
  554. }
  555. }
  556. class SDLGenericMotionListener_API24 extends SDLGenericMotionListener_API12 {
  557. // Generic Motion (mouse hover, joystick...) events go here
  558. private boolean mRelativeModeEnabled;
  559. @Override
  560. public boolean onGenericMotion(View v, MotionEvent event) {
  561. float x, y;
  562. int action;
  563. switch ( event.getSource() ) {
  564. case InputDevice.SOURCE_JOYSTICK:
  565. case InputDevice.SOURCE_GAMEPAD:
  566. case InputDevice.SOURCE_DPAD:
  567. return SDLControllerManager.handleJoystickMotionEvent(event);
  568. case InputDevice.SOURCE_MOUSE:
  569. if (!SDLActivity.mSeparateMouseAndTouch) {
  570. break;
  571. }
  572. action = event.getActionMasked();
  573. switch (action) {
  574. case MotionEvent.ACTION_SCROLL:
  575. x = event.getAxisValue(MotionEvent.AXIS_HSCROLL, 0);
  576. y = event.getAxisValue(MotionEvent.AXIS_VSCROLL, 0);
  577. SDLActivity.onNativeMouse(0, action, x, y, false);
  578. return true;
  579. case MotionEvent.ACTION_HOVER_MOVE:
  580. if (mRelativeModeEnabled) {
  581. x = event.getAxisValue(MotionEvent.AXIS_RELATIVE_X);
  582. y = event.getAxisValue(MotionEvent.AXIS_RELATIVE_Y);
  583. }
  584. else {
  585. x = event.getX(0);
  586. y = event.getY(0);
  587. }
  588. SDLActivity.onNativeMouse(0, action, x, y, mRelativeModeEnabled);
  589. return true;
  590. default:
  591. break;
  592. }
  593. break;
  594. default:
  595. break;
  596. }
  597. // Event was not managed
  598. return false;
  599. }
  600. @Override
  601. public boolean supportsRelativeMouse() {
  602. return true;
  603. }
  604. @Override
  605. public boolean inRelativeMode() {
  606. return mRelativeModeEnabled;
  607. }
  608. @Override
  609. public boolean setRelativeMouseEnabled(boolean enabled) {
  610. mRelativeModeEnabled = enabled;
  611. return true;
  612. }
  613. @Override
  614. public float getEventX(MotionEvent event) {
  615. if (mRelativeModeEnabled) {
  616. return event.getAxisValue(MotionEvent.AXIS_RELATIVE_X);
  617. }
  618. else {
  619. return event.getX(0);
  620. }
  621. }
  622. @Override
  623. public float getEventY(MotionEvent event) {
  624. if (mRelativeModeEnabled) {
  625. return event.getAxisValue(MotionEvent.AXIS_RELATIVE_Y);
  626. }
  627. else {
  628. return event.getY(0);
  629. }
  630. }
  631. }
  632. class SDLGenericMotionListener_API26 extends SDLGenericMotionListener_API24 {
  633. // Generic Motion (mouse hover, joystick...) events go here
  634. private boolean mRelativeModeEnabled;
  635. @Override
  636. public boolean onGenericMotion(View v, MotionEvent event) {
  637. float x, y;
  638. int action;
  639. switch ( event.getSource() ) {
  640. case InputDevice.SOURCE_JOYSTICK:
  641. case InputDevice.SOURCE_GAMEPAD:
  642. case InputDevice.SOURCE_DPAD:
  643. return SDLControllerManager.handleJoystickMotionEvent(event);
  644. case InputDevice.SOURCE_MOUSE:
  645. case 12290: // DeX desktop mouse cursor is a separate non-standard input type.
  646. if (!SDLActivity.mSeparateMouseAndTouch) {
  647. break;
  648. }
  649. action = event.getActionMasked();
  650. switch (action) {
  651. case MotionEvent.ACTION_SCROLL:
  652. x = event.getAxisValue(MotionEvent.AXIS_HSCROLL, 0);
  653. y = event.getAxisValue(MotionEvent.AXIS_VSCROLL, 0);
  654. SDLActivity.onNativeMouse(0, action, x, y, false);
  655. return true;
  656. case MotionEvent.ACTION_HOVER_MOVE:
  657. x = event.getX(0);
  658. y = event.getY(0);
  659. SDLActivity.onNativeMouse(0, action, x, y, false);
  660. return true;
  661. default:
  662. break;
  663. }
  664. break;
  665. case InputDevice.SOURCE_MOUSE_RELATIVE:
  666. if (!SDLActivity.mSeparateMouseAndTouch) {
  667. break;
  668. }
  669. action = event.getActionMasked();
  670. switch (action) {
  671. case MotionEvent.ACTION_SCROLL:
  672. x = event.getAxisValue(MotionEvent.AXIS_HSCROLL, 0);
  673. y = event.getAxisValue(MotionEvent.AXIS_VSCROLL, 0);
  674. SDLActivity.onNativeMouse(0, action, x, y, false);
  675. return true;
  676. case MotionEvent.ACTION_HOVER_MOVE:
  677. x = event.getX(0);
  678. y = event.getY(0);
  679. SDLActivity.onNativeMouse(0, action, x, y, true);
  680. return true;
  681. default:
  682. break;
  683. }
  684. break;
  685. default:
  686. break;
  687. }
  688. // Event was not managed
  689. return false;
  690. }
  691. @Override
  692. public boolean supportsRelativeMouse() {
  693. return (!SDLActivity.isDeXMode() || (Build.VERSION.SDK_INT >= 27));
  694. }
  695. @Override
  696. public boolean inRelativeMode() {
  697. return mRelativeModeEnabled;
  698. }
  699. @Override
  700. public boolean setRelativeMouseEnabled(boolean enabled) {
  701. if (!SDLActivity.isDeXMode() || (Build.VERSION.SDK_INT >= 27)) {
  702. if (enabled) {
  703. SDLActivity.getContentView().requestPointerCapture();
  704. }
  705. else {
  706. SDLActivity.getContentView().releasePointerCapture();
  707. }
  708. mRelativeModeEnabled = enabled;
  709. return true;
  710. }
  711. else
  712. {
  713. return false;
  714. }
  715. }
  716. @Override
  717. public void reclaimRelativeMouseModeIfNeeded()
  718. {
  719. if (mRelativeModeEnabled && !SDLActivity.isDeXMode()) {
  720. SDLActivity.getContentView().requestPointerCapture();
  721. }
  722. }
  723. @Override
  724. public float getEventX(MotionEvent event) {
  725. // Relative mouse in capture mode will only have relative for X/Y
  726. return event.getX(0);
  727. }
  728. @Override
  729. public float getEventY(MotionEvent event) {
  730. // Relative mouse in capture mode will only have relative for X/Y
  731. return event.getY(0);
  732. }
  733. }