Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- * 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.app.Activity;
- import android.content.Context;
- import android.os.Vibrator;
- import android.view.InputDevice;
- import android.view.MotionEvent;
- import android.view.Surface;
- import android.view.View;
- import com.jme3.input.AbstractJoystick;
- import com.jme3.input.DefaultJoystickAxis;
- import com.jme3.input.InputManager;
- import com.jme3.input.JoyInput;
- import com.jme3.input.Joystick;
- import com.jme3.input.JoystickAxis;
- import com.jme3.input.SensorJoystickAxis;
- import com.jme3.input.RawInputListener;
- import com.jme3.input.event.JoyAxisEvent;
- import com.jme3.math.FastMath;
- import com.jme3.system.android.JmeAndroidSystem;
- import com.jme3.util.IntMap;
- import com.jme3.util.IntMap.Entry;
- import java.util.ArrayList;
- import java.util.List;
- import java.util.logging.Level;
- import java.util.logging.Logger;
- /**
- * GamepadJoyInput converts the Android Sensor system into Joystick events.
- * A single joystick is configured and includes data for all configured sensors
- * as seperate axes of the joystick.
- *
- * Each axis is named accounting to the static strings in SensorJoystickAxis.
- * Refer to the strings defined in SensorJoystickAxis for a list of supported
- * sensors and their axis data. Each sensor type defined in SensorJoystickAxis
- * will be attempted to be configured. If the device does not support a particular
- * sensor, the axis will return null if joystick.getAxis(String name) is called.
- *
- * The joystick.getXAxis and getYAxis methods of the joystick are configured to
- * return the device orientation values in the device's X and Y directions.
- *
- * This joystick 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 is 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 GamepadJoyInput implements JoyInput, View.OnGenericMotionListener {
- private final static Logger logger = Logger.getLogger(GamepadJoyInput.class.getName());
- private Activity activity = null;
- private InputManager inputManager = null;
- private InputDevice inputDevice = null;
- private Vibrator vibrator = null;
- private boolean vibratorActive = false;
- private long maxRumbleTime = 250; // 250ms
- private RawInputListener listener = null;
- private IntMap<SensorData> sensors = new IntMap<SensorData>();
- private AndroidJoystick[] joysticks;
- private int lastRotation = 0;
- private boolean initialized = false;
- private boolean loaded = false;
- private View mView = null;
- private final ArrayList<JoyAxisEvent> eventQueue = new ArrayList<JoyAxisEvent>();
- public void setView(View view)
- {
- mView = view;
- if (view != null)
- {
- view.setOnGenericMotionListener(this);
- }
- }
- public boolean onGenericMotion(View view, MotionEvent event)
- {
- SensorData sensorData = sensors.get(InputDevice.SOURCE_CLASS_JOYSTICK);
- if (!initialized || !loaded)
- {
- return view.onGenericMotionEvent(event);
- }
- // Check that the event came from a joystick since a generic motion event
- // could be almost anything.
- if ((event.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) != 0
- && event.getAction() == MotionEvent.ACTION_MOVE) {
- // Cache the most recently obtained device information.
- // The device information may change over time but it can be
- // somewhat expensive to query.
- if (inputDevice == null || inputDevice.getId() != event.getDeviceId()) {
- inputDevice = event.getDevice();
- // It's possible for the device id to be invalid.
- // In that case, getDevice() will return null.
- if (inputDevice == null) {
- return false;
- }
- }
- // Process all historical movement samples in the batch.
- final int historySize = event.getHistorySize();
- for (int i = 0; i < historySize; i++) {
- processJoystickInput(event, i, sensorData);
- }
- // Process the current movement sample in the batch.
- processJoystickInput(event, -1, sensorData);
- return true;
- }
- return true;
- }
- private void processJoystickInput(MotionEvent event, int historyPos, SensorData sensorData)
- {
- // Get joystick position.
- // Many game pads with two joysticks report the position of the second joystick
- // using the Z and RZ axes so we also handle those.
- // In a real game, we would allow the user to configure the axes manually.
- float x = getCenteredAxis(event, inputDevice, MotionEvent.AXIS_X, historyPos);
- if (x == 0) {
- x = getCenteredAxis(event, inputDevice, MotionEvent.AXIS_HAT_X, historyPos);
- }
- if (x == 0) {
- x = getCenteredAxis(event, inputDevice, MotionEvent.AXIS_Z, historyPos);
- }
- float y = getCenteredAxis(event, inputDevice, MotionEvent.AXIS_Y, historyPos);
- if (y == 0) {
- y = getCenteredAxis(event, inputDevice, MotionEvent.AXIS_HAT_Y, historyPos);
- }
- if (y == 0) {
- y = getCenteredAxis(event, inputDevice, MotionEvent.AXIS_RZ, historyPos);
- }
- if (sensorData != null && sensorData.enabled)
- {
- for (int i=0; i<sensorData.lastValues.length; i++)
- {
- sensorData.lastValues[i] = event.getAxisValue(i);
- }
- if (sensorData != null && sensorData.axes.size() > 0)
- {
- AndroidJoystickAxis axis;
- for (int i=0; i<sensorData.axes.size(); i++) {
- axis = sensorData.axes.get(i);
- if (axis != null) {
- axis.setCurRawValue(event.getAxisValue(i));
- if (!sensorData.haveData) {
- sensorData.haveData = true;
- } else {
- synchronized (eventQueue){
- if (axis.isChanged()) {
- eventQueue.add(new JoyAxisEvent(axis, axis.getJoystickAxisValue()));
- }
- }
- }
- }
- }
- } else if (sensorData != null)
- {
- if (!sensorData.haveData) {
- sensorData.haveData = true;
- }
- }
- }
- }
- private static float getCenteredAxis(MotionEvent event, InputDevice device,
- int axis, int historyPos) {
- final InputDevice.MotionRange range = device.getMotionRange(axis, event.getSource());
- if (range != null) {
- final float flat = range.getFlat();
- final float value = historyPos < 0 ? event.getAxisValue(axis)
- : event.getHistoricalAxisValue(axis, historyPos);
- // Ignore axis values that are within the 'flat' region of the joystick axis center.
- // A joystick at rest does not always report an absolute position of (0,0).
- if (Math.abs(value) > flat) {
- return value;
- }
- }
- return 0;
- }
- /**
- * Internal class to enclose data for each sensor.
- */
- private class SensorData {
- int androidSensorType = -1;
- InputDevice inputDevice = null;
- int sensorAccuracy = 0;
- float[] lastValues;
- final Object valuesLock = new Object();
- ArrayList<AndroidJoystickAxis> axes = new ArrayList<AndroidJoystickAxis>();
- boolean enabled = false;
- boolean haveData = false;
- public SensorData(int androidSensorType, InputDevice inputDevice) {
- this.androidSensorType = androidSensorType;
- this.inputDevice = inputDevice;
- }
- }
- private void initSensorManager() {
- this.activity = JmeAndroidSystem.getActivity();
- // Get instance of Vibrator from current Context
- vibrator = (Vibrator) activity.getSystemService(Context.VIBRATOR_SERVICE);
- if (vibrator == null) {
- logger.log(Level.FINE, "Vibrator Service not found.");
- }
- }
- /**
- * Pauses the sensors to save battery life if the sensors are not needed.
- * Used to pause sensors when the activity pauses
- */
- public void pauseSensors()
- {
- if (vibrator != null && vibratorActive) {
- vibrator.cancel();
- }
- }
- /**
- * Resumes the sensors.
- * Used to resume sensors when the activity comes to the top of the stack
- */
- public void resumeSensors()
- {
- }
- // Start of JoyInput methods
- 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;
- }
- }
- }
- public Joystick[] loadJoysticks(InputManager inputManager) {
- this.inputManager = inputManager;
- initSensorManager();
- setView(mView);
- SensorData sensorData;
- List<Joystick> list = new ArrayList<Joystick>();
- AndroidJoystick joystick;
- AndroidJoystickAxis axis;
- joystick = new AndroidJoystick(inputManager,
- this,
- list.size(),
- "AndroidSensorsJoystick");
- list.add(joystick);
- // manually create orientation sensor data since orientation is not a physical sensor
- sensorData = new SensorData(InputDevice.SOURCE_CLASS_JOYSTICK, null);
- sensorData.androidSensorType = InputDevice.SOURCE_CLASS_JOYSTICK;
- //sensorData.sensor = sensorManager.getDefaultSensor(sensorType);
- sensorData.enabled = true;
- if (sensorData != null) {
- sensorData.lastValues = new float[2];
- sensors.put(InputDevice.SOURCE_CLASS_JOYSTICK, sensorData);
- axis = joystick.addAxis(SensorJoystickAxis.ORIENTATION_X, SensorJoystickAxis.ORIENTATION_X, joystick.getAxisCount(), 1);
- joystick.setYAxis(axis); // joystick y axis = rotation around device x axis
- sensorData.axes.add(axis);
- axis = joystick.addAxis(SensorJoystickAxis.ORIENTATION_Y, SensorJoystickAxis.ORIENTATION_Y, joystick.getAxisCount(), 1);
- joystick.setXAxis(axis); // joystick x axis = rotation around device y axis
- sensorData.axes.add(axis);
- }
- joysticks = list.toArray( new AndroidJoystick[list.size()] );
- loaded = true;
- return joysticks;
- }
- public void initialize() {
- initialized = true;
- loaded = false;
- }
- public void update() {
- if (!loaded) {
- return;
- }
- synchronized (eventQueue){
- // flush events to listener
- if (listener != null && eventQueue.size() > 0) {
- for (int i = 0; i < eventQueue.size(); i++){
- listener.onJoyAxisEvent(eventQueue.get(i));
- }
- eventQueue.clear();
- }
- }
- }
- public void destroy() {
- logger.log(Level.FINE, "Doing Destroy.");
- pauseSensors();
- sensors.clear();
- eventQueue.clear();
- initialized = false;
- loaded = false;
- joysticks = null;
- vibrator = null;
- activity = null;
- }
- public boolean isInitialized() {
- return initialized;
- }
- public void setInputListener(RawInputListener listener) {
- this.listener = listener;
- }
- public long getInputTimeNanos() {
- return System.nanoTime();
- }
- // End of JoyInput methods
- protected class AndroidJoystick extends AbstractJoystick {
- private JoystickAxis nullAxis;
- private JoystickAxis xAxis;
- private JoystickAxis yAxis;
- private JoystickAxis povX;
- private JoystickAxis povY;
- public AndroidJoystick( InputManager inputManager, JoyInput joyInput,
- int joyId, String name){
- super( inputManager, joyInput, joyId, name );
- 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 AndroidJoystickAxis addAxis(String axisName, String logicalName, int axisNum, float maxRawValue) {
- AndroidJoystickAxis axis;
- axis = new AndroidJoystickAxis(
- inputManager, // InputManager (InputManager)
- this, // parent Joystick (Joystick)
- axisNum, // Axis Index (int)
- axisName, // Axis Name (String)
- logicalName, // Logical ID (String)
- true, // isAnalog (boolean)
- false, // isRelative (boolean)
- 0.01f, // Axis Deadzone (float)
- maxRawValue); // Axis Max Raw Value (float)
- super.addAxis(axis);
- return axis;
- }
- protected void setXAxis(JoystickAxis axis) {
- xAxis = axis;
- }
- protected void setYAxis(JoystickAxis axis) {
- yAxis = 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;
- }
- }
- public class AndroidJoystickAxis extends DefaultJoystickAxis implements SensorJoystickAxis {
- float zeroRawValue = 0f;
- float curRawValue = 0f;
- float lastRawValue = 0f;
- boolean hasChanged = false;
- float maxRawValue = FastMath.HALF_PI;
- boolean enabled = true;
- public AndroidJoystickAxis(InputManager inputManager, Joystick parent,
- int axisIndex, String name, String logicalId,
- boolean isAnalog, boolean isRelative, float deadZone,
- float maxRawValue) {
- super(inputManager, parent, axisIndex, name, logicalId, isAnalog, isRelative, deadZone);
- this.maxRawValue = maxRawValue;
- }
- public float getMaxRawValue() {
- return maxRawValue;
- }
- public void setMaxRawValue(float maxRawValue) {
- this.maxRawValue = maxRawValue;
- }
- protected float getLastRawValue() {
- return lastRawValue;
- }
- protected void setCurRawValue(float rawValue) {
- this.curRawValue = rawValue;
- if (Math.abs(curRawValue - lastRawValue) > getDeadZone()) {
- hasChanged = true;
- lastRawValue = curRawValue;
- } else {
- hasChanged = false;
- }
- }
- protected float getJoystickAxisValue() {
- return (lastRawValue-zeroRawValue) / maxRawValue;
- }
- protected boolean isChanged() {
- return hasChanged;
- }
- public void calibrateCenter() {
- zeroRawValue = lastRawValue;
- logger.log(Level.FINE, "Calibrating axis {0} to {1}",
- new Object[]{getName(), zeroRawValue});
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement