فهرست منبع

Merge branch 'AndroidInput'

iwgeric 10 سال پیش
والد
کامیت
a5b4df68d8

+ 100 - 174
jme3-android/src/main/java/com/jme3/input/android/AndroidGestureHandler.java → jme3-android/src/main/java/com/jme3/input/android/AndroidGestureProcessor.java

@@ -35,314 +35,240 @@ package com.jme3.input.android;
 import android.view.GestureDetector;
 import android.view.GestureDetector;
 import android.view.MotionEvent;
 import android.view.MotionEvent;
 import android.view.ScaleGestureDetector;
 import android.view.ScaleGestureDetector;
-import android.view.View;
-import com.jme3.input.event.InputEvent;
-import com.jme3.input.event.MouseMotionEvent;
 import com.jme3.input.event.TouchEvent;
 import com.jme3.input.event.TouchEvent;
 import java.util.logging.Level;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 import java.util.logging.Logger;
 
 
 /**
 /**
  * AndroidGestureHandler uses Gesture type listeners to create jME TouchEvents
  * AndroidGestureHandler uses Gesture type listeners to create jME TouchEvents
- * for gestures.  This class is designed to handle the gestures supported 
+ * for gestures.  This class is designed to handle the gestures supported
  * on Android rev 9 (Android 2.3).  Extend this class to add functionality
  * on Android rev 9 (Android 2.3).  Extend this class to add functionality
  * added by Android after rev 9.
  * added by Android after rev 9.
- * 
+ *
  * @author iwgeric
  * @author iwgeric
  */
  */
-public class AndroidGestureHandler implements 
-        GestureDetector.OnGestureListener, 
+public class AndroidGestureProcessor implements
+        GestureDetector.OnGestureListener,
         GestureDetector.OnDoubleTapListener,
         GestureDetector.OnDoubleTapListener,
         ScaleGestureDetector.OnScaleGestureListener {
         ScaleGestureDetector.OnScaleGestureListener {
-    private static final Logger logger = Logger.getLogger(AndroidGestureHandler.class.getName());
-    private AndroidInputHandler androidInput;
-    private GestureDetector gestureDetector;
-    private ScaleGestureDetector scaleDetector;
+    private static final Logger logger = Logger.getLogger(AndroidGestureProcessor.class.getName());
+
+    private AndroidTouchInput touchInput;
     float gestureDownX = -1f;
     float gestureDownX = -1f;
     float gestureDownY = -1f;
     float gestureDownY = -1f;
     float scaleStartX = -1f;
     float scaleStartX = -1f;
     float scaleStartY = -1f;
     float scaleStartY = -1f;
 
 
-    public AndroidGestureHandler(AndroidInputHandler androidInput) {
-        this.androidInput = androidInput;
-    }
-    
-    public void initialize() {
-    }
-    
-    public void destroy() {
-        setView(null);
-    }
-    
-    public void setView(View view) {
-        if (view != null) {
-            gestureDetector = new GestureDetector(view.getContext(), this);
-            scaleDetector = new ScaleGestureDetector(view.getContext(), this);
-        } else {
-            gestureDetector = null;
-            scaleDetector = null;
-        }
-    }
-    
-    public void detectGesture(MotionEvent event) {
-        if (gestureDetector != null && scaleDetector != null) {
-            gestureDetector.onTouchEvent(event);
-            scaleDetector.onTouchEvent(event);
-        }
-    }
-
-    private int getPointerIndex(MotionEvent event) {
-        return (event.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK)
-                >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
-    }
-    
-    private int getPointerId(MotionEvent event) {
-        return event.getPointerId(getPointerIndex(event));
+    public AndroidGestureProcessor(AndroidTouchInput touchInput) {
+        this.touchInput = touchInput;
     }
     }
-    
-    private void processEvent(TouchEvent event) {
-        // Add the touch event
-        androidInput.addEvent(event);
-        if (androidInput.isSimulateMouse()) {
-            InputEvent mouseEvent = generateMouseEvent(event);
-            if (mouseEvent != null) {
-                // Add the mouse event
-                androidInput.addEvent(mouseEvent);
-            }
-        }
-    }
-
-    // TODO: Ring Buffer for mouse events?
-    private InputEvent generateMouseEvent(TouchEvent event) {
-        InputEvent inputEvent = null;
-        int newX;
-        int newY;
-        int newDX;
-        int newDY;
 
 
-        if (androidInput.isMouseEventsInvertX()) {
-            newX = (int) (androidInput.invertX(event.getX()));
-            newDX = (int)event.getDeltaX() * -1;
-        } else {
-            newX = (int) event.getX();
-            newDX = (int)event.getDeltaX();
-        }
-        int wheel = (int) (event.getScaleSpan()); // might need to scale to match mouse wheel
-        int dWheel = (int) (event.getDeltaScaleSpan()); // might need to scale to match mouse wheel
-
-        if (androidInput.isMouseEventsInvertY()) {
-            newY = (int) (androidInput.invertY(event.getY()));
-            newDY = (int)event.getDeltaY() * -1;
-        } else {
-            newY = (int) event.getY();
-            newDY = (int)event.getDeltaY();
-        }
-
-        switch (event.getType()) {
-            case SCALE_MOVE:
-                inputEvent = new MouseMotionEvent(newX, newY, newDX, newDY, wheel, dWheel);
-                inputEvent.setTime(event.getTime());
-                break;
-        }
-
-        return inputEvent;
-    }
-    
     /* Events from onGestureListener */
     /* Events from onGestureListener */
-    
+
+    @Override
     public boolean onDown(MotionEvent event) {
     public boolean onDown(MotionEvent event) {
         // start of all GestureListeners.  Not really a gesture by itself
         // start of all GestureListeners.  Not really a gesture by itself
         // so we don't create an event.
         // so we don't create an event.
         // However, reset the scaleInProgress here since this is the beginning
         // However, reset the scaleInProgress here since this is the beginning
         // of a series of gesture events.
         // of a series of gesture events.
-//        logger.log(Level.INFO, "onDown pointerId: {0}, action: {1}, x: {2}, y: {3}", 
-//                new Object[]{getPointerId(event), getAction(event), event.getX(), event.getY()});
-        gestureDownX = androidInput.getJmeX(event.getX());
-        gestureDownY = androidInput.invertY(androidInput.getJmeY(event.getY()));
+//        logger.log(Level.INFO, "onDown pointerId: {0}, action: {1}, x: {2}, y: {3}",
+//                new Object[]{touchInput.getPointerId(event), touchInput.getAction(event), event.getX(), event.getY()});
+        gestureDownX = touchInput.getJmeX(event.getX());
+        gestureDownY = touchInput.invertY(touchInput.getJmeY(event.getY()));
         return true;
         return true;
     }
     }
 
 
+    @Override
     public boolean onSingleTapUp(MotionEvent event) {
     public boolean onSingleTapUp(MotionEvent event) {
         // Up of single tap.  May be followed by a double tap later.
         // Up of single tap.  May be followed by a double tap later.
         // use onSingleTapConfirmed instead.
         // use onSingleTapConfirmed instead.
-//        logger.log(Level.INFO, "onSingleTapUp pointerId: {0}, action: {1}, x: {2}, y: {3}", 
-//                new Object[]{getPointerId(event), getAction(event), event.getX(), event.getY()});
+//        logger.log(Level.INFO, "onSingleTapUp pointerId: {0}, action: {1}, x: {2}, y: {3}",
+//                new Object[]{touchInput.getPointerId(event), touchInput.getAction(event), event.getX(), event.getY()});
         return true;
         return true;
     }
     }
 
 
+    @Override
     public void onShowPress(MotionEvent event) {
     public void onShowPress(MotionEvent event) {
-//        logger.log(Level.INFO, "onShowPress pointerId: {0}, action: {1}, x: {2}, y: {3}", 
-//                new Object[]{getPointerId(event), getAction(event), event.getX(), event.getY()});
-        float jmeX = androidInput.getJmeX(event.getX());
-        float jmeY = androidInput.invertY(androidInput.getJmeY(event.getY()));
-        TouchEvent touchEvent = androidInput.getFreeTouchEvent();
+//        logger.log(Level.INFO, "onShowPress pointerId: {0}, action: {1}, x: {2}, y: {3}",
+//                new Object[]{touchInput.getPointerId(event), touchInput.getAction(event), event.getX(), event.getY()});
+        float jmeX = touchInput.getJmeX(event.getX());
+        float jmeY = touchInput.invertY(touchInput.getJmeY(event.getY()));
+        TouchEvent touchEvent = touchInput.getFreeTouchEvent();
         touchEvent.set(TouchEvent.Type.SHOWPRESS, jmeX, jmeY, 0, 0);
         touchEvent.set(TouchEvent.Type.SHOWPRESS, jmeX, jmeY, 0, 0);
-        touchEvent.setPointerId(getPointerId(event));
+        touchEvent.setPointerId(touchInput.getPointerId(event));
         touchEvent.setTime(event.getEventTime());
         touchEvent.setTime(event.getEventTime());
         touchEvent.setPressure(event.getPressure());
         touchEvent.setPressure(event.getPressure());
-        processEvent(touchEvent);
+        touchInput.addEvent(touchEvent);
     }
     }
 
 
+    @Override
     public void onLongPress(MotionEvent event) {
     public void onLongPress(MotionEvent event) {
-//        logger.log(Level.INFO, "onLongPress pointerId: {0}, action: {1}, x: {2}, y: {3}", 
-//                new Object[]{getPointerId(event), getAction(event), event.getX(), event.getY()});
-        float jmeX = androidInput.getJmeX(event.getX());
-        float jmeY = androidInput.invertY(androidInput.getJmeY(event.getY()));
-        TouchEvent touchEvent = androidInput.getFreeTouchEvent();
+//        logger.log(Level.INFO, "onLongPress pointerId: {0}, action: {1}, x: {2}, y: {3}",
+//                new Object[]{touchInput.getPointerId(event), touchInput.getAction(event), event.getX(), event.getY()});
+        float jmeX = touchInput.getJmeX(event.getX());
+        float jmeY = touchInput.invertY(touchInput.getJmeY(event.getY()));
+        TouchEvent touchEvent = touchInput.getFreeTouchEvent();
         touchEvent.set(TouchEvent.Type.LONGPRESSED, jmeX, jmeY, 0, 0);
         touchEvent.set(TouchEvent.Type.LONGPRESSED, jmeX, jmeY, 0, 0);
-        touchEvent.setPointerId(getPointerId(event));
+        touchEvent.setPointerId(touchInput.getPointerId(event));
         touchEvent.setTime(event.getEventTime());
         touchEvent.setTime(event.getEventTime());
         touchEvent.setPressure(event.getPressure());
         touchEvent.setPressure(event.getPressure());
-        processEvent(touchEvent);
+        touchInput.addEvent(touchEvent);
     }
     }
 
 
+    @Override
     public boolean onScroll(MotionEvent startEvent, MotionEvent endEvent, float distX, float distY) {
     public boolean onScroll(MotionEvent startEvent, MotionEvent endEvent, float distX, float distY) {
         // if not scaleInProgess, send scroll events.  This is to avoid sending
         // if not scaleInProgess, send scroll events.  This is to avoid sending
         // scroll events when one of the fingers is lifted just before the other one.
         // scroll events when one of the fingers is lifted just before the other one.
         // Avoids sending the scroll for that brief period of time.
         // Avoids sending the scroll for that brief period of time.
         // Return true so that the next event doesn't accumulate the distX and distY values.
         // Return true so that the next event doesn't accumulate the distX and distY values.
-        // Apparantly, both distX and distY are negative.  
+        // Apparantly, both distX and distY are negative.
         // Negate distX to get the real value, but leave distY negative to compensate
         // Negate distX to get the real value, but leave distY negative to compensate
         // for the fact that jME has y=0 at bottom where Android has y=0 at top.
         // for the fact that jME has y=0 at bottom where Android has y=0 at top.
-//        if (!scaleInProgress) {
-        if (!scaleDetector.isInProgress()) {
-//            logger.log(Level.INFO, "onScroll pointerId: {0}, startAction: {1}, startX: {2}, startY: {3}, endAction: {4}, endX: {5}, endY: {6}, dx: {7}, dy: {8}", 
-//                    new Object[]{getPointerId(startEvent), getAction(startEvent), startEvent.getX(), startEvent.getY(), getAction(endEvent), endEvent.getX(), endEvent.getY(), distX, distY});
+        if (!touchInput.getScaleDetector().isInProgress()) {
+//            logger.log(Level.INFO, "onScroll pointerId: {0}, startAction: {1}, startX: {2}, startY: {3}, endAction: {4}, endX: {5}, endY: {6}, dx: {7}, dy: {8}",
+//                    new Object[]{touchInput.getPointerId(startEvent), touchInput.getAction(startEvent), startEvent.getX(), startEvent.getY(), touchInput.getAction(endEvent), endEvent.getX(), endEvent.getY(), distX, distY});
 
 
-            float jmeX = androidInput.getJmeX(endEvent.getX());
-            float jmeY = androidInput.invertY(androidInput.getJmeY(endEvent.getY()));
-            TouchEvent touchEvent = androidInput.getFreeTouchEvent();
-            touchEvent.set(TouchEvent.Type.SCROLL, jmeX, jmeY, androidInput.getJmeX(-distX), androidInput.getJmeY(distY));
-            touchEvent.setPointerId(getPointerId(endEvent));
+            float jmeX = touchInput.getJmeX(endEvent.getX());
+            float jmeY = touchInput.invertY(touchInput.getJmeY(endEvent.getY()));
+            TouchEvent touchEvent = touchInput.getFreeTouchEvent();
+            touchEvent.set(TouchEvent.Type.SCROLL, jmeX, jmeY, touchInput.getJmeX(-distX), touchInput.getJmeY(distY));
+            touchEvent.setPointerId(touchInput.getPointerId(endEvent));
             touchEvent.setTime(endEvent.getEventTime());
             touchEvent.setTime(endEvent.getEventTime());
             touchEvent.setPressure(endEvent.getPressure());
             touchEvent.setPressure(endEvent.getPressure());
-            processEvent(touchEvent);
+            touchInput.addEvent(touchEvent);
         }
         }
         return true;
         return true;
     }
     }
 
 
+    @Override
     public boolean onFling(MotionEvent startEvent, MotionEvent endEvent, float velocityX, float velocityY) {
     public boolean onFling(MotionEvent startEvent, MotionEvent endEvent, float velocityX, float velocityY) {
         // Fling happens only once at the end of the gesture (all fingers up).
         // Fling happens only once at the end of the gesture (all fingers up).
         // Fling returns the velocity of the finger movement in pixels/sec.
         // Fling returns the velocity of the finger movement in pixels/sec.
         // Therefore, the dX and dY values are actually velocity instead of distance values
         // Therefore, the dX and dY values are actually velocity instead of distance values
         // Since this does not track the movement, use the start position and velocity values.
         // Since this does not track the movement, use the start position and velocity values.
-        
-//        logger.log(Level.INFO, "onFling pointerId: {0}, startAction: {1}, startX: {2}, startY: {3}, endAction: {4}, endX: {5}, endY: {6}, velocityX: {7}, velocityY: {8}", 
-//                new Object[]{getPointerId(startEvent), getAction(startEvent), startEvent.getX(), startEvent.getY(), getAction(endEvent), endEvent.getX(), endEvent.getY(), velocityX, velocityY});
 
 
-        float jmeX = androidInput.getJmeX(startEvent.getX());
-        float jmeY = androidInput.invertY(androidInput.getJmeY(startEvent.getY()));
-        TouchEvent touchEvent = androidInput.getFreeTouchEvent();
+//        logger.log(Level.INFO, "onFling pointerId: {0}, startAction: {1}, startX: {2}, startY: {3}, endAction: {4}, endX: {5}, endY: {6}, velocityX: {7}, velocityY: {8}",
+//                new Object[]{touchInput.getPointerId(startEvent), touchInput.getAction(startEvent), startEvent.getX(), startEvent.getY(), touchInput.getAction(endEvent), endEvent.getX(), endEvent.getY(), velocityX, velocityY});
+
+        float jmeX = touchInput.getJmeX(startEvent.getX());
+        float jmeY = touchInput.invertY(touchInput.getJmeY(startEvent.getY()));
+        TouchEvent touchEvent = touchInput.getFreeTouchEvent();
         touchEvent.set(TouchEvent.Type.FLING, jmeX, jmeY, velocityX, velocityY);
         touchEvent.set(TouchEvent.Type.FLING, jmeX, jmeY, velocityX, velocityY);
-        touchEvent.setPointerId(getPointerId(endEvent));
+        touchEvent.setPointerId(touchInput.getPointerId(endEvent));
         touchEvent.setTime(endEvent.getEventTime());
         touchEvent.setTime(endEvent.getEventTime());
         touchEvent.setPressure(endEvent.getPressure());
         touchEvent.setPressure(endEvent.getPressure());
-        processEvent(touchEvent);
+        touchInput.addEvent(touchEvent);
         return true;
         return true;
     }
     }
 
 
     /* Events from onDoubleTapListener */
     /* Events from onDoubleTapListener */
-    
+
+    @Override
     public boolean onSingleTapConfirmed(MotionEvent event) {
     public boolean onSingleTapConfirmed(MotionEvent event) {
         // Up of single tap when no double tap followed.
         // Up of single tap when no double tap followed.
-//        logger.log(Level.INFO, "onSingleTapConfirmed pointerId: {0}, action: {1}, x: {2}, y: {3}", 
-//                new Object[]{getPointerId(event), getAction(event), event.getX(), event.getY()});
-        float jmeX = androidInput.getJmeX(event.getX());
-        float jmeY = androidInput.invertY(androidInput.getJmeY(event.getY()));
-        TouchEvent touchEvent = androidInput.getFreeTouchEvent();
+//        logger.log(Level.INFO, "onSingleTapConfirmed pointerId: {0}, action: {1}, x: {2}, y: {3}",
+//                new Object[]{touchInput.getPointerId(event), touchInput.getAction(event), event.getX(), event.getY()});
+        float jmeX = touchInput.getJmeX(event.getX());
+        float jmeY = touchInput.invertY(touchInput.getJmeY(event.getY()));
+        TouchEvent touchEvent = touchInput.getFreeTouchEvent();
         touchEvent.set(TouchEvent.Type.TAP, jmeX, jmeY, 0, 0);
         touchEvent.set(TouchEvent.Type.TAP, jmeX, jmeY, 0, 0);
-        touchEvent.setPointerId(getPointerId(event));
+        touchEvent.setPointerId(touchInput.getPointerId(event));
         touchEvent.setTime(event.getEventTime());
         touchEvent.setTime(event.getEventTime());
         touchEvent.setPressure(event.getPressure());
         touchEvent.setPressure(event.getPressure());
-        processEvent(touchEvent);
+        touchInput.addEvent(touchEvent);
         return true;
         return true;
     }
     }
 
 
+    @Override
     public boolean onDoubleTap(MotionEvent event) {
     public boolean onDoubleTap(MotionEvent event) {
         //The down motion event of the first tap of the double-tap
         //The down motion event of the first tap of the double-tap
-        // We could use this event to fire off a double tap event, or use 
+        // We could use this event to fire off a double tap event, or use
         // DoubleTapEvent with a check for the UP action
         // DoubleTapEvent with a check for the UP action
-//        logger.log(Level.INFO, "onDoubleTap pointerId: {0}, action: {1}, x: {2}, y: {3}", 
-//                new Object[]{getPointerId(event), getAction(event), event.getX(), event.getY()});
-        float jmeX = androidInput.getJmeX(event.getX());
-        float jmeY = androidInput.invertY(androidInput.getJmeY(event.getY()));
-        TouchEvent touchEvent = androidInput.getFreeTouchEvent();
+//        logger.log(Level.INFO, "onDoubleTap pointerId: {0}, action: {1}, x: {2}, y: {3}",
+//                new Object[]{touchInput.getPointerId(event), touchInput.getAction(event), event.getX(), event.getY()});
+        float jmeX = touchInput.getJmeX(event.getX());
+        float jmeY = touchInput.invertY(touchInput.getJmeY(event.getY()));
+        TouchEvent touchEvent = touchInput.getFreeTouchEvent();
         touchEvent.set(TouchEvent.Type.DOUBLETAP, jmeX, jmeY, 0, 0);
         touchEvent.set(TouchEvent.Type.DOUBLETAP, jmeX, jmeY, 0, 0);
-        touchEvent.setPointerId(getPointerId(event));
+        touchEvent.setPointerId(touchInput.getPointerId(event));
         touchEvent.setTime(event.getEventTime());
         touchEvent.setTime(event.getEventTime());
         touchEvent.setPressure(event.getPressure());
         touchEvent.setPressure(event.getPressure());
-        processEvent(touchEvent);
+        touchInput.addEvent(touchEvent);
         return true;
         return true;
     }
     }
 
 
+    @Override
     public boolean onDoubleTapEvent(MotionEvent event) {
     public boolean onDoubleTapEvent(MotionEvent event) {
         //Notified when an event within a double-tap gesture occurs, including the down, move(s), and up events.
         //Notified when an event within a double-tap gesture occurs, including the down, move(s), and up events.
         // this means it will get called multiple times for a single double tap
         // this means it will get called multiple times for a single double tap
-//        logger.log(Level.INFO, "onDoubleTapEvent pointerId: {0}, action: {1}, x: {2}, y: {3}", 
-//                new Object[]{getPointerId(event), getAction(event), event.getX(), event.getY()});
-//        if (getAction(event) == MotionEvent.ACTION_UP) {
-//            TouchEvent touchEvent = touchEventPool.getNextFreeEvent();
-//            touchEvent.set(TouchEvent.Type.DOUBLETAP, event.getX(), androidInput.invertY(event.getY()), 0, 0);
-//            touchEvent.setPointerId(getPointerId(event));
-//            touchEvent.setTime(event.getEventTime());
-//            touchEvent.setPressure(event.getPressure());
-//            processEvent(touchEvent);
-//        }
+//        logger.log(Level.INFO, "onDoubleTapEvent pointerId: {0}, action: {1}, x: {2}, y: {3}",
+//                new Object[]{touchInput.getPointerId(event), touchInput.getAction(event), event.getX(), event.getY()});
+        if (touchInput.getAction(event) == MotionEvent.ACTION_UP) {
+            TouchEvent touchEvent = touchInput.getFreeTouchEvent();
+            touchEvent.set(TouchEvent.Type.DOUBLETAP, event.getX(), touchInput.invertY(event.getY()), 0, 0);
+            touchEvent.setPointerId(touchInput.getPointerId(event));
+            touchEvent.setTime(event.getEventTime());
+            touchEvent.setPressure(event.getPressure());
+            touchInput.addEvent(touchEvent);
+        }
         return true;
         return true;
     }
     }
 
 
     /* Events from ScaleGestureDetector */
     /* Events from ScaleGestureDetector */
-    
+
+    @Override
     public boolean onScaleBegin(ScaleGestureDetector scaleGestureDetector) {
     public boolean onScaleBegin(ScaleGestureDetector scaleGestureDetector) {
         // Scale uses a focusX and focusY instead of x and y.  Focus is the middle
         // Scale uses a focusX and focusY instead of x and y.  Focus is the middle
         // of the fingers.  Therefore, use the x and y values from the Down event
         // of the fingers.  Therefore, use the x and y values from the Down event
         // so that the x and y values don't jump to the middle position.
         // so that the x and y values don't jump to the middle position.
         // return true or all gestures for this beginning event will be discarded
         // return true or all gestures for this beginning event will be discarded
-        logger.log(Level.INFO, "onScaleBegin");
+//        logger.log(Level.INFO, "onScaleBegin");
         scaleStartX = gestureDownX;
         scaleStartX = gestureDownX;
         scaleStartY = gestureDownY;
         scaleStartY = gestureDownY;
-        TouchEvent touchEvent = androidInput.getFreeTouchEvent();
+        TouchEvent touchEvent = touchInput.getFreeTouchEvent();
         touchEvent.set(TouchEvent.Type.SCALE_START, scaleStartX, scaleStartY, 0f, 0f);
         touchEvent.set(TouchEvent.Type.SCALE_START, scaleStartX, scaleStartY, 0f, 0f);
         touchEvent.setPointerId(0);
         touchEvent.setPointerId(0);
         touchEvent.setTime(scaleGestureDetector.getEventTime());
         touchEvent.setTime(scaleGestureDetector.getEventTime());
         touchEvent.setScaleSpan(scaleGestureDetector.getCurrentSpan());
         touchEvent.setScaleSpan(scaleGestureDetector.getCurrentSpan());
         touchEvent.setDeltaScaleSpan(0f);
         touchEvent.setDeltaScaleSpan(0f);
         touchEvent.setScaleFactor(scaleGestureDetector.getScaleFactor());
         touchEvent.setScaleFactor(scaleGestureDetector.getScaleFactor());
-        touchEvent.setScaleSpanInProgress(scaleDetector.isInProgress());
-        processEvent(touchEvent);
-        
+        touchEvent.setScaleSpanInProgress(touchInput.getScaleDetector().isInProgress());
+        touchInput.addEvent(touchEvent);
+
         return true;
         return true;
     }
     }
 
 
+    @Override
     public boolean onScale(ScaleGestureDetector scaleGestureDetector) {
     public boolean onScale(ScaleGestureDetector scaleGestureDetector) {
         // return true or all gestures for this event will be accumulated
         // return true or all gestures for this event will be accumulated
-        logger.log(Level.INFO, "onScale");
+//        logger.log(Level.INFO, "onScale");
         scaleStartX = gestureDownX;
         scaleStartX = gestureDownX;
         scaleStartY = gestureDownY;
         scaleStartY = gestureDownY;
-        TouchEvent touchEvent = androidInput.getFreeTouchEvent();
+        TouchEvent touchEvent = touchInput.getFreeTouchEvent();
         touchEvent.set(TouchEvent.Type.SCALE_MOVE, scaleStartX, scaleStartY, 0f, 0f);
         touchEvent.set(TouchEvent.Type.SCALE_MOVE, scaleStartX, scaleStartY, 0f, 0f);
         touchEvent.setPointerId(0);
         touchEvent.setPointerId(0);
         touchEvent.setTime(scaleGestureDetector.getEventTime());
         touchEvent.setTime(scaleGestureDetector.getEventTime());
         touchEvent.setScaleSpan(scaleGestureDetector.getCurrentSpan());
         touchEvent.setScaleSpan(scaleGestureDetector.getCurrentSpan());
         touchEvent.setDeltaScaleSpan(scaleGestureDetector.getCurrentSpan() - scaleGestureDetector.getPreviousSpan());
         touchEvent.setDeltaScaleSpan(scaleGestureDetector.getCurrentSpan() - scaleGestureDetector.getPreviousSpan());
         touchEvent.setScaleFactor(scaleGestureDetector.getScaleFactor());
         touchEvent.setScaleFactor(scaleGestureDetector.getScaleFactor());
-        touchEvent.setScaleSpanInProgress(scaleDetector.isInProgress());
-        processEvent(touchEvent);
+        touchEvent.setScaleSpanInProgress(touchInput.getScaleDetector().isInProgress());
+        touchInput.addEvent(touchEvent);
         return true;
         return true;
     }
     }
 
 
+    @Override
     public void onScaleEnd(ScaleGestureDetector scaleGestureDetector) {
     public void onScaleEnd(ScaleGestureDetector scaleGestureDetector) {
-        logger.log(Level.INFO, "onScaleEnd");
+//        logger.log(Level.INFO, "onScaleEnd");
         scaleStartX = gestureDownX;
         scaleStartX = gestureDownX;
         scaleStartY = gestureDownY;
         scaleStartY = gestureDownY;
-        TouchEvent touchEvent = androidInput.getFreeTouchEvent();
+        TouchEvent touchEvent = touchInput.getFreeTouchEvent();
         touchEvent.set(TouchEvent.Type.SCALE_END, scaleStartX, scaleStartY, 0f, 0f);
         touchEvent.set(TouchEvent.Type.SCALE_END, scaleStartX, scaleStartY, 0f, 0f);
         touchEvent.setPointerId(0);
         touchEvent.setPointerId(0);
         touchEvent.setTime(scaleGestureDetector.getEventTime());
         touchEvent.setTime(scaleGestureDetector.getEventTime());
         touchEvent.setScaleSpan(scaleGestureDetector.getCurrentSpan());
         touchEvent.setScaleSpan(scaleGestureDetector.getCurrentSpan());
         touchEvent.setDeltaScaleSpan(scaleGestureDetector.getCurrentSpan() - scaleGestureDetector.getPreviousSpan());
         touchEvent.setDeltaScaleSpan(scaleGestureDetector.getCurrentSpan() - scaleGestureDetector.getPreviousSpan());
         touchEvent.setScaleFactor(scaleGestureDetector.getScaleFactor());
         touchEvent.setScaleFactor(scaleGestureDetector.getScaleFactor());
-        touchEvent.setScaleSpanInProgress(scaleDetector.isInProgress());
-        processEvent(touchEvent);
+        touchEvent.setScaleSpanInProgress(touchInput.getScaleDetector().isInProgress());
+        touchInput.addEvent(touchEvent);
     }
     }
 }
 }

+ 0 - 686
jme3-android/src/main/java/com/jme3/input/android/AndroidInput.java

@@ -1,686 +0,0 @@
-package com.jme3.input.android;
-
-import android.view.*;
-import com.jme3.input.KeyInput;
-import com.jme3.input.RawInputListener;
-import com.jme3.input.TouchInput;
-import com.jme3.input.event.MouseButtonEvent;
-import com.jme3.input.event.MouseMotionEvent;
-import com.jme3.input.event.TouchEvent;
-import com.jme3.input.event.TouchEvent.Type;
-import com.jme3.math.Vector2f;
-import com.jme3.system.AppSettings;
-import com.jme3.util.RingBuffer;
-import java.util.HashMap;
-import java.util.logging.Logger;
-
-/**
- * <code>AndroidInput</code> is one of the main components that connect jme with android. Is derived from GLSurfaceView and handles all Inputs
- * @author larynx
- *
- */
-public class AndroidInput implements
-        TouchInput,
-        View.OnTouchListener,
-        View.OnKeyListener,
-        GestureDetector.OnGestureListener,
-        GestureDetector.OnDoubleTapListener,
-        ScaleGestureDetector.OnScaleGestureListener {
-
-    final private static int MAX_EVENTS = 1024;
-    // Custom settings
-    public boolean mouseEventsEnabled = true;
-    public boolean mouseEventsInvertX = false;
-    public boolean mouseEventsInvertY = false;
-    public boolean keyboardEventsEnabled = false;
-    public boolean dontSendHistory = false;
-    // Used to transfer events from android thread to GLThread
-    final private RingBuffer<TouchEvent> eventQueue = new RingBuffer<TouchEvent>(MAX_EVENTS);
-    final private RingBuffer<TouchEvent> eventPoolUnConsumed = new RingBuffer<TouchEvent>(MAX_EVENTS);
-    final private RingBuffer<TouchEvent> eventPool = new RingBuffer<TouchEvent>(MAX_EVENTS);
-    final private HashMap<Integer, Vector2f> lastPositions = new HashMap<Integer, Vector2f>();
-    // Internal
-    private View view;
-    private ScaleGestureDetector scaledetector;
-    private boolean scaleInProgress = false;
-    private GestureDetector detector;
-    private int lastX;
-    private int lastY;
-    private final static Logger logger = Logger.getLogger(AndroidInput.class.getName());
-    private boolean isInitialized = false;
-    private RawInputListener listener = null;
-    private static final int[] ANDROID_TO_JME = {
-        0x0, // unknown
-        0x0, // key code soft left
-        0x0, // key code soft right
-        KeyInput.KEY_HOME,
-        KeyInput.KEY_ESCAPE, // key back
-        0x0, // key call
-        0x0, // key endcall
-        KeyInput.KEY_0,
-        KeyInput.KEY_1,
-        KeyInput.KEY_2,
-        KeyInput.KEY_3,
-        KeyInput.KEY_4,
-        KeyInput.KEY_5,
-        KeyInput.KEY_6,
-        KeyInput.KEY_7,
-        KeyInput.KEY_8,
-        KeyInput.KEY_9,
-        KeyInput.KEY_MULTIPLY,
-        0x0, // key pound
-        KeyInput.KEY_UP,
-        KeyInput.KEY_DOWN,
-        KeyInput.KEY_LEFT,
-        KeyInput.KEY_RIGHT,
-        KeyInput.KEY_RETURN, // dpad center
-        0x0, // volume up
-        0x0, // volume down
-        KeyInput.KEY_POWER, // power (?)
-        0x0, // camera
-        0x0, // clear
-        KeyInput.KEY_A,
-        KeyInput.KEY_B,
-        KeyInput.KEY_C,
-        KeyInput.KEY_D,
-        KeyInput.KEY_E,
-        KeyInput.KEY_F,
-        KeyInput.KEY_G,
-        KeyInput.KEY_H,
-        KeyInput.KEY_I,
-        KeyInput.KEY_J,
-        KeyInput.KEY_K,
-        KeyInput.KEY_L,
-        KeyInput.KEY_M,
-        KeyInput.KEY_N,
-        KeyInput.KEY_O,
-        KeyInput.KEY_P,
-        KeyInput.KEY_Q,
-        KeyInput.KEY_R,
-        KeyInput.KEY_S,
-        KeyInput.KEY_T,
-        KeyInput.KEY_U,
-        KeyInput.KEY_V,
-        KeyInput.KEY_W,
-        KeyInput.KEY_X,
-        KeyInput.KEY_Y,
-        KeyInput.KEY_Z,
-        KeyInput.KEY_COMMA,
-        KeyInput.KEY_PERIOD,
-        KeyInput.KEY_LMENU,
-        KeyInput.KEY_RMENU,
-        KeyInput.KEY_LSHIFT,
-        KeyInput.KEY_RSHIFT,
-        //        0x0, // fn
-        //        0x0, // cap (?)
-
-        KeyInput.KEY_TAB,
-        KeyInput.KEY_SPACE,
-        0x0, // sym (?) symbol
-        0x0, // explorer
-        0x0, // envelope
-        KeyInput.KEY_RETURN, // newline/enter
-        KeyInput.KEY_DELETE,
-        KeyInput.KEY_GRAVE,
-        KeyInput.KEY_MINUS,
-        KeyInput.KEY_EQUALS,
-        KeyInput.KEY_LBRACKET,
-        KeyInput.KEY_RBRACKET,
-        KeyInput.KEY_BACKSLASH,
-        KeyInput.KEY_SEMICOLON,
-        KeyInput.KEY_APOSTROPHE,
-        KeyInput.KEY_SLASH,
-        KeyInput.KEY_AT, // at (@)
-        KeyInput.KEY_NUMLOCK, //0x0, // num
-        0x0, //headset hook
-        0x0, //focus
-        KeyInput.KEY_ADD,
-        KeyInput.KEY_LMETA, //menu
-        0x0,//notification
-        0x0,//search
-        0x0,//media play/pause
-        0x0,//media stop
-        0x0,//media next
-        0x0,//media previous
-        0x0,//media rewind
-        0x0,//media fastforward
-        0x0,//mute
-    };
-
-    public AndroidInput() {
-    }
-
-    public void setView(View view) {
-        this.view = view;
-        if (view != null) {
-            detector = new GestureDetector(null, this, null, false);
-            scaledetector = new ScaleGestureDetector(view.getContext(), this);
-            view.setOnTouchListener(this);
-            view.setOnKeyListener(this);
-        }
-    }
-
-    private TouchEvent getNextFreeTouchEvent() {
-        return getNextFreeTouchEvent(false);
-    }
-
-    /**
-     * Fetches a touch event from the reuse pool
-     * @param wait if true waits for a reusable event to get available/released
-     * by an other thread, if false returns a new one if needed.
-     *
-     * @return a usable TouchEvent
-     */
-    private TouchEvent getNextFreeTouchEvent(boolean wait) {
-        TouchEvent evt = null;
-        synchronized (eventPoolUnConsumed) {
-            int size = eventPoolUnConsumed.size();
-            while (size > 0) {
-                evt = eventPoolUnConsumed.pop();
-                if (!evt.isConsumed()) {
-                    eventPoolUnConsumed.push(evt);
-                    evt = null;
-                } else {
-                    break;
-                }
-                size--;
-            }
-        }
-
-        if (evt == null) {
-            if (eventPool.isEmpty() && wait) {
-                logger.warning("eventPool buffer underrun");
-                boolean isEmpty;
-                do {
-                    synchronized (eventPool) {
-                        isEmpty = eventPool.isEmpty();
-                    }
-                    try {
-                        Thread.sleep(50);
-                    } catch (InterruptedException e) {
-                    }
-                } while (isEmpty);
-                synchronized (eventPool) {
-                    evt = eventPool.pop();
-                }
-            } else if (eventPool.isEmpty()) {
-                evt = new TouchEvent();
-                logger.warning("eventPool buffer underrun");
-            } else {
-                synchronized (eventPool) {
-                    evt = eventPool.pop();
-                }
-            }
-        }
-        return evt;
-    }
-
-    /**
-     * onTouch gets called from android thread on touchpad events
-     */
-    public boolean onTouch(View view, MotionEvent event) {
-        if (view != this.view) {
-            return false;
-        }
-        boolean bWasHandled = false;
-        TouchEvent touch;
-        //    System.out.println("native : " + event.getAction());
-        int action = event.getAction() & MotionEvent.ACTION_MASK;
-        int pointerIndex = (event.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK)
-                >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
-        int pointerId = event.getPointerId(pointerIndex);
-        Vector2f lastPos = lastPositions.get(pointerId);
-
-        // final int historySize = event.getHistorySize();
-        //final int pointerCount = event.getPointerCount();
-        switch (action) {
-            case MotionEvent.ACTION_POINTER_DOWN:
-            case MotionEvent.ACTION_DOWN:
-                touch = getNextFreeTouchEvent();
-                touch.set(Type.DOWN, event.getX(pointerIndex), view.getHeight() - event.getY(pointerIndex), 0, 0);
-                touch.setPointerId(pointerId);
-                touch.setTime(event.getEventTime());
-                touch.setPressure(event.getPressure(pointerIndex));
-                processEvent(touch);
-
-                lastPos = new Vector2f(event.getX(pointerIndex), view.getHeight() - event.getY(pointerIndex));
-                lastPositions.put(pointerId, lastPos);
-
-                bWasHandled = true;
-                break;
-            case MotionEvent.ACTION_POINTER_UP:
-            case MotionEvent.ACTION_CANCEL:
-            case MotionEvent.ACTION_UP:
-                touch = getNextFreeTouchEvent();
-                touch.set(Type.UP, event.getX(pointerIndex), view.getHeight() - event.getY(pointerIndex), 0, 0);
-                touch.setPointerId(pointerId);
-                touch.setTime(event.getEventTime());
-                touch.setPressure(event.getPressure(pointerIndex));
-                processEvent(touch);
-                lastPositions.remove(pointerId);
-
-                bWasHandled = true;
-                break;
-            case MotionEvent.ACTION_MOVE:
-                // Convert all pointers into events
-                for (int p = 0; p < event.getPointerCount(); p++) {
-                    lastPos = lastPositions.get(event.getPointerId(p));
-                    if (lastPos == null) {
-                        lastPos = new Vector2f(event.getX(p), view.getHeight() - event.getY(p));
-                        lastPositions.put(event.getPointerId(p), lastPos);
-                    }
-
-                    float dX = event.getX(p) - lastPos.x;
-                    float dY = view.getHeight() - event.getY(p) - lastPos.y;
-                    if (dX != 0 || dY != 0) {
-                        touch = getNextFreeTouchEvent();
-                        touch.set(Type.MOVE, event.getX(p), view.getHeight() - event.getY(p), dX, dY);
-                        touch.setPointerId(event.getPointerId(p));
-                        touch.setTime(event.getEventTime());
-                        touch.setPressure(event.getPressure(p));
-                        touch.setScaleSpanInProgress(scaleInProgress);
-                        processEvent(touch);
-                        lastPos.set(event.getX(p), view.getHeight() - event.getY(p));
-                    }
-                }
-                bWasHandled = true;
-                break;
-            case MotionEvent.ACTION_OUTSIDE:
-                break;
-
-        }
-
-        // Try to detect gestures
-        this.detector.onTouchEvent(event);
-        this.scaledetector.onTouchEvent(event);
-
-        return bWasHandled;
-    }
-
-    /**
-     * onKey gets called from android thread on key events
-     */
-    public boolean onKey(View view, int keyCode, KeyEvent event) {
-        if (view != this.view) {
-            return false;
-        }
-
-        if (event.getAction() == KeyEvent.ACTION_DOWN) {
-        TouchEvent evt;
-        evt = getNextFreeTouchEvent();
-        evt.set(TouchEvent.Type.KEY_DOWN);
-        evt.setKeyCode(keyCode);
-        evt.setCharacters(event.getCharacters());
-        evt.setTime(event.getEventTime());
-
-        // Send the event
-        processEvent(evt);
-
-        // Handle all keys ourself except Volume Up/Down
-        if ((keyCode == KeyEvent.KEYCODE_VOLUME_UP) || (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN)) {
-            return false;
-        } else {
-            return true;
-        }
-        } else if (event.getAction() == KeyEvent.ACTION_UP) {
-        TouchEvent evt;
-        evt = getNextFreeTouchEvent();
-        evt.set(TouchEvent.Type.KEY_UP);
-        evt.setKeyCode(keyCode);
-        evt.setCharacters(event.getCharacters());
-        evt.setTime(event.getEventTime());
-
-        // Send the event
-        processEvent(evt);
-
-        // Handle all keys ourself except Volume Up/Down
-        if ((keyCode == KeyEvent.KEYCODE_VOLUME_UP) || (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN)) {
-            return false;
-        } else {
-            return true;
-        }
-        } else {
-            return false;
-        }
-    }
-
-    public void loadSettings(AppSettings settings) {
-        mouseEventsEnabled = settings.isEmulateMouse();
-        mouseEventsInvertX = settings.isEmulateMouseFlipX();
-        mouseEventsInvertY = settings.isEmulateMouseFlipY();
-    }
-
-    // -----------------------------------------
-    // JME3 Input interface
-    @Override
-    public void initialize() {
-        TouchEvent item;
-        for (int i = 0; i < MAX_EVENTS; i++) {
-            item = new TouchEvent();
-            eventPool.push(item);
-        }
-        isInitialized = true;
-    }
-
-    @Override
-    public void destroy() {
-        isInitialized = false;
-
-        // Clean up queues
-        while (!eventPool.isEmpty()) {
-            eventPool.pop();
-        }
-        while (!eventQueue.isEmpty()) {
-            eventQueue.pop();
-        }
-
-
-        this.view = null;
-    }
-
-    @Override
-    public boolean isInitialized() {
-        return isInitialized;
-    }
-
-    @Override
-    public void setInputListener(RawInputListener listener) {
-        this.listener = listener;
-    }
-
-    @Override
-    public long getInputTimeNanos() {
-        return System.nanoTime();
-    }
-    // -----------------------------------------
-
-    private void processEvent(TouchEvent event) {
-        synchronized (eventQueue) {
-            //Discarding events when the ring buffer is full to avoid buffer overflow.
-            if(eventQueue.size()< MAX_EVENTS){
-                eventQueue.push(event);
-            }
-
-        }
-    }
-
-    //  ---------------  INSIDE GLThread  ---------------
-    @Override
-    public void update() {
-        generateEvents();
-    }
-
-    private void generateEvents() {
-        if (listener != null) {
-            TouchEvent event;
-            MouseButtonEvent btn;
-            MouseMotionEvent mot;
-            int newX;
-            int newY;
-
-            while (!eventQueue.isEmpty()) {
-                synchronized (eventQueue) {
-                    event = eventQueue.pop();
-                }
-                if (event != null) {
-                    listener.onTouchEvent(event);
-
-                    if (mouseEventsEnabled) {
-                        if (mouseEventsInvertX) {
-                            newX = view.getWidth() - (int) event.getX();
-                        } else {
-                            newX = (int) event.getX();
-                        }
-
-                        if (mouseEventsInvertY) {
-                            newY = view.getHeight() - (int) event.getY();
-                        } else {
-                            newY = (int) event.getY();
-                        }
-
-                        switch (event.getType()) {
-                            case DOWN:
-                                // Handle mouse down event
-                                btn = new MouseButtonEvent(0, true, newX, newY);
-                                btn.setTime(event.getTime());
-                                listener.onMouseButtonEvent(btn);
-                                // Store current pos
-                                lastX = -1;
-                                lastY = -1;
-                                break;
-
-                            case UP:
-                                // Handle mouse up event
-                                btn = new MouseButtonEvent(0, false, newX, newY);
-                                btn.setTime(event.getTime());
-                                listener.onMouseButtonEvent(btn);
-                                // Store current pos
-                                lastX = -1;
-                                lastY = -1;
-                                break;
-
-                            case SCALE_MOVE:
-                                if (lastX != -1 && lastY != -1) {
-                                    newX = lastX;
-                                    newY = lastY;
-                                }
-                                int wheel = (int) (event.getScaleSpan() / 4f); // scale to match mouse wheel
-                                int dwheel = (int) (event.getDeltaScaleSpan() / 4f); // scale to match mouse wheel
-                                mot = new MouseMotionEvent(newX, newX, 0, 0, wheel, dwheel);
-                                mot.setTime(event.getTime());
-                                listener.onMouseMotionEvent(mot);
-                                lastX = newX;
-                                lastY = newY;
-
-                                break;
-
-                            case MOVE:
-                                if (event.isScaleSpanInProgress()) {
-                                    break;
-                                }
-
-                                int dx;
-                                int dy;
-                                if (lastX != -1) {
-                                    dx = newX - lastX;
-                                    dy = newY - lastY;
-                                } else {
-                                    dx = 0;
-                                    dy = 0;
-                                }
-
-                                mot = new MouseMotionEvent(newX, newY, dx, dy, (int)event.getScaleSpan(), (int)event.getDeltaScaleSpan());
-                                mot.setTime(event.getTime());
-                                listener.onMouseMotionEvent(mot);
-                                lastX = newX;
-                                lastY = newY;
-
-                                break;
-                        }
-                    }
-                }
-
-                if (event.isConsumed() == false) {
-                    synchronized (eventPoolUnConsumed) {
-                        eventPoolUnConsumed.push(event);
-                    }
-
-                } else {
-                    synchronized (eventPool) {
-                        eventPool.push(event);
-                    }
-                }
-            }
-
-        }
-    }
-    //  --------------- ENDOF INSIDE GLThread  ---------------
-
-    // --------------- Gesture detected callback events  ---------------
-    public boolean onDown(MotionEvent event) {
-        return false;
-    }
-
-    public void onLongPress(MotionEvent event) {
-        TouchEvent touch = getNextFreeTouchEvent();
-        touch.set(Type.LONGPRESSED, event.getX(), view.getHeight() - event.getY(), 0f, 0f);
-        touch.setPointerId(0);
-        touch.setTime(event.getEventTime());
-        processEvent(touch);
-    }
-
-    public boolean onFling(MotionEvent event, MotionEvent event2, float vx, float vy) {
-        TouchEvent touch = getNextFreeTouchEvent();
-        touch.set(Type.FLING, event.getX(), view.getHeight() - event.getY(), vx, vy);
-        touch.setPointerId(0);
-        touch.setTime(event.getEventTime());
-        processEvent(touch);
-
-        return true;
-    }
-
-    public boolean onSingleTapConfirmed(MotionEvent event) {
-        //Nothing to do here the tap has already been detected.
-        return false;
-    }
-
-    public boolean onDoubleTap(MotionEvent event) {
-        TouchEvent touch = getNextFreeTouchEvent();
-        touch.set(Type.DOUBLETAP, event.getX(), view.getHeight() - event.getY(), 0f, 0f);
-        touch.setPointerId(0);
-        touch.setTime(event.getEventTime());
-        processEvent(touch);
-        return true;
-    }
-
-    public boolean onDoubleTapEvent(MotionEvent event) {
-        return false;
-    }
-
-    public boolean onScaleBegin(ScaleGestureDetector scaleGestureDetector) {
-        scaleInProgress = true;
-        TouchEvent touch = getNextFreeTouchEvent();
-        touch.set(Type.SCALE_START, scaleGestureDetector.getFocusX(), scaleGestureDetector.getFocusY(), 0f, 0f);
-        touch.setPointerId(0);
-        touch.setTime(scaleGestureDetector.getEventTime());
-        touch.setScaleSpan(scaleGestureDetector.getCurrentSpan());
-        touch.setDeltaScaleSpan(scaleGestureDetector.getCurrentSpan() - scaleGestureDetector.getPreviousSpan());
-        touch.setScaleFactor(scaleGestureDetector.getScaleFactor());
-        touch.setScaleSpanInProgress(scaleInProgress);
-        processEvent(touch);
-        //    System.out.println("scaleBegin");
-
-        return true;
-    }
-
-    public boolean onScale(ScaleGestureDetector scaleGestureDetector) {
-        TouchEvent touch = getNextFreeTouchEvent();
-        touch.set(Type.SCALE_MOVE, scaleGestureDetector.getFocusX(), view.getHeight() - scaleGestureDetector.getFocusY(), 0f, 0f);
-        touch.setPointerId(0);
-        touch.setTime(scaleGestureDetector.getEventTime());
-        touch.setScaleSpan(scaleGestureDetector.getCurrentSpan());
-        touch.setDeltaScaleSpan(scaleGestureDetector.getCurrentSpan() - scaleGestureDetector.getPreviousSpan());
-        touch.setScaleFactor(scaleGestureDetector.getScaleFactor());
-        touch.setScaleSpanInProgress(scaleInProgress);
-        processEvent(touch);
-        //   System.out.println("scale");
-
-        return false;
-    }
-
-    public void onScaleEnd(ScaleGestureDetector scaleGestureDetector) {
-        scaleInProgress = false;
-        TouchEvent touch = getNextFreeTouchEvent();
-        touch.set(Type.SCALE_END, scaleGestureDetector.getFocusX(), view.getHeight() - scaleGestureDetector.getFocusY(), 0f, 0f);
-        touch.setPointerId(0);
-        touch.setTime(scaleGestureDetector.getEventTime());
-        touch.setScaleSpan(scaleGestureDetector.getCurrentSpan());
-        touch.setDeltaScaleSpan(scaleGestureDetector.getCurrentSpan() - scaleGestureDetector.getPreviousSpan());
-        touch.setScaleFactor(scaleGestureDetector.getScaleFactor());
-        touch.setScaleSpanInProgress(scaleInProgress);
-        processEvent(touch);
-    }
-
-    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
-        TouchEvent touch = getNextFreeTouchEvent();
-        touch.set(Type.SCROLL, e1.getX(), view.getHeight() - e1.getY(), distanceX, distanceY * (-1));
-        touch.setPointerId(0);
-        touch.setTime(e1.getEventTime());
-        processEvent(touch);
-        //System.out.println("scroll " + e1.getPointerCount());
-        return false;
-    }
-
-    public void onShowPress(MotionEvent event) {
-        TouchEvent touch = getNextFreeTouchEvent();
-        touch.set(Type.SHOWPRESS, event.getX(), view.getHeight() - event.getY(), 0f, 0f);
-        touch.setPointerId(0);
-        touch.setTime(event.getEventTime());
-        processEvent(touch);
-    }
-
-    public boolean onSingleTapUp(MotionEvent event) {
-        TouchEvent touch = getNextFreeTouchEvent();
-        touch.set(Type.TAP, event.getX(), view.getHeight() - event.getY(), 0f, 0f);
-        touch.setPointerId(0);
-        touch.setTime(event.getEventTime());
-        processEvent(touch);
-        return true;
-    }
-
-    @Override
-    public void setSimulateKeyboard(boolean simulate) {
-        keyboardEventsEnabled = simulate;
-    }
-
-    @Override
-    public void setOmitHistoricEvents(boolean dontSendHistory) {
-        this.dontSendHistory = dontSendHistory;
-    }
-
-    /**
-     * @deprecated Use {@link #getSimulateMouse()};
-     */
-    @Deprecated
-    public boolean isMouseEventsEnabled() {
-        return mouseEventsEnabled;
-    }
-
-    @Deprecated
-    public void setMouseEventsEnabled(boolean mouseEventsEnabled) {
-        this.mouseEventsEnabled = mouseEventsEnabled;
-    }
-
-    public boolean isMouseEventsInvertY() {
-        return mouseEventsInvertY;
-    }
-
-    public void setMouseEventsInvertY(boolean mouseEventsInvertY) {
-        this.mouseEventsInvertY = mouseEventsInvertY;
-    }
-
-    public boolean isMouseEventsInvertX() {
-        return mouseEventsInvertX;
-    }
-
-    public void setMouseEventsInvertX(boolean mouseEventsInvertX) {
-        this.mouseEventsInvertX = mouseEventsInvertX;
-    }
-
-    public void setSimulateMouse(boolean simulate) {
-        mouseEventsEnabled = simulate;
-    }
-
-    public boolean getSimulateMouse() {
-        return isSimulateMouse();
-    }
-
-    public boolean isSimulateMouse() {
-        return mouseEventsEnabled;
-    }
-
-    public boolean isSimulateKeyboard() {
-        return keyboardEventsEnabled;
-    }
-
-}

+ 147 - 172
jme3-android/src/main/java/com/jme3/input/android/AndroidInputHandler.java

@@ -33,231 +33,206 @@
 package com.jme3.input.android;
 package com.jme3.input.android;
 
 
 import android.opengl.GLSurfaceView;
 import android.opengl.GLSurfaceView;
-import android.os.Build;
+import android.view.GestureDetector;
+import android.view.InputDevice;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.ScaleGestureDetector;
 import android.view.View;
 import android.view.View;
-import com.jme3.input.RawInputListener;
+import com.jme3.input.JoyInput;
 import com.jme3.input.TouchInput;
 import com.jme3.input.TouchInput;
-import com.jme3.input.event.InputEvent;
-import com.jme3.input.event.KeyInputEvent;
-import com.jme3.input.event.MouseButtonEvent;
-import com.jme3.input.event.MouseMotionEvent;
-import com.jme3.input.event.TouchEvent;
 import com.jme3.system.AppSettings;
 import com.jme3.system.AppSettings;
-import java.util.concurrent.ConcurrentLinkedQueue;
 import java.util.logging.Level;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 import java.util.logging.Logger;
 
 
 /**
 /**
  * <code>AndroidInput</code> is the main class that connects the Android system
  * <code>AndroidInput</code> is the main class that connects the Android system
- * inputs to jME. It serves as the manager that gathers inputs from the various
- * Android input methods and provides them to jME's <code>InputManager</code>.
+ * inputs to jME. It receives the inputs from the Android View and passes them
+ * to the appropriate classes based on the source of the input.</br>
+ * This class is to be extended when new functionality is released in Android.
  *
  *
  * @author iwgeric
  * @author iwgeric
  */
  */
-public class AndroidInputHandler implements TouchInput {
-    private static final Logger logger = Logger.getLogger(AndroidInputHandler.class.getName());
-
-    // Custom settings
-    private boolean mouseEventsEnabled = true;
-    private boolean mouseEventsInvertX = false;
-    private boolean mouseEventsInvertY = false;
-    private boolean keyboardEventsEnabled = false;
-    private boolean dontSendHistory = false;
+public class AndroidInputHandler implements View.OnTouchListener,
+                                            View.OnKeyListener {
 
 
+    private static final Logger logger = Logger.getLogger(AndroidInputHandler.class.getName());
 
 
-    // Internal
-    private GLSurfaceView view;
-    private AndroidTouchHandler touchHandler;
-    private AndroidKeyHandler keyHandler;
-    private AndroidGestureHandler gestureHandler;
-    private boolean initialized = false;
-    private RawInputListener listener = null;
-    private ConcurrentLinkedQueue<InputEvent> inputEventQueue = new ConcurrentLinkedQueue<InputEvent>();
-    private final static int MAX_TOUCH_EVENTS = 1024;
-    private final TouchEventPool touchEventPool = new TouchEventPool(MAX_TOUCH_EVENTS);
-    private float scaleX = 1f;
-    private float scaleY = 1f;
+    protected GLSurfaceView view;
+    protected AndroidTouchInput touchInput;
+    protected AndroidJoyInput joyInput;
 
 
 
 
     public AndroidInputHandler() {
     public AndroidInputHandler() {
-        int buildVersion = Build.VERSION.SDK_INT;
-        logger.log(Level.INFO, "Android Build Version: {0}", buildVersion);
-        if (buildVersion >= 14) {
-            // add support for onHover and GenericMotionEvent (ie. gamepads)
-            gestureHandler = new AndroidGestureHandler(this);
-            touchHandler = new AndroidTouchHandler14(this, gestureHandler);
-            keyHandler = new AndroidKeyHandler(this);
-        } else if (buildVersion >= 8){
-            gestureHandler = new AndroidGestureHandler(this);
-            touchHandler = new AndroidTouchHandler(this, gestureHandler);
-            keyHandler = new AndroidKeyHandler(this);
-        }
-    }
-
-    public AndroidInputHandler(AndroidTouchHandler touchInput,
-            AndroidKeyHandler keyInput, AndroidGestureHandler gestureHandler) {
-        this.touchHandler = touchInput;
-        this.keyHandler = keyInput;
-        this.gestureHandler = gestureHandler;
+        touchInput = new AndroidTouchInput(this);
+        joyInput = new AndroidJoyInput(this);
     }
     }
 
 
     public void setView(View view) {
     public void setView(View view) {
-        if (touchHandler != null) {
-            touchHandler.setView(view);
+        if (this.view != null && view != null && this.view.equals(view)) {
+            return;
         }
         }
-        if (keyHandler != null) {
-            keyHandler.setView(view);
-        }
-        if (gestureHandler != null) {
-            gestureHandler.setView(view);
+
+        if (this.view != null) {
+            removeListeners(this.view);
         }
         }
+
         this.view = (GLSurfaceView)view;
         this.view = (GLSurfaceView)view;
-    }
 
 
-    public View getView() {
-        return view;
-    }
+        if (this.view != null) {
+            addListeners(this.view);
+        }
 
 
-    public float invertX(float origX) {
-        return getJmeX(view.getWidth()) - origX;
+        joyInput.setView((GLSurfaceView)view);
     }
     }
 
 
-    public float invertY(float origY) {
-        return getJmeY(view.getHeight()) - origY;
+    public View getView() {
+        return view;
     }
     }
 
 
-    public float getJmeX(float origX) {
-        return origX * scaleX;
+    protected void removeListeners(GLSurfaceView view) {
+        view.setOnTouchListener(null);
+        view.setOnKeyListener(null);
+        touchInput.setGestureDetector(null);
+        touchInput.setScaleDetector(null);
     }
     }
 
 
-    public float getJmeY(float origY) {
-        return origY * scaleY;
+    protected void addListeners(GLSurfaceView view) {
+        view.setOnTouchListener(this);
+        view.setOnKeyListener(this);
+        AndroidGestureProcessor gestureHandler = new AndroidGestureProcessor(touchInput);
+        touchInput.setGestureDetector(new GestureDetector(
+                view.getContext(), gestureHandler));
+        touchInput.setScaleDetector(new ScaleGestureDetector(
+                view.getContext(), gestureHandler));
     }
     }
 
 
     public void loadSettings(AppSettings settings) {
     public void loadSettings(AppSettings settings) {
-        keyboardEventsEnabled = settings.isEmulateKeyboard();
-        mouseEventsEnabled = settings.isEmulateMouse();
-        mouseEventsInvertX = settings.isEmulateMouseFlipX();
-        mouseEventsInvertY = settings.isEmulateMouseFlipY();
-
-        // view width and height are 0 until the view is displayed on the screen
-        if (view.getWidth() != 0 && view.getHeight() != 0) {
-            scaleX = (float)settings.getWidth() / (float)view.getWidth();
-            scaleY = (float)settings.getHeight() / (float)view.getHeight();
-        }
-        logger.log(Level.FINE, "Setting input scaling, scaleX: {0}, scaleY: {1}",
-                new Object[]{scaleX, scaleY});
+        touchInput.loadSettings(settings);
+    }
+
+    public TouchInput getTouchInput() {
+        return touchInput;
+    }
+
+    public JoyInput getJoyInput() {
+        return joyInput;
+    }
+
+    /*
+     *  Android input events include the source from which the input came from.
+     *  We must look at the source of the input event to determine which type
+     *  of jME input it belongs to.
+     *  If the input is from a gamepad or joystick source, the event is sent
+     *  to the JoyInput class to convert the event into jME joystick events.
+     *  </br>
+     *  If the input is from a touchscreen source, the event is sent to the
+     *  TouchProcessor to convert the event into touch events.
+     *  The TouchProcessor also converts the events into Mouse and Key events
+     *  if AppSettings is set to simulate Mouse or Keyboard events.
+     *
+     *  Android reports the source as a bitmask as shown below.</br>
+     *
+     *  InputDevice Sources
+     *     0000 0000 0000 0000 0000 0000 0000 0000 - 32 bit bitmask
+     *
+     *     0000 0000 0000 0000 0000 0000 1111 1111 - SOURCE_CLASS_MASK       (0x000000ff)
+     *     0000 0000 0000 0000 0000 0000 0000 0000 - SOURCE_CLASS_NONE       (0x00000000)
+     *     0000 0000 0000 0000 0000 0000 0000 0001 - SOURCE_CLASS_BUTTON     (0x00000001)
+     *     0000 0000 0000 0000 0000 0000 0000 0010 - SOURCE_CLASS_POINTER    (0x00000002)
+     *     0000 0000 0000 0000 0000 0000 0000 0100 - SOURCE_CLASS_TRACKBALL  (0x00000004)
+     *     0000 0000 0000 0000 0000 0000 0000 1000 - SOURCE_CLASS_POSITION   (0x00000008)
+     *     0000 0000 0000 0000 0000 0000 0001 0000 - SOURCE_CLASS_JOYSTICK   (0x00000010)
+     *
+     *     1111 1111 1111 1111 1111 1111 0000 0000 - Source_Any              (0xffffff00)
+     *     0000 0000 0000 0000 0000 0000 0000 0000 - SOURCE_UNKNOWN          (0x00000000)
+     *     0000 0000 0000 0000 0000 0001 0000 0001 - SOURCE_KEYBOARD         (0x00000101)
+     *     0000 0000 0000 0000 0000 0010 0000 0001 - SOURCE_DPAD             (0x00000201)
+     *     0000 0000 0000 0000 0000 0100 0000 0001 - SOURCE_GAMEPAD          (0x00000401)
+     *     0000 0000 0000 0000 0001 0000 0000 0010 - SOURCE_TOUCHSCREEN      (0x00001002)
+     *     0000 0000 0000 0000 0010 0000 0000 0010 - SOURCE_MOUSE            (0x00002002)
+     *     0000 0000 0000 0000 0100 0000 0000 0010 - SOURCE_STYLUS           (0x00004002)
+     *     0000 0000 0000 0001 0000 0000 0000 0100 - SOURCE_TRACKBALL        (0x00010004)
+     *     0000 0000 0001 0000 0000 0000 0000 1000 - SOURCE_TOUCHPAD         (0x00100008)
+     *     0000 0000 0010 0000 0000 0000 0000 0000 - SOURCE_TOUCH_NAVIGATION (0x00200000)
+     *     0000 0001 0000 0000 0000 0000 0001 0000 - SOURCE_JOYSTICK         (0x01000010)
+     *     0000 0010 0000 0000 0000 0000 0000 0001 - SOURCE_HDMI             (0x02000001)
+     *
+     * Example values reported by Android for Source
+     * 4,098 = 0x00001002 =
+     *     0000 0000 0000 0000 0001 0000 0000 0010 - SOURCE_CLASS_POINTER
+     *                                               SOURCE_TOUCHSCREEN
+     * 1,281 = 0x00000501 =
+     *     0000 0000 0000 0000 0000 0101 0000 0001 - SOURCE_CLASS_BUTTON
+     *                                               SOURCE_KEYBOARD
+     *                                               SOURCE_GAMEPAD
+     * 16,777,232 = 0x01000010 =
+     *     0000 0001 0000 0000 0000 0000 0001 0000 - SOURCE_CLASS_JOYSTICK
+     *                                               SOURCE_JOYSTICK
+     *
+     * 16,778,513 = 0x01000511 =
+     *     0000 0001 0000 0000 0000 0101 0001 0001 - SOURCE_CLASS_BUTTON
+     *                                               SOURCE_CLASS_JOYSTICK
+     *                                               SOURCE_GAMEPAD
+     *                                               SOURCE_KEYBOARD
+     *                                               SOURCE_JOYSTICK
+     *
+     * 257 = 0x00000101 =
+     *     0000 0000 0000 0000 0000 0001 0000 0001 - SOURCE_CLASS_BUTTON
+     *                                               SOURCE_KEYBOARD
+     *
+     *
+     *
+     */
 
 
-    }
 
 
-        // -----------------------------------------
-    // JME3 Input interface
     @Override
     @Override
-    public void initialize() {
-        touchEventPool.initialize();
-        if (touchHandler != null) {
-            touchHandler.initialize();
-        }
-        if (keyHandler != null) {
-            keyHandler.initialize();
-        }
-        if (gestureHandler != null) {
-            gestureHandler.initialize();
+    public boolean onTouch(View view, MotionEvent event) {
+        if (view != getView()) {
+            return false;
         }
         }
 
 
-        initialized = true;
-    }
+        boolean consumed = false;
 
 
-    @Override
-    public void destroy() {
-        initialized = false;
+        int source = event.getSource();
+//        logger.log(Level.INFO, "onTouch source: {0}", source);
 
 
-        touchEventPool.destroy();
-        if (touchHandler != null) {
-            touchHandler.destroy();
-        }
-        if (keyHandler != null) {
-            keyHandler.destroy();
-        }
-        if (gestureHandler != null) {
-            gestureHandler.destroy();
-        }
-
-        setView(null);
-    }
-
-    @Override
-    public boolean isInitialized() {
-        return initialized;
-    }
-
-    @Override
-    public void setInputListener(RawInputListener listener) {
-        this.listener = listener;
-    }
-
-    @Override
-    public long getInputTimeNanos() {
-        return System.nanoTime();
-    }
+        boolean isTouch = ((source & InputDevice.SOURCE_TOUCHSCREEN) == InputDevice.SOURCE_TOUCHSCREEN);
+//        logger.log(Level.INFO, "onTouch source: {0}, isTouch: {1}",
+//                new Object[]{source, isTouch});
 
 
-    public void update() {
-        if (listener != null) {
-            InputEvent inputEvent;
-
-            while ((inputEvent = inputEventQueue.poll()) != null) {
-                if (inputEvent instanceof TouchEvent) {
-                    listener.onTouchEvent((TouchEvent)inputEvent);
-                } else if (inputEvent instanceof MouseButtonEvent) {
-                    listener.onMouseButtonEvent((MouseButtonEvent)inputEvent);
-                } else if (inputEvent instanceof MouseMotionEvent) {
-                    listener.onMouseMotionEvent((MouseMotionEvent)inputEvent);
-                } else if (inputEvent instanceof KeyInputEvent) {
-                    listener.onKeyEvent((KeyInputEvent)inputEvent);
-                }
-            }
+        if (isTouch && touchInput != null) {
+            // send the event to the touch processor
+            consumed = touchInput.onTouch(event);
         }
         }
-    }
 
 
-    // -----------------------------------------
+        return consumed;
 
 
-    public TouchEvent getFreeTouchEvent() {
-            return touchEventPool.getNextFreeEvent();
     }
     }
 
 
-    public void addEvent(InputEvent event) {
-        inputEventQueue.add(event);
-        if (event instanceof TouchEvent) {
-            touchEventPool.storeEvent((TouchEvent)event);
+    @Override
+    public boolean onKey(View view, int keyCode, KeyEvent event) {
+        if (view != getView()) {
+            return false;
         }
         }
-    }
 
 
-    public void setSimulateMouse(boolean simulate) {
-        this.mouseEventsEnabled = simulate;
-    }
+        boolean consumed = false;
 
 
-    public boolean isSimulateMouse() {
-        return mouseEventsEnabled;
-    }
+        int source = event.getSource();
+//        logger.log(Level.INFO, "onKey source: {0}", source);
 
 
-    public boolean isMouseEventsInvertX() {
-        return mouseEventsInvertX;
-    }
+        boolean isTouch =
+                ((source & InputDevice.SOURCE_TOUCHSCREEN) == InputDevice.SOURCE_TOUCHSCREEN) ||
+                ((source & InputDevice.SOURCE_KEYBOARD) == InputDevice.SOURCE_KEYBOARD);
+//        logger.log(Level.INFO, "onKey source: {0}, isTouch: {1}",
+//                new Object[]{source, isTouch});
 
 
-    public boolean isMouseEventsInvertY() {
-        return mouseEventsInvertY;
-    }
-
-    public void setSimulateKeyboard(boolean simulate) {
-        this.keyboardEventsEnabled = simulate;
-    }
+        if (touchInput != null) {
+            consumed = touchInput.onKey(event);
+        }
 
 
-    public boolean isSimulateKeyboard() {
-        return keyboardEventsEnabled;
-    }
+        return consumed;
 
 
-    public void setOmitHistoricEvents(boolean dontSendHistory) {
-        this.dontSendHistory = dontSendHistory;
     }
     }
 
 
 }
 }

+ 158 - 0
jme3-android/src/main/java/com/jme3/input/android/AndroidInputHandler14.java

