Advertisement
Guest User

GamepadJoyInput.java

a guest
Jul 20th, 2013
50
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 19.36 KB | None | 0 0
  1. /*
  2.  * Copyright (c) 2009-2012 jMonkeyEngine
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions are
  7.  * met:
  8.  *
  9.  * * Redistributions of source code must retain the above copyright
  10.  *   notice, this list of conditions and the following disclaimer.
  11.  *
  12.  * * Redistributions in binary form must reproduce the above copyright
  13.  *   notice, this list of conditions and the following disclaimer in the
  14.  *   documentation and/or other materials provided with the distribution.
  15.  *
  16.  * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
  17.  *   may be used to endorse or promote products derived from this software
  18.  *   without specific prior written permission.
  19.  *
  20.  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  21.  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
  22.  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  23.  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  24.  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  25.  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  26.  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  27.  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  28.  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  29.  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  30.  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  31.  */
  32.  
  33. package com.jme3.input.android;
  34.  
  35. import android.app.Activity;
  36. import android.content.Context;
  37. import android.os.Vibrator;
  38. import android.view.InputDevice;
  39. import android.view.MotionEvent;
  40. import android.view.Surface;
  41. import android.view.View;
  42. import com.jme3.input.AbstractJoystick;
  43. import com.jme3.input.DefaultJoystickAxis;
  44. import com.jme3.input.InputManager;
  45. import com.jme3.input.JoyInput;
  46. import com.jme3.input.Joystick;
  47. import com.jme3.input.JoystickAxis;
  48. import com.jme3.input.SensorJoystickAxis;
  49. import com.jme3.input.RawInputListener;
  50. import com.jme3.input.event.JoyAxisEvent;
  51. import com.jme3.math.FastMath;
  52. import com.jme3.system.android.JmeAndroidSystem;
  53. import com.jme3.util.IntMap;
  54. import com.jme3.util.IntMap.Entry;
  55. import java.util.ArrayList;
  56. import java.util.List;
  57. import java.util.logging.Level;
  58. import java.util.logging.Logger;
  59.  
  60. /**
  61.  * GamepadJoyInput converts the Android Sensor system into Joystick events.
  62.  * A single joystick is configured and includes data for all configured sensors
  63.  * as seperate axes of the joystick.
  64.  *
  65.  * Each axis is named accounting to the static strings in SensorJoystickAxis.
  66.  * Refer to the strings defined in SensorJoystickAxis for a list of supported
  67.  * sensors and their axis data.  Each sensor type defined in SensorJoystickAxis
  68.  * will be attempted to be configured.  If the device does not support a particular
  69.  * sensor, the axis will return null if joystick.getAxis(String name) is called.
  70.  *
  71.  * The joystick.getXAxis and getYAxis methods of the joystick are configured to
  72.  * return the device orientation values in the device's X and Y directions.
  73.  *
  74.  * This joystick also supports the joystick.rumble(rumbleAmount) method.  In this
  75.  * case, when joystick.rumble(rumbleAmount) is called, the Android device will vibrate
  76.  * if the device has a built in vibrate motor.
  77.  *
  78.  * Because Andorid does not allow for the user to define the intensity of the
  79.  * vibration, the rumble amount (ie strength) is converted into vibration pulses
  80.  * The stronger the strength amount, the shorter the delay between pulses.  If
  81.  * amount is 1, then the vibration stays on the whole time.  If amount is 0.5,
  82.  * the vibration will a pulse of equal parts vibration and delay.
  83.  * To turn off vibration, set rumble amount to 0.
  84.  *
  85.  * MainActivity needs the following line to enable Joysticks on Android platforms
  86.  *    joystickEventsEnabled = true;
  87.  * This is done to allow for battery conservation when sensor data is not required
  88.  * by the application.
  89.  *
  90.  * To use the joystick rumble feature, the following line needs to be
  91.  * added to the Android Manifest File
  92.  *     <uses-permission android:name="android.permission.VIBRATE"/>
  93.  *
  94.  * @author iwgeric
  95.  */
  96. public class GamepadJoyInput implements JoyInput, View.OnGenericMotionListener {
  97.     private final static Logger logger = Logger.getLogger(GamepadJoyInput.class.getName());
  98.  
  99.     private Activity activity = null;
  100.     private InputManager inputManager = null;
  101.     private InputDevice inputDevice = null;
  102.     private Vibrator vibrator = null;
  103.     private boolean vibratorActive = false;
  104.     private long maxRumbleTime = 250;  // 250ms
  105.     private RawInputListener listener = null;
  106.     private IntMap<SensorData> sensors = new IntMap<SensorData>();
  107.     private AndroidJoystick[] joysticks;
  108.     private int lastRotation = 0;
  109.     private boolean initialized = false;
  110.     private boolean loaded = false;
  111.     private View mView = null;
  112.  
  113.     private final ArrayList<JoyAxisEvent> eventQueue = new ArrayList<JoyAxisEvent>();
  114.    
  115.     public void setView(View view)
  116.     {
  117.         mView = view;
  118.         if (view != null)
  119.         {
  120.             view.setOnGenericMotionListener(this);
  121.         }
  122.     }
  123.    
  124.     public boolean onGenericMotion(View view, MotionEvent event)
  125.     {
  126.         SensorData sensorData = sensors.get(InputDevice.SOURCE_CLASS_JOYSTICK);
  127.        
  128.         if (!initialized || !loaded)
  129.         {
  130.             return view.onGenericMotionEvent(event);
  131.         }
  132.        
  133.         // Check that the event came from a joystick since a generic motion event
  134.         // could be almost anything.
  135.         if ((event.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) != 0
  136.                 && event.getAction() == MotionEvent.ACTION_MOVE) {
  137.             // Cache the most recently obtained device information.
  138.             // The device information may change over time but it can be
  139.             // somewhat expensive to query.
  140.             if (inputDevice == null || inputDevice.getId() != event.getDeviceId()) {
  141.                 inputDevice = event.getDevice();
  142.                 // It's possible for the device id to be invalid.
  143.                 // In that case, getDevice() will return null.
  144.                 if (inputDevice == null) {
  145.                     return false;
  146.                 }
  147.             }
  148.  
  149.             // Process all historical movement samples in the batch.
  150.             final int historySize = event.getHistorySize();
  151.             for (int i = 0; i < historySize; i++) {
  152.                 processJoystickInput(event, i, sensorData);
  153.             }
  154.  
  155.             // Process the current movement sample in the batch.
  156.             processJoystickInput(event, -1, sensorData);
  157.             return true;
  158.         }
  159.         return true;
  160.     }
  161.    
  162.     private void processJoystickInput(MotionEvent event, int historyPos, SensorData sensorData)
  163.     {
  164.  
  165.         // Get joystick position.
  166.         // Many game pads with two joysticks report the position of the second joystick
  167.         // using the Z and RZ axes so we also handle those.
  168.         // In a real game, we would allow the user to configure the axes manually.
  169.         float x = getCenteredAxis(event, inputDevice, MotionEvent.AXIS_X, historyPos);
  170.         if (x == 0) {
  171.             x = getCenteredAxis(event, inputDevice, MotionEvent.AXIS_HAT_X, historyPos);
  172.         }
  173.         if (x == 0) {
  174.             x = getCenteredAxis(event, inputDevice, MotionEvent.AXIS_Z, historyPos);
  175.         }
  176.  
  177.         float y = getCenteredAxis(event, inputDevice, MotionEvent.AXIS_Y, historyPos);
  178.         if (y == 0) {
  179.             y = getCenteredAxis(event, inputDevice, MotionEvent.AXIS_HAT_Y, historyPos);
  180.         }
  181.         if (y == 0) {
  182.             y = getCenteredAxis(event, inputDevice, MotionEvent.AXIS_RZ, historyPos);
  183.         }    
  184.  
  185.         if (sensorData != null && sensorData.enabled)
  186.         {
  187.  
  188.             for (int i=0; i<sensorData.lastValues.length; i++)
  189.             {
  190.                 sensorData.lastValues[i] = event.getAxisValue(i);
  191.             }
  192.  
  193.             if (sensorData != null && sensorData.axes.size() > 0)
  194.             {
  195.                 AndroidJoystickAxis axis;
  196.                 for (int i=0; i<sensorData.axes.size(); i++) {
  197.                     axis = sensorData.axes.get(i);
  198.                     if (axis != null) {
  199.                         axis.setCurRawValue(event.getAxisValue(i));
  200.                         if (!sensorData.haveData) {
  201.                             sensorData.haveData = true;
  202.                         } else {
  203.                             synchronized (eventQueue){
  204.                                 if (axis.isChanged()) {
  205.                                     eventQueue.add(new JoyAxisEvent(axis, axis.getJoystickAxisValue()));
  206.                                 }
  207.                             }
  208.                         }
  209.                     }
  210.                 }
  211.             } else if (sensorData != null)
  212.             {
  213.                 if (!sensorData.haveData) {
  214.                     sensorData.haveData = true;
  215.                 }
  216.             }
  217.  
  218.        
  219.         }
  220.     }
  221.  
  222.     private static float getCenteredAxis(MotionEvent event, InputDevice device,
  223.             int axis, int historyPos) {
  224.         final InputDevice.MotionRange range = device.getMotionRange(axis, event.getSource());
  225.         if (range != null) {
  226.             final float flat = range.getFlat();
  227.             final float value = historyPos < 0 ? event.getAxisValue(axis)
  228.                     : event.getHistoricalAxisValue(axis, historyPos);
  229.  
  230.             // Ignore axis values that are within the 'flat' region of the joystick axis center.
  231.             // A joystick at rest does not always report an absolute position of (0,0).
  232.             if (Math.abs(value) > flat) {
  233.                 return value;
  234.             }
  235.         }
  236.         return 0;
  237.     }
  238.    
  239.     /**
  240.      * Internal class to enclose data for each sensor.
  241.      */
  242.     private class SensorData {
  243.         int androidSensorType = -1;
  244.         InputDevice inputDevice = null;
  245.         int sensorAccuracy = 0;
  246.         float[] lastValues;
  247.         final Object valuesLock = new Object();
  248.         ArrayList<AndroidJoystickAxis> axes = new ArrayList<AndroidJoystickAxis>();
  249.         boolean enabled = false;
  250.         boolean haveData = false;
  251.  
  252.         public SensorData(int androidSensorType, InputDevice inputDevice) {
  253.             this.androidSensorType = androidSensorType;
  254.             this.inputDevice = inputDevice;
  255.         }
  256.  
  257.     }
  258.  
  259.     private void initSensorManager() {
  260.         this.activity = JmeAndroidSystem.getActivity();
  261.         // Get instance of Vibrator from current Context
  262.         vibrator = (Vibrator) activity.getSystemService(Context.VIBRATOR_SERVICE);
  263.         if (vibrator == null) {
  264.             logger.log(Level.FINE, "Vibrator Service not found.");
  265.         }
  266.     }
  267.  
  268.     /**
  269.      * Pauses the sensors to save battery life if the sensors are not needed.
  270.      * Used to pause sensors when the activity pauses
  271.      */
  272.     public void pauseSensors()
  273.     {
  274.         if (vibrator != null && vibratorActive) {
  275.             vibrator.cancel();
  276.         }
  277.     }
  278.  
  279.     /**
  280.      * Resumes the sensors.
  281.      * Used to resume sensors when the activity comes to the top of the stack
  282.      */
  283.     public void resumeSensors()
  284.     {
  285.  
  286.     }
  287.  
  288.  
  289.  
  290.     // Start of JoyInput methods
  291.  
  292.     public void setJoyRumble(int joyId, float amount) {
  293.         // convert amount to pulses since Android doesn't allow intensity
  294.         if (vibrator != null) {
  295.             final long rumbleOnDur = (long)(amount * maxRumbleTime); // ms to pulse vibration on
  296.             final long rumbleOffDur = maxRumbleTime - rumbleOnDur; // ms to delay between pulses
  297.             final long[] rumblePattern = {
  298.                 0, // start immediately
  299.                 rumbleOnDur, // time to leave vibration on
  300.                 rumbleOffDur // time to delay between vibrations
  301.             };
  302.             final int rumbleRepeatFrom = 0; // index into rumble pattern to repeat from
  303.  
  304.             logger.log(Level.FINE, "Rumble amount: {0}, rumbleOnDur: {1}, rumbleOffDur: {2}",
  305.                     new Object[]{amount, rumbleOnDur, rumbleOffDur});
  306.  
  307.             if (rumbleOnDur > 0) {
  308.                 vibrator.vibrate(rumblePattern, rumbleRepeatFrom);
  309.                 vibratorActive = true;
  310.             } else {
  311.                 vibrator.cancel();
  312.                 vibratorActive = false;
  313.             }
  314.         }
  315.  
  316.     }
  317.  
  318.     public Joystick[] loadJoysticks(InputManager inputManager) {
  319.         this.inputManager = inputManager;
  320.  
  321.         initSensorManager();
  322.         setView(mView);
  323.  
  324.         SensorData sensorData;
  325.         List<Joystick> list = new ArrayList<Joystick>();
  326.         AndroidJoystick joystick;
  327.         AndroidJoystickAxis axis;
  328.  
  329.         joystick = new AndroidJoystick(inputManager,
  330.                                     this,
  331.                                     list.size(),
  332.                                     "AndroidSensorsJoystick");
  333.         list.add(joystick);
  334.  
  335.         // manually create orientation sensor data since orientation is not a physical sensor
  336.         sensorData = new SensorData(InputDevice.SOURCE_CLASS_JOYSTICK, null);
  337.  
  338.         sensorData.androidSensorType = InputDevice.SOURCE_CLASS_JOYSTICK;
  339.         //sensorData.sensor = sensorManager.getDefaultSensor(sensorType);
  340.         sensorData.enabled = true;
  341.  
  342.         if (sensorData != null) {
  343.             sensorData.lastValues = new float[2];
  344.             sensors.put(InputDevice.SOURCE_CLASS_JOYSTICK, sensorData);      
  345.             axis = joystick.addAxis(SensorJoystickAxis.ORIENTATION_X, SensorJoystickAxis.ORIENTATION_X, joystick.getAxisCount(), 1);
  346.             joystick.setYAxis(axis); // joystick y axis = rotation around device x axis
  347.             sensorData.axes.add(axis);
  348.             axis = joystick.addAxis(SensorJoystickAxis.ORIENTATION_Y, SensorJoystickAxis.ORIENTATION_Y, joystick.getAxisCount(), 1);
  349.             joystick.setXAxis(axis); // joystick x axis = rotation around device y axis
  350.             sensorData.axes.add(axis);
  351.         }
  352.  
  353.         joysticks = list.toArray( new AndroidJoystick[list.size()] );
  354.         loaded = true;
  355.         return joysticks;
  356.     }
  357.  
  358.     public void initialize() {
  359.         initialized = true;
  360.         loaded = false;
  361.     }
  362.  
  363.     public void update() {
  364.         if (!loaded) {
  365.             return;
  366.         }
  367.         synchronized (eventQueue){
  368.             // flush events to listener
  369.             if (listener != null && eventQueue.size() > 0) {
  370.                 for (int i = 0; i < eventQueue.size(); i++){
  371.                     listener.onJoyAxisEvent(eventQueue.get(i));
  372.                 }
  373.                 eventQueue.clear();
  374.             }
  375.         }
  376.     }
  377.  
  378.     public void destroy() {
  379.         logger.log(Level.FINE, "Doing Destroy.");
  380.         pauseSensors();
  381.         sensors.clear();
  382.         eventQueue.clear();
  383.         initialized = false;
  384.         loaded = false;
  385.         joysticks = null;
  386.         vibrator = null;
  387.         activity = null;
  388.     }
  389.  
  390.     public boolean isInitialized() {
  391.         return initialized;
  392.     }
  393.  
  394.     public void setInputListener(RawInputListener listener) {
  395.         this.listener = listener;
  396.     }
  397.  
  398.     public long getInputTimeNanos() {
  399.         return System.nanoTime();
  400.     }
  401.  
  402.     // End of JoyInput methods
  403.  
  404.     protected class AndroidJoystick extends AbstractJoystick {
  405.         private JoystickAxis nullAxis;
  406.         private JoystickAxis xAxis;
  407.         private JoystickAxis yAxis;
  408.         private JoystickAxis povX;
  409.         private JoystickAxis povY;
  410.  
  411.         public AndroidJoystick( InputManager inputManager, JoyInput joyInput,
  412.                                 int joyId, String name){
  413.  
  414.             super( inputManager, joyInput, joyId, name );
  415.  
  416.             this.nullAxis = new DefaultJoystickAxis( getInputManager(), this, -1,
  417.                                                      "Null", "null", false, false, 0 );
  418.             this.xAxis = nullAxis;
  419.             this.yAxis = nullAxis;
  420.             this.povX = nullAxis;
  421.             this.povY = nullAxis;
  422.  
  423.         }
  424.  
  425.         protected AndroidJoystickAxis addAxis(String axisName, String logicalName, int axisNum, float maxRawValue) {
  426.             AndroidJoystickAxis axis;
  427.  
  428.             axis = new AndroidJoystickAxis(
  429.                     inputManager,               // InputManager (InputManager)
  430.                     this,                       // parent Joystick (Joystick)
  431.                     axisNum,                    // Axis Index (int)
  432.                     axisName,                   // Axis Name (String)
  433.                     logicalName,                // Logical ID (String)
  434.                     true,                       // isAnalog (boolean)
  435.                     false,                      // isRelative (boolean)
  436.                     0.01f,                      // Axis Deadzone (float)
  437.                     maxRawValue);               // Axis Max Raw Value (float)
  438.  
  439.             super.addAxis(axis);
  440.  
  441.             return axis;
  442.         }
  443.  
  444.         protected void setXAxis(JoystickAxis axis) {
  445.             xAxis = axis;
  446.         }
  447.         protected void setYAxis(JoystickAxis axis) {
  448.             yAxis = axis;
  449.         }
  450.  
  451.         @Override
  452.         public JoystickAxis getXAxis() {
  453.             return xAxis;
  454.         }
  455.  
  456.         @Override
  457.         public JoystickAxis getYAxis() {
  458.             return yAxis;
  459.         }
  460.  
  461.         @Override
  462.         public JoystickAxis getPovXAxis() {
  463.             return povX;
  464.         }
  465.  
  466.         @Override
  467.         public JoystickAxis getPovYAxis() {
  468.             return povY;
  469.         }
  470.  
  471.     }
  472.  
  473.     public class AndroidJoystickAxis extends DefaultJoystickAxis implements SensorJoystickAxis {
  474.         float zeroRawValue = 0f;
  475.         float curRawValue = 0f;
  476.         float lastRawValue = 0f;
  477.         boolean hasChanged = false;
  478.         float maxRawValue = FastMath.HALF_PI;
  479.         boolean enabled = true;
  480.  
  481.         public AndroidJoystickAxis(InputManager inputManager, Joystick parent,
  482.                            int axisIndex, String name, String logicalId,
  483.                            boolean isAnalog, boolean isRelative, float deadZone,
  484.                            float maxRawValue) {
  485.             super(inputManager, parent, axisIndex, name, logicalId, isAnalog, isRelative, deadZone);
  486.  
  487.             this.maxRawValue = maxRawValue;
  488.         }
  489.  
  490.         public float getMaxRawValue() {
  491.             return maxRawValue;
  492.         }
  493.  
  494.         public void setMaxRawValue(float maxRawValue) {
  495.             this.maxRawValue = maxRawValue;
  496.         }
  497.  
  498.         protected float getLastRawValue() {
  499.             return lastRawValue;
  500.         }
  501.         protected void setCurRawValue(float rawValue) {
  502.             this.curRawValue = rawValue;
  503.             if (Math.abs(curRawValue - lastRawValue) > getDeadZone()) {
  504.                 hasChanged = true;
  505.                 lastRawValue = curRawValue;
  506.             } else {
  507.                 hasChanged = false;
  508.             }
  509.         }
  510.  
  511.         protected float getJoystickAxisValue() {
  512.             return (lastRawValue-zeroRawValue) / maxRawValue;
  513.         }
  514.  
  515.         protected boolean isChanged() {
  516.             return hasChanged;
  517.         }
  518.  
  519.         public void calibrateCenter() {
  520.             zeroRawValue = lastRawValue;
  521.             logger.log(Level.FINE, "Calibrating axis {0} to {1}",
  522.                     new Object[]{getName(), zeroRawValue});
  523.         }
  524.  
  525.     }
  526. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement