diff --git a/jme3-android/src/main/java/com/jme3/input/android/AndroidGestureHandler.java b/jme3-android/src/main/java/com/jme3/input/android/AndroidGestureProcessor.java similarity index 51% rename from jme3-android/src/main/java/com/jme3/input/android/AndroidGestureHandler.java rename to jme3-android/src/main/java/com/jme3/input/android/AndroidGestureProcessor.java index d233836a5..2c0367946 100644 --- a/jme3-android/src/main/java/com/jme3/input/android/AndroidGestureHandler.java +++ b/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.MotionEvent; 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 java.util.logging.Level; import java.util.logging.Logger; /** * 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 * added by Android after rev 9. - * + * * @author iwgeric */ -public class AndroidGestureHandler implements - GestureDetector.OnGestureListener, +public class AndroidGestureProcessor implements + GestureDetector.OnGestureListener, GestureDetector.OnDoubleTapListener, 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 gestureDownY = -1f; float scaleStartX = -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 */ - + + @Override public boolean onDown(MotionEvent event) { // start of all GestureListeners. Not really a gesture by itself // so we don't create an event. // However, reset the scaleInProgress here since this is the beginning // 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; } + @Override public boolean onSingleTapUp(MotionEvent event) { // Up of single tap. May be followed by a double tap later. // 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; } + @Override 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.setPointerId(getPointerId(event)); + touchEvent.setPointerId(touchInput.getPointerId(event)); touchEvent.setTime(event.getEventTime()); touchEvent.setPressure(event.getPressure()); - processEvent(touchEvent); + touchInput.addEvent(touchEvent); } + @Override 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.setPointerId(getPointerId(event)); + touchEvent.setPointerId(touchInput.getPointerId(event)); touchEvent.setTime(event.getEventTime()); touchEvent.setPressure(event.getPressure()); - processEvent(touchEvent); + touchInput.addEvent(touchEvent); } + @Override public boolean onScroll(MotionEvent startEvent, MotionEvent endEvent, float distX, float distY) { // 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. // 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. - // 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 // 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.setPressure(endEvent.getPressure()); - processEvent(touchEvent); + touchInput.addEvent(touchEvent); } return true; } + @Override 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 returns the velocity of the finger movement in pixels/sec. // 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. - -// 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.setPointerId(getPointerId(endEvent)); + touchEvent.setPointerId(touchInput.getPointerId(endEvent)); touchEvent.setTime(endEvent.getEventTime()); touchEvent.setPressure(endEvent.getPressure()); - processEvent(touchEvent); + touchInput.addEvent(touchEvent); return true; } /* Events from onDoubleTapListener */ - + + @Override public boolean onSingleTapConfirmed(MotionEvent event) { // 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.setPointerId(getPointerId(event)); + touchEvent.setPointerId(touchInput.getPointerId(event)); touchEvent.setTime(event.getEventTime()); touchEvent.setPressure(event.getPressure()); - processEvent(touchEvent); + touchInput.addEvent(touchEvent); return true; } + @Override public boolean onDoubleTap(MotionEvent event) { //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 -// 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.setPointerId(getPointerId(event)); + touchEvent.setPointerId(touchInput.getPointerId(event)); touchEvent.setTime(event.getEventTime()); touchEvent.setPressure(event.getPressure()); - processEvent(touchEvent); + touchInput.addEvent(touchEvent); return true; } + @Override public boolean onDoubleTapEvent(MotionEvent event) { //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 -// 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; } /* Events from ScaleGestureDetector */ - + + @Override public boolean onScaleBegin(ScaleGestureDetector scaleGestureDetector) { // 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 // 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 - logger.log(Level.INFO, "onScaleBegin"); +// logger.log(Level.INFO, "onScaleBegin"); scaleStartX = gestureDownX; scaleStartY = gestureDownY; - TouchEvent touchEvent = androidInput.getFreeTouchEvent(); + TouchEvent touchEvent = touchInput.getFreeTouchEvent(); touchEvent.set(TouchEvent.Type.SCALE_START, scaleStartX, scaleStartY, 0f, 0f); touchEvent.setPointerId(0); touchEvent.setTime(scaleGestureDetector.getEventTime()); touchEvent.setScaleSpan(scaleGestureDetector.getCurrentSpan()); touchEvent.setDeltaScaleSpan(0f); touchEvent.setScaleFactor(scaleGestureDetector.getScaleFactor()); - touchEvent.setScaleSpanInProgress(scaleDetector.isInProgress()); - processEvent(touchEvent); - + touchEvent.setScaleSpanInProgress(touchInput.getScaleDetector().isInProgress()); + touchInput.addEvent(touchEvent); + return true; } + @Override public boolean onScale(ScaleGestureDetector scaleGestureDetector) { // return true or all gestures for this event will be accumulated - logger.log(Level.INFO, "onScale"); +// logger.log(Level.INFO, "onScale"); scaleStartX = gestureDownX; scaleStartY = gestureDownY; - TouchEvent touchEvent = androidInput.getFreeTouchEvent(); + TouchEvent touchEvent = touchInput.getFreeTouchEvent(); touchEvent.set(TouchEvent.Type.SCALE_MOVE, scaleStartX, scaleStartY, 0f, 0f); touchEvent.setPointerId(0); touchEvent.setTime(scaleGestureDetector.getEventTime()); touchEvent.setScaleSpan(scaleGestureDetector.getCurrentSpan()); touchEvent.setDeltaScaleSpan(scaleGestureDetector.getCurrentSpan() - scaleGestureDetector.getPreviousSpan()); touchEvent.setScaleFactor(scaleGestureDetector.getScaleFactor()); - touchEvent.setScaleSpanInProgress(scaleDetector.isInProgress()); - processEvent(touchEvent); + touchEvent.setScaleSpanInProgress(touchInput.getScaleDetector().isInProgress()); + touchInput.addEvent(touchEvent); return true; } + @Override public void onScaleEnd(ScaleGestureDetector scaleGestureDetector) { - logger.log(Level.INFO, "onScaleEnd"); +// logger.log(Level.INFO, "onScaleEnd"); scaleStartX = gestureDownX; scaleStartY = gestureDownY; - TouchEvent touchEvent = androidInput.getFreeTouchEvent(); + TouchEvent touchEvent = touchInput.getFreeTouchEvent(); touchEvent.set(TouchEvent.Type.SCALE_END, scaleStartX, scaleStartY, 0f, 0f); touchEvent.setPointerId(0); touchEvent.setTime(scaleGestureDetector.getEventTime()); touchEvent.setScaleSpan(scaleGestureDetector.getCurrentSpan()); touchEvent.setDeltaScaleSpan(scaleGestureDetector.getCurrentSpan() - scaleGestureDetector.getPreviousSpan()); touchEvent.setScaleFactor(scaleGestureDetector.getScaleFactor()); - touchEvent.setScaleSpanInProgress(scaleDetector.isInProgress()); - processEvent(touchEvent); + touchEvent.setScaleSpanInProgress(touchInput.getScaleDetector().isInProgress()); + touchInput.addEvent(touchEvent); } } diff --git a/jme3-android/src/main/java/com/jme3/input/android/AndroidInput.java b/jme3-android/src/main/java/com/jme3/input/android/AndroidInput.java deleted file mode 100644 index 02fef6b0f..000000000 --- a/jme3-android/src/main/java/com/jme3/input/android/AndroidInput.java +++ /dev/null @@ -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; - -/** - * AndroidInput 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 eventQueue = new RingBuffer(MAX_EVENTS); - final private RingBuffer eventPoolUnConsumed = new RingBuffer(MAX_EVENTS); - final private RingBuffer eventPool = new RingBuffer(MAX_EVENTS); - final private HashMap lastPositions = new HashMap(); - // 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; - } - -} diff --git a/jme3-android/src/main/java/com/jme3/input/android/AndroidInputHandler.java b/jme3-android/src/main/java/com/jme3/input/android/AndroidInputHandler.java index 202907316..9f4729c66 100644 --- a/jme3-android/src/main/java/com/jme3/input/android/AndroidInputHandler.java +++ b/jme3-android/src/main/java/com/jme3/input/android/AndroidInputHandler.java @@ -33,231 +33,206 @@ package com.jme3.input.android; 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 com.jme3.input.RawInputListener; +import com.jme3.input.JoyInput; 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 java.util.concurrent.ConcurrentLinkedQueue; import java.util.logging.Level; import java.util.logging.Logger; /** * AndroidInput 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 InputManager. + * 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.
+ * This class is to be extended when new functionality is released in Android. * * @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 inputEventQueue = new ConcurrentLinkedQueue(); - 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() { - 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) { - 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; - } - 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) { - 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. + *
+ * 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.
+ * + * 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 - 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; } } diff --git a/jme3-android/src/main/java/com/jme3/input/android/AndroidInputHandler14.java b/jme3-android/src/main/java/com/jme3/input/android/AndroidInputHandler14.java new file mode 100644 index 000000000..114bb98fd --- /dev/null +++ b/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; + +/** + * AndroidInputHandler14 extends AndroidInputHandler to + * add the onHover and onGenericMotion events that where added in Android rev 14 (Android 4.0).
+ * 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; + + } + +} diff --git a/jme3-android/src/main/java/com/jme3/input/android/AndroidJoyInputHandler.java b/jme3-android/src/main/java/com/jme3/input/android/AndroidJoyInput.java similarity index 84% rename from jme3-android/src/main/java/com/jme3/input/android/AndroidJoyInputHandler.java rename to jme3-android/src/main/java/com/jme3/input/android/AndroidJoyInput.java index 2c3a1d74e..e31504520 100644 --- a/jme3-android/src/main/java/com/jme3/input/android/AndroidJoyInputHandler.java +++ b/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.opengl.GLSurfaceView; -import android.os.Build; import android.os.Vibrator; -import android.view.View; import com.jme3.input.InputManager; import com.jme3.input.JoyInput; import com.jme3.input.Joystick; @@ -79,15 +77,15 @@ import java.util.logging.Logger; * * @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 joystickList = new ArrayList(); + protected AndroidInputHandler inputHandler; + protected List joystickList = new ArrayList(); // private boolean dontSendHistory = false; // Internal - private GLSurfaceView view; private boolean initialized = false; private RawInputListener listener = null; private ConcurrentLinkedQueue eventQueue = new ConcurrentLinkedQueue(); @@ -96,34 +94,29 @@ public class AndroidJoyInputHandler implements JoyInput { private boolean vibratorActive = false; 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); } 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) { sensorJoyInput.setView(view); } - this.view = (GLSurfaceView)view; - - } - - public View getView() { - return view; } public void loadSettings(AppSettings settings) { -// sensorEventsEnabled = settings.useSensors(); + } public void addEvent(InputEvent event) { @@ -155,20 +148,8 @@ public class AndroidJoyInputHandler implements JoyInput { } - - - - @Override 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; } @@ -211,8 +192,8 @@ public class AndroidJoyInputHandler implements JoyInput { }; 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) { vibrator.vibrate(rumblePattern, rumbleRepeatFrom); @@ -226,9 +207,8 @@ public class AndroidJoyInputHandler implements JoyInput { @Override public Joystick[] loadJoysticks(InputManager inputManager) { + logger.log(Level.INFO, "loading joysticks for {0}", this.getClass().getName()); joystickList.add(sensorJoyInput.loadJoystick(joystickList.size(), inputManager)); - - return joystickList.toArray( new Joystick[joystickList.size()] ); } @@ -252,6 +232,4 @@ public class AndroidJoyInputHandler implements JoyInput { } - - } diff --git a/jme3-android/src/main/java/com/jme3/input/android/AndroidJoyInput14.java b/jme3-android/src/main/java/com/jme3/input/android/AndroidJoyInput14.java new file mode 100644 index 000000000..00478aea1 --- /dev/null +++ b/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; + +/** + * AndroidJoyInput14 extends AndroidJoyInput + * to include support for physical joysticks/gamepads.
+ * + * @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); + } + +} diff --git a/jme3-android/src/main/java/com/jme3/input/android/AndroidJoystickJoyInput14.java b/jme3-android/src/main/java/com/jme3/input/android/AndroidJoystickJoyInput14.java new file mode 100644 index 000000000..370db4f10 --- /dev/null +++ b/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 joystickIndex = new HashMap(); + + 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 loadJoysticks(int joyId, InputManager inputManager) { + logger.log(Level.INFO, "loading Joystick devices"); + ArrayList joysticks = new ArrayList(); + 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 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 axisIndex = new HashMap(); + private Map buttonIndex = new HashMap(); + + 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 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(); + } + } +} diff --git a/jme3-android/src/main/java/com/jme3/input/android/AndroidKeyHandler.java b/jme3-android/src/main/java/com/jme3/input/android/AndroidKeyHandler.java deleted file mode 100644 index 997974c31..000000000 --- a/jme3-android/src/main/java/com/jme3/input/android/AndroidKeyHandler.java +++ /dev/null @@ -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; - } - - } - -} diff --git a/jme3-android/src/main/java/com/jme3/input/android/AndroidKeyMapping.java b/jme3-android/src/main/java/com/jme3/input/android/AndroidKeyMapping.java index e99d8e9fc..32d1e0008 100644 --- a/jme3-android/src/main/java/com/jme3/input/android/AndroidKeyMapping.java +++ b/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 - * 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 */ public class AndroidKeyMapping { private static final Logger logger = Logger.getLogger(AndroidKeyMapping.class.getName()); - + private static final int[] ANDROID_TO_JME = { 0x0, // unknown 0x0, // key code soft left @@ -141,9 +142,13 @@ public class AndroidKeyMapping { 0x0,//media fastforward 0x0,//mute }; - + 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]; + } } - + } diff --git a/jme3-android/src/main/java/com/jme3/input/android/AndroidSensorJoyInput.java b/jme3-android/src/main/java/com/jme3/input/android/AndroidSensorJoyInput.java index 823aa3d9d..cdd7e6494 100644 --- a/jme3-android/src/main/java/com/jme3/input/android/AndroidSensorJoyInput.java +++ b/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 { private final static Logger logger = Logger.getLogger(AndroidSensorJoyInput.class.getName()); - private AndroidJoyInputHandler joyHandler; + private AndroidJoyInput joyInput; private SensorManager sensorManager = null; private WindowManager windowManager = null; private IntMap sensors = new IntMap(); private int lastRotation = 0; 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; float[] lastValues; final Object valuesLock = new Object(); - ArrayList axes = new ArrayList(); + ArrayList axes = new ArrayList(); boolean enabled = false; boolean haveData = false; @@ -306,7 +306,7 @@ public class AndroidSensorJoyInput implements SensorEventListener { */ private boolean updateOrientation() { SensorData sensorData; - AndroidJoystickAxis axis; + AndroidSensorJoystickAxis axis; final float[] curInclinationMat = new float[16]; final float[] curRotationMat = new float[16]; final float[] rotatedRotationMat = new float[16]; @@ -374,7 +374,7 @@ public class AndroidSensorJoyInput implements SensorEventListener { sensorData.haveData = true; } else { 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) { SensorData sensorData; - AndroidJoystickAxis axis; + AndroidSensorJoystickAxis axis; - AndroidJoystick joystick = new AndroidJoystick(inputManager, - joyHandler, + AndroidSensorJoystick joystick = new AndroidSensorJoystick(inputManager, + joyInput, joyId, "AndroidSensorsJoystick"); @@ -522,15 +522,15 @@ public class AndroidSensorJoyInput implements SensorEventListener { if (!loaded) { 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(); SensorData sensorData = sensors.get(sensorType); 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) { @@ -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 lastPositions = new HashMap(); - - 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; - } - -} diff --git a/jme3-android/src/main/java/com/jme3/input/android/AndroidTouchInput.java b/jme3-android/src/main/java/com/jme3/input/android/AndroidTouchInput.java new file mode 100644 index 000000000..bddc5fab3 --- /dev/null +++ b/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 lastPositions = new HashMap(); + final private ConcurrentLinkedQueue inputEventQueue = new ConcurrentLinkedQueue(); + 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; + } + +} diff --git a/jme3-android/src/main/java/com/jme3/input/android/AndroidTouchHandler14.java b/jme3-android/src/main/java/com/jme3/input/android/AndroidTouchInput14.java similarity index 67% rename from jme3-android/src/main/java/com/jme3/input/android/AndroidTouchHandler14.java rename to jme3-android/src/main/java/com/jme3/input/android/AndroidTouchInput14.java index 1a785a5e9..617a4b719 100644 --- a/jme3-android/src/main/java/com/jme3/input/android/AndroidTouchHandler14.java +++ b/jme3-android/src/main/java/com/jme3/input/android/AndroidTouchInput14.java @@ -33,7 +33,6 @@ package com.jme3.input.android; import android.view.MotionEvent; -import android.view.View; import com.jme3.input.event.TouchEvent; import com.jme3.math.Vector2f; import java.util.HashMap; @@ -41,36 +40,20 @@ import java.util.logging.Level; 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 */ -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 lastHoverPositions = new HashMap(); - - 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; int action = getAction(event); int pointerId = getPointerId(event); @@ -78,34 +61,34 @@ public class AndroidTouchHandler14 extends AndroidTouchHandler implements Vector2f lastPos = lastHoverPositions.get(pointerId); float jmeX; float jmeY; - + 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; switch (action) { 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.setPointerId(pointerId); touchEvent.setTime(event.getEventTime()); touchEvent.setPressure(event.getPressure(pointerIndex)); - + lastPos = new Vector2f(jmeX, jmeY); lastHoverPositions.put(pointerId, lastPos); - - processEvent(touchEvent); + + addEvent(touchEvent); consumed = true; break; case MotionEvent.ACTION_HOVER_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))); + jmeX = getJmeX(event.getX(p)); + jmeY = invertY(getJmeY(event.getY(p))); lastPos = lastHoverPositions.get(event.getPointerId(p)); if (lastPos == null) { lastPos = new Vector2f(jmeX, jmeY); @@ -115,38 +98,39 @@ public class AndroidTouchHandler14 extends AndroidTouchHandler implements float dX = jmeX - lastPos.x; float dY = jmeY - lastPos.y; if (dX != 0 || dY != 0) { - touchEvent = androidInput.getFreeTouchEvent(); + touchEvent = getFreeTouchEvent(); touchEvent.set(TouchEvent.Type.HOVER_MOVE, jmeX, jmeY, dX, dY); touchEvent.setPointerId(event.getPointerId(p)); touchEvent.setTime(event.getEventTime()); touchEvent.setPressure(event.getPressure(p)); lastPos.set(jmeX, jmeY); - processEvent(touchEvent); + addEvent(touchEvent); } } consumed = true; break; 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.setPointerId(pointerId); touchEvent.setTime(event.getEventTime()); touchEvent.setPressure(event.getPressure(pointerIndex)); lastHoverPositions.remove(pointerId); - processEvent(touchEvent); + addEvent(touchEvent); consumed = true; break; default: consumed = false; break; } - + return consumed; + } - + } diff --git a/jme3-android/src/main/java/com/jme3/system/android/OGLESContext.java b/jme3-android/src/main/java/com/jme3/system/android/OGLESContext.java index 5ef866188..9472bff0b 100644 --- a/jme3-android/src/main/java/com/jme3/system/android/OGLESContext.java +++ b/jme3-android/src/main/java/com/jme3/system/android/OGLESContext.java @@ -47,7 +47,7 @@ import android.widget.EditText; import android.widget.FrameLayout; import com.jme3.input.*; 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.dummy.DummyKeyInput; import com.jme3.input.dummy.DummyMouseInput; @@ -75,7 +75,6 @@ public class OGLESContext implements JmeContext, GLSurfaceView.Renderer, SoftTex protected SystemListener listener; protected boolean autoFlush = true; protected AndroidInputHandler androidInput; - protected AndroidJoyInputHandler androidJoyInput = null; protected long minFrameDuration = 0; // No FPS cap protected long lastUpdateTime = 0; @@ -111,18 +110,17 @@ public class OGLESContext implements JmeContext, GLSurfaceView.Renderer, SoftTex // Start to set up the view GLSurfaceView view = new GLSurfaceView(context); + logger.log(Level.INFO, "Android Build Version: {0}", Build.VERSION.SDK_INT); 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.loadSettings(settings); - if (androidJoyInput == null) { - androidJoyInput = new AndroidJoyInputHandler(); - } - androidJoyInput.setView(view); - androidJoyInput.loadSettings(settings); - // setEGLContextClientVersion must be set before calling setRenderer // this means it cannot be set in AndroidConfigChooser (too late) view.setEGLContextClientVersion(2); @@ -235,9 +233,6 @@ public class OGLESContext implements JmeContext, GLSurfaceView.Renderer, SoftTex if (androidInput != null) { androidInput.loadSettings(settings); } - if (androidJoyInput != null) { - androidJoyInput.loadSettings(settings); - } if (settings.getFrameRate() > 0) { minFrameDuration = (long)(1000d / (double)settings.getFrameRate()); // ms @@ -274,12 +269,12 @@ public class OGLESContext implements JmeContext, GLSurfaceView.Renderer, SoftTex @Override public JoyInput getJoyInput() { - return androidJoyInput; + return androidInput.getJoyInput(); } @Override public TouchInput getTouchInput() { - return androidInput; + return androidInput.getTouchInput(); } @Override