@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ *   may be used to endorse or promote products derived from this software
+ *   without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.jme3.input.android;
+
+import android.opengl.GLSurfaceView;
+import android.view.InputDevice;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.View;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * <code>AndroidInputHandler14</code> extends <code>AndroidInputHandler</code> to
+ * add the onHover and onGenericMotion events that where added in Android rev 14 (Android 4.0).</br>
+ * The onGenericMotion events are the main interface to Joystick axes.  They
+ * were actually released in Android rev 12.
+ *
+ * @author iwgeric
+ */
+public class AndroidInputHandler14 extends AndroidInputHandler implements View.OnHoverListener,
+                                                                            View.OnGenericMotionListener {
+
+    private static final Logger logger = Logger.getLogger(AndroidInputHandler14.class.getName());
+
+    public AndroidInputHandler14() {
+        touchInput = new AndroidTouchInput14(this);
+        joyInput = new AndroidJoyInput14(this);
+    }
+
+    @Override
+    protected void removeListeners(GLSurfaceView view) {
+        super.removeListeners(view);
+        view.setOnHoverListener(null);
+        view.setOnGenericMotionListener(null);
+    }
+
+    @Override
+    protected void addListeners(GLSurfaceView view) {
+        super.addListeners(view);
+        view.setOnHoverListener(this);
+        view.setOnGenericMotionListener(this);
+    }
+
+    @Override
+    public boolean onHover(View view, MotionEvent event) {
+        if (view != getView()) {
+            return false;
+        }
+
+        boolean consumed = false;
+
+        int source = event.getSource();
+//        logger.log(Level.INFO, "onTouch source: {0}", source);
+
+        boolean isTouch = ((source & InputDevice.SOURCE_TOUCHSCREEN) == InputDevice.SOURCE_TOUCHSCREEN);
+//        logger.log(Level.INFO, "onTouch source: {0}, isTouch: {1}",
+//                new Object[]{source, isTouch});
+
+        if (isTouch && touchInput != null) {
+            // send the event to the touch processor
+            consumed = ((AndroidTouchInput14)touchInput).onHover(event);
+        }
+
+        return consumed;
+    }
+
+    @Override
+    public boolean onGenericMotion(View view, MotionEvent event) {
+        if (view != getView()) {
+            return false;
+        }
+
+        boolean consumed = false;
+
+        int source = event.getSource();
+//        logger.log(Level.INFO, "onGenericMotion source: {0}", source);
+
+        boolean isJoystick =
+                ((source & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD) ||
+                ((source & InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK);
+
+        if (isJoystick && joyInput != null) {
+//            logger.log(Level.INFO, "onGenericMotion source: {0}, isJoystick: {1}",
+//                    new Object[]{source, isJoystick});
+            // send the event to the touch processor
+            consumed = consumed || ((AndroidJoyInput14)joyInput).onGenericMotion(event);
+        }
+
+        return consumed;
+    }
+
+    @Override
+    public boolean onKey(View view, int keyCode, KeyEvent event) {
+        if (view != getView()) {
+            return false;
+        }
+
+        boolean consumed = false;
+
+//        logger.log(Level.INFO, "onKey keyCode: {0}, action: {1}, event: {2}",
+//                new Object[]{KeyEvent.keyCodeToString(keyCode), event.getAction(), event});
+        int source = event.getSource();
+//        logger.log(Level.INFO, "onKey source: {0}", source);
+
+        boolean isTouch =
+                ((source & InputDevice.SOURCE_TOUCHSCREEN) == InputDevice.SOURCE_TOUCHSCREEN) ||
+                ((source & InputDevice.SOURCE_KEYBOARD) == InputDevice.SOURCE_KEYBOARD);
+        boolean isJoystick =
+                ((source & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD) ||
+                ((source & InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK);
+
+        if (isTouch && touchInput != null) {
+//            logger.log(Level.INFO, "onKey source: {0}, isTouch: {1}",
+//                    new Object[]{source, isTouch});
+            consumed = touchInput.onKey(event);
+        }
+        if (isJoystick && joyInput != null) {
+//            logger.log(Level.INFO, "onKey source: {0}, isJoystick: {1}",
+//                    new Object[]{source, isJoystick});
+            consumed = consumed || ((AndroidJoyInput14)joyInput).onKey(event);
+        }
+
+        return consumed;
+
+    }
+
+}

+ 20 - 42
jme3-android/src/main/java/com/jme3/input/android/AndroidJoyInputHandler.java → jme3-android/src/main/java/com/jme3/input/android/AndroidJoyInput.java

@@ -33,9 +33,7 @@ package com.jme3.input.android;
 
 
 import android.content.Context;
 import android.content.Context;
 import android.opengl.GLSurfaceView;
 import android.opengl.GLSurfaceView;
-import android.os.Build;
 import android.os.Vibrator;
 import android.os.Vibrator;
-import android.view.View;
 import com.jme3.input.InputManager;
 import com.jme3.input.InputManager;
 import com.jme3.input.JoyInput;
 import com.jme3.input.JoyInput;
 import com.jme3.input.Joystick;
 import com.jme3.input.Joystick;
@@ -79,15 +77,15 @@ import java.util.logging.Logger;
  *
  *
  * @author iwgeric
  * @author iwgeric
  */
  */
-public class AndroidJoyInputHandler implements JoyInput {
-    private static final Logger logger = Logger.getLogger(AndroidJoyInputHandler.class.getName());
+public class AndroidJoyInput implements JoyInput {
+    private static final Logger logger = Logger.getLogger(AndroidJoyInput.class.getName());
 
 
-    private List<Joystick> joystickList = new ArrayList<Joystick>();
+    protected AndroidInputHandler inputHandler;
+    protected List<Joystick> joystickList = new ArrayList<Joystick>();
 //    private boolean dontSendHistory = false;
 //    private boolean dontSendHistory = false;
 
 
 
 
     // Internal
     // Internal
-    private GLSurfaceView view;
     private boolean initialized = false;
     private boolean initialized = false;
     private RawInputListener listener = null;
     private RawInputListener listener = null;
     private ConcurrentLinkedQueue<InputEvent> eventQueue = new ConcurrentLinkedQueue<InputEvent>();
     private ConcurrentLinkedQueue<InputEvent> eventQueue = new ConcurrentLinkedQueue<InputEvent>();
@@ -96,34 +94,29 @@ public class AndroidJoyInputHandler implements JoyInput {
     private boolean vibratorActive = false;
     private boolean vibratorActive = false;
     private long maxRumbleTime = 250;  // 250ms
     private long maxRumbleTime = 250;  // 250ms
 
 
-    public AndroidJoyInputHandler() {
-        int buildVersion = Build.VERSION.SDK_INT;
-        logger.log(Level.INFO, "Android Build Version: {0}", buildVersion);
-//        if (buildVersion >= 14) {
-//            touchHandler = new AndroidTouchHandler14(this);
-//        } else if (buildVersion >= 8){
-//            touchHandler = new AndroidTouchHandler(this);
-//        }
+    public AndroidJoyInput(AndroidInputHandler inputHandler) {
+        this.inputHandler = inputHandler;
         sensorJoyInput = new AndroidSensorJoyInput(this);
         sensorJoyInput = new AndroidSensorJoyInput(this);
     }
     }
 
 
     public void setView(GLSurfaceView view) {
     public void setView(GLSurfaceView view) {
-//        if (touchHandler != null) {
-//            touchHandler.setView(view);
-//        }
+        if (view == null) {
+            vibrator = null;
+        } else {
+            // Get instance of Vibrator from current Context
+            vibrator = (Vibrator) view.getContext().getSystemService(Context.VIBRATOR_SERVICE);
+            if (vibrator == null) {
+                logger.log(Level.FINE, "Vibrator Service not found.");
+            }
+        }
+
         if (sensorJoyInput != null) {
         if (sensorJoyInput != null) {
             sensorJoyInput.setView(view);
             sensorJoyInput.setView(view);
         }
         }
-        this.view = (GLSurfaceView)view;
-
-    }
-
-    public View getView() {
-        return view;
     }
     }
 
 
     public void loadSettings(AppSettings settings) {
     public void loadSettings(AppSettings settings) {
-//        sensorEventsEnabled = settings.useSensors();
+
     }
     }
 
 
     public void addEvent(InputEvent event) {
     public void addEvent(InputEvent event) {
@@ -155,20 +148,8 @@ public class AndroidJoyInputHandler implements JoyInput {
 
 
     }
     }
 
 
-
-
-
-
     @Override
     @Override
     public void initialize() {
     public void initialize() {
-//        if (sensorJoyInput != null) {
-//            sensorJoyInput.initialize();
-//        }
-        // Get instance of Vibrator from current Context
-        vibrator = (Vibrator) view.getContext().getSystemService(Context.VIBRATOR_SERVICE);
-        if (vibrator == null) {
-            logger.log(Level.FINE, "Vibrator Service not found.");
-        }
         initialized = true;
         initialized = true;
     }
     }
 
 
@@ -211,8 +192,8 @@ public class AndroidJoyInputHandler implements JoyInput {
             };
             };
             final int rumbleRepeatFrom = 0; // index into rumble pattern to repeat from
             final int rumbleRepeatFrom = 0; // index into rumble pattern to repeat from
 
 
-            logger.log(Level.FINE, "Rumble amount: {0}, rumbleOnDur: {1}, rumbleOffDur: {2}",
-                    new Object[]{amount, rumbleOnDur, rumbleOffDur});
+//            logger.log(Level.FINE, "Rumble amount: {0}, rumbleOnDur: {1}, rumbleOffDur: {2}",
+//                    new Object[]{amount, rumbleOnDur, rumbleOffDur});
 
 
             if (rumbleOnDur > 0) {
             if (rumbleOnDur > 0) {
                 vibrator.vibrate(rumblePattern, rumbleRepeatFrom);
                 vibrator.vibrate(rumblePattern, rumbleRepeatFrom);
@@ -226,9 +207,8 @@ public class AndroidJoyInputHandler implements JoyInput {
 
 
     @Override
     @Override
     public Joystick[] loadJoysticks(InputManager inputManager) {
     public Joystick[] loadJoysticks(InputManager inputManager) {
+        logger.log(Level.INFO, "loading joysticks for {0}", this.getClass().getName());
         joystickList.add(sensorJoyInput.loadJoystick(joystickList.size(), inputManager));
         joystickList.add(sensorJoyInput.loadJoystick(joystickList.size(), inputManager));
-
-
         return joystickList.toArray( new Joystick[joystickList.size()] );
         return joystickList.toArray( new Joystick[joystickList.size()] );
     }
     }
 
 
@@ -252,6 +232,4 @@ public class AndroidJoyInputHandler implements JoyInput {
 
 
     }
     }
 
 
-
-
 }
 }

+ 108 - 0
jme3-android/src/main/java/com/jme3/input/android/AndroidJoyInput14.java

@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2009-2015 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ *   may be used to endorse or promote products derived from this software
+ *   without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.jme3.input.android;
+
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import com.jme3.input.InputManager;
+import com.jme3.input.Joystick;
+import java.util.logging.Logger;
+
+/**
+ * <code>AndroidJoyInput14</code> extends <code>AndroidJoyInput</code>
+ * to include support for physical joysticks/gamepads.</br>
+ *
+ * @author iwgeric
+ */
+public class AndroidJoyInput14 extends AndroidJoyInput {
+    private static final Logger logger = Logger.getLogger(AndroidJoyInput14.class.getName());
+
+    private AndroidJoystickJoyInput14 joystickJoyInput;
+
+    public AndroidJoyInput14(AndroidInputHandler inputHandler) {
+        super(inputHandler);
+        joystickJoyInput = new AndroidJoystickJoyInput14(this);
+    }
+
+    /**
+     * Pauses the joystick device listeners to save battery life if they are not needed.
+     * Used to pause when the activity pauses
+     */
+    @Override
+    public void pauseJoysticks() {
+        super.pauseJoysticks();
+
+        if (joystickJoyInput != null) {
+            joystickJoyInput.pauseJoysticks();
+        }
+    }
+
+    /**
+     * Resumes the joystick device listeners.
+     * Used to resume when the activity comes to the top of the stack
+     */
+    @Override
+    public void resumeJoysticks() {
+        super.resumeJoysticks();
+        if (joystickJoyInput != null) {
+            joystickJoyInput.resumeJoysticks();
+        }
+
+    }
+
+    @Override
+    public void destroy() {
+        super.destroy();
+        if (joystickJoyInput != null) {
+            joystickJoyInput.destroy();
+        }
+    }
+
+    @Override
+    public Joystick[] loadJoysticks(InputManager inputManager) {
+        // load the simulated joystick for device orientation
+        super.loadJoysticks(inputManager);
+        // load physical gamepads/joysticks
+        joystickList.addAll(joystickJoyInput.loadJoysticks(joystickList.size(), inputManager));
+        // return the list of joysticks back to InputManager
+        return joystickList.toArray( new Joystick[joystickList.size()] );
+    }
+
+    public boolean onGenericMotion(MotionEvent event) {
+        return joystickJoyInput.onGenericMotion(event);
+    }
+
+    public boolean onKey(KeyEvent event) {
+        return joystickJoyInput.onKey(event);
+    }
+
+}

+ 403 - 0
jme3-android/src/main/java/com/jme3/input/android/AndroidJoystickJoyInput14.java

@@ -0,0 +1,403 @@
+/*
+ * Copyright (c) 2009-2015 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ *   may be used to endorse or promote products derived from this software
+ *   without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.jme3.input.android;
+
+import android.view.InputDevice;
+import android.view.InputDevice.MotionRange;
+import android.view.KeyCharacterMap;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import com.jme3.input.AbstractJoystick;
+import com.jme3.input.DefaultJoystickAxis;
+import com.jme3.input.DefaultJoystickButton;
+import com.jme3.input.InputManager;
+import com.jme3.input.JoyInput;
+import com.jme3.input.Joystick;
+import com.jme3.input.JoystickAxis;
+import com.jme3.input.JoystickButton;
+import com.jme3.input.event.JoyAxisEvent;
+import com.jme3.input.event.JoyButtonEvent;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * Main class that creates and manages Android inputs for physical gamepads/joysticks.
+ *
+ * @author iwgeric
+ */
+public class AndroidJoystickJoyInput14 {
+    private static final Logger logger = Logger.getLogger(AndroidJoystickJoyInput14.class.getName());
+
+    private boolean loaded = false;
+    private AndroidJoyInput joyInput;
+    private Map<Integer, AndroidJoystick> joystickIndex = new HashMap<Integer, AndroidJoystick>();
+
+    private static int[] AndroidGamepadButtons = {
+            // Dpad buttons
+            KeyEvent.KEYCODE_DPAD_UP,        KeyEvent.KEYCODE_DPAD_DOWN,
+            KeyEvent.KEYCODE_DPAD_LEFT,      KeyEvent.KEYCODE_DPAD_RIGHT,
+            KeyEvent.KEYCODE_DPAD_CENTER,
+
+            // pressing joystick down
+            KeyEvent.KEYCODE_BUTTON_THUMBL,  KeyEvent.KEYCODE_BUTTON_THUMBR,
+
+            // buttons
+            KeyEvent.KEYCODE_BUTTON_A,       KeyEvent.KEYCODE_BUTTON_B,
+            KeyEvent.KEYCODE_BUTTON_X,       KeyEvent.KEYCODE_BUTTON_Y,
+
+            // buttons on back of device
+            KeyEvent.KEYCODE_BUTTON_L1,      KeyEvent.KEYCODE_BUTTON_R1,
+            KeyEvent.KEYCODE_BUTTON_L2,      KeyEvent.KEYCODE_BUTTON_R2,
+
+            // start / select buttons
+            KeyEvent.KEYCODE_BUTTON_START,   KeyEvent.KEYCODE_BUTTON_SELECT,
+            KeyEvent.KEYCODE_BUTTON_MODE,
+
+    };
+
+    public AndroidJoystickJoyInput14(AndroidJoyInput joyInput) {
+        this.joyInput = joyInput;
+    }
+
+
+    public void pauseJoysticks() {
+
+    }
+
+    public void resumeJoysticks() {
+
+    }
+
+    public void destroy() {
+
+    }
+
+    public List<Joystick> loadJoysticks(int joyId, InputManager inputManager) {
+        logger.log(Level.INFO, "loading Joystick devices");
+        ArrayList<Joystick> joysticks = new ArrayList<Joystick>();
+        joysticks.clear();
+        joystickIndex.clear();
+
+        ArrayList gameControllerDeviceIds = new ArrayList();
+        int[] deviceIds = InputDevice.getDeviceIds();
+        for (int deviceId : deviceIds) {
+            InputDevice dev = InputDevice.getDevice(deviceId);
+            int sources = dev.getSources();
+            logger.log(Level.FINE, "deviceId[{0}] sources: {1}", new Object[]{deviceId, sources});
+
+            // Verify that the device has gamepad buttons, control sticks, or both.
+            if (((sources & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD) ||
+                    ((sources & InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK)) {
+                // This device is a game controller. Store its device ID.
+                if (!gameControllerDeviceIds.contains(deviceId)) {
+                    gameControllerDeviceIds.add(deviceId);
+                    logger.log(Level.FINE, "Attempting to create joystick for device: {0}", dev);
+                    // Create an AndroidJoystick and store the InputDevice so we
+                    // can later correspond the input from the InputDevice to the
+                    // appropriate jME Joystick event
+                    AndroidJoystick joystick = new AndroidJoystick(inputManager,
+                                                                joyInput,
+                                                                dev,
+                                                                joyId+joysticks.size(),
+                                                                dev.getName());
+                    joystickIndex.put(deviceId, joystick);
+                    joysticks.add(joystick);
+
+                    // Each analog input is reported as a MotionRange
+                    // The axis number corresponds to the type of axis
+                    // The AndroidJoystick.addAxis(MotionRange) converts the axis
+                    // type reported by Android into the jME Joystick axis
+                    List<MotionRange> motionRanges = dev.getMotionRanges();
+                    for (MotionRange motionRange: motionRanges) {
+                        logger.log(Level.INFO, "motion range: {0}", motionRange.toString());
+                        logger.log(Level.INFO, "axis: {0}", motionRange.getAxis());
+                        JoystickAxis axis = joystick.addAxis(motionRange);
+                        logger.log(Level.INFO, "added axis: {0}", axis);
+                    }
+
+                    // InputDevice has a method for determining if a keyCode is
+                    // supported (InputDevice  public boolean[] hasKeys (int... keys)).
+                    // But this method wasn't added until rev 19 (Android 4.4)
+                    // Therefore, we only can query the entire device and see if
+                    // any InputDevice supports the keyCode.  This may result in
+                    // buttons being configured that don't exist on the specific
+                    // device, but I haven't found a better way yet.
+                    for (int keyCode: AndroidGamepadButtons) {
+                        logger.log(Level.INFO, "button[{0}]: {1}",
+                                new Object[]{keyCode, KeyCharacterMap.deviceHasKey(keyCode)});
+                        if (KeyCharacterMap.deviceHasKey(keyCode)) {
+                            // add button even though we aren't sure if the button
+                            // actually exists on this InputDevice
+                            logger.log(Level.INFO, "button[{0}] exists somewhere", keyCode);
+                            JoystickButton button = joystick.addButton(keyCode);
+                            logger.log(Level.INFO, "added button: {0}", button);
+                        }
+                    }
+
+                }
+            }
+        }
+
+
+        loaded = true;
+        return joysticks;
+    }
+
+    public boolean onGenericMotion(MotionEvent event) {
+        boolean consumed = false;
+//        logger.log(Level.INFO, "onGenericMotion event: {0}", event);
+        event.getDeviceId();
+        event.getSource();
+//        logger.log(Level.INFO, "deviceId: {0}, source: {1}", new Object[]{event.getDeviceId(), event.getSource()});
+        AndroidJoystick joystick = joystickIndex.get(event.getDeviceId());
+        if (joystick != null) {
+            for (int androidAxis: joystick.getAndroidAxes()) {
+                String axisName = MotionEvent.axisToString(androidAxis);
+                float value = event.getAxisValue(androidAxis);
+                int action = event.getAction();
+                if (action == MotionEvent.ACTION_MOVE) {
+//                    logger.log(Level.INFO, "MOVE axis num: {0}, axisName: {1}, value: {2}",
+//                            new Object[]{androidAxis, axisName, value});
+                    JoystickAxis axis = joystick.getAxis(androidAxis);
+                    if (axis != null) {
+//                        logger.log(Level.INFO, "MOVE axis num: {0}, axisName: {1}, value: {2}, deadzone: {3}",
+//                                new Object[]{androidAxis, axisName, value, axis.getDeadZone()});
+                        JoyAxisEvent axisEvent = new JoyAxisEvent(axis, value);
+                        joyInput.addEvent(axisEvent);
+                        consumed = true;
+                    } else {
+//                        logger.log(Level.INFO, "axis was null for axisName: {0}", axisName);
+                    }
+                } else {
+//                    logger.log(Level.INFO, "action: {0}", action);
+                }
+            }
+        }
+
+        return consumed;
+    }
+
+    public boolean onKey(KeyEvent event) {
+        boolean consumed = false;
+//        logger.log(Level.INFO, "onKey event: {0}", event);
+
+        event.getDeviceId();
+        event.getSource();
+        AndroidJoystick joystick = joystickIndex.get(event.getDeviceId());
+        if (joystick != null) {
+            JoystickButton button = joystick.getButton(event.getKeyCode());
+            if (button != null) {
+                boolean pressed = event.getAction() == KeyEvent.ACTION_DOWN;
+                JoyButtonEvent buttonEvent = new JoyButtonEvent(button, pressed);
+                joyInput.addEvent(buttonEvent);
+                consumed = true;
+            }
+        }
+
+        return consumed;
+    }
+
+    protected class AndroidJoystick extends AbstractJoystick {
+
+        private JoystickAxis nullAxis;
+        private InputDevice device;
+        private JoystickAxis xAxis;
+        private JoystickAxis yAxis;
+        private JoystickAxis povX;
+        private JoystickAxis povY;
+        private Map<Integer, JoystickAxis> axisIndex = new HashMap<Integer, JoystickAxis>();
+        private Map<Integer, JoystickButton> buttonIndex = new HashMap<Integer, JoystickButton>();
+
+        public AndroidJoystick( InputManager inputManager, JoyInput joyInput, InputDevice device,
+                               int joyId, String name ) {
+            super( inputManager, joyInput, joyId, name );
+
+            this.device = device;
+
+            this.nullAxis = new DefaultJoystickAxis( getInputManager(), this, -1,
+                                                     "Null", "null", false, false, 0 );
+            this.xAxis = nullAxis;
+            this.yAxis = nullAxis;
+            this.povX = nullAxis;
+            this.povY = nullAxis;
+        }
+
+        protected JoystickAxis getAxis(int androidAxis) {
+            return axisIndex.get(androidAxis);
+        }
+
+        protected Set<Integer> getAndroidAxes() {
+            return axisIndex.keySet();
+        }
+
+        protected JoystickButton getButton(int keyCode) {
+            return buttonIndex.get(keyCode);
+        }
+
+        protected JoystickButton addButton( int keyCode ) {
+
+//            logger.log(Level.FINE, "Adding button: {0}", keyCode);
+
+            String name = KeyEvent.keyCodeToString(keyCode);
+            String logicalId = KeyEvent.keyCodeToString(keyCode);
+            // A/B/X/Y buttons
+            if (keyCode == KeyEvent.KEYCODE_BUTTON_Y) {
+                logicalId = JoystickButton.BUTTON_0;
+            } else if (keyCode == KeyEvent.KEYCODE_BUTTON_A) {
+                logicalId = JoystickButton.BUTTON_2;
+            } else if (keyCode == KeyEvent.KEYCODE_BUTTON_B) {
+                logicalId = JoystickButton.BUTTON_1;
+            } else if (keyCode == KeyEvent.KEYCODE_BUTTON_X) {
+                logicalId = JoystickButton.BUTTON_3;
+            // Front buttons  Some of these have the top ones and the bottoms ones flipped.
+            } else if (keyCode == KeyEvent.KEYCODE_BUTTON_L1) {
+                logicalId = JoystickButton.BUTTON_4;
+            } else if (keyCode == KeyEvent.KEYCODE_BUTTON_R1) {
+                logicalId = JoystickButton.BUTTON_5;
+            } else if (keyCode == KeyEvent.KEYCODE_BUTTON_L2) {
+                logicalId = JoystickButton.BUTTON_6;
+            } else if (keyCode == KeyEvent.KEYCODE_BUTTON_R2) {
+                logicalId = JoystickButton.BUTTON_7;
+//            // Dpad buttons
+//            } else if (keyCode == KeyEvent.KEYCODE_DPAD_UP) {
+//                logicalId = JoystickButton.BUTTON_8;
+//            } else if (keyCode == KeyEvent.KEYCODE_DPAD_UP) {
+//                logicalId = JoystickButton.BUTTON_9;
+//            } else if (keyCode == KeyEvent.KEYCODE_DPAD_UP) {
+//                logicalId = JoystickButton.BUTTON_8;
+//            } else if (keyCode == KeyEvent.KEYCODE_DPAD_UP) {
+//                logicalId = JoystickButton.BUTTON_9;
+            // Select and start buttons
+            } else if (keyCode == KeyEvent.KEYCODE_BUTTON_SELECT) {
+                logicalId = JoystickButton.BUTTON_8;
+            } else if (keyCode == KeyEvent.KEYCODE_BUTTON_START) {
+                logicalId = JoystickButton.BUTTON_9;
+            // Joystick push buttons
+            } else if (keyCode == KeyEvent.KEYCODE_BUTTON_THUMBL) {
+                logicalId = JoystickButton.BUTTON_10;
+            } else if (keyCode == KeyEvent.KEYCODE_BUTTON_THUMBR) {
+                logicalId = JoystickButton.BUTTON_11;
+            }
+
+            JoystickButton button = new DefaultJoystickButton( getInputManager(), this, getButtonCount(),
+                                                               name, logicalId );
+            addButton(button);
+            buttonIndex.put( keyCode, button );
+            return button;
+        }
+
+        protected JoystickAxis addAxis(MotionRange motionRange) {
+
+            String name = MotionEvent.axisToString(motionRange.getAxis());
+
+            String logicalId = MotionEvent.axisToString(motionRange.getAxis());
+            if (motionRange.getAxis() == MotionEvent.AXIS_X) {
+                logicalId = JoystickAxis.X_AXIS;
+            } else if (motionRange.getAxis() == MotionEvent.AXIS_Y) {
+                logicalId = JoystickAxis.Y_AXIS;
+            } else if (motionRange.getAxis() == MotionEvent.AXIS_Z) {
+                logicalId = JoystickAxis.Z_AXIS;
+            } else if (motionRange.getAxis() == MotionEvent.AXIS_RZ) {
+                logicalId = JoystickAxis.Z_ROTATION;
+            } else if (motionRange.getAxis() == MotionEvent.AXIS_HAT_X) {
+                logicalId = JoystickAxis.POV_X;
+            } else if (motionRange.getAxis() == MotionEvent.AXIS_HAT_Y) {
+                logicalId = JoystickAxis.POV_Y;
+            }
+//            String logicalId = JoystickCompatibilityMappings.remapComponent( controller.getName(), original );
+//            if( name != original ) {
+//                logger.log(Level.FINE, "Remapped:" + original + " to:" + logicalId);
+//            }
+
+            JoystickAxis axis = new DefaultJoystickAxis(getInputManager(),
+                                                this,
+                                                getAxisCount(),
+                                                name,
+                                                logicalId,
+                                                true,
+                                                true,
+                                                motionRange.getFlat());
+
+            if (motionRange.getAxis() == MotionEvent.AXIS_X) {
+                xAxis = axis;
+            }
+            if (motionRange.getAxis() == MotionEvent.AXIS_Y) {
+                yAxis = axis;
+            }
+            if (motionRange.getAxis() == MotionEvent.AXIS_HAT_X) {
+                povX = axis;
+            }
+            if (motionRange.getAxis() == MotionEvent.AXIS_HAT_Y) {
+                povY = axis;
+            }
+
+            addAxis(axis);
+            axisIndex.put(motionRange.getAxis(), axis);
+            return axis;
+        }
+
+        @Override
+        public JoystickAxis getXAxis() {
+            return xAxis;
+        }
+
+        @Override
+        public JoystickAxis getYAxis() {
+            return yAxis;
+        }
+
+        @Override
+        public JoystickAxis getPovXAxis() {
+            return povX;
+        }
+
+        @Override
+        public JoystickAxis getPovYAxis() {
+            return povY;
+        }
+
+        @Override
+        public int getXAxisIndex(){
+            return xAxis.getAxisId();
+        }
+
+        @Override
+        public int getYAxisIndex(){
+            return yAxis.getAxisId();
+        }
+    }
+}

+ 0 - 140
jme3-android/src/main/java/com/jme3/input/android/AndroidKeyHandler.java

@@ -1,140 +0,0 @@
-/*
- * Copyright (c) 2009-2012 jMonkeyEngine
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- *
- * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
- *   may be used to endorse or promote products derived from this software
- *   without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
- * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-package com.jme3.input.android;
-
-import android.content.Context;
-import android.view.KeyEvent;
-import android.view.View;
-import android.view.inputmethod.InputMethodManager;
-import com.jme3.input.event.KeyInputEvent;
-import com.jme3.input.event.TouchEvent;
-import java.util.logging.Logger;
-
-/**
- * AndroidKeyHandler recieves onKey events from the Android system and creates
- * the jME KeyEvents.  onKey is used by Android to receive keys from the keyboard
- * or device buttons.  All key events are consumed by jME except for the Volume
- * buttons and menu button.
- *
- * This class also provides the functionality to display or hide the soft keyboard
- * for inputing single key events.  Use OGLESContext to display an dialog to type
- * in complete strings.
- *
- * @author iwgeric
- */
-public class AndroidKeyHandler implements View.OnKeyListener {
-    private static final Logger logger = Logger.getLogger(AndroidKeyHandler.class.getName());
-
-    private AndroidInputHandler androidInput;
-    private boolean sendKeyEvents = true;
-
-    public AndroidKeyHandler(AndroidInputHandler androidInput) {
-        this.androidInput = androidInput;
-    }
-
-    public void initialize() {
-    }
-
-    public void destroy() {
-    }
-
-    public void setView(View view) {
-        if (view != null) {
-            view.setOnKeyListener(this);
-        } else {
-            androidInput.getView().setOnKeyListener(null);
-        }
-    }
-
-    /**
-     * onKey gets called from android thread on key events
-     */
-    public boolean onKey(View view, int keyCode, KeyEvent event) {
-        if (androidInput.isInitialized() && view != androidInput.getView()) {
-            return false;
-        }
-
-        TouchEvent evt;
-        // TODO: get touch event from pool
-        if (event.getAction() == KeyEvent.ACTION_DOWN) {
-            evt = new TouchEvent();
-            evt.set(TouchEvent.Type.KEY_DOWN);
-            evt.setKeyCode(keyCode);
-            evt.setCharacters(event.getCharacters());
-            evt.setTime(event.getEventTime());
-
-            // Send the event
-            androidInput.addEvent(evt);
-
-        } else if (event.getAction() == KeyEvent.ACTION_UP) {
-            evt = new TouchEvent();
-            evt.set(TouchEvent.Type.KEY_UP);
-            evt.setKeyCode(keyCode);
-            evt.setCharacters(event.getCharacters());
-            evt.setTime(event.getEventTime());
-
-            // Send the event
-            androidInput.addEvent(evt);
-
-        }
-
-        if (androidInput.isSimulateKeyboard()) {
-            KeyInputEvent kie;
-            char unicodeChar = (char)event.getUnicodeChar();
-            int jmeKeyCode = AndroidKeyMapping.getJmeKey(keyCode);
-
-            boolean pressed = event.getAction() == KeyEvent.ACTION_DOWN;
-            boolean repeating = pressed && event.getRepeatCount() > 0;
-
-            kie = new KeyInputEvent(jmeKeyCode, unicodeChar, pressed, repeating);
-            kie.setTime(event.getEventTime());
-            androidInput.addEvent(kie);
-//            logger.log(Level.FINE, "onKey keyCode: {0}, jmeKeyCode: {1}, pressed: {2}, repeating: {3}",
-//                    new Object[]{keyCode, jmeKeyCode, pressed, repeating});
-//            logger.log(Level.FINE, "creating KeyInputEvent: {0}", kie);
-        }
-
-        // consume all keys ourself except Volume Up/Down and Menu
-        //   Don't do Menu so that typical Android Menus can be created and used
-        //   by the user in MainActivity
-        if ((keyCode == KeyEvent.KEYCODE_VOLUME_UP) ||
-                (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) ||
-                (keyCode == KeyEvent.KEYCODE_MENU)) {
-            return false;
-        } else {
-            return true;
-        }
-
-   }
-
-}

+ 11 - 6
jme3-android/src/main/java/com/jme3/input/android/AndroidKeyMapping.java

@@ -37,13 +37,14 @@ import java.util.logging.Logger;
 
 
 /**
 /**
  * AndroidKeyMapping is just a utility to convert the Android keyCodes into
  * AndroidKeyMapping is just a utility to convert the Android keyCodes into
- * jME KeyCodes received in jME's KeyEvent will match between Desktop and Android.
- * 
+ * jME KeyCodes so that events received in jME's KeyEvent will match between
+ * Desktop and Android.
+ *
  * @author iwgeric
  * @author iwgeric
  */
  */
 public class AndroidKeyMapping {
 public class AndroidKeyMapping {
     private static final Logger logger = Logger.getLogger(AndroidKeyMapping.class.getName());
     private static final Logger logger = Logger.getLogger(AndroidKeyMapping.class.getName());
-    
+
     private static final int[] ANDROID_TO_JME = {
     private static final int[] ANDROID_TO_JME = {
         0x0, // unknown
         0x0, // unknown
         0x0, // key code soft left
         0x0, // key code soft left
@@ -141,9 +142,13 @@ public class AndroidKeyMapping {
         0x0,//media fastforward
         0x0,//media fastforward
         0x0,//mute
         0x0,//mute
     };
     };
-    
+
     public static int getJmeKey(int androidKey) {
     public static int getJmeKey(int androidKey) {
-        return ANDROID_TO_JME[androidKey];
+        if (androidKey > ANDROID_TO_JME.length) {
+            return androidKey;
+        } else {
+            return ANDROID_TO_JME[androidKey];
+        }
     }
     }
-    
+
 }
 }

+ 24 - 24
jme3-android/src/main/java/com/jme3/input/android/AndroidSensorJoyInput.java

@@ -75,15 +75,15 @@ import java.util.logging.Logger;
 public class AndroidSensorJoyInput implements SensorEventListener {
 public class AndroidSensorJoyInput implements SensorEventListener {
     private final static Logger logger = Logger.getLogger(AndroidSensorJoyInput.class.getName());
     private final static Logger logger = Logger.getLogger(AndroidSensorJoyInput.class.getName());
 
 
-    private AndroidJoyInputHandler joyHandler;
+    private AndroidJoyInput joyInput;
     private SensorManager sensorManager = null;
     private SensorManager sensorManager = null;
     private WindowManager windowManager = null;
     private WindowManager windowManager = null;
     private IntMap<SensorData> sensors = new IntMap<SensorData>();
     private IntMap<SensorData> sensors = new IntMap<SensorData>();
     private int lastRotation = 0;
     private int lastRotation = 0;
     private boolean loaded = false;
     private boolean loaded = false;
 
 
-    public AndroidSensorJoyInput(AndroidJoyInputHandler joyHandler) {
-        this.joyHandler = joyHandler;
+    public AndroidSensorJoyInput(AndroidJoyInput joyInput) {
+        this.joyInput = joyInput;
     }
     }
 
 
     /**
     /**
@@ -96,7 +96,7 @@ public class AndroidSensorJoyInput implements SensorEventListener {
         int sensorAccuracy = -1;
         int sensorAccuracy = -1;
         float[] lastValues;
         float[] lastValues;
         final Object valuesLock = new Object();
         final Object valuesLock = new Object();
-        ArrayList<AndroidJoystickAxis> axes = new ArrayList<AndroidJoystickAxis>();
+        ArrayList<AndroidSensorJoystickAxis> axes = new ArrayList<AndroidSensorJoystickAxis>();
         boolean enabled = false;
         boolean enabled = false;
         boolean haveData = false;
         boolean haveData = false;
 
 
@@ -306,7 +306,7 @@ public class AndroidSensorJoyInput implements SensorEventListener {
      */
      */
     private boolean updateOrientation() {
     private boolean updateOrientation() {
         SensorData sensorData;
         SensorData sensorData;
-        AndroidJoystickAxis axis;
+        AndroidSensorJoystickAxis axis;
         final float[] curInclinationMat = new float[16];
         final float[] curInclinationMat = new float[16];
         final float[] curRotationMat = new float[16];
         final float[] curRotationMat = new float[16];
         final float[] rotatedRotationMat = new float[16];
         final float[] rotatedRotationMat = new float[16];
@@ -374,7 +374,7 @@ public class AndroidSensorJoyInput implements SensorEventListener {
                                 sensorData.haveData = true;
                                 sensorData.haveData = true;
                             } else {
                             } else {
                                 if (axis.isChanged()) {
                                 if (axis.isChanged()) {
-                                    joyHandler.addEvent(new JoyAxisEvent(axis, axis.getJoystickAxisValue()));
+                                    joyInput.addEvent(new JoyAxisEvent(axis, axis.getJoystickAxisValue()));
                                 }
                                 }
                             }
                             }
                         }
                         }
@@ -401,10 +401,10 @@ public class AndroidSensorJoyInput implements SensorEventListener {
 
 
     public Joystick loadJoystick(int joyId, InputManager inputManager) {
     public Joystick loadJoystick(int joyId, InputManager inputManager) {
         SensorData sensorData;
         SensorData sensorData;
-        AndroidJoystickAxis axis;
+        AndroidSensorJoystickAxis axis;
 
 
-        AndroidJoystick joystick = new AndroidJoystick(inputManager,
-                                    joyHandler,
+        AndroidSensorJoystick joystick = new AndroidSensorJoystick(inputManager,
+                                    joyInput,
                                     joyId,
                                     joyId,
                                     "AndroidSensorsJoystick");
                                     "AndroidSensorsJoystick");
 
 
@@ -522,15 +522,15 @@ public class AndroidSensorJoyInput implements SensorEventListener {
         if (!loaded) {
         if (!loaded) {
             return;
             return;
         }
         }
-        logger.log(Level.FINE, "onSensorChanged for {0}: accuracy: {1}, values: {2}",
-                new Object[]{se.sensor.getName(), se.accuracy, se.values});
+//        logger.log(Level.FINE, "onSensorChanged for {0}: accuracy: {1}, values: {2}",
+//                new Object[]{se.sensor.getName(), se.accuracy, se.values});
 
 
         int sensorType = se.sensor.getType();
         int sensorType = se.sensor.getType();
 
 
         SensorData sensorData = sensors.get(sensorType);
         SensorData sensorData = sensors.get(sensorType);
         if (sensorData != null) {
         if (sensorData != null) {
-            logger.log(Level.FINE, "sensorData name: {0}, enabled: {1}, unreliable: {2}",
-                    new Object[]{sensorData.sensor.getName(), sensorData.enabled, sensorData.sensorAccuracy == SensorManager.SENSOR_STATUS_UNRELIABLE});
+//            logger.log(Level.FINE, "sensorData name: {0}, enabled: {1}, unreliable: {2}",
+//                    new Object[]{sensorData.sensor.getName(), sensorData.enabled, sensorData.sensorAccuracy == SensorManager.SENSOR_STATUS_UNRELIABLE});
         }
         }
         if (sensorData != null && sensorData.sensor.equals(se.sensor) && sensorData.enabled) {
         if (sensorData != null && sensorData.sensor.equals(se.sensor) && sensorData.enabled) {
 
 
@@ -543,8 +543,8 @@ public class AndroidSensorJoyInput implements SensorEventListener {
                 }
                 }
             }
             }
 
 
-            if (sensorData != null && sensorData.axes.size() > 0) {
-                AndroidJoystickAxis axis;
+            if (sensorData.axes.size() > 0) {
+                AndroidSensorJoystickAxis axis;
                 for (int i=0; i<se.values.length; i++) {
                 for (int i=0; i<se.values.length; i++) {
                     axis = sensorData.axes.get(i);
                     axis = sensorData.axes.get(i);
                     if (axis != null) {
                     if (axis != null) {
@@ -554,8 +554,8 @@ public class AndroidSensorJoyInput implements SensorEventListener {
                         } else {
                         } else {
                             if (axis.isChanged()) {
                             if (axis.isChanged()) {
                                 JoyAxisEvent event = new JoyAxisEvent(axis, axis.getJoystickAxisValue());
                                 JoyAxisEvent event = new JoyAxisEvent(axis, axis.getJoystickAxisValue());
-                                logger.log(Level.INFO, "adding JoyAxisEvent: {0}", event);
-                                joyHandler.addEvent(event);
+//                                logger.log(Level.INFO, "adding JoyAxisEvent: {0}", event);
+                                joyInput.addEvent(event);
 //                                joyHandler.addEvent(new JoyAxisEvent(axis, axis.getJoystickAxisValue()));
 //                                joyHandler.addEvent(new JoyAxisEvent(axis, axis.getJoystickAxisValue()));
                             }
                             }
                         }
                         }
@@ -585,14 +585,14 @@ public class AndroidSensorJoyInput implements SensorEventListener {
 
 
     // End of SensorEventListener methods
     // End of SensorEventListener methods
 
 
-    protected class AndroidJoystick extends AbstractJoystick {
+    protected class AndroidSensorJoystick extends AbstractJoystick {
         private JoystickAxis nullAxis;
         private JoystickAxis nullAxis;
         private JoystickAxis xAxis;
         private JoystickAxis xAxis;
         private JoystickAxis yAxis;
         private JoystickAxis yAxis;
         private JoystickAxis povX;
         private JoystickAxis povX;
         private JoystickAxis povY;
         private JoystickAxis povY;
 
 
-        public AndroidJoystick( InputManager inputManager, JoyInput joyInput,
+        public AndroidSensorJoystick( InputManager inputManager, JoyInput joyInput,
                                 int joyId, String name){
                                 int joyId, String name){
 
 
             super( inputManager, joyInput, joyId, name );
             super( inputManager, joyInput, joyId, name );
@@ -606,10 +606,10 @@ public class AndroidSensorJoyInput implements SensorEventListener {
 
 
         }
         }
 
 
-        protected AndroidJoystickAxis addAxis(String axisName, String logicalName, int axisNum, float maxRawValue) {
-            AndroidJoystickAxis axis;
+        protected AndroidSensorJoystickAxis addAxis(String axisName, String logicalName, int axisNum, float maxRawValue) {
+            AndroidSensorJoystickAxis axis;
 
 
-            axis = new AndroidJoystickAxis(
+            axis = new AndroidSensorJoystickAxis(
                     getInputManager(),          // InputManager (InputManager)
                     getInputManager(),          // InputManager (InputManager)
                     this,                       // parent Joystick (Joystick)
                     this,                       // parent Joystick (Joystick)
                     axisNum,                    // Axis Index (int)
                     axisNum,                    // Axis Index (int)
@@ -654,7 +654,7 @@ public class AndroidSensorJoyInput implements SensorEventListener {
 
 
     }
     }
 
 
-    public class AndroidJoystickAxis extends DefaultJoystickAxis implements SensorJoystickAxis {
+    public class AndroidSensorJoystickAxis extends DefaultJoystickAxis implements SensorJoystickAxis {
         float zeroRawValue = 0f;
         float zeroRawValue = 0f;
         float curRawValue = 0f;
         float curRawValue = 0f;
         float lastRawValue = 0f;
         float lastRawValue = 0f;
@@ -662,7 +662,7 @@ public class AndroidSensorJoyInput implements SensorEventListener {
         float maxRawValue = FastMath.HALF_PI;
         float maxRawValue = FastMath.HALF_PI;
         boolean enabled = true;
         boolean enabled = true;
 
 
-        public AndroidJoystickAxis(InputManager inputManager, Joystick parent,
+        public AndroidSensorJoystickAxis(InputManager inputManager, Joystick parent,
                            int axisIndex, String name, String logicalId,
                            int axisIndex, String name, String logicalId,
                            boolean isAnalog, boolean isRelative, float deadZone,
                            boolean isAnalog, boolean isRelative, float deadZone,
                            float maxRawValue) {
                            float maxRawValue) {

+ 0 - 257
jme3-android/src/main/java/com/jme3/input/android/AndroidTouchHandler.java

@@ -1,257 +0,0 @@
-/*
- * Copyright (c) 2009-2012 jMonkeyEngine
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- *
- * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
- *   may be used to endorse or promote products derived from this software
- *   without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
- * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-package com.jme3.input.android;
-
-import android.view.MotionEvent;
-import android.view.View;
-import com.jme3.input.event.InputEvent;
-import com.jme3.input.event.MouseButtonEvent;
-import com.jme3.input.event.MouseMotionEvent;
-import com.jme3.input.event.TouchEvent;
-import static com.jme3.input.event.TouchEvent.Type.DOWN;
-import static com.jme3.input.event.TouchEvent.Type.MOVE;
-import static com.jme3.input.event.TouchEvent.Type.UP;
-import com.jme3.math.Vector2f;
-import java.util.HashMap;
-import java.util.logging.Logger;
-
-/**
- * AndroidTouchHandler is the base class that receives touch inputs from the 
- * Android system and creates the TouchEvents for jME.  This class is designed
- * to handle the base touch events for Android rev 9 (Android 2.3).  This is
- * extended by other classes to add features that were introducted after
- * Android rev 9.
- * 
- * @author iwgeric
- */
-public class AndroidTouchHandler implements View.OnTouchListener {
-    private static final Logger logger = Logger.getLogger(AndroidTouchHandler.class.getName());
-    
-    final private HashMap<Integer, Vector2f> lastPositions = new HashMap<Integer, Vector2f>();
-
-    protected int numPointers = 0;
-    
-    protected AndroidInputHandler androidInput;
-    protected AndroidGestureHandler gestureHandler;
-
-    public AndroidTouchHandler(AndroidInputHandler androidInput, AndroidGestureHandler gestureHandler) {
-        this.androidInput = androidInput;
-        this.gestureHandler = gestureHandler;
-    }
-
-    public void initialize() {
-    }
-    
-    public void destroy() {
-        setView(null);
-    }
-    
-    public void setView(View view) {
-        if (view != null) {
-            view.setOnTouchListener(this);
-        } else {
-            androidInput.getView().setOnTouchListener(null);
-        }
-    }
-    
-    protected int getPointerIndex(MotionEvent event) {
-        return (event.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK)
-                >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
-    }
-    
-    protected int getPointerId(MotionEvent event) {
-        return event.getPointerId(getPointerIndex(event));
-    }
-    
-    protected int getAction(MotionEvent event) {
-        return event.getAction() & MotionEvent.ACTION_MASK;
-    }
-    
-    /**
-     * onTouch gets called from android thread on touch events
-     */
-    public boolean onTouch(View view, MotionEvent event) {
-        if (!androidInput.isInitialized() || view != androidInput.getView()) {
-            return false;
-        }
-        
-        boolean bWasHandled = false;
-        TouchEvent touch = null;
-        //    System.out.println("native : " + event.getAction());
-        int action = getAction(event);
-        int pointerIndex = getPointerIndex(event);
-        int pointerId = getPointerId(event);
-        Vector2f lastPos = lastPositions.get(pointerId);
-        float jmeX;
-        float jmeY;
-        
-        numPointers = event.getPointerCount();
-
-        // final int historySize = event.getHistorySize();
-        //final int pointerCount = event.getPointerCount();
-        switch (getAction(event)) {
-            case MotionEvent.ACTION_POINTER_DOWN:
-            case MotionEvent.ACTION_DOWN:
-                jmeX = androidInput.getJmeX(event.getX(pointerIndex));
-                jmeY = androidInput.invertY(androidInput.getJmeY(event.getY(pointerIndex)));
-                touch = androidInput.getFreeTouchEvent();
-                touch.set(TouchEvent.Type.DOWN, jmeX, jmeY, 0, 0);
-                touch.setPointerId(pointerId);
-                touch.setTime(event.getEventTime());
-                touch.setPressure(event.getPressure(pointerIndex));
-
-                lastPos = new Vector2f(jmeX, jmeY);
-                lastPositions.put(pointerId, lastPos);
-
-                processEvent(touch);
-
-                bWasHandled = true;
-                break;
-            case MotionEvent.ACTION_POINTER_UP:
-            case MotionEvent.ACTION_CANCEL:
-            case MotionEvent.ACTION_UP:
-                jmeX = androidInput.getJmeX(event.getX(pointerIndex));
-                jmeY = androidInput.invertY(androidInput.getJmeY(event.getY(pointerIndex)));
-                touch = androidInput.getFreeTouchEvent();
-                touch.set(TouchEvent.Type.UP, jmeX, jmeY, 0, 0);
-                touch.setPointerId(pointerId);
-                touch.setTime(event.getEventTime());
-                touch.setPressure(event.getPressure(pointerIndex));
-                lastPositions.remove(pointerId);
-
-                processEvent(touch);
-
-                bWasHandled = true;
-                break;
-            case MotionEvent.ACTION_MOVE:
-                // Convert all pointers into events
-                for (int p = 0; p < event.getPointerCount(); p++) {
-                    jmeX = androidInput.getJmeX(event.getX(p));
-                    jmeY = androidInput.invertY(androidInput.getJmeY(event.getY(p)));
-                    lastPos = lastPositions.get(event.getPointerId(p));
-                    if (lastPos == null) {
-                        lastPos = new Vector2f(jmeX, jmeY);
-                        lastPositions.put(event.getPointerId(p), lastPos);
-                    }
-
-                    float dX = jmeX - lastPos.x;
-                    float dY = jmeY - lastPos.y;
-                    if (dX != 0 || dY != 0) {
-                        touch = androidInput.getFreeTouchEvent();
-                        touch.set(TouchEvent.Type.MOVE, jmeX, jmeY, dX, dY);
-                        touch.setPointerId(event.getPointerId(p));
-                        touch.setTime(event.getEventTime());
-                        touch.setPressure(event.getPressure(p));
-                        lastPos.set(jmeX, jmeY);
-
-                        processEvent(touch);
-
-                        bWasHandled = true;
-                    }
-                }
-                break;
-            case MotionEvent.ACTION_OUTSIDE:
-                break;
-
-        }
-
-        // Try to detect gestures
-        if (gestureHandler != null) {
-            gestureHandler.detectGesture(event);
-        }
-
-        return bWasHandled;
-    }
-
-    protected void processEvent(TouchEvent event) {
-        // Add the touch event
-        androidInput.addEvent(event);
-        // MouseEvents do not support multi-touch, so only evaluate 1 finger pointer events
-        if (androidInput.isSimulateMouse() && numPointers == 1) {
-            InputEvent mouseEvent = generateMouseEvent(event);
-            if (mouseEvent != null) {
-                // Add the mouse event
-                androidInput.addEvent(mouseEvent);
-            }
-        }
-        
-    }
-
-    // TODO: Ring Buffer for mouse events?
-    protected InputEvent generateMouseEvent(TouchEvent event) {
-        InputEvent inputEvent = null;
-        int newX;
-        int newY;
-        int newDX;
-        int newDY;
-
-        if (androidInput.isMouseEventsInvertX()) {
-            newX = (int) (androidInput.invertX(event.getX()));
-            newDX = (int)event.getDeltaX() * -1;
-        } else {
-            newX = (int) event.getX();
-            newDX = (int)event.getDeltaX();
-        }
-
-        if (androidInput.isMouseEventsInvertY()) {
-            newY = (int) (androidInput.invertY(event.getY()));
-            newDY = (int)event.getDeltaY() * -1;
-        } else {
-            newY = (int) event.getY();
-            newDY = (int)event.getDeltaY();
-        }
-
-        switch (event.getType()) {
-            case DOWN:
-                // Handle mouse down event
-                inputEvent = new MouseButtonEvent(0, true, newX, newY);
-                inputEvent.setTime(event.getTime());
-                break;
-
-            case UP:
-                // Handle mouse up event
-                inputEvent = new MouseButtonEvent(0, false, newX, newY);
-                inputEvent.setTime(event.getTime());
-                break;
-
-            case HOVER_MOVE:
-            case MOVE:
-                inputEvent = new MouseMotionEvent(newX, newY, newDX, newDY, (int)event.getScaleSpan(), (int)event.getDeltaScaleSpan());
-                inputEvent.setTime(event.getTime());
-                break;
-        }
-
-        return inputEvent;
-    }
-    
-}

+ 475 - 0
jme3-android/src/main/java/com/jme3/input/android/AndroidTouchInput.java

@@ -0,0 +1,475 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ *   may be used to endorse or promote products derived from this software
+ *   without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.jme3.input.android;
+
+import android.view.GestureDetector;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.ScaleGestureDetector;
+import com.jme3.input.RawInputListener;
+import com.jme3.input.TouchInput;
+import com.jme3.input.event.InputEvent;
+import com.jme3.input.event.KeyInputEvent;
+import com.jme3.input.event.MouseButtonEvent;
+import com.jme3.input.event.MouseMotionEvent;
+import com.jme3.input.event.TouchEvent;
+import static com.jme3.input.event.TouchEvent.Type.DOWN;
+import static com.jme3.input.event.TouchEvent.Type.MOVE;
+import static com.jme3.input.event.TouchEvent.Type.UP;
+import com.jme3.math.Vector2f;
+import com.jme3.system.AppSettings;
+import java.util.HashMap;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * AndroidTouchInput is the base class that receives touch inputs from the
+ * Android system and creates the TouchEvents for jME.  This class is designed
+ * to handle the base touch events for Android rev 9 (Android 2.3).  This is
+ * extended by other classes to add features that were introducted after
+ * Android rev 9.
+ *
+ * @author iwgeric
+ */
+public class AndroidTouchInput implements TouchInput {
+    private static final Logger logger = Logger.getLogger(AndroidTouchInput.class.getName());
+
+    private boolean mouseEventsEnabled = true;
+    private boolean mouseEventsInvertX = false;
+    private boolean mouseEventsInvertY = false;
+    private boolean keyboardEventsEnabled = false;
+    private boolean dontSendHistory = false;
+
+    protected int numPointers = 0;
+    final private HashMap<Integer, Vector2f> lastPositions = new HashMap<Integer, Vector2f>();
+    final private ConcurrentLinkedQueue<InputEvent> inputEventQueue = new ConcurrentLinkedQueue<InputEvent>();
+    private final static int MAX_TOUCH_EVENTS = 1024;
+    private final TouchEventPool touchEventPool = new TouchEventPool(MAX_TOUCH_EVENTS);
+    private float scaleX = 1f;
+    private float scaleY = 1f;
+
+    private boolean initialized = false;
+    private RawInputListener listener = null;
+
+    private GestureDetector gestureDetector;
+    private ScaleGestureDetector scaleDetector;
+
+    protected AndroidInputHandler androidInput;
+
+    public AndroidTouchInput(AndroidInputHandler androidInput) {
+        this.androidInput = androidInput;
+    }
+
+    public GestureDetector getGestureDetector() {
+        return gestureDetector;
+    }
+
+    public void setGestureDetector(GestureDetector gestureDetector) {
+        this.gestureDetector = gestureDetector;
+    }
+
+    public ScaleGestureDetector getScaleDetector() {
+        return scaleDetector;
+    }
+
+    public void setScaleDetector(ScaleGestureDetector scaleDetector) {
+        this.scaleDetector = scaleDetector;
+    }
+
+    public float invertX(float origX) {
+        return getJmeX(androidInput.getView().getWidth()) - origX;
+    }
+
+    public float invertY(float origY) {
+        return getJmeY(androidInput.getView().getHeight()) - origY;
+    }
+
+    public float getJmeX(float origX) {
+        return origX * scaleX;
+    }
+
+    public float getJmeY(float origY) {
+        return origY * scaleY;
+    }
+
+    public void loadSettings(AppSettings settings) {
+        keyboardEventsEnabled = settings.isEmulateKeyboard();
+        mouseEventsEnabled = settings.isEmulateMouse();
+        mouseEventsInvertX = settings.isEmulateMouseFlipX();
+        mouseEventsInvertY = settings.isEmulateMouseFlipY();
+
+        // view width and height are 0 until the view is displayed on the screen
+        if (androidInput.getView().getWidth() != 0 && androidInput.getView().getHeight() != 0) {
+            scaleX = (float)settings.getWidth() / (float)androidInput.getView().getWidth();
+            scaleY = (float)settings.getHeight() / (float)androidInput.getView().getHeight();
+        }
+        logger.log(Level.FINE, "Setting input scaling, scaleX: {0}, scaleY: {1}",
+                new Object[]{scaleX, scaleY});
+
+
+    }
+
+
+    protected int getPointerIndex(MotionEvent event) {
+        return (event.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK)
+                >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
+    }
+
+    protected int getPointerId(MotionEvent event) {
+        return event.getPointerId(getPointerIndex(event));
+    }
+
+    protected int getAction(MotionEvent event) {
+        return event.getAction() & MotionEvent.ACTION_MASK;
+    }
+
+    public boolean onTouch(MotionEvent event) {
+        if (!isInitialized()) {
+            return false;
+        }
+
+        boolean bWasHandled = false;
+        TouchEvent touch = null;
+        //    System.out.println("native : " + event.getAction());
+        int action = getAction(event);
+        int pointerIndex = getPointerIndex(event);
+        int pointerId = getPointerId(event);
+        Vector2f lastPos = lastPositions.get(pointerId);
+        float jmeX;
+        float jmeY;
+
+        numPointers = event.getPointerCount();
+
+        // final int historySize = event.getHistorySize();
+        //final int pointerCount = event.getPointerCount();
+        switch (getAction(event)) {
+            case MotionEvent.ACTION_POINTER_DOWN:
+            case MotionEvent.ACTION_DOWN:
+                jmeX = getJmeX(event.getX(pointerIndex));
+                jmeY = invertY(getJmeY(event.getY(pointerIndex)));
+                touch = getFreeTouchEvent();
+                touch.set(TouchEvent.Type.DOWN, jmeX, jmeY, 0, 0);
+                touch.setPointerId(pointerId);
+                touch.setTime(event.getEventTime());
+                touch.setPressure(event.getPressure(pointerIndex));
+
+                lastPos = new Vector2f(jmeX, jmeY);
+                lastPositions.put(pointerId, lastPos);
+
+                addEvent(touch);
+                addEvent(generateMouseEvent(touch));
+
+                bWasHandled = true;
+                break;
+            case MotionEvent.ACTION_POINTER_UP:
+            case MotionEvent.ACTION_CANCEL:
+            case MotionEvent.ACTION_UP:
+                jmeX = getJmeX(event.getX(pointerIndex));
+                jmeY = invertY(getJmeY(event.getY(pointerIndex)));
+                touch = getFreeTouchEvent();
+                touch.set(TouchEvent.Type.UP, jmeX, jmeY, 0, 0);
+                touch.setPointerId(pointerId);
+                touch.setTime(event.getEventTime());
+                touch.setPressure(event.getPressure(pointerIndex));
+                lastPositions.remove(pointerId);
+
+                addEvent(touch);
+                addEvent(generateMouseEvent(touch));
+
+                bWasHandled = true;
+                break;
+            case MotionEvent.ACTION_MOVE:
+                // Convert all pointers into events
+                for (int p = 0; p < event.getPointerCount(); p++) {
+                    jmeX = getJmeX(event.getX(p));
+                    jmeY = invertY(getJmeY(event.getY(p)));
+                    lastPos = lastPositions.get(event.getPointerId(p));
+                    if (lastPos == null) {
+                        lastPos = new Vector2f(jmeX, jmeY);
+                        lastPositions.put(event.getPointerId(p), lastPos);
+                    }
+
+                    float dX = jmeX - lastPos.x;
+                    float dY = jmeY - lastPos.y;
+                    if (dX != 0 || dY != 0) {
+                        touch = getFreeTouchEvent();
+                        touch.set(TouchEvent.Type.MOVE, jmeX, jmeY, dX, dY);
+                        touch.setPointerId(event.getPointerId(p));
+                        touch.setTime(event.getEventTime());
+                        touch.setPressure(event.getPressure(p));
+                        lastPos.set(jmeX, jmeY);
+
+                        addEvent(touch);
+                        addEvent(generateMouseEvent(touch));
+
+                        bWasHandled = true;
+                    }
+                }
+                break;
+            case MotionEvent.ACTION_OUTSIDE:
+                break;
+
+        }
+
+        // Try to detect gestures
+        if (gestureDetector != null) {
+            gestureDetector.onTouchEvent(event);
+        }
+        if (scaleDetector != null) {
+            scaleDetector.onTouchEvent(event);
+        }
+
+        return bWasHandled;
+    }
+
+    // TODO: Ring Buffer for mouse events?
+    public InputEvent generateMouseEvent(TouchEvent event) {
+        InputEvent inputEvent = null;
+        int newX;
+        int newY;
+        int newDX;
+        int newDY;
+
+        // MouseEvents do not support multi-touch, so only evaluate 1 finger pointer events
+        if (!isSimulateMouse() || numPointers > 1) {
+            return null;
+        }
+
+
+        if (isMouseEventsInvertX()) {
+            newX = (int) (invertX(event.getX()));
+            newDX = (int)event.getDeltaX() * -1;
+        } else {
+            newX = (int) event.getX();
+            newDX = (int)event.getDeltaX();
+        }
+
+        if (isMouseEventsInvertY()) {
+            newY = (int) (invertY(event.getY()));
+            newDY = (int)event.getDeltaY() * -1;
+        } else {
+            newY = (int) event.getY();
+            newDY = (int)event.getDeltaY();
+        }
+
+        switch (event.getType()) {
+            case DOWN:
+                // Handle mouse down event
+                inputEvent = new MouseButtonEvent(0, true, newX, newY);
+                inputEvent.setTime(event.getTime());
+                break;
+
+            case UP:
+                // Handle mouse up event
+                inputEvent = new MouseButtonEvent(0, false, newX, newY);
+                inputEvent.setTime(event.getTime());
+                break;
+
+            case HOVER_MOVE:
+            case MOVE:
+                inputEvent = new MouseMotionEvent(newX, newY, newDX, newDY, (int)event.getScaleSpan(), (int)event.getDeltaScaleSpan());
+                inputEvent.setTime(event.getTime());
+                break;
+        }
+
+        return inputEvent;
+    }
+
+
+    public boolean onKey(KeyEvent event) {
+        if (!isInitialized()) {
+            return false;
+        }
+
+        TouchEvent evt;
+        // TODO: get touch event from pool
+        if (event.getAction() == KeyEvent.ACTION_DOWN) {
+            evt = new TouchEvent();
+            evt.set(TouchEvent.Type.KEY_DOWN);
+            evt.setKeyCode(event.getKeyCode());
+            evt.setCharacters(event.getCharacters());
+            evt.setTime(event.getEventTime());
+
+            // Send the event
+            addEvent(evt);
+
+        } else if (event.getAction() == KeyEvent.ACTION_UP) {
+            evt = new TouchEvent();
+            evt.set(TouchEvent.Type.KEY_UP);
+            evt.setKeyCode(event.getKeyCode());
+            evt.setCharacters(event.getCharacters());
+            evt.setTime(event.getEventTime());
+
+            // Send the event
+            addEvent(evt);
+
+        }
+
+        if (isSimulateKeyboard()) {
+            KeyInputEvent kie;
+            char unicodeChar = (char)event.getUnicodeChar();
+            int jmeKeyCode = AndroidKeyMapping.getJmeKey(event.getKeyCode());
+
+            boolean pressed = event.getAction() == KeyEvent.ACTION_DOWN;
+            boolean repeating = pressed && event.getRepeatCount() > 0;
+
+            kie = new KeyInputEvent(jmeKeyCode, unicodeChar, pressed, repeating);
+            kie.setTime(event.getEventTime());
+            addEvent(kie);
+//            logger.log(Level.FINE, "onKey keyCode: {0}, jmeKeyCode: {1}, pressed: {2}, repeating: {3}",
+//                    new Object[]{event.getKeyCode(), jmeKeyCode, pressed, repeating});
+//            logger.log(Level.FINE, "creating KeyInputEvent: {0}", kie);
+        }
+
+        // consume all keys ourself except Volume Up/Down and Menu
+        //   Don't do Menu so that typical Android Menus can be created and used
+        //   by the user in MainActivity
+        if ((event.getKeyCode() == KeyEvent.KEYCODE_VOLUME_UP) ||
+                (event.getKeyCode() == KeyEvent.KEYCODE_VOLUME_DOWN) ||
+                (event.getKeyCode() == KeyEvent.KEYCODE_MENU)) {
+            return false;
+        } else {
+            return true;
+        }
+
+   }
+
+
+
+
+        // -----------------------------------------
+    // JME3 Input interface
+    @Override
+    public void initialize() {
+        touchEventPool.initialize();
+
+        initialized = true;
+    }
+
+    @Override
+    public void destroy() {
+        initialized = false;
+
+        touchEventPool.destroy();
+
+    }
+
+    @Override
+    public boolean isInitialized() {
+        return initialized;
+    }
+
+    @Override
+    public void setInputListener(RawInputListener listener) {
+        this.listener = listener;
+    }
+
+    @Override
+    public long getInputTimeNanos() {
+        return System.nanoTime();
+    }
+
+    @Override
+    public void update() {
+        if (listener != null) {
+            InputEvent inputEvent;
+
+            while ((inputEvent = inputEventQueue.poll()) != null) {
+                if (inputEvent instanceof TouchEvent) {
+                    listener.onTouchEvent((TouchEvent)inputEvent);
+                } else if (inputEvent instanceof MouseButtonEvent) {
+                    listener.onMouseButtonEvent((MouseButtonEvent)inputEvent);
+                } else if (inputEvent instanceof MouseMotionEvent) {
+                    listener.onMouseMotionEvent((MouseMotionEvent)inputEvent);
+                } else if (inputEvent instanceof KeyInputEvent) {
+                    listener.onKeyEvent((KeyInputEvent)inputEvent);
+                }
+            }
+        }
+    }
+
+    // -----------------------------------------
+
+    public TouchEvent getFreeTouchEvent() {
+            return touchEventPool.getNextFreeEvent();
+    }
+
+    public void addEvent(InputEvent event) {
+        if (event == null) {
+            return;
+        }
+
+        logger.log(Level.INFO, "event: {0}", event);
+
+        inputEventQueue.add(event);
+        if (event instanceof TouchEvent) {
+            touchEventPool.storeEvent((TouchEvent)event);
+        }
+
+    }
+
+    @Override
+    public void setSimulateMouse(boolean simulate) {
+        this.mouseEventsEnabled = simulate;
+    }
+
+    @Override
+    public boolean isSimulateMouse() {
+        return mouseEventsEnabled;
+    }
+
+    public boolean isMouseEventsInvertX() {
+        return mouseEventsInvertX;
+    }
+
+    public boolean isMouseEventsInvertY() {
+        return mouseEventsInvertY;
+    }
+
+    @Override
+    public void setSimulateKeyboard(boolean simulate) {
+        this.keyboardEventsEnabled = simulate;
+    }
+
+    @Override
+    public boolean isSimulateKeyboard() {
+        return keyboardEventsEnabled;
+    }
+
+    @Override
+    public void setOmitHistoricEvents(boolean dontSendHistory) {
+        this.dontSendHistory = dontSendHistory;
+    }
+
+}

+ 30 - 46
jme3-android/src/main/java/com/jme3/input/android/AndroidTouchHandler14.java → jme3-android/src/main/java/com/jme3/input/android/AndroidTouchInput14.java

@@ -33,7 +33,6 @@
 package com.jme3.input.android;
 package com.jme3.input.android;
 
 
 import android.view.MotionEvent;
 import android.view.MotionEvent;
-import android.view.View;
 import com.jme3.input.event.TouchEvent;
 import com.jme3.input.event.TouchEvent;
 import com.jme3.math.Vector2f;
 import com.jme3.math.Vector2f;
 import java.util.HashMap;
 import java.util.HashMap;
@@ -41,36 +40,20 @@ import java.util.logging.Level;
 import java.util.logging.Logger;
 import java.util.logging.Logger;
 
 
 /**
 /**
- * AndroidTouchHandler14 is an extension of AndroidTouchHander that adds the
- * Android touch event functionality between Android rev 9 (Android 2.3) and 
- * Android rev 14 (Android 4.0).
- * 
+ * AndroidTouchHandler14 extends AndroidTouchHandler to process the onHover
+ * events added in Android rev 14 (Android 4.0).
+ *
  * @author iwgeric
  * @author iwgeric
  */
  */
-public class AndroidTouchHandler14 extends AndroidTouchHandler implements 
-        View.OnHoverListener {
-    private static final Logger logger = Logger.getLogger(AndroidTouchHandler14.class.getName());
+public class AndroidTouchInput14 extends AndroidTouchInput {
+    private static final Logger logger = Logger.getLogger(AndroidTouchInput14.class.getName());
     final private HashMap<Integer, Vector2f> lastHoverPositions = new HashMap<Integer, Vector2f>();
     final private HashMap<Integer, Vector2f> lastHoverPositions = new HashMap<Integer, Vector2f>();
-    
-    public AndroidTouchHandler14(AndroidInputHandler androidInput, AndroidGestureHandler gestureHandler) {
-        super(androidInput, gestureHandler);
-    }
 
 
-    @Override
-    public void setView(View view) {
-        if (view != null) {
-            view.setOnHoverListener(this);
-        } else {
-            androidInput.getView().setOnHoverListener(null);
-        }
-        super.setView(view);
+    public AndroidTouchInput14(AndroidInputHandler androidInput) {
+        super(androidInput);
     }
     }
-    
-    public boolean onHover(View view, MotionEvent event) {
-        if (view == null || view != androidInput.getView()) {
-            return false;
-        }
-        
+
+    public boolean onHover(MotionEvent event) {
         boolean consumed = false;
         boolean consumed = false;
         int action = getAction(event);
         int action = getAction(event);
         int pointerId = getPointerId(event);
         int pointerId = getPointerId(event);
@@ -78,34 +61,34 @@ public class AndroidTouchHandler14 extends AndroidTouchHandler implements
         Vector2f lastPos = lastHoverPositions.get(pointerId);
         Vector2f lastPos = lastHoverPositions.get(pointerId);
         float jmeX;
         float jmeX;
         float jmeY;
         float jmeY;
-        
+
         numPointers = event.getPointerCount();
         numPointers = event.getPointerCount();
-        
-        logger.log(Level.INFO, "onHover pointerId: {0}, action: {1}, x: {2}, y: {3}, numPointers: {4}", 
-                new Object[]{pointerId, action, event.getX(), event.getY(), event.getPointerCount()});
+
+//        logger.log(Level.INFO, "onHover pointerId: {0}, action: {1}, x: {2}, y: {3}, numPointers: {4}",
+//                new Object[]{pointerId, action, event.getX(), event.getY(), event.getPointerCount()});
 
 
         TouchEvent touchEvent;
         TouchEvent touchEvent;
         switch (action) {
         switch (action) {
             case MotionEvent.ACTION_HOVER_ENTER:
             case MotionEvent.ACTION_HOVER_ENTER:
-                jmeX = androidInput.getJmeX(event.getX(pointerIndex));
-                jmeY = androidInput.invertY(androidInput.getJmeY(event.getY(pointerIndex)));
-                touchEvent = androidInput.getFreeTouchEvent();
+                jmeX = getJmeX(event.getX(pointerIndex));
+                jmeY = invertY(getJmeY(event.getY(pointerIndex)));
+                touchEvent = getFreeTouchEvent();
                 touchEvent.set(TouchEvent.Type.HOVER_START, jmeX, jmeY, 0, 0);
                 touchEvent.set(TouchEvent.Type.HOVER_START, jmeX, jmeY, 0, 0);
                 touchEvent.setPointerId(pointerId);
                 touchEvent.setPointerId(pointerId);
                 touchEvent.setTime(event.getEventTime());
                 touchEvent.setTime(event.getEventTime());
                 touchEvent.setPressure(event.getPressure(pointerIndex));
                 touchEvent.setPressure(event.getPressure(pointerIndex));
-                
+
                 lastPos = new Vector2f(jmeX, jmeY);
                 lastPos = new Vector2f(jmeX, jmeY);
                 lastHoverPositions.put(pointerId, lastPos);
                 lastHoverPositions.put(pointerId, lastPos);
-                
-                processEvent(touchEvent);
+
+                addEvent(touchEvent);
                 consumed = true;
                 consumed = true;
                 break;
                 break;
             case MotionEvent.ACTION_HOVER_MOVE:
             case MotionEvent.ACTION_HOVER_MOVE:
                 // Convert all pointers into events
                 // Convert all pointers into events
                 for (int p = 0; p < event.getPointerCount(); p++) {
                 for (int p = 0; p < event.getPointerCount(); p++) {
-                    jmeX = androidInput.getJmeX(event.getX(p));
-                    jmeY = androidInput.invertY(androidInput.getJmeY(event.getY(p)));
+                    jmeX = getJmeX(event.getX(p));
+                    jmeY = invertY(getJmeY(event.getY(p)));
                     lastPos = lastHoverPositions.get(event.getPointerId(p));
                     lastPos = lastHoverPositions.get(event.getPointerId(p));
                     if (lastPos == null) {
                     if (lastPos == null) {
                         lastPos = new Vector2f(jmeX, jmeY);
                         lastPos = new Vector2f(jmeX, jmeY);
@@ -115,38 +98,39 @@ public class AndroidTouchHandler14 extends AndroidTouchHandler implements
                     float dX = jmeX - lastPos.x;
                     float dX = jmeX - lastPos.x;
                     float dY = jmeY - lastPos.y;
                     float dY = jmeY - lastPos.y;
                     if (dX != 0 || dY != 0) {
                     if (dX != 0 || dY != 0) {
-                        touchEvent = androidInput.getFreeTouchEvent();
+                        touchEvent = getFreeTouchEvent();
                         touchEvent.set(TouchEvent.Type.HOVER_MOVE, jmeX, jmeY, dX, dY);
                         touchEvent.set(TouchEvent.Type.HOVER_MOVE, jmeX, jmeY, dX, dY);
                         touchEvent.setPointerId(event.getPointerId(p));
                         touchEvent.setPointerId(event.getPointerId(p));
                         touchEvent.setTime(event.getEventTime());
                         touchEvent.setTime(event.getEventTime());
                         touchEvent.setPressure(event.getPressure(p));
                         touchEvent.setPressure(event.getPressure(p));
                         lastPos.set(jmeX, jmeY);
                         lastPos.set(jmeX, jmeY);
 
 
-                        processEvent(touchEvent);
+                        addEvent(touchEvent);
 
 
                     }
                     }
                 }
                 }
                 consumed = true;
                 consumed = true;
                 break;
                 break;
             case MotionEvent.ACTION_HOVER_EXIT:
             case MotionEvent.ACTION_HOVER_EXIT:
-                jmeX = androidInput.getJmeX(event.getX(pointerIndex));
-                jmeY = androidInput.invertY(androidInput.getJmeY(event.getY(pointerIndex)));
-                touchEvent = androidInput.getFreeTouchEvent();
+                jmeX = getJmeX(event.getX(pointerIndex));
+                jmeY = invertY(getJmeY(event.getY(pointerIndex)));
+                touchEvent = getFreeTouchEvent();
                 touchEvent.set(TouchEvent.Type.HOVER_END, jmeX, jmeY, 0, 0);
                 touchEvent.set(TouchEvent.Type.HOVER_END, jmeX, jmeY, 0, 0);
                 touchEvent.setPointerId(pointerId);
                 touchEvent.setPointerId(pointerId);
                 touchEvent.setTime(event.getEventTime());
                 touchEvent.setTime(event.getEventTime());
                 touchEvent.setPressure(event.getPressure(pointerIndex));
                 touchEvent.setPressure(event.getPressure(pointerIndex));
                 lastHoverPositions.remove(pointerId);
                 lastHoverPositions.remove(pointerId);
 
 
-                processEvent(touchEvent);
+                addEvent(touchEvent);
                 consumed = true;
                 consumed = true;
                 break;
                 break;
             default:
             default:
                 consumed = false;
                 consumed = false;
                 break;
                 break;
         }
         }
-        
+
         return consumed;
         return consumed;
+
     }
     }
-    
+
 }
 }

+ 9 - 14
jme3-android/src/main/java/com/jme3/system/android/OGLESContext.java

@@ -47,7 +47,7 @@ import android.widget.EditText;
 import android.widget.FrameLayout;
 import android.widget.FrameLayout;
 import com.jme3.input.*;
 import com.jme3.input.*;
 import com.jme3.input.android.AndroidInputHandler;
 import com.jme3.input.android.AndroidInputHandler;
-import com.jme3.input.android.AndroidJoyInputHandler;
+import com.jme3.input.android.AndroidInputHandler14;
 import com.jme3.input.controls.SoftTextDialogInputListener;
 import com.jme3.input.controls.SoftTextDialogInputListener;
 import com.jme3.input.dummy.DummyKeyInput;
 import com.jme3.input.dummy.DummyKeyInput;
 import com.jme3.input.dummy.DummyMouseInput;
 import com.jme3.input.dummy.DummyMouseInput;
@@ -75,7 +75,6 @@ public class OGLESContext implements JmeContext, GLSurfaceView.Renderer, SoftTex
     protected SystemListener listener;
     protected SystemListener listener;
     protected boolean autoFlush = true;
     protected boolean autoFlush = true;
     protected AndroidInputHandler androidInput;
     protected AndroidInputHandler androidInput;
-    protected AndroidJoyInputHandler androidJoyInput = null;
     protected long minFrameDuration = 0;                   // No FPS cap
     protected long minFrameDuration = 0;                   // No FPS cap
     protected long lastUpdateTime = 0;
     protected long lastUpdateTime = 0;
 
 
@@ -111,18 +110,17 @@ public class OGLESContext implements JmeContext, GLSurfaceView.Renderer, SoftTex
 
 
         // Start to set up the view
         // Start to set up the view
         GLSurfaceView view = new GLSurfaceView(context);
         GLSurfaceView view = new GLSurfaceView(context);
+        logger.log(Level.INFO, "Android Build Version: {0}", Build.VERSION.SDK_INT);
         if (androidInput == null) {
         if (androidInput == null) {
-            androidInput = new AndroidInputHandler();
+            if (Build.VERSION.SDK_INT >= 14) {
+                androidInput = new AndroidInputHandler14();
+            } else if (Build.VERSION.SDK_INT >= 9){
+                androidInput = new AndroidInputHandler();
+            }
         }
         }
         androidInput.setView(view);
         androidInput.setView(view);
         androidInput.loadSettings(settings);
         androidInput.loadSettings(settings);
 
 
-        if (androidJoyInput == null) {
-            androidJoyInput = new AndroidJoyInputHandler();
-        }
-        androidJoyInput.setView(view);
-        androidJoyInput.loadSettings(settings);
-
         // setEGLContextClientVersion must be set before calling setRenderer
         // setEGLContextClientVersion must be set before calling setRenderer
         // this means it cannot be set in AndroidConfigChooser (too late)
         // this means it cannot be set in AndroidConfigChooser (too late)
         view.setEGLContextClientVersion(2);
         view.setEGLContextClientVersion(2);
@@ -235,9 +233,6 @@ public class OGLESContext implements JmeContext, GLSurfaceView.Renderer, SoftTex
         if (androidInput != null) {
         if (androidInput != null) {
             androidInput.loadSettings(settings);
             androidInput.loadSettings(settings);
         }
         }
-        if (androidJoyInput != null) {
-            androidJoyInput.loadSettings(settings);
-        }
 
 
         if (settings.getFrameRate() > 0) {
         if (settings.getFrameRate() > 0) {
             minFrameDuration = (long)(1000d / (double)settings.getFrameRate()); // ms
             minFrameDuration = (long)(1000d / (double)settings.getFrameRate()); // ms
@@ -274,12 +269,12 @@ public class OGLESContext implements JmeContext, GLSurfaceView.Renderer, SoftTex
 
 
     @Override
     @Override
     public JoyInput getJoyInput() {
     public JoyInput getJoyInput() {
-        return androidJoyInput;
+        return androidInput.getJoyInput();
     }
     }
 
 
     @Override
     @Override
     public TouchInput getTouchInput() {
     public TouchInput getTouchInput() {
-        return androidInput;
+        return androidInput.getTouchInput();
     }
     }
 
 
     @Override
     @Override