Updated the joystick test to allow better testing

of joysticks and gamepads.  It now presents a gamepad
on the screen that updates itself whenever any connected
joystick or gamepad are used.  This allows the tester
to compare the actual controller layout to the "default"
controller layout.
Information about the active joystick's available axes
and buttons is also rendered to the display.
A dump of all controllers and their components is written
to joysticks-###.txt file.


git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@9762 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
3.0
PSp..om 13 years ago
parent 6db4dde5e8
commit 2970ff46b3
  1. 378
      engine/src/test/jme3test/input/TestJoystick.java
  2. BIN
      engine/test-data/Interface/Joystick/gamepad-buttons.png
  3. BIN
      engine/test-data/Interface/Joystick/gamepad-frame.png
  4. BIN
      engine/test-data/Interface/Joystick/gamepad-stick.png

@ -1,13 +1,38 @@
package jme3test.input;
import com.jme3.app.SimpleApplication;
import com.jme3.input.JoyInput;
import com.jme3.font.BitmapText;
import com.jme3.input.Joystick;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.AnalogListener;
import com.jme3.input.JoystickAxis;
import com.jme3.input.JoystickButton;
import com.jme3.input.RawInputListener;
import com.jme3.input.event.JoyAxisEvent;
import com.jme3.input.event.JoyButtonEvent;
import com.jme3.input.event.KeyInputEvent;
import com.jme3.input.event.MouseButtonEvent;
import com.jme3.input.event.MouseMotionEvent;
import com.jme3.input.event.TouchEvent;
import com.jme3.material.Material;
import com.jme3.material.RenderState.BlendMode;
import com.jme3.math.ColorRGBA;
import com.jme3.math.FastMath;
import com.jme3.math.Vector2f;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.shape.Quad;
import com.jme3.system.AppSettings;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;
public class TestJoystick extends SimpleApplication implements AnalogListener, ActionListener {
public class TestJoystick extends SimpleApplication {
private Joystick viewedJoystick;
private GamepadView gamepad;
private Node joystickInfo;
private float yInfo = 0;
public static void main(String[] args){
TestJoystick app = new TestJoystick();
@ -16,35 +41,348 @@ public class TestJoystick extends SimpleApplication implements AnalogListener, A
app.setSettings(settings);
app.start();
}
@Override
public void simpleInitApp() {
Joystick[] joysticks = inputManager.getJoysticks();
if (joysticks == null)
throw new IllegalStateException("Cannot find any joysticks!");
for (int i = 0; i < joysticks.length; i++){
Joystick joy = joysticks[i];
System.out.println(joy.toString());
try {
PrintWriter out = new PrintWriter( new FileWriter( "joysticks-" + System.currentTimeMillis() + ".txt" ) );
dumpJoysticks( joysticks, out );
out.close();
} catch( IOException e ) {
throw new RuntimeException( "Error writing joystick dump", e );
}
int gamepadSize = cam.getHeight() / 2;
float scale = gamepadSize / 512.0f;
gamepad = new GamepadView();
gamepad.setLocalTranslation( cam.getWidth() - gamepadSize - (scale * 20), 0, 0 );
gamepad.setLocalScale( scale, scale, scale );
guiNode.attachChild(gamepad);
joystickInfo = new Node( "joystickInfo" );
joystickInfo.setLocalTranslation( 0, cam.getHeight(), 0 );
guiNode.attachChild( joystickInfo );
// Add a raw listener because it's eisier to get all joystick events
// this way.
inputManager.addRawInputListener( new JoystickEventListener() );
}
protected void dumpJoysticks( Joystick[] joysticks, PrintWriter out ) {
for( Joystick j : joysticks ) {
out.println( "Joystick[" + j.getJoyId() + "]:" + j.getName() );
out.println( " buttons:" + j.getButtonCount() );
joy.assignAxis("Joy Right", "Joy Left", joy.getXAxisIndex());
joy.assignAxis("Joy Down", "Joy Up", joy.getYAxisIndex());
joy.assignAxis("DPAD Right", "DPAD Left", JoyInput.AXIS_POV_X);
joy.assignAxis("DPAD Up", "DPAD Down", JoyInput.AXIS_POV_Y);
joy.assignButton("Button", 0);
for( JoystickAxis axis : j.getAxes() ) {
out.println( " " + axis );
}
}
}
inputManager.addListener(this, "DPAD Left", "DPAD Right", "DPAD Down", "DPAD Up");
inputManager.addListener(this, "Joy Left", "Joy Right", "Joy Down", "Joy Up");
inputManager.addListener(this, "Button");
protected void addInfo( String info, int column ) {
BitmapText t = new BitmapText(guiFont);
t.setText( info );
t.setLocalTranslation( column * 200, yInfo, 0 );
joystickInfo.attachChild(t);
yInfo -= t.getHeight();
}
public void onAnalog(String name, float isPressed, float tpf) {
System.out.println(name + " = " + isPressed / tpf);
protected void setViewedJoystick( Joystick stick ) {
if( this.viewedJoystick == stick )
return;
if( this.viewedJoystick != null ) {
joystickInfo.detachAllChildren();
}
this.viewedJoystick = stick;
if( this.viewedJoystick != null ) {
// Draw the hud
yInfo = 0;
addInfo( "Joystick:\"" + stick.getName() + "\" id:" + stick.getJoyId(), 0 );
yInfo -= 5;
float ySave = yInfo;
// Column one for the buttons
addInfo( "Buttons:", 0 );
for( JoystickButton b : stick.getButtons() ) {
addInfo( " '" + b.getName() + "' id:'" + b.getLogicalId() + "'", 0 );
}
yInfo = ySave;
// Column two for the axes
addInfo( "Axes:", 1 );
for( JoystickAxis a : stick.getAxes() ) {
addInfo( " '" + a.getName() + "' id:'" + a.getLogicalId() + "' analog:" + a.isAnalog(), 1 );
}
}
}
/**
* Easier to watch for all button and axis events with a raw input listener.
*/
protected class JoystickEventListener implements RawInputListener {
public void onAction(String name, boolean isPressed, float tpf) {
System.out.println(name + " = " + isPressed);
public void onJoyAxisEvent(JoyAxisEvent evt) {
setViewedJoystick( evt.getAxis().getJoystick() );
gamepad.setAxisValue( evt.getAxis(), evt.getValue() );
}
public void onJoyButtonEvent(JoyButtonEvent evt) {
setViewedJoystick( evt.getButton().getJoystick() );
gamepad.setButtonValue( evt.getButton(), evt.isPressed() );
}
public void beginInput() {}
public void endInput() {}
public void onMouseMotionEvent(MouseMotionEvent evt) {}
public void onMouseButtonEvent(MouseButtonEvent evt) {}
public void onKeyEvent(KeyInputEvent evt) {}
public void onTouchEvent(TouchEvent evt) {}
}
protected class GamepadView extends Node {
float xAxis = 0;
float yAxis = 0;
float zAxis = 0;
float zRotation = 0;
float lastPovX = 0;
float lastPovY = 0;
Geometry leftStick;
Geometry rightStick;
Map<String, ButtonView> buttons = new HashMap<String, ButtonView>();
public GamepadView() {
super( "gamepad" );
// Sizes naturally for the texture size. All positions will
// be in that space because it's easier.
int size = 512;
Material m = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
m.setTexture( "ColorMap", assetManager.loadTexture( "Interface/Joystick/gamepad-buttons.png" ) );
m.getAdditionalRenderState().setBlendMode( BlendMode.Alpha );
Geometry buttonPanel = new Geometry( "buttons", new Quad(size, size) );
buttonPanel.setLocalTranslation( 0, 0, -1 );
buttonPanel.setMaterial(m);
attachChild(buttonPanel);
m = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
m.setTexture( "ColorMap", assetManager.loadTexture( "Interface/Joystick/gamepad-frame.png" ) );
m.getAdditionalRenderState().setBlendMode( BlendMode.Alpha );
Geometry frame = new Geometry( "frame", new Quad(size, size) );
frame.setMaterial(m);
attachChild(frame);
m = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
m.setTexture( "ColorMap", assetManager.loadTexture( "Interface/Joystick/gamepad-stick.png" ) );
m.getAdditionalRenderState().setBlendMode( BlendMode.Alpha );
leftStick = new Geometry( "leftStick", new Quad(64, 64) );
leftStick.setMaterial(m);
attachChild(leftStick);
rightStick = new Geometry( "leftStick", new Quad(64, 64) );
rightStick.setMaterial(m);
attachChild(rightStick);
// A "standard" mapping... fits a majority of my game pads
addButton( "Button 0", 371, 512 - 176, 42, 42 );
addButton( "Button 1", 407, 512 - 212, 42, 42 );
addButton( "Button 2", 371, 512 - 248, 42, 42 );
addButton( "Button 3", 334, 512 - 212, 42, 42 );
// Front buttons Some of these have the top ones and the bottoms ones flipped.
addButton( "Button 4", 67, 512 - 111, 95, 21 );
addButton( "Button 5", 348, 512 - 111, 95, 21 );
addButton( "Button 6", 67, 512 - 89, 95, 21 );
addButton( "Button 7", 348, 512 - 89, 95, 21 );
// Select and start buttons
addButton( "Button 8", 206, 512 - 198, 48, 30 );
addButton( "Button 9", 262, 512 - 198, 48, 30 );
// Joystick push buttons
addButton( "Button 10", 147, 512 - 300, 75, 70 );
addButton( "Button 11", 285, 512 - 300, 75, 70 );
// Fake button highlights for the POV axes
//
// +Y
// -X +X
// -Y
//
addButton( "POV +Y", 96, 512 - 174, 40, 38 );
addButton( "POV +X", 128, 512 - 208, 40, 38 );
addButton( "POV -Y", 96, 512 - 239, 40, 38 );
addButton( "POV -X", 65, 512 - 208, 40, 38 );
resetPositions();
}
private void addButton( String name, float x, float y, float width, float height ) {
ButtonView b = new ButtonView(name, x, y, width, height);
attachChild(b);
buttons.put(name, b);
}
public void setAxisValue( JoystickAxis axis, float value ) {
System.out.println( "Axis:" + axis.getName() + "=" + value );
if( axis == axis.getJoystick().getXAxis() ) {
setXAxis(value);
} else if( axis == axis.getJoystick().getYAxis() ) {
setYAxis(-value);
} else if( axis == axis.getJoystick().getAxis("Z Axis") ) {
// Note: in the above condition, we could check the axis name but
// I have at least one joystick that reports 2 "Z Axis" axes.
// In this particular case, the first one is the right one so
// a name based lookup will find the proper one. It's a problem
// because the erroneous axis sends a constant stream of values.
setZAxis(value);
} else if( axis == axis.getJoystick().getAxis("Z Rotation") ) {
setZRotation(-value);
} else if( axis == axis.getJoystick().getPovXAxis() ) {
if( lastPovX < 0 ) {
setButtonValue( "POV -X", false );
} else if( lastPovX > 0 ) {
setButtonValue( "POV +X", false );
}
if( value < 0 ) {
setButtonValue( "POV -X", true );
} else if( value > 0 ) {
setButtonValue( "POV +X", true );
}
lastPovX = value;
} else if( axis == axis.getJoystick().getPovYAxis() ) {
if( lastPovY < 0 ) {
setButtonValue( "POV -Y", false );
} else if( lastPovY > 0 ) {
setButtonValue( "POV +Y", false );
}
if( value < 0 ) {
setButtonValue( "POV -Y", true );
} else if( value > 0 ) {
setButtonValue( "POV +Y", true );
}
lastPovY = value;
}
}
public void setButtonValue( JoystickButton button, boolean isPressed ) {
System.out.println( "Button:" + button.getName() + "=" + (isPressed ? "Down" : "Up") );
setButtonValue( button.getName(), isPressed );
}
protected void setButtonValue( String name, boolean isPressed ) {
ButtonView view = buttons.get(name);
if( view != null ) {
if( isPressed ) {
view.down();
} else {
view.up();
}
}
}
public void setXAxis( float f ) {
xAxis = f;
resetPositions();
}
public void setYAxis( float f ) {
yAxis = f;
resetPositions();
}
public void setZAxis( float f ) {
zAxis = f;
resetPositions();
}
public void setZRotation( float f ) {
zRotation = f;
resetPositions();
}
private void resetPositions() {
float xBase = 155;
float yBase = 212;
Vector2f dir = new Vector2f(xAxis, yAxis);
float length = Math.min(1, dir.length());
dir.normalizeLocal();
float angle = dir.getAngle();
float x = FastMath.cos(angle) * length * 10;
float y = FastMath.sin(angle) * length * 10;
leftStick.setLocalTranslation( xBase + x, yBase + y, 0 );
xBase = 291;
dir = new Vector2f(zAxis, zRotation);
length = Math.min(1, dir.length());
dir.normalizeLocal();
angle = dir.getAngle();
x = FastMath.cos(angle) * length * 10;
y = FastMath.sin(angle) * length * 10;
rightStick.setLocalTranslation( xBase + x, yBase + y, 0 );
}
}
protected class ButtonView extends Node {
private int state = 0;
private Material material;
private ColorRGBA hilite = new ColorRGBA( 0.0f, 0.75f, 0.75f, 0.5f );
public ButtonView( String name, float x, float y, float width, float height ) {
super(name);
setLocalTranslation( x, y, -0.5f );
material = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
material.setColor( "Color", hilite );
material.getAdditionalRenderState().setBlendMode( BlendMode.Alpha );
Geometry g = new Geometry( "highlight", new Quad(width, height) );
g.setMaterial(material);
attachChild(g);
resetState();
}
private void resetState() {
if( state <= 0 ) {
setCullHint( CullHint.Always );
} else {
setCullHint( CullHint.Dynamic );
}
System.out.println( getName() + " state:" + state );
}
public void down() {
state++;
resetState();
}
public void up() {
state--;
resetState();
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Loading…
Cancel
Save