3232package com .jme3 .input .android ;
3333
3434import android .opengl .GLSurfaceView ;
35+ import android .view .MotionEvent ;
3536import com .jme3 .input .InputManager ;
3637import com .jme3 .input .JoyInput ;
3738import com .jme3 .input .Joystick ;
3839import com .jme3 .input .RawInputListener ;
3940import com .jme3 .input .event .InputEvent ;
4041import com .jme3 .input .event .JoyAxisEvent ;
4142import com .jme3 .input .event .JoyButtonEvent ;
43+ import com .jme3 .input .virtual .VirtualJoystick ;
4244import com .jme3 .system .AppSettings ;
4345import com .jme3 .system .JmeSystem ;
4446import java .util .ArrayList ;
4850import java .util .logging .Logger ;
4951
5052/**
51- * Main class that manages various joystick devices. Joysticks can be many forms
52- * including a simulated joystick to communicate the device orientation as well
53- * as physical gamepads. <br>
53+ * Main class that manages joystick devices. Joysticks can be physical gamepads,
54+ * the on-screen virtual joystick, or an explicitly-enabled sensor joystick. <br>
5455 * This class manages all the joysticks and feeds the inputs from each back
5556 * to jME's InputManager.
5657 *
6768 *
6869 * MainActivity needs the following line to enable Joysticks on Android platforms
6970 * joystickEventsEnabled = true;
70- * This is done to allow for battery conservation when sensor data or gamepads
71+ * This is done to allow for battery conservation when sensor data or joysticks
7172 * are not required by the application.
7273 *
7374 * {@code
7980 */
8081public class AndroidJoyInput implements JoyInput {
8182 private static final Logger logger = Logger .getLogger (AndroidJoyInput .class .getName ());
82- public static boolean disableSensors = false ;
8383
8484 protected AndroidInputHandler inputHandler ;
8585 protected List <Joystick > joystickList = new ArrayList <>();
@@ -92,20 +92,32 @@ public class AndroidJoyInput implements JoyInput {
9292 private ConcurrentLinkedQueue <InputEvent > eventQueue = new ConcurrentLinkedQueue <>();
9393 private AndroidSensorJoyInput sensorJoyInput ;
9494 private boolean onDeviceJoystickRumble = false ;
95+ private String virtualJoystickMode = AppSettings .VIRTUAL_JOYSTICK_AUTO ;
96+ private String virtualJoystickDefaultLayout = AppSettings .VIRTUAL_JOYSTICK_LAYOUT_DYNAMIC ;
97+ private boolean useJoysticks = true ;
98+ private boolean useAndroidSensorJoystick = false ;
99+ private boolean physicalJoystickAvailable = false ;
100+ private boolean keyboardSuppressedAutoJoystick = false ;
101+ private volatile VirtualJoystick virtualJoystick ;
102+ private GLSurfaceView view ;
95103
96104 public AndroidJoyInput (AndroidInputHandler inputHandler ) {
97105 this .inputHandler = inputHandler ;
98- sensorJoyInput = new AndroidSensorJoyInput (this );
99106 }
100107
101108 public void setView (GLSurfaceView view ) {
109+ this .view = view ;
102110 if (sensorJoyInput != null ) {
103111 sensorJoyInput .setView (view );
104112 }
105113 }
106114
107115 public void loadSettings (AppSettings settings ) {
108116 onDeviceJoystickRumble = settings .isOnDeviceJoystickRumble ();
117+ virtualJoystickMode = settings .getVirtualJoystickMode ();
118+ virtualJoystickDefaultLayout = settings .getVirtualJoystickDefaultLayout ();
119+ useJoysticks = settings .useJoysticks ();
120+ useAndroidSensorJoystick = settings .useAndroidSensorJoystick ();
109121 }
110122
111123 boolean isOnDeviceJoystickRumble () {
@@ -127,6 +139,9 @@ public void pauseJoysticks() {
127139 if (onDeviceJoystickRumble ) {
128140 JmeSystem .stopRumble ();
129141 }
142+ if (virtualJoystick != null ) {
143+ virtualJoystick .onPointerCancel (0L );
144+ }
130145
131146 }
132147
@@ -138,7 +153,6 @@ public void resumeJoysticks() {
138153 if (sensorJoyInput != null ) {
139154 sensorJoyInput .resumeSensors ();
140155 }
141-
142156 }
143157
144158 @ Override
@@ -154,12 +168,11 @@ public boolean isInitialized() {
154168 @ Override
155169 public void destroy () {
156170 initialized = false ;
157-
158171 if (sensorJoyInput != null ) {
159172 sensorJoyInput .destroy ();
173+ sensorJoyInput = null ;
160174 }
161-
162- setView (null );
175+ view = null ;
163176 }
164177
165178 @ Override
@@ -191,12 +204,72 @@ public Joystick[] loadJoysticks(InputManager inputManager) {
191204 if (logger .isLoggable (Level .INFO )) {
192205 logger .log (Level .INFO , "loading joysticks for {0}" , this .getClass ().getName ());
193206 }
194- if (!disableSensors ) {
207+ joystickList .clear ();
208+ if (useJoysticks && useAndroidSensorJoystick ) {
209+ if (sensorJoyInput == null ) {
210+ sensorJoyInput = new AndroidSensorJoyInput (this );
211+ sensorJoyInput .setView (view );
212+ }
195213 joystickList .add (sensorJoyInput .loadJoystick (joystickList .size (), inputManager ));
196214 }
215+ physicalJoystickAvailable = false ;
216+ if (shouldCreateVirtualJoystick ()) {
217+ virtualJoystick = new VirtualJoystick (inputManager , this , joystickList .size ());
218+ virtualJoystick .setLayout (VirtualJoystick .createLayout (virtualJoystickDefaultLayout ));
219+ virtualJoystick .setEnabled (false );
220+ updateVirtualJoystickAutoVisibility ();
221+ joystickList .add (virtualJoystick );
222+ } else {
223+ virtualJoystick = null ;
224+ }
197225 return joystickList .toArray ( new Joystick [joystickList .size ()] );
198226 }
199227
228+ public boolean onTouch (MotionEvent event ) {
229+ VirtualJoystick joystick = virtualJoystick ;
230+ if (joystick == null || inputHandler .getView () == null ) {
231+ return false ;
232+ }
233+
234+ boolean consumed = false ;
235+ int action = event .getAction () & MotionEvent .ACTION_MASK ;
236+ int pointerIndex = (event .getAction () & MotionEvent .ACTION_POINTER_INDEX_MASK )
237+ >> MotionEvent .ACTION_POINTER_INDEX_SHIFT ;
238+ long time = event .getEventTime ();
239+
240+ switch (action ) {
241+ case MotionEvent .ACTION_POINTER_DOWN :
242+ case MotionEvent .ACTION_DOWN :
243+ consumed = joystick .onPointerDown (event .getPointerId (pointerIndex ),
244+ toJmeX (event .getX (pointerIndex )), toJmeY (event .getY (pointerIndex )), time );
245+ break ;
246+ case MotionEvent .ACTION_POINTER_UP :
247+ case MotionEvent .ACTION_UP :
248+ consumed = joystick .onPointerUp (event .getPointerId (pointerIndex ),
249+ toJmeX (event .getX (pointerIndex )), toJmeY (event .getY (pointerIndex )), time );
250+ break ;
251+ case MotionEvent .ACTION_CANCEL :
252+ consumed = joystick .onPointerCancel (time );
253+ break ;
254+ case MotionEvent .ACTION_MOVE :
255+ for (int i = 0 ; i < event .getPointerCount (); i ++) {
256+ consumed = joystick .onPointerMove (event .getPointerId (i ),
257+ toJmeX (event .getX (i )), toJmeY (event .getY (i )), time ) || consumed ;
258+ }
259+ break ;
260+ default :
261+ break ;
262+ }
263+ return consumed ;
264+ }
265+
266+ public void onKeyboardInput () {
267+ if (AppSettings .VIRTUAL_JOYSTICK_AUTO .equals (virtualJoystickMode )) {
268+ keyboardSuppressedAutoJoystick = true ;
269+ updateVirtualJoystickAutoVisibility ();
270+ }
271+ }
272+
200273 @ Override
201274 public void update () {
202275 if (sensorJoyInput != null ) {
@@ -214,7 +287,43 @@ public void update() {
214287 }
215288 }
216289 }
290+ if (virtualJoystick != null ) {
291+ updateVirtualJoystickAutoVisibility ();
292+ virtualJoystick .dispatchEvents (listener );
293+ }
294+
295+ }
296+
297+ private float toJmeX (float x ) {
298+ return inputHandler .touchInput .getJmeX (x );
299+ }
300+
301+ private float toJmeY (float y ) {
302+ return inputHandler .touchInput .invertY (inputHandler .touchInput .getJmeY (y ));
303+ }
304+
305+ protected void setPhysicalJoystickAvailable (boolean available ) {
306+ physicalJoystickAvailable = available ;
307+ updateVirtualJoystickAutoVisibility ();
308+ }
217309
310+ private boolean shouldCreateVirtualJoystick () {
311+ return useJoysticks && !AppSettings .VIRTUAL_JOYSTICK_DISABLED .equals (virtualJoystickMode );
312+ }
313+
314+ private void updateVirtualJoystickAutoVisibility () {
315+ if (virtualJoystick == null ) {
316+ return ;
317+ }
318+ boolean wasEnabled = virtualJoystick .isEnabled ();
319+ boolean active = AppSettings .VIRTUAL_JOYSTICK_ENABLED .equals (virtualJoystickMode )
320+ || (AppSettings .VIRTUAL_JOYSTICK_AUTO .equals (virtualJoystickMode )
321+ && !physicalJoystickAvailable
322+ && !keyboardSuppressedAutoJoystick
323+ && virtualJoystick .hasInputBindings ());
324+ if (wasEnabled != active ) {
325+ virtualJoystick .setEnabled (active );
326+ }
218327 }
219328
220329}
0 commit comments