commit
a5b4df68d8
@ -1,686 +0,0 @@ |
|||||||
package com.jme3.input.android; |
|
||||||
|
|
||||||
import android.view.*; |
|
||||||
import com.jme3.input.KeyInput; |
|
||||||
import com.jme3.input.RawInputListener; |
|
||||||
import com.jme3.input.TouchInput; |
|
||||||
import com.jme3.input.event.MouseButtonEvent; |
|
||||||
import com.jme3.input.event.MouseMotionEvent; |
|
||||||
import com.jme3.input.event.TouchEvent; |
|
||||||
import com.jme3.input.event.TouchEvent.Type; |
|
||||||
import com.jme3.math.Vector2f; |
|
||||||
import com.jme3.system.AppSettings; |
|
||||||
import com.jme3.util.RingBuffer; |
|
||||||
import java.util.HashMap; |
|
||||||
import java.util.logging.Logger; |
|
||||||
|
|
||||||
/** |
|
||||||
* <code>AndroidInput</code> is one of the main components that connect jme with android. Is derived from GLSurfaceView and handles all Inputs |
|
||||||
* @author larynx |
|
||||||
* |
|
||||||
*/ |
|
||||||
public class AndroidInput implements |
|
||||||
TouchInput, |
|
||||||
View.OnTouchListener, |
|
||||||
View.OnKeyListener, |
|
||||||
GestureDetector.OnGestureListener, |
|
||||||
GestureDetector.OnDoubleTapListener, |
|
||||||
ScaleGestureDetector.OnScaleGestureListener { |
|
||||||
|
|
||||||
final private static int MAX_EVENTS = 1024; |
|
||||||
// Custom settings
|
|
||||||
public boolean mouseEventsEnabled = true; |
|
||||||
public boolean mouseEventsInvertX = false; |
|
||||||
public boolean mouseEventsInvertY = false; |
|
||||||
public boolean keyboardEventsEnabled = false; |
|
||||||
public boolean dontSendHistory = false; |
|
||||||
// Used to transfer events from android thread to GLThread
|
|
||||||
final private RingBuffer<TouchEvent> eventQueue = new RingBuffer<TouchEvent>(MAX_EVENTS); |
|
||||||
final private RingBuffer<TouchEvent> eventPoolUnConsumed = new RingBuffer<TouchEvent>(MAX_EVENTS); |
|
||||||
final private RingBuffer<TouchEvent> eventPool = new RingBuffer<TouchEvent>(MAX_EVENTS); |
|
||||||
final private HashMap<Integer, Vector2f> lastPositions = new HashMap<Integer, Vector2f>(); |
|
||||||
// Internal
|
|
||||||
private View view; |
|
||||||
private ScaleGestureDetector scaledetector; |
|
||||||
private boolean scaleInProgress = false; |
|
||||||
private GestureDetector detector; |
|
||||||
private int lastX; |
|
||||||
private int lastY; |
|
||||||
private final static Logger logger = Logger.getLogger(AndroidInput.class.getName()); |
|
||||||
private boolean isInitialized = false; |
|
||||||
private RawInputListener listener = null; |
|
||||||
private static final int[] ANDROID_TO_JME = { |
|
||||||
0x0, // unknown
|
|
||||||
0x0, // key code soft left
|
|
||||||
0x0, // key code soft right
|
|
||||||
KeyInput.KEY_HOME, |
|
||||||
KeyInput.KEY_ESCAPE, // key back
|
|
||||||
0x0, // key call
|
|
||||||
0x0, // key endcall
|
|
||||||
KeyInput.KEY_0, |
|
||||||
KeyInput.KEY_1, |
|
||||||
KeyInput.KEY_2, |
|
||||||
KeyInput.KEY_3, |
|
||||||
KeyInput.KEY_4, |
|
||||||
KeyInput.KEY_5, |
|
||||||
KeyInput.KEY_6, |
|
||||||
KeyInput.KEY_7, |
|
||||||
KeyInput.KEY_8, |
|
||||||
KeyInput.KEY_9, |
|
||||||
KeyInput.KEY_MULTIPLY, |
|
||||||
0x0, // key pound
|
|
||||||
KeyInput.KEY_UP, |
|
||||||
KeyInput.KEY_DOWN, |
|
||||||
KeyInput.KEY_LEFT, |
|
||||||
KeyInput.KEY_RIGHT, |
|
||||||
KeyInput.KEY_RETURN, // dpad center
|
|
||||||
0x0, // volume up
|
|
||||||
0x0, // volume down
|
|
||||||
KeyInput.KEY_POWER, // power (?)
|
|
||||||
0x0, // camera
|
|
||||||
0x0, // clear
|
|
||||||
KeyInput.KEY_A, |
|
||||||
KeyInput.KEY_B, |
|
||||||
KeyInput.KEY_C, |
|
||||||
KeyInput.KEY_D, |
|
||||||
KeyInput.KEY_E, |
|
||||||
KeyInput.KEY_F, |
|
||||||
KeyInput.KEY_G, |
|
||||||
KeyInput.KEY_H, |
|
||||||
KeyInput.KEY_I, |
|
||||||
KeyInput.KEY_J, |
|
||||||
KeyInput.KEY_K, |
|
||||||
KeyInput.KEY_L, |
|
||||||
KeyInput.KEY_M, |
|
||||||
KeyInput.KEY_N, |
|
||||||
KeyInput.KEY_O, |
|
||||||
KeyInput.KEY_P, |
|
||||||
KeyInput.KEY_Q, |
|
||||||
KeyInput.KEY_R, |
|
||||||
KeyInput.KEY_S, |
|
||||||
KeyInput.KEY_T, |
|
||||||
KeyInput.KEY_U, |
|
||||||
KeyInput.KEY_V, |
|
||||||
KeyInput.KEY_W, |
|
||||||
KeyInput.KEY_X, |
|
||||||
KeyInput.KEY_Y, |
|
||||||
KeyInput.KEY_Z, |
|
||||||
KeyInput.KEY_COMMA, |
|
||||||
KeyInput.KEY_PERIOD, |
|
||||||
KeyInput.KEY_LMENU, |
|
||||||
KeyInput.KEY_RMENU, |
|
||||||
KeyInput.KEY_LSHIFT, |
|
||||||
KeyInput.KEY_RSHIFT, |
|
||||||
// 0x0, // fn
|
|
||||||
// 0x0, // cap (?)
|
|
||||||
|
|
||||||
KeyInput.KEY_TAB, |
|
||||||
KeyInput.KEY_SPACE, |
|
||||||
0x0, // sym (?) symbol
|
|
||||||
0x0, // explorer
|
|
||||||
0x0, // envelope
|
|
||||||
KeyInput.KEY_RETURN, // newline/enter
|
|
||||||
KeyInput.KEY_DELETE, |
|
||||||
KeyInput.KEY_GRAVE, |
|
||||||
KeyInput.KEY_MINUS, |
|
||||||
KeyInput.KEY_EQUALS, |
|
||||||
KeyInput.KEY_LBRACKET, |
|
||||||
KeyInput.KEY_RBRACKET, |
|
||||||
KeyInput.KEY_BACKSLASH, |
|
||||||
KeyInput.KEY_SEMICOLON, |
|
||||||
KeyInput.KEY_APOSTROPHE, |
|
||||||
KeyInput.KEY_SLASH, |
|
||||||
KeyInput.KEY_AT, // at (@)
|
|
||||||
KeyInput.KEY_NUMLOCK, //0x0, // num
|
|
||||||
0x0, //headset hook
|
|
||||||
0x0, //focus
|
|
||||||
KeyInput.KEY_ADD, |
|
||||||
KeyInput.KEY_LMETA, //menu
|
|
||||||
0x0,//notification
|
|
||||||
0x0,//search
|
|
||||||
0x0,//media play/pause
|
|
||||||
0x0,//media stop
|
|
||||||
0x0,//media next
|
|
||||||
0x0,//media previous
|
|
||||||
0x0,//media rewind
|
|
||||||
0x0,//media fastforward
|
|
||||||
0x0,//mute
|
|
||||||
}; |
|
||||||
|
|
||||||
public AndroidInput() { |
|
||||||
} |
|
||||||
|
|
||||||
public void setView(View view) { |
|
||||||
this.view = view; |
|
||||||
if (view != null) { |
|
||||||
detector = new GestureDetector(null, this, null, false); |
|
||||||
scaledetector = new ScaleGestureDetector(view.getContext(), this); |
|
||||||
view.setOnTouchListener(this); |
|
||||||
view.setOnKeyListener(this); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
private TouchEvent getNextFreeTouchEvent() { |
|
||||||
return getNextFreeTouchEvent(false); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Fetches a touch event from the reuse pool |
|
||||||
* @param wait if true waits for a reusable event to get available/released |
|
||||||
* by an other thread, if false returns a new one if needed. |
|
||||||
* |
|
||||||
* @return a usable TouchEvent |
|
||||||
*/ |
|
||||||
private TouchEvent getNextFreeTouchEvent(boolean wait) { |
|
||||||
TouchEvent evt = null; |
|
||||||
synchronized (eventPoolUnConsumed) { |
|
||||||
int size = eventPoolUnConsumed.size(); |
|
||||||
while (size > 0) { |
|
||||||
evt = eventPoolUnConsumed.pop(); |
|
||||||
if (!evt.isConsumed()) { |
|
||||||
eventPoolUnConsumed.push(evt); |
|
||||||
evt = null; |
|
||||||
} else { |
|
||||||
break; |
|
||||||
} |
|
||||||
size--; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
if (evt == null) { |
|
||||||
if (eventPool.isEmpty() && wait) { |
|
||||||
logger.warning("eventPool buffer underrun"); |
|
||||||
boolean isEmpty; |
|
||||||
do { |
|
||||||
synchronized (eventPool) { |
|
||||||
isEmpty = eventPool.isEmpty(); |
|
||||||
} |
|
||||||
try { |
|
||||||
Thread.sleep(50); |
|
||||||
} catch (InterruptedException e) { |
|
||||||
} |
|
||||||
} while (isEmpty); |
|
||||||
synchronized (eventPool) { |
|
||||||
evt = eventPool.pop(); |
|
||||||
} |
|
||||||
} else if (eventPool.isEmpty()) { |
|
||||||
evt = new TouchEvent(); |
|
||||||
logger.warning("eventPool buffer underrun"); |
|
||||||
} else { |
|
||||||
synchronized (eventPool) { |
|
||||||
evt = eventPool.pop(); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
return evt; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* onTouch gets called from android thread on touchpad events |
|
||||||
*/ |
|
||||||
public boolean onTouch(View view, MotionEvent event) { |
|
||||||
if (view != this.view) { |
|
||||||
return false; |
|
||||||
} |
|
||||||
boolean bWasHandled = false; |
|
||||||
TouchEvent touch; |
|
||||||
// System.out.println("native : " + event.getAction());
|
|
||||||
int action = event.getAction() & MotionEvent.ACTION_MASK; |
|
||||||
int pointerIndex = (event.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) |
|
||||||
>> MotionEvent.ACTION_POINTER_INDEX_SHIFT; |
|
||||||
int pointerId = event.getPointerId(pointerIndex); |
|
||||||
Vector2f lastPos = lastPositions.get(pointerId); |
|
||||||
|
|
||||||
// final int historySize = event.getHistorySize();
|
|
||||||
//final int pointerCount = event.getPointerCount();
|
|
||||||
switch (action) { |
|
||||||
case MotionEvent.ACTION_POINTER_DOWN: |
|
||||||
case MotionEvent.ACTION_DOWN: |
|
||||||
touch = getNextFreeTouchEvent(); |
|
||||||
touch.set(Type.DOWN, event.getX(pointerIndex), view.getHeight() - event.getY(pointerIndex), 0, 0); |
|
||||||
touch.setPointerId(pointerId); |
|
||||||
touch.setTime(event.getEventTime()); |
|
||||||
touch.setPressure(event.getPressure(pointerIndex)); |
|
||||||
processEvent(touch); |
|
||||||
|
|
||||||
lastPos = new Vector2f(event.getX(pointerIndex), view.getHeight() - event.getY(pointerIndex)); |
|
||||||
lastPositions.put(pointerId, lastPos); |
|
||||||
|
|
||||||
bWasHandled = true; |
|
||||||
break; |
|
||||||
case MotionEvent.ACTION_POINTER_UP: |
|
||||||
case MotionEvent.ACTION_CANCEL: |
|
||||||
case MotionEvent.ACTION_UP: |
|
||||||
touch = getNextFreeTouchEvent(); |
|
||||||
touch.set(Type.UP, event.getX(pointerIndex), view.getHeight() - event.getY(pointerIndex), 0, 0); |
|
||||||
touch.setPointerId(pointerId); |
|
||||||
touch.setTime(event.getEventTime()); |
|
||||||
touch.setPressure(event.getPressure(pointerIndex)); |
|
||||||
processEvent(touch); |
|
||||||
lastPositions.remove(pointerId); |
|
||||||
|
|
||||||
bWasHandled = true; |
|
||||||
break; |
|
||||||
case MotionEvent.ACTION_MOVE: |
|
||||||
// Convert all pointers into events
|
|
||||||
for (int p = 0; p < event.getPointerCount(); p++) { |
|
||||||
lastPos = lastPositions.get(event.getPointerId(p)); |
|
||||||
if (lastPos == null) { |
|
||||||
lastPos = new Vector2f(event.getX(p), view.getHeight() - event.getY(p)); |
|
||||||
lastPositions.put(event.getPointerId(p), lastPos); |
|
||||||
} |
|
||||||
|
|
||||||
float dX = event.getX(p) - lastPos.x; |
|
||||||
float dY = view.getHeight() - event.getY(p) - lastPos.y; |
|
||||||
if (dX != 0 || dY != 0) { |
|
||||||
touch = getNextFreeTouchEvent(); |
|
||||||
touch.set(Type.MOVE, event.getX(p), view.getHeight() - event.getY(p), dX, dY); |
|
||||||
touch.setPointerId(event.getPointerId(p)); |
|
||||||
touch.setTime(event.getEventTime()); |
|
||||||
touch.setPressure(event.getPressure(p)); |
|
||||||
touch.setScaleSpanInProgress(scaleInProgress); |
|
||||||
processEvent(touch); |
|
||||||
lastPos.set(event.getX(p), view.getHeight() - event.getY(p)); |
|
||||||
} |
|
||||||
} |
|
||||||
bWasHandled = true; |
|
||||||
break; |
|
||||||
case MotionEvent.ACTION_OUTSIDE: |
|
||||||
break; |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
// Try to detect gestures
|
|
||||||
this.detector.onTouchEvent(event); |
|
||||||
this.scaledetector.onTouchEvent(event); |
|
||||||
|
|
||||||
return bWasHandled; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* onKey gets called from android thread on key events |
|
||||||
*/ |
|
||||||
public boolean onKey(View view, int keyCode, KeyEvent event) { |
|
||||||
if (view != this.view) { |
|
||||||
return false; |
|
||||||
} |
|
||||||
|
|
||||||
if (event.getAction() == KeyEvent.ACTION_DOWN) { |
|
||||||
TouchEvent evt; |
|
||||||
evt = getNextFreeTouchEvent(); |
|
||||||
evt.set(TouchEvent.Type.KEY_DOWN); |
|
||||||
evt.setKeyCode(keyCode); |
|
||||||
evt.setCharacters(event.getCharacters()); |
|
||||||
evt.setTime(event.getEventTime()); |
|
||||||
|
|
||||||
// Send the event
|
|
||||||
processEvent(evt); |
|
||||||
|
|
||||||
// Handle all keys ourself except Volume Up/Down
|
|
||||||
if ((keyCode == KeyEvent.KEYCODE_VOLUME_UP) || (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN)) { |
|
||||||
return false; |
|
||||||
} else { |
|
||||||
return true; |
|
||||||
} |
|
||||||
} else if (event.getAction() == KeyEvent.ACTION_UP) { |
|
||||||
TouchEvent evt; |
|
||||||
evt = getNextFreeTouchEvent(); |
|
||||||
evt.set(TouchEvent.Type.KEY_UP); |
|
||||||
evt.setKeyCode(keyCode); |
|
||||||
evt.setCharacters(event.getCharacters()); |
|
||||||
evt.setTime(event.getEventTime()); |
|
||||||
|
|
||||||
// Send the event
|
|
||||||
processEvent(evt); |
|
||||||
|
|
||||||
// Handle all keys ourself except Volume Up/Down
|
|
||||||
if ((keyCode == KeyEvent.KEYCODE_VOLUME_UP) || (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN)) { |
|
||||||
return false; |
|
||||||
} else { |
|
||||||
return true; |
|
||||||
} |
|
||||||
} else { |
|
||||||
return false; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public void loadSettings(AppSettings settings) { |
|
||||||
mouseEventsEnabled = settings.isEmulateMouse(); |
|
||||||
mouseEventsInvertX = settings.isEmulateMouseFlipX(); |
|
||||||
mouseEventsInvertY = settings.isEmulateMouseFlipY(); |
|
||||||
} |
|
||||||
|
|
||||||
// -----------------------------------------
|
|
||||||
// JME3 Input interface
|
|
||||||
@Override |
|
||||||
public void initialize() { |
|
||||||
TouchEvent item; |
|
||||||
for (int i = 0; i < MAX_EVENTS; i++) { |
|
||||||
item = new TouchEvent(); |
|
||||||
eventPool.push(item); |
|
||||||
} |
|
||||||
isInitialized = true; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void destroy() { |
|
||||||
isInitialized = false; |
|
||||||
|
|
||||||
// Clean up queues
|
|
||||||
while (!eventPool.isEmpty()) { |
|
||||||
eventPool.pop(); |
|
||||||
} |
|
||||||
while (!eventQueue.isEmpty()) { |
|
||||||
eventQueue.pop(); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
this.view = null; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public boolean isInitialized() { |
|
||||||
return isInitialized; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void setInputListener(RawInputListener listener) { |
|
||||||
this.listener = listener; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public long getInputTimeNanos() { |
|
||||||
return System.nanoTime(); |
|
||||||
} |
|
||||||
// -----------------------------------------
|
|
||||||
|
|
||||||
private void processEvent(TouchEvent event) { |
|
||||||
synchronized (eventQueue) { |
|
||||||
//Discarding events when the ring buffer is full to avoid buffer overflow.
|
|
||||||
if(eventQueue.size()< MAX_EVENTS){ |
|
||||||
eventQueue.push(event); |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
// --------------- INSIDE GLThread ---------------
|
|
||||||
@Override |
|
||||||
public void update() { |
|
||||||
generateEvents(); |
|
||||||
} |
|
||||||
|
|
||||||
private void generateEvents() { |
|
||||||
if (listener != null) { |
|
||||||
TouchEvent event; |
|
||||||
MouseButtonEvent btn; |
|
||||||
MouseMotionEvent mot; |
|
||||||
int newX; |
|
||||||
int newY; |
|
||||||
|
|
||||||
while (!eventQueue.isEmpty()) { |
|
||||||
synchronized (eventQueue) { |
|
||||||
event = eventQueue.pop(); |
|
||||||
} |
|
||||||
if (event != null) { |
|
||||||
listener.onTouchEvent(event); |
|
||||||
|
|
||||||
if (mouseEventsEnabled) { |
|
||||||
if (mouseEventsInvertX) { |
|
||||||
newX = view.getWidth() - (int) event.getX(); |
|
||||||
} else { |
|
||||||
newX = (int) event.getX(); |
|
||||||
} |
|
||||||
|
|
||||||
if (mouseEventsInvertY) { |
|
||||||
newY = view.getHeight() - (int) event.getY(); |
|
||||||
} else { |
|
||||||
newY = (int) event.getY(); |
|
||||||
} |
|
||||||
|
|
||||||
switch (event.getType()) { |
|
||||||
case DOWN: |
|
||||||
// Handle mouse down event
|
|
||||||
btn = new MouseButtonEvent(0, true, newX, newY); |
|
||||||
btn.setTime(event.getTime()); |
|
||||||
listener.onMouseButtonEvent(btn); |
|
||||||
// Store current pos
|
|
||||||
lastX = -1; |
|
||||||
lastY = -1; |
|
||||||
break; |
|
||||||
|
|
||||||
case UP: |
|
||||||
// Handle mouse up event
|
|
||||||
btn = new MouseButtonEvent(0, false, newX, newY); |
|
||||||
btn.setTime(event.getTime()); |
|
||||||
listener.onMouseButtonEvent(btn); |
|
||||||
// Store current pos
|
|
||||||
lastX = -1; |
|
||||||
lastY = -1; |
|
||||||
break; |
|
||||||
|
|
||||||
case SCALE_MOVE: |
|
||||||
if (lastX != -1 && lastY != -1) { |
|
||||||
newX = lastX; |
|
||||||
newY = lastY; |
|
||||||
} |
|
||||||
int wheel = (int) (event.getScaleSpan() / 4f); // scale to match mouse wheel
|
|
||||||
int dwheel = (int) (event.getDeltaScaleSpan() / 4f); // scale to match mouse wheel
|
|
||||||
mot = new MouseMotionEvent(newX, newX, 0, 0, wheel, dwheel); |
|
||||||
mot.setTime(event.getTime()); |
|
||||||
listener.onMouseMotionEvent(mot); |
|
||||||
lastX = newX; |
|
||||||
lastY = newY; |
|
||||||
|
|
||||||
break; |
|
||||||
|
|
||||||
case MOVE: |
|
||||||
if (event.isScaleSpanInProgress()) { |
|
||||||
break; |
|
||||||
} |
|
||||||
|
|
||||||
int dx; |
|
||||||
int dy; |
|
||||||
if (lastX != -1) { |
|
||||||
dx = newX - lastX; |
|
||||||
dy = newY - lastY; |
|
||||||
} else { |
|
||||||
dx = 0; |
|
||||||
dy = 0; |
|
||||||
} |
|
||||||
|
|
||||||
mot = new MouseMotionEvent(newX, newY, dx, dy, (int)event.getScaleSpan(), (int)event.getDeltaScaleSpan()); |
|
||||||
mot.setTime(event.getTime()); |
|
||||||
listener.onMouseMotionEvent(mot); |
|
||||||
lastX = newX; |
|
||||||
lastY = newY; |
|
||||||
|
|
||||||
break; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
if (event.isConsumed() == false) { |
|
||||||
synchronized (eventPoolUnConsumed) { |
|
||||||
eventPoolUnConsumed.push(event); |
|
||||||
} |
|
||||||
|
|
||||||
} else { |
|
||||||
synchronized (eventPool) { |
|
||||||
eventPool.push(event); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
} |
|
||||||
// --------------- ENDOF INSIDE GLThread ---------------
|
|
||||||
|
|
||||||
// --------------- Gesture detected callback events ---------------
|
|
||||||
public boolean onDown(MotionEvent event) { |
|
||||||
return false; |
|
||||||
} |
|
||||||
|
|
||||||
public void onLongPress(MotionEvent event) { |
|
||||||
TouchEvent touch = getNextFreeTouchEvent(); |
|
||||||
touch.set(Type.LONGPRESSED, event.getX(), view.getHeight() - event.getY(), 0f, 0f); |
|
||||||
touch.setPointerId(0); |
|
||||||
touch.setTime(event.getEventTime()); |
|
||||||
processEvent(touch); |
|
||||||
} |
|
||||||
|
|
||||||
public boolean onFling(MotionEvent event, MotionEvent event2, float vx, float vy) { |
|
||||||
TouchEvent touch = getNextFreeTouchEvent(); |
|
||||||
touch.set(Type.FLING, event.getX(), view.getHeight() - event.getY(), vx, vy); |
|
||||||
touch.setPointerId(0); |
|
||||||
touch.setTime(event.getEventTime()); |
|
||||||
processEvent(touch); |
|
||||||
|
|
||||||
return true; |
|
||||||
} |
|
||||||
|
|
||||||
public boolean onSingleTapConfirmed(MotionEvent event) { |
|
||||||
//Nothing to do here the tap has already been detected.
|
|
||||||
return false; |
|
||||||
} |
|
||||||
|
|
||||||
public boolean onDoubleTap(MotionEvent event) { |
|
||||||
TouchEvent touch = getNextFreeTouchEvent(); |
|
||||||
touch.set(Type.DOUBLETAP, event.getX(), view.getHeight() - event.getY(), 0f, 0f); |
|
||||||
touch.setPointerId(0); |
|
||||||
touch.setTime(event.getEventTime()); |
|
||||||
processEvent(touch); |
|
||||||
return true; |
|
||||||
} |
|
||||||
|
|
||||||
public boolean onDoubleTapEvent(MotionEvent event) { |
|
||||||
return false; |
|
||||||
} |
|
||||||
|
|
||||||
public boolean onScaleBegin(ScaleGestureDetector scaleGestureDetector) { |
|
||||||
scaleInProgress = true; |
|
||||||
TouchEvent touch = getNextFreeTouchEvent(); |
|
||||||
touch.set(Type.SCALE_START, scaleGestureDetector.getFocusX(), scaleGestureDetector.getFocusY(), 0f, 0f); |
|
||||||
touch.setPointerId(0); |
|
||||||
touch.setTime(scaleGestureDetector.getEventTime()); |
|
||||||
touch.setScaleSpan(scaleGestureDetector.getCurrentSpan()); |
|
||||||
touch.setDeltaScaleSpan(scaleGestureDetector.getCurrentSpan() - scaleGestureDetector.getPreviousSpan()); |
|
||||||
touch.setScaleFactor(scaleGestureDetector.getScaleFactor()); |
|
||||||
touch.setScaleSpanInProgress(scaleInProgress); |
|
||||||
processEvent(touch); |
|
||||||
// System.out.println("scaleBegin");
|
|
||||||
|
|
||||||
return true; |
|
||||||
} |
|
||||||
|
|
||||||
public boolean onScale(ScaleGestureDetector scaleGestureDetector) { |
|
||||||
TouchEvent touch = getNextFreeTouchEvent(); |
|
||||||
touch.set(Type.SCALE_MOVE, scaleGestureDetector.getFocusX(), view.getHeight() - scaleGestureDetector.getFocusY(), 0f, 0f); |
|
||||||
touch.setPointerId(0); |
|
||||||
touch.setTime(scaleGestureDetector.getEventTime()); |
|
||||||
touch.setScaleSpan(scaleGestureDetector.getCurrentSpan()); |
|
||||||
touch.setDeltaScaleSpan(scaleGestureDetector.getCurrentSpan() - scaleGestureDetector.getPreviousSpan()); |
|
||||||
touch.setScaleFactor(scaleGestureDetector.getScaleFactor()); |
|
||||||
touch.setScaleSpanInProgress(scaleInProgress); |
|
||||||
processEvent(touch); |
|
||||||
// System.out.println("scale");
|
|
||||||
|
|
||||||
return false; |
|
||||||
} |
|
||||||
|
|
||||||
public void onScaleEnd(ScaleGestureDetector scaleGestureDetector) { |
|
||||||
scaleInProgress = false; |
|
||||||
TouchEvent touch = getNextFreeTouchEvent(); |
|
||||||
touch.set(Type.SCALE_END, scaleGestureDetector.getFocusX(), view.getHeight() - scaleGestureDetector.getFocusY(), 0f, 0f); |
|
||||||
touch.setPointerId(0); |
|
||||||
touch.setTime(scaleGestureDetector.getEventTime()); |
|
||||||
touch.setScaleSpan(scaleGestureDetector.getCurrentSpan()); |
|
||||||
touch.setDeltaScaleSpan(scaleGestureDetector.getCurrentSpan() - scaleGestureDetector.getPreviousSpan()); |
|
||||||
touch.setScaleFactor(scaleGestureDetector.getScaleFactor()); |
|
||||||
touch.setScaleSpanInProgress(scaleInProgress); |
|
||||||
processEvent(touch); |
|
||||||
} |
|
||||||
|
|
||||||
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { |
|
||||||
TouchEvent touch = getNextFreeTouchEvent(); |
|
||||||
touch.set(Type.SCROLL, e1.getX(), view.getHeight() - e1.getY(), distanceX, distanceY * (-1)); |
|
||||||
touch.setPointerId(0); |
|
||||||
touch.setTime(e1.getEventTime()); |
|
||||||
processEvent(touch); |
|
||||||
//System.out.println("scroll " + e1.getPointerCount());
|
|
||||||
return false; |
|
||||||
} |
|
||||||
|
|
||||||
public void onShowPress(MotionEvent event) { |
|
||||||
TouchEvent touch = getNextFreeTouchEvent(); |
|
||||||
touch.set(Type.SHOWPRESS, event.getX(), view.getHeight() - event.getY(), 0f, 0f); |
|
||||||
touch.setPointerId(0); |
|
||||||
touch.setTime(event.getEventTime()); |
|
||||||
processEvent(touch); |
|
||||||
} |
|
||||||
|
|
||||||
public boolean onSingleTapUp(MotionEvent event) { |
|
||||||
TouchEvent touch = getNextFreeTouchEvent(); |
|
||||||
touch.set(Type.TAP, event.getX(), view.getHeight() - event.getY(), 0f, 0f); |
|
||||||
touch.setPointerId(0); |
|
||||||
touch.setTime(event.getEventTime()); |
|
||||||
processEvent(touch); |
|
||||||
return true; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void setSimulateKeyboard(boolean simulate) { |
|
||||||
keyboardEventsEnabled = simulate; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void setOmitHistoricEvents(boolean dontSendHistory) { |
|
||||||
this.dontSendHistory = dontSendHistory; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* @deprecated Use {@link #getSimulateMouse()}; |
|
||||||
*/ |
|
||||||
@Deprecated |
|
||||||
public boolean isMouseEventsEnabled() { |
|
||||||
return mouseEventsEnabled; |
|
||||||
} |
|
||||||
|
|
||||||
@Deprecated |
|
||||||
public void setMouseEventsEnabled(boolean mouseEventsEnabled) { |
|
||||||
this.mouseEventsEnabled = mouseEventsEnabled; |
|
||||||
} |
|
||||||
|
|
||||||
public boolean isMouseEventsInvertY() { |
|
||||||
return mouseEventsInvertY; |
|
||||||
} |
|
||||||
|
|
||||||
public void setMouseEventsInvertY(boolean mouseEventsInvertY) { |
|
||||||
this.mouseEventsInvertY = mouseEventsInvertY; |
|
||||||
} |
|
||||||
|
|
||||||
public boolean isMouseEventsInvertX() { |
|
||||||
return mouseEventsInvertX; |
|
||||||
} |
|
||||||
|
|
||||||
public void setMouseEventsInvertX(boolean mouseEventsInvertX) { |
|
||||||
this.mouseEventsInvertX = mouseEventsInvertX; |
|
||||||
} |
|
||||||
|
|
||||||
public void setSimulateMouse(boolean simulate) { |
|
||||||
mouseEventsEnabled = simulate; |
|
||||||
} |
|
||||||
|
|
||||||
public boolean getSimulateMouse() { |
|
||||||
return isSimulateMouse(); |
|
||||||
} |
|
||||||
|
|
||||||
public boolean isSimulateMouse() { |
|
||||||
return mouseEventsEnabled; |
|
||||||
} |
|
||||||
|
|
||||||
public boolean isSimulateKeyboard() { |
|
||||||
return keyboardEventsEnabled; |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -0,0 +1,158 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2009-2012 jMonkeyEngine |
||||||
|
* All rights reserved. |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms, with or without |
||||||
|
* modification, are permitted provided that the following conditions are |
||||||
|
* met: |
||||||
|
* |
||||||
|
* * Redistributions of source code must retain the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer. |
||||||
|
* |
||||||
|
* * Redistributions in binary form must reproduce the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer in the |
||||||
|
* documentation and/or other materials provided with the distribution. |
||||||
|
* |
||||||
|
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors |
||||||
|
* may be used to endorse or promote products derived from this software |
||||||
|
* without specific prior written permission. |
||||||
|
* |
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
||||||
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
*/ |
||||||
|
|
||||||
|
package com.jme3.input.android; |
||||||
|
|
||||||
|
import android.opengl.GLSurfaceView; |
||||||
|
import android.view.InputDevice; |
||||||
|
import android.view.KeyEvent; |
||||||
|
import android.view.MotionEvent; |
||||||
|
import android.view.View; |
||||||
|
import java.util.logging.Level; |
||||||
|
import java.util.logging.Logger; |
||||||
|
|
||||||
|
/** |
||||||
|
* <code>AndroidInputHandler14</code> extends <code>AndroidInputHandler</code> to |
||||||
|
* add the onHover and onGenericMotion events that where added in Android rev 14 (Android 4.0).</br> |
||||||
|
* The onGenericMotion events are the main interface to Joystick axes. They |
||||||
|
* were actually released in Android rev 12. |
||||||
|
* |
||||||
|
* @author iwgeric |
||||||
|
*/ |
||||||
|
public class AndroidInputHandler14 extends AndroidInputHandler implements View.OnHoverListener, |
||||||
|
View.OnGenericMotionListener { |
||||||
|
|
||||||
|
private static final Logger logger = Logger.getLogger(AndroidInputHandler14.class.getName()); |
||||||
|
|
||||||
|
public AndroidInputHandler14() { |
||||||
|
touchInput = new AndroidTouchInput14(this); |
||||||
|
joyInput = new AndroidJoyInput14(this); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected void removeListeners(GLSurfaceView view) { |
||||||
|
super.removeListeners(view); |
||||||
|
view.setOnHoverListener(null); |
||||||
|
view.setOnGenericMotionListener(null); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected void addListeners(GLSurfaceView view) { |
||||||
|
super.addListeners(view); |
||||||
|
view.setOnHoverListener(this); |
||||||
|
view.setOnGenericMotionListener(this); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean onHover(View view, MotionEvent event) { |
||||||
|
if (view != getView()) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
boolean consumed = false; |
||||||
|
|
||||||
|
int source = event.getSource(); |
||||||
|
// logger.log(Level.INFO, "onTouch source: {0}", source);
|
||||||
|
|
||||||
|
boolean isTouch = ((source & InputDevice.SOURCE_TOUCHSCREEN) == InputDevice.SOURCE_TOUCHSCREEN); |
||||||
|
// logger.log(Level.INFO, "onTouch source: {0}, isTouch: {1}",
|
||||||
|
// new Object[]{source, isTouch});
|
||||||
|
|
||||||
|
if (isTouch && touchInput != null) { |
||||||
|
// send the event to the touch processor
|
||||||
|
consumed = ((AndroidTouchInput14)touchInput).onHover(event); |
||||||
|
} |
||||||
|
|
||||||
|
return consumed; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean onGenericMotion(View view, MotionEvent event) { |
||||||
|
if (view != getView()) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
boolean consumed = false; |
||||||
|
|
||||||
|
int source = event.getSource(); |
||||||
|
// logger.log(Level.INFO, "onGenericMotion source: {0}", source);
|
||||||
|
|
||||||
|
boolean isJoystick = |
||||||
|
((source & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD) || |
||||||
|
((source & InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK); |
||||||
|
|
||||||
|
if (isJoystick && joyInput != null) { |
||||||
|
// logger.log(Level.INFO, "onGenericMotion source: {0}, isJoystick: {1}",
|
||||||
|
// new Object[]{source, isJoystick});
|
||||||
|
// send the event to the touch processor
|
||||||
|
consumed = consumed || ((AndroidJoyInput14)joyInput).onGenericMotion(event); |
||||||
|
} |
||||||
|
|
||||||
|
return consumed; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean onKey(View view, int keyCode, KeyEvent event) { |
||||||
|
if (view != getView()) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
boolean consumed = false; |
||||||
|
|
||||||
|
// logger.log(Level.INFO, "onKey keyCode: {0}, action: {1}, event: {2}",
|
||||||
|
// new Object[]{KeyEvent.keyCodeToString(keyCode), event.getAction(), event});
|
||||||
|
int source = event.getSource(); |
||||||
|
// logger.log(Level.INFO, "onKey source: {0}", source);
|
||||||
|
|
||||||
|
boolean isTouch = |
||||||
|
((source & InputDevice.SOURCE_TOUCHSCREEN) == InputDevice.SOURCE_TOUCHSCREEN) || |
||||||
|
((source & InputDevice.SOURCE_KEYBOARD) == InputDevice.SOURCE_KEYBOARD); |
||||||
|
boolean isJoystick = |
||||||
|
((source & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD) || |
||||||
|
((source & InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK); |
||||||
|
|
||||||
|
if (isTouch && touchInput != null) { |
||||||
|
// logger.log(Level.INFO, "onKey source: {0}, isTouch: {1}",
|
||||||
|
// new Object[]{source, isTouch});
|
||||||
|
consumed = touchInput.onKey(event); |
||||||
|
} |
||||||
|
if (isJoystick && joyInput != null) { |
||||||
|
// logger.log(Level.INFO, "onKey source: {0}, isJoystick: {1}",
|
||||||
|
// new Object[]{source, isJoystick});
|
||||||
|
consumed = consumed || ((AndroidJoyInput14)joyInput).onKey(event); |
||||||
|
} |
||||||
|
|
||||||
|
return consumed; |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,108 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2009-2015 jMonkeyEngine |
||||||
|
* All rights reserved. |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms, with or without |
||||||
|
* modification, are permitted provided that the following conditions are |
||||||
|
* met: |
||||||
|
* |
||||||
|
* * Redistributions of source code must retain the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer. |
||||||
|
* |
||||||
|
* * Redistributions in binary form must reproduce the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer in the |
||||||
|
* documentation and/or other materials provided with the distribution. |
||||||
|
* |
||||||
|
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors |
||||||
|
* may be used to endorse or promote products derived from this software |
||||||
|
* without specific prior written permission. |
||||||
|
* |
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
||||||
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
*/ |
||||||
|
package com.jme3.input.android; |
||||||
|
|
||||||
|
import android.view.KeyEvent; |
||||||
|
import android.view.MotionEvent; |
||||||
|
import com.jme3.input.InputManager; |
||||||
|
import com.jme3.input.Joystick; |
||||||
|
import java.util.logging.Logger; |
||||||
|
|
||||||
|
/** |
||||||
|
* <code>AndroidJoyInput14</code> extends <code>AndroidJoyInput</code> |
||||||
|
* to include support for physical joysticks/gamepads.</br> |
||||||
|
* |
||||||
|
* @author iwgeric |
||||||
|
*/ |
||||||
|
public class AndroidJoyInput14 extends AndroidJoyInput { |
||||||
|
private static final Logger logger = Logger.getLogger(AndroidJoyInput14.class.getName()); |
||||||
|
|
||||||
|
private AndroidJoystickJoyInput14 joystickJoyInput; |
||||||
|
|
||||||
|
public AndroidJoyInput14(AndroidInputHandler inputHandler) { |
||||||
|
super(inputHandler); |
||||||
|
joystickJoyInput = new AndroidJoystickJoyInput14(this); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Pauses the joystick device listeners to save battery life if they are not needed. |
||||||
|
* Used to pause when the activity pauses |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public void pauseJoysticks() { |
||||||
|
super.pauseJoysticks(); |
||||||
|
|
||||||
|
if (joystickJoyInput != null) { |
||||||
|
joystickJoyInput.pauseJoysticks(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Resumes the joystick device listeners. |
||||||
|
* Used to resume when the activity comes to the top of the stack |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public void resumeJoysticks() { |
||||||
|
super.resumeJoysticks(); |
||||||
|
if (joystickJoyInput != null) { |
||||||
|
joystickJoyInput.resumeJoysticks(); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void destroy() { |
||||||
|
super.destroy(); |
||||||
|
if (joystickJoyInput != null) { |
||||||
|
joystickJoyInput.destroy(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Joystick[] loadJoysticks(InputManager inputManager) { |
||||||
|
// load the simulated joystick for device orientation
|
||||||
|
super.loadJoysticks(inputManager); |
||||||
|
// load physical gamepads/joysticks
|
||||||
|
joystickList.addAll(joystickJoyInput.loadJoysticks(joystickList.size(), inputManager)); |
||||||
|
// return the list of joysticks back to InputManager
|
||||||
|
return joystickList.toArray( new Joystick[joystickList.size()] ); |
||||||
|
} |
||||||
|
|
||||||
|
public boolean onGenericMotion(MotionEvent event) { |
||||||
|
return joystickJoyInput.onGenericMotion(event); |
||||||
|
} |
||||||
|
|
||||||
|
public boolean onKey(KeyEvent event) { |
||||||
|
return joystickJoyInput.onKey(event); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,403 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2009-2015 jMonkeyEngine |
||||||
|
* All rights reserved. |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms, with or without |
||||||
|
* modification, are permitted provided that the following conditions are |
||||||
|
* met: |
||||||
|
* |
||||||
|
* * Redistributions of source code must retain the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer. |
||||||
|
* |
||||||
|
* * Redistributions in binary form must reproduce the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer in the |
||||||
|
* documentation and/or other materials provided with the distribution. |
||||||
|
* |
||||||
|
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors |
||||||
|
* may be used to endorse or promote products derived from this software |
||||||
|
* without specific prior written permission. |
||||||
|
* |
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
||||||
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
*/ |
||||||
|
package com.jme3.input.android; |
||||||
|
|
||||||
|
import android.view.InputDevice; |
||||||
|
import android.view.InputDevice.MotionRange; |
||||||
|
import android.view.KeyCharacterMap; |
||||||
|
import android.view.KeyEvent; |
||||||
|
import android.view.MotionEvent; |
||||||
|
import com.jme3.input.AbstractJoystick; |
||||||
|
import com.jme3.input.DefaultJoystickAxis; |
||||||
|
import com.jme3.input.DefaultJoystickButton; |
||||||
|
import com.jme3.input.InputManager; |
||||||
|
import com.jme3.input.JoyInput; |
||||||
|
import com.jme3.input.Joystick; |
||||||
|
import com.jme3.input.JoystickAxis; |
||||||
|
import com.jme3.input.JoystickButton; |
||||||
|
import com.jme3.input.event.JoyAxisEvent; |
||||||
|
import com.jme3.input.event.JoyButtonEvent; |
||||||
|
import java.util.ArrayList; |
||||||
|
import java.util.HashMap; |
||||||
|
import java.util.List; |
||||||
|
import java.util.Map; |
||||||
|
import java.util.Set; |
||||||
|
import java.util.logging.Level; |
||||||
|
import java.util.logging.Logger; |
||||||
|
|
||||||
|
/** |
||||||
|
* Main class that creates and manages Android inputs for physical gamepads/joysticks. |
||||||
|
* |
||||||
|
* @author iwgeric |
||||||
|
*/ |
||||||
|
public class AndroidJoystickJoyInput14 { |
||||||
|
private static final Logger logger = Logger.getLogger(AndroidJoystickJoyInput14.class.getName()); |
||||||
|
|
||||||
|
private boolean loaded = false; |
||||||
|
private AndroidJoyInput joyInput; |
||||||
|
private Map<Integer, AndroidJoystick> joystickIndex = new HashMap<Integer, AndroidJoystick>(); |
||||||
|
|
||||||
|
private static int[] AndroidGamepadButtons = { |
||||||
|
// Dpad buttons
|
||||||
|
KeyEvent.KEYCODE_DPAD_UP, KeyEvent.KEYCODE_DPAD_DOWN, |
||||||
|
KeyEvent.KEYCODE_DPAD_LEFT, KeyEvent.KEYCODE_DPAD_RIGHT, |
||||||
|
KeyEvent.KEYCODE_DPAD_CENTER, |
||||||
|
|
||||||
|
// pressing joystick down
|
||||||
|
KeyEvent.KEYCODE_BUTTON_THUMBL, KeyEvent.KEYCODE_BUTTON_THUMBR, |
||||||
|
|
||||||
|
// buttons
|
||||||
|
KeyEvent.KEYCODE_BUTTON_A, KeyEvent.KEYCODE_BUTTON_B, |
||||||
|
KeyEvent.KEYCODE_BUTTON_X, KeyEvent.KEYCODE_BUTTON_Y, |
||||||
|
|
||||||
|
// buttons on back of device
|
||||||
|
KeyEvent.KEYCODE_BUTTON_L1, KeyEvent.KEYCODE_BUTTON_R1, |
||||||
|
KeyEvent.KEYCODE_BUTTON_L2, KeyEvent.KEYCODE_BUTTON_R2, |
||||||
|
|
||||||
|
// start / select buttons
|
||||||
|
KeyEvent.KEYCODE_BUTTON_START, KeyEvent.KEYCODE_BUTTON_SELECT, |
||||||
|
KeyEvent.KEYCODE_BUTTON_MODE, |
||||||
|
|
||||||
|
}; |
||||||
|
|
||||||
|
public AndroidJoystickJoyInput14(AndroidJoyInput joyInput) { |
||||||
|
this.joyInput = joyInput; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public void pauseJoysticks() { |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public void resumeJoysticks() { |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public void destroy() { |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public List<Joystick> loadJoysticks(int joyId, InputManager inputManager) { |
||||||
|
logger.log(Level.INFO, "loading Joystick devices"); |
||||||
|
ArrayList<Joystick> joysticks = new ArrayList<Joystick>(); |
||||||
|
joysticks.clear(); |
||||||
|
joystickIndex.clear(); |
||||||
|
|
||||||
|
ArrayList gameControllerDeviceIds = new ArrayList(); |
||||||
|
int[] deviceIds = InputDevice.getDeviceIds(); |
||||||
|
for (int deviceId : deviceIds) { |
||||||
|
InputDevice dev = InputDevice.getDevice(deviceId); |
||||||
|
int sources = dev.getSources(); |
||||||
|
logger.log(Level.FINE, "deviceId[{0}] sources: {1}", new Object[]{deviceId, sources}); |
||||||
|
|
||||||
|
// Verify that the device has gamepad buttons, control sticks, or both.
|
||||||
|
if (((sources & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD) || |
||||||
|
((sources & InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK)) { |
||||||
|
// This device is a game controller. Store its device ID.
|
||||||
|
if (!gameControllerDeviceIds.contains(deviceId)) { |
||||||
|
gameControllerDeviceIds.add(deviceId); |
||||||
|
logger.log(Level.FINE, "Attempting to create joystick for device: {0}", dev); |
||||||
|
// Create an AndroidJoystick and store the InputDevice so we
|
||||||
|
// can later correspond the input from the InputDevice to the
|
||||||
|
// appropriate jME Joystick event
|
||||||
|
AndroidJoystick joystick = new AndroidJoystick(inputManager, |
||||||
|
joyInput, |
||||||
|
dev, |
||||||
|
joyId+joysticks.size(), |
||||||
|
dev.getName()); |
||||||
|
joystickIndex.put(deviceId, joystick); |
||||||
|
joysticks.add(joystick); |
||||||
|
|
||||||
|
// Each analog input is reported as a MotionRange
|
||||||
|
// The axis number corresponds to the type of axis
|
||||||
|
// The AndroidJoystick.addAxis(MotionRange) converts the axis
|
||||||
|
// type reported by Android into the jME Joystick axis
|
||||||
|
List<MotionRange> motionRanges = dev.getMotionRanges(); |
||||||
|
for (MotionRange motionRange: motionRanges) { |
||||||
|
logger.log(Level.INFO, "motion range: {0}", motionRange.toString()); |
||||||
|
logger.log(Level.INFO, "axis: {0}", motionRange.getAxis()); |
||||||
|
JoystickAxis axis = joystick.addAxis(motionRange); |
||||||
|
logger.log(Level.INFO, "added axis: {0}", axis); |
||||||
|
} |
||||||
|
|
||||||
|
// InputDevice has a method for determining if a keyCode is
|
||||||
|
// supported (InputDevice public boolean[] hasKeys (int... keys)).
|
||||||
|
// But this method wasn't added until rev 19 (Android 4.4)
|
||||||
|
// Therefore, we only can query the entire device and see if
|
||||||
|
// any InputDevice supports the keyCode. This may result in
|
||||||
|
// buttons being configured that don't exist on the specific
|
||||||
|
// device, but I haven't found a better way yet.
|
||||||
|
for (int keyCode: AndroidGamepadButtons) { |
||||||
|
logger.log(Level.INFO, "button[{0}]: {1}", |
||||||
|
new Object[]{keyCode, KeyCharacterMap.deviceHasKey(keyCode)}); |
||||||
|
if (KeyCharacterMap.deviceHasKey(keyCode)) { |
||||||
|
// add button even though we aren't sure if the button
|
||||||
|
// actually exists on this InputDevice
|
||||||
|
logger.log(Level.INFO, "button[{0}] exists somewhere", keyCode); |
||||||
|
JoystickButton button = joystick.addButton(keyCode); |
||||||
|
logger.log(Level.INFO, "added button: {0}", button); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
loaded = true; |
||||||
|
return joysticks; |
||||||
|
} |
||||||
|
|
||||||
|
public boolean onGenericMotion(MotionEvent event) { |
||||||
|
boolean consumed = false; |
||||||
|
// logger.log(Level.INFO, "onGenericMotion event: {0}", event);
|
||||||
|
event.getDeviceId(); |
||||||
|
event.getSource(); |
||||||
|
// logger.log(Level.INFO, "deviceId: {0}, source: {1}", new Object[]{event.getDeviceId(), event.getSource()});
|
||||||
|
AndroidJoystick joystick = joystickIndex.get(event.getDeviceId()); |
||||||
|
if (joystick != null) { |
||||||
|
for (int androidAxis: joystick.getAndroidAxes()) { |
||||||
|
String axisName = MotionEvent.axisToString(androidAxis); |
||||||
|
float value = event.getAxisValue(androidAxis); |
||||||
|
int action = event.getAction(); |
||||||
|
if (action == MotionEvent.ACTION_MOVE) { |
||||||
|
// logger.log(Level.INFO, "MOVE axis num: {0}, axisName: {1}, value: {2}",
|
||||||
|
// new Object[]{androidAxis, axisName, value});
|
||||||
|
JoystickAxis axis = joystick.getAxis(androidAxis); |
||||||
|
if (axis != null) { |
||||||
|
// logger.log(Level.INFO, "MOVE axis num: {0}, axisName: {1}, value: {2}, deadzone: {3}",
|
||||||
|
// new Object[]{androidAxis, axisName, value, axis.getDeadZone()});
|
||||||
|
JoyAxisEvent axisEvent = new JoyAxisEvent(axis, value); |
||||||
|
joyInput.addEvent(axisEvent); |
||||||
|
consumed = true; |
||||||
|
} else { |
||||||
|
// logger.log(Level.INFO, "axis was null for axisName: {0}", axisName);
|
||||||
|
} |
||||||
|
} else { |
||||||
|
// logger.log(Level.INFO, "action: {0}", action);
|
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return consumed; |
||||||
|
} |
||||||
|
|
||||||
|
public boolean onKey(KeyEvent event) { |
||||||
|
boolean consumed = false; |
||||||
|
// logger.log(Level.INFO, "onKey event: {0}", event);
|
||||||
|
|
||||||
|
event.getDeviceId(); |
||||||
|
event.getSource(); |
||||||
|
AndroidJoystick joystick = joystickIndex.get(event.getDeviceId()); |
||||||
|
if (joystick != null) { |
||||||
|
JoystickButton button = joystick.getButton(event.getKeyCode()); |
||||||
|
if (button != null) { |
||||||
|
boolean pressed = event.getAction() == KeyEvent.ACTION_DOWN; |
||||||
|
JoyButtonEvent buttonEvent = new JoyButtonEvent(button, pressed); |
||||||
|
joyInput.addEvent(buttonEvent); |
||||||
|
consumed = true; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return consumed; |
||||||
|
} |
||||||
|
|
||||||
|
protected class AndroidJoystick extends AbstractJoystick { |
||||||
|
|
||||||
|
private JoystickAxis nullAxis; |
||||||
|
private InputDevice device; |
||||||
|
private JoystickAxis xAxis; |
||||||
|
private JoystickAxis yAxis; |
||||||
|
private JoystickAxis povX; |
||||||
|
private JoystickAxis povY; |
||||||
|
private Map<Integer, JoystickAxis> axisIndex = new HashMap<Integer, JoystickAxis>(); |
||||||
|
private Map<Integer, JoystickButton> buttonIndex = new HashMap<Integer, JoystickButton>(); |
||||||
|
|
||||||
|
public AndroidJoystick( InputManager inputManager, JoyInput joyInput, InputDevice device, |
||||||
|
int joyId, String name ) { |
||||||
|
super( inputManager, joyInput, joyId, name ); |
||||||
|
|
||||||
|
this.device = device; |
||||||
|
|
||||||
|
this.nullAxis = new DefaultJoystickAxis( getInputManager(), this, -1, |
||||||
|
"Null", "null", false, false, 0 ); |
||||||
|
this.xAxis = nullAxis; |
||||||
|
this.yAxis = nullAxis; |
||||||
|
this.povX = nullAxis; |
||||||
|
this.povY = nullAxis; |
||||||
|
} |
||||||
|
|
||||||
|
protected JoystickAxis getAxis(int androidAxis) { |
||||||
|
return axisIndex.get(androidAxis); |
||||||
|
} |
||||||
|
|
||||||
|
protected Set<Integer> getAndroidAxes() { |
||||||
|
return axisIndex.keySet(); |
||||||
|
} |
||||||
|
|
||||||
|
protected JoystickButton getButton(int keyCode) { |
||||||
|
return buttonIndex.get(keyCode); |
||||||
|
} |
||||||
|
|
||||||
|
protected JoystickButton addButton( int keyCode ) { |
||||||
|
|
||||||
|
// logger.log(Level.FINE, "Adding button: {0}", keyCode);
|
||||||
|
|
||||||
|
String name = KeyEvent.keyCodeToString(keyCode); |
||||||
|
String logicalId = KeyEvent.keyCodeToString(keyCode); |
||||||
|
// A/B/X/Y buttons
|
||||||
|
if (keyCode == KeyEvent.KEYCODE_BUTTON_Y) { |
||||||
|
logicalId = JoystickButton.BUTTON_0; |
||||||
|
} else if (keyCode == KeyEvent.KEYCODE_BUTTON_A) { |
||||||
|
logicalId = JoystickButton.BUTTON_2; |
||||||
|
} else if (keyCode == KeyEvent.KEYCODE_BUTTON_B) { |
||||||
|
logicalId = JoystickButton.BUTTON_1; |
||||||
|
} else if (keyCode == KeyEvent.KEYCODE_BUTTON_X) { |
||||||
|
logicalId = JoystickButton.BUTTON_3; |
||||||
|
// Front buttons Some of these have the top ones and the bottoms ones flipped.
|
||||||
|
} else if (keyCode == KeyEvent.KEYCODE_BUTTON_L1) { |
||||||
|
logicalId = JoystickButton.BUTTON_4; |
||||||
|
} else if (keyCode == KeyEvent.KEYCODE_BUTTON_R1) { |
||||||
|
logicalId = JoystickButton.BUTTON_5; |
||||||
|
} else if (keyCode == KeyEvent.KEYCODE_BUTTON_L2) { |
||||||
|
logicalId = JoystickButton.BUTTON_6; |
||||||
|
} else if (keyCode == KeyEvent.KEYCODE_BUTTON_R2) { |
||||||
|
logicalId = JoystickButton.BUTTON_7; |
||||||
|
// // Dpad buttons
|
||||||
|
// } else if (keyCode == KeyEvent.KEYCODE_DPAD_UP) {
|
||||||
|
// logicalId = JoystickButton.BUTTON_8;
|
||||||
|
// } else if (keyCode == KeyEvent.KEYCODE_DPAD_UP) {
|
||||||
|
// logicalId = JoystickButton.BUTTON_9;
|
||||||
|
// } else if (keyCode == KeyEvent.KEYCODE_DPAD_UP) {
|
||||||
|
// logicalId = JoystickButton.BUTTON_8;
|
||||||
|
// } else if (keyCode == KeyEvent.KEYCODE_DPAD_UP) {
|
||||||
|
// logicalId = JoystickButton.BUTTON_9;
|
||||||
|
// Select and start buttons
|
||||||
|
} else if (keyCode == KeyEvent.KEYCODE_BUTTON_SELECT) { |
||||||
|
logicalId = JoystickButton.BUTTON_8; |
||||||
|
} else if (keyCode == KeyEvent.KEYCODE_BUTTON_START) { |
||||||
|
logicalId = JoystickButton.BUTTON_9; |
||||||
|
// Joystick push buttons
|
||||||
|
} else if (keyCode == KeyEvent.KEYCODE_BUTTON_THUMBL) { |
||||||
|
logicalId = JoystickButton.BUTTON_10; |
||||||
|
} else if (keyCode == KeyEvent.KEYCODE_BUTTON_THUMBR) { |
||||||
|
logicalId = JoystickButton.BUTTON_11; |
||||||
|
} |
||||||
|
|
||||||
|
JoystickButton button = new DefaultJoystickButton( getInputManager(), this, getButtonCount(), |
||||||
|
name, logicalId ); |
||||||
|
addButton(button); |
||||||
|
buttonIndex.put( keyCode, button ); |
||||||
|
return button; |
||||||
|
} |
||||||
|
|
||||||
|
protected JoystickAxis addAxis(MotionRange motionRange) { |
||||||
|
|
||||||
|
String name = MotionEvent.axisToString(motionRange.getAxis()); |
||||||
|
|
||||||
|
String logicalId = MotionEvent.axisToString(motionRange.getAxis()); |
||||||
|
if (motionRange.getAxis() == MotionEvent.AXIS_X) { |
||||||
|
logicalId = JoystickAxis.X_AXIS; |
||||||
|
} else if (motionRange.getAxis() == MotionEvent.AXIS_Y) { |
||||||
|
logicalId = JoystickAxis.Y_AXIS; |
||||||
|
} else if (motionRange.getAxis() == MotionEvent.AXIS_Z) { |
||||||
|
logicalId = JoystickAxis.Z_AXIS; |
||||||
|
} else if (motionRange.getAxis() == MotionEvent.AXIS_RZ) { |
||||||
|
logicalId = JoystickAxis.Z_ROTATION; |
||||||
|
} else if (motionRange.getAxis() == MotionEvent.AXIS_HAT_X) { |
||||||
|
logicalId = JoystickAxis.POV_X; |
||||||
|
} else if (motionRange.getAxis() == MotionEvent.AXIS_HAT_Y) { |
||||||
|
logicalId = JoystickAxis.POV_Y; |
||||||
|
} |
||||||
|
// String logicalId = JoystickCompatibilityMappings.remapComponent( controller.getName(), original );
|
||||||
|
// if( name != original ) {
|
||||||
|
// logger.log(Level.FINE, "Remapped:" + original + " to:" + logicalId);
|
||||||
|
// }
|
||||||
|
|
||||||
|
JoystickAxis axis = new DefaultJoystickAxis(getInputManager(), |
||||||
|
this, |
||||||
|
getAxisCount(), |
||||||
|
name, |
||||||
|
logicalId, |
||||||
|
true, |
||||||
|
true, |
||||||
|
motionRange.getFlat()); |
||||||
|
|
||||||
|
if (motionRange.getAxis() == MotionEvent.AXIS_X) { |
||||||
|
xAxis = axis; |
||||||
|
} |
||||||
|
if (motionRange.getAxis() == MotionEvent.AXIS_Y) { |
||||||
|
yAxis = axis; |
||||||
|
} |
||||||
|
if (motionRange.getAxis() == MotionEvent.AXIS_HAT_X) { |
||||||
|
povX = axis; |
||||||
|
} |
||||||
|
if (motionRange.getAxis() == MotionEvent.AXIS_HAT_Y) { |
||||||
|
povY = axis; |
||||||
|
} |
||||||
|
|
||||||
|
addAxis(axis); |
||||||
|
axisIndex.put(motionRange.getAxis(), axis); |
||||||
|
return axis; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public JoystickAxis getXAxis() { |
||||||
|
return xAxis; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public JoystickAxis getYAxis() { |
||||||
|
return yAxis; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public JoystickAxis getPovXAxis() { |
||||||
|
return povX; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public JoystickAxis getPovYAxis() { |
||||||
|
return povY; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public int getXAxisIndex(){ |
||||||
|
return xAxis.getAxisId(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public int getYAxisIndex(){ |
||||||
|
return yAxis.getAxisId(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -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; |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -1,257 +0,0 @@ |
|||||||
/* |
|
||||||
* Copyright (c) 2009-2012 jMonkeyEngine |
|
||||||
* All rights reserved. |
|
||||||
* |
|
||||||
* Redistribution and use in source and binary forms, with or without |
|
||||||
* modification, are permitted provided that the following conditions are |
|
||||||
* met: |
|
||||||
* |
|
||||||
* * Redistributions of source code must retain the above copyright |
|
||||||
* notice, this list of conditions and the following disclaimer. |
|
||||||
* |
|
||||||
* * Redistributions in binary form must reproduce the above copyright |
|
||||||
* notice, this list of conditions and the following disclaimer in the |
|
||||||
* documentation and/or other materials provided with the distribution. |
|
||||||
* |
|
||||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors |
|
||||||
* may be used to endorse or promote products derived from this software |
|
||||||
* without specific prior written permission. |
|
||||||
* |
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
|
||||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
|
||||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
|
||||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
|
||||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
|
||||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
|
||||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
|
||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
||||||
*/ |
|
||||||
|
|
||||||
package com.jme3.input.android; |
|
||||||
|
|
||||||
import android.view.MotionEvent; |
|
||||||
import android.view.View; |
|
||||||
import com.jme3.input.event.InputEvent; |
|
||||||
import com.jme3.input.event.MouseButtonEvent; |
|
||||||
import com.jme3.input.event.MouseMotionEvent; |
|
||||||
import com.jme3.input.event.TouchEvent; |
|
||||||
import static com.jme3.input.event.TouchEvent.Type.DOWN; |
|
||||||
import static com.jme3.input.event.TouchEvent.Type.MOVE; |
|
||||||
import static com.jme3.input.event.TouchEvent.Type.UP; |
|
||||||
import com.jme3.math.Vector2f; |
|
||||||
import java.util.HashMap; |
|
||||||
import java.util.logging.Logger; |
|
||||||
|
|
||||||
/** |
|
||||||
* AndroidTouchHandler is the base class that receives touch inputs from the |
|
||||||
* Android system and creates the TouchEvents for jME. This class is designed |
|
||||||
* to handle the base touch events for Android rev 9 (Android 2.3). This is |
|
||||||
* extended by other classes to add features that were introducted after |
|
||||||
* Android rev 9. |
|
||||||
* |
|
||||||
* @author iwgeric |
|
||||||
*/ |
|
||||||
public class AndroidTouchHandler implements View.OnTouchListener { |
|
||||||
private static final Logger logger = Logger.getLogger(AndroidTouchHandler.class.getName()); |
|
||||||
|
|
||||||
final private HashMap<Integer, Vector2f> lastPositions = new HashMap<Integer, Vector2f>(); |
|
||||||
|
|
||||||
protected int numPointers = 0; |
|
||||||
|
|
||||||
protected AndroidInputHandler androidInput; |
|
||||||
protected AndroidGestureHandler gestureHandler; |
|
||||||
|
|
||||||
public AndroidTouchHandler(AndroidInputHandler androidInput, AndroidGestureHandler gestureHandler) { |
|
||||||
this.androidInput = androidInput; |
|
||||||
this.gestureHandler = gestureHandler; |
|
||||||
} |
|
||||||
|
|
||||||
public void initialize() { |
|
||||||
} |
|
||||||
|
|
||||||
public void destroy() { |
|
||||||
setView(null); |
|
||||||
} |
|
||||||
|
|
||||||
public void setView(View view) { |
|
||||||
if (view != null) { |
|
||||||
view.setOnTouchListener(this); |
|
||||||
} else { |
|
||||||
androidInput.getView().setOnTouchListener(null); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
protected int getPointerIndex(MotionEvent event) { |
|
||||||
return (event.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) |
|
||||||
>> MotionEvent.ACTION_POINTER_INDEX_SHIFT; |
|
||||||
} |
|
||||||
|
|
||||||
protected int getPointerId(MotionEvent event) { |
|
||||||
return event.getPointerId(getPointerIndex(event)); |
|
||||||
} |
|
||||||
|
|
||||||
protected int getAction(MotionEvent event) { |
|
||||||
return event.getAction() & MotionEvent.ACTION_MASK; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* onTouch gets called from android thread on touch events |
|
||||||
*/ |
|
||||||
public boolean onTouch(View view, MotionEvent event) { |
|
||||||
if (!androidInput.isInitialized() || view != androidInput.getView()) { |
|
||||||
return false; |
|
||||||
} |
|
||||||
|
|
||||||
boolean bWasHandled = false; |
|
||||||
TouchEvent touch = null; |
|
||||||
// System.out.println("native : " + event.getAction());
|
|
||||||
int action = getAction(event); |
|
||||||
int pointerIndex = getPointerIndex(event); |
|
||||||
int pointerId = getPointerId(event); |
|
||||||
Vector2f lastPos = lastPositions.get(pointerId); |
|
||||||
float jmeX; |
|
||||||
float jmeY; |
|
||||||
|
|
||||||
numPointers = event.getPointerCount(); |
|
||||||
|
|
||||||
// final int historySize = event.getHistorySize();
|
|
||||||
//final int pointerCount = event.getPointerCount();
|
|
||||||
switch (getAction(event)) { |
|
||||||
case MotionEvent.ACTION_POINTER_DOWN: |
|
||||||
case MotionEvent.ACTION_DOWN: |
|
||||||
jmeX = androidInput.getJmeX(event.getX(pointerIndex)); |
|
||||||
jmeY = androidInput.invertY(androidInput.getJmeY(event.getY(pointerIndex))); |
|
||||||
touch = androidInput.getFreeTouchEvent(); |
|
||||||
touch.set(TouchEvent.Type.DOWN, jmeX, jmeY, 0, 0); |
|
||||||
touch.setPointerId(pointerId); |
|
||||||
touch.setTime(event.getEventTime()); |
|
||||||
touch.setPressure(event.getPressure(pointerIndex)); |
|
||||||
|
|
||||||
lastPos = new Vector2f(jmeX, jmeY); |
|
||||||
lastPositions.put(pointerId, lastPos); |
|
||||||
|
|
||||||
processEvent(touch); |
|
||||||
|
|
||||||
bWasHandled = true; |
|
||||||
break; |
|
||||||
case MotionEvent.ACTION_POINTER_UP: |
|
||||||
case MotionEvent.ACTION_CANCEL: |
|
||||||
case MotionEvent.ACTION_UP: |
|
||||||
jmeX = androidInput.getJmeX(event.getX(pointerIndex)); |
|
||||||
jmeY = androidInput.invertY(androidInput.getJmeY(event.getY(pointerIndex))); |
|
||||||
touch = androidInput.getFreeTouchEvent(); |
|
||||||
touch.set(TouchEvent.Type.UP, jmeX, jmeY, 0, 0); |
|
||||||
touch.setPointerId(pointerId); |
|
||||||
touch.setTime(event.getEventTime()); |
|
||||||
touch.setPressure(event.getPressure(pointerIndex)); |
|
||||||
lastPositions.remove(pointerId); |
|
||||||
|
|
||||||
processEvent(touch); |
|
||||||
|
|
||||||
bWasHandled = true; |
|
||||||
break; |
|
||||||
case MotionEvent.ACTION_MOVE: |
|
||||||
// Convert all pointers into events
|
|
||||||
for (int p = 0; p < event.getPointerCount(); p++) { |
|
||||||
jmeX = androidInput.getJmeX(event.getX(p)); |
|
||||||
jmeY = androidInput.invertY(androidInput.getJmeY(event.getY(p))); |
|
||||||
lastPos = lastPositions.get(event.getPointerId(p)); |
|
||||||
if (lastPos == null) { |
|
||||||
lastPos = new Vector2f(jmeX, jmeY); |
|
||||||
lastPositions.put(event.getPointerId(p), lastPos); |
|
||||||
} |
|
||||||
|
|
||||||
float dX = jmeX - lastPos.x; |
|
||||||
float dY = jmeY - lastPos.y; |
|
||||||
if (dX != 0 || dY != 0) { |
|
||||||
touch = androidInput.getFreeTouchEvent(); |
|
||||||
touch.set(TouchEvent.Type.MOVE, jmeX, jmeY, dX, dY); |
|
||||||
touch.setPointerId(event.getPointerId(p)); |
|
||||||
touch.setTime(event.getEventTime()); |
|
||||||
touch.setPressure(event.getPressure(p)); |
|
||||||
lastPos.set(jmeX, jmeY); |
|
||||||
|
|
||||||
processEvent(touch); |
|
||||||
|
|
||||||
bWasHandled = true; |
|
||||||
} |
|
||||||
} |
|
||||||
break; |
|
||||||
case MotionEvent.ACTION_OUTSIDE: |
|
||||||
break; |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
// Try to detect gestures
|
|
||||||
if (gestureHandler != null) { |
|
||||||
gestureHandler.detectGesture(event); |
|
||||||
} |
|
||||||
|
|
||||||
return bWasHandled; |
|
||||||
} |
|
||||||
|
|
||||||
protected void processEvent(TouchEvent event) { |
|
||||||
// Add the touch event
|
|
||||||
androidInput.addEvent(event); |
|
||||||
// MouseEvents do not support multi-touch, so only evaluate 1 finger pointer events
|
|
||||||
if (androidInput.isSimulateMouse() && numPointers == 1) { |
|
||||||
InputEvent mouseEvent = generateMouseEvent(event); |
|
||||||
if (mouseEvent != null) { |
|
||||||
// Add the mouse event
|
|
||||||
androidInput.addEvent(mouseEvent); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
// TODO: Ring Buffer for mouse events?
|
|
||||||
protected InputEvent generateMouseEvent(TouchEvent event) { |
|
||||||
InputEvent inputEvent = null; |
|
||||||
int newX; |
|
||||||
int newY; |
|
||||||
int newDX; |
|
||||||
int newDY; |
|
||||||
|
|
||||||
if (androidInput.isMouseEventsInvertX()) { |
|
||||||
newX = (int) (androidInput.invertX(event.getX())); |
|
||||||
newDX = (int)event.getDeltaX() * -1; |
|
||||||
} else { |
|
||||||
newX = (int) event.getX(); |
|
||||||
newDX = (int)event.getDeltaX(); |
|
||||||
} |
|
||||||
|
|
||||||
if (androidInput.isMouseEventsInvertY()) { |
|
||||||
newY = (int) (androidInput.invertY(event.getY())); |
|
||||||
newDY = (int)event.getDeltaY() * -1; |
|
||||||
} else { |
|
||||||
newY = (int) event.getY(); |
|
||||||
newDY = (int)event.getDeltaY(); |
|
||||||
} |
|
||||||
|
|
||||||
switch (event.getType()) { |
|
||||||
case DOWN: |
|
||||||
// Handle mouse down event
|
|
||||||
inputEvent = new MouseButtonEvent(0, true, newX, newY); |
|
||||||
inputEvent.setTime(event.getTime()); |
|
||||||
break; |
|
||||||
|
|
||||||
case UP: |
|
||||||
// Handle mouse up event
|
|
||||||
inputEvent = new MouseButtonEvent(0, false, newX, newY); |
|
||||||
inputEvent.setTime(event.getTime()); |
|
||||||
break; |
|
||||||
|
|
||||||
case HOVER_MOVE: |
|
||||||
case MOVE: |
|
||||||
inputEvent = new MouseMotionEvent(newX, newY, newDX, newDY, (int)event.getScaleSpan(), (int)event.getDeltaScaleSpan()); |
|
||||||
inputEvent.setTime(event.getTime()); |
|
||||||
break; |
|
||||||
} |
|
||||||
|
|
||||||
return inputEvent; |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -0,0 +1,475 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2009-2012 jMonkeyEngine |
||||||
|
* All rights reserved. |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms, with or without |
||||||
|
* modification, are permitted provided that the following conditions are |
||||||
|
* met: |
||||||
|
* |
||||||
|
* * Redistributions of source code must retain the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer. |
||||||
|
* |
||||||
|
* * Redistributions in binary form must reproduce the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer in the |
||||||
|
* documentation and/or other materials provided with the distribution. |
||||||
|
* |
||||||
|
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors |
||||||
|
* may be used to endorse or promote products derived from this software |
||||||
|
* without specific prior written permission. |
||||||
|
* |
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
||||||
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
*/ |
||||||
|
|
||||||
|
package com.jme3.input.android; |
||||||
|
|
||||||
|
import android.view.GestureDetector; |
||||||
|
import android.view.KeyEvent; |
||||||
|
import android.view.MotionEvent; |
||||||
|
import android.view.ScaleGestureDetector; |
||||||
|
import com.jme3.input.RawInputListener; |
||||||
|
import com.jme3.input.TouchInput; |
||||||
|
import com.jme3.input.event.InputEvent; |
||||||
|
import com.jme3.input.event.KeyInputEvent; |
||||||
|
import com.jme3.input.event.MouseButtonEvent; |
||||||
|
import com.jme3.input.event.MouseMotionEvent; |
||||||
|
import com.jme3.input.event.TouchEvent; |
||||||
|
import static com.jme3.input.event.TouchEvent.Type.DOWN; |
||||||
|
import static com.jme3.input.event.TouchEvent.Type.MOVE; |
||||||
|
import static com.jme3.input.event.TouchEvent.Type.UP; |
||||||
|
import com.jme3.math.Vector2f; |
||||||
|
import com.jme3.system.AppSettings; |
||||||
|
import java.util.HashMap; |
||||||
|
import java.util.concurrent.ConcurrentLinkedQueue; |
||||||
|
import java.util.logging.Level; |
||||||
|
import java.util.logging.Logger; |
||||||
|
|
||||||
|
/** |
||||||
|
* AndroidTouchInput is the base class that receives touch inputs from the |
||||||
|
* Android system and creates the TouchEvents for jME. This class is designed |
||||||
|
* to handle the base touch events for Android rev 9 (Android 2.3). This is |
||||||
|
* extended by other classes to add features that were introducted after |
||||||
|
* Android rev 9. |
||||||
|
* |
||||||
|
* @author iwgeric |
||||||
|
*/ |
||||||
|
public class AndroidTouchInput implements TouchInput { |
||||||
|
private static final Logger logger = Logger.getLogger(AndroidTouchInput.class.getName()); |
||||||
|
|
||||||
|
private boolean mouseEventsEnabled = true; |
||||||
|
private boolean mouseEventsInvertX = false; |
||||||
|
private boolean mouseEventsInvertY = false; |
||||||
|
private boolean keyboardEventsEnabled = false; |
||||||
|
private boolean dontSendHistory = false; |
||||||
|
|
||||||
|
protected int numPointers = 0; |
||||||
|
final private HashMap<Integer, Vector2f> lastPositions = new HashMap<Integer, Vector2f>(); |
||||||
|
final private ConcurrentLinkedQueue<InputEvent> inputEventQueue = new ConcurrentLinkedQueue<InputEvent>(); |
||||||
|
private final static int MAX_TOUCH_EVENTS = 1024; |
||||||
|
private final TouchEventPool touchEventPool = new TouchEventPool(MAX_TOUCH_EVENTS); |
||||||
|
private float scaleX = 1f; |
||||||
|
private float scaleY = 1f; |
||||||
|
|
||||||
|
private boolean initialized = false; |
||||||
|
private RawInputListener listener = null; |
||||||
|
|
||||||
|
private GestureDetector gestureDetector; |
||||||
|
private ScaleGestureDetector scaleDetector; |
||||||
|
|
||||||
|
protected AndroidInputHandler androidInput; |
||||||
|
|
||||||
|
public AndroidTouchInput(AndroidInputHandler androidInput) { |
||||||
|
this.androidInput = androidInput; |
||||||
|
} |
||||||
|
|
||||||
|
public GestureDetector getGestureDetector() { |
||||||
|
return gestureDetector; |
||||||
|
} |
||||||
|
|
||||||
|
public void setGestureDetector(GestureDetector gestureDetector) { |
||||||
|
this.gestureDetector = gestureDetector; |
||||||
|
} |
||||||
|
|
||||||
|
public ScaleGestureDetector getScaleDetector() { |
||||||
|
return scaleDetector; |
||||||
|
} |
||||||
|
|
||||||
|
public void setScaleDetector(ScaleGestureDetector scaleDetector) { |
||||||
|
this.scaleDetector = scaleDetector; |
||||||
|
} |
||||||
|
|
||||||
|
public float invertX(float origX) { |
||||||
|
return getJmeX(androidInput.getView().getWidth()) - origX; |
||||||
|
} |
||||||
|
|
||||||
|
public float invertY(float origY) { |
||||||
|
return getJmeY(androidInput.getView().getHeight()) - origY; |
||||||
|
} |
||||||
|
|
||||||
|
public float getJmeX(float origX) { |
||||||
|
return origX * scaleX; |
||||||
|
} |
||||||
|
|
||||||
|
public float getJmeY(float origY) { |
||||||
|
return origY * scaleY; |
||||||
|
} |
||||||
|
|
||||||
|
public void loadSettings(AppSettings settings) { |
||||||
|
keyboardEventsEnabled = settings.isEmulateKeyboard(); |
||||||
|
mouseEventsEnabled = settings.isEmulateMouse(); |
||||||
|
mouseEventsInvertX = settings.isEmulateMouseFlipX(); |
||||||
|
mouseEventsInvertY = settings.isEmulateMouseFlipY(); |
||||||
|
|
||||||
|
// view width and height are 0 until the view is displayed on the screen
|
||||||
|
if (androidInput.getView().getWidth() != 0 && androidInput.getView().getHeight() != 0) { |
||||||
|
scaleX = (float)settings.getWidth() / (float)androidInput.getView().getWidth(); |
||||||
|
scaleY = (float)settings.getHeight() / (float)androidInput.getView().getHeight(); |
||||||
|
} |
||||||
|
logger.log(Level.FINE, "Setting input scaling, scaleX: {0}, scaleY: {1}", |
||||||
|
new Object[]{scaleX, scaleY}); |
||||||
|
|
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
protected int getPointerIndex(MotionEvent event) { |
||||||
|
return (event.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) |
||||||
|
>> MotionEvent.ACTION_POINTER_INDEX_SHIFT; |
||||||
|
} |
||||||
|
|
||||||
|
protected int getPointerId(MotionEvent event) { |
||||||
|
return event.getPointerId(getPointerIndex(event)); |
||||||
|
} |
||||||
|
|
||||||
|
protected int getAction(MotionEvent event) { |
||||||
|
return event.getAction() & MotionEvent.ACTION_MASK; |
||||||
|
} |
||||||
|
|
||||||
|
public boolean onTouch(MotionEvent event) { |
||||||
|
if (!isInitialized()) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
boolean bWasHandled = false; |
||||||
|
TouchEvent touch = null; |
||||||
|
// System.out.println("native : " + event.getAction());
|
||||||
|
int action = getAction(event); |
||||||
|
int pointerIndex = getPointerIndex(event); |
||||||
|
int pointerId = getPointerId(event); |
||||||
|
Vector2f lastPos = lastPositions.get(pointerId); |
||||||
|
float jmeX; |
||||||
|
float jmeY; |
||||||
|
|
||||||
|
numPointers = event.getPointerCount(); |
||||||
|
|
||||||
|
// final int historySize = event.getHistorySize();
|
||||||
|
//final int pointerCount = event.getPointerCount();
|
||||||
|
switch (getAction(event)) { |
||||||
|
case MotionEvent.ACTION_POINTER_DOWN: |
||||||
|
case MotionEvent.ACTION_DOWN: |
||||||
|
jmeX = getJmeX(event.getX(pointerIndex)); |
||||||
|
jmeY = invertY(getJmeY(event.getY(pointerIndex))); |
||||||
|
touch = getFreeTouchEvent(); |
||||||
|
touch.set(TouchEvent.Type.DOWN, jmeX, jmeY, 0, 0); |
||||||
|
touch.setPointerId(pointerId); |
||||||
|
touch.setTime(event.getEventTime()); |
||||||
|
touch.setPressure(event.getPressure(pointerIndex)); |
||||||
|
|
||||||
|
lastPos = new Vector2f(jmeX, jmeY); |
||||||
|
lastPositions.put(pointerId, lastPos); |
||||||
|
|
||||||
|
addEvent(touch); |
||||||
|
addEvent(generateMouseEvent(touch)); |
||||||
|
|
||||||
|
bWasHandled = true; |
||||||
|
break; |
||||||
|
case MotionEvent.ACTION_POINTER_UP: |
||||||
|
case MotionEvent.ACTION_CANCEL: |
||||||
|
case MotionEvent.ACTION_UP: |
||||||
|
jmeX = getJmeX(event.getX(pointerIndex)); |
||||||
|
jmeY = invertY(getJmeY(event.getY(pointerIndex))); |
||||||
|
touch = getFreeTouchEvent(); |
||||||
|
touch.set(TouchEvent.Type.UP, jmeX, jmeY, 0, 0); |
||||||
|
touch.setPointerId(pointerId); |
||||||
|
touch.setTime(event.getEventTime()); |
||||||
|
touch.setPressure(event.getPressure(pointerIndex)); |
||||||
|
lastPositions.remove(pointerId); |
||||||
|
|
||||||
|
addEvent(touch); |
||||||
|
addEvent(generateMouseEvent(touch)); |
||||||
|
|
||||||
|
bWasHandled = true; |
||||||
|
break; |
||||||
|
case MotionEvent.ACTION_MOVE: |
||||||
|
// Convert all pointers into events
|
||||||
|
for (int p = 0; p < event.getPointerCount(); p++) { |
||||||
|
jmeX = getJmeX(event.getX(p)); |
||||||
|
jmeY = invertY(getJmeY(event.getY(p))); |
||||||
|
lastPos = lastPositions.get(event.getPointerId(p)); |
||||||
|
if (lastPos == null) { |
||||||
|
lastPos = new Vector2f(jmeX, jmeY); |
||||||
|
lastPositions.put(event.getPointerId(p), lastPos); |
||||||
|
} |
||||||
|
|
||||||
|
float dX = jmeX - lastPos.x; |
||||||
|
float dY = jmeY - lastPos.y; |
||||||
|
if (dX != 0 || dY != 0) { |
||||||
|
touch = getFreeTouchEvent(); |
||||||
|
touch.set(TouchEvent.Type.MOVE, jmeX, jmeY, dX, dY); |
||||||
|
touch.setPointerId(event.getPointerId(p)); |
||||||
|
touch.setTime(event.getEventTime()); |
||||||
|
touch.setPressure(event.getPressure(p)); |
||||||
|
lastPos.set(jmeX, jmeY); |
||||||
|
|
||||||
|
addEvent(touch); |
||||||
|
addEvent(generateMouseEvent(touch)); |
||||||
|
|
||||||
|
bWasHandled = true; |
||||||
|
} |
||||||
|
} |
||||||
|
break; |
||||||
|
case MotionEvent.ACTION_OUTSIDE: |
||||||
|
break; |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
// Try to detect gestures
|
||||||
|
if (gestureDetector != null) { |
||||||
|
gestureDetector.onTouchEvent(event); |
||||||
|
} |
||||||
|
if (scaleDetector != null) { |
||||||
|
scaleDetector.onTouchEvent(event); |
||||||
|
} |
||||||
|
|
||||||
|
return bWasHandled; |
||||||
|
} |
||||||
|
|
||||||
|
// TODO: Ring Buffer for mouse events?
|
||||||
|
public InputEvent generateMouseEvent(TouchEvent event) { |
||||||
|
InputEvent inputEvent = null; |
||||||
|
int newX; |
||||||
|
int newY; |
||||||
|
int newDX; |
||||||
|
int newDY; |
||||||
|
|
||||||
|
// MouseEvents do not support multi-touch, so only evaluate 1 finger pointer events
|
||||||
|
if (!isSimulateMouse() || numPointers > 1) { |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
if (isMouseEventsInvertX()) { |
||||||
|
newX = (int) (invertX(event.getX())); |
||||||
|
newDX = (int)event.getDeltaX() * -1; |
||||||
|
} else { |
||||||
|
newX = (int) event.getX(); |
||||||
|
newDX = (int)event.getDeltaX(); |
||||||
|
} |
||||||
|
|
||||||
|
if (isMouseEventsInvertY()) { |
||||||
|
newY = (int) (invertY(event.getY())); |
||||||
|
newDY = (int)event.getDeltaY() * -1; |
||||||
|
} else { |
||||||
|
newY = (int) event.getY(); |
||||||
|
newDY = (int)event.getDeltaY(); |
||||||
|
} |
||||||
|
|
||||||
|
switch (event.getType()) { |
||||||
|
case DOWN: |
||||||
|
// Handle mouse down event
|
||||||
|
inputEvent = new MouseButtonEvent(0, true, newX, newY); |
||||||
|
inputEvent.setTime(event.getTime()); |
||||||
|
break; |
||||||
|
|
||||||
|
case UP: |
||||||
|
// Handle mouse up event
|
||||||
|
inputEvent = new MouseButtonEvent(0, false, newX, newY); |
||||||
|
inputEvent.setTime(event.getTime()); |
||||||
|
break; |
||||||
|
|
||||||
|
case HOVER_MOVE: |
||||||
|
case MOVE: |
||||||
|
inputEvent = new MouseMotionEvent(newX, newY, newDX, newDY, (int)event.getScaleSpan(), (int)event.getDeltaScaleSpan()); |
||||||
|
inputEvent.setTime(event.getTime()); |
||||||
|
break; |
||||||
|
} |
||||||
|
|
||||||
|
return inputEvent; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public boolean onKey(KeyEvent event) { |
||||||
|
if (!isInitialized()) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
TouchEvent evt; |
||||||
|
// TODO: get touch event from pool
|
||||||
|
if (event.getAction() == KeyEvent.ACTION_DOWN) { |
||||||
|
evt = new TouchEvent(); |
||||||
|
evt.set(TouchEvent.Type.KEY_DOWN); |
||||||
|
evt.setKeyCode(event.getKeyCode()); |
||||||
|
evt.setCharacters(event.getCharacters()); |
||||||
|
evt.setTime(event.getEventTime()); |
||||||
|
|
||||||
|
// Send the event
|
||||||
|
addEvent(evt); |
||||||
|
|
||||||
|
} else if (event.getAction() == KeyEvent.ACTION_UP) { |
||||||
|
evt = new TouchEvent(); |
||||||
|
evt.set(TouchEvent.Type.KEY_UP); |
||||||
|
evt.setKeyCode(event.getKeyCode()); |
||||||
|
evt.setCharacters(event.getCharacters()); |
||||||
|
evt.setTime(event.getEventTime()); |
||||||
|
|
||||||
|
// Send the event
|
||||||
|
addEvent(evt); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
if (isSimulateKeyboard()) { |
||||||
|
KeyInputEvent kie; |
||||||
|
char unicodeChar = (char)event.getUnicodeChar(); |
||||||
|
int jmeKeyCode = AndroidKeyMapping.getJmeKey(event.getKeyCode()); |
||||||
|
|
||||||
|
boolean pressed = event.getAction() == KeyEvent.ACTION_DOWN; |
||||||
|
boolean repeating = pressed && event.getRepeatCount() > 0; |
||||||
|
|
||||||
|
kie = new KeyInputEvent(jmeKeyCode, unicodeChar, pressed, repeating); |
||||||
|
kie.setTime(event.getEventTime()); |
||||||
|
addEvent(kie); |
||||||
|
// logger.log(Level.FINE, "onKey keyCode: {0}, jmeKeyCode: {1}, pressed: {2}, repeating: {3}",
|
||||||
|
// new Object[]{event.getKeyCode(), jmeKeyCode, pressed, repeating});
|
||||||
|
// logger.log(Level.FINE, "creating KeyInputEvent: {0}", kie);
|
||||||
|
} |
||||||
|
|
||||||
|
// consume all keys ourself except Volume Up/Down and Menu
|
||||||
|
// Don't do Menu so that typical Android Menus can be created and used
|
||||||
|
// by the user in MainActivity
|
||||||
|
if ((event.getKeyCode() == KeyEvent.KEYCODE_VOLUME_UP) || |
||||||
|
(event.getKeyCode() == KeyEvent.KEYCODE_VOLUME_DOWN) || |
||||||
|
(event.getKeyCode() == KeyEvent.KEYCODE_MENU)) { |
||||||
|
return false; |
||||||
|
} else { |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// -----------------------------------------
|
||||||
|
// JME3 Input interface
|
||||||
|
@Override |
||||||
|
public void initialize() { |
||||||
|
touchEventPool.initialize(); |
||||||
|
|
||||||
|
initialized = true; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void destroy() { |
||||||
|
initialized = false; |
||||||
|
|
||||||
|
touchEventPool.destroy(); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean isInitialized() { |
||||||
|
return initialized; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void setInputListener(RawInputListener listener) { |
||||||
|
this.listener = listener; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public long getInputTimeNanos() { |
||||||
|
return System.nanoTime(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void update() { |
||||||
|
if (listener != null) { |
||||||
|
InputEvent inputEvent; |
||||||
|
|
||||||
|
while ((inputEvent = inputEventQueue.poll()) != null) { |
||||||
|
if (inputEvent instanceof TouchEvent) { |
||||||
|
listener.onTouchEvent((TouchEvent)inputEvent); |
||||||
|
} else if (inputEvent instanceof MouseButtonEvent) { |
||||||
|
listener.onMouseButtonEvent((MouseButtonEvent)inputEvent); |
||||||
|
} else if (inputEvent instanceof MouseMotionEvent) { |
||||||
|
listener.onMouseMotionEvent((MouseMotionEvent)inputEvent); |
||||||
|
} else if (inputEvent instanceof KeyInputEvent) { |
||||||
|
listener.onKeyEvent((KeyInputEvent)inputEvent); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// -----------------------------------------
|
||||||
|
|
||||||
|
public TouchEvent getFreeTouchEvent() { |
||||||
|
return touchEventPool.getNextFreeEvent(); |
||||||
|
} |
||||||
|
|
||||||
|
public void addEvent(InputEvent event) { |
||||||
|
if (event == null) { |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
logger.log(Level.INFO, "event: {0}", event); |
||||||
|
|
||||||
|
inputEventQueue.add(event); |
||||||
|
if (event instanceof TouchEvent) { |
||||||
|
touchEventPool.storeEvent((TouchEvent)event); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void setSimulateMouse(boolean simulate) { |
||||||
|
this.mouseEventsEnabled = simulate; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean isSimulateMouse() { |
||||||
|
return mouseEventsEnabled; |
||||||
|
} |
||||||
|
|
||||||
|
public boolean isMouseEventsInvertX() { |
||||||
|
return mouseEventsInvertX; |
||||||
|
} |
||||||
|
|
||||||
|
public boolean isMouseEventsInvertY() { |
||||||
|
return mouseEventsInvertY; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void setSimulateKeyboard(boolean simulate) { |
||||||
|
this.keyboardEventsEnabled = simulate; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean isSimulateKeyboard() { |
||||||
|
return keyboardEventsEnabled; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void setOmitHistoricEvents(boolean dontSendHistory) { |
||||||
|
this.dontSendHistory = dontSendHistory; |
||||||
|
} |
||||||
|
|
||||||
|
} |
Loading…
Reference in new issue