commit
013f67ee89
@ -0,0 +1,13 @@ |
|||||||
|
apply plugin: 'com.android.application' |
||||||
|
|
||||||
|
group = 'com.jme3' |
||||||
|
version = jmeVersion + '-' + jmeVersionTag |
||||||
|
|
||||||
|
sourceCompatibility = '1.6' |
||||||
|
|
||||||
|
repositories { |
||||||
|
mavenCentral() |
||||||
|
maven { |
||||||
|
url "http://nifty-gui.sourceforge.net/nifty-maven-repo" |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,40 @@ |
|||||||
|
dependencies { |
||||||
|
compile project(':jme3-core') |
||||||
|
compile project(':jme3-android') |
||||||
|
compile project(':jme3-effects') |
||||||
|
compile project(':jme3-bullet') |
||||||
|
compile project(':jme3-bullet-native-android') |
||||||
|
compile project(':jme3-networking') |
||||||
|
compile project(':jme3-niftygui') |
||||||
|
compile project(':jme3-plugins') |
||||||
|
compile project(':jme3-terrain') |
||||||
|
compile project(':jme3-testdata') |
||||||
|
} |
||||||
|
|
||||||
|
android { |
||||||
|
compileSdkVersion 10 |
||||||
|
buildToolsVersion "22.0.1" |
||||||
|
|
||||||
|
lintOptions { |
||||||
|
// Fix nifty gui referencing "java.awt" package. |
||||||
|
disable 'InvalidPackage' |
||||||
|
} |
||||||
|
|
||||||
|
defaultConfig { |
||||||
|
applicationId "com.jme3.android" |
||||||
|
minSdkVersion 10 // Android 2.3 GINGERBREAD |
||||||
|
targetSdkVersion 22 // Android 5.1 LOLLIPOP |
||||||
|
versionCode 1 |
||||||
|
versionName "1.0" // TODO: from settings.gradle |
||||||
|
} |
||||||
|
|
||||||
|
buildTypes { |
||||||
|
release { |
||||||
|
minifyEnabled false |
||||||
|
} |
||||||
|
debug { |
||||||
|
applicationIdSuffix ".debug" |
||||||
|
debuggable true |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,20 @@ |
|||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android" |
||||||
|
package="com.jme3.android"> |
||||||
|
|
||||||
|
<!-- Tell the system that you need ES 2.0. --> |
||||||
|
<uses-feature android:glEsVersion="0x00020000" android:required="true" /> |
||||||
|
|
||||||
|
<!-- Tell the system that you need distinct touches (for the zoom gesture). --> |
||||||
|
<uses-feature android:name="android.hardware.touchscreen.multitouch.distinct" android:required="true" /> |
||||||
|
|
||||||
|
<application android:label="@string/app_name" android:allowBackup="true"> |
||||||
|
<activity android:name="jme3test.android.TestChooserAndroid" |
||||||
|
android:label="@string/app_name"> |
||||||
|
<intent-filter> |
||||||
|
<action android:name="android.intent.action.MAIN" /> |
||||||
|
<category android:name="android.intent.category.LAUNCHER" /> |
||||||
|
</intent-filter> |
||||||
|
</activity> |
||||||
|
</application> |
||||||
|
|
||||||
|
</manifest> |
@ -0,0 +1,12 @@ |
|||||||
|
package jme3test.android; |
||||||
|
|
||||||
|
import android.content.pm.ActivityInfo; |
||||||
|
import android.app.*; |
||||||
|
import android.os.Bundle; |
||||||
|
|
||||||
|
public class TestChooserAndroid extends Activity { |
||||||
|
@Override |
||||||
|
public void onCreate(Bundle savedInstanceState) { |
||||||
|
super.onCreate(savedInstanceState); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,6 @@ |
|||||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||||
|
<resources> |
||||||
|
<string name="app_name">JMEAndroidTest</string> |
||||||
|
<string name="about">About</string> |
||||||
|
<string name="quit">Quit</string> |
||||||
|
</resources> |
File diff suppressed because it is too large
Load Diff
@ -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; |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -1,265 +1,238 @@ |
|||||||
/* |
/* |
||||||
* Copyright (c) 2009-2012 jMonkeyEngine |
* Copyright (c) 2009-2012 jMonkeyEngine |
||||||
* All rights reserved. |
* All rights reserved. |
||||||
* |
* |
||||||
* Redistribution and use in source and binary forms, with or without |
* Redistribution and use in source and binary forms, with or without |
||||||
* modification, are permitted provided that the following conditions are |
* modification, are permitted provided that the following conditions are |
||||||
* met: |
* met: |
||||||
* |
* |
||||||
* * Redistributions of source code must retain the above copyright |
* * Redistributions of source code must retain the above copyright |
||||||
* notice, this list of conditions and the following disclaimer. |
* notice, this list of conditions and the following disclaimer. |
||||||
* |
* |
||||||
* * Redistributions in binary form must reproduce the above copyright |
* * Redistributions in binary form must reproduce the above copyright |
||||||
* notice, this list of conditions and the following disclaimer in the |
* notice, this list of conditions and the following disclaimer in the |
||||||
* documentation and/or other materials provided with the distribution. |
* documentation and/or other materials provided with the distribution. |
||||||
* |
* |
||||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors |
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors |
||||||
* may be used to endorse or promote products derived from this software |
* may be used to endorse or promote products derived from this software |
||||||
* without specific prior written permission. |
* without specific prior written permission. |
||||||
* |
* |
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
||||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
||||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
||||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
||||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
||||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
*/ |
*/ |
||||||
|
|
||||||
package com.jme3.input.android; |
package com.jme3.input.android; |
||||||
|
|
||||||
import android.opengl.GLSurfaceView; |
import android.opengl.GLSurfaceView; |
||||||
import android.os.Build; |
import android.view.GestureDetector; |
||||||
import android.view.View; |
import android.view.InputDevice; |
||||||
import com.jme3.input.RawInputListener; |
import android.view.KeyEvent; |
||||||
import com.jme3.input.TouchInput; |
import android.view.MotionEvent; |
||||||
import com.jme3.input.event.InputEvent; |
import android.view.ScaleGestureDetector; |
||||||
import com.jme3.input.event.KeyInputEvent; |
import android.view.View; |
||||||
import com.jme3.input.event.MouseButtonEvent; |
import com.jme3.input.JoyInput; |
||||||
import com.jme3.input.event.MouseMotionEvent; |
import com.jme3.input.TouchInput; |
||||||
import com.jme3.input.event.TouchEvent; |
import com.jme3.system.AppSettings; |
||||||
import com.jme3.system.AppSettings; |
import java.util.logging.Level; |
||||||
import java.util.concurrent.ConcurrentLinkedQueue; |
import java.util.logging.Logger; |
||||||
import java.util.logging.Level; |
|
||||||
import java.util.logging.Logger; |
/** |
||||||
|
* <code>AndroidInput</code> is the main class that connects the Android system |
||||||
/** |
* inputs to jME. It receives the inputs from the Android View and passes them |
||||||
* <code>AndroidInput</code> is the main class that connects the Android system |
* to the appropriate classes based on the source of the input.</br> |
||||||
* inputs to jME. It serves as the manager that gathers inputs from the various |
* This class is to be extended when new functionality is released in Android. |
||||||
* Android input methods and provides them to jME's <code>InputManager</code>. |
* |
||||||
* |
* @author iwgeric |
||||||
* @author iwgeric |
*/ |
||||||
*/ |
public class AndroidInputHandler implements View.OnTouchListener, |
||||||
public class AndroidInputHandler implements TouchInput { |
View.OnKeyListener { |
||||||
private static final Logger logger = Logger.getLogger(AndroidInputHandler.class.getName()); |
|
||||||
|
private static final Logger logger = Logger.getLogger(AndroidInputHandler.class.getName()); |
||||||
// Custom settings
|
|
||||||
private boolean mouseEventsEnabled = true; |
protected GLSurfaceView view; |
||||||
private boolean mouseEventsInvertX = false; |
protected AndroidTouchInput touchInput; |
||||||
private boolean mouseEventsInvertY = false; |
protected AndroidJoyInput joyInput; |
||||||
private boolean keyboardEventsEnabled = false; |
|
||||||
private boolean joystickEventsEnabled = false; |
|
||||||
private boolean dontSendHistory = false; |
public AndroidInputHandler() { |
||||||
|
touchInput = new AndroidTouchInput(this); |
||||||
|
joyInput = new AndroidJoyInput(this); |
||||||
// Internal
|
} |
||||||
private GLSurfaceView view; |
|
||||||
private AndroidTouchHandler touchHandler; |
public void setView(View view) { |
||||||
private AndroidKeyHandler keyHandler; |
if (this.view != null && view != null && this.view.equals(view)) { |
||||||
private AndroidGestureHandler gestureHandler; |
return; |
||||||
private boolean initialized = false; |
} |
||||||
private RawInputListener listener = null; |
|
||||||
private ConcurrentLinkedQueue<InputEvent> inputEventQueue = new ConcurrentLinkedQueue<InputEvent>(); |
if (this.view != null) { |
||||||
private final static int MAX_TOUCH_EVENTS = 1024; |
removeListeners(this.view); |
||||||
private final TouchEventPool touchEventPool = new TouchEventPool(MAX_TOUCH_EVENTS); |
} |
||||||
private float scaleX = 1f; |
|
||||||
private float scaleY = 1f; |
this.view = (GLSurfaceView)view; |
||||||
|
|
||||||
|
if (this.view != null) { |
||||||
public AndroidInputHandler() { |
addListeners(this.view); |
||||||
int buildVersion = Build.VERSION.SDK_INT; |
} |
||||||
logger.log(Level.INFO, "Android Build Version: {0}", buildVersion); |
|
||||||
if (buildVersion >= 14) { |
joyInput.setView((GLSurfaceView)view); |
||||||
// add support for onHover and GenericMotionEvent (ie. gamepads)
|
} |
||||||
gestureHandler = new AndroidGestureHandler(this); |
|
||||||
touchHandler = new AndroidTouchHandler14(this, gestureHandler); |
public View getView() { |
||||||
keyHandler = new AndroidKeyHandler(this); |
return view; |
||||||
} else if (buildVersion >= 8){ |
} |
||||||
gestureHandler = new AndroidGestureHandler(this); |
|
||||||
touchHandler = new AndroidTouchHandler(this, gestureHandler); |
protected void removeListeners(GLSurfaceView view) { |
||||||
keyHandler = new AndroidKeyHandler(this); |
view.setOnTouchListener(null); |
||||||
} |
view.setOnKeyListener(null); |
||||||
} |
touchInput.setGestureDetector(null); |
||||||
|
touchInput.setScaleDetector(null); |
||||||
public AndroidInputHandler(AndroidTouchHandler touchInput, |
} |
||||||
AndroidKeyHandler keyInput, AndroidGestureHandler gestureHandler) { |
|
||||||
this.touchHandler = touchInput; |
protected void addListeners(GLSurfaceView view) { |
||||||
this.keyHandler = keyInput; |
view.setOnTouchListener(this); |
||||||
this.gestureHandler = gestureHandler; |
view.setOnKeyListener(this); |
||||||
} |
AndroidGestureProcessor gestureHandler = new AndroidGestureProcessor(touchInput); |
||||||
|
touchInput.setGestureDetector(new GestureDetector( |
||||||
public void setView(View view) { |
view.getContext(), gestureHandler)); |
||||||
if (touchHandler != null) { |
touchInput.setScaleDetector(new ScaleGestureDetector( |
||||||
touchHandler.setView(view); |
view.getContext(), gestureHandler)); |
||||||
} |
} |
||||||
if (keyHandler != null) { |
|
||||||
keyHandler.setView(view); |
public void loadSettings(AppSettings settings) { |
||||||
} |
touchInput.loadSettings(settings); |
||||||
if (gestureHandler != null) { |
} |
||||||
gestureHandler.setView(view); |
|
||||||
} |
public TouchInput getTouchInput() { |
||||||
this.view = (GLSurfaceView)view; |
return touchInput; |
||||||
} |
} |
||||||
|
|
||||||
public View getView() { |
public JoyInput getJoyInput() { |
||||||
return view; |
return joyInput; |
||||||
} |
} |
||||||
|
|
||||||
public float invertX(float origX) { |
/* |
||||||
return getJmeX(view.getWidth()) - origX; |
* 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. |
||||||
public float invertY(float origY) { |
* If the input is from a gamepad or joystick source, the event is sent |
||||||
return getJmeY(view.getHeight()) - origY; |
* to the JoyInput class to convert the event into jME joystick events. |
||||||
} |
* </br> |
||||||
|
* If the input is from a touchscreen source, the event is sent to the |
||||||
public float getJmeX(float origX) { |
* TouchProcessor to convert the event into touch events. |
||||||
return origX * scaleX; |
* The TouchProcessor also converts the events into Mouse and Key events |
||||||
} |
* if AppSettings is set to simulate Mouse or Keyboard events. |
||||||
|
* |
||||||
public float getJmeY(float origY) { |
* Android reports the source as a bitmask as shown below.</br> |
||||||
return origY * scaleY; |
* |
||||||
} |
* InputDevice Sources |
||||||
|
* 0000 0000 0000 0000 0000 0000 0000 0000 - 32 bit bitmask |
||||||
public void loadSettings(AppSettings settings) { |
* |
||||||
keyboardEventsEnabled = settings.isEmulateKeyboard(); |
* 0000 0000 0000 0000 0000 0000 1111 1111 - SOURCE_CLASS_MASK (0x000000ff) |
||||||
mouseEventsEnabled = settings.isEmulateMouse(); |
* 0000 0000 0000 0000 0000 0000 0000 0000 - SOURCE_CLASS_NONE (0x00000000) |
||||||
mouseEventsInvertX = settings.isEmulateMouseFlipX(); |
* 0000 0000 0000 0000 0000 0000 0000 0001 - SOURCE_CLASS_BUTTON (0x00000001) |
||||||
mouseEventsInvertY = settings.isEmulateMouseFlipY(); |
* 0000 0000 0000 0000 0000 0000 0000 0010 - SOURCE_CLASS_POINTER (0x00000002) |
||||||
joystickEventsEnabled = settings.useJoysticks(); |
* 0000 0000 0000 0000 0000 0000 0000 0100 - SOURCE_CLASS_TRACKBALL (0x00000004) |
||||||
|
* 0000 0000 0000 0000 0000 0000 0000 1000 - SOURCE_CLASS_POSITION (0x00000008) |
||||||
// view width and height are 0 until the view is displayed on the screen
|
* 0000 0000 0000 0000 0000 0000 0001 0000 - SOURCE_CLASS_JOYSTICK (0x00000010) |
||||||
if (view.getWidth() != 0 && view.getHeight() != 0) { |
* |
||||||
scaleX = (float)settings.getWidth() / (float)view.getWidth(); |
* 1111 1111 1111 1111 1111 1111 0000 0000 - Source_Any (0xffffff00) |
||||||
scaleY = (float)settings.getHeight() / (float)view.getHeight(); |
* 0000 0000 0000 0000 0000 0000 0000 0000 - SOURCE_UNKNOWN (0x00000000) |
||||||
} |
* 0000 0000 0000 0000 0000 0001 0000 0001 - SOURCE_KEYBOARD (0x00000101) |
||||||
logger.log(Level.FINE, "Setting input scaling, scaleX: {0}, scaleY: {1}", |
* 0000 0000 0000 0000 0000 0010 0000 0001 - SOURCE_DPAD (0x00000201) |
||||||
new Object[]{scaleX, scaleY}); |
* 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) |
||||||
// JME3 Input interface
|
* 0000 0000 0001 0000 0000 0000 0000 1000 - SOURCE_TOUCHPAD (0x00100008) |
||||||
@Override |
* 0000 0000 0010 0000 0000 0000 0000 0000 - SOURCE_TOUCH_NAVIGATION (0x00200000) |
||||||
public void initialize() { |
* 0000 0001 0000 0000 0000 0000 0001 0000 - SOURCE_JOYSTICK (0x01000010) |
||||||
touchEventPool.initialize(); |
* 0000 0010 0000 0000 0000 0000 0000 0001 - SOURCE_HDMI (0x02000001) |
||||||
if (touchHandler != null) { |
* |
||||||
touchHandler.initialize(); |
* Example values reported by Android for Source |
||||||
} |
* 4,098 = 0x00001002 = |
||||||
if (keyHandler != null) { |
* 0000 0000 0000 0000 0001 0000 0000 0010 - SOURCE_CLASS_POINTER |
||||||
keyHandler.initialize(); |
* SOURCE_TOUCHSCREEN |
||||||
} |
* 1,281 = 0x00000501 = |
||||||
if (gestureHandler != null) { |
* 0000 0000 0000 0000 0000 0101 0000 0001 - SOURCE_CLASS_BUTTON |
||||||
gestureHandler.initialize(); |
* SOURCE_KEYBOARD |
||||||
} |
* SOURCE_GAMEPAD |
||||||
|
* 16,777,232 = 0x01000010 = |
||||||
initialized = true; |
* 0000 0001 0000 0000 0000 0000 0001 0000 - SOURCE_CLASS_JOYSTICK |
||||||
} |
* SOURCE_JOYSTICK |
||||||
|
* |
||||||
@Override |
* 16,778,513 = 0x01000511 = |
||||||
public void destroy() { |
* 0000 0001 0000 0000 0000 0101 0001 0001 - SOURCE_CLASS_BUTTON |
||||||
initialized = false; |
* SOURCE_CLASS_JOYSTICK |
||||||
|
* SOURCE_GAMEPAD |
||||||
touchEventPool.destroy(); |
* SOURCE_KEYBOARD |
||||||
if (touchHandler != null) { |
* SOURCE_JOYSTICK |
||||||
touchHandler.destroy(); |
* |
||||||
} |
* 257 = 0x00000101 = |
||||||
if (keyHandler != null) { |
* 0000 0000 0000 0000 0000 0001 0000 0001 - SOURCE_CLASS_BUTTON |
||||||
keyHandler.destroy(); |
* SOURCE_KEYBOARD |
||||||
} |
* |
||||||
if (gestureHandler != null) { |
* |
||||||
gestureHandler.destroy(); |
* |
||||||
} |
*/ |
||||||
|
|
||||||
setView(null); |
|
||||||
} |
@Override |
||||||
|
public boolean onTouch(View view, MotionEvent event) { |
||||||
@Override |
if (view != getView()) { |
||||||
public boolean isInitialized() { |
return false; |
||||||
return initialized; |
} |
||||||
} |
|
||||||
|
boolean consumed = false; |
||||||
@Override |
|
||||||
public void setInputListener(RawInputListener listener) { |
int source = event.getSource(); |
||||||
this.listener = listener; |
// logger.log(Level.INFO, "onTouch source: {0}", source);
|
||||||
} |
|
||||||
|
boolean isTouch = ((source & InputDevice.SOURCE_TOUCHSCREEN) == InputDevice.SOURCE_TOUCHSCREEN); |
||||||
@Override |
// logger.log(Level.INFO, "onTouch source: {0}, isTouch: {1}",
|
||||||
public long getInputTimeNanos() { |
// new Object[]{source, isTouch});
|
||||||
return System.nanoTime(); |
|
||||||
} |
if (isTouch && touchInput != null) { |
||||||
|
// send the event to the touch processor
|
||||||
public void update() { |
consumed = touchInput.onTouch(event); |
||||||
if (listener != null) { |
} |
||||||
InputEvent inputEvent; |
|
||||||
|
return consumed; |
||||||
while ((inputEvent = inputEventQueue.poll()) != null) { |
|
||||||
if (inputEvent instanceof TouchEvent) { |
} |
||||||
listener.onTouchEvent((TouchEvent)inputEvent); |
|
||||||
} else if (inputEvent instanceof MouseButtonEvent) { |
@Override |
||||||
listener.onMouseButtonEvent((MouseButtonEvent)inputEvent); |
public boolean onKey(View view, int keyCode, KeyEvent event) { |
||||||
} else if (inputEvent instanceof MouseMotionEvent) { |
if (view != getView()) { |
||||||
listener.onMouseMotionEvent((MouseMotionEvent)inputEvent); |
return false; |
||||||
} else if (inputEvent instanceof KeyInputEvent) { |
} |
||||||
listener.onKeyEvent((KeyInputEvent)inputEvent); |
|
||||||
} |
boolean consumed = false; |
||||||
} |
|
||||||
} |
int source = event.getSource(); |
||||||
} |
// logger.log(Level.INFO, "onKey source: {0}", source);
|
||||||
|
|
||||||
// -----------------------------------------
|
boolean isTouch = |
||||||
|
((source & InputDevice.SOURCE_TOUCHSCREEN) == InputDevice.SOURCE_TOUCHSCREEN) || |
||||||
public TouchEvent getFreeTouchEvent() { |
((source & InputDevice.SOURCE_KEYBOARD) == InputDevice.SOURCE_KEYBOARD); |
||||||
return touchEventPool.getNextFreeEvent(); |
// logger.log(Level.INFO, "onKey source: {0}, isTouch: {1}",
|
||||||
} |
// new Object[]{source, isTouch});
|
||||||
|
|
||||||
public void addEvent(InputEvent event) { |
if (touchInput != null) { |
||||||
inputEventQueue.add(event); |
consumed = touchInput.onKey(event); |
||||||
if (event instanceof TouchEvent) { |
} |
||||||
touchEventPool.storeEvent((TouchEvent)event); |
|
||||||
} |
return consumed; |
||||||
} |
|
||||||
|
} |
||||||
public void setSimulateMouse(boolean simulate) { |
|
||||||
this.mouseEventsEnabled = simulate; |
} |
||||||
} |
|
||||||
|
|
||||||
public boolean isSimulateMouse() { |
|
||||||
return mouseEventsEnabled; |
|
||||||
} |
|
||||||
|
|
||||||
public boolean isMouseEventsInvertX() { |
|
||||||
return mouseEventsInvertX; |
|
||||||
} |
|
||||||
|
|
||||||
public boolean isMouseEventsInvertY() { |
|
||||||
return mouseEventsInvertY; |
|
||||||
} |
|
||||||
|
|
||||||
public void setSimulateKeyboard(boolean simulate) { |
|
||||||
this.keyboardEventsEnabled = simulate; |
|
||||||
} |
|
||||||
|
|
||||||
public boolean isSimulateKeyboard() { |
|
||||||
return keyboardEventsEnabled; |
|
||||||
} |
|
||||||
|
|
||||||
public void setOmitHistoricEvents(boolean dontSendHistory) { |
|
||||||
this.dontSendHistory = dontSendHistory; |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
|
@ -0,0 +1,159 @@ |
|||||||
|
/* |
||||||
|
* 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});
|
||||||
|
// use inclusive OR to make sure the onKey method is called.
|
||||||
|
consumed = consumed | ((AndroidJoyInput14)joyInput).onKey(event); |
||||||
|
} |
||||||
|
|
||||||
|
return consumed; |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,238 @@ |
|||||||
|
/* |
||||||
|
* 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.content.Context; |
||||||
|
import android.opengl.GLSurfaceView; |
||||||
|
import android.os.Vibrator; |
||||||
|
import com.jme3.input.InputManager; |
||||||
|
import com.jme3.input.JoyInput; |
||||||
|
import com.jme3.input.Joystick; |
||||||
|
import com.jme3.input.RawInputListener; |
||||||
|
import com.jme3.input.event.InputEvent; |
||||||
|
import com.jme3.input.event.JoyAxisEvent; |
||||||
|
import com.jme3.input.event.JoyButtonEvent; |
||||||
|
import com.jme3.system.AppSettings; |
||||||
|
import java.util.ArrayList; |
||||||
|
import java.util.List; |
||||||
|
import java.util.concurrent.ConcurrentLinkedQueue; |
||||||
|
import java.util.logging.Level; |
||||||
|
import java.util.logging.Logger; |
||||||
|
|
||||||
|
/** |
||||||
|
* Main class that manages various joystick devices. Joysticks can be many forms |
||||||
|
* including a simulated joystick to communicate the device orientation as well |
||||||
|
* as physical gamepads. </br> |
||||||
|
* This class manages all the joysticks and feeds the inputs from each back |
||||||
|
* to jME's InputManager. |
||||||
|
* |
||||||
|
* This handler also supports the joystick.rumble(rumbleAmount) method. In this |
||||||
|
* case, when joystick.rumble(rumbleAmount) is called, the Android device will vibrate |
||||||
|
* if the device has a built in vibrate motor. |
||||||
|
* |
||||||
|
* Because Andorid does not allow for the user to define the intensity of the |
||||||
|
* vibration, the rumble amount (ie strength) is converted into vibration pulses |
||||||
|
* The stronger the strength amount, the shorter the delay between pulses. If |
||||||
|
* amount is 1, then the vibration stays on the whole time. If amount is 0.5, |
||||||
|
* the vibration will a pulse of equal parts vibration and delay. |
||||||
|
* To turn off vibration, set rumble amount to 0. |
||||||
|
* |
||||||
|
* MainActivity needs the following line to enable Joysticks on Android platforms |
||||||
|
* joystickEventsEnabled = true; |
||||||
|
* This is done to allow for battery conservation when sensor data or gamepads |
||||||
|
* are not required by the application. |
||||||
|
* |
||||||
|
* To use the joystick rumble feature, the following line needs to be |
||||||
|
* added to the Android Manifest File |
||||||
|
* <uses-permission android:name="android.permission.VIBRATE"/> |
||||||
|
* |
||||||
|
* @author iwgeric |
||||||
|
*/ |
||||||
|
public class AndroidJoyInput implements JoyInput { |
||||||
|
private static final Logger logger = Logger.getLogger(AndroidJoyInput.class.getName()); |
||||||
|
public static boolean disableSensors = false; |
||||||
|
|
||||||
|
protected AndroidInputHandler inputHandler; |
||||||
|
protected List<Joystick> joystickList = new ArrayList<Joystick>(); |
||||||
|
// private boolean dontSendHistory = false;
|
||||||
|
|
||||||
|
|
||||||
|
// Internal
|
||||||
|
private boolean initialized = false; |
||||||
|
private RawInputListener listener = null; |
||||||
|
private ConcurrentLinkedQueue<InputEvent> eventQueue = new ConcurrentLinkedQueue<InputEvent>(); |
||||||
|
private AndroidSensorJoyInput sensorJoyInput; |
||||||
|
private Vibrator vibrator = null; |
||||||
|
private boolean vibratorActive = false; |
||||||
|
private long maxRumbleTime = 250; // 250ms
|
||||||
|
|
||||||
|
public AndroidJoyInput(AndroidInputHandler inputHandler) { |
||||||
|
this.inputHandler = inputHandler; |
||||||
|
sensorJoyInput = new AndroidSensorJoyInput(this); |
||||||
|
} |
||||||
|
|
||||||
|
public void setView(GLSurfaceView 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); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void loadSettings(AppSettings settings) { |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public void addEvent(InputEvent event) { |
||||||
|
eventQueue.add(event); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Pauses the joystick device listeners to save battery life if they are not needed. |
||||||
|
* Used to pause when the activity pauses |
||||||
|
*/ |
||||||
|
public void pauseJoysticks() { |
||||||
|
if (sensorJoyInput != null) { |
||||||
|
sensorJoyInput.pauseSensors(); |
||||||
|
} |
||||||
|
if (vibrator != null && vibratorActive) { |
||||||
|
vibrator.cancel(); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Resumes the joystick device listeners. |
||||||
|
* Used to resume when the activity comes to the top of the stack |
||||||
|
*/ |
||||||
|
public void resumeJoysticks() { |
||||||
|
if (sensorJoyInput != null) { |
||||||
|
sensorJoyInput.resumeSensors(); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void initialize() { |
||||||
|
initialized = true; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean isInitialized() { |
||||||
|
return initialized; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void destroy() { |
||||||
|
initialized = false; |
||||||
|
|
||||||
|
if (sensorJoyInput != null) { |
||||||
|
sensorJoyInput.destroy(); |
||||||
|
} |
||||||
|
|
||||||
|
setView(null); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void setInputListener(RawInputListener listener) { |
||||||
|
this.listener = listener; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public long getInputTimeNanos() { |
||||||
|
return System.nanoTime(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void setJoyRumble(int joyId, float amount) { |
||||||
|
// convert amount to pulses since Android doesn't allow intensity
|
||||||
|
if (vibrator != null) { |
||||||
|
final long rumbleOnDur = (long)(amount * maxRumbleTime); // ms to pulse vibration on
|
||||||
|
final long rumbleOffDur = maxRumbleTime - rumbleOnDur; // ms to delay between pulses
|
||||||
|
final long[] rumblePattern = { |
||||||
|
0, // start immediately
|
||||||
|
rumbleOnDur, // time to leave vibration on
|
||||||
|
rumbleOffDur // time to delay between vibrations
|
||||||
|
}; |
||||||
|
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});
|
||||||
|
|
||||||
|
if (rumbleOnDur > 0) { |
||||||
|
vibrator.vibrate(rumblePattern, rumbleRepeatFrom); |
||||||
|
vibratorActive = true; |
||||||
|
} else { |
||||||
|
vibrator.cancel(); |
||||||
|
vibratorActive = false; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Joystick[] loadJoysticks(InputManager inputManager) { |
||||||
|
logger.log(Level.INFO, "loading joysticks for {0}", this.getClass().getName()); |
||||||
|
if (!disableSensors) { |
||||||
|
joystickList.add(sensorJoyInput.loadJoystick(joystickList.size(), inputManager)); |
||||||
|
} |
||||||
|
return joystickList.toArray( new Joystick[joystickList.size()] ); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void update() { |
||||||
|
if (sensorJoyInput != null) { |
||||||
|
sensorJoyInput.update(); |
||||||
|
} |
||||||
|
|
||||||
|
if (listener != null) { |
||||||
|
InputEvent inputEvent; |
||||||
|
|
||||||
|
while ((inputEvent = eventQueue.poll()) != null) { |
||||||
|
if (inputEvent instanceof JoyAxisEvent) { |
||||||
|
listener.onJoyAxisEvent((JoyAxisEvent)inputEvent); |
||||||
|
} else if (inputEvent instanceof JoyButtonEvent) { |
||||||
|
listener.onJoyButtonEvent((JoyButtonEvent)inputEvent); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -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,416 @@ |
|||||||
|
/* |
||||||
|
* 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.JoystickCompatibilityMappings; |
||||||
|
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()); |
||||||
|
boolean pressed = event.getAction() == KeyEvent.ACTION_DOWN; |
||||||
|
if (button != null) { |
||||||
|
JoyButtonEvent buttonEvent = new JoyButtonEvent(button, pressed); |
||||||
|
joyInput.addEvent(buttonEvent); |
||||||
|
consumed = true; |
||||||
|
} else { |
||||||
|
JoystickButton newButton = joystick.addButton(event.getKeyCode()); |
||||||
|
JoyButtonEvent buttonEvent = new JoyButtonEvent(newButton, 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 original = KeyEvent.keyCodeToString(keyCode); |
||||||
|
// A/B/X/Y buttons
|
||||||
|
if (keyCode == KeyEvent.KEYCODE_BUTTON_Y) { |
||||||
|
original = JoystickButton.BUTTON_0; |
||||||
|
} else if (keyCode == KeyEvent.KEYCODE_BUTTON_B) { |
||||||
|
original = JoystickButton.BUTTON_1; |
||||||
|
} else if (keyCode == KeyEvent.KEYCODE_BUTTON_A) { |
||||||
|
original = JoystickButton.BUTTON_2; |
||||||
|
} else if (keyCode == KeyEvent.KEYCODE_BUTTON_X) { |
||||||
|
original = JoystickButton.BUTTON_3; |
||||||
|
// Front buttons Some of these have the top ones and the bottoms ones flipped.
|
||||||
|
} else if (keyCode == KeyEvent.KEYCODE_BUTTON_L1) { |
||||||
|
original = JoystickButton.BUTTON_4; |
||||||
|
} else if (keyCode == KeyEvent.KEYCODE_BUTTON_R1) { |
||||||
|
original = JoystickButton.BUTTON_5; |
||||||
|
} else if (keyCode == KeyEvent.KEYCODE_BUTTON_L2) { |
||||||
|
original = JoystickButton.BUTTON_6; |
||||||
|
} else if (keyCode == KeyEvent.KEYCODE_BUTTON_R2) { |
||||||
|
original = JoystickButton.BUTTON_7; |
||||||
|
// // Dpad buttons
|
||||||
|
// } else if (keyCode == KeyEvent.KEYCODE_DPAD_UP) {
|
||||||
|
// original = JoystickButton.BUTTON_8;
|
||||||
|
// } else if (keyCode == KeyEvent.KEYCODE_DPAD_UP) {
|
||||||
|
// original = JoystickButton.BUTTON_9;
|
||||||
|
// } else if (keyCode == KeyEvent.KEYCODE_DPAD_UP) {
|
||||||
|
// original = JoystickButton.BUTTON_8;
|
||||||
|
// } else if (keyCode == KeyEvent.KEYCODE_DPAD_UP) {
|
||||||
|
// original = JoystickButton.BUTTON_9;
|
||||||
|
// Select and start buttons
|
||||||
|
} else if (keyCode == KeyEvent.KEYCODE_BUTTON_SELECT) { |
||||||
|
original = JoystickButton.BUTTON_8; |
||||||
|
} else if (keyCode == KeyEvent.KEYCODE_BUTTON_START) { |
||||||
|
original = JoystickButton.BUTTON_9; |
||||||
|
// Joystick push buttons
|
||||||
|
} else if (keyCode == KeyEvent.KEYCODE_BUTTON_THUMBL) { |
||||||
|
original = JoystickButton.BUTTON_10; |
||||||
|
} else if (keyCode == KeyEvent.KEYCODE_BUTTON_THUMBR) { |
||||||
|
original = JoystickButton.BUTTON_11; |
||||||
|
} |
||||||
|
|
||||||
|
String logicalId = JoystickCompatibilityMappings.remapComponent( getName(), original ); |
||||||
|
if( logicalId == null ? original != null : !logicalId.equals(original) ) { |
||||||
|
logger.log(Level.FINE, "Remapped: {0} to: {1}", |
||||||
|
new Object[]{original, logicalId}); |
||||||
|
} |
||||||
|
|
||||||
|
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 original = MotionEvent.axisToString(motionRange.getAxis()); |
||||||
|
if (motionRange.getAxis() == MotionEvent.AXIS_X) { |
||||||
|
original = JoystickAxis.X_AXIS; |
||||||
|
} else if (motionRange.getAxis() == MotionEvent.AXIS_Y) { |
||||||
|
original = JoystickAxis.Y_AXIS; |
||||||
|
} else if (motionRange.getAxis() == MotionEvent.AXIS_Z) { |
||||||
|
original = JoystickAxis.Z_AXIS; |
||||||
|
} else if (motionRange.getAxis() == MotionEvent.AXIS_RZ) { |
||||||
|
original = JoystickAxis.Z_ROTATION; |
||||||
|
} else if (motionRange.getAxis() == MotionEvent.AXIS_HAT_X) { |
||||||
|
original = JoystickAxis.POV_X; |
||||||
|
} else if (motionRange.getAxis() == MotionEvent.AXIS_HAT_Y) { |
||||||
|
original = JoystickAxis.POV_Y; |
||||||
|
} |
||||||
|
String logicalId = JoystickCompatibilityMappings.remapComponent( getName(), original ); |
||||||
|
if( logicalId == null ? original != null : !logicalId.equals(original) ) { |
||||||
|
logger.log(Level.FINE, "Remapped: {0} to: {1}", |
||||||
|
new Object[]{original, 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; |
||||||
|
} |
||||||
|
|
||||||
|
} |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,214 @@ |
|||||||
|
package com.jme3.scene.plugins.blender.math; |
||||||
|
|
||||||
|
import java.text.DecimalFormat; |
||||||
|
|
||||||
|
import org.ejml.ops.CommonOps; |
||||||
|
import org.ejml.simple.SimpleMatrix; |
||||||
|
import org.ejml.simple.SimpleSVD; |
||||||
|
|
||||||
|
import com.jme3.math.FastMath; |
||||||
|
|
||||||
|
/** |
||||||
|
* Encapsulates a 4x4 matrix |
||||||
|
* |
||||||
|
* |
||||||
|
*/ |
||||||
|
public class Matrix extends SimpleMatrix { |
||||||
|
private static final long serialVersionUID = 2396600537315902559L; |
||||||
|
|
||||||
|
public Matrix(int rows, int cols) { |
||||||
|
super(rows, cols); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Copy constructor |
||||||
|
*/ |
||||||
|
public Matrix(SimpleMatrix m) { |
||||||
|
super(m); |
||||||
|
} |
||||||
|
|
||||||
|
public Matrix(double[][] data) { |
||||||
|
super(data); |
||||||
|
} |
||||||
|
|
||||||
|
public static Matrix identity(int size) { |
||||||
|
Matrix result = new Matrix(size, size); |
||||||
|
CommonOps.setIdentity(result.mat); |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
public Matrix pseudoinverse() { |
||||||
|
return this.pseudoinverse(1); |
||||||
|
} |
||||||
|
|
||||||
|
@SuppressWarnings("unchecked") |
||||||
|
public Matrix pseudoinverse(double lambda) { |
||||||
|
SimpleSVD<SimpleMatrix> simpleSVD = this.svd(); |
||||||
|
|
||||||
|
SimpleMatrix U = simpleSVD.getU(); |
||||||
|
SimpleMatrix S = simpleSVD.getW(); |
||||||
|
SimpleMatrix V = simpleSVD.getV(); |
||||||
|
|
||||||
|
int N = Math.min(this.numRows(),this.numCols()); |
||||||
|
double maxSingular = 0; |
||||||
|
for( int i = 0; i < N; ++i ) { |
||||||
|
if( S.get(i, i) > maxSingular ) { |
||||||
|
maxSingular = S.get(i, i); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
double tolerance = FastMath.DBL_EPSILON * Math.max(this.numRows(),this.numCols()) * maxSingular; |
||||||
|
for(int i=0;i<Math.min(S.numRows(), S.numCols());++i) { |
||||||
|
double a = S.get(i, i); |
||||||
|
if(a <= tolerance) { |
||||||
|
a = 0; |
||||||
|
} else { |
||||||
|
a = a/(a * a + lambda * lambda); |
||||||
|
} |
||||||
|
S.set(i, i, a); |
||||||
|
} |
||||||
|
return new Matrix(V.mult(S.transpose()).mult(U.transpose())); |
||||||
|
} |
||||||
|
|
||||||
|
public void setColumn(Vector3d col, int column) { |
||||||
|
this.setColumn(column, 0, col.x, col.y, col.z); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Just for some debug informations in order to compare the results with the scilab computation program. |
||||||
|
* @param name the name of the matrix |
||||||
|
* @param m the matrix to print out |
||||||
|
* @return the String format of the matrix to easily input it to Scilab |
||||||
|
*/ |
||||||
|
public String toScilabString(String name, SimpleMatrix m) { |
||||||
|
String result = name + " = ["; |
||||||
|
|
||||||
|
for(int i=0;i<m.numRows();++i) { |
||||||
|
for(int j=0;j<m.numCols();++j) { |
||||||
|
result += m.get(i, j) + " "; |
||||||
|
} |
||||||
|
result += ";"; |
||||||
|
} |
||||||
|
|
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @return a String representation of the matrix |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public String toString() { |
||||||
|
DecimalFormat df = new DecimalFormat("#.0000"); |
||||||
|
StringBuilder buf = new StringBuilder(); |
||||||
|
for (int r = 0; r < this.numRows(); ++r) { |
||||||
|
buf.append("\n| "); |
||||||
|
for (int c = 0; c < this.numCols(); ++c) { |
||||||
|
buf.append(df.format(this.get(r, c))).append(' '); |
||||||
|
} |
||||||
|
buf.append('|'); |
||||||
|
} |
||||||
|
return buf.toString(); |
||||||
|
} |
||||||
|
|
||||||
|
public void setTranslation(Vector3d translation) { |
||||||
|
this.setColumn(translation, 3); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Sets the scale. |
||||||
|
* |
||||||
|
* @param scale |
||||||
|
* the scale vector to set |
||||||
|
*/ |
||||||
|
public void setScale(Vector3d scale) { |
||||||
|
this.setScale(scale.x, scale.y, scale.z); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Sets the scale. |
||||||
|
* |
||||||
|
* @param x |
||||||
|
* the X scale |
||||||
|
* @param y |
||||||
|
* the Y scale |
||||||
|
* @param z |
||||||
|
* the Z scale |
||||||
|
*/ |
||||||
|
public void setScale(double x, double y, double z) { |
||||||
|
Vector3d vect1 = new Vector3d(this.get(0, 0), this.get(1, 0), this.get(2, 0)); |
||||||
|
vect1.normalizeLocal().multLocal(x); |
||||||
|
this.set(0, 0, vect1.x); |
||||||
|
this.set(1, 0, vect1.y); |
||||||
|
this.set(2, 0, vect1.z); |
||||||
|
|
||||||
|
vect1.set(this.get(0, 1), this.get(1, 1), this.get(2, 1)); |
||||||
|
vect1.normalizeLocal().multLocal(y); |
||||||
|
this.set(0, 1, vect1.x); |
||||||
|
this.set(1, 1, vect1.y); |
||||||
|
this.set(2, 1, vect1.z); |
||||||
|
|
||||||
|
vect1.set(this.get(0, 2), this.get(1, 2), this.get(2, 2)); |
||||||
|
vect1.normalizeLocal().multLocal(z); |
||||||
|
this.set(0, 2, vect1.x); |
||||||
|
this.set(1, 2, vect1.y); |
||||||
|
this.set(2, 2, vect1.z); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* <code>setRotationQuaternion</code> builds a rotation from a |
||||||
|
* <code>Quaternion</code>. |
||||||
|
* |
||||||
|
* @param quat |
||||||
|
* the quaternion to build the rotation from. |
||||||
|
* @throws NullPointerException |
||||||
|
* if quat is null. |
||||||
|
*/ |
||||||
|
public void setRotationQuaternion(DQuaternion quat) { |
||||||
|
quat.toRotationMatrix(this); |
||||||
|
} |
||||||
|
|
||||||
|
public DTransform toTransform() { |
||||||
|
DTransform result = new DTransform(); |
||||||
|
result.setTranslation(this.toTranslationVector()); |
||||||
|
result.setRotation(this.toRotationQuat()); |
||||||
|
result.setScale(this.toScaleVector()); |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
public Vector3d toTranslationVector() { |
||||||
|
return new Vector3d(this.get(0, 3), this.get(1, 3), this.get(2, 3)); |
||||||
|
} |
||||||
|
|
||||||
|
public DQuaternion toRotationQuat() { |
||||||
|
DQuaternion quat = new DQuaternion(); |
||||||
|
quat.fromRotationMatrix(this.get(0, 0), this.get(0, 1), this.get(0, 2), this.get(1, 0), this.get(1, 1), this.get(1, 2), this.get(2, 0), this.get(2, 1), this.get(2, 2)); |
||||||
|
return quat; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Retreives the scale vector from the matrix and stores it into a given |
||||||
|
* vector. |
||||||
|
* |
||||||
|
* @param the |
||||||
|
* vector where the scale will be stored |
||||||
|
*/ |
||||||
|
public Vector3d toScaleVector() { |
||||||
|
Vector3d result = new Vector3d(); |
||||||
|
this.toScaleVector(result); |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Retreives the scale vector from the matrix and stores it into a given |
||||||
|
* vector. |
||||||
|
* |
||||||
|
* @param the |
||||||
|
* vector where the scale will be stored |
||||||
|
*/ |
||||||
|
public void toScaleVector(Vector3d vector) { |
||||||
|
double scaleX = Math.sqrt(this.get(0, 0) * this.get(0, 0) + this.get(1, 0) * this.get(1, 0) + this.get(2, 0) * this.get(2, 0)); |
||||||
|
double scaleY = Math.sqrt(this.get(0, 1) * this.get(0, 1) + this.get(1, 1) * this.get(1, 1) + this.get(2, 1) * this.get(2, 1)); |
||||||
|
double scaleZ = Math.sqrt(this.get(0, 2) * this.get(0, 2) + this.get(1, 2) * this.get(1, 2) + this.get(2, 2) * this.get(2, 2)); |
||||||
|
vector.set(scaleX, scaleY, scaleZ); |
||||||
|
} |
||||||
|
} |
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